don't use metadata, use database !

This commit is contained in:
Jonas 12t 2021-09-30 14:32:05 +04:00
parent 3ad6135f60
commit 8b84f47656
8 changed files with 118 additions and 98 deletions

View File

@ -218,11 +218,12 @@ staff_admin_site.register(Billet, admin.ModelAdmin)
class PaiementStripeAdmin(admin.ModelAdmin): class PaiementStripeAdmin(admin.ModelAdmin):
list_display = ( list_display = (
'detail', 'uuid_8',
'user',
'total', 'total',
'order_date', 'order_date',
'user',
'status', 'status',
'articles',
) )
ordering = ('-order_date',) ordering = ('-order_date',)
# readonly_fields = ( # readonly_fields = (

View File

@ -13,6 +13,7 @@ from stdimage.validators import MaxSizeValidator
from django.db import connection from django.db import connection
from PaiementStripe.models import Paiement_stripe from PaiementStripe.models import Paiement_stripe
from QrcodeCashless.models import CarteCashless
from TiBillet import settings from TiBillet import settings
import stripe import stripe
@ -350,6 +351,7 @@ class LigneArticle(models.Model):
uuid = models.UUIDField(primary_key=True, db_index=True, default=uuid.uuid4) uuid = models.UUIDField(primary_key=True, db_index=True, default=uuid.uuid4)
reservation = models.ForeignKey(Reservation, on_delete=models.CASCADE, blank=True, null=True) reservation = models.ForeignKey(Reservation, on_delete=models.CASCADE, blank=True, null=True)
article = models.ForeignKey(Article, 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) billet = models.ForeignKey(Billet, on_delete=models.CASCADE, blank=True, null=True)
qty = models.SmallIntegerField() qty = models.SmallIntegerField()
paiement_stripe = models.ForeignKey(Paiement_stripe, on_delete=models.PROTECT, blank=True, null=True) paiement_stripe = models.ForeignKey(Paiement_stripe, on_delete=models.PROTECT, blank=True, null=True)

View File

@ -3,9 +3,6 @@ from django.contrib.postgres.fields import JSONField
import uuid import uuid
# Create your models here. # Create your models here.
from TiBillet import settings 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): class Paiement_stripe(models.Model):
@ -36,8 +33,17 @@ class Paiement_stripe(models.Model):
total = models.FloatField(default=0) total = models.FloatField(default=0)
def uuid_8(self):
return f"{self.uuid}".partition('-')[0]
def __str__(self): 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 PRESAVE DANS LE VIEW QRCODECASHELESS
@receiver(pre_save, sender=Paiement_stripe) @receiver(pre_save, sender=Paiement_stripe)

View File

@ -12,7 +12,7 @@ from django.utils import timezone
from django.views import View from django.views import View
from AuthBillet.models import HumanUser 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 PaiementStripe.models import Paiement_stripe
# from QrcodeCashless.views import postPaimentRecharge # from QrcodeCashless.views import postPaimentRecharge
@ -22,7 +22,7 @@ import logging
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class creation_checkout_stripe(): class creation_paiement_stripe():
def __init__(self, def __init__(self,
email_paiement: str, email_paiement: str,
@ -38,7 +38,6 @@ class creation_checkout_stripe():
self.configuration = Configuration.get_solo() self.configuration = Configuration.get_solo()
self.user = self._user_paiement() self.user = self._user_paiement()
self.detail = self._detail()
self.total = self._total() self.total = self._total()
self.metadata_json = json.dumps(self.metadata) self.metadata_json = json.dumps(self.metadata)
self.paiement_stripe_db = self._paiement_stripe_db() self.paiement_stripe_db = self._paiement_stripe_db()
@ -51,6 +50,8 @@ class creation_checkout_stripe():
user_paiement, created = User.objects.get_or_create( user_paiement, created = User.objects.get_or_create(
email=self.email_paiement) 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: if created:
user_paiement: HumanUser user_paiement: HumanUser
user_paiement.client_source = connection.tenant user_paiement.client_source = connection.tenant
@ -65,26 +66,22 @@ class creation_checkout_stripe():
def _total(self): def _total(self):
total = 0 total = 0
for ligne in self.liste_ligne_article: for ligne in self.liste_ligne_article:
ligne: LigneArticle
total += float(ligne.qty) * float(ligne.article.prix) total += float(ligne.qty) * float(ligne.article.prix)
return total 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): def _paiement_stripe_db(self):
paiementStripeDb = Paiement_stripe.objects.create( paiementStripeDb = Paiement_stripe.objects.create(
user=self.user, user=self.user,
detail=self.detail,
total=self.total, total=self.total,
metadata_stripe=self.metadata_json, 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 return paiementStripeDb
def _stripe_api_key(self): def _stripe_api_key(self):
@ -140,6 +137,27 @@ class creation_checkout_stripe():
return HttpResponseRedirect(self.checkout_session.url) 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): class retour_stripe(View):
def get(self, request, uuid_stripe): def get(self, request, uuid_stripe):
@ -155,6 +173,10 @@ class retour_stripe(View):
if paiement_stripe.status != Paiement_stripe.VALID: if paiement_stripe.status != Paiement_stripe.VALID:
checkout_session = stripe.checkout.Session.retrieve(paiement_stripe.id_stripe) checkout_session = stripe.checkout.Session.retrieve(paiement_stripe.id_stripe)
# on vérfie que les metatada soient cohérente. #NTUI !
if metatadata_valid(paiement_stripe , checkout_session):
if checkout_session.payment_status == "unpaid": if checkout_session.payment_status == "unpaid":
paiement_stripe.status = Paiement_stripe.PENDING paiement_stripe.status = Paiement_stripe.PENDING
if checkout_session.expires_at > datetime.now().timestamp(): if checkout_session.expires_at > datetime.now().timestamp():
@ -162,43 +184,31 @@ class retour_stripe(View):
paiement_stripe.save() paiement_stripe.save()
elif checkout_session.payment_status == "paid": 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))
metadata_db_json = paiement_stripe.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]
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.status = Paiement_stripe.PAID
# le .save() lance le process pre_save dans le view QrcodeCashless qui peut modifier son status
paiement_stripe.save() 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")
else: else:
paiement_stripe.status = Paiement_stripe.CANCELED paiement_stripe.status = Paiement_stripe.CANCELED
paiement_stripe.save() paiement_stripe.save()
else:
raise Http404
# on vérifie que le status n'ai pas changé
paiement_stripe.refresh_from_db()
if paiement_stripe.status == Paiement_stripe.VALID: if paiement_stripe.status == Paiement_stripe.VALID:
metadata_db_json = paiement_stripe.metadata_stripe for ligne_article in paiement_stripe.lignearticle_set.all():
metadata_db = json.loads(metadata_db_json) if ligne_article.carte :
if metadata_db.get('recharge_carte_uuid'): messages.success(request, f"Paiement validé. Merci !")
return HttpResponseRedirect(f"/qr/{metadata_db.get('recharge_carte_uuid')}#historique") return HttpResponseRedirect(f"/qr/{ligne_article.carte.uuid}#success")
else : 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("/") # return HttpResponseRedirect("/")

