From cb71139d02cae2d100b59bf3fa5c7ab783ab0f45 Mon Sep 17 00:00:00 2001 From: Valentin Samir Date: Tue, 2 Dec 2014 01:55:39 +0100 Subject: [PATCH] =?UTF-8?q?[dialog/adherent]=20Possibilit=C3=A9=20de=20pro?= =?UTF-8?q?longer=20une=20connexion?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gestion/dialog/adherent.py | 270 ++++++++++++++++++++++++++++++------- 1 file changed, 223 insertions(+), 47 deletions(-) diff --git a/gestion/dialog/adherent.py b/gestion/dialog/adherent.py index d66ca337..ef547cac 100644 --- a/gestion/dialog/adherent.py +++ b/gestion/dialog/adherent.py @@ -9,6 +9,7 @@ Licence : GPLv3 import sys import time import datetime +import dateutil.relativedelta if '/usr/scripts' not in sys.path: sys.path.append('/usr/scripts') @@ -159,7 +160,48 @@ class Dialog(proprio.Dialog): codes_todo=[([self.dialog.DIALOG_OK], todo, [tag, menu, adherent, self_cont])] ) - def adherent_adhesion(self, cont, adherent, tag_paiment=None, comment_paiement=None): + def adherent_adhesion_connexion_crediter(self, facture, adherent): + adhesion = False + connexion = False + if [a for a in facture["article"] if a["code"] == "ADH"]: + adhesion = True + if [a for a in facture["article"] if a["code"].startswith("CAI")]: + connexion = True + # Appeler créditer va créditer ou débiter le solde, sauver le proprio et créer la facture + if facture.mode == 'rw': + facture.crediter() + else: + with self.conn.search(dn=facture.dn, scope=0, mode='rw')[0] as facture: + facture.crediter() + with self.conn.search(dn=adherent.dn, scope=0, mode='rw')[0] as adherent: + if facture["finAdhesion"]: + adherent["finAdhesion"].append(facture["finAdhesion"][0]) + if facture["debutAdhesion"]: + adherent["debutAdhesion"].append(facture["debutAdhesion"][0]) + if facture["debutConnexion"]: + adherent["debutConnexion"].append(facture["debutConnexion"][0]) + if facture["finConnexion"]: + adherent["finConnexion"].append(facture["finConnexion"][0]) + adherent.validate_changes() + adherent.history_gen() + adherent.save() + try: + if adhesion and not connexion: + self.dialog.msgbox(text=u"Adhésion effectué avec success", title=u"Adhésion terminé", width=0, height=0, timeout=self.timeout) + elif not adhesion and connexion: + self.dialog.msgbox(text=u"Connexion prolongée avec success", title=u"Connexion prolongée", width=0, height=0, timeout=self.timeout) + elif adhesion and connexion: + self.dialog.msgbox(text=u"Adhésion effectué et connexion prolongée avec success", title=u"Connexion & Adhésion", width=0, height=0, timeout=self.timeout) + except KeyboardInterrupt: + pass + if facture['modePaiement'][0] == "solde": + try: + self.dialog.msgbox(text=u"Le solde de l'adhérent à bien été débité", title="Solde débité", width=0, height=0, timeout=self.timeout) + except KeyboardInterrupt: + pass + return adherent + + def adherent_adhesion(self, cont, adherent, cancel_cont=None, tag_paiment=None, comment_paiement=None, crediter=True, facture=None): # Boite si on ne peux pas réahdérer def box_already(end): @@ -179,6 +221,12 @@ class Dialog(proprio.Dialog): adherer=self.confirm(text="Adhésion pour un an, continuer ?", title="Adhésion de %s %s" % (adherent.get("prenom", [''])[0], adherent["nom"][0])) return adherer + def delete_facture(facture, cont): + if facture: + with self.conn.search(dn=facture.dn, scope=0, mode='rw')[0] as facture: + facture.delete() + raise Continue(cont) + # Génération de la facture pour adhésion def paiement(tag_paiement, adherent, finadhesion, comment, cancel_cont, cont): now = time.time() @@ -191,55 +239,182 @@ class Dialog(proprio.Dialog): facture['info']=unicode(comment, 'utf-8') facture["finAdhesion"]=unicode(new_finadhesion) facture["debutAdhesion"]=unicode(new_debutadhesion) - if self.confirm_item(item=facture, - text=u"Le paiement de %sEUR a-t-il bien été reçu (mode : %s) ?\n" % (facture.total(), tag_paiement), - title=u"Validation du paiement", - timeout=self.timeout): - # Appeler créditer va créditer ou débiter le solde, sauver le proprio et créer la facture - facture.crediter() - with self.conn.search(dn=adherent.dn, scope=0, mode='rw')[0] as adherent: - adherent["finAdhesion"].append(unicode(new_finadhesion)) - adherent["debutAdhesion"].append(unicode(new_debutadhesion)) - adherent.validate_changes() - adherent.history_gen() - adherent.save() - self.dialog.msgbox( - text=u"Adhésion effectué avec success", - title=u"Adhésion terminé", - width=0, height=0, timeout=self.timeout) - if tag_paiement == "solde": - self.dialog.msgbox(text=u"Le solde de l'adhérent à bien été débité", title="Solde débité", width=0, height=0, timeout=self.timeout) + if crediter: + if self.confirm_item(item=facture, + text=u"Le paiement de %sEUR a-t-il bien été reçu (mode : %s) ?\n" % (facture.total(), tag_paiement), + title=u"Validation du paiement", + timeout=self.timeout): + # Appeler créditer va créditer ou débiter le solde, sauver le proprio et créer la facture + adherent = self.adherent_adhesion_connexion_crediter(facture, adherent) + else: + if not self.confirm(text=u"Le paiement n'a pas été reçue.\n Annuler ?", title="Annulation de l'adhésion", defaultno=True): + raise Continue(cancel_cont) else: - if not self.confirm(text=u"Le paiement n'a pas été reçue.\n Annuler ?", title="Annulation de l'adhésion", defaultno=True): - raise Continue(cancel_cont) + facture.create() + raise Continue(cont(facture=facture)) raise Continue(cont(adherent=adherent)) finadhesion = adherent.fin_adhesion() # Si fin de l'adhésion trop loin dans le futur, rien a faire if finadhesion and finadhesion - config.cotisation.delai_readh > time.time(): self.handle_dialog(cont, box_already, finadhesion) - return cont + raise Continue(cancel_cont if cancel_cont else cont) # Sinon, si on accepte l'adhésion elif tag_paiment or self.handle_dialog(cont, box_adherer, finadhesion): - self_cont = TailCall(self.adherent_adhesion, cont=cont, adherent=adherent, tag_paiment=tag_paiment, comment_paiement=comment_paiement) + self_cont = TailCall(self.adherent_adhesion, cont=cont, adherent=adherent, cancel_cont=cancel_cont, tag_paiment=tag_paiment, comment_paiement=comment_paiement, crediter=crediter, facture=facture) # On choisi un mode de paiement if not tag_paiment or not comment_paiement: - return self.proprio_choose_paiement(proprio=adherent, cont=self_cont, cancel_cont=cont) + return self.proprio_choose_paiement(proprio=adherent, cont=self_cont, cancel_cont=TailCall(delete_facture, facture, cancel_cont if cancel_cont else cont)) else: - cancel_cont = self_cont.copy() - cancel_cont(comment_paiement=None) + lcont = self_cont.copy() + lcont(comment_paiement=None) return self.handle_dialog_result( code=self.dialog.DIALOG_OK, output=[], - cancel_cont=cancel_cont, - error_cont=cancel_cont, - codes_todo=[([self.dialog.DIALOG_OK], paiement, [tag_paiment, adherent, finadhesion, comment_paiement, cancel_cont, cont])] + cancel_cont=lcont, + error_cont=lcont, + codes_todo=[([self.dialog.DIALOG_OK], paiement, [tag_paiment, adherent, finadhesion, comment_paiement, lcont, cont])] ) else: - return cont - def adherent_connexion(self, cont, adherent, cancel_cont=None): - self.dialog.msgbox("todo", width=0, height=0) + return self.handle_dialog_result( + code=self.dialog.DIALOG_OK, + output=[], + cancel_cont=None, + error_cont=cancel_cont if cancel_cont else cont, + codes_todo=[([self.dialog.DIALOG_OK], delete_facture, [facture, cancel_cont if cancel_cont else cont])] + ) + + def adherent_connexion(self, cont, adherent, cancel_cont=None, facture=None, mois=None, default_item=None, tag_paiment=None, comment_paiement=None): + menu = { + "An": {'text':"Prolonger d'un an (pour %s€)" % config.cotisation.plafond_contribution, 'callback':TailCall(self.adherent_connexion, cont, adherent, cancel_cont, facture, 12, default_item, tag_paiment, comment_paiement)}, + "NC": {'text':"Pas de connexion", 'callback':TailCall(self.adherent_connexion, cont, adherent, cancel_cont, facture, 12, default_item, tag_paiment, comment_paiement)} + } + menu_order = ["An"] + for i in range(1, config.cotisation.duree_conn_plafond): + if config.cotisation.contribution * i < config.cotisation.plafond_contribution: + menu["%s mois" % i] = {'text':"Prolonger de %s mois (pour %s€)" % (i, config.cotisation.contribution * i), 'callback':TailCall(self.adherent_connexion, cont, adherent, cancel_cont, facture, i, default_item, tag_paiment, comment_paiement)} + menu_order.append("%s mois" % i) + + if facture: + menu_order.append("NC") + + def box(finconnexion, default_item=None): + t_end = time.strftime('%d/%m/%Y %H:%M:%S', time.localtime(finconnexion)) + return self.dialog.menu( + "Connexion jusqu'au %s" % t_end if finconnexion else "N'a jamais été connecté", + width=0, + height=0, + menu_height=0, + timeout=self.timeout, + item_help=0, + default_item=str(default_item), + title="Connexion de %s %s" % (adherent['prenom'][0], adherent["nom"][0]), + scrollbar=True, + cancel_label="Retour", + backtitle=u"Vous êtes connecté en tant que %s" % self.conn.current_login, + choices=[(k, menu[k]['text']) for k in menu_order]) + + def todo(adherent, mois, finconnexion, cancel_cont, cont, facture=None, tag_paiment=None, comment=None): + now = time.time() + new_finconnexion = datetime.datetime.fromtimestamp(max(finconnexion, now)) + # On ajoute 3600 secondes sur suggestion de Raphaël Bonaque (), pour tenir compte des malheureux qui + # pourraient subir le changement d'heure. + new_finconnexion = time.mktime((new_finconnexion + dateutil.relativedelta.relativedelta(months=mois)).timetuple()) + 3600 + new_debutconnexion = max(now, finconnexion) + if facture: + with self.conn.search(dn=facture.dn, scope=0, mode='rw')[0] as facture: + if mois: + facture["finConnexion"]=unicode(new_finconnexion) + facture["debutConnexion"]=unicode(new_debutconnexion) + facture["article"].append(config.cotisation.dico_cotis(mois)) + if self.confirm_item(item=facture, + text=u"Le paiement de %sEUR a-t-il bien été reçu (mode : %s) ?\n" % (facture.total(), facture['modePaiement'][0]), + title=u"Validation du paiement", + timeout=self.timeout): + # Appeler créditer va créditer ou débiter le solde, sauver le proprio et crée + adherent = self.adherent_adhesion_connexion_crediter(facture, adherent) + else: + if not self.confirm(text=u"Le paiement n'a pas été reçue.\n Annuler ?", title="Annulation de l'adhésion", defaultno=True): + raise Continue(cancel_cont) + else: + facture.delete() + + else: + if tag_paiment is None or comment is None: + raise ValueError("Il faut définir une méthode de paiement avec un commentaire") + if not mois: + raise ValueError("Il faut prolonger la connexion d'un nombre de mois strictement positif") + with self.conn.newFacture(adherent.dn, {}) as facture: + facture['modePaiement']=unicode(tag_paiment, 'utf-8') + facture['article'].append(config.cotisation.dico_cotis(mois)) + facture['info']=unicode(comment, 'utf-8') + facture["finConnexion"]=unicode(new_finconnexion) + facture["debutConnexion"]=unicode(new_debutconnexion) + if self.confirm_item(item=facture, + text=u"Le paiement de %sEUR a-t-il bien été reçu (mode : %s) ?\n" % (facture.total(), tag_paiment), + title=u"Validation du paiement", + timeout=self.timeout): + # Appeler créditer va créditer ou débiter le solde, sauver le proprio et crée + adherent = self.adherent_adhesion_connexion_crediter(facture, adherent) + else: + if not self.confirm(text=u"Le paiement n'a pas été reçue.\n Annuler ?", title="Annulation de l'adhésion", defaultno=True): + raise Continue(cancel_cont) + raise Continue(cont(adherent=adherent)) + + def todo_mois(tag, self_cont): + if tag == 'An': + mois = 12 + else: + mois = int(tag.split(' ',1)[0]) + raise Continue(self_cont(mois=mois, default_item=tag)) + + self_cont = TailCall(self.adherent_connexion, cont=cont, adherent=adherent, cancel_cont=cancel_cont, facture=facture, mois=mois, default_item=default_item, tag_paiment=tag_paiment, comment_paiement=comment_paiement) + + finadhesion = adherent.fin_adhesion() + if facture: + finadhesion = max(finadhesion, facture["finAdhesion"][0] if facture["finAdhesion"] else 0) + finconnexion = adherent.fin_connexion() + + # Si l'adhésion fini avant la connexion + if finadhesion <= time.time() or finadhesion < finconnexion: + if finadhesion: + if finadhesion <= time.time(): + self.dialog.msgbox(text=u"L'adhésion a expiré, il va falloir réadhérer d'abord", title="Réadhésion nécessaire", width=0, height=0, timeout=self.timeout) + elif finadhesion < finconnexion: + self.dialog.msgbox(text=u"L'adhésion de termine avant la fin de la connexion, il va falloir réadhérer d'abord", title="Réadhésion nécessaire", width=0, height=0, timeout=self.timeout) + # Échouera si on essaie de prolonger la connexion au dela de l'adhésion et que l'adhésion est encore valable plus de quinze jours + return self.adherent_adhesion(cont=self_cont, cancel_cont=cont, adherent=adherent, crediter=False) + if facture: + cancel_cont = TailCall(self.adherent_adhesion, cont=self_cont, adherent=adherent, cancel_cont=cont, tag_paiment=str(facture['modePaiement'][0]), comment_paiement=None, crediter=False, facture=facture) + self_cont(cancel_cont=cancel_cont) + if mois is None: + (code, tag) = self.handle_dialog(cont, box, finconnexion, default_item) + return self.handle_dialog_result( + code=code, + output=[], + cancel_cont=cancel_cont if cancel_cont else cont, + error_cont=self_cont, + codes_todo=[([self.dialog.DIALOG_OK], todo_mois, [tag, self_cont])] + ) + elif tag_paiment or facture: + lcont=self_cont.copy() + if facture: + lcont(mois=None) + else: + lcont(tag_paiment=None) + return self.handle_dialog_result( + code=self.dialog.DIALOG_OK, + output=[], + cancel_cont=lcont, + error_cont=lcont, + codes_todo=[([self.dialog.DIALOG_OK], todo, [adherent, mois, finconnexion, lcont, cont, facture, tag_paiment, comment_paiement])] + ) + else: + lcont=self_cont.copy() + lcont(mois=None) + return self.proprio_choose_paiement(proprio=adherent, cont=self_cont, cancel_cont=lcont) return cont + def adherent_carte_etudiant(self, cont, adherent, values={}, cancel_cont=None): # Dictionnaire décrivant quelle est la valeur booléenne à donner à l'absence de l'attribut a = attributs @@ -419,7 +594,7 @@ class Dialog(proprio.Dialog): # On traite les valeurs reçues for ((a,l),values) in zip(to_display, tags): if not values and a in non_empty: - raise ValueError("%s ne devrait pas être vide" % a.legend) + raise ValueError(u"%s ne devrait pas être vide" % a.legend) values = unicode(values, 'utf-8') # Si le champs n'est pas single value, on utilise separateur pour découper # et on ne garde que les valeurs non vides @@ -674,13 +849,14 @@ class Dialog(proprio.Dialog): def mycont(adherent=None, **kwargs): if adherent: # Une fois l'adhérent créé, on vois s'il donne sa carte étudiant et s'il adhére/prend la connexion internet - adh_cont = TailCall(self.modif_adherent, cont=cont, adherent=adherent) - conn_cont = TailCall(self.adherent_connexion, cont=adh_cont, adherent=adherent) + #adh_cont = TailCall(self.modif_adherent, cont=cont, adherent=adherent) + conn_cont = TailCall(self.adherent_connexion, cont=cont(proprio=adherent), adherent=adherent) carte_cont = TailCall(self.adherent_carte_etudiant, cont=conn_cont, adherent=adherent) etude_cont = TailCall(self.adherent_etudes, cont=carte_cont, adherent=adherent) etude_cont(cancel_cont=etude_cont) carte_cont(cancel_cont=etude_cont) - conn_cont(cancel_cont=carte_cont) + # Comme on crée une facture, pas de retour possible + conn_cont(cancel_cont=conn_cont) raise Continue(etude_cont) else: raise Continue(cont) @@ -703,8 +879,8 @@ class Dialog(proprio.Dialog): return self.handle_dialog_result( code=self.dialog.DIALOG_OK, output="", - cancel_cont=cont(proprio=adherent), - error_cont=cont(proprio=adherent), + cancel_cont=cont(adherent=adherent), + error_cont=cont(adherent=adherent), codes_todo=[([self.dialog.DIALOG_OK], todo, [adherent])] ) @@ -740,7 +916,7 @@ class Dialog(proprio.Dialog): ) - def adherent_etudes(self, adherent, cont, default_item=None, etablissement=None, annee=None, section=None): + def adherent_etudes(self, adherent, cont, cancel_cont=None, default_item=None, etablissement=None, annee=None, section=None): """Gestion des études de l'adhérent. etudes est un triplet (établissement, année, section)""" choices_etablissement = [ ('Autre', ''), @@ -910,11 +1086,11 @@ class Dialog(proprio.Dialog): backtitle=u"Vous êtes connecté en tant que %s" % self.conn.current_login, choices=section_ENS) - self_cont = TailCall(self.adherent_etudes, adherent=adherent, cont=cont, default_item=default_item, etablissement=etablissement, annee=annee, section=section) + self_cont = TailCall(self.adherent_etudes, adherent=adherent, cont=cont, cancel_cont=cancel_cont, default_item=default_item, etablissement=etablissement, annee=annee, section=section) if etablissement is None or etablissement == 'Autre': if not default_item and adherent["etudes"]: default_item = str(adherent["etudes"][0]) - cancel_cont = cont + lcont = cancel_cont if cancel_cont else cont (code, etablissement) = self.handle_dialog(cancel_cont, box_etablissement, default_item) output = etablissement self_cont(default_item=etablissement) @@ -922,20 +1098,20 @@ class Dialog(proprio.Dialog): if not default_item and adherent["etudes"]: default_item = str(adherent["etudes"][1]) print default_item - cancel_cont = TailCall(self.adherent_etudes, adherent=adherent, cont=cont, default_item=etablissement, etablissement=None, annee=None, section=None) - (code , annee) = self.handle_dialog(cancel_cont, box_annee, default_item) + lcont = TailCall(self.adherent_etudes, adherent=adherent, cont=cont, cancel_cont=cancel_cont, default_item=etablissement, etablissement=None, annee=None, section=None) + (code , annee) = self.handle_dialog(lcont, box_annee, default_item) output = annee self_cont(default_item=annee) elif section is None or section == 'Autre': if not default_item and adherent["etudes"]: default_item = str(adherent["etudes"][2]) - cancel_cont = TailCall(self.adherent_etudes, adherent=adherent, cont=cont, default_item=annee, etablissement=etablissement, annee=None, section=None) - (code, section) = self.handle_dialog(cancel_cont, box_section, default_item) + lcont = TailCall(self.adherent_etudes, adherent=adherent, cont=cont, cancel_cont=cancel_cont, default_item=annee, etablissement=etablissement, annee=None, section=None) + (code, section) = self.handle_dialog(lcont, box_section, default_item) output = section self_cont(default_item=section) else: output = "" - cancel_cont = TailCall(self.adherent_etudes, adherent=adherent, cont=cont, default_item=section, etablissement=etablissement, annee=annee, section=None) + lcont = TailCall(self.adherent_etudes, adherent=adherent, cont=cont, cancel_cont=cancel_cont, default_item=section, etablissement=etablissement, annee=annee, section=None) def todo(etablissement, annee, section, adherent, self_cont, cont): if etablissement is None or etablissement == 'Autre': @@ -955,7 +1131,7 @@ class Dialog(proprio.Dialog): return self.handle_dialog_result( code=code, output=output, - cancel_cont=cancel_cont, + cancel_cont=lcont, error_cont=self_cont, codes_todo=[([self.dialog.DIALOG_OK], todo, [etablissement, annee, section, adherent, self_cont, cont])] )