diff --git a/DjangoFiles/Administration/admin_tenant.py b/DjangoFiles/Administration/admin_tenant.py index 38ee3f9..06c559e 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, Billet, Reservation, LigneArticle +from BaseBillet.models import Configuration, Event, OptionGenerale, Article, Billet, Reservation, LigneArticle, TarifsAdhesion from django.contrib.auth.admin import UserAdmin from Customers.models import Client @@ -117,6 +117,12 @@ class ConfigurationAdmin(SingletonModelAdmin): 'carte_restaurant', ) }), + ('Adhésions', { + 'fields': ( + 'adhesion_obligatoire', + 'cadeau_adhesion', + ), + }), ('Paiements', { 'fields': ( 'mollie_api_key', @@ -144,6 +150,16 @@ class ConfigurationAdmin(SingletonModelAdmin): staff_admin_site.register(Configuration, ConfigurationAdmin) +class TarifsAdhesionAdmin(admin.ModelAdmin): + list_display = ( + 'name', + 'tarif' + ) + list_editable = ('tarif',) + ordering = ('tarif',) + +staff_admin_site.register(TarifsAdhesion, TarifsAdhesionAdmin) + class EventAdmin(admin.ModelAdmin): list_display = ( diff --git a/DjangoFiles/AuthBillet/migrations/0001_initial.py b/DjangoFiles/AuthBillet/migrations/0001_initial.py index 8583765..f2c0360 100644 --- a/DjangoFiles/AuthBillet/migrations/0001_initial.py +++ b/DjangoFiles/AuthBillet/migrations/0001_initial.py @@ -1,8 +1,9 @@ -# Generated by Django 2.2 on 2021-06-23 09:09 +# Generated by Django 2.2 on 2021-09-27 12:56 from django.db import migrations, models import django.db.models.deletion import django.utils.timezone +import uuid class Migration(migrations.Migration): @@ -11,7 +12,7 @@ class Migration(migrations.Migration): dependencies = [ ('auth', '0011_update_proxy_permissions'), - ('Customers', '0001_initial'), + ('Customers', '0003_auto_20210623_1351'), ] operations = [ @@ -27,8 +28,10 @@ class Migration(migrations.Migration): ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), + ('uuid_user', models.UUIDField(default=uuid.uuid4, editable=False)), ('email', models.EmailField(max_length=254, unique=True, verbose_name='email')), ('username', models.CharField(blank=True, max_length=200, null=True)), + ('phone', models.CharField(blank=True, max_length=20, null=True)), ('espece', models.CharField(choices=[('TE', 'Terminal'), ('AN', 'Android'), ('HU', 'Humain')], default='HU', max_length=2)), ('offre', models.CharField(choices=[('PU', 'Public'), ('FR', 'Gratuit'), ('PR', 'Premium'), ('EN', 'Entreprise'), ('CU', 'Custom')], default='PU', max_length=2)), ('client_achat', models.ManyToManyField(blank=True, related_name='user_achats', to='Customers.Client')), diff --git a/DjangoFiles/AuthBillet/migrations/0002_tibilletuser_phone.py b/DjangoFiles/AuthBillet/migrations/0002_tibilletuser_phone.py deleted file mode 100644 index faff2d9..0000000 --- a/DjangoFiles/AuthBillet/migrations/0002_tibilletuser_phone.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 2.2 on 2021-06-29 12:03 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('AuthBillet', '0001_initial'), - ] - - operations = [ - migrations.AddField( - model_name='tibilletuser', - name='phone', - field=models.CharField(blank=True, max_length=12, null=True), - ), - ] diff --git a/DjangoFiles/AuthBillet/migrations/0003_auto_20210629_1605.py b/DjangoFiles/AuthBillet/migrations/0003_auto_20210629_1605.py deleted file mode 100644 index e61198f..0000000 --- a/DjangoFiles/AuthBillet/migrations/0003_auto_20210629_1605.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 2.2 on 2021-06-29 12:05 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('AuthBillet', '0002_tibilletuser_phone'), - ] - - operations = [ - migrations.AlterField( - model_name='tibilletuser', - name='phone', - field=models.CharField(blank=True, max_length=20, null=True), - ), - ] diff --git a/DjangoFiles/AuthBillet/models.py b/DjangoFiles/AuthBillet/models.py index d2de93f..6372e03 100644 --- a/DjangoFiles/AuthBillet/models.py +++ b/DjangoFiles/AuthBillet/models.py @@ -46,7 +46,9 @@ class TibilletManager(BaseUserManager): class TibilletUser(AbstractUser): #TODO regarder du coté du dashboard de jet, ça plante avec uuid ! - # uuid_user = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, unique=True, db_index=True) + # uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, unique=True, db_index=True) + + uuid_user = models.UUIDField(default=uuid.uuid4, editable=False) USERNAME_FIELD = 'email' REQUIRED_FIELDS = [] # removes email from REQUIRED_FIELDS diff --git a/DjangoFiles/BaseBillet/migrations/0049_auto_20210927_1047.py b/DjangoFiles/BaseBillet/migrations/0049_auto_20210927_1047.py new file mode 100644 index 0000000..d095e18 --- /dev/null +++ b/DjangoFiles/BaseBillet/migrations/0049_auto_20210927_1047.py @@ -0,0 +1,32 @@ +# Generated by Django 2.2 on 2021-09-27 06:47 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('BaseBillet', '0048_auto_20210926_1531'), + ] + + operations = [ + migrations.CreateModel( + name='TarifsAdhesion', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=30)), + ('tarif', models.FloatField()), + ], + ), + migrations.AddField( + model_name='configuration', + name='adhesion_obligatoire', + field=models.BooleanField(default=False), + ), + migrations.AlterField( + model_name='lignearticle', + name='reservation', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='BaseBillet.Reservation'), + ), + ] diff --git a/DjangoFiles/BaseBillet/migrations/0050_auto_20210927_1132.py b/DjangoFiles/BaseBillet/migrations/0050_auto_20210927_1132.py new file mode 100644 index 0000000..117b224 --- /dev/null +++ b/DjangoFiles/BaseBillet/migrations/0050_auto_20210927_1132.py @@ -0,0 +1,28 @@ +# Generated by Django 2.2 on 2021-09-27 07:32 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('BaseBillet', '0049_auto_20210927_1047'), + ] + + operations = [ + migrations.AlterModelOptions( + name='tarifsadhesion', + options={'ordering': ('-tarif',)}, + ), + migrations.AddField( + model_name='configuration', + name='cadeau_adhesion', + field=models.FloatField(default=0), + ), + migrations.AlterField( + model_name='lignearticle', + name='reservation', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='BaseBillet.Reservation'), + ), + ] diff --git a/DjangoFiles/BaseBillet/migrations/0051_auto_20210927_1334.py b/DjangoFiles/BaseBillet/migrations/0051_auto_20210927_1334.py new file mode 100644 index 0000000..01bc884 --- /dev/null +++ b/DjangoFiles/BaseBillet/migrations/0051_auto_20210927_1334.py @@ -0,0 +1,29 @@ +# Generated by Django 2.2 on 2021-09-27 09:34 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('BaseBillet', '0050_auto_20210927_1132'), + ] + + operations = [ + migrations.AddField( + model_name='article', + name='categorie_article', + field=models.CharField(choices=[('B', 'Billet'), ('P', "Pack d'objets"), ('R', 'Recharge cashless'), ('T', 'Vetement'), ('M', 'Merchandasing')], default='B', max_length=3, verbose_name='Status de la réservation'), + ), + migrations.AlterField( + model_name='configuration', + name='cadeau_adhesion', + field=models.FloatField(default=0, help_text="Recharge cadeau a l'adhésion"), + ), + migrations.AlterField( + model_name='lignearticle', + name='reservation', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='BaseBillet.Reservation'), + ), + ] diff --git a/DjangoFiles/BaseBillet/migrations/0052_auto_20210927_1335.py b/DjangoFiles/BaseBillet/migrations/0052_auto_20210927_1335.py new file mode 100644 index 0000000..047feff --- /dev/null +++ b/DjangoFiles/BaseBillet/migrations/0052_auto_20210927_1335.py @@ -0,0 +1,24 @@ +# Generated by Django 2.2 on 2021-09-27 09:35 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('BaseBillet', '0051_auto_20210927_1334'), + ] + + operations = [ + migrations.AddField( + model_name='article', + name='id_stripe', + field=models.CharField(blank=True, max_length=30, null=True), + ), + migrations.AlterField( + model_name='lignearticle', + name='reservation', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='BaseBillet.Reservation'), + ), + ] diff --git a/DjangoFiles/BaseBillet/migrations/0053_auto_20210927_1348.py b/DjangoFiles/BaseBillet/migrations/0053_auto_20210927_1348.py new file mode 100644 index 0000000..4a55c18 --- /dev/null +++ b/DjangoFiles/BaseBillet/migrations/0053_auto_20210927_1348.py @@ -0,0 +1,26 @@ +# Generated by Django 2.2 on 2021-09-27 09:48 + +from django.db import migrations, models +import django.db.models.deletion +import stdimage.models +import stdimage.validators + + +class Migration(migrations.Migration): + + dependencies = [ + ('BaseBillet', '0052_auto_20210927_1335'), + ] + + operations = [ + migrations.AddField( + model_name='article', + name='img', + field=stdimage.models.StdImageField(blank=True, null=True, upload_to='images/', validators=[stdimage.validators.MaxSizeValidator(1920, 1920)], verbose_name='Image'), + ), + migrations.AlterField( + model_name='lignearticle', + name='reservation', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='BaseBillet.Reservation'), + ), + ] diff --git a/DjangoFiles/BaseBillet/migrations/0054_auto_20210927_1350.py b/DjangoFiles/BaseBillet/migrations/0054_auto_20210927_1350.py new file mode 100644 index 0000000..172a7c6 --- /dev/null +++ b/DjangoFiles/BaseBillet/migrations/0054_auto_20210927_1350.py @@ -0,0 +1,29 @@ +# Generated by Django 2.2 on 2021-09-27 09:50 + +from django.db import migrations, models +import django.db.models.deletion +import uuid + + +class Migration(migrations.Migration): + + dependencies = [ + ('BaseBillet', '0053_auto_20210927_1348'), + ] + + operations = [ + migrations.RemoveField( + model_name='article', + name='id', + ), + migrations.AddField( + model_name='article', + name='uuid', + field=models.UUIDField(db_index=True, default=uuid.uuid4, primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='lignearticle', + name='reservation', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='BaseBillet.Reservation'), + ), + ] diff --git a/DjangoFiles/BaseBillet/migrations/0055_auto_20210927_1407.py b/DjangoFiles/BaseBillet/migrations/0055_auto_20210927_1407.py new file mode 100644 index 0000000..0111fbd --- /dev/null +++ b/DjangoFiles/BaseBillet/migrations/0055_auto_20210927_1407.py @@ -0,0 +1,29 @@ +# Generated by Django 2.2 on 2021-09-27 10:07 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('BaseBillet', '0054_auto_20210927_1350'), + ] + + operations = [ + migrations.RenameField( + model_name='article', + old_name='id_stripe', + new_name='id_price_stripe', + ), + migrations.AlterField( + model_name='article', + name='categorie_article', + field=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"), + ), + migrations.AlterField( + model_name='lignearticle', + name='reservation', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='BaseBillet.Reservation'), + ), + ] diff --git a/DjangoFiles/BaseBillet/migrations/0056_auto_20210927_1407.py b/DjangoFiles/BaseBillet/migrations/0056_auto_20210927_1407.py new file mode 100644 index 0000000..57436eb --- /dev/null +++ b/DjangoFiles/BaseBillet/migrations/0056_auto_20210927_1407.py @@ -0,0 +1,24 @@ +# Generated by Django 2.2 on 2021-09-27 10:07 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('BaseBillet', '0055_auto_20210927_1407'), + ] + + operations = [ + migrations.AddField( + model_name='article', + name='id_product_stripe', + field=models.CharField(blank=True, max_length=30, null=True), + ), + migrations.AlterField( + model_name='lignearticle', + name='reservation', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='BaseBillet.Reservation'), + ), + ] diff --git a/DjangoFiles/BaseBillet/migrations/0057_auto_20210927_1543.py b/DjangoFiles/BaseBillet/migrations/0057_auto_20210927_1543.py new file mode 100644 index 0000000..9552541 --- /dev/null +++ b/DjangoFiles/BaseBillet/migrations/0057_auto_20210927_1543.py @@ -0,0 +1,19 @@ +# Generated by Django 2.2 on 2021-09-27 11:43 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('BaseBillet', '0056_auto_20210927_1407'), + ] + + operations = [ + migrations.AlterField( + model_name='lignearticle', + name='reservation', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='BaseBillet.Reservation'), + ), + ] diff --git a/DjangoFiles/BaseBillet/migrations/0058_auto_20210927_1634.py b/DjangoFiles/BaseBillet/migrations/0058_auto_20210927_1634.py new file mode 100644 index 0000000..df38ad4 --- /dev/null +++ b/DjangoFiles/BaseBillet/migrations/0058_auto_20210927_1634.py @@ -0,0 +1,19 @@ +# Generated by Django 2.2 on 2021-09-27 12:34 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('BaseBillet', '0057_auto_20210927_1543'), + ] + + operations = [ + migrations.AlterField( + model_name='lignearticle', + name='reservation', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='BaseBillet.Reservation'), + ), + ] diff --git a/DjangoFiles/BaseBillet/migrations/0059_auto_20210927_1634.py b/DjangoFiles/BaseBillet/migrations/0059_auto_20210927_1634.py new file mode 100644 index 0000000..5e524db --- /dev/null +++ b/DjangoFiles/BaseBillet/migrations/0059_auto_20210927_1634.py @@ -0,0 +1,19 @@ +# Generated by Django 2.2 on 2021-09-27 12:34 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('BaseBillet', '0058_auto_20210927_1634'), + ] + + operations = [ + migrations.AlterField( + model_name='lignearticle', + name='reservation', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='BaseBillet.Reservation'), + ), + ] diff --git a/DjangoFiles/BaseBillet/migrations/0060_auto_20210927_1718.py b/DjangoFiles/BaseBillet/migrations/0060_auto_20210927_1718.py new file mode 100644 index 0000000..1341e67 --- /dev/null +++ b/DjangoFiles/BaseBillet/migrations/0060_auto_20210927_1718.py @@ -0,0 +1,25 @@ +# Generated by Django 2.2 on 2021-09-27 13:18 + +from django.db import migrations, models +import django.db.models.deletion +import uuid + + +class Migration(migrations.Migration): + + dependencies = [ + ('BaseBillet', '0059_auto_20210927_1634'), + ] + + operations = [ + migrations.AlterField( + model_name='article', + name='uuid', + field=models.UUIDField(db_index=True, default=uuid.uuid4, editable=False, primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='lignearticle', + name='reservation', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='BaseBillet.Reservation'), + ), + ] diff --git a/DjangoFiles/BaseBillet/migrations/0061_auto_20210927_1718.py b/DjangoFiles/BaseBillet/migrations/0061_auto_20210927_1718.py new file mode 100644 index 0000000..f88b6c3 --- /dev/null +++ b/DjangoFiles/BaseBillet/migrations/0061_auto_20210927_1718.py @@ -0,0 +1,19 @@ +# Generated by Django 2.2 on 2021-09-27 13:18 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('BaseBillet', '0060_auto_20210927_1718'), + ] + + operations = [ + migrations.AlterField( + model_name='lignearticle', + name='reservation', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='BaseBillet.Reservation'), + ), + ] diff --git a/DjangoFiles/BaseBillet/models.py b/DjangoFiles/BaseBillet/models.py index 468459c..cfc8344 100644 --- a/DjangoFiles/BaseBillet/models.py +++ b/DjangoFiles/BaseBillet/models.py @@ -10,9 +10,11 @@ from solo.models import SingletonModel from django.utils.translation import ugettext_lazy as _ from stdimage import StdImageField from stdimage.validators import MaxSizeValidator +from django.db import connection from PaiementStripe.models import Paiement_stripe from TiBillet import settings +import stripe class OptionGenerale(models.Model): @@ -38,6 +40,17 @@ def poids_option_generale(sender, instance: OptionGenerale, created, **kwargs): instance.save() +class TarifsAdhesion(models.Model): + name = models.CharField(max_length=30) + tarif = models.FloatField() + + class Meta: + ordering = ('-tarif',) + + def __str__(self): + return f"{self.name} {self.tarif}" + + class Configuration(SingletonModel): organisation = models.CharField(max_length=50) short_description = models.CharField(max_length=250) @@ -52,6 +65,9 @@ class Configuration(SingletonModel): 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 = StdImageField(upload_to='images/', null=True, blank=True, validators=[MaxSizeValidator(1920, 1920)], @@ -141,6 +157,8 @@ class VAT(models.Model): class Article(models.Model): + uuid = models.UUIDField(primary_key=True, db_index=True, default=uuid.uuid4, editable=False) + name = models.CharField(max_length=50, blank=True, null=True) prix = models.FloatField() @@ -151,9 +169,94 @@ class Article(models.Model): publish = models.BooleanField(default=False) + img = StdImageField(upload_to='images/', + null=True, blank=True, + validators=[MaxSizeValidator(1920, 1920)], + variations={ + 'fhd': (1920, 1920), + 'hdr': (720, 720), + 'med': (480, 480), + 'thumbnail': (150, 90), + }, + delete_orphans=True, + verbose_name='Image' + ) + + BILLET, PACK, RECHARGE_CASHLESS, VETEMENT, MERCH, ADHESION = 'B', 'P', 'R', 'T', 'M', 'A' + TYPE_CHOICES = [ + (BILLET, _('Billet')), + (PACK, _("Pack d'objets")), + (RECHARGE_CASHLESS, _('Recharge cashless')), + (VETEMENT, _('Vetement')), + (MERCH, _('Merchandasing')), + (ADHESION, ('Adhésion')), + ] + + categorie_article = models.CharField(max_length=3, choices=TYPE_CHOICES, default=BILLET, + 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 get_id_product_stripe(self): + configuration = Configuration.get_solo() + if configuration.stripe_api_key and not self.id_product_stripe: + if configuration.stripe_mode_test: + stripe.api_key = configuration.stripe_test_api_key + else: + stripe.api_key = configuration.stripe_api_key + + if self.img : + # noinspection PyUnresolvedReferences + domain_url = connection.tenant.domains.all()[0].domain + images = [f"https://{domain_url}{self.img.med.url}",] + else: + images = [] + + product = stripe.Product.create( + name=f"{self.name}", + images=images + ) + self.id_product_stripe = product.id + self.save() + return self.id_product_stripe + + elif self.id_product_stripe: + return self.id_product_stripe + else: + return False + + def get_id_price_stripe(self): + configuration = Configuration.get_solo() + if configuration.stripe_api_key and not self.id_price_stripe: + if configuration.stripe_mode_test: + stripe.api_key = configuration.stripe_test_api_key + else: + stripe.api_key = configuration.stripe_api_key + + price = stripe.Price.create( + unit_amount=int("{0:.2f}".format(self.prix).replace('.', '')), + currency="eur", + product=self.get_id_product_stripe(), + ) + + self.id_price_stripe = price.id + self.save() + return self.id_price_stripe + + elif self.id_price_stripe: + return self.id_price_stripe + else: + return False + + def reset_id_stripe(self): + self.id_price_stripe = None + self.id_product_stripe = None + self.save() + def __str__(self): return f"{self.name}" diff --git a/DjangoFiles/PaiementStripe/views.py b/DjangoFiles/PaiementStripe/views.py index 0c0e7c6..e93c6a1 100644 --- a/DjangoFiles/PaiementStripe/views.py +++ b/DjangoFiles/PaiementStripe/views.py @@ -1,22 +1,140 @@ import json from datetime import datetime -from django.http import HttpResponse, Http404 +from django.contrib.auth import get_user_model +from django.db import connection +from django.http import HttpResponse, Http404, HttpResponseRedirect from django.shortcuts import get_object_or_404 import stripe # Create your views here. from django.utils import timezone from django.views import View -from BaseBillet.models import Configuration +from AuthBillet.models import HumanUser +from BaseBillet.models import Configuration, Article, LigneArticle from PaiementStripe.models import Paiement_stripe - -from QrcodeCashless.views import postPaimentRecharge +# from QrcodeCashless.views import postPaimentRecharge import logging + logger = logging.getLogger(__name__) + +class creation_checkout_stripe(): + + def __init__(self, + email_paiement: str, + liste_ligne_article: list, + metadata: dict, + absolute_domain: str + ) -> None: + + self.absolute_domain = absolute_domain + self.configuration = Configuration.get_solo() + self.email_paiement = email_paiement + self.user = self._user_paiement() + self.detail = self._detail() + self.total = self._total() + self.liste_ligne_article = liste_ligne_article + self.metadata = metadata + self.metadata_json = json.dumps(self.metadata) + self.paiement_stripe_db = self._paiement_stripe_db() + self.stripe_api_key = self._stripe_api_key() + self.line_items = self._line_items() + self.checkout_session = self._checkout_session() + + def _user_paiement(self): + User = get_user_model() + user_paiement, created = User.objects.get_or_create( + email=self.email_paiement) + + if created: + user_paiement: HumanUser + user_paiement.client_source = connection.tenant + user_paiement.client_achat.add(connection.tenant) + user_paiement.is_active = False + else: + user_paiement.client_achat.add(connection.tenant) + user_paiement.save() + + return user_paiement + + def _total(self): + total = 0 + for ligne in self.liste_ligne_article: + ligne: LigneArticle + total += ligne.qty * ligne.article.prix + return total + + def _detail(self): + detail = "" + for ligne in self.liste_ligne_article: + ligne: LigneArticle + detail += f"{ligne.article}" + return detail + + def _paiement_stripe_db(self): + + paiementStripeDb = Paiement_stripe.objects.create( + user=self.user, + detail=self.detail, + total=self.total, + metadata_stripe=self.metadata_json, + ) + + return paiementStripeDb + + def _stripe_api_key(self): + if self.configuration.stripe_mode_test: + stripe.api_key = self.configuration.stripe_test_api_key + else: + stripe.api_key = self.configuration.stripe_api_key + + return stripe.api_key + + def _line_items(self): + line_items = [] + for ligne in self.liste_ligne_article: + ligne: LigneArticle + line_items.append( + { + "price": f"{ligne.article.get_id_price_stripe()}", + "quantity": ligne.qty, + } + ) + + def _checkout_session(self): + checkout_session = stripe.checkout.Session.create( + customer_email=f'{self.user.email}', + line_items=self.line_items, + payment_method_types=['card'], + mode='payment', + metadata=self.metadata, + success_url=f'{self.absolute_domain}/stripe/return/{self.paiement_stripe_db.uuid}', + cancel_url=f'{self.absolute_domain}/stripe/return/{self.paiement_stripe_db.uuid}', + client_reference_id=f"{self.user.uuid_user}", + ) + + print(checkout_session.id) + self.paiement_stripe_db.id_stripe = checkout_session.id + self.paiement_stripe_db.status = Paiement_stripe.PENDING + self.paiement_stripe_db.save() + + return checkout_session + + def is_valid(self): + if self.checkout_session.id and \ + self.checkout_session.url : + return True + + else: + return False + + def redirect_to_stripe(self): + return HttpResponseRedirect(self.checkout_session.url) + + class retour_stripe(View): def get(self, request, uuid_stripe): @@ -28,12 +146,12 @@ class retour_stripe(View): else: stripe.api_key = configuration.stripe_api_key - if paiement_stripe.status != Paiement_stripe.VALID : + if paiement_stripe.status != Paiement_stripe.VALID: checkout_session = stripe.checkout.Session.retrieve(paiement_stripe.id_stripe) if checkout_session.payment_status == "unpaid": paiement_stripe.status = Paiement_stripe.PENDING - if checkout_session.expires_at > datetime.now().timestamp() : + if checkout_session.expires_at > datetime.now().timestamp(): paiement_stripe.status = Paiement_stripe.EXPIRE paiement_stripe.save() @@ -51,7 +169,7 @@ class retour_stripe(View): try: assert metadata_stripe == metadata_db assert set(metadata_db.keys()) == set(metadata_stripe.keys()) - for key in set(metadata_stripe.keys()) : + for key in set(metadata_stripe.keys()): assert metadata_db[key] == metadata_stripe[key] except: logger.error(f"{timezone.now()} " @@ -60,10 +178,14 @@ class retour_stripe(View): raise Http404 # on check si il y a un rechargement de carte cashless dans la commande - if metadata_db.get('recharge_carte_uuid') : - logger.info(f'{timezone.now()} retour stripe pour rechargement carte : {metadata_db.get("recharge_carte_uuid")}') - print (f'{timezone.now()} retour stripe pour rechargement carte : {metadata_db.get("recharge_carte_uuid")}') - return postPaimentRecharge(paiement_stripe, request) + if metadata_db.get('recharge_carte_uuid'): + logger.info( + f'{timezone.now()} retour stripe pour rechargement carte : {metadata_db.get("recharge_carte_uuid")}') + print( + f'{timezone.now()} retour stripe pour rechargement carte : {metadata_db.get("recharge_carte_uuid")}') + + print('gerer la recharge sur le serveur cashless') + # return postPaimentRecharge(paiement_stripe, request) @@ -71,11 +193,13 @@ class retour_stripe(View): else: paiement_stripe.status = Paiement_stripe.CANCELED paiement_stripe.save() - return HttpResponse(f'Le paiement a été annulé.') + return HttpResponse(f'Le paiement annulé.') - return HttpResponse(f'ok {uuid_stripe}') + return HttpResponse(f'Paiement validé') +''' + class webhook_stripe(View): def get(self, request): print(f"webhook_stripe GET") @@ -103,3 +227,4 @@ class webhook_stripe(View): print(f"webhook_stripe POST {event}") return HttpResponse(f'ok {event}') +''' diff --git a/DjangoFiles/QrcodeCashless/templates/html5up-dimension/index.html b/DjangoFiles/QrcodeCashless/templates/html5up-dimension/index.html index fdd79bf..6d4170a 100644 --- a/DjangoFiles/QrcodeCashless/templates/html5up-dimension/index.html +++ b/DjangoFiles/QrcodeCashless/templates/html5up-dimension/index.html @@ -16,7 +16,7 @@ - +< class="is-preload">
@@ -96,6 +96,11 @@
+ {% if messages %} + {% for message in messages %} +

{{ message }}

+ {% endfor %} + {% endif %}

Solde

@@ -109,14 +114,14 @@ {% for asset in assets %} - + {% endfor %} - +
{{ asset.nom }}{{ asset.qty |floatformat:2|intcomma }}{{ asset.qty | floatformat:2 | intcomma }}
{{ total_monnaie |floatformat:2|intcomma }}{{ total_monnaie | floatformat:2 | intcomma }}
@@ -148,10 +153,6 @@
-
-

Adhésion

-

Merci !

-

Rechargement OK

@@ -168,14 +169,14 @@ {% for asset in assets %} {{ asset.nom }} - {{ asset.qty |floatformat:2|intcomma }} + {{ asset.qty | floatformat:2 | intcomma }} {% endfor %} - {{ total_monnaie |floatformat:2|intcomma }} + {{ total_monnaie | floatformat:2 | intcomma }} @@ -185,14 +186,6 @@
-
-

ERREUR

-

Le paiement n'a pas fonctionné.

-

Vérifiez votre moyen de paiement ou contacter un administrateur

- -
@@ -200,19 +193,36 @@
{% csrf_token %}
-
+
+ + +
+
+
    +
  • +
+ +
+ + +
+

Adhésion {{ client_name }}

+

Nous avons déja :

+

Il nous manque ces informations pour votre adhésion :

+
+ {% csrf_token %} +
+ + +
-
+
-
- - -
-
+
@@ -223,255 +233,94 @@
- -
-

Elements

+
+

Adhésion

+ {% if messages %} + {% for message in messages %} +

{{ message }}

+ {% endfor %} + {% endif %} -
-

Text

-

This is bold and this is strong. This is italic and this is emphasized. - This is superscript text and this is subscript text. - This is underlined and this is code: for (;;) { ... }. Finally, this - is a link.

-
-

Heading Level 2

-

Heading Level 3

-

Heading Level 4

-
Heading Level 5
-
Heading Level 6
-
-

Blockquote

-
Fringilla nisl. Donec accumsan interdum nisi, quis tincidunt felis sagittis eget tempus - euismod. Vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis - volutpat ac adipiscing accumsan faucibus. Vestibulum ante ipsum primis in faucibus lorem ipsum dolor - sit amet nullam adipiscing eu felis. -
-

Preformatted

-
i = 0;
-
-while (!deck.isInOrder()) {
-    print 'Iteration ' + i;
-    deck.shuffle();
-    i++;
-}
-
-print 'It took ' + i + ' iterations to sort the deck.';
-
- -
-

Lists

- -

Unordered

-
    -
  • Dolor pulvinar etiam.
  • -
  • Sagittis adipiscing.
  • -
  • Felis enim feugiat.
  • -
- -

Alternate

-
    -
  • Dolor pulvinar etiam.
  • -
  • Sagittis adipiscing.
  • -
  • Felis enim feugiat.
  • -
- -

Ordered

-
    -
  1. Dolor pulvinar etiam.
  2. -
  3. Etiam vel felis viverra.
  4. -
  5. Felis enim feugiat.
  6. -
  7. Dolor pulvinar etiam.
  8. -
  9. Etiam vel felis lorem.
  10. -
  11. Felis enim et feugiat.
  12. -
-

Icons

- - -

Actions

- - -
- -
-

Table

-

Default

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameDescriptionPrice
Item OneAnte turpis integer aliquet porttitor.29.99
Item TwoVis ac commodo adipiscing arcu aliquet.19.99
Item Three Morbi faucibus arcu accumsan lorem.29.99
Item FourVitae integer tempus condimentum.19.99
Item FiveAnte turpis integer aliquet porttitor.29.99
100.00
-
- -

Alternate

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameDescriptionPrice
Item OneAnte turpis integer aliquet porttitor.29.99
Item TwoVis ac commodo adipiscing arcu aliquet.19.99
Item Three Morbi faucibus arcu accumsan lorem.29.99
Item FourVitae integer tempus condimentum.19.99
Item FiveAnte turpis integer aliquet porttitor.29.99
100.00
-
-
- -
-

Buttons

- - - -
    -
  • Disabled
  • -
  • Disabled
  • -
-
- -
-

Form

-
-
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
+ {% if adhesion_obligatoire %} + {% if tarifs_adhesion %} +

Payer en ligne avec un vrai robot :

+ {% for tarif in tarifs_adhesion %} + + {% endfor %} +

Payer à l'acceuil de l'association avec un vrai humain :

-
-
+ {% endif %} + {% endif %} +
+ +
+

Paiement en ligne

+ {% if messages %} + {% for message in messages %} +

{{ message }}

+ {% endfor %} + {% endif %} +

Adhésion :

+
+ {% csrf_token %} +
+ + + + +
+

Voulez vous recharger votre carte en même temps ? Laissez vide si non.

+ + +
+
+
    +
  • +
+
+
+

ERREUR

+

Le paiement n'a pas fonctionné.

+

Vérifiez votre moyen de paiement ou contacter un administrateur

+ {% if messages %} + {% for message in messages %} +

{{ message }}

+ {% endfor %} + {% endif %} + +
+ +
+

ERREUR

+

Oups, Quelque chose s'est mal passé.

+ {% if messages %} + {% for message in messages %} +

{{ message }}

+ {% endfor %} + {% endif %} +
+ +
@@ -492,5 +341,57 @@ print 'It took ' + i + ' iterations to sort the deck.'; + +{# Script qui n'affiche que les champs dont nous avons besoin lors de l'adhésion #} + + +{#Script pour remplir la page d'adhésion de paiement#} + + + diff --git a/DjangoFiles/QrcodeCashless/views.py b/DjangoFiles/QrcodeCashless/views.py index 7f2888b..a03ad62 100644 --- a/DjangoFiles/QrcodeCashless/views.py +++ b/DjangoFiles/QrcodeCashless/views.py @@ -1,7 +1,7 @@ from datetime import datetime import requests, json -from django.contrib.auth import get_user_model +from django.contrib import messages from django.db import connection from django.http import HttpResponseRedirect, HttpResponse, Http404 from django.shortcuts import render @@ -13,11 +13,10 @@ import stripe # Create your views here. from django.views import View from rest_framework import status -from rest_framework.response import Response -from AuthBillet.models import TibilletUser, HumanUser -from BaseBillet.models import Configuration, Article +from BaseBillet.models import Configuration, Article, TarifsAdhesion, LigneArticle from PaiementStripe.models import Paiement_stripe +from PaiementStripe.views import creation_checkout_stripe from QrcodeCashless.models import CarteCashless import logging logger = logging.getLogger(__name__) @@ -47,6 +46,11 @@ class gen_one_bisik(View): class index_scan(View): template_name = "html5up-dimension/index.html" + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.carte = None + self.adhesion = None + def check_carte_serveur_cashless(self, uuid): configuration = Configuration.get_solo() # on questionne le serveur cashless pour voir si la carte existe : @@ -104,6 +108,8 @@ class index_scan(View): request, self.template_name, { + 'tarifs_adhesion': TarifsAdhesion.objects.all(), + 'adhesion_obligatoire': configuration.adhesion_obligatoire, 'assets': json_reponse.get('assets'), 'total_monnaie': json_reponse.get('total_monnaie'), 'history': json_reponse.get('history'), @@ -140,98 +146,112 @@ class index_scan(View): data = request.POST print(data) # c'est une recharge - if data.get('montant_recharge') : - - reponse_server_cashless = self.check_carte_serveur_cashless(carte.uuid) + if data.get('montant_recharge') and data.get('email'): + # montant_recharge = data.get('montant_recharge') montant_recharge = float("{0:.2f}".format(float(data.get('montant_recharge')))) - configuration = Configuration.get_solo() + if montant_recharge > 0: - if reponse_server_cashless.status_code == 200 and \ - montant_recharge > 0: - - User = get_user_model() - user_recharge, created = User.objects.get_or_create( - email=data.get('email')) - if created: - user_recharge: HumanUser - user_recharge.client_source = connection.tenant - user_recharge.client_achat.add(connection.tenant) - user_recharge.is_active = False - else: - user_recharge.client_achat.add(connection.tenant) - user_recharge.save() + # reponse_server_cashless = self.check_carte_serveur_cashless(carte.uuid) + # configuration = Configuration.get_solo() art, created = Article.objects.get_or_create( - name="Recharge Stripe", - prix="1", + name="Recharge Carte", + prix=1, publish=False, + categorie_article=Article.RECHARGE_CASHLESS, ) + ligne_article = LigneArticle.objects.create( + article = art, + qty = montant_recharge, + ) metadata = { 'recharge_carte_uuid': str(carte.uuid), 'recharge_carte_montant': str(montant_recharge), } - metadata_json = json.dumps(metadata) - paiementStripe = Paiement_stripe.objects.create( - user=user_recharge, - detail=f"{art.name}", - total=montant_recharge, - metadata_stripe=metadata_json, + new_checkout_session = creation_checkout_stripe( + email_paiement = data.get('email'), + liste_ligne_article = [ligne_article,], + metadata = metadata, + absolute_domain = request.build_absolute_uri().partition('/qr')[0], ) - absolute_domain = request.build_absolute_uri().partition('/qr')[0] + if new_checkout_session.is_valid() : + print(new_checkout_session.checkout_session.stripe_id) + return new_checkout_session.redirect_to_stripe() - if configuration.stripe_mode_test: - stripe.api_key = configuration.stripe_test_api_key - else: - stripe.api_key = configuration.stripe_api_key + # c'est la première étape de l'adhésion + elif data.get('email') \ + and not data.get('prenom') \ + and not data.get('prenom') \ + and not data.get('tel') : - checkout_session = stripe.checkout.Session.create( - customer_email=f'{user_recharge.email}', - line_items=[{ - 'price_data': { - 'currency': 'eur', + sess = requests.Session() + configuration = Configuration.get_solo() + r = sess.post( + f'{configuration.server_cashless}/api/billetterie_qrcode_adhesion', + headers={ + 'Authorization': f'Api-Key {configuration.key_cashless}' + }, + data={ + 'email': data.get('email'), + 'uuid_carte': carte.uuid, + }) - 'product_data': { - 'name': 'Recharge Cashless', - "images": [f'{carte.detail.img_url}', ], - }, - 'unit_amount': int("{0:.2f}".format(montant_recharge).replace('.', '')), - }, - 'quantity': 1, + sess.close() - }], - payment_method_types=[ - 'card', - ], - mode='payment', - metadata=metadata, - success_url=f'{absolute_domain}/stripe/return/{paiementStripe.uuid}', - cancel_url=f'{absolute_domain}/stripe/return/{paiementStripe.uuid}', - # submit_type='Go go go', - client_reference_id=f"{data.get('numero_carte_cashless')}", - ) + # nouveau membre crée avec uniquqment l'email on demande la suite. + if r.status_code in (201, 204) : + messages.success(request, f"{data.get('email')}", extra_tags='email') + return HttpResponseRedirect(f'#demande_nom_prenom_tel') - print(checkout_session.id) - paiementStripe.id_stripe = checkout_session.id - paiementStripe.status = Paiement_stripe.PENDING - paiementStripe.save() + #partial information : + elif r.status_code == 206: + partial = json.loads(r.text) + messages.success(request, f"{data.get('email')}", extra_tags='email') + if partial.get('name'): + messages.success(request, f"Email déja connu. Name déja connu", extra_tags='name') + if partial.get('prenom'): + messages.success(request, f"Email déja connu. prenom déja connu", extra_tags='prenom') + if partial.get('tel'): + messages.success(request, f"Email déja connu. tel déja connu", extra_tags='tel') + return HttpResponseRedirect(f'#demande_nom_prenom_tel') + else: + messages.error(request, f'Erreur {r.status_code} {r.text}') + return HttpResponseRedirect(f'#erreur') - return HttpResponseRedirect(checkout_session.url) + # suite de l'adhesion + elif data.get('email') and data.get('name') and data.get('prenom') and data.get('tel'): + sess = requests.Session() + configuration = Configuration.get_solo() + r = sess.post( + f'{configuration.server_cashless}/api/billetterie_qrcode_adhesion', + headers={ + 'Authorization': f'Api-Key {configuration.key_cashless}' + }, + data={ + 'prenom': data.get('prenom'), + 'name': data.get('name'), + 'email': data.get('email'), + 'tel': data.get('tel'), + 'uuid_carte': carte.uuid, + }) - elif data.get('prenom') \ - and data.get('name') \ - and data.get('email') \ - and data.get('tel'): + sess.close() + + # nouveau membre crée, on demande la suite. + if r.status_code == 202 : + messages.success(request, f"Merci ! Membre créé et carte liée.") + + return HttpResponseRedirect(f'#adhesionsuccess') + else : + messages.error(request, f'Erreur {r.status_code} {r.text}') + return HttpResponseRedirect(f'#erreur') - print("adhésion !") - absolute_domain = request.build_absolute_uri().partition('/qr')[0] - return HttpResponseRedirect(f'{absolute_domain}/qr/{carte.uuid}#adhesionsuccess') def postPaimentRecharge(paiementStripe: Paiement_stripe, request): - absolute_domain = request.build_absolute_uri().partition('/stripe/return')[0] if paiementStripe.status == Paiement_stripe.PAID: metadata_db_json = paiementStripe.metadata_stripe @@ -273,10 +293,10 @@ def postPaimentRecharge(paiementStripe: Paiement_stripe, request): paiementStripe.status = Paiement_stripe.VALID paiementStripe.save() - return HttpResponseRedirect(f'{absolute_domain}/qr/{uuid_carte}#success') + return HttpResponseRedirect(f'#success') elif paiementStripe.status == Paiement_stripe.VALID: - # Le paiement a bien été accepté par le passé et envoyé au serveur cashless. - return HttpResponseRedirect(f'{absolute_domain}/qr/{uuid_carte}#historique') + messages.success(request, f"Le paiement a déja été validé.") + return HttpResponseRedirect(f'#historique') - return HttpResponseRedirect(f'{absolute_domain}/qr/{uuid_carte}#error') + return HttpResponseRedirect(f'#erreurpaiement') diff --git a/DjangoFiles/TiBillet/urls_tenants.py b/DjangoFiles/TiBillet/urls_tenants.py index 2966a0d..9c1f3e1 100644 --- a/DjangoFiles/TiBillet/urls_tenants.py +++ b/DjangoFiles/TiBillet/urls_tenants.py @@ -23,7 +23,8 @@ from Administration.admin_tenant import staff_admin_site urlpatterns = [ path('jet/', include('jet.urls', 'jet')), # Django JET URLS re_path(r'^jet/dashboard/', include('jet.dashboard.urls', 'jet-dashboard')), # Django JET dashboard URLS - path('admin/', staff_admin_site.urls, name="staff_admin_site"), + # path('admin/', staff_admin_site.urls, name="staff_admin_site"), + re_path(r'^admin\/{0,}', staff_admin_site.urls, name="staff_admin_site"), re_path(r'^auth/', include('djoser.urls')), re_path(r'^auth/', include('djoser.urls.authtoken')),