création d'evenements

This commit is contained in:
Jonas Legion 2021-06-29 16:34:51 +02:00
parent 52b413b3a6
commit 1c08754905
13 changed files with 483 additions and 186 deletions

View File

@ -53,6 +53,7 @@ class UserAdminTibillet(UserAdmin):
'first_name', 'first_name',
'last_name', 'last_name',
'email', 'email',
'phone',
'client_source', 'client_source',
'client_admin', 'client_admin',
'client_achat', 'client_achat',

View File

@ -4,7 +4,7 @@ from django.contrib.auth.models import Group
from solo.admin import SingletonModelAdmin from solo.admin import SingletonModelAdmin
from AuthBillet.models import HumanUser, SuperHumanUser, TermUser from AuthBillet.models import HumanUser, SuperHumanUser, TermUser
from BaseBillet.models import Configuration, Event, OptionGenerale from BaseBillet.models import Configuration, Event, OptionGenerale, Article, Billet, Reservation, LigneArticle
from django.contrib.auth.admin import UserAdmin from django.contrib.auth.admin import UserAdmin
from Customers.models import Client from Customers.models import Client
@ -124,4 +124,25 @@ class OptionGeneraleAdmin(admin.ModelAdmin):
'poids', 'poids',
) )
class ReservationAdmin(admin.ModelAdmin):
list_display = (
'user_mail',
'total_billet',
'_options_',
'total_prix',
'status'
)
readonly_fields = list_display
staff_admin_site.register(Reservation, ReservationAdmin)
staff_admin_site.register(OptionGenerale, OptionGeneraleAdmin) staff_admin_site.register(OptionGenerale, OptionGeneraleAdmin)
staff_admin_site.register(Billet, admin.ModelAdmin)
staff_admin_site.register(Article, admin.ModelAdmin)
staff_admin_site.register(LigneArticle, admin.ModelAdmin)

View File

@ -1,11 +1,11 @@
from django.contrib.auth.tokens import default_token_generator from django.contrib.auth.tokens import default_token_generator
from rest_framework import serializers from rest_framework import serializers
from templated_mail.mail import BaseEmailMessage from templated_mail.mail import BaseEmailMessage
from django.utils.translation import ugettext_lazy as _
from djoser import utils from djoser import utils
from djoser.conf import settings from djoser.conf import settings
from BaseBillet.models import Configuration
class ActivationEmail(BaseEmailMessage): class ActivationEmail(BaseEmailMessage):
@ -28,9 +28,8 @@ class ActivationEmail(BaseEmailMessage):
return context return context
def send(self, to, *args, **kwargs): def send(self, to, *args, **kwargs):
configuration = Configuration.get_solo()
if not configuration.email : from_email = kwargs.get('from_email', 'contact@tibillet.re')
return serializers.ValidationError(_(f"Manque l'email de la structure. Merci de configurer votre instance."))
self.render() self.render()
@ -39,11 +38,12 @@ class ActivationEmail(BaseEmailMessage):
self.bcc = kwargs.pop('bcc', []) self.bcc = kwargs.pop('bcc', [])
self.reply_to = kwargs.pop('reply_to', []) self.reply_to = kwargs.pop('reply_to', [])
self.from_email = kwargs.pop( self.from_email = kwargs.pop(
'from_email', configuration.email 'from_email', from_email
) )
# import ipdb; ipdb.set_trace() # import ipdb; ipdb.set_trace()
mail_send = super(BaseEmailMessage, self).send(*args, **kwargs) mail_send = super(BaseEmailMessage, self).send(*args, **kwargs)
print(f'mail_send to {self.to} from {self.from_email} : {mail_send}') print(f'mail_send to {self.to} from {self.from_email} : {mail_send}')

View File

