diff --git a/DjangoFiles/Administration/admin_tenant.py b/DjangoFiles/Administration/admin_tenant.py index 3cab2c0..83205af 100644 --- a/DjangoFiles/Administration/admin_tenant.py +++ b/DjangoFiles/Administration/admin_tenant.py @@ -218,11 +218,12 @@ staff_admin_site.register(Billet, admin.ModelAdmin) class PaiementStripeAdmin(admin.ModelAdmin): list_display = ( - 'detail', + 'uuid_8', + 'user', 'total', 'order_date', - 'user', 'status', + 'articles', ) ordering = ('-order_date',) # readonly_fields = ( diff --git a/DjangoFiles/BaseBillet/models.py b/DjangoFiles/BaseBillet/models.py index 3157b27..c01330d 100644 --- a/DjangoFiles/BaseBillet/models.py +++ b/DjangoFiles/BaseBillet/models.py @@ -13,6 +13,7 @@ from stdimage.validators import MaxSizeValidator from django.db import connection from PaiementStripe.models import Paiement_stripe +from QrcodeCashless.models import CarteCashless from TiBillet import settings import stripe @@ -350,6 +351,7 @@ class LigneArticle(models.Model): uuid = models.UUIDField(primary_key=True, db_index=True, default=uuid.uuid4) reservation = models.ForeignKey(Reservation, on_delete=models.CASCADE, blank=True, null=True) article = models.ForeignKey(Article, on_delete=models.CASCADE, blank=True, null=True) + carte = models.ForeignKey(CarteCashless, on_delete=models.PROTECT, blank=True, null=True) billet = models.ForeignKey(Billet, on_delete=models.CASCADE, blank=True, null=True) qty = models.SmallIntegerField() paiement_stripe = models.ForeignKey(Paiement_stripe, on_delete=models.PROTECT, blank=True, null=True) diff --git a/DjangoFiles/PaiementStripe/models.py b/DjangoFiles/PaiementStripe/models.py index d992593..d54a93c 100644 --- a/DjangoFiles/PaiementStripe/models.py +++ b/DjangoFiles/PaiementStripe/models.py @@ -3,9 +3,6 @@ from django.contrib.postgres.fields import JSONField import uuid # Create your models here. from TiBillet import settings -from django.db.models.signals import post_save, pre_save -from django.dispatch import receiver -# from QrcodeCashless.views import postPaimentRecharge class Paiement_stripe(models.Model): @@ -36,8 +33,17 @@ class Paiement_stripe(models.Model): total = models.FloatField(default=0) + + def uuid_8(self): + return f"{self.uuid}".partition('-')[0] + def __str__(self): - return f"{self.detail} - {self.status}" + return self.uuid_8() + + def articles(self): + return " - ".join([ f"{ligne.article.name} {ligne.qty * ligne.article.prix }€" for ligne in self.lignearticle_set.all() ]) + + ''' RECEIVER PRESAVE DANS LE VIEW QRCODECASHELESS @receiver(pre_save, sender=Paiement_stripe) diff --git a/DjangoFiles/PaiementStripe/views.py b/DjangoFiles/PaiementStripe/views.py index c4c192b..9359fa9 100644 --- a/DjangoFiles/PaiementStripe/views.py +++ b/DjangoFiles/PaiementStripe/views.py @@ -12,7 +12,7 @@ from django.utils import timezone from django.views import View from AuthBillet.models import HumanUser -from BaseBillet.models import Configuration, Article, LigneArticle +from BaseBillet.models import Configuration, LigneArticle, Article from PaiementStripe.models import Paiement_stripe # from QrcodeCashless.views import postPaimentRecharge @@ -22,7 +22,7 @@ import logging logger = logging.getLogger(__name__) -class creation_checkout_stripe(): +class creation_paiement_stripe(): def __init__(self, email_paiement: str, @@ -38,7 +38,6 @@ class creation_checkout_stripe(): self.configuration = Configuration.get_solo() self.user = self._user_paiement() - self.detail = self._detail() self.total = self._total() self.metadata_json = json.dumps(self.metadata) self.paiement_stripe_db = self._paiement_stripe_db() @@ -51,6 +50,8 @@ class creation_checkout_stripe(): user_paiement, created = User.objects.get_or_create( email=self.email_paiement) + # On ne lie pas tout de suite la carte a l'user, + # on attendra une réponse positive du serveur cashless. if created: user_paiement: HumanUser user_paiement.client_source = connection.tenant @@ -65,26 +66,22 @@ class creation_checkout_stripe(): def _total(self): total = 0 for ligne in self.liste_ligne_article: - ligne: LigneArticle total += float(ligne.qty) * float(ligne.article.prix) return total - def _detail(self): - detail = "" - for ligne in self.liste_ligne_article: - ligne: LigneArticle - detail += f"{ligne.article}" - return detail - def _paiement_stripe_db(self): paiementStripeDb = Paiement_stripe.objects.create( user=self.user, - detail=self.detail, total=self.total, metadata_stripe=self.metadata_json, ) + for ligne_article in self.liste_ligne_article : + ligne_article: LigneArticle + ligne_article.paiement_stripe = paiementStripeDb + ligne_article.save() + return paiementStripeDb def _stripe_api_key(self): @@ -140,6 +137,27 @@ class creation_checkout_stripe(): return HttpResponseRedirect(self.checkout_session.url) + +# On vérifie que les métatada soient les meme dans la DB et chez Stripe. +def metatadata_valid(paiement_stripe_db: Paiement_stripe, checkout_session): + metadata_stripe_json = checkout_session.metadata + metadata_stripe = json.loads(str(metadata_stripe_json)) + + metadata_db_json = paiement_stripe_db.metadata_stripe + metadata_db = json.loads(metadata_db_json) + + try: + assert metadata_stripe == metadata_db + assert set(metadata_db.keys()) == set(metadata_stripe.keys()) + for key in set(metadata_stripe.keys()): + assert metadata_db[key] == metadata_stripe[key] + return True + except: + logger.error(f"{timezone.now()} " + f"retour_stripe {paiement_stripe_db.uuid} : " + f"metadata ne correspondent pas : {metadata_stripe} {metadata_db}") + return False + class retour_stripe(View): def get(self, request, uuid_stripe): @@ -155,50 +173,42 @@ class retour_stripe(View): if paiement_stripe.status != Paiement_stripe.VALID: checkout_session = stripe.checkout.Session.retrieve(paiement_stripe.id_stripe) - if checkout_session.payment_status == "unpaid": - paiement_stripe.status = Paiement_stripe.PENDING - if checkout_session.expires_at > datetime.now().timestamp(): - paiement_stripe.status = Paiement_stripe.EXPIRE - paiement_stripe.save() - elif checkout_session.payment_status == "paid": - # on vérifie si les infos sont cohérente avec la db : Never Trust Input :) - metadata_stripe_json = checkout_session.metadata - metadata_stripe = json.loads(str(metadata_stripe_json)) + # on vérfie que les metatada soient cohérente. #NTUI ! + if metatadata_valid(paiement_stripe , checkout_session): - metadata_db_json = paiement_stripe.metadata_stripe - metadata_db = json.loads(metadata_db_json) + if checkout_session.payment_status == "unpaid": + paiement_stripe.status = Paiement_stripe.PENDING + if checkout_session.expires_at > datetime.now().timestamp(): + paiement_stripe.status = Paiement_stripe.EXPIRE + paiement_stripe.save() - try: - assert metadata_stripe == metadata_db - assert set(metadata_db.keys()) == set(metadata_stripe.keys()) - for key in set(metadata_stripe.keys()): - assert metadata_db[key] == metadata_stripe[key] - except: - logger.error(f"{timezone.now()} " - f"retour_stripe {uuid_stripe} : " - f"metadata ne correspondent pas : {metadata_stripe} {metadata_db}") - raise Http404 - - paiement_stripe.status = Paiement_stripe.PAID - paiement_stripe.save() - # le .save() lance le process pre_save dans le view QrcodeCashless, qui peut modifier son status - paiement_stripe.refresh_from_db() - if paiement_stripe.status == Paiement_stripe.VALID : - messages.success(request, f"Paiement validé. Merci !") - return HttpResponseRedirect(f"/qr/{metadata_db.get('recharge_carte_uuid')}#success") + elif checkout_session.payment_status == "paid": + paiement_stripe.status = Paiement_stripe.PAID + # le .save() lance le process pre_save dans le view QrcodeCashless qui peut modifier son status + paiement_stripe.save() + else: + paiement_stripe.status = Paiement_stripe.CANCELED + paiement_stripe.save() else: - paiement_stripe.status = Paiement_stripe.CANCELED - paiement_stripe.save() + raise Http404 + # on vérifie que le status n'ai pas changé + paiement_stripe.refresh_from_db() if paiement_stripe.status == Paiement_stripe.VALID: - metadata_db_json = paiement_stripe.metadata_stripe - metadata_db = json.loads(metadata_db_json) - if metadata_db.get('recharge_carte_uuid'): - return HttpResponseRedirect(f"/qr/{metadata_db.get('recharge_carte_uuid')}#historique") + for ligne_article in paiement_stripe.lignearticle_set.all(): + if ligne_article.carte : + messages.success(request, f"Paiement validé. Merci !") + return HttpResponseRedirect(f"/qr/{ligne_article.carte.uuid}#success") + else : - return HttpResponse('Un problème de validation de paiement a été detecté. Merci de contacter un responsable.') + for ligne_article in paiement_stripe.lignearticle_set.all(): + if ligne_article.carte : + messages.error(request, f"Un problème de validation de paiement a été detecté. Merci de vérifier votre moyen de paiement ou contactez un responsable.") + return HttpResponseRedirect(f"/qr/{ligne_article.carte.uuid}#error") + + return HttpResponse('Un problème de validation de paiement a été detecté. Merci de vérifier votre moyen de paiement ou contactez un responsable.') # return HttpResponseRedirect("/") diff --git a/DjangoFiles/QrcodeCashless/migrations/0002_cartecashless_user.py b/DjangoFiles/QrcodeCashless/migrations/0002_cartecashless_user.py new file mode 100644 index 0000000..1f26501 --- /dev/null +++ b/DjangoFiles/QrcodeCashless/migrations/0002_cartecashless_user.py @@ -0,0 +1,21 @@ +# Generated by Django 2.2 on 2021-09-30 07:42 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('QrcodeCashless', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='cartecashless', + name='user', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/DjangoFiles/QrcodeCashless/models.py b/DjangoFiles/QrcodeCashless/models.py index 148380c..a69152c 100644 --- a/DjangoFiles/QrcodeCashless/models.py +++ b/DjangoFiles/QrcodeCashless/models.py @@ -5,6 +5,8 @@ from stdimage import StdImageField from stdimage.validators import MaxSizeValidator from Customers.models import Client as Customers_Client +from TiBillet import settings + class Detail(models.Model): img = StdImageField(upload_to='images/', @@ -45,4 +47,5 @@ class CarteCashless(models.Model): detail = models.ForeignKey(Detail, on_delete=models.CASCADE, null=True, blank=True) + user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT, null=True, blank=True) diff --git a/DjangoFiles/QrcodeCashless/templates/html5up-dimension/index.html b/DjangoFiles/QrcodeCashless/templates/html5up-dimension/index.html index a58e5e6..51b934f 100644 --- a/DjangoFiles/QrcodeCashless/templates/html5up-dimension/index.html +++ b/DjangoFiles/QrcodeCashless/templates/html5up-dimension/index.html @@ -22,16 +22,11 @@