Gestion des factures dans gest_crans.

* Attention, c'est à utiliser avec précaution.
This commit is contained in:
Pierre-Elliott Bécue 2014-08-29 02:36:07 +02:00
parent 04a129f879
commit ad5e4e9d09
3 changed files with 226 additions and 17 deletions

View file

@ -1653,6 +1653,62 @@ def del_club(club):
arg += u'--msgbox "Club détruit\n\n\n" 0 0' arg += u'--msgbox "Club détruit\n\n\n" 0 0'
dialog(arg) dialog(arg)
##################################################################
## Fonctions de modif des factures
def set_facture_mode(facture):
"""Change le mode de paiement
"""
arg = u'--title "Mode de paiement pour la facture fid=%s (%s)" ' % (facture.id(), facture.proprietaire().Nom(),)
arg += u'--menu "Quel moyen de paiement enregistrer ?" 0 0 0 '
arg += u'"Liquide" "En espèces : penser à mettre l\'argent dans une enveloppe." '
arg += u'"Cheque" "Par chèque : ne pas oublier de vérifier signature, date, ordre et montant." '
if facture.proprietaire().solde() - facture.total() > 0:
arg += u'"Solde" "Par solde : il a assez d\'argent pour ça." '
annul, res = dialog(arg)
if annul:
return 1
facture.modePaiement(res[0].lower())
def set_facture_recu(facture):
"""Change le reçu d'une facture
"""
arg = u'--title "Reçu pour la facture fid=%s (%s)" ' % (facture.id(), facture.proprietaire().Nom())
arg += u'--separate-output '
arg += u'--checklist "État du paiement\n" 0 0 0 '
arg += u'"Pmt" "Paiement fourni." "%s"' % (on_off(facture.recuPaiement() is not None),)
annul, res = dialog(arg)
if annul:
return 1
if "Pmt\n" in res:
facture.recuPaiement(strftime("%Y-%m-%d %H:%M:%S"))
else:
facture.recuPaiement(False)
def set_facture_controle(facture):
"""Change le contrôle de la facture
"""
arg = u'--title "Contrôle pour la facture fid=%s (%s)" ' % (facture.id(), facture.proprietaire().Nom())
arg += u'--separate-output '
arg += u'--checklist "État du contrôle\n" 0 0 0 '
arg += u'"Ctl" "Contrôle OK." "%s" ' % (on_off(facture.controle() == "TRUE"),)
arg += u'"NCtl" "Contrôle pas OK." "%s" ' % (on_off(facture.controle() == "FALSE"),)
annul, res = dialog(arg)
if annul:
return 1
if "Ctl\n" in res:
facture.controle(True)
elif "NCtl\n" in res:
facture.controle(False)
else:
facture.controle("")
################################################################## ##################################################################
## Fonctions de remplissage ou modification des paramètres machine ## Fonctions de remplissage ou modification des paramètres machine
@ -1906,6 +1962,31 @@ def del_machine(machine):
arg += u'--msgbox "Machine détruite\n\n\n" 0 0' arg += u'--msgbox "Machine détruite\n\n\n" 0 0'
dialog(arg) dialog(arg)
def del_facture(facture):
u"""
Destruction facture
"""
while 1:
arg = u'--title "Destruction facture fid=%s" --colors ' % facture.id()
arg += u'--inputbox "\Zr\Z1ATTENTION\Zn : la destruction est définitive, et aucun remboursement automatique n\'aura lieu.\nCommentaire à insérer ?" 0 0'
annul, res = dialog(arg)
if annul: return 1
if res[0]: break
arg = u'--title "Destruction facture" '
arg += u'--msgbox "Le commentaire est obligatoire\n\n\n" 0 0'
dialog(arg)
try:
facture.delete(res[0])
except EnvironmentError, c:
arg = u'--title "Destruction facture" '
arg += u'--msgbox "ERREUR n°%s\n\n\n" 0 0' % to_unicode(c.args[0])
dialog(arg)
return 1
arg = u'--title "Destruction facture" '
arg += u'--msgbox "Facture détruite\n\n\n" 0 0'
dialog(arg)
#################################### ####################################
## Fonctions principales d'interface ## Fonctions principales d'interface
@ -2174,6 +2255,36 @@ def modif_machine(machine):
if machine.modifs: if machine.modifs:
return confirm(machine) return confirm(machine)
def modif_facture(facture):
"""Modifie la facture sélectionnée
"""
if facture.controle() and not iscontroleur and not isadm:
return 1
arg = u'--title "Modification de la facture %s (%s)" ' % (facture.id(), facture.proprietaire().Nom(),)
arg += u'--menu "Que souhaitez vous modifier ?" 0 0 0 '
if not (facture.controle() == "TRUE" or facture.controle() == "FALSE") and not facture.recuPaiement():
arg += u'"Mode" "Mode de paiement" '
if not (facture.controle() == "TRUE" or facture.controle() == "FALSE") and facture.modePaiement():
arg += u'"Recu" "Valider le reçu du paiement ou non" '
if facture.recuPaiement() and (iscontroleur or isadm):
arg += u'"Controle" "Valider ou non le contrôle de la facture." '
annul, res = dialog(arg)
if annul: return 1
if res[0] == 'Mode':
set_facture_mode(facture)
elif res[0] == 'Recu':
set_facture_recu(facture)
elif res[0] == 'Controle':
set_facture_controle(facture)
if facture.modifs:
return confirm(facture)
######################################################################## ########################################################################
## Fonction de sélection (adhérent ou machine) ## Fonction de sélection (adhérent ou machine)
@ -2268,7 +2379,7 @@ def select(clas, quoi, mde=''):
# Affichage # Affichage
if quoi[-1] == 'a': if quoi[-1] == 'a':
valid = res['adherent'] valid = res['adherent']
if not valid and res['machine']: if not valid and (res['machine'] or res['facture']):
# On va récupérer les adhérents correspondants aux machines trouvés # On va récupérer les adhérents correspondants aux machines trouvés
deja= [] deja= []
for m in res['machine']: for m in res['machine']:
@ -2276,6 +2387,11 @@ def select(clas, quoi, mde=''):
if a.id() in deja: continue if a.id() in deja: continue
deja.append(a.id()) deja.append(a.id())
valid.append(a) valid.append(a)
for f in res['facture']:
a = f.proprietaire()
if a.id() in deja: continue
deja.append(a.id())
valid.append(a)
elif quoi[-1] == 'm': elif quoi[-1] == 'm':
valid = res['machine'] valid = res['machine']
if not valid and res['adherent']: if not valid and res['adherent']:
@ -2283,6 +2399,13 @@ def select(clas, quoi, mde=''):
for a in res['adherent']: for a in res['adherent']:
for m in a.machines(): for m in a.machines():
valid.append(m) valid.append(m)
elif quoi[-1] == 'f':
valid = res['facture']
if not valid and res['adherent']:
# On va récupérer les machines des adhérents trouvés
for a in res['adherent']:
for f in a.factures():
valid.append(f)
else: else:
raise TypeError('Argument fonction invalide') raise TypeError('Argument fonction invalide')
@ -2382,6 +2505,9 @@ def menu_principal():
arg += u'"mM" "Modifier une machine existante" "Changer le nom ou la MAC d\'une machine." ' arg += u'"mM" "Modifier une machine existante" "Changer le nom ou la MAC d\'une machine." '
arg += u'"dM" "Détruire une machine" "" ' arg += u'"dM" "Détruire une machine" "" '
arg += u'"" "---------------------------------------" "" ' arg += u'"" "---------------------------------------" "" '
arg += u'"mF" "Modifier une facture existante" "Modifier les données relatives à la facture…" '
arg += u'"dF" "Détruire une facture" "" '
arg += u'"" "---------------------------------------" "" '
arg += u'"aC" "Inscrire un nouveau club" "" ' arg += u'"aC" "Inscrire un nouveau club" "" '
arg += u'"mC" "Modifier un club" "" ' arg += u'"mC" "Modifier un club" "" '
arg += u'"aMC" "Ajouter une machine à un club" "" ' arg += u'"aMC" "Ajouter une machine à un club" "" '
@ -2438,6 +2564,12 @@ def menu_principal():
if not becane: continue if not becane: continue
choix= 'mMc' choix= 'mMc'
elif choix == "mF":
# Modif d'une facture. Choisir facture.
facture = select(db, u'Facture à modifier f')
if not facture: continue
choix = "mFc"
elif choix == 'aC': elif choix == 'aC':
# Ajout d'un club # Ajout d'un club
proprio = Club() proprio = Club()
@ -2474,6 +2606,17 @@ def menu_principal():
del(proprio) ; proprio= None del(proprio) ; proprio= None
del(becane) ; becane= None del(becane) ; becane= None
elif choix == 'dF':
# Destruction machine
facture = select(db, u'facture à détruire f')
if not facture: continue
proprio = facture.proprietaire()
if del_facture(facture): continue
del(facture)
facture = None
proprio.update_adhesion()
proprio.update_connexion()
elif choix == 'aKM': elif choix == 'aKM':
# Ajout machine au crans # Ajout machine au crans
becane = MachineCrans(AssociationCrans(db.conn)) becane = MachineCrans(AssociationCrans(db.conn))
@ -2583,6 +2726,12 @@ def menu_principal():
# Annulation des modifs # Annulation des modifs
becane.restore() becane.restore()
elif choix == 'mFc':
# Modif machine courante
if modif_facture(facture):
# Annulation des modifs
facture.restore()
elif choix == 'mCc': elif choix == 'mCc':
# Modif club courant # Modif club courant
if modif_club(proprio): if modif_club(proprio):