@ -53,6 +53,7 @@ class TibilletUser(AbstractUser):
email = models.EmailField(_('email'), unique=True) # changes email to unique and blank to false email = models.EmailField(_('email'), unique=True) # changes email to unique and blank to false
username = models.CharField(max_length=200, null=True, blank=True) username = models.CharField(max_length=200, null=True, blank=True)
phone = models.CharField(max_length=20, null=True, blank=True)
TYPE_TERM, TYPE_HUM, TYPE_ANDR = 'TE', 'HU', 'AN' TYPE_TERM, TYPE_HUM, TYPE_ANDR = 'TE', 'HU', 'AN'
ESPECE_CHOICES = ( ESPECE_CHOICES = (

View File

@ -0,0 +1,7 @@
from django.urls import include, path, re_path
from AuthBillet import views as auth_view
urlpatterns = [
re_path('activate/<str:uid>/<str:token>', auth_view.activate.as_view()),
]

View File

@ -1,3 +1,16 @@
from django.shortcuts import render from django.shortcuts import render
# Create your views here. # Create your views here.
from rest_framework import status
from rest_framework.permissions import AllowAny
from rest_framework.response import Response
from rest_framework.views import APIView
class activate(APIView):
permission_classes = [AllowAny]
def get(self, uid, token):
print(uid, token)
return Response(f'{uid} {token}', status=status.HTTP_200_OK)

View File

@ -1,3 +1,6 @@
import uuid
from django.contrib.auth import get_user_model
from django.db import models from django.db import models
# Create your models here. # Create your models here.
@ -8,6 +11,8 @@ from django.utils.translation import ugettext_lazy as _
from stdimage import StdImageField from stdimage import StdImageField
from stdimage.validators import MaxSizeValidator from stdimage.validators import MaxSizeValidator
from TiBillet import settings
class OptionGenerale(models.Model): class OptionGenerale(models.Model):
name = models.CharField(max_length=30) name = models.CharField(max_length=30)
@ -60,8 +65,6 @@ class Configuration(SingletonModel):
mollie_api_key = models.CharField(max_length=50, mollie_api_key = models.CharField(max_length=50,
blank=True, null=True) blank=True, null=True)
reservation_par_user_max = models.PositiveSmallIntegerField(default=6)
jauge_max = models.PositiveSmallIntegerField(default=50) jauge_max = models.PositiveSmallIntegerField(default=50)
option_generale_radio = models.ManyToManyField(OptionGenerale, option_generale_radio = models.ManyToManyField(OptionGenerale,
@ -73,11 +76,42 @@ class Configuration(SingletonModel):
related_name="checkbox") related_name="checkbox")
class Billet(models.Model):
name = models.CharField(max_length=50,
blank=True, null=True)
prix = models.FloatField()
reservation_par_user_max = models.PositiveSmallIntegerField(default=6)
def range_max(self):
return range(self.reservation_par_user_max + 1)
def __str__(self):
return f"{self.name}"
class Article(models.Model):
name = models.CharField(max_length=50,
blank=True, null=True)
prix = models.FloatField()
stock = models.SmallIntegerField(blank=True, null=True)
reservation_par_user_max = models.PositiveSmallIntegerField(default=10)
def range_max(self):
return range(self.reservation_par_user_max + 1)
def __str__(self):
return f"{self.name}"
class Event(models.Model): class Event(models.Model):
name = models.CharField(max_length=200) name = models.CharField(max_length=200)
short_description = models.CharField(max_length=250) short_description = models.CharField(max_length=250)
long_description = models.TextField(blank=True, null=True) long_description = models.TextField(blank=True, null=True)
datetime = models.DateTimeField() datetime = models.DateTimeField()
billets = models.ManyToManyField(Billet)
articles = models.ManyToManyField(Article)
img = StdImageField(upload_to='images/', img = StdImageField(upload_to='images/',
null=True, blank=True, null=True, blank=True,
@ -105,19 +139,74 @@ class Event(models.Model):
verbose_name_plural = _('Evenements') verbose_name_plural = _('Evenements')
class reservation(models.Model): class Reservation(models.Model):
uuid = models.UUIDField(primary_key=True, db_index=True, default=uuid.uuid4)
user_commande = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT)
event = models.ForeignKey(Event, event = models.ForeignKey(Event,
on_delete=models.CASCADE, on_delete=models.CASCADE,
related_name="reservation") related_name="reservation")
ANNULEE, NON_VALIDEE, VALIDEE, PAYEE = 'NAN', 'NOV', 'VAL', 'PAY' ANNULEE, MAIL_NON_VALIDEE, NON_PAYEE, VALIDEE, PAYEE = 'NAN', 'MNV', 'NPA', 'VAL', 'PAY'
TYPE_CHOICES = [ TYPE_CHOICES = [
(ANNULEE, _('Annulée')), (ANNULEE, _('Annulée')),
(NON_VALIDEE, _('Email non validé')), (MAIL_NON_VALIDEE, _('Email non validé')),
(NON_PAYEE, _('Non payée')),
(VALIDEE, _('Validée')), (VALIDEE, _('Validée')),
(PAYEE, _('Payée')), (PAYEE, _('Payée')),
] ]
status = models.CharField(max_length=3, choices=TYPE_CHOICES, default=NON_VALIDEE,
status = models.CharField(max_length=3, choices=TYPE_CHOICES, default=NON_PAYEE,
verbose_name=_("Status de la réservation")) verbose_name=_("Status de la réservation"))
qty = models.IntegerField() options = models.ManyToManyField(OptionGenerale)
def __str__(self):
return self.user_commande.email
def user_mail(self):
return self.user_commande.email
def total_billet(self):
total = 0
for ligne in self.lignearticle_set.all():
if ligne.billet:
total += ligne.qty
return total
def total_prix(self):
total = 0
for ligne in self.lignearticle_set.all():
if ligne.article :
total += ligne.qty * ligne.article.prix
if ligne.billet :
total += ligne.qty * ligne.billet.prix
return total
def _options_(self):
return " - ".join([f"{option.name}" for option in self.options.all()])
@receiver(post_save, sender=Reservation)
def poids_option_generaler(sender, instance: Reservation, created, **kwargs):
if created:
if not instance.user_commande.is_active :
instance.status = instance.MAIL_NON_VALIDEE
instance.save()
class LigneArticle(models.Model):
uuid = models.UUIDField(primary_key=True, db_index=True, default=uuid.uuid4)
reservation = models.ForeignKey(Reservation, on_delete=models.CASCADE, verbose_name="lignes_article")
article = models.ForeignKey(Article, on_delete=models.CASCADE, blank=True, null=True)
billet = models.ForeignKey(Billet, on_delete=models.CASCADE, blank=True, null=True)
qty = models.SmallIntegerField()
reste = models.SmallIntegerField()
def __str__(self):
if self.article :
return f"{self.reservation.user_commande.email} {self.qty} {self.article}"
if self.billet :
return f"{self.reservation.user_commande.email} {self.qty} {self.billet}"

View File

@ -1,27 +1,27 @@
{% block header %} {% block header %}
<!DOCTYPE HTML> <!DOCTYPE HTML>
<!-- <!--
Massively by HTML5 UP Massively by HTML5 UP
html5up.net | @ajlkn html5up.net | @ajlkn
Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
--> -->
<html lang="fr"> <html lang="fr">
<head> <head>
<title>{{ configuration.organisation }}</title> <title>{{ configuration.organisation }}</title>
<meta charset="utf-8"/> <meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"/> <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"/>
{% load static %} {% load static %}
<style> <style>
#wrapper > .bg { #wrapper > .bg {
background-image: url("{% static 'html5up-massively/images/overlay.png' %}"), linear-gradient(0deg, rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.1)), url("/media/{{ configuration.img }}"); background-image: url("{% static 'html5up-massively/images/overlay.png' %}"), linear-gradient(0deg, rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.1)), url("/media/{{ configuration.img }}");
} }
</style> </style>
<link rel="stylesheet" href="{% static 'html5up-massively/assets/css/main.css' %}"/> <link rel="stylesheet" href="{% static 'html5up-massively/assets/css/main.css' %}"/>
{# <noscript>#} {# <noscript>#}
{# <link rel="stylesheet" href="{% static 'html5up-massively/assets/css/noscript.css' %}"/>#} {# <link rel="stylesheet" href="{% static 'html5up-massively/assets/css/noscript.css' %}"/>#}
{# </noscript>#} {# </noscript>#}
</head> </head>
{% endblock header %} {% endblock header %}
@ -31,23 +31,22 @@
{% block footer %} {% block footer %}
<!-- Footer --> <!-- Footer -->
{# <footer>#} {# <footer>#}
{# <div class="pagination">#} {# <div class="pagination">#}
{# <!--<a href="#" class="previous">Prev</a>-->#} {# <!--<a href="#" class="previous">Prev</a>-->#}
{# <a href="#" class="page active">1</a>#} {# <a href="#" class="page active">1</a>#}
{# <a href="#" class="page">2</a>#} {# <a href="#" class="page">2</a>#}
{# <a href="#" class="page">3</a>#} {# <a href="#" class="page">3</a>#}
{# <span class="extra">&hellip;</span>#} {# <span class="extra">&hellip;</span>#}
{# <a href="#" class="page">8</a>#} {# <a href="#" class="page">8</a>#}
{# <a href="#" class="page">9</a>#} {# <a href="#" class="page">9</a>#}
{# <a href="#" class="page">10</a>#} {# <a href="#" class="page">10</a>#}
{# <a href="#" class="next">Next</a>#} {# <a href="#" class="next">Next</a>#}
{# </div>#} {# </div>#}
{# </footer>#} {# </footer>#}
</div>
<!-- Footer --> <!-- Footer -->
<footer id="footer"> <footer id="footer">
@ -83,7 +82,7 @@
</section> </section>
<section> <section>
<h3>Email</h3> <h3>Email</h3>
<p>{{ configuration.email }}</p> <p><a href="mailto:{{ configuration.email }}">{{ configuration.email }}</a></p>
</section> </section>
<section> <section>
<h3>Social</h3> <h3>Social</h3>
@ -115,19 +114,17 @@
</ul> </ul>
</div> </div>
</div>
<!-- Scripts --> <script src="{% static 'html5up-massively/assets/js/jquery.min.js' %}"></script>
<script src="{% static 'html5up-massively/assets/js/jquery.min.js' %}"></script> <script src="{% static 'html5up-massively/assets/js/jquery.scrollex.min.js' %}"></script>
<script src="{% static 'html5up-massively/assets/js/jquery.scrollex.min.js' %}"></script> <script src="{% static 'html5up-massively/assets/js/jquery.scrolly.min.js' %}"></script>
<script src="{% static 'html5up-massively/assets/js/jquery.scrolly.min.js' %}"></script> <script src="{% static 'html5up-massively/assets/js/browser.min.js' %}"></script>
<script src="{% static 'html5up-massively/assets/js/browser.min.js' %}"></script> <script src="{% static 'html5up-massively/assets/js/breakpoints.min.js' %}"></script>
<script src="{% static 'html5up-massively/assets/js/breakpoints.min.js' %}"></script> <script src="{% static 'html5up-massively/assets/js/util.js' %}"></script>
<script src="{% static 'html5up-massively/assets/js/util.js' %}"></script> <script src="{% static 'html5up-massively/assets/js/main.js' %}"></script>
<script src="{% static 'html5up-massively/assets/js/main.js' %}"></script>
</body> </body>
</html> </html>
{% endblock footer %} {% endblock footer %}

View File

@ -3,122 +3,153 @@
<!-- Wrapper --> <!-- Wrapper -->
<div id="wrapper"> <div id="wrapper">
<!-- Header --> <!-- Header -->
<header id="header"> <header id="header">
<a href="/" class="logo">{{ configuration.organisation }}</a> <a href="/" class="logo">{{ configuration.organisation }}</a>
</header> </header>
<!-- Nav --> <!-- Nav -->
<nav id="nav"> <nav id="nav">
<ul class="links"> <ul class="links">
<li class="active"><a href="index.html">Billetterie</a></li> <li class="active"><a href="index.html">Billetterie</a></li>
<li><a href="">Informations</a></li> <li><a href="">Informations</a></li>
<li><a href="">Cashless</a></li> <li><a href="">Cashless</a></li>
</ul> </ul>
<ul class="icons"> <ul class="icons">
{% if configuration.twitter %} {% if configuration.twitter %}
<li><a href="{{ configuration.twitter }}" class="icon brands fa-twitter"><span <li><a href="{{ configuration.twitter }}" class="icon brands fa-twitter"><span
class="label">Twitter</span></a></li> class="label">Twitter</span></a></li>
{% endif %} {% endif %}
{% if configuration.facebook %} {% if configuration.facebook %}
<li><a href="{{ configuration.facebook }}" class="icon brands fa-facebook-f"><span <li><a href="{{ configuration.facebook }}" class="icon brands fa-facebook-f"><span
class="label">Facebook</span></a> class="label">Facebook</span></a>
</li> </li>
{% endif %} {% endif %}
{% if configuration.instagram %} {% if configuration.instagram %}
<li><a href="{{ configuration.instagram }}" class="icon brands fa-instagram"><span <li><a href="{{ configuration.instagram }}" class="icon brands fa-instagram"><span
class="label">Instagram</span></a> class="label">Instagram</span></a>
</li> </li>
{% endif %} {% endif %}
</ul> </ul>
</nav> </nav>
<!-- Main --> <!-- Main -->
<div id="main"> <div id="main">
<!-- Post --> <!-- Post -->
<section class="post"> <section class="post">
<header class="major"> <header class="major">
<span class="date">{{ event.datetime | date:"d F Y" }}<br/>{{ event.datetime | time }}</span> <span class="date">{{ event.datetime | date:"d F Y" }}<br/>{{ event.datetime | time }}</span>
<h1>{{ event.name }}</h1> <h1>{{ event.name }}</h1>
<p>{{ event.short_description }}</p> <p>{{ event.short_description }}</p>
</header> </header>
<div class="image main"><img src="/media/{{ event.img.fhd }}" alt=""/></div> <div class="image main"><img src="/media/{{ event.img.fhd }}" alt=""/></div>
<p>{{ event.long_description | linebreaks }}</p> <p>{{ event.long_description | linebreaks }}</p>
</section> </section>
{% if not event.complet %} {% if not event.complet %}
<!-- Form --> <!-- Form -->
<form id="reservation" method="post" action="#"> <form id="reservation" method="post" action="#">
{% csrf_token %} {% csrf_token %}
<h2>RESERVEZ</h2> <h2>RESERVEZ</h2>
<div class="row gtr-uniform"> <div class="row gtr-uniform">
<div class="col-6 col-12-xsmall"> <div class="col-6 col-12-xsmall">
<input type="text" name="nom" id="nom" value="" placeholder="Nom" required="True"/> <input type="text" name="nom" id="nom" value="" placeholder="Nom" required="True"/>
</div>
<div class="col-6 col-12-xsmall">
<input type="text" name="prenom" id="prenom" value="" placeholder="Prénom" required="True"/>
</div>
<div class="col-12 col-12-xsmall">
<input type="email" name="email" id="email" value="" placeholder="Email" required="True"/>
</div>
<div class="col-12 col-12-xsmall">
<input type="text" name="phone" id="phone" value="" placeholder="Téléphone" required="True"/>
</div>
<!-- Break -->
<div class="col-12">
<select name="qty" id="qty" required="True">
<option value="">- Quantitée -</option>
{# {% for nbr in configuration.reservation_max %}#}
<option value="{{ configuration.reservation_par_user_max }}">{{ configuration.reservation_par_user_max }}</option>
{# {% endfor %}#}
</select>
</div>
<!-- Break -->
{% for option_radio in configuration.option_generale_radio.all %}
<div class="col-4 col-12-small">
<input type="radio" id="{{ option_radio.name }}" name="radio_generale"
value="{{ option_radio.pk }}">
<label for="{{ option_radio.name }}">{{ option_radio.name }}</label>
</div> </div>
{% endfor %} <div class="col-6 col-12-xsmall">
<!-- Break --> <input type="text" name="prenom" id="prenom" value="" placeholder="Prénom" required="True"/>
{% for option_checkbox in configuration.option_generale_checkbox.all %} </div>
<div class="col-12 col-12-xsmall">
<div class="col-6 col-12-small"> <input id="email" name="email" placeholder="Email" required="True" type="email" value=""/>
<input type="checkbox" id="{{ option_checkbox.name }}" name="{{ option_checkbox.name }}" </div>
value="{{ option_checkbox.pk }}"> <div class="col-12 col-12-xsmall">
<label for="{{ option_checkbox.name }}">{{ option_checkbox.name }}</label> <input id="phone" name="phone" placeholder="Téléphone" required="True" type="text"
value=""/>
</div> </div>
{% endfor %} <!-- Break -->
<!-- Break --> {% for billet in event.billets.all %}
{# <div class="col-12">#} <div class="col-4 col-12-medium col-12-small">
{# <textarea name="demo-message" id="demo-message" placeholder="Enter your message"#} <label for="{{ billet.name }}">
{# rows="6"></textarea>#} BILLET {{ billet.name }} : {{ billet.prix | floatformat:"-2" }}€
{# </div>#} </label>
<!-- Break --> <select name="billets" id="{{ billet.name }}">
<div class="col-12"> {% for nbr in billet.range_max %}
<ul class="actions"> <option value="{{ billet.pk }},{{ nbr }}">{{ nbr }}</option>
<li><input type="submit" value="validez" class="primary"/></li> {% endfor %}
<li><input type="reset" value="Reset"/></li> </select>
</ul> </div>
{% endfor %}
{% for article in event.articles.all %}
<div class="col-4 col-12-medium col-12-small">
<label for="{{ article.name }}">
{{ article.name }} : {{ article.prix | floatformat:"-2" }}€
</label>
<select name="articles" id="{{ article.name }}">
{% for nbr in article.range_max %}
<option value="{{ article.pk }},{{ nbr }}">{{ nbr }}</option>
{% endfor %}
</select>
</div>
{% endfor %}
<div class="row">
<!-- Break -->
{% for option_radio in configuration.option_generale_radio.all %}
<div class="col-12-small">
<input type="radio" id="{{ option_radio.name }}" name="radio_generale"
value="{{ option_radio.pk }}">
<label for="{{ option_radio.name }}">{{ option_radio.name }}</label>
</div>
{% endfor %}
<!-- Break -->
</div>
<div class="row">
{% for option_checkbox in configuration.option_generale_checkbox.all %}
<div class="col-12-small">
<input type="checkbox" id="{{ option_checkbox.pk }}"
name="option_checkbox"
value="{{ option_checkbox.pk }}">
<label for="{{ option_checkbox.pk }}">{{ option_checkbox.name }}</label>
</div>
{% endfor %}
</div>
<!-- Break -->
{# <div class="col-12">#}
{# <textarea name="demo-message" id="demo-message" placeholder="Enter your message"#}
{# rows="6"></textarea>#}
{# </div>#}
<!-- Break -->
<div class="col-12">
<ul class="actions">
<li><input type="submit" value="validez" class="primary"/></li>
<li><input type="reset" value="Reset"/></li>
</ul>
</div>
</div> </div>
</brdiv> </form>
</form>
<hr/> <hr/>
{% else %} {% else %}
<h2>COMPLET</h2> <h2>COMPLET</h2>
{% endif %} {% endif %}
</div>
</div> </div>
{% endblock content %} {% endblock content %}

View File

@ -1,22 +1,38 @@
from rest_framework import serializers from rest_framework import serializers
from django.utils import timezone from django.utils import timezone
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from BaseBillet.models import OptionGenerale, Configuration, Event from BaseBillet.models import OptionGenerale, Configuration, Event, Article, Billet
class ReservationValidator(serializers.Serializer): class ReservationValidator(serializers.Serializer):
nom = serializers.CharField(max_length=100, required=True) nom = serializers.CharField(max_length=100, required=True)
prenom = serializers.CharField(max_length=100, required=True) prenom = serializers.CharField(max_length=100, required=True)
email = serializers.EmailField(required=True) email = serializers.EmailField(required=True)
phone = serializers.CharField(max_length=100, required=True) phone = serializers.CharField(max_length=20, required=True)
qty = serializers.IntegerField(required=True)
radio_generale = serializers.PrimaryKeyRelatedField(queryset=OptionGenerale.objects.all(), many=True) radio_generale = serializers.PrimaryKeyRelatedField(queryset=OptionGenerale.objects.all(), many=True)
option_checkbox = serializers.PrimaryKeyRelatedField(queryset=OptionGenerale.objects.all(), many=True)
articles = serializers.ListField()
billets = serializers.ListField()
def validate_qty(self, value): def validate_articles(self, value):
configuration = Configuration.get_solo() value_dict = {}
if value <= configuration.reservation_par_user_max : art_obj = Article.objects.all()
return value for couple in value:
else : pk, qty = art_obj.get(pk=couple.split(',')[0]), int(couple.split(',')[1])
raise serializers.ValidationError(_(f"Pas plus de {configuration.reservation_par_user_max} places en même temps.")) value_dict[pk] = qty
return value_dict
def validate_billets(self, value):
value_dict = {}
billet_obj = Billet.objects.all()
for couple in value:
pk, qty = billet_obj.get(pk=couple.split(',')[0]), int(couple.split(',')[1])
value_dict[pk] = qty
return value_dict
#
# # if value <= configuration.reservation_par_user_max :
# return value
# else :
# raise serializers.ValidationError(_(f"Pas plus de {configuration.reservation_par_user_max} places en même temps."))

View File

@ -1,5 +1,6 @@
from datetime import datetime from datetime import datetime
from django.contrib.auth import get_user_model
from django.shortcuts import render, redirect from django.shortcuts import render, redirect
# Create your views here. # Create your views here.
@ -10,8 +11,13 @@ from rest_framework.views import APIView
from rest_framework.response import Response from rest_framework.response import Response
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from BaseBillet.models import Configuration, Event from AuthBillet.email import ActivationEmail
from BaseBillet.models import Configuration, Event, Reservation, LigneArticle
from BaseBillet.validator import ReservationValidator from BaseBillet.validator import ReservationValidator
from django.db import connection
from AuthBillet.models import TibilletUser
from threading import Thread
class index(APIView): class index(APIView):
@ -21,9 +27,9 @@ class index(APIView):
configuration = Configuration.get_solo() configuration = Configuration.get_solo()
events = Event.objects.filter(datetime__gt=datetime.now()) events = Event.objects.filter(datetime__gt=datetime.now())
if len(events) > 0 : if len(events) > 0:
first_event = events[0] first_event = events[0]
else : else:
first_event = None first_event = None
context = { context = {
@ -35,7 +41,40 @@ class index(APIView):
return render(request, 'html5up-massively/index.html', context=context) 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,
reste = qty,
)
for article in data.get('articles'):
qty = data.get('articles')[article]
LigneArticle.objects.create(
reservation = reservation,
article = article,
qty = qty,
reste = qty,
)
return reservation
class event(APIView): class event(APIView):
permission_classes = [AllowAny] permission_classes = [AllowAny]
@ -53,23 +92,74 @@ class event(APIView):
def post(self, request, id): def post(self, request, id):
print(request.data)
# for key, value in enumerate(request.data):
# print(key, value, request.data[value])
# print(request.POST)
# for key, value in enumerate(request.POST):
# print(key, value, request.data[value])
# import ipdb; ipdb.set_trace()
reservation_validator = ReservationValidator(data=request.data) reservation_validator = ReservationValidator(data=request.data)
if reservation_validator.is_valid(): if reservation_validator.is_valid():
print(reservation_validator.validated_data)
configuration = Configuration.get_solo()
context = {}
data_reservation = reservation_validator.validated_data data_reservation = reservation_validator.validated_data
event = get_object_or_404(Event, pk=id) event = get_object_or_404(Event, pk=id)
configuration = Configuration.get_solo()
reste_place = configuration.jauge_max - event.reservations # import ipdb; ipdb.set_trace()
if data_reservation.get('qty') > reste_place: # reste_place = configuration.jauge_max - event.reservations
raise serializers.ValidationError(_(f"Il ne reste plus que {reste_place} places")) # if data_reservation.get('qty') > reste_place:
# raise serializers.ValidationError(_(f"Il ne reste plus que {reste_place} places"))
context = { if request.user.is_anonymous:
'configuration': configuration, User: TibilletUser = get_user_model()
'event': event, email = data_reservation.get('email')
'message': 'Merci de valider votre réservation sur votre boite mail', 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:
print(f"{request.user} not active")
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) return render(request, 'html5up-massively/event.html', context=context)
else: else:
print(f"validator.errors : {reservation_validator.errors}") print(f"validator.errors : {reservation_validator.errors}")
return Response(reservation_validator.errors, status=status.HTTP_400_BAD_REQUEST) return Response(reservation_validator.errors, status=status.HTTP_400_BAD_REQUEST)

View File

@ -0,0 +1,29 @@
# Generated by Django 2.2 on 2021-06-23 09:51
from django.db import migrations, models
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('Customers', '0002_create_tenant_public'),
]
operations = [
migrations.AlterField(
model_name='client',
name='name',
field=models.CharField(db_index=True, max_length=100, unique=True),
),
migrations.AlterField(
model_name='client',
name='on_trial',
field=models.BooleanField(default=True),
),
migrations.AlterField(
model_name='client',
name='paid_until',
field=models.DateField(default=django.utils.timezone.now),
),
]

View File

@ -29,6 +29,8 @@ urlpatterns = [
re_path(r'^auth/', include('djoser.urls.authtoken')), re_path(r'^auth/', include('djoser.urls.authtoken')),
re_path(r'^auth/', include('djoser.urls.jwt')), re_path(r'^auth/', include('djoser.urls.jwt')),
path('activate/', include('AuthBillet.urls')),
path('', include('BaseBillet.urls')), path('', include('BaseBillet.urls')),
# path('admin/', admin.site.urls, name="public_admin_url"), # path('admin/', admin.site.urls, name="public_admin_url"),