diff --git a/gestion/gest_crans_lc.py b/gestion/gest_crans_lc.py index a740c8f9..63728c74 100755 --- a/gestion/gest_crans_lc.py +++ b/gestion/gest_crans_lc.py @@ -17,6 +17,7 @@ import os import sys import ssl import time +import copy import ldap import signal import inspect @@ -31,6 +32,7 @@ from gestion.cert_utils import createCertRequest from gestion.affich_tools import get_screen_size, coul from gestion.chgpass import checkpass import gestion.config as config +import gestion.config.factures import lc_ldap.shortcuts import lc_ldap.objets as objets @@ -142,6 +144,12 @@ class TailCall(object) : def __str__(self): return "TailCall<%s(%s%s%s)>" % (self.call.func_name, ', '.join(repr(a) for a in self.args), ', ' if self.args and self.kwargs else '', ', '.join("%s=%s" % (repr(k),repr(v)) for (k,v) in self.kwargs.items())) + def copy(self): + ''' Patch the deepcopy dispatcher to pass modules back unchanged ''' + result = TailCall(self.call, *list(self.args), **dict(self.kwargs)) + result.stacklvl = self.stacklvl + return result + def __call__(self, *args, **kwargs): self.kwargs.update(kwargs) self.args = self.args + args @@ -251,6 +259,17 @@ class GestCrans(object): self.dialog_last_access = time.time() return self._dialog + def nyan(self, cont, *args, **kwargs): + (lines, cols) = get_screen_size() + print "\033[48;5;17m" + print " "*(lines * cols) + cols = int(min(cols/2, 65)) + lines = int(lines) -1 + cmd = "/usr/bin/nyancat -W %s -H %s" % (cols, lines) + os.system(cmd) + raise Continue(cont) + + @tailcaller def handle_dialog(self, cancel_cont, box, *args): ctrlC=False @@ -2469,9 +2488,184 @@ les valeurs valident sont : self.dialog.msgbox("todo", width=0, height=0) return cont - def proprio_vente(self, proprio, cont): - self.dialog.msgbox("todo", width=0, height=0) - return cont + @tailcaller + def proprio_vente_set(self, article, cont): + def box(): + if article['pu'] == '*': + return self.dialog.inputbox(title="Montant pour %s ?" % article['designation'], + text="", init=str(article.get('nombre','')), timeout=self.timeout, width=70) + else: + return self.dialog.inputbox(title="Nombre de %s ?" % article['designation'], + text="", timeout=self.timeout, init=str(article.get('nombre','1')), width=70) + def todo(article, output, cont): + article['nombre']=output + # Il faut entrer quelque chose + if not output: + raise ValueError("Merci d'entrer une valeur") + # Vérification des centimes + if article['pu'] == '*' and '.' in output: + if len(output.split('.', 1)[1])>2: + raise ValueError("Les centimes, c'est seulement deux chiffres après la virgule") + typ = float if article['pu'] == '*' else int + # Vérification du type de l'entré + try: + output=typ(output) + except ValueError: + raise ValueError("Merci d'entrez seulement des nombres") + # On définis le nombre d'entrée. Pour pu=* il y aura du trairement à faire + # avant de générer la facture : mettre pu à nombre et nombre à 1 + # on le met comme ça pour pouvoir naviger aisément entre les écrans dialog + article['nombre'] = output + return article + + (code, output) = self.handle_dialog(cont, box) + self_cont = TailCall(self.proprio_vente_set, article=article, cont=cont) + return self.handle_dialog_result( + code=code, + output=output, + cancel_cont=cont, + error_cont=self_cont, + codes_todo=[([self.dialog.DIALOG_OK], todo, [article, output, cont])] + ) + + @tailcaller + def proprio_vente(self, proprio, cont, tags=[], tag_paiment=None, to_set=[], have_set=[]): + box_paiement = { + "liquide" : "Espèces", + "cheque" : "Chèque", + "solde" : "Solde Crans (actuel : %s€)", + } + + def box_choose_item(tags): + choices = [] + for code, article in gestion.config.factures.items.items(): + choices.append((code, u"%s%s" % (article['designation'], (u' (%s€)' % article['pu']) if article['pu'] != '*' else ""), 1 if code in tags else 0)) + return self.dialog.checklist( + text="", + title="Vente de truc à %s %s" % (proprio.get("prenom", [''])[0], proprio["nom"][0]), + choices=choices, + timeout=self.timeout) + + def box_choose_paiment(tag, articles): + box_paiement_order = ["liquide", "cheque"] + if "cransAccount" in proprio['objectClass']: + if not "SOLDE" in [art['code'] for art in articles]: + box_paiement_order.append("solde") + box_paiement["solde"] = box_paiement["solde"] % proprio["solde"][0] + choices = [] + for key in box_paiement_order: + choices.append((key, box_paiement[key], 1 if key == tag else 0)) + return self.dialog.radiolist( + text="", + title="Choix d'un mode de paiement pour %s %s" % (proprio.get("prenom", [''])[0], proprio["nom"][0]), + choices=choices, + timeout=self.timeout) + + def choose_item(proprio, tags, articles, self_cont): + to_set=[] + for tag in tags: + articles[tag]['code']=tag + to_set.append(articles[tag]) + raise Continue(self_cont(to_set=to_set, have_set=[])) + + def number_of_items(to_set, have_set, self_cont): + # Où faut-il aller si l'utilisateur appuis sur annuler + if not have_set: + lcont = self_cont(to_set=[]) + else: + lcont = self_cont(to_set=[have_set[-1]] + to_set, have_set=have_set[:-1]) + art = self.proprio_vente_set(to_set[0], cont=lcont) + if not to_set[1:]: + total = 0 + line=1 + text=u"Résumé :\n" + for article in have_set + [art]: + if article['pu'] == '*': + total += article['nombre'] + text+=u" * %s pour %s€\n" % (article['designation'], article['nombre']) + else: + total += article['nombre']*article['pu'] + text+=u" * %dx %s à %s€\n" % (article['nombre'], article['designation'], article['pu']) + line+=1 + text+=u"Total à payer : %s€" % total + self.dialog.msgbox(text=text, + title="Résumé de la facture à payer", + width=70, height=5+line, timeout=self.timeout) + return self_cont(to_set=to_set[1:], have_set=have_set + [art]) + + def choose_paiment(have_set, tag, proprio, lcont, self_cont, cont): + if not tag: + raise ValueError("Il faut choisir un moyen de paiement") + code, comment = self.dialog.inputbox(text="Détail pour les espèce, nom de la note ou banque du chèque", title="Commentaire", width=70, timeout=self.timeout) + if code != self.dialog.DIALOG_OK: + raise Continue(self_cont) + if not comment: + raise ValueError("Commentaire nécessaire") + articles = copy.deepcopy(have_set) + for article in articles: + if article['pu'] == '*': + article['pu'] = article['nombre'] + article['nombre'] = 1 + + with self.conn.newFacture(proprio.dn, {}) as facture: + facture['modePaiement']=unicode(tag, 'utf-8') + facture['article']=articles + facture['info']=unicode(comment, 'utf-8') + if self.confirm_item(item=facture, + text=u"Le paiement de %s€ a-t-il bien été reçu (mode : %s) ?\n" % (facture.total(), tag), + 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() + arts = ["%s %s" % (art['nombre'], art['designation']) for art in facture['article'] if art['code'] != 'SOLDE'] + if arts: + self.dialog.msgbox( + text=u"Vous pouvez remettre à l'adherent les articles (si se sont des articles) suivant :\n * %s" % '\n * '.join(arts), + title=u"Vente terminée", + width=0, height=0, timeout=self.timeout) + if tag == "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 [a for a in facture['article'] if art['code'] == 'SOLDE']: + self.dialog.msgbox(text=u"Le solde de l'adhérent à bien été crédité", title="Solde crédité", width=0, height=0, timeout=self.timeout) + else: + self.dialog.msgbox(text=u"Le paiement n'ayant pas été reçue\nla vente est annulée", title="Annulation de la vente", width=0, height=0, timeout=self.timeout) + raise Continue(cont) + + self_cont=TailCall(self.proprio_vente, proprio=proprio, cont=cont, tags=tags, tag_paiment=tag_paiment, to_set=to_set, have_set=have_set) + # S'il y a des article dont il faut définir la quantité + if to_set: + return self.handle_dialog_result( + code=self.dialog.DIALOG_OK, + output=None, + cancel_cont=None, + error_cont=self_cont, + codes_todo=[([self.dialog.DIALOG_OK], number_of_items, [to_set, have_set, self_cont])] + ) + # Sinon, si tous les quantités de tous les articles sont définis + elif have_set: + lcont = self_cont.copy() + lcont(to_set=[have_set[-1]] + to_set, have_set=have_set[:-1]) + (code, tag) = self.handle_dialog(lcont, box_choose_paiment, tag_paiment, have_set) + self_cont=self_cont(tag_paiment=tag) + lcont(tag_paiment=tag) + return self.handle_dialog_result( + code=code, + output=tag, + cancel_cont=lcont, + error_cont=self_cont, + codes_todo=[([self.dialog.DIALOG_OK], choose_paiment, [have_set, tag, proprio, lcont, self_cont, cont])] + ) + # Sinon, on propose des articles à chosir + else: + (code, tags) = self.handle_dialog(cont, box_choose_item, tags) + self_cont=self_cont(tags=tags, have_set=[], to_set=[], tag_paiment=None) + return self.handle_dialog_result( + code=code, + output=tags, + cancel_cont=cont, + error_cont=self_cont, + codes_todo=[([self.dialog.DIALOG_OK], choose_item, [proprio, tags, copy.deepcopy(gestion.config.factures.items), self_cont])] + ) def create_adherent(self, cont): def mycont(adherent=None, **kwargs): @@ -2561,7 +2755,7 @@ les valeurs valident sont : 'aMC': {'text':"Ajouter une machine à un club", 'callback': self.create_machine_club}, #'dC' : {'text':"Détruire un club", 'callback': self.delete_club}, 'aKM': {'text':"Ajouter une machine à l'association", 'callback': self.create_machine_crans}, - '' : {'text':"---------------------------------------",'callback': None}, + '' : {'text':"---------------------------------------",'callback': self.nyan}, } ### Les clef qui n'existe pas sont toute renvoyé sur la clef '' #menu_order = ["aA", "mA", "aMA", "dA", "", "mM", "dM", " ", "aC", "mC", "aMC", "dC", " ", "aKM"]