signal return after stripe paiement ok
This commit is contained in:
parent
a6eff19fa2
commit
d1a22548cd
|
|
@ -5,11 +5,13 @@ import json
|
|||
from django.utils.translation import gettext, gettext_lazy as _
|
||||
from rest_framework.generics import get_object_or_404
|
||||
|
||||
import PaiementStripe
|
||||
from AuthBillet.models import TibilletUser, HumanUser
|
||||
from BaseBillet.models import Event, Price, Product, Reservation, Configuration, LigneArticle, Ticket, Paiement_stripe
|
||||
from PaiementStripe.views import creation_paiement_stripe
|
||||
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ProductSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
|
|
@ -265,9 +267,15 @@ class ReservationValidator(serializers.Serializer):
|
|||
)
|
||||
|
||||
if new_paiement_stripe.is_valid():
|
||||
reservation.paiement = new_paiement_stripe.paiement_stripe_db
|
||||
paiement_stripe : Paiement_stripe = new_paiement_stripe.paiement_stripe_db
|
||||
paiement_stripe.lignearticle_set.all().update(status=LigneArticle.UNPAID)
|
||||
|
||||
reservation.tickets.all().update(status=Ticket.NOT_ACTIV)
|
||||
|
||||
reservation.paiement = paiement_stripe
|
||||
reservation.status = Reservation.UNPAID
|
||||
reservation.save()
|
||||
|
||||
print(new_paiement_stripe.checkout_session.stripe_id)
|
||||
# return new_paiement_stripe.redirect_to_stripe()
|
||||
self.checkout_session = new_paiement_stripe.checkout_session
|
||||
|
|
@ -278,6 +286,7 @@ class ReservationValidator(serializers.Serializer):
|
|||
|
||||
def to_representation(self, instance):
|
||||
representation = super().to_representation(instance)
|
||||
logger.info(f"{self.checkout_session.url}")
|
||||
representation['checkout_url'] = self.checkout_session.url
|
||||
# import ipdb;ipdb.set_trace()
|
||||
return representation
|
||||
|
|
|
|||
|
|
@ -440,41 +440,14 @@
|
|||
<strong>Grand merci pour votre reservation !</strong>
|
||||
<br><br>
|
||||
{% if reservation.tickets %}
|
||||
Vous trouverez vos tickets en pièce jointe.
|
||||
Vous trouverez vos billets en pièce jointe.
|
||||
{% else %}
|
||||
Aucun ticket pour un concert ? Etrange etrange
|
||||
Aucun billets pour un concert ? Etrange etrange
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<!-- END BODY COPY -->
|
||||
<!-- BUTTON -->
|
||||
<tr>
|
||||
<td align="left"
|
||||
style="padding: 18px 18px 18px 18px; mso-alt-padding: 18px 18px 18px 18px!important;">
|
||||
<table width="100%" border="0" cellspacing="0"
|
||||
cellpadding="0">
|
||||
<tr>
|
||||
<td>
|
||||
<table border="0" cellspacing="0"
|
||||
cellpadding="0">
|
||||
<tr>
|
||||
<td align="left"
|
||||
style="border-radius: 3px;"
|
||||
bgcolor="#17bef7">
|
||||
<a class="button raised"
|
||||
href="{{ config.domaine_cashless }}/rapport/invoice/{{ adhesion.commande }}"
|
||||
target="_blank"
|
||||
style="font-size: 14px; line-height: 14px; font-weight: 500; font-family: Helvetica, Arial, sans-serif; color: #ffffff; text-decoration: none; border-radius: 3px; padding: 10px 25px; border: 1px solid #17bef7; display: inline-block;">
|
||||
TELECHARGER REÇU</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- END BUTTON -->
|
||||
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
<body>
|
||||
<section id="informations">
|
||||
<h1 id="name">{{ ticket.first_name }} {{ ticket.last_name }}</h1>
|
||||
<h1 id="destination">CDG ✈ LFLL</h1>
|
||||
<h1 id="destination">{{ ticket.reservation.event.name }}</h1>
|
||||
<dl>
|
||||
<dt>Flight</dt>
|
||||
<dd>DL31</dd>
|
||||
|
|
@ -33,7 +33,7 @@
|
|||
|
||||
<section id="ticket">
|
||||
<p>1257797706706</p>
|
||||
<h2>Théodore Marcelin</h2>
|
||||
<h2>{{ ticket.first_name }} {{ ticket.last_name }}</h2>
|
||||
<dl>
|
||||
<dt>Flight</dt>
|
||||
<dd>DL31</dd>
|
||||
|
|
@ -45,7 +45,7 @@
|
|||
<dd>4</dd>
|
||||
</dl>
|
||||
<ul>
|
||||
<li>CDG ✈ LFLL</li>
|
||||
<li>{{ ticket.reservation.event.name }}</li>
|
||||
<li>5:10pm</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ from weasyprint import HTML
|
|||
from BaseBillet.models import Configuration, Reservation, Ticket
|
||||
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
'''
|
||||
from ApiBillet.thread_mailer import ThreadMaileur
|
||||
|
|
@ -23,34 +23,28 @@ mail.send_with_tread()
|
|||
|
||||
class ThreadMaileur():
|
||||
|
||||
def __init__(self, email, title, text=None, html=None, template=None, context=None):
|
||||
def __init__(self,
|
||||
email: str,
|
||||
title: str,
|
||||
text=None,
|
||||
html=None,
|
||||
template=None,
|
||||
context=None,
|
||||
urls_for_attached_files=None,
|
||||
):
|
||||
|
||||
self.title = title
|
||||
self.email = email
|
||||
self.text = text
|
||||
self.html = html
|
||||
self.config = Configuration.get_solo()
|
||||
self.context = None
|
||||
self.context = context
|
||||
self.urls_for_attached_files = urls_for_attached_files
|
||||
|
||||
if template and context:
|
||||
self.html = render_to_string(template, context=context)
|
||||
self.context = context
|
||||
self.tickets_uuid = self._tickets_uuid()
|
||||
self.url = self._url()
|
||||
|
||||
def _url(self):
|
||||
url = f"http://{connection.tenant.domains.all()[0].domain}:8002/api/ticket/"
|
||||
return url
|
||||
|
||||
def _tickets_uuid(self):
|
||||
tickets_uuid = []
|
||||
if self.context :
|
||||
if self.context.get('reservation'):
|
||||
reservation: Reservation = self.context.get('reservation')
|
||||
tickets = reservation.tickets.filter(status=Ticket.NOT_SCANNED)
|
||||
if len(tickets) > 0:
|
||||
for ticket in tickets :
|
||||
tickets_uuid.append(f"{ticket.uuid}")
|
||||
|
||||
return tickets_uuid
|
||||
|
||||
def config_valid(self):
|
||||
EMAIL_HOST = os.environ.get('EMAIL_HOST')
|
||||
|
|
@ -74,28 +68,13 @@ class ThreadMaileur():
|
|||
)
|
||||
mail.attach_alternative(self.html, "text/html")
|
||||
|
||||
attached_file = []
|
||||
for ticket in self.tickets_uuid :
|
||||
|
||||
response = requests.get(f"{self.url}{ticket}")
|
||||
for filename, url in self.urls_for_attached_files.items():
|
||||
response = requests.get(url)
|
||||
if response.status_code == 200:
|
||||
attached_file.append(response.content)
|
||||
|
||||
# attached_file.append(render_to_string('ticket/ticket.html', context={'context': 'context'}))
|
||||
# msg = EmailMessage(subject, html_content, from_email, [to])
|
||||
# msg.content_subtype = "html" # Main content is now text/html
|
||||
# msg.send()
|
||||
|
||||
# import ipdb; ipdb.set_trace()
|
||||
i=1
|
||||
for file in attached_file:
|
||||
# html_before_pdf = HTML(string=file)
|
||||
# mail.attach(f'ticket_{i}.pdf', html_before_pdf.write_pdf(), 'application/pdf')
|
||||
mail.attach(f'ticket_{i}.pdf', file, 'application/pdf')
|
||||
i += 1
|
||||
|
||||
mail.attach(filename, response.content, 'application/pdf')
|
||||
|
||||
mail_return = mail.send(fail_silently=False)
|
||||
|
||||
if mail_return == 1:
|
||||
logger.info(f' mail envoyé : {mail_return} - {self.email}')
|
||||
else:
|
||||
|
|
@ -105,7 +84,6 @@ class ThreadMaileur():
|
|||
logger.error(f'Pas de contenu HTML ou de configuration email valide')
|
||||
raise ValueError('Pas de contenu HTML ou de configuration email valide')
|
||||
|
||||
|
||||
def send_with_tread(self):
|
||||
|
||||
# self.send()
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@ router.register(r'reservations', api_view.ReservationViewset, basename='reservat
|
|||
|
||||
urlpatterns = [
|
||||
path('', include(router.urls)),
|
||||
path('ticket/<uuid:pk_uuid>', TicketPdf.as_view(), name='ticket_uuid'),
|
||||
|
||||
#download ticket :
|
||||
path('ticket/pdf/<uuid:pk_uuid>', TicketPdf.as_view(), name='ticket_uuid_to_pdf'),
|
||||
|
||||
]
|
||||
|
|
@ -150,11 +150,10 @@ class TicketPdf(WeasyTemplateView):
|
|||
kwargs['ticket'] = ticket
|
||||
kwargs['config'] = self.config
|
||||
|
||||
self.nom_prenom = f"{ticket.first_name.upper()}_{ticket.last_name.capitalize()}"
|
||||
self.pdf_filename = ticket.pdf_filename()
|
||||
return kwargs
|
||||
|
||||
def get_pdf_filename(self, **kwargs):
|
||||
nom_prenom = self.nom_prenom
|
||||
return f"Ticket_{nom_prenom}.pdf"
|
||||
return self.pdf_filename
|
||||
|
||||
#
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ from django.db.models.aggregates import Sum
|
|||
from django.db.models import Q
|
||||
from django.db.models.signals import post_save, pre_save
|
||||
from django.dispatch import receiver
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
from django.contrib.postgres.fields import JSONField
|
||||
from solo.models import SingletonModel
|
||||
|
|
@ -325,7 +326,7 @@ class Reservation(models.Model):
|
|||
on_delete=models.PROTECT,
|
||||
related_name="reservation")
|
||||
|
||||
CANCELED, CREATED, UNPAID, PAID, VALID, = 'C', 'R', 'N', 'P', 'V'
|
||||
CANCELED, CREATED, UNPAID, PAID, VALID, = 'C', 'R', 'U', 'P', 'V'
|
||||
TYPE_CHOICES = [
|
||||
(CANCELED, _('Annulée')),
|
||||
(CREATED, _('Crée')),
|
||||
|
|
@ -356,7 +357,7 @@ class Reservation(models.Model):
|
|||
|
||||
def articles_paid(self):
|
||||
articles_paid = []
|
||||
for paiement in self.paiements_paid():
|
||||
for paiement in self.paiements.all():
|
||||
for ligne in paiement.lignearticle_set.filter(
|
||||
Q(status=LigneArticle.PAID) | Q(status=LigneArticle.VALID)
|
||||
):
|
||||
|
|
@ -401,16 +402,39 @@ class Ticket(models.Model):
|
|||
|
||||
reservation = models.ForeignKey(Reservation, on_delete=models.CASCADE, related_name="tickets")
|
||||
|
||||
NOT_ACTIV, NOT_SCANNED, SCANNED = 'N', 'K', 'S'
|
||||
CREATED, NOT_ACTIV, NOT_SCANNED, SCANNED = 'C', 'N', 'K', 'S'
|
||||
SCAN_CHOICES = [
|
||||
(CREATED, _('Crée')),
|
||||
(NOT_ACTIV, _('Non actif')),
|
||||
(NOT_SCANNED, _('Non scanné')),
|
||||
(SCANNED, _('scanné')),
|
||||
]
|
||||
|
||||
status = models.CharField(max_length=1, choices=SCAN_CHOICES, default=NOT_ACTIV,
|
||||
status = models.CharField(max_length=1, choices=SCAN_CHOICES, default=CREATED,
|
||||
verbose_name=_("Status du scan"))
|
||||
|
||||
seat = models.CharField(max_length=20, default=_('Placement libre'))
|
||||
|
||||
def pdf_filename(self):
|
||||
config = Configuration.get_solo()
|
||||
return f"{config.organisation.upper()} " \
|
||||
f"{self.reservation.event.datetime.astimezone().strftime('%d/%m/%Y')} " \
|
||||
f"{self.first_name.upper()} " \
|
||||
f"{self.last_name.capitalize()}" \
|
||||
f".pdf"
|
||||
|
||||
|
||||
def pdf_url(self):
|
||||
domain = connection.tenant.domains.all().first().domain
|
||||
api_pdf = reverse("ticket_uuid_to_pdf", args=[f"{self.uuid}"])
|
||||
protocol = "https://"
|
||||
port = ""
|
||||
if settings.DEBUG:
|
||||
protocol = "http://"
|
||||
port = ":8002"
|
||||
return f"{protocol}{domain}{port}{api_pdf}"
|
||||
|
||||
|
||||
def event(self):
|
||||
return self.reservation.event
|
||||
|
||||
|
|
@ -454,11 +478,11 @@ class Paiement_stripe(models.Model):
|
|||
(VALID, 'Payée et validée'), # envoyé sur serveur cashless
|
||||
(CANCELED, 'Annulée'),
|
||||
)
|
||||
status = models.CharField(max_length=1, choices=STATUT_CHOICES, default=NON, verbose_name="Statut de la commande")
|
||||
|
||||
reservation = models.ForeignKey(Reservation, on_delete=models.PROTECT, blank=True, null=True,
|
||||
related_name="paiements")
|
||||
|
||||
status = models.CharField(max_length=1, choices=STATUT_CHOICES, default=NON, verbose_name="Statut de la commande")
|
||||
|
||||
QRCODE, API_BILLETTERIE = 'Q', 'B'
|
||||
SOURCE_CHOICES = (
|
||||
|
|
@ -493,15 +517,16 @@ class LigneArticle(models.Model):
|
|||
|
||||
paiement_stripe = models.ForeignKey(Paiement_stripe, on_delete=models.PROTECT, blank=True, null=True)
|
||||
|
||||
CANCELED, UNPAID, PAID, VALID, = 'C', 'N', 'P', 'V'
|
||||
CANCELED, CREATED, UNPAID, PAID, VALID, = 'C', 'O', 'U', 'P', 'V'
|
||||
TYPE_CHOICES = [
|
||||
(CANCELED, _('Annulée')),
|
||||
(CREATED, _('Non envoyé en paiement')),
|
||||
(UNPAID, _('Non payée')),
|
||||
(PAID, _('Payée')),
|
||||
(VALID, _('Validée par serveur cashless')),
|
||||
]
|
||||
|
||||
status = models.CharField(max_length=3, choices=TYPE_CHOICES, default=UNPAID,
|
||||
status = models.CharField(max_length=3, choices=TYPE_CHOICES, default=CREATED,
|
||||
verbose_name=_("Status de ligne article"))
|
||||
|
||||
class Meta:
|
||||
|
|
|
|||
|
|
@ -9,8 +9,9 @@ from ApiBillet.thread_mailer import ThreadMaileur
|
|||
from BaseBillet.models import Reservation, LigneArticle, Ticket, Product, Configuration, Paiement_stripe
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
from TiBillet import settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.info(f'import basebillet.signals')
|
||||
|
||||
|
||||
|
|
@ -26,31 +27,58 @@ logger.info(f'import basebillet.signals')
|
|||
########################################################################
|
||||
|
||||
|
||||
######################## 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 :
|
||||
# try :
|
||||
if new_instance.reservation:
|
||||
new_instance.reservation.status = Reservation.PAID
|
||||
new_instance.reservation.save()
|
||||
# except new_instance.reservation.RelatedObjectDoesNotExist:
|
||||
|
||||
|
||||
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 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()
|
||||
# si toutes les lignes articles sont save en VALID.
|
||||
# @receiver(post_save, sender=LigneArticle)
|
||||
|
||||
def set_paiement_and_reservation_valid(old_instance, new_instance):
|
||||
lignes_dans_paiement_stripe = new_instance.paiement_stripe.lignearticle_set.all()
|
||||
# TODO: calculer -1 ??
|
||||
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()
|
||||
logger.info(f" TRIGGER LIGNE ARTICLE set_paiement_and_reservation_valid {new_instance.price} "
|
||||
f"paiement stripe {new_instance.paiement_stripe} {new_instance.paiement_stripe.status} à VALID")
|
||||
new_instance.paiement_stripe.status = Paiement_stripe.VALID
|
||||
new_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):
|
||||
|
|
@ -89,56 +117,40 @@ def send_to_cashless(instance):
|
|||
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):
|
||||
def check_paid(old_instance, new_instance):
|
||||
# Type :
|
||||
old_instance: Paiement_stripe
|
||||
new_instance: Paiement_stripe
|
||||
old_instance: LigneArticle
|
||||
new_instance: LigneArticle
|
||||
logger.info(f" TRIGGER LIGNE ARTICLE check_paid {old_instance.price}")
|
||||
|
||||
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 :
|
||||
# try :
|
||||
if new_instance.reservation:
|
||||
new_instance.reservation.status = Reservation.PAID
|
||||
new_instance.reservation.save()
|
||||
# except new_instance.reservation.RelatedObjectDoesNotExist:
|
||||
|
||||
|
||||
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
|
||||
if new_instance.price.product.categorie_article in \
|
||||
[Product.RECHARGE_CASHLESS, Product.ADHESION]:
|
||||
send_to_cashless(new_instance)
|
||||
|
||||
|
||||
######################## TRIGGER RESERVATION ########################
|
||||
|
||||
|
||||
# @receiver(post_save, sender=Reservation)
|
||||
# def send_billet_to_mail(sender, instance: Reservation, **kwargs):
|
||||
def send_billet_to_mail(old_instance, new_instance):
|
||||
# On active les tickets
|
||||
urls_for_attached_files = {}
|
||||
if new_instance.tickets:
|
||||
for ticket in new_instance.tickets.filter(status=Ticket.NOT_ACTIV):
|
||||
# On prend aussi ceux qui sont déja activé ( avec les Q() )
|
||||
# pour pouvoir les envoyer par mail en cas de nouvelle demande
|
||||
for ticket in new_instance.tickets.filter(Q(status=Ticket.NOT_ACTIV) | Q(status=Ticket.NOT_SCANNED)):
|
||||
logger.info(f'trigger_reservation, activation des tickets {ticket} NOT_SCANNED')
|
||||
ticket.status = Ticket.NOT_SCANNED
|
||||
ticket.save()
|
||||
|
||||
# On vérifier qu'on a pas déja envoyé le mail
|
||||
# on rajoute les urls du pdf pour le thread async
|
||||
urls_for_attached_files[ticket.pdf_filename()] = ticket.pdf_url()
|
||||
|
||||
# import ipdb; ipdb.set_trace()
|
||||
# On vérifie qu'on a pas déja envoyé le mail
|
||||
if not new_instance.mail_send :
|
||||
logger.info(f" TRIGGER RESERVATION send_billet_to_mail {old_instance.status} to {new_instance.status}")
|
||||
logger.info(f" TRIGGER RESERVATION send_billet_to_mail {new_instance.status}")
|
||||
new_instance : Reservation
|
||||
config = Configuration.get_solo()
|
||||
|
||||
|
|
@ -152,13 +164,15 @@ def send_billet_to_mail(old_instance, new_instance):
|
|||
'config': config,
|
||||
'reservation': new_instance,
|
||||
},
|
||||
urls_for_attached_files = urls_for_attached_files,
|
||||
)
|
||||
# import ipdb; ipdb.set_trace()
|
||||
mail.send_with_tread()
|
||||
except Exception as e :
|
||||
logger.error(f"{timezone.now()} Erreur envoie de mail pour reservation {new_instance} : {e}")
|
||||
|
||||
else :
|
||||
logger.info(f" TRIGGER RESERVATION mail déja envoyé {new_instance} : {new_instance.mail_send} - status : {old_instance.status} to {new_instance.status}")
|
||||
logger.info(f" TRIGGER RESERVATION mail déja envoyé {new_instance} : {new_instance.mail_send} - status : {new_instance.status}")
|
||||
|
||||
|
||||
######################## MOTEUR TRIGGER ########################
|
||||
|
|
@ -174,19 +188,6 @@ def error_regression(old_instance, new_instance):
|
|||
# Exemple première ligne : Si status passe de PENDING vers PAID, alors on lance set_ligne_article_paid
|
||||
|
||||
TRANSITIONS = {
|
||||
'RESERVATION': {
|
||||
Reservation.UNPAID: {
|
||||
Reservation.PAID: send_billet_to_mail,
|
||||
},
|
||||
Reservation.PAID: {
|
||||
Reservation.VALID: send_billet_to_mail,
|
||||
Reservation.PAID: send_billet_to_mail,
|
||||
'_else_': error_regression,
|
||||
},
|
||||
Reservation.VALID: {
|
||||
'_all_': error_regression,
|
||||
}
|
||||
},
|
||||
'PAIEMENT_STRIPE': {
|
||||
Paiement_stripe.PENDING: {
|
||||
Paiement_stripe.PAID: set_ligne_article_paid,
|
||||
|
|
@ -202,19 +203,34 @@ TRANSITIONS = {
|
|||
'_all_': error_regression,
|
||||
}
|
||||
},
|
||||
|
||||
'LIGNEARTICLE': {
|
||||
LigneArticle.UNPAID: {
|
||||
LigneArticle.PAID: check_paid,
|
||||
},
|
||||
LigneArticle.PAID: {
|
||||
LigneArticle.PAID: check_paid,
|
||||
# LigneArticle.VALID: valide_stripe_paiement,
|
||||
LigneArticle.VALID: set_paiement_and_reservation_valid,
|
||||
'_else_': error_regression,
|
||||
},
|
||||
LigneArticle.VALID: {
|
||||
'_all_': error_regression,
|
||||
}
|
||||
},
|
||||
|
||||
'RESERVATION': {
|
||||
Reservation.UNPAID: {
|
||||
Reservation.PAID: send_billet_to_mail,
|
||||
},
|
||||
Reservation.PAID: {
|
||||
Reservation.VALID: send_billet_to_mail,
|
||||
Reservation.PAID: send_billet_to_mail,
|
||||
'_else_': error_regression,
|
||||
},
|
||||
Reservation.VALID: {
|
||||
'_all_': error_regression,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@receiver(pre_save)
|
||||
|
|
|
|||
|
|
@ -3,6 +3,6 @@ from django.urls import include, path, re_path
|
|||
from BaseBillet import views as base_view
|
||||
|
||||
urlpatterns = [
|
||||
path('event/<str:id>', base_view.event.as_view()),
|
||||
path('ticket/<uuid:pk_uuid>', base_view.Ticket_html_view.as_view()),
|
||||
path('', base_view.index.as_view(), name="index"),
|
||||
]
|
||||
|
|
@ -1,24 +1,12 @@
|
|||
from datetime import datetime
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.shortcuts import render, redirect
|
||||
from django.shortcuts import render
|
||||
|
||||
# Create your views here.
|
||||
from rest_framework import serializers, status
|
||||
from rest_framework.generics import get_object_or_404
|
||||
from rest_framework.permissions import AllowAny
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework.response import Response
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from AuthBillet.email import ActivationEmail
|
||||
from BaseBillet.models import Configuration, Event, Reservation, LigneArticle
|
||||
from BaseBillet.validator import ReservationValidator
|
||||
from django.db import connection
|
||||
from AuthBillet.models import TibilletUser
|
||||
|
||||
from threading import Thread
|
||||
from BaseBillet.models import Configuration, Event, Ticket
|
||||
|
||||
|
||||
class index(APIView):
|
||||
|
|
@ -44,128 +32,14 @@ class index(APIView):
|
|||
return render(request, 'html5up-massively/index.html', context=context)
|
||||
|
||||
|
||||
def creation_de_la_reservation(user: TibilletUser, event: Event, data):
|
||||
|
||||
reservation = Reservation.objects.create(
|
||||
user_commande = user,
|
||||
event= event,
|
||||
)
|
||||
|
||||
if data.get('radio_generale'):
|
||||
reservation.options.add(data.get('radio_generale')[0])
|
||||
|
||||
for option_checkbox in data.get('option_checkbox'):
|
||||
reservation.options.add(option_checkbox)
|
||||
|
||||
# import ipdb; ipdb.set_trace()
|
||||
#
|
||||
for billet in data.get('billets'):
|
||||
qty = data.get('billets')[billet]
|
||||
LigneArticle.objects.create(
|
||||
reservation = reservation,
|
||||
billet = billet,
|
||||
qty = qty,
|
||||
)
|
||||
|
||||
for article in data.get('products'):
|
||||
qty = data.get('products')[article]
|
||||
LigneArticle.objects.create(
|
||||
reservation = reservation,
|
||||
article = article,
|
||||
qty = qty,
|
||||
)
|
||||
|
||||
return reservation
|
||||
|
||||
|
||||
#Modèle MVC
|
||||
class event(APIView):
|
||||
class Ticket_html_view(APIView):
|
||||
permission_classes = [AllowAny]
|
||||
|
||||
|
||||
|
||||
def get(self, request, id):
|
||||
event = get_object_or_404(Event, pk=id)
|
||||
configuration = Configuration.get_solo()
|
||||
|
||||
def get(self, request, pk_uuid):
|
||||
ticket = get_object_or_404(Ticket, uuid=pk_uuid)
|
||||
context = {
|
||||
'configuration': configuration,
|
||||
'event': event,
|
||||
'ticket': ticket,
|
||||
'config': Configuration.get_solo(),
|
||||
}
|
||||
|
||||
return render(request, 'html5up-massively/event.html', context=context)
|
||||
|
||||
def post(self, request, id):
|
||||
|
||||
print(request.data)
|
||||
|
||||
reservation_validator = ReservationValidator(data=request.data)
|
||||
|
||||
if reservation_validator.is_valid():
|
||||
print(reservation_validator.validated_data)
|
||||
configuration = Configuration.get_solo()
|
||||
context = {}
|
||||
|
||||
data_reservation = reservation_validator.validated_data
|
||||
event = get_object_or_404(Event, pk=id)
|
||||
|
||||
# import ipdb; ipdb.set_trace()
|
||||
# reste_place = configuration.jauge_max - event.reservations
|
||||
# if data_reservation.get('qty') > reste_place:
|
||||
# raise serializers.ValidationError(_(f"Il ne reste plus que {reste_place} places"))
|
||||
|
||||
if request.user.is_anonymous:
|
||||
User: TibilletUser = get_user_model()
|
||||
email = data_reservation.get('email')
|
||||
user, created = User.objects.get_or_create(username=email, email=email)
|
||||
|
||||
if created:
|
||||
user.is_active = False
|
||||
user.first_name = data_reservation.get('nom')
|
||||
user.last_name = data_reservation.get('prenom')
|
||||
user.phone = data_reservation.get('phone')
|
||||
user.client_source = connection.tenant
|
||||
user.client_achat.add(connection.tenant)
|
||||
user.save()
|
||||
|
||||
request.user = user
|
||||
|
||||
if not request.user.is_active or not request.user.password :
|
||||
|
||||
print(f"{request.user} not active or no password")
|
||||
# on retire les commande non validé pour éviter les doublons
|
||||
# et on le remet non actif si pas de mot de passe :
|
||||
asupr = Reservation.objects.filter(user_commande=request.user, status=Reservation.MAIL_NON_VALIDEE, event=event)
|
||||
asupr.delete()
|
||||
request.user.is_active = False
|
||||
request.user.save()
|
||||
|
||||
email_activation = ActivationEmail(request)
|
||||
|
||||
# email_activation.send(to=[email,])
|
||||
thread_email = Thread(
|
||||
target=email_activation.send,
|
||||
kwargs={'to': [request.user.email, ],
|
||||
'from_email': configuration.email}
|
||||
)
|
||||
|
||||
thread_email.start()
|
||||
|
||||
context['message'] = "Merci pour votre réservation ! \n" \
|
||||
"Il semble que vous n'avez pas encore de compte TiBillet. \n" \
|
||||
"Merci de vérifier votre boite mail pour valider votre réservation. \n" \
|
||||
"( N'oubliez pas de regarder dans les spams si vous ne voyez rien venir. ) \n" \
|
||||
"Merci !"
|
||||
|
||||
elif request.user.is_active:
|
||||
print("is is_active !")
|
||||
|
||||
reservation = creation_de_la_reservation(request.user, event, data_reservation)
|
||||
|
||||
context['configuration'] = configuration
|
||||
context['event'] = event
|
||||
|
||||
return render(request, 'html5up-massively/event.html', context=context)
|
||||
else:
|
||||
print(f"validator.errors : {reservation_validator.errors}")
|
||||
return Response(reservation_validator.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||
return render(request, 'ticket/ticket.html', context=context)
|
||||
|
|
@ -0,0 +1,171 @@
|
|||
from datetime import datetime
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.shortcuts import render, redirect
|
||||
|
||||
# Create your views here.
|
||||
from rest_framework import serializers, status
|
||||
from rest_framework.generics import get_object_or_404
|
||||
from rest_framework.permissions import AllowAny
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework.response import Response
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from AuthBillet.email import ActivationEmail
|
||||
from BaseBillet.models import Configuration, Event, Reservation, LigneArticle
|
||||
from BaseBillet.validator import ReservationValidator
|
||||
from django.db import connection
|
||||
from AuthBillet.models import TibilletUser
|
||||
|
||||
from threading import Thread
|
||||
|
||||
|
||||
class index(APIView):
|
||||
permission_classes = [AllowAny]
|
||||
|
||||
def get(self, request):
|
||||
configuration = Configuration.get_solo()
|
||||
if not configuration.activer_billetterie :
|
||||
return HttpResponseRedirect('https://www.tibillet.re')
|
||||
|
||||
events = Event.objects.filter(datetime__gt=datetime.now())
|
||||
if len(events) > 0:
|
||||
first_event = events[0]
|
||||
else:
|
||||
first_event = None
|
||||
|
||||
context = {
|
||||
'configuration': configuration,
|
||||
'events': events[1:],
|
||||
'first_event': first_event,
|
||||
}
|
||||
|
||||
return render(request, 'html5up-massively/index.html', context=context)
|
||||
|
||||
|
||||
def creation_de_la_reservation(user: TibilletUser, event: Event, data):
|
||||
|
||||
reservation = Reservation.objects.create(
|
||||
user_commande = user,
|
||||
event= event,
|
||||
)
|
||||
|
||||
if data.get('radio_generale'):
|
||||
reservation.options.add(data.get('radio_generale')[0])
|
||||
|
||||
for option_checkbox in data.get('option_checkbox'):
|
||||
reservation.options.add(option_checkbox)
|
||||
|
||||
# import ipdb; ipdb.set_trace()
|
||||
#
|
||||
for billet in data.get('billets'):
|
||||
qty = data.get('billets')[billet]
|
||||
LigneArticle.objects.create(
|
||||
reservation = reservation,
|
||||
billet = billet,
|
||||
qty = qty,
|
||||
)
|
||||
|
||||
for article in data.get('products'):
|
||||
qty = data.get('products')[article]
|
||||
LigneArticle.objects.create(
|
||||
reservation = reservation,
|
||||
article = article,
|
||||
qty = qty,
|
||||
)
|
||||
|
||||
return reservation
|
||||
|
||||
|
||||
#Modèle MVC
|
||||
class event(APIView):
|
||||
permission_classes = [AllowAny]
|
||||
|
||||
|
||||
|
||||
def get(self, request, id):
|
||||
event = get_object_or_404(Event, pk=id)
|
||||
configuration = Configuration.get_solo()
|
||||
|
||||
context = {
|
||||
'configuration': configuration,
|
||||
'event': event,
|
||||
}
|
||||
|
||||
return render(request, 'html5up-massively/event.html', context=context)
|
||||
|
||||
def post(self, request, id):
|
||||
|
||||
print(request.data)
|
||||
|
||||
reservation_validator = ReservationValidator(data=request.data)
|
||||
|
||||
if reservation_validator.is_valid():
|
||||
print(reservation_validator.validated_data)
|
||||
configuration = Configuration.get_solo()
|
||||
context = {}
|
||||
|
||||
data_reservation = reservation_validator.validated_data
|
||||
event = get_object_or_404(Event, pk=id)
|
||||
|
||||
# import ipdb; ipdb.set_trace()
|
||||
# reste_place = configuration.jauge_max - event.reservations
|
||||
# if data_reservation.get('qty') > reste_place:
|
||||
# raise serializers.ValidationError(_(f"Il ne reste plus que {reste_place} places"))
|
||||
|
||||
if request.user.is_anonymous:
|
||||
User: TibilletUser = get_user_model()
|
||||
email = data_reservation.get('email')
|
||||
user, created = User.objects.get_or_create(username=email, email=email)
|
||||
|
||||
if created:
|
||||
user.is_active = False
|
||||
user.first_name = data_reservation.get('nom')
|
||||
user.last_name = data_reservation.get('prenom')
|
||||
user.phone = data_reservation.get('phone')
|
||||
user.client_source = connection.tenant
|
||||
user.client_achat.add(connection.tenant)
|
||||
user.save()
|
||||
|
||||
request.user = user
|
||||
|
||||
if not request.user.is_active or not request.user.password :
|
||||
|
||||
print(f"{request.user} not active or no password")
|
||||
# on retire les commande non validé pour éviter les doublons
|
||||
# et on le remet non actif si pas de mot de passe :
|
||||
asupr = Reservation.objects.filter(user_commande=request.user, status=Reservation.MAIL_NON_VALIDEE, event=event)
|
||||
asupr.delete()
|
||||
request.user.is_active = False
|
||||
request.user.save()
|
||||
|
||||
email_activation = ActivationEmail(request)
|
||||
|
||||
# email_activation.send(to=[email,])
|
||||
thread_email = Thread(
|
||||
target=email_activation.send,
|
||||
kwargs={'to': [request.user.email, ],
|
||||
'from_email': configuration.email}
|
||||
)
|
||||
|
||||
thread_email.start()
|
||||
|
||||
context['message'] = "Merci pour votre réservation ! \n" \
|
||||
"Il semble que vous n'avez pas encore de compte TiBillet. \n" \
|
||||
"Merci de vérifier votre boite mail pour valider votre réservation. \n" \
|
||||
"( N'oubliez pas de regarder dans les spams si vous ne voyez rien venir. ) \n" \
|
||||
"Merci !"
|
||||
|
||||
elif request.user.is_active:
|
||||
print("is is_active !")
|
||||
|
||||
reservation = creation_de_la_reservation(request.user, event, data_reservation)
|
||||
|
||||
context['configuration'] = configuration
|
||||
context['event'] = event
|
||||
|
||||
return render(request, 'html5up-massively/event.html', context=context)
|
||||
else:
|
||||
print(f"validator.errors : {reservation_validator.errors}")
|
||||
return Response(reservation_validator.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
|
@ -229,9 +229,13 @@ class retour_stripe(View):
|
|||
return HttpResponseRedirect(f"/qr/{ligne_article.carte.uuid}#erreurpaiement")
|
||||
|
||||
elif paiement_stripe.source == Paiement_stripe.API_BILLETTERIE :
|
||||
if paiement_stripe.status == Paiement_stripe.PAID :
|
||||
return HttpResponse(
|
||||
'Paiement okay, on lance les process de validation.')
|
||||
|
||||
if paiement_stripe.status == Paiement_stripe.VALID :
|
||||
return HttpResponse(
|
||||
'Coucou')
|
||||
'Paiement validé !')
|
||||
|
||||
|
||||
raise Http404(f'{paiement_stripe.status}')
|
||||
|
|
|
|||
|
|
@ -224,11 +224,11 @@ LOGGING = {
|
|||
'disable_existing_loggers': False,
|
||||
'handlers': {
|
||||
'console': {
|
||||
'level': 'DEBUG',
|
||||
'level': 'INFO',
|
||||
'class': 'logging.StreamHandler',
|
||||
},
|
||||
'logfile': {
|
||||
'level': 'DEBUG',
|
||||
'level': 'INFO',
|
||||
'class': 'logging.FileHandler',
|
||||
'filename': f"{BASE_DIR}/www/Djangologfile",
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
from python:3.8-slim
|
||||
from python:3.8-bullseye
|
||||
|
||||
## UPDATE
|
||||
RUN apt-get update
|
||||
RUN apt-get upgrade -y
|
||||
RUN apt install -y python3-pip
|
||||
|
||||
RUN pip install pip --upgrade
|
||||
|
||||
## PYTHON
|
||||
|
|
@ -61,17 +63,27 @@ RUN pip install django-stdimage
|
|||
RUN pip install stripe
|
||||
|
||||
|
||||
RUN apt-get install -y fonts-font-awesome
|
||||
RUN apt-get install -y libffi-dev
|
||||
RUN apt-get install -y libgdk-pixbuf2.0-0
|
||||
RUN apt-get install -y libpango1.0-0
|
||||
RUN apt-get install -y python-dev
|
||||
# RUN apt-get install -y fonts-font-awesome
|
||||
# RUN apt-get install -y libffi-dev
|
||||
# RUN apt-get install -y libgdk-pixbuf2.0-0
|
||||
# RUN apt-get install -y libpango1.0-0
|
||||
# RUN apt-get install -y python-dev
|
||||
# RUN apt-get install -y python-lxml
|
||||
RUN apt-get install -y shared-mime-info
|
||||
RUN apt-get install -y libcairo2
|
||||
# RUN apt-get install -y shared-mime-info
|
||||
# RUN apt-get install -y libcairo2
|
||||
|
||||
RUN apt install -y python3-cffi
|
||||
RUN apt install -y python3-brotli
|
||||
RUN apt install -y libpango-1.0-0
|
||||
RUN apt install -y libpangoft2-1.0-0
|
||||
RUN pip install django-weasyprint
|
||||
|
||||
RUN apt-get -y clean
|
||||
|
||||
RUN python --version
|
||||
RUN django-admin --version
|
||||
RUN pip freeze
|
||||
|
||||
RUN weasyprint --version
|
||||
RUN pip freeze | grep weasyprint
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue