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):
list_display = (
'detail',
'uuid_8',
'user',
'total',
'order_date',
'user',
'status',
'articles',
)
ordering = ('-order_date',)
# readonly_fields = (

View File

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

View File

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

View File

@ -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,6 +173,10 @@ class retour_stripe(View):
if paiement_stripe.status != Paiement_stripe.VALID:
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":
paiement_stripe.status = Paiement_stripe.PENDING
if checkout_session.expires_at > datetime.now().timestamp():
@ -162,43 +184,31 @@ class retour_stripe(View):
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))
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
# le .save() lance le process pre_save dans le view QrcodeCashless qui peut modifier son status
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:
paiement_stripe.status = Paiement_stripe.CANCELED
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:
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("/")

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 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)

View File

@ -22,16 +22,11 @@
<!-- Header -->
<header id="header">
{# <div class="logo">#}
{# <span class="icon fa-gem"></span>#}
{# </div>#}
<div class="content">
<div class="inner">
<h1>Carte Cashless</h1>
<h1>{{ numero_carte }}</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>
<nav>
@ -81,8 +76,8 @@
<label for="email">Email</label>
{% if email %}
<label for="email">Vérifiez votre adresse Email</label>
<input type="email" name="email" id="Email" required="True" value="{{ email }}"
style="text-transform: lowercase;"/>
<input type="email" name="email" id="Email" required="True"
style="text-transform: lowercase;" value="{{ email }}" />
{% else %}
<label for="email">Entrez votre adresse Email</label>
<input type="email" name="email" id="email" required="True"
@ -267,7 +262,7 @@
{% for tarif in tarifs_adhesion %}
<ul class="actions">
<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>
{% endfor %}
<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 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 django.db.models.signals import pre_save
from django.dispatch import receiver
import logging
logger = logging.getLogger(__name__)
@ -172,6 +171,7 @@ class index_scan(View):
ligne_article_recharge = LigneArticle.objects.create(
article=art,
qty=montant_recharge,
carte=carte,
)
ligne_articles.append(ligne_article_recharge)
@ -183,21 +183,23 @@ class index_scan(View):
ligne_article_recharge = LigneArticle.objects.create(
article=art_adhesion,
qty=1,
carte=carte,
)
ligne_articles.append(ligne_article_recharge)
metadata['pk_adhesion'] = str(art_adhesion.pk)
if len(ligne_articles) > 0:
new_checkout_session = creation_checkout_stripe(
new_paiement_stripe = creation_paiement_stripe(
email_paiement=data.get('email'),
liste_ligne_article=ligne_articles,
metadata=metadata,
absolute_domain=request.build_absolute_uri().partition('/qr')[0],
)
if new_checkout_session.is_valid():
print(new_checkout_session.checkout_session.stripe_id)
return new_checkout_session.redirect_to_stripe()
if new_paiement_stripe.is_valid():
print(new_paiement_stripe.checkout_session.stripe_id)
return new_paiement_stripe.redirect_to_stripe()
# Email seul sans montant, c'est une adhésion
elif data.get('email'):
@ -256,29 +258,20 @@ def changement_paid_to_valid(sender, instance: Paiement_stripe, update_fields=No
else:
paiementStripe = instance
if paiementStripe.status == Paiement_stripe.PAID:
# old_instance = Paiement_stripe.objects.get(pk=paiementStripe.pk)
# 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 = {'uuid_commande': paiementStripe.uuid}
data_pour_serveur_cashless = {
'uuid': carte.uuid,
'uuid_commande': paiementStripe.uuid,
}
for ligne_article in paiementStripe.lignearticle_set.all():
if ligne_article.carte :
data_pour_serveur_cashless['uuid'] = ligne_article.carte.uuid
if recharge_carte_montant:
data_pour_serveur_cashless['recharge_qty'] = float(recharge_carte_montant)
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.RECHARGE_CASHLESS :
data_pour_serveur_cashless['recharge_qty'] = float(ligne_article.qty)
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()
configuration = Configuration.get_solo()
r = sess.post(
@ -296,14 +289,3 @@ def changement_paid_to_valid(sender, instance: Paiement_stripe, update_fields=No
if r.status_code == 200:
# la commande a été envoyé au serveur cashless et 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')
'''