diff --git a/DjangoFiles/Administration/admin_public.py b/DjangoFiles/Administration/admin_public.py index ad36be2..1043443 100644 --- a/DjangoFiles/Administration/admin_public.py +++ b/DjangoFiles/Administration/admin_public.py @@ -10,7 +10,7 @@ from django.utils.translation import gettext, gettext_lazy as _ from QrcodeCashless.models import Detail, CarteCashless -# from boutique.models import Category, Product, Tag, VAT, Event, LandingPageContent, TarifBillet +# from boutique.models import Category, Product, Tag, VAT, Event, LandingPageContent, Price # from solo.admin import SingletonModelAdmin class PublicAdminSite(AdminSite): diff --git a/DjangoFiles/Administration/admin_tenant.py b/DjangoFiles/Administration/admin_tenant.py index 3fee623..4fd8fb8 100644 --- a/DjangoFiles/Administration/admin_tenant.py +++ b/DjangoFiles/Administration/admin_tenant.py @@ -4,7 +4,7 @@ from django.contrib.auth.models import Group from solo.admin import SingletonModelAdmin from AuthBillet.models import HumanUser, SuperHumanUser, TermUser -from BaseBillet.models import Configuration, Event, OptionGenerale, Article, TarifBillet, Reservation, LigneArticle +from BaseBillet.models import Configuration, Event, OptionGenerale, Product, Price, Reservation, LigneArticle from django.contrib.auth.admin import UserAdmin from Customers.models import Client @@ -106,7 +106,7 @@ class ConfigurationAdmin(SingletonModelAdmin): 'fields': ( 'organisation', 'short_description', - 'adresse', + 'adress', 'phone', 'email', 'site_web', @@ -186,24 +186,19 @@ class ReservationAdmin(admin.ModelAdmin): staff_admin_site.register(Reservation, ReservationAdmin) -class ArticleAdmin(admin.ModelAdmin): +class ProductAdmin(admin.ModelAdmin): list_display = ( 'name', - 'prix', - 'stock', - 'reservation_par_user_max', - 'vat', 'publish', + 'img', + 'categorie_article', + 'id_product_stripe', ) list_editable = ( - 'prix', - 'stock', - 'reservation_par_user_max', - 'vat', 'publish', ) -staff_admin_site.register(Article, ArticleAdmin) +staff_admin_site.register(Product, ProductAdmin) @@ -213,7 +208,7 @@ staff_admin_site.register(LigneArticle, admin.ModelAdmin) staff_admin_site.register(OptionGenerale, OptionGeneraleAdmin) -staff_admin_site.register(TarifBillet, admin.ModelAdmin) +staff_admin_site.register(Price, admin.ModelAdmin) class PaiementStripeAdmin(admin.ModelAdmin): @@ -223,12 +218,8 @@ class PaiementStripeAdmin(admin.ModelAdmin): 'total', 'order_date', 'status', - 'articles', ) ordering = ('-order_date',) - # readonly_fields = ( - # 'reservations', - # ) staff_admin_site.register(Paiement_stripe, PaiementStripeAdmin) diff --git a/DjangoFiles/ApiBillet/serializers.py b/DjangoFiles/ApiBillet/serializers.py index 5feb7ef..a89cf6a 100644 --- a/DjangoFiles/ApiBillet/serializers.py +++ b/DjangoFiles/ApiBillet/serializers.py @@ -3,47 +3,55 @@ import json from django.utils.translation import gettext, gettext_lazy as _ from rest_framework.generics import get_object_or_404 -from BaseBillet.models import Event, TarifBillet, Article +from BaseBillet.models import Event, Price, Product -class TarifsSerializer(serializers.ModelSerializer): + + +class ProductSerializer(serializers.ModelSerializer): class Meta: - model = TarifBillet + model = Product fields = [ - 'uuid', + "uuid", "name", - "prix", - "reservation_par_user_max", - ] - read_only_fields = ['uuid'] - - -class ArticleSerializer(serializers.ModelSerializer): - class Meta: - model = Article - fields = [ - 'uuid', - 'name', - 'prix', - 'stock', - 'reservation_par_user_max', - 'vat', - 'publish', - 'img', - 'categorie_article', - 'id_product_stripe', - 'id_price_stripe', + "publish", + "img", + "categorie_article", + "prices", + "id_product_stripe", ] + depth = 1 read_only_fields = [ 'uuid', 'id_product_stripe', + 'prices', + ] + +class PriceSerializer(serializers.ModelSerializer): + product = serializers.PrimaryKeyRelatedField(queryset=Product.objects.all()) + + class Meta: + model = Price + fields = [ + 'uuid', + 'product', + 'name', + 'prix', + 'vat', + 'id_price_stripe', + 'stock', + 'max_per_user', + ] + + read_only_fields = [ + 'uuid', 'id_price_stripe', ] depth = 1 class EventSerializer(serializers.ModelSerializer): - tarifs = TarifsSerializer( + products = ProductSerializer( many=True, read_only=True ) @@ -56,8 +64,7 @@ class EventSerializer(serializers.ModelSerializer): 'short_description', 'long_description', 'datetime', - 'tarifs', - 'articles', + 'products', 'img', 'reservations', 'complet', @@ -65,37 +72,36 @@ class EventSerializer(serializers.ModelSerializer): read_only_fields = ['uuid', 'reservations'] depth = 1 + def validate(self, attrs): - tarifs = self.initial_data.get('tarifs') - if tarifs: + products = self.initial_data.get('products') + if products: try: - tarifs_list = json.loads(tarifs) + products_list = json.loads(products) except json.decoder.JSONDecodeError as e: - raise serializers.ValidationError(_(f'tarifs doit être un json valide : {e}')) + raise serializers.ValidationError(_(f'products doit être un json valide : {e}')) - self.tarif_to_db = [] - for tarif in tarifs_list: - self.tarif_to_db.append(get_object_or_404(TarifBillet, uuid=tarif.get('uuid'))) + self.products_to_db = [] + for product in products_list: + self.products_to_db.append(get_object_or_404(Product, uuid=product.get('uuid'))) return super().validate(attrs) else: - raise serializers.ValidationError(_('tarifs doit être un json valide')) + raise serializers.ValidationError(_('products doit être un json valide')) def save(self, **kwargs): instance = super().save(**kwargs) - instance.tarifs.clear() - for tarif in self.tarif_to_db: - instance.tarifs.add(tarif) + instance.products.clear() + for product in self.products_to_db: + instance.products.add(product) return instance +''' -''' -[ - { - "uuid": "37a1093f-565d-4b38-858d-680568269d43", - }, - { - "uuid": "94d36be2-9bb9-4aa6-ab60-fc76287a1290", - } +products = [ + {"uuid":"9340a9a1-1b90-488e-ab68-7b358b213dd7"}, + {"uuid":"60db1531-fd0a-4d92-a785-f384e77cd213"} ] -''' + + +''' \ No newline at end of file diff --git a/DjangoFiles/ApiBillet/urls.py b/DjangoFiles/ApiBillet/urls.py index 95fde65..aedc44e 100644 --- a/DjangoFiles/ApiBillet/urls.py +++ b/DjangoFiles/ApiBillet/urls.py @@ -6,8 +6,8 @@ from rest_framework import routers router = routers.DefaultRouter() router.register(r'events', api_view.EventsViewSet, basename='event') -router.register(r'tarifs', api_view.TarifBilletViewSet, basename='billet') -router.register(r'articles', api_view.ArticleViewSet, basename='article') +router.register(r'products', api_view.ProductViewSet, basename='product') +router.register(r'prices', api_view.TarifBilletViewSet, basename='price') urlpatterns = [ diff --git a/DjangoFiles/ApiBillet/validators.py b/DjangoFiles/ApiBillet/validators.py index 012b19e..86fc347 100644 --- a/DjangoFiles/ApiBillet/validators.py +++ b/DjangoFiles/ApiBillet/validators.py @@ -1,16 +1,16 @@ from rest_framework import serializers import json -from BaseBillet.models import Event, TarifBillet +from BaseBillet.models import Event, Price class BilletSerializer(serializers.ModelSerializer): class Meta: - model = TarifBillet + model = Price fields = [ 'uuid', "name", "prix", - "reservation_par_user_max", + "max_per_user", ] @@ -20,7 +20,7 @@ class EventSerializer(serializers.ModelSerializer): many=True, read_only=True, ) - # billets = serializers.PrimaryKeyRelatedField(queryset=TarifBillet.objects.all(), many=True) + # billets = serializers.PrimaryKeyRelatedField(queryset=Price.objects.all(), many=True) class Meta: model = Event @@ -31,7 +31,7 @@ class EventSerializer(serializers.ModelSerializer): 'long_description', 'datetime', 'billets', - # 'articles', + # 'products', 'img', # 'reservations', 'complet', @@ -49,6 +49,6 @@ class EventSerializer(serializers.ModelSerializer): # billet_to_db = [] # for billet in billets_list : # billet_to_db.append(billet.get('uuid')) - # value['billets'] = serializers.ManyRelatedField(queryset=TarifBillet.objects.filter(uuid__in=billet_to_db), many=True) + # value['billets'] = serializers.ManyRelatedField(queryset=Price.objects.filter(uuid__in=billet_to_db), many=True) # return value diff --git a/DjangoFiles/ApiBillet/views.py b/DjangoFiles/ApiBillet/views.py index e5d5d2d..d9dd359 100644 --- a/DjangoFiles/ApiBillet/views.py +++ b/DjangoFiles/ApiBillet/views.py @@ -4,10 +4,10 @@ from django.shortcuts import render from rest_framework.generics import get_object_or_404 from rest_framework.response import Response -from ApiBillet.serializers import EventSerializer, TarifsSerializer, ArticleSerializer +from ApiBillet.serializers import EventSerializer, PriceSerializer, ProductSerializer from AuthBillet.models import TenantAdminPermission from Customers.models import Client, Domain -from BaseBillet.models import Event, TarifBillet, Article +from BaseBillet.models import Event, Price, Product from rest_framework import viewsets, permissions, status import os @@ -29,12 +29,12 @@ def new_tenants(schema_name): class TarifBilletViewSet(viewsets.ViewSet): def list(self, request): - queryset = TarifBillet.objects.all().order_by('prix') - serializer = TarifsSerializer(queryset, many=True, context={'request': request}) + queryset = Price.objects.all().order_by('prix') + serializer = PriceSerializer(queryset, many=True, context={'request': request}) return Response(serializer.data) def create(self, request): - serializer = TarifsSerializer(data=request.data) + serializer = PriceSerializer(data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) @@ -48,15 +48,15 @@ class TarifBilletViewSet(viewsets.ViewSet): return [permission() for permission in permission_classes] -class ArticleViewSet(viewsets.ViewSet): +class ProductViewSet(viewsets.ViewSet): def list(self, request): - serializer = ArticleSerializer(Article.objects.all(), many=True, context={'request': request}) + serializer = ProductSerializer(Product.objects.all(), many=True, context={'request': request}) print(serializer.data) return Response(serializer.data) def create(self, request): - serializer = ArticleSerializer(data=request.data) + serializer = ProductSerializer(data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) diff --git a/DjangoFiles/BaseBillet/migrations/0001_initial.py b/DjangoFiles/BaseBillet/migrations/0001_initial.py index c061e73..a019066 100644 --- a/DjangoFiles/BaseBillet/migrations/0001_initial.py +++ b/DjangoFiles/BaseBillet/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 2.2 on 2021-10-23 09:56 +# Generated by Django 2.2 on 2021-10-24 10:22 from django.conf import settings from django.db import migrations, models @@ -14,26 +14,11 @@ class Migration(migrations.Migration): dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('PaiementStripe', '0001_initial'), ('QrcodeCashless', '0002_cartecashless_user'), + ('PaiementStripe', '0001_initial'), ] operations = [ - migrations.CreateModel( - name='Article', - fields=[ - ('uuid', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True)), - ('name', models.CharField(blank=True, max_length=50, null=True)), - ('prix', models.FloatField()), - ('stock', models.SmallIntegerField(blank=True, null=True)), - ('reservation_par_user_max', models.PositiveSmallIntegerField(default=10)), - ('publish', models.BooleanField(default=False)), - ('img', stdimage.models.StdImageField(blank=True, null=True, upload_to='images/', validators=[stdimage.validators.MaxSizeValidator(1920, 1920)], verbose_name='Image')), - ('categorie_article', models.CharField(choices=[('B', 'Billet'), ('P', "Pack d'objets"), ('R', 'Recharge cashless'), ('T', 'Vetement'), ('M', 'Merchandasing'), ('A', 'Adhésion')], default='B', max_length=3, verbose_name="Type d'article")), - ('id_product_stripe', models.CharField(blank=True, max_length=30, null=True)), - ('id_price_stripe', models.CharField(blank=True, max_length=30, null=True)), - ], - ), migrations.CreateModel( name='Event', fields=[ @@ -45,7 +30,6 @@ class Migration(migrations.Migration): ('img', stdimage.models.StdImageField(upload_to='images/', validators=[stdimage.validators.MaxSizeValidator(1920, 1920)])), ('reservations', models.PositiveSmallIntegerField(default=0)), ('categorie', models.CharField(choices=[('LIV', 'Concert'), ('FES', 'Festival'), ('REU', 'Réunion'), ('CON', 'Conférence')], default='LIV', max_length=3, verbose_name="Catégorie d'évènement")), - ('articles', models.ManyToManyField(blank=True, to='BaseBillet.Article')), ], options={ 'verbose_name': 'Evenement', @@ -67,25 +51,16 @@ class Migration(migrations.Migration): }, ), migrations.CreateModel( - name='TarifBillet', + name='Product', fields=[ ('uuid', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True)), - ('name', models.CharField(blank=True, max_length=50, null=True)), - ('prix', models.FloatField()), - ('reservation_par_user_max', models.PositiveSmallIntegerField(default=6)), + ('name', models.CharField(max_length=50)), + ('publish', models.BooleanField(default=False)), + ('img', stdimage.models.StdImageField(blank=True, null=True, upload_to='images/', validators=[stdimage.validators.MaxSizeValidator(1920, 1920)], verbose_name='Image')), + ('categorie_article', models.CharField(choices=[('B', 'Billet'), ('P', "Pack d'objets"), ('R', 'Recharge cashless'), ('T', 'Vetement'), ('M', 'Merchandasing'), ('A', 'Adhésion')], default='B', max_length=3, verbose_name="Type d'article")), + ('id_product_stripe', models.CharField(blank=True, max_length=30, null=True)), ], ), - migrations.CreateModel( - name='VAT', - fields=[ - ('uuid', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True)), - ('percent', models.FloatField(verbose_name='Taux de TVA (%)')), - ], - options={ - 'verbose_name': 'TVA', - 'verbose_name_plural': 'TVA', - }, - ), migrations.CreateModel( name='Reservation', fields=[ @@ -96,31 +71,48 @@ class Migration(migrations.Migration): ('user_commande', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL)), ], ), + migrations.CreateModel( + name='Price', + fields=[ + ('uuid', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True)), + ('name', models.CharField(max_length=50)), + ('prix', models.FloatField()), + ('vat', models.CharField(choices=[('NA', 'Non applicable'), ('DX', '10 %'), ('VG', '20 %')], default='NA', max_length=2, verbose_name='Taux TVA')), + ('id_price_stripe', models.CharField(blank=True, max_length=30, null=True)), + ('stock', models.SmallIntegerField(blank=True, null=True)), + ('max_per_user', models.PositiveSmallIntegerField(default=10)), + ('product', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='BaseBillet.Product')), + ], + ), migrations.CreateModel( name='LigneArticle', fields=[ ('uuid', models.UUIDField(db_index=True, default=uuid.uuid4, primary_key=True, serialize=False)), - ('qty', models.SmallIntegerField()), ('datetime', models.DateTimeField(auto_now=True)), - ('article', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='BaseBillet.Article')), - ('billet', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='BaseBillet.TarifBillet')), + ('qty', models.SmallIntegerField()), ('carte', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='QrcodeCashless.CarteCashless')), ('paiement_stripe', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='PaiementStripe.Paiement_stripe')), + ('product', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='BaseBillet.Product')), ('reservation', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='BaseBillet.Reservation')), ], ), + migrations.AddField( + model_name='event', + name='products', + field=models.ManyToManyField(blank=True, to='BaseBillet.Product'), + ), migrations.AddField( model_name='event', name='tarifs', - field=models.ManyToManyField(to='BaseBillet.TarifBillet'), + field=models.ManyToManyField(to='BaseBillet.Price'), ), migrations.CreateModel( name='Configuration', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('organisation', models.CharField(max_length=50)), - ('short_description', models.CharField(max_length=250)), - ('adresse', models.CharField(max_length=250)), + ('organisation', models.CharField(max_length=50, verbose_name="Nom de l'organisation")), + ('short_description', models.CharField(max_length=250, verbose_name='Description courte')), + ('adress', models.CharField(max_length=250)), ('phone', models.CharField(max_length=20)), ('email', models.EmailField(max_length=254)), ('site_web', models.URLField(blank=True, null=True)), @@ -128,15 +120,14 @@ class Migration(migrations.Migration): ('facebook', models.URLField(blank=True, null=True)), ('instagram', models.URLField(blank=True, null=True)), ('adhesion_obligatoire', models.BooleanField(default=False)), - ('cadeau_adhesion', models.FloatField(default=0, help_text="Recharge cadeau a l'adhésion")), ('carte_restaurant', stdimage.models.StdImageField(blank=True, null=True, upload_to='images/', validators=[stdimage.validators.MaxSizeValidator(1920, 1920)], verbose_name='Carte du restaurant')), ('img', stdimage.models.StdImageField(blank=True, null=True, upload_to='images/', verbose_name='Background')), ('mollie_api_key', models.CharField(blank=True, max_length=50, null=True)), ('stripe_api_key', models.CharField(blank=True, max_length=110, null=True)), ('stripe_test_api_key', models.CharField(blank=True, max_length=110, null=True)), ('stripe_mode_test', models.BooleanField(default=True)), - ('activer_billetterie', models.BooleanField(default=True)), - ('jauge_max', models.PositiveSmallIntegerField(default=50)), + ('activer_billetterie', models.BooleanField(default=True, verbose_name='Activer la billetterie')), + ('jauge_max', models.PositiveSmallIntegerField(default=50, verbose_name='Jauge maximale')), ('server_cashless', models.URLField(blank=True, max_length=300, null=True, verbose_name='Adresse du serveur Cashless')), ('key_cashless', models.CharField(blank=True, max_length=41, null=True, verbose_name="Clé d'API du serveur cashless")), ('option_generale_checkbox', models.ManyToManyField(blank=True, related_name='checkbox', to='BaseBillet.OptionGenerale')), @@ -146,9 +137,4 @@ class Migration(migrations.Migration): 'abstract': False, }, ), - migrations.AddField( - model_name='article', - name='vat', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='BaseBillet.VAT', verbose_name='TVA'), - ), ] diff --git a/DjangoFiles/BaseBillet/migrations/0002_auto_20211024_1431.py b/DjangoFiles/BaseBillet/migrations/0002_auto_20211024_1431.py new file mode 100644 index 0000000..3c350e3 --- /dev/null +++ b/DjangoFiles/BaseBillet/migrations/0002_auto_20211024_1431.py @@ -0,0 +1,19 @@ +# Generated by Django 2.2 on 2021-10-24 10:31 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('BaseBillet', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='price', + name='product', + field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='prices', to='BaseBillet.Product'), + ), + ] diff --git a/DjangoFiles/BaseBillet/migrations/0003_remove_event_tarifs.py b/DjangoFiles/BaseBillet/migrations/0003_remove_event_tarifs.py new file mode 100644 index 0000000..829f9e8 --- /dev/null +++ b/DjangoFiles/BaseBillet/migrations/0003_remove_event_tarifs.py @@ -0,0 +1,17 @@ +# Generated by Django 2.2 on 2021-10-24 10:40 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('BaseBillet', '0002_auto_20211024_1431'), + ] + + operations = [ + migrations.RemoveField( + model_name='event', + name='tarifs', + ), + ] diff --git a/DjangoFiles/BaseBillet/models.py b/DjangoFiles/BaseBillet/models.py index 030c040..f65f785 100644 --- a/DjangoFiles/BaseBillet/models.py +++ b/DjangoFiles/BaseBillet/models.py @@ -43,10 +43,10 @@ def poids_option_generale(sender, instance: OptionGenerale, created, **kwargs): class Configuration(SingletonModel): - organisation = models.CharField(max_length=50) - short_description = models.CharField(max_length=250) + organisation = models.CharField(max_length=50, verbose_name=_("Nom de l'organisation")) + short_description = models.CharField(max_length=250, verbose_name=_("Description courte")) - adresse = models.CharField(max_length=250) + adress = models.CharField(max_length=250) phone = models.CharField(max_length=20) email = models.EmailField() @@ -57,7 +57,6 @@ class Configuration(SingletonModel): instagram = models.URLField(blank=True, null=True) adhesion_obligatoire = models.BooleanField(default=False) - cadeau_adhesion = models.FloatField(default=0, help_text="Recharge cadeau a l'adhésion") carte_restaurant = StdImageField(upload_to='images/', null=True, blank=True, @@ -69,7 +68,7 @@ class Configuration(SingletonModel): 'thumbnail': (150, 90), }, delete_orphans=True, - verbose_name='Carte du restaurant' + verbose_name=_('Carte du restaurant') ) img = StdImageField(upload_to='images/', @@ -92,9 +91,9 @@ class Configuration(SingletonModel): stripe_test_api_key = models.CharField(max_length=110, blank=True, null=True) stripe_mode_test = models.BooleanField(default=True) - activer_billetterie = models.BooleanField(default=True) + activer_billetterie = models.BooleanField(default=True, verbose_name=_("Activer la billetterie")) - jauge_max = models.PositiveSmallIntegerField(default=50) + jauge_max = models.PositiveSmallIntegerField(default=50, verbose_name=_("Jauge maximale")) option_generale_radio = models.ManyToManyField(OptionGenerale, blank=True, @@ -108,56 +107,22 @@ class Configuration(SingletonModel): max_length=300, blank=True, null=True, - verbose_name="Adresse du serveur Cashless" + verbose_name=_("Adresse du serveur Cashless") ) key_cashless = models.CharField( max_length=41, blank=True, null=True, - verbose_name="Clé d'API du serveur cashless" + verbose_name=_("Clé d'API du serveur cashless") ) -class TarifBillet(models.Model): - uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, unique=True, db_index=True) - 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 VAT(models.Model): - """ - Les différents taux de TVA sont associés à des produits. - """ - uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, unique=True, db_index=True) - percent = models.FloatField(verbose_name="Taux de TVA (%)") - - class Meta: - verbose_name = _('TVA') - verbose_name_plural = _('TVA') - - def __str__(self): - return f"{self.percent}%" - - -class Article(models.Model): +class Product(models.Model): uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, unique=True, db_index=True) name = models.CharField(max_length=50) - prix = models.FloatField() - stock = models.SmallIntegerField(blank=True, null=True) - - reservation_par_user_max = models.PositiveSmallIntegerField(default=10) - vat = models.ForeignKey(VAT, on_delete=models.PROTECT, verbose_name="TVA", null=True, blank=True) publish = models.BooleanField(default=False) @@ -188,11 +153,11 @@ class Article(models.Model): verbose_name=_("Type d'article")) id_product_stripe = models.CharField(max_length=30, null=True, blank=True) - id_price_stripe = models.CharField(max_length=30, null=True, blank=True) - def range_max(self): - return range(self.reservation_par_user_max + 1) + def __str__(self): + return f"{self.name}" + ''' def get_id_product_stripe(self): configuration = Configuration.get_solo() if configuration.stripe_api_key and not self.id_product_stripe: @@ -204,6 +169,7 @@ class Article(models.Model): if self.img: # noinspection PyUnresolvedReferences domain_url = connection.tenant.domains.all()[0].domain + # noinspection PyUnresolvedReferences images = [f"https://{domain_url}{self.img.med.url}", ] else: images = [] @@ -248,6 +214,37 @@ class Article(models.Model): self.id_price_stripe = None self.id_product_stripe = None self.save() + ''' + + +class Price(models.Model): + uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, unique=True, db_index=True) + + product = models.ForeignKey(Product, on_delete=models.PROTECT, related_name="prices") + + name = models.CharField(max_length=50) + prix = models.FloatField() + + NA, DIX, VINGT = 'NA', 'DX', 'VG' + TVA_CHOICES = [ + (NA, _('Non applicable')), + (DIX, _("10 %")), + (VINGT, _('20 %')), + ] + + vat = models.CharField(max_length=2, + choices=TVA_CHOICES, + default=NA, + verbose_name=_("Taux TVA"), + ) + + id_price_stripe = models.CharField(max_length=30, null=True, blank=True) + + stock = models.SmallIntegerField(blank=True, null=True) + max_per_user = models.PositiveSmallIntegerField(default=10) + + def range_max(self): + return range(self.max_per_user + 1) def __str__(self): return f"{self.name}" @@ -255,12 +252,14 @@ class Article(models.Model): class Event(models.Model): uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, unique=True, db_index=True) + name = models.CharField(max_length=200) + datetime = models.DateTimeField() + short_description = models.CharField(max_length=250) long_description = models.TextField(blank=True, null=True) - datetime = models.DateTimeField() - tarifs = models.ManyToManyField(TarifBillet) - articles = models.ManyToManyField(Article, blank=True) + + products = models.ManyToManyField(Product, blank=True) img = StdImageField(upload_to='images/', validators=[MaxSizeValidator(1920, 1920)], @@ -286,7 +285,7 @@ class Event(models.Model): ] categorie = models.CharField(max_length=3, choices=TYPE_CHOICES, default=CONCERT, - verbose_name=_("Catégorie d'évènement")) + verbose_name=_("Catégorie d'évènement")) def complet(self): # TODO: Benchmarker et tester si c'est pas mieux dans template @@ -343,8 +342,8 @@ class Reservation(models.Model): def total_prix(self): total = 0 for ligne in self.lignearticle_set.all(): - if ligne.article: - total += ligne.qty * ligne.article.prix + if ligne.product: + total += ligne.qty * ligne.product.prix if ligne.billet: total += ligne.qty * ligne.billet.prix @@ -357,6 +356,7 @@ class Reservation(models.Model): @receiver(post_save, sender=Reservation) def verif_mail_valide(sender, instance: Reservation, created, **kwargs): if created: + # noinspection PyUnresolvedReferences if not instance.user_commande.is_active: instance.status = instance.MAIL_NON_VALIDEE instance.save() @@ -364,10 +364,12 @@ def verif_mail_valide(sender, instance: Reservation, created, **kwargs): class LigneArticle(models.Model): uuid = models.UUIDField(primary_key=True, db_index=True, default=uuid.uuid4) - reservation = models.ForeignKey(Reservation, on_delete=models.CASCADE, blank=True, null=True) - article = models.ForeignKey(Article, on_delete=models.CASCADE, blank=True, null=True) - carte = models.ForeignKey(CarteCashless, on_delete=models.PROTECT, blank=True, null=True) - billet = models.ForeignKey(TarifBillet, on_delete=models.CASCADE, blank=True, null=True) - qty = models.SmallIntegerField() - paiement_stripe = models.ForeignKey(Paiement_stripe, on_delete=models.PROTECT, blank=True, null=True) datetime = models.DateTimeField(auto_now=True) + + product = models.ForeignKey(Product, on_delete=models.CASCADE, blank=True, null=True) + qty = models.SmallIntegerField() + + reservation = models.ForeignKey(Reservation, on_delete=models.CASCADE, blank=True, null=True) + carte = models.ForeignKey(CarteCashless, on_delete=models.PROTECT, blank=True, null=True) + + paiement_stripe = models.ForeignKey(Paiement_stripe, on_delete=models.PROTECT, blank=True, null=True) diff --git a/DjangoFiles/BaseBillet/validator.py b/DjangoFiles/BaseBillet/validator.py index 89ca191..5190c99 100644 --- a/DjangoFiles/BaseBillet/validator.py +++ b/DjangoFiles/BaseBillet/validator.py @@ -1,7 +1,7 @@ from rest_framework import serializers from django.utils import timezone from django.utils.translation import ugettext_lazy as _ -from BaseBillet.models import OptionGenerale, Configuration, Event, Article, TarifBillet +from BaseBillet.models import OptionGenerale, Configuration, Event, Product, Price class ReservationValidator(serializers.Serializer): @@ -16,7 +16,7 @@ class ReservationValidator(serializers.Serializer): def validate_articles(self, value): value_dict = {} - art_obj = Article.objects.all() + art_obj = Product.objects.all() for couple in value: pk, qty = art_obj.get(pk=couple.split(',')[0]), int(couple.split(',')[1]) value_dict[pk] = qty @@ -25,14 +25,14 @@ class ReservationValidator(serializers.Serializer): def validate_billets(self, value): value_dict = {} - billet_obj = TarifBillet.objects.all() + billet_obj = Price.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 : + # # if value <= configuration.max_per_user : # return value # else : - # raise serializers.ValidationError(_(f"Pas plus de {configuration.reservation_par_user_max} places en même temps.")) + # raise serializers.ValidationError(_(f"Pas plus de {configuration.max_per_user} places en même temps.")) diff --git a/DjangoFiles/BaseBillet/views.py b/DjangoFiles/BaseBillet/views.py index 1f8f516..f31af96 100644 --- a/DjangoFiles/BaseBillet/views.py +++ b/DjangoFiles/BaseBillet/views.py @@ -67,8 +67,8 @@ def creation_de_la_reservation(user: TibilletUser, event: Event, data): qty = qty, ) - for article in data.get('articles'): - qty = data.get('articles')[article] + for article in data.get('products'): + qty = data.get('products')[article] LigneArticle.objects.create( reservation = reservation, article = article, diff --git a/DjangoFiles/PaiementStripe/models.py b/DjangoFiles/PaiementStripe/models.py index d54a93c..0535df2 100644 --- a/DjangoFiles/PaiementStripe/models.py +++ b/DjangoFiles/PaiementStripe/models.py @@ -41,7 +41,7 @@ class Paiement_stripe(models.Model): return self.uuid_8() def articles(self): - return " - ".join([ f"{ligne.article.name} {ligne.qty * ligne.article.prix }€" for ligne in self.lignearticle_set.all() ]) + return " - ".join([ f"{ligne.product.name} {ligne.qty * ligne.product.prix }€" for ligne in self.lignearticle_set.all()]) diff --git a/DjangoFiles/PaiementStripe/views.py b/DjangoFiles/PaiementStripe/views.py index f7433f5..ecf77fd 100644 --- a/DjangoFiles/PaiementStripe/views.py +++ b/DjangoFiles/PaiementStripe/views.py @@ -64,7 +64,7 @@ class creation_paiement_stripe(): def _total(self): total = 0 for ligne in self.liste_ligne_article: - total += float(ligne.qty) * float(ligne.article.prix) + total += float(ligne.qty) * float(ligne.product.prix) return total def _paiement_stripe_db(self): @@ -96,7 +96,7 @@ class creation_paiement_stripe(): ligne: LigneArticle line_items.append( { - "price": f"{ligne.article.get_id_price_stripe()}", + "price": f"{ligne.product.get_id_price_stripe()}", "quantity": int(ligne.qty), } ) diff --git a/DjangoFiles/QrcodeCashless/views.py b/DjangoFiles/QrcodeCashless/views.py index 2031916..3758fe3 100644 --- a/DjangoFiles/QrcodeCashless/views.py +++ b/DjangoFiles/QrcodeCashless/views.py @@ -10,7 +10,7 @@ from rest_framework.generics import get_object_or_404 from django.views import View from rest_framework import status -from BaseBillet.models import Configuration, Article, LigneArticle +from BaseBillet.models import Configuration, Product, LigneArticle from PaiementStripe.models import Paiement_stripe from PaiementStripe.views import creation_paiement_stripe from QrcodeCashless.models import CarteCashless @@ -95,7 +95,7 @@ class index_scan(View): configuration = Configuration.get_solo() if not configuration.server_cashless: return HttpResponse( - "L'adresse du serveur cashless n'est pas renseignée dans la configuration de la billetterie.") + "L'adress du serveur cashless n'est pas renseignée dans la configuration de la billetterie.") if not configuration.stripe_api_key or not configuration.stripe_test_api_key: return HttpResponse( "Pas d'information de configuration pour paiement en ligne.") @@ -114,7 +114,7 @@ class index_scan(View): request, self.template_name, { - 'tarifs_adhesion': Article.objects.filter(categorie_article=Article.ADHESION).order_by('-prix'), + 'tarifs_adhesion': Product.objects.filter(categorie_article=Product.ADHESION).order_by('-prix'), 'adhesion_obligatoire': configuration.adhesion_obligatoire, 'history': json_reponse.get('history'), 'carte_resto': configuration.carte_restaurant, @@ -163,10 +163,10 @@ class index_scan(View): metadata = {} metadata['recharge_carte_uuid'] = str(carte.uuid) if montant_recharge: - art, created = Article.objects.get_or_create( + art, created = Product.objects.get_or_create( name="Recharge Carte", prix=1, - categorie_article=Article.RECHARGE_CASHLESS, + categorie_article=Product.RECHARGE_CASHLESS, ) ligne_article_recharge = LigneArticle.objects.create( @@ -180,7 +180,7 @@ class index_scan(View): metadata['recharge_carte_montant'] = str(montant_recharge) if pk_adhesion: - art_adhesion = Article.objects.get(pk=data.get('pk_adhesion')) + art_adhesion = Product.objects.get(pk=data.get('pk_adhesion')) ligne_article_recharge = LigneArticle.objects.create( article=art_adhesion, qty=1, @@ -265,11 +265,11 @@ def changement_paid_to_valid(sender, instance: Paiement_stripe, update_fields=No if ligne_article.carte : data_pour_serveur_cashless['uuid'] = ligne_article.carte.uuid - if ligne_article.article.categorie_article == Article.RECHARGE_CASHLESS : + if ligne_article.product.categorie_article == Product.RECHARGE_CASHLESS : data_pour_serveur_cashless['recharge_qty'] = float(ligne_article.qty) - if ligne_article.article.categorie_article == Article.ADHESION : - data_pour_serveur_cashless['tarif_adhesion'] = ligne_article.article.prix + if ligne_article.product.categorie_article == Product.ADHESION : + data_pour_serveur_cashless['tarif_adhesion'] = ligne_article.product.prix # si il y a autre chose que uuid_commande : if len(data_pour_serveur_cashless) > 1 : diff --git a/README.md b/README.md index 4dffac3..c141aef 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Pour en savoir plus : https://www.tibillet.re & https://wiki.tibillet.re ## Introduction. -TiBillet est en période d'Alpha, et en expérimentation sur plusieurs lieux sur l'ile de la Réunion. Venez nous voir au +TiBillet est en période de BETA et en expérimentation sur plusieurs lieux sur l'ile de la Réunion. Venez nous voir au Bisik, à la Raffinerie, à Vavang'Art et au Manapany Festival ! Le présent dépot ne contient pas encore toutes les sources du projet. La billetterie est en cours de refactoring et les