View File

@ -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),
),
]

View File

@ -5,6 +5,8 @@ from stdimage import StdImageField
from stdimage.validators import MaxSizeValidator from stdimage.validators import MaxSizeValidator
from Customers.models import Client as Customers_Client from Customers.models import Client as Customers_Client
from TiBillet import settings
class Detail(models.Model): class Detail(models.Model):
img = StdImageField(upload_to='images/', 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) 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)

View File

@ -22,16 +22,11 @@
<!-- Header --> <!-- Header -->
<header id="header"> <header id="header">
{# <div class="logo">#}
{# <span class="icon fa-gem"></span>#}
{# </div>#}
<div class="content"> <div class="content">
<div class="inner"> <div class="inner">
<h1>Carte Cashless</h1> <h1>Carte Cashless</h1>
<h1>{{ numero_carte }}</h1> <h1>{{ numero_carte }}</h1>
<h1>{{ client_name }}</h1> <h1>{{ client_name }}</h1>
{# <p>A fully responsive site template designed by <a href="https://html5up.net">HTML5 UP</a> and released<br />#}
{# for free under the <a href="https://html5up.net/license">Creative Commons</a> license.</p>#}
</div> </div>
</div> </div>
<nav> <nav>
@ -81,8 +76,8 @@
<label for="email">Email</label> <label for="email">Email</label>
{% if email %} {% if email %}
<label for="email">Vérifiez votre adresse Email</label> <label for="email">Vérifiez votre adresse Email</label>
<input type="email" name="email" id="Email" required="True" value="{{ email }}" <input type="email" name="email" id="Email" required="True"
style="text-transform: lowercase;"/> style="text-transform: lowercase;" value="{{ email }}" />
{% else %} {% else %}
<label for="email">Entrez votre adresse Email</label> <label for="email">Entrez votre adresse Email</label>
<input type="email" name="email" id="email" required="True" <input type="email" name="email" id="email" required="True"
@ -267,7 +262,7 @@
{% for tarif in tarifs_adhesion %} {% for tarif in tarifs_adhesion %}
<ul class="actions"> <ul class="actions">
<li><a id="{{ tarif.name | slugify }}" href="#paiementadhesionenligne" <li><a id="{{ tarif.name | slugify }}" href="#paiementadhesionenligne"
class="button primary field">{{ tarif.name }} {{ tarif.prix }}€</a></li> class="button primary field">{{ tarif.name }} {{ tarif.prix | floatformat:2 | intcomma }}€</a></li>
</ul> </ul>
{% endfor %} {% endfor %}
<h4>Payer à l'acceuil de l'association avec un vrai humain :</h4> <h4>Payer à l'acceuil de l'association avec un vrai humain :</h4>

View File

@ -12,14 +12,13 @@ from rest_framework import status
from BaseBillet.models import Configuration, Article, LigneArticle from BaseBillet.models import Configuration, Article, LigneArticle
from PaiementStripe.models import Paiement_stripe from PaiementStripe.models import Paiement_stripe
from PaiementStripe.views import creation_checkout_stripe from PaiementStripe.views import creation_paiement_stripe
from QrcodeCashless.models import CarteCashless from QrcodeCashless.models import CarteCashless
from django.db.models.signals import pre_save from django.db.models.signals import pre_save
from django.dispatch import receiver from django.dispatch import receiver
import logging import logging
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -172,6 +171,7 @@ class index_scan(View):
ligne_article_recharge = LigneArticle.objects.create( ligne_article_recharge = LigneArticle.objects.create(
article=art, article=art,
qty=montant_recharge, qty=montant_recharge,
carte=carte,
) )
ligne_articles.append(ligne_article_recharge) ligne_articles.append(ligne_article_recharge)
@ -183,21 +183,23 @@ class index_scan(View):
ligne_article_recharge = LigneArticle.objects.create( ligne_article_recharge = LigneArticle.objects.create(
article=art_adhesion, article=art_adhesion,
qty=1, qty=1,
carte=carte,
) )
ligne_articles.append(ligne_article_recharge) ligne_articles.append(ligne_article_recharge)
metadata['pk_adhesion'] = str(art_adhesion.pk) metadata['pk_adhesion'] = str(art_adhesion.pk)
if len(ligne_articles) > 0: if len(ligne_articles) > 0:
new_checkout_session = creation_checkout_stripe( new_paiement_stripe = creation_paiement_stripe(
email_paiement=data.get('email'), email_paiement=data.get('email'),
liste_ligne_article=ligne_articles, liste_ligne_article=ligne_articles,
metadata=metadata, metadata=metadata,
absolute_domain=request.build_absolute_uri().partition('/qr')[0], absolute_domain=request.build_absolute_uri().partition('/qr')[0],
) )
if new_checkout_session.is_valid(): if new_paiement_stripe.is_valid():
print(new_checkout_session.checkout_session.stripe_id) print(new_paiement_stripe.checkout_session.stripe_id)
return new_checkout_session.redirect_to_stripe() return new_paiement_stripe.redirect_to_stripe()
# Email seul sans montant, c'est une adhésion # Email seul sans montant, c'est une adhésion
elif data.get('email'): elif data.get('email'):
@ -256,29 +258,20 @@ def changement_paid_to_valid(sender, instance: Paiement_stripe, update_fields=No
else: else:
paiementStripe = instance paiementStripe = instance
if paiementStripe.status == Paiement_stripe.PAID: if paiementStripe.status == Paiement_stripe.PAID:
# old_instance = Paiement_stripe.objects.get(pk=paiementStripe.pk) data_pour_serveur_cashless = {'uuid_commande': paiementStripe.uuid}
# print(f"on passe de {old_instance.status} à {paiementStripe.status}")
# on passe de non payé -> payé
metadata_db_json = paiementStripe.metadata_stripe
metadata_db = json.loads(metadata_db_json)
uuid_carte = metadata_db.get('recharge_carte_uuid')
recharge_carte_montant = metadata_db.get('recharge_carte_montant')
pk_adhesion = metadata_db.get('pk_adhesion')
if recharge_carte_montant or pk_adhesion:
carte = check_carte_local(uuid_carte)
data_pour_serveur_cashless = { for ligne_article in paiementStripe.lignearticle_set.all():
'uuid': carte.uuid, if ligne_article.carte :
'uuid_commande': paiementStripe.uuid, data_pour_serveur_cashless['uuid'] = ligne_article.carte.uuid
}
if recharge_carte_montant: if ligne_article.article.categorie_article == Article.RECHARGE_CASHLESS :
data_pour_serveur_cashless['recharge_qty'] = float(recharge_carte_montant) data_pour_serveur_cashless['recharge_qty'] = float(ligne_article.qty)
if pk_adhesion :
adhesion = Article.objects.get(pk=pk_adhesion)
data_pour_serveur_cashless['tarif_adhesion'] = adhesion.prix
if ligne_article.article.categorie_article == Article.ADHESION :
data_pour_serveur_cashless['tarif_adhesion'] = ligne_article.article.prix
# si il y a autre chose que uuid_commande :
if len(data_pour_serveur_cashless) > 1 :
sess = requests.Session() sess = requests.Session()
configuration = Configuration.get_solo() configuration = Configuration.get_solo()
r = sess.post( r = sess.post(
@ -296,14 +289,3 @@ def changement_paid_to_valid(sender, instance: Paiement_stripe, update_fields=No
if r.status_code == 200: if r.status_code == 200:
# la commande a été envoyé au serveur cashless et validé. # la commande a été envoyé au serveur cashless et validé.
paiementStripe.status = Paiement_stripe.VALID paiementStripe.status = Paiement_stripe.VALID
'''
# return HttpResponseRedirect(f'#success')
#
# elif paiementStripe.status == Paiement_stripe.VALID:
# messages.success(request, f"Le paiement a déja été validé.")
# return HttpResponseRedirect(f'#historique')
#
# return HttpResponseRedirect(f'#erreurpaiement')
'''