View file

@ -1503,7 +1503,7 @@ class BaseProprietaire(BaseClasseCrans):
# On récupère sur les factures l'ensemble de celles comportant une adhésion. # On récupère sur les factures l'ensemble de celles comportant une adhésion.
adh_factures = self.factures_adh() adh_factures = self.factures_adh()
finAdh = max([0.0] + [fromGeneralizedTimeFormat(facture._data.get('finAdhesion', ["19700101000000Z"])[0]) for facture in adh_factures if facture.controle() != "FALSE"]) finAdh = max([0.0] + [fromGeneralizedTimeFormat(facture._data.get('finAdhesion', ["19700101000000Z"])[0]) for facture in adh_factures if facture.controle() != "FALSE" and facture.recuPaiement() is not None])
if update == False: if update == False:
return finAdh return finAdh
@ -1530,6 +1530,19 @@ class BaseProprietaire(BaseClasseCrans):
self._set("debutAdhesion", self._data.get("debutAdhesion", []) + [generalizedTimeFormat(thetime)]) self._set("debutAdhesion", self._data.get("debutAdhesion", []) + [generalizedTimeFormat(thetime)])
return f return f
def update_adhesion(self):
"""Récupère les dates de début et fin d'adhésion dans les factures
de l'adhérent, et met à jour ses données."""
debutAdh = []
finAdh = []
for facture in self.factures_adh():
debutAdh.append(generalizedTimeFormat(facture._data['debutAdhesion'][0]))
finAdh.append(generalizedTimeFormat(facture._data['finAdhesion'][0]))
self._set('debutAdhesion', debutAdh)
self._set('finAdhesion', finAdh)
self._save()
def droits(self, droits=None, light=False): def droits(self, droits=None, light=False):
""" Renvoie les droits courants. Non modifiable (sauf si surchargée dans classe enfant)""" """ Renvoie les droits courants. Non modifiable (sauf si surchargée dans classe enfant)"""
if droits <> None: if droits <> None:
@ -2378,7 +2391,7 @@ class Adherent(BaseProprietaire):
# On récupère sur les factures l'ensemble de celles comportant une connexion. # On récupère sur les factures l'ensemble de celles comportant une connexion.
conn_factures = self.factures_conn() conn_factures = self.factures_conn()
finConn = max([0.0] + [fromGeneralizedTimeFormat(facture._data.get('finConnexion', ["19700101000000Z"])[0]) for facture in conn_factures if facture.controle() != "FALSE"]) finConn = max([0.0] + [fromGeneralizedTimeFormat(facture._data.get('finConnexion', ["19700101000000Z"])[0]) for facture in conn_factures if facture.controle() != "FALSE" and facture.recuPaiement() is not None])
if mois is None: if mois is None:
return finConn return finConn
@ -2408,6 +2421,19 @@ class Adherent(BaseProprietaire):
self._set("debutConnexion", self._data.get("debutConnexion", []) + [generalizedTimeFormat(thetime)]) self._set("debutConnexion", self._data.get("debutConnexion", []) + [generalizedTimeFormat(thetime)])
return f return f
def update_connexion(self):
"""Récupère les dates de début et fin de connexion dans les factures
de l'adhérent, et met à jour ses données."""
debutConn = []
finConn = []
for facture in self.factures_adh():
debutConn.append(generalizedTimeFormat(facture._data['debutConnexion'][0]))
finConn.append(generalizedTimeFormat(facture._data['finConnexion'][0]))
self._set('debutConnexion', debutConn)
self._set('finConnexion', finConn)
self._save()
def adherentPayant(self, valeur = None): def adherentPayant(self, valeur = None):
""" """
L'adhérent paie sa cotisation (a droit au WiFi, à un compte Crans, ... True par défaut L'adhérent paie sa cotisation (a droit au WiFi, à un compte Crans, ... True par défaut
@ -3946,7 +3972,7 @@ class Facture(BaseClasseCrans):
raise ValueError, u'Facture déja payée' raise ValueError, u'Facture déja payée'
# modification de la valeur # modification de la valeur
if new != None: if new is not None and new != False:
# on vérifie que la facture est modifiable # on vérifie que la facture est modifiable
if not self._modifiable and new: if not self._modifiable and new:
raise NotImplementedError, "La facture n'est pas modifiable" raise NotImplementedError, "La facture n'est pas modifiable"
@ -3960,6 +3986,17 @@ class Facture(BaseClasseCrans):
# modifie la base ldap # modifie la base ldap
self._set("recuPaiement", [new]) self._set("recuPaiement", [new])
elif new == False:
# 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._vider()
# modifie la base ldap
self._set("recuPaiement", [])
# renvoie la valeur trouvée dans la base # renvoie la valeur trouvée dans la base
return self._data.get("recuPaiement", [None])[0] return self._data.get("recuPaiement", [None])[0]
@ -3997,13 +4034,36 @@ class Facture(BaseClasseCrans):
# on crédite les articles # on crédite les articles
for art in self._articles(): for art in self._articles():
# solde impression (on débite d'abord si jamais quelqu'un s'amuse à recharger son solde avec son solde) # solde impression (on débite d'abord si jamais quelqu'un s'amuse à recharger son solde avec son solde)
if art["code"] == "SOLDE":
proprio = self.proprietaire()
proprio.solde(operation=art['nombre']*art["pu"], comment="Facture n°%s : %s" % (self.numero(), art['designation']))
proprio.save()
if self.modePaiement() == 'solde': if self.modePaiement() == 'solde':
proprio = self.proprietaire() proprio = self.proprietaire()
proprio.solde(operation=0.0 - self.total(), comment="Facture n°%s" % self.numero()) proprio.solde(operation=0.0 - self.total(), comment="Facture n°%s" % self.numero())
proprio.save() proprio.save()
def _vider(self):
"""
Retire les articles à son propriétaire
"""
# 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():
# solde impression (on débite d'abord si jamais quelqu'un s'amuse à recharger son solde avec son solde)
if art["code"] == "SOLDE": if art["code"] == "SOLDE":
proprio = self.proprietaire() proprio = self.proprietaire()
proprio.solde(operation=art['nombre']*art["pu"], comment="Facture n°%s : %s" % (self.numero(), art['designation'])) proprio.solde(operation=-art['nombre']*art["pu"], comment="Revert facture n°%s : %s" % (self.numero(), art['designation']))
proprio.save()
if art["code"] == "FRAIS":
self.supprime(art)
if self.modePaiement() == 'solde':
proprio = self.proprietaire()
proprio.solde(operation=0.0 + self.total(), comment="Revert facture n°%s" % self.numero())
proprio.save() proprio.save()
def _frais(self): def _frais(self):

View file

@ -295,11 +295,11 @@ def factures_brief(factures) :
# Contrôle # Contrôle
controle = facture.controle() controle = facture.controle()
if controle == "TRUE": if controle == "TRUE":
controle = coul("Validée", "vert") controle = coul(u"Validée", "vert")
elif controle == "FALSE": elif controle == "FALSE":
controle = coul("Invalide", "rouge") controle = coul(u"Invalide", "rouge")
else: else:
controle = "N/A" controle = u"N/A"
# Données # Données
data.append([ data.append([
@ -423,11 +423,11 @@ def list_factures(factures) :
for f in factures : for f in factures :
controle = f.controle() controle = f.controle()
if controle == "TRUE": if controle == "TRUE":
controle = coul("Validée", "vert") controle = coul(u"Validée", "vert")
elif controle == "FALSE": elif controle == "FALSE":
controle = coul("Invalide", "rouge") controle = coul(u"Invalide", "rouge")
else: else:
controle = "N/A" controle = u"N/A"
data.append([ data.append([
f.id(), f.id(),
f.modePaiement(), f.modePaiement(),
@ -702,11 +702,11 @@ def facture_details(facture) :
controle = facture.controle() controle = facture.controle()
if controle == "TRUE": if controle == "TRUE":
controle = coul("Validée", "vert") controle = coul(u"Validée", "vert")
elif controle == "FALSE": elif controle == "FALSE":
controle = coul("Invalide", "rouge") controle = coul(u"Invalide", "rouge")
else: else:
controle = "N/A" controle = u"N/A"
f=u'' f=u''
# Fid # Fid