From fa6fc9263cdea5f4e132c0f22803c32a95125a53 Mon Sep 17 00:00:00 2001 From: Jonas 12t Date: Fri, 29 Oct 2021 12:00:57 +0400 Subject: [PATCH] Moteur de pre_save des models --- DjangoFiles/BaseBillet/models.py | 274 ++++++++++++++---- DjangoFiles/PaiementStripe/models.py | 4 +- DjangoFiles/PaiementStripe/views.py | 8 +- .../templates/html5up-dimension/index.html | 2 - 4 files changed, 231 insertions(+), 57 deletions(-) diff --git a/DjangoFiles/BaseBillet/models.py b/DjangoFiles/BaseBillet/models.py index 6bac8fe..3a3d633 100644 --- a/DjangoFiles/BaseBillet/models.py +++ b/DjangoFiles/BaseBillet/models.py @@ -447,8 +447,14 @@ class LigneArticle(models.Model): return _('no stripe send') -@receiver(post_save, sender=LigneArticle) -def check_status_stripe(sender, instance: LigneArticle, created, **kwargs): +@receiver(pre_save, sender=LigneArticle) +def trigger_LigneArticle(sender, instance: LigneArticle, update_fields=None, **kwargs): + # if not created + if not instance._state.adding: + old_instance = sender.objects.get(pk=instance.pk) + new_instance = pre_save_signal_status(old_instance, instance) + + ''' if instance.paiement_stripe: logger.info(f"Trigger LigneArticle {instance.status}") if instance.paiement_stripe.status != Paiement_stripe.VALID: @@ -469,66 +475,232 @@ def check_status_stripe(sender, instance: LigneArticle, created, **kwargs): f"Trigger LigneArticle {instance} check_status_stripe Passage de {instance.paiement_stripe} {instance.paiement_stripe.status} à VALID") instance.paiement_stripe.status = Paiement_stripe.VALID instance.paiement_stripe.save() + ''' @receiver(pre_save, sender=Paiement_stripe) def trigger_paiement_stripe(sender, instance: Paiement_stripe, update_fields=None, **kwargs): - # si l'instance vient d'être créé, ne rien faire : - if instance.pk is None: - pass - else: - if instance.status == Paiement_stripe.PAID: - logger.info(f"trigger_paiement_stripe {instance} PAID") - paiementStripe = instance - - data_pour_serveur_cashless = {'uuid_commande': paiementStripe.uuid} - for ligne_article in paiementStripe.lignearticle_set.exclude(status=LigneArticle.VALID): - if ligne_article.carte: - data_pour_serveur_cashless['uuid'] = ligne_article.carte.uuid - - if ligne_article.price.product.categorie_article == Product.RECHARGE_CASHLESS: - data_pour_serveur_cashless['recharge_qty'] = ligne_article.price.prix - - if ligne_article.price.product.categorie_article == Product.ADHESION: - data_pour_serveur_cashless['tarif_adhesion'] = ligne_article.price.prix - - logger.info( - f"trigger_paiement_stripe, ligne_article : {ligne_article.qty} x {ligne_article.price} payé ! status = PAID") - ligne_article.status = LigneArticle.PAID - ligne_article.save() + # if not create + if not instance._state.adding: + old_instance = sender.objects.get(pk=instance.pk) + new_instance = pre_save_signal_status(old_instance, instance) + ''' # Si il y a une reservation, on a la met en payée if instance.reservation: if instance.reservation.status not in [Reservation.PAID, Reservation.VALID]: logger.info(f"trigger_paiement_stripe, reservation : {instance.reservation} payé ! status = PAID") instance.reservation.status = Reservation.PAID instance.reservation.save() + ''' - # si il y a des données a envoyer au serveur cashless : - if len(data_pour_serveur_cashless) > 1: - sess = requests.Session() - configuration = Configuration.get_solo() - r = sess.post( - f'{configuration.server_cashless}/api/billetterie_endpoint', - headers={ - 'Authorization': f'Api-Key {configuration.key_cashless}' - }, - data=data_pour_serveur_cashless, - ) - sess.close() - logger.info( - f"{timezone.now()} demande au serveur cashless pour un rechargement. réponse : {r.status_code} ") +######################################################################## +######################## SIGNAL PRE & POST SAVE ######################## +######################################################################## - if r.status_code == 200: - # la commande a été envoyé au serveur cashless et validé. - for ligne_article in paiementStripe.lignearticle_set.filter( - Q(price__product__categorie_article=Product.RECHARGE_CASHLESS) | - Q(price__product__categorie_article=Product.ADHESION)): - logger.info( - f'réponse serveur cashless ok : on passe {ligne_article} {ligne_article.status} -> VALID') - ligne_article.status = LigneArticle.VALID - ligne_article.save() - else: - logger.error( - f"erreur réponse serveur cashless {r.status_code} {r.text} pour paiement stripe {instance}") + +######################## TRIGGER LIGNE ARTICLE ######################## + +# post_save ici nécéssaire pour mettre a jour le status du paiement stripe en validé +# si toutes les lignes articles sont VALID. +@receiver(post_save, sender=LigneArticle) +def set_paiement_and_reservation_valid(sender, instance: LigneArticle, **kwargs): + if instance.status == LigneArticle.VALID: + lignes_dans_paiement_stripe = instance.paiement_stripe.lignearticle_set.all() + if len(lignes_dans_paiement_stripe) == len(lignes_dans_paiement_stripe.filter(status=LigneArticle.VALID)): + # on passe le status du paiement stripe en VALID + logger.info(f" TRIGGER LIGNE ARTICLE set_paiement_and_reservation_valid {instance.price} " + f"paiement stripe {instance.paiement_stripe} {instance.paiement_stripe.status} à VALID") + instance.paiement_stripe.status = Paiement_stripe.VALID + instance.paiement_stripe.save() + + +def check_paid(old_instance, new_instance): + # Type : + old_instance: LigneArticle + new_instance: LigneArticle + logger.info(f" TRIGGER LIGNE ARTICLE check_paid {old_instance.price}") + + if new_instance.price.product.categorie_article in \ + [Product.RECHARGE_CASHLESS, Product.ADHESION]: + send_to_cashless(new_instance) + + +def send_to_cashless(instance): + # Type : + instance: LigneArticle + + logger.info(f" send_to_cashless {instance.price}") + data_for_cashless = {'uuid_commande': instance.paiement_stripe.uuid} + data_for_cashless['uuid'] = instance.carte.uuid + + if instance.price.product.categorie_article == Product.RECHARGE_CASHLESS: + data_for_cashless['recharge_qty'] = instance.price.prix + + if instance.price.product.categorie_article == Product.ADHESION: + data_for_cashless['tarif_adhesion'] = instance.price.prix + + # si il y a des données a envoyer au serveur cashless : + sess = requests.Session() + configuration = Configuration.get_solo() + r = sess.post( + f'{configuration.server_cashless}/api/billetterie_endpoint', + headers={ + 'Authorization': f'Api-Key {configuration.key_cashless}' + }, + data=data_for_cashless, + ) + + sess.close() + logger.info( + f" demande au serveur cashless pour un rechargement. réponse : {r.status_code} ") + + if r.status_code == 200: + instance.status = LigneArticle.VALID + else: + logger.error( + f"erreur réponse serveur cashless {r.status_code} {r.text} pour paiement stripe {instance.price} uuid {instance.uuid}") + + +######################## TRIGGER PAIEMENT STRIPE ######################## + + +def set_ligne_article_paid(old_instance, new_instance): + # Type : + old_instance: Paiement_stripe + new_instance: Paiement_stripe + + logger.info(f" TRIGGER PAIEMENT STRIPE set_ligne_article_paid {old_instance}.") + logger.info(f" On passe toutes les lignes d'article non validées en payées !") + + lignes_article = new_instance.lignearticle_set.exclude(status=LigneArticle.VALID) + for ligne_article in lignes_article: + logger.info(f" {ligne_article.price} {ligne_article.status} to P]") + ligne_article.status = LigneArticle.PAID + ligne_article.save() + + # si ya une reservation, on la met aussi en payée : + if new_instance.reservation: + new_instance.reservation.status = Reservation.PAID + new_instance.reservation.save() + + +def expire_paiement_stripe(old_instance, new_instance): + logger.info(f" TRIGGER PAIEMENT STRIPE expire_paiement_stripe {old_instance.status} to {new_instance.status}") + pass + + +def valide_stripe_paiement(old_instance, new_instance): + logger.info(f" TRIGGER PAIEMENT STRIPE valide_stripe_paiement {old_instance.status} to {new_instance.status}") + pass + +######################## TRIGGER RESERVATION ######################## + + +def send_billet_to_mail(old_instance, new_instance): + logger.info(f" TRIGGER RESERVATION send_billet_to_mail {old_instance.status} to {new_instance.status}") + pass + + +######################## MOTEUR TRIGGER ######################## + +def error_regression(old_instance, new_instance): + logger.info(f"models_trigger erreur_regression {old_instance.status} to {new_instance.status}") + logger.error(f"######################## error_regression ########################") + # raise Exception('Regression de status impossible.') + pass + + +# def pass(old_instance, new_instance): + +# On déclare les transitions possibles entre différents etats des statuts. +# Exemple première ligne : Si status passe de PENDING vers PAID, alors on lance set_ligne_article_paid +class Transitions(): + '''''' + ''' + Reservation choices : + (CANCELED, _('Annulée')), + (UNPAID, _('Non payée')), + (PAID, _('Payée')), + (VALID, _('Validée')), + ''' + RESERVATION = { + Reservation.UNPAID: { + Reservation.PAID : send_billet_to_mail + }, + Reservation.PAID: { + LigneArticle.PAID: send_billet_to_mail, + '_else_': error_regression, + }, + Reservation.VALID: { + '_all_': error_regression, + } + } + ''' + Paiement_stripe choices : + (NON, 'Lien de paiement non créé'), + (OPEN, 'Envoyée a Stripe'), + (PENDING, 'En attente de paiement'), + (EXPIRE, 'Expiré'), + (PAID, 'Payée'), + (VALID, 'Payée et validée'), # envoyé sur serveur cashless + (CANCELED, 'Annulée'), + ''' + PAIEMENT_STRIPE = { + Paiement_stripe.PENDING: { + Paiement_stripe.PAID: set_ligne_article_paid, + Paiement_stripe.EXPIRE: expire_paiement_stripe, + Paiement_stripe.CANCELED: expire_paiement_stripe, + }, + Paiement_stripe.PAID: { + Paiement_stripe.PAID: set_ligne_article_paid, + Paiement_stripe.VALID: valide_stripe_paiement, + '_else_': error_regression, + }, + Paiement_stripe.VALID: { + '_all_': error_regression, + } + } + ''' + LigneArticle Choices : + (CANCELED, _('Annulée')), + (UNPAID, _('Non payée')), + (PAID, _('Payée')), + (VALID, _('Validée par serveur cashless')), + ''' + LIGNEARTICLE = { + LigneArticle.UNPAID: { + LigneArticle.PAID: check_paid, + }, + LigneArticle.PAID: { + LigneArticle.PAID: check_paid, + # LigneArticle.VALID: valide_stripe_paiement, + '_else_': error_regression, + }, + LigneArticle.VALID: { + '_all_': error_regression, + } + } + + +def pre_save_signal_status(old_instance, new_instance): + # import ipdb; ipdb.set_trace() + sender_str = old_instance.__class__.__name__.upper() + dict_transition = getattr(Transitions, f"{sender_str}", None) + if dict_transition: + logger.info(f"dict_transition {sender_str} {new_instance} : {old_instance.status} to {new_instance.status}") + transitions = dict_transition.get(old_instance.status, None) + if transitions: + # Par ordre de préférence : + trigger_function = transitions.get('_all_', ( + transitions.get(new_instance.status, ( + transitions.get('_else_', None) + )))) + + if trigger_function: + # import ipdb; ipdb.set_trace() + + if not callable(trigger_function): + raise Exception(f'Fonction {trigger_function} is not callable. Disdonc !?') + trigger_function(old_instance, new_instance) diff --git a/DjangoFiles/PaiementStripe/models.py b/DjangoFiles/PaiementStripe/models.py index 4662ada..61ab053 100644 --- a/DjangoFiles/PaiementStripe/models.py +++ b/DjangoFiles/PaiementStripe/models.py @@ -17,7 +17,9 @@ class Paiement_stripe(models.Model): id_stripe = models.CharField(max_length=80, blank=True, null=True) metadata_stripe = JSONField(blank=True, null=True) - order_date = models.DateTimeField(auto_now=True, verbose_name="Date") + order_date = models.DateTimeField(auto_now_add=True, verbose_name="Date") + last_action = models.DateTimeField(auto_now=True) + user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT, blank=True, null=True) NON, OPEN, PENDING, EXPIRE, PAID, VALID, CANCELED = 'N', 'O', 'W', 'E', 'P', 'V', 'C' diff --git a/DjangoFiles/PaiementStripe/views.py b/DjangoFiles/PaiementStripe/views.py index a68477a..f7a3316 100644 --- a/DjangoFiles/PaiementStripe/views.py +++ b/DjangoFiles/PaiementStripe/views.py @@ -184,13 +184,15 @@ class retour_stripe(View): elif checkout_session.payment_status == "paid": paiement_stripe.status = Paiement_stripe.PAID logger.info(f"retour_stripe - checkout_session.payment_status : {checkout_session.payment_status}") + + # le .save() lance le process pre_save BaseBillet.models.send_to_cashless # qui modifie le status de chaque ligne # et envoie les informations au serveur cashless. # si validé par le serveur cashless, alors la ligne sera VALID. # Si toute les lignes sont VALID, le paiement_stripe sera aussi VALID # grace au post_save BaseBillet.models.check_status_stripe - + paiement_stripe.last_action = timezone.now() paiement_stripe.save() else: @@ -221,8 +223,8 @@ class retour_stripe(View): if ligne_article.carte: messages.error(request, f"Un problème de validation de paiement a été detecté. " - f"Merci de vérifier votre moyen de paiement ou contactez un responsable.") - return HttpResponseRedirect(f"/qr/{ligne_article.carte.uuid}#error") + f"Merci de vérifier votre moyen de paiement et/ou contactez un responsable.") + return HttpResponseRedirect(f"/qr/{ligne_article.carte.uuid}#erreurpaiement") elif paiement_stripe.source == Paiement_stripe.API_BILLETTERIE : return HttpResponse( diff --git a/DjangoFiles/QrcodeCashless/templates/html5up-dimension/index.html b/DjangoFiles/QrcodeCashless/templates/html5up-dimension/index.html index 6186873..9d97139 100644 --- a/DjangoFiles/QrcodeCashless/templates/html5up-dimension/index.html +++ b/DjangoFiles/QrcodeCashless/templates/html5up-dimension/index.html @@ -313,8 +313,6 @@

ERREUR

-

Le paiement n'a pas fonctionné.

-

Vérifiez votre moyen de paiement ou contacter un administrateur

{% if messages %} {% for message in messages %}

{{ message }}