diff --git a/DjangoFiles/ApiBillet/serializers.py b/DjangoFiles/ApiBillet/serializers.py index 5248d41..788475e 100644 --- a/DjangoFiles/ApiBillet/serializers.py +++ b/DjangoFiles/ApiBillet/serializers.py @@ -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 diff --git a/DjangoFiles/ApiBillet/templates/mails/buy_confirmation.html b/DjangoFiles/ApiBillet/templates/mails/buy_confirmation.html index f2f2e37..b88de0f 100644 --- a/DjangoFiles/ApiBillet/templates/mails/buy_confirmation.html +++ b/DjangoFiles/ApiBillet/templates/mails/buy_confirmation.html @@ -440,41 +440,14 @@ Grand merci pour votre reservation !

{% 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 %} - - - - - - - -
- - - - -
- - TELECHARGER REÇU -
-
- - - + diff --git a/DjangoFiles/ApiBillet/templates/ticket/ticket.html b/DjangoFiles/ApiBillet/templates/ticket/ticket.html index fefcf5f..e2a3db5 100644 --- a/DjangoFiles/ApiBillet/templates/ticket/ticket.html +++ b/DjangoFiles/ApiBillet/templates/ticket/ticket.html @@ -12,7 +12,7 @@

{{ ticket.first_name }} {{ ticket.last_name }}

-

CDG ✈ LFLL

+

{{ ticket.reservation.event.name }}

Flight
DL31
@@ -33,7 +33,7 @@

1257797706706

-

Théodore Marcelin

+

{{ ticket.first_name }} {{ ticket.last_name }}

Flight
DL31
@@ -45,7 +45,7 @@
4
    -
  • CDG ✈ LFLL
  • +
  • {{ ticket.reservation.event.name }}
  • 5:10pm
diff --git a/DjangoFiles/ApiBillet/thread_mailer.py b/DjangoFiles/ApiBillet/thread_mailer.py index 266a691..4c3e842 100644 --- a/DjangoFiles/ApiBillet/thread_mailer.py +++ b/DjangoFiles/ApiBillet/thread_mailer.py @@ -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 - if template and context : + 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') @@ -58,58 +52,42 @@ class ThreadMaileur(): EMAIL_HOST_USER = os.environ.get('EMAIL_HOST_USER') EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_HOST_PASSWORD') - if EMAIL_HOST and EMAIL_PORT and EMAIL_HOST_USER and EMAIL_HOST_PASSWORD and self.config.email : + if EMAIL_HOST and EMAIL_PORT and EMAIL_HOST_USER and EMAIL_HOST_PASSWORD and self.config.email: return True else: return False def send(self): - if self.html and self.config_valid() : + if self.html and self.config_valid(): logger.info(f' send_mail') mail = EmailMultiAlternatives( self.title, self.text, self.config.email, - [self.email,], + [self.email, ], ) 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 : + + if mail_return == 1: logger.info(f' mail envoyé : {mail_return} - {self.email}') - else : + else: logger.error(f' mail non envoyé : {mail_return} - {self.email}') return mail - else : + else: 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() logger.info(f'{timezone.now()} on lance le thread email {self.email}') thread_email = threading.Thread(target=self.send) thread_email.start() - logger.info(f'{timezone.now()} Thread email lancé') \ No newline at end of file + logger.info(f'{timezone.now()} Thread email lancé') diff --git a/DjangoFiles/ApiBillet/urls.py b/DjangoFiles/ApiBillet/urls.py index 4308307..ed3a281 100644 --- a/DjangoFiles/ApiBillet/urls.py +++ b/DjangoFiles/ApiBillet/urls.py @@ -15,6 +15,8 @@ router.register(r'reservations', api_view.ReservationViewset, basename='reservat urlpatterns = [ path('', include(router.urls)), - path('ticket/', TicketPdf.as_view(), name='ticket_uuid'), + + #download ticket : + path('ticket/pdf/', TicketPdf.as_view(), name='ticket_uuid_to_pdf'), ] \ No newline at end of file diff --git a/DjangoFiles/ApiBillet/views.py b/DjangoFiles/ApiBillet/views.py index dd5d7c2..a2679b8 100644 --- a/DjangoFiles/ApiBillet/views.py +++ b/DjangoFiles/ApiBillet/views.py @@ -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 # diff --git a/DjangoFiles/BaseBillet/models.py b/DjangoFiles/BaseBillet/models.py index c1ac64e..8e2f6b9 100644 --- a/DjangoFiles/BaseBillet/models.py +++ b/DjangoFiles/BaseBillet/models.py @@ -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: diff --git a/DjangoFiles/BaseBillet/signals.py b/DjangoFiles/BaseBillet/signals.py index 5728cd7..e139ce2 100644 --- a/DjangoFiles/BaseBillet/signals.py +++ b/DjangoFiles/BaseBillet/signals.py @@ -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() - 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() +# 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 {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) diff --git a/DjangoFiles/BaseBillet/urls.py b/DjangoFiles/BaseBillet/urls.py index 8be85e7..c19b494 100644 --- a/DjangoFiles/BaseBillet/urls.py +++ b/DjangoFiles/BaseBillet/urls.py @@ -3,6 +3,6 @@ from django.urls import include, path, re_path from BaseBillet import views as base_view urlpatterns = [ - path('event/', base_view.event.as_view()), + path('ticket/', base_view.Ticket_html_view.as_view()), path('', base_view.index.as_view(), name="index"), ] \ No newline at end of file diff --git a/DjangoFiles/BaseBillet/views.py b/DjangoFiles/BaseBillet/views.py index f31af96..4e4a3cc 100644 --- a/DjangoFiles/BaseBillet/views.py +++ b/DjangoFiles/BaseBillet/views.py @@ -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) \ No newline at end of file diff --git a/DjangoFiles/BaseBillet/x_mvc_views.py b/DjangoFiles/BaseBillet/x_mvc_views.py new file mode 100644 index 0000000..f31af96 --- /dev/null +++ b/DjangoFiles/BaseBillet/x_mvc_views.py @@ -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) diff --git a/DjangoFiles/PaiementStripe/views.py b/DjangoFiles/PaiementStripe/views.py index 0f649f2..bd3de7d 100644 --- a/DjangoFiles/PaiementStripe/views.py +++ b/DjangoFiles/PaiementStripe/views.py @@ -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}') diff --git a/DjangoFiles/TiBillet/settings.py b/DjangoFiles/TiBillet/settings.py index 1b3b691..bc16b11 100644 --- a/DjangoFiles/TiBillet/settings.py +++ b/DjangoFiles/TiBillet/settings.py @@ -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", }, diff --git a/Docker/Dockerfile/dockerfile b/Docker/Dockerfile/dockerfile index 4a122ab..6ab38d8 100644 --- a/Docker/Dockerfile/dockerfile +++ b/Docker/Dockerfile/dockerfile @@ -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 +