From ba7d4af4d6e2ec556d41b10e9b7fb39679d17d53 Mon Sep 17 00:00:00 2001 From: Jonas 12t Date: Sat, 25 Sep 2021 19:21:35 +0400 Subject: [PATCH] integration stripe et mise au norme API cashless --- DjangoFiles/Administration/admin_public.py | 33 ++- DjangoFiles/Administration/admin_tenant.py | 52 +++- DjangoFiles/AuthBillet/models.py | 1 - DjangoFiles/BaseBillet/models.py | 21 +- DjangoFiles/PaiementStripe/models.py | 22 +- DjangoFiles/PaiementStripe/urls.py | 8 + DjangoFiles/PaiementStripe/views.py | 66 ++++- .../QrcodeCashless/management/__init__.py | 0 .../management/commands/__init__.py | 0 .../management/commands/load_card.py | 83 +++++++ .../management/commands/load_card_json.py | 68 ++++++ DjangoFiles/QrcodeCashless/models.py | 29 ++- DjangoFiles/QrcodeCashless/urls.py | 3 +- DjangoFiles/QrcodeCashless/views.py | 231 +++++++++++++----- DjangoFiles/TiBillet/urls_tenants.py | 5 + Docker/Development/docker-compose.yml | 2 + Docker/Dockerfile/dockerfile | 1 + 17 files changed, 542 insertions(+), 83 deletions(-) create mode 100644 DjangoFiles/PaiementStripe/urls.py create mode 100644 DjangoFiles/QrcodeCashless/management/__init__.py create mode 100644 DjangoFiles/QrcodeCashless/management/commands/__init__.py create mode 100644 DjangoFiles/QrcodeCashless/management/commands/load_card.py create mode 100644 DjangoFiles/QrcodeCashless/management/commands/load_card_json.py diff --git a/DjangoFiles/Administration/admin_public.py b/DjangoFiles/Administration/admin_public.py index 98d8754..e159eaa 100644 --- a/DjangoFiles/Administration/admin_public.py +++ b/DjangoFiles/Administration/admin_public.py @@ -7,6 +7,7 @@ from django.contrib.auth.admin import UserAdmin, GroupAdmin from Customers.models import Client, Domain from AuthBillet.models import TibilletUser, HumanUser, TermUser, SuperHumanUser 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, Billet @@ -128,5 +129,35 @@ class ClientAdmin(admin.ModelAdmin): 'created_on', ) - public_admin_site.register(Client, ClientAdmin) + + +class DetailAdmin(admin.ModelAdmin): + list_display = ( + 'base_url', + 'origine', + 'generation', + 'img_url', + 'img', + ) + +public_admin_site.register(Detail, DetailAdmin) + +class CarteCashlessAdmin(admin.ModelAdmin): + + + list_display = ( + 'tag_id', + 'uuid', + 'number', + 'get_origin', + ) + + def get_origin(self, obj): + return obj.detail.origine + get_origin.short_description = 'Origine' + + search_fields = ('tag_id', 'uuid', 'number') + list_filter = ('tag_id', 'uuid', 'number') + +public_admin_site.register(CarteCashless, CarteCashlessAdmin) diff --git a/DjangoFiles/Administration/admin_tenant.py b/DjangoFiles/Administration/admin_tenant.py index 973aceb..2f46704 100644 --- a/DjangoFiles/Administration/admin_tenant.py +++ b/DjangoFiles/Administration/admin_tenant.py @@ -8,6 +8,7 @@ from BaseBillet.models import Configuration, Event, OptionGenerale, Article, Bil from django.contrib.auth.admin import UserAdmin from Customers.models import Client +from PaiementStripe.models import Paiement_stripe class StaffAdminSite(AdminSite): @@ -117,6 +118,9 @@ class ConfigurationAdmin(SingletonModelAdmin): ('Paiements', { 'fields': ( 'mollie_api_key', + 'stripe_api_key', + 'stripe_test_api_key', + 'stripe_mode_test', ), }), ('Billetterie', { @@ -172,13 +176,51 @@ class ReservationAdmin(admin.ModelAdmin): staff_admin_site.register(Reservation, ReservationAdmin) +class ArticleAdmin(admin.ModelAdmin): + list_display = ( + 'name', + 'prix', + 'stock', + 'reservation_par_user_max', + 'vat', + 'publish', + ) + list_editable = ( + 'prix', + 'stock', + 'reservation_par_user_max', + 'vat', + 'publish', + ) -staff_admin_site.register(OptionGenerale, OptionGeneraleAdmin) - -staff_admin_site.register(Billet, admin.ModelAdmin) -staff_admin_site.register(Article, admin.ModelAdmin) - +staff_admin_site.register(Article, ArticleAdmin) staff_admin_site.register(LigneArticle, admin.ModelAdmin) + + + +staff_admin_site.register(OptionGenerale, OptionGeneraleAdmin) + +staff_admin_site.register(Billet, admin.ModelAdmin) + + +class PaiementStripeAdmin(admin.ModelAdmin): + list_display = ( + 'detail', + 'total', + 'order_date', + 'user', + 'status', + ) + ordering = ('-order_date',) + # readonly_fields = ( + # 'reservations', + # ) + + +staff_admin_site.register(Paiement_stripe, PaiementStripeAdmin) + + + diff --git a/DjangoFiles/AuthBillet/models.py b/DjangoFiles/AuthBillet/models.py index b08b4c1..d2de93f 100644 --- a/DjangoFiles/AuthBillet/models.py +++ b/DjangoFiles/AuthBillet/models.py @@ -169,7 +169,6 @@ class HumanUserManager(TibilletManager): is_superuser=False, client_achat__id__in=[connection.tenant.id, ], ) - # .distinct() ??? class HumanUser(TibilletUser): diff --git a/DjangoFiles/BaseBillet/models.py b/DjangoFiles/BaseBillet/models.py index 4d9b910..e748559 100644 --- a/DjangoFiles/BaseBillet/models.py +++ b/DjangoFiles/BaseBillet/models.py @@ -67,6 +67,10 @@ class Configuration(SingletonModel): mollie_api_key = models.CharField(max_length=50, blank=True, null=True) + stripe_api_key = models.CharField(max_length=110, blank=True, null=True) + stripe_test_api_key = models.CharField(max_length=110, blank=True, null=True) + stripe_mode_test = models.BooleanField(default=True) + jauge_max = models.PositiveSmallIntegerField(default=50) option_generale_radio = models.ManyToManyField(OptionGenerale, @@ -105,6 +109,18 @@ class Billet(models.Model): def __str__(self): return f"{self.name}" +class VAT(models.Model): + """ + Les différents taux de TVA sont associés à des produits. + """ + 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): name = models.CharField(max_length=50, @@ -113,6 +129,9 @@ class Article(models.Model): 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) def range_max(self): return range(self.reservation_par_user_max + 1) @@ -224,7 +243,7 @@ class LigneArticle(models.Model): qty = models.SmallIntegerField() reste = models.SmallIntegerField() paiement_stripe = models.ForeignKey(Paiement_stripe, on_delete=models.PROTECT, blank=True, null=True) - + datetime = models.DateTimeField(auto_now=True) # def __str__(self): # if self.reservation : # if self.article : diff --git a/DjangoFiles/PaiementStripe/models.py b/DjangoFiles/PaiementStripe/models.py index 50299cb..9412925 100644 --- a/DjangoFiles/PaiementStripe/models.py +++ b/DjangoFiles/PaiementStripe/models.py @@ -1,6 +1,9 @@ from django.db import models import uuid # Create your models here. +from TiBillet import settings + +# class Configuration_stripe(models.Model): class Paiement_stripe(models.Model): @@ -8,34 +11,29 @@ class Paiement_stripe(models.Model): La commande """ uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, unique=True, db_index=True) + detail = models.CharField(max_length=50, blank=True, null=True) - id_stripe = models.CharField(max_length=20, blank=True, null=True) + id_stripe = models.CharField(max_length=80, blank=True, null=True) order_date = models.DateTimeField(auto_now=True, verbose_name="Date") + user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT, blank=True, null=True) - NON, OPEN, PENDING, PAID, VALID, CANCELED = 'N', 'O', 'W', 'P', 'V', 'C' + NON, OPEN, PENDING, EXPIRE, PAID, VALID, CANCELED = 'N', 'O', 'W', 'E', 'P', 'V', 'C' STATUT_CHOICES = ( (NON, 'Lien de paiement non crée'), (OPEN, 'Envoyée a Stripe'), (PENDING, 'En attente de paiement'), + (EXPIRE, 'Expiré'), (PAID, 'Payée'), (VALID, 'Payée et validée'), # envoyé sur serveur cashless (CANCELED, 'Annulée'), ) status = models.CharField(max_length=1, choices=STATUT_CHOICES, default=NON, verbose_name="Statut de la commande") - # a remplir par default sur le front par User.email. - email_billet = models.CharField(max_length=30, verbose_name="Email de récéption des billets", blank=True) - - # def total(self): - # total = 0 - # for article in ArticleCommande.objects.filter(commande=self): - # total += article.total() - # - # return total + total = models.FloatField(default=0) def __str__(self): - return self.status + return f"{self.detail} - {self.status}" diff --git a/DjangoFiles/PaiementStripe/urls.py b/DjangoFiles/PaiementStripe/urls.py new file mode 100644 index 0000000..338d698 --- /dev/null +++ b/DjangoFiles/PaiementStripe/urls.py @@ -0,0 +1,8 @@ +from django.urls import include, path, re_path + +from .views import retour_stripe + +urlpatterns = [ + path('return/', retour_stripe.as_view()), + path('webhook_stripe', retour_stripe.as_view()), +] \ No newline at end of file diff --git a/DjangoFiles/PaiementStripe/views.py b/DjangoFiles/PaiementStripe/views.py index 91ea44a..b306723 100644 --- a/DjangoFiles/PaiementStripe/views.py +++ b/DjangoFiles/PaiementStripe/views.py @@ -1,3 +1,67 @@ -from django.shortcuts import render +from datetime import datetime +from django.http import HttpResponse +from django.shortcuts import render, get_object_or_404 +import stripe # Create your views here. +from django.views import View + +from BaseBillet.models import Configuration +from PaiementStripe.models import Paiement_stripe + + +class retour_stripe(View): + + def get(self, request, uuid): + configuration = Configuration.get_solo() + paiement_stripe = get_object_or_404(Paiement_stripe, uuid=uuid) + + if configuration.stripe_mode_test: + stripe.api_key = configuration.stripe_test_api_key + else: + stripe.api_key = configuration.stripe_api_key + + + 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() : + paiement_stripe.status = Paiement_stripe.EXPIRE + elif checkout_session.payment_status == "paid": + paiement_stripe.status = Paiement_stripe.PAID + else: + paiement_stripe.status = Paiement_stripe.CANCELED + + paiement_stripe.save() + return HttpResponse(f'ok {uuid}') + + +class webhook_stripe(View): + def get(self, request): + print(f"webhook_stripe GET") + return HttpResponse(f'ok') + + def post(self, request): + endpoint_secret = 'whsec_1Urn98yUMsgwdXA7vhN5dwDTRQLD2vmD' + event = None + payload = request.data + sig_header = request.headers['STRIPE_SIGNATURE'] + + try: + event = stripe.Webhook.construct_event( + payload, sig_header, endpoint_secret + ) + except ValueError as e: + # Invalid payload + raise e + except stripe.error.SignatureVerificationError as e: + # Invalid signature + raise e + + # Handle the event + print('Unhandled event type {}'.format(event['type'])) + + print(f"webhook_stripe POST {event}") + return HttpResponse(f'ok {event}') diff --git a/DjangoFiles/QrcodeCashless/management/__init__.py b/DjangoFiles/QrcodeCashless/management/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/DjangoFiles/QrcodeCashless/management/commands/__init__.py b/DjangoFiles/QrcodeCashless/management/commands/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/DjangoFiles/QrcodeCashless/management/commands/load_card.py b/DjangoFiles/QrcodeCashless/management/commands/load_card.py new file mode 100644 index 0000000..a4c22b4 --- /dev/null +++ b/DjangoFiles/QrcodeCashless/management/commands/load_card.py @@ -0,0 +1,83 @@ +import os + +from django.core.exceptions import ValidationError +from django.core.management.base import BaseCommand +from Customers.models import Client, Domain +from QrcodeCashless.models import Detail, CarteCashless +from django.core.validators import URLValidator + +import csv, uuid + + + + +class Command(BaseCommand): + + def is_string_an_url(self, url_string): + validate_url = URLValidator() + + try: + validate_url(url_string) + except ValidationError as e: + return False + return True + + + def handle(self, *args, **options): + for client in Client.objects.all(): + print (client.schema_name) + + input_client = input('quel client ? \n') + client_tenant = Client.objects.get(schema_name=input_client) + print(' ') + + input_generation = input('quelle génération ? \n') + print(' ') + + print('url, numéro imprimé len(8), fisrt tag id len(8)') + input_fichier_csv = input('path fichier csv ? \n') + file = open(input_fichier_csv) + + # file = open('data/raffinerie_1_RETOUR_USINE.csv') + + + csv_parser = csv.reader(file) + list_csv = [] + for line in csv_parser: + list_csv.append(line) + + # on saucissonne l'url d'une ligne au pif : + part = list_csv[10][0].partition('/qr/') + base_url = f"{part[0]}{part[1]}" + if self.is_string_an_url(base_url) : + detail_carte, created = Detail.objects.get_or_create( + base_url=base_url, + origine=client_tenant, + generation=input_generation, + ) + + numline = 1 + for line in list_csv: + print(numline) + part = line[0].partition('/qr/') + try: + uuid_url = uuid.UUID(part[2]) + print(f"uuid_url : {uuid_url}") + print(f"number : {line[1]}") + print(f"tag_id : {line[2]}") + if str(uuid_url).partition('-')[0].upper() != line[1]: + print('ERROR PRINT != uuid') + break + + + carte, created = CarteCashless.objects.get_or_create( + tag_id=line[2], + uuid=uuid_url, + number=line[1], + detail=detail_carte, + ) + + numline += 1 + except: + pass + diff --git a/DjangoFiles/QrcodeCashless/management/commands/load_card_json.py b/DjangoFiles/QrcodeCashless/management/commands/load_card_json.py new file mode 100644 index 0000000..a5e6bcc --- /dev/null +++ b/DjangoFiles/QrcodeCashless/management/commands/load_card_json.py @@ -0,0 +1,68 @@ +import json +import os + +from django.core.exceptions import ValidationError +from django.core.management.base import BaseCommand +from Customers.models import Client, Domain +from QrcodeCashless.models import Detail, CarteCashless +from django.core.validators import URLValidator + +import csv, uuid + + + + +class Command(BaseCommand): + + def is_string_an_url(self, url_string): + validate_url = URLValidator() + + try: + validate_url(url_string) + except ValidationError as e: + return False + return True + + + def handle(self, *args, **options): + for client in Client.objects.all(): + print (client.schema_name) + + input_client = input('quel client ? \n') + client_tenant = Client.objects.get(schema_name=input_client) + print(' ') + print('url, numéro imprimé len(8), fisrt tag id len(8)') + + input_generation = input('quelle génération ? \n') + print(' ') + + detail_carte, created = Detail.objects.get_or_create( + base_url='https://m.tibillet.re/', + origine=client_tenant, + generation=input_generation, + ) + + file = open('data/CarteCashlessBisik.json') + json_dict = json.load(file) + + for card in json_dict: + tag_id = card['fields']['tag_id'] + number = card['fields']['number'] + if tag_id and number: + # on va generer un faux uuid pour le bisik + # Namespace hardcodé volontairement pour vérification + namespace = uuid.UUID('6ba7b811-9dad-11d1-80b4-00c04fd430c8') + gen_uuid = uuid.uuid5(namespace, number) + + print(tag_id) + print(number) + print(gen_uuid) + + carte, created = CarteCashless.objects.get_or_create( + tag_id=tag_id, + uuid=gen_uuid, + number=number, + detail=detail_carte, + ) + + diff --git a/DjangoFiles/QrcodeCashless/models.py b/DjangoFiles/QrcodeCashless/models.py index 63fd1c0..148380c 100644 --- a/DjangoFiles/QrcodeCashless/models.py +++ b/DjangoFiles/QrcodeCashless/models.py @@ -1,8 +1,29 @@ from django.db import models # Create your models here. +from stdimage import StdImageField +from stdimage.validators import MaxSizeValidator + from Customers.models import Client as Customers_Client +class Detail(models.Model): + img = StdImageField(upload_to='images/', + null=True, blank=True, + validators=[MaxSizeValidator(1920, 1920)], + variations={ + 'med': (480, 480), + 'thumbnail': (150, 90), + }, + delete_orphans=True, + verbose_name='Recto de la carte' + ) + img_url = models.URLField(null=True, blank=True) + base_url = models.CharField(max_length=60, null=True, blank=True) + origine = models.ForeignKey(Customers_Client, on_delete=models.PROTECT, null=True, blank=True) + generation = models.SmallIntegerField() + + def __str__(self): + return self.base_url class CarteCashless(models.Model): tag_id = models.CharField( @@ -11,7 +32,7 @@ class CarteCashless(models.Model): unique=True ) - uuid_qrcode = models.UUIDField( + uuid = models.UUIDField( blank=True, null=True, verbose_name='Uuid', ) @@ -19,9 +40,9 @@ class CarteCashless(models.Model): number = models.CharField( db_index=True, max_length=8, - blank=True, - null=True, unique=True ) - origine = models.ForeignKey(Customers_Client, on_delete=models.PROTECT) \ No newline at end of file + detail = models.ForeignKey(Detail, on_delete=models.CASCADE, null=True, blank=True) + + diff --git a/DjangoFiles/QrcodeCashless/urls.py b/DjangoFiles/QrcodeCashless/urls.py index 9a4e228..cc232be 100644 --- a/DjangoFiles/QrcodeCashless/urls.py +++ b/DjangoFiles/QrcodeCashless/urls.py @@ -1,7 +1,8 @@ from django.urls import include, path, re_path -from .views import index_scan +from .views import index_scan, gen_one_bisik urlpatterns = [ path('', index_scan.as_view()), + path('', gen_one_bisik.as_view()) ] \ No newline at end of file diff --git a/DjangoFiles/QrcodeCashless/views.py b/DjangoFiles/QrcodeCashless/views.py index 2f244b7..4b8f23c 100644 --- a/DjangoFiles/QrcodeCashless/views.py +++ b/DjangoFiles/QrcodeCashless/views.py @@ -1,19 +1,47 @@ import requests, json -from django.http import HttpResponseRedirect, HttpResponse +from django.contrib.auth import get_user_model +from django.db import connection +from django.http import HttpResponseRedirect, HttpResponse, Http404 from django.shortcuts import render +from rest_framework.generics import get_object_or_404 + +import stripe # Create your views here. from django.views import View from rest_framework import status from rest_framework.response import Response -from BaseBillet.models import Configuration +from AuthBillet.models import TibilletUser, HumanUser +from BaseBillet.models import Configuration, Article +from PaiementStripe.models import Paiement_stripe +from QrcodeCashless.models import CarteCashless + +def get_domain(request): + absolute_uri = request.build_absolute_uri() + for domain in request.tenant.domains.all(): + if domain.domain in absolute_uri: + return domain.domain + + raise Http404 + +class gen_one_bisik(View): + def get(self, request, numero_carte): + print(numero_carte) + carte = get_object_or_404(CarteCashless, number=numero_carte) + address = request.build_absolute_uri() + return HttpResponseRedirect(address.replace("://m.", "://bisik.").replace(f"{carte.number}", f"qr/{carte.uuid}")) class index_scan(View): template_name = "RechargementWebUuid.html" - def check_carte(self, uuid): + def check_carte_local(self, uuid): + carte = get_object_or_404(CarteCashless, uuid=uuid) + return carte + + + def check_carte_serveur_cashless(self, uuid): configuration = Configuration.get_solo() # on questionne le serveur cashless pour voir si la carte existe : @@ -28,81 +56,47 @@ class index_scan(View): 'uuid': f'{uuid}', }) except requests.exceptions.ConnectionError: - reponse = HttpResponse("Serveur non disponible. Merci de revenir ultérieurement.", status=status.HTTP_503_SERVICE_UNAVAILABLE) + reponse = HttpResponse("Serveur non disponible. Merci de revenir ultérieurement.", + status=status.HTTP_503_SERVICE_UNAVAILABLE) sess.close() return reponse - def post(self, request, uuid): - data = request.POST - reponse_server_cashless = self.check_carte(uuid) - - if data.get('numero_carte_cashless') == str(uuid).split('-')[0].upper() and \ - reponse_server_cashless.status_code == 200: - - userWeb, created = User.objects.get_or_create( - username="RechargementWeb", - email="rechargementweb@tibillet.re") - - vat, created = VAT.objects.get_or_create(percent=0) - - commande = Commande.objects.create( - user=userWeb, - email_billet=data.get('email'), - ) - - art, created = Product.objects.get_or_create( - name="CashlessRechargementWeb", - price_ttc="1", - publish=False, - vat=vat - ) - - ArticleCommande.objects.create( - product=art, - quantity=data.get('thune'), - commande=commande, - ) - - domain = get_domain(request) - sub_domain = str(domain).split('.')[0] - absolute_domain = request.build_absolute_uri().partition('/qr')[0] - - Paiement = CreationPaiementMollie(commande, domain, - description=f"Rechargez votre carte {sub_domain.capitalize()}", - redirectUrl=f"{absolute_domain}/RechargementWebAfterMollie/{commande.uuid}", - webhookUrl=f"{absolute_domain}/RechargementWebAfterMollie/{commande.uuid}", - numero_carte_cashless=data.get('numero_carte_cashless')) - - if Paiement.is_send(): - return HttpResponseRedirect(Paiement.is_send()) - - def get(self, request, uuid): + carte = self.check_carte_local(uuid) + if carte.detail.origine != connection.tenant : + raise Http404 + + # dette technique ... + # pour rediriger les premières générations de qrcode + # m.tibillet.re et raffinerie - # pour rediriger les carte imprimés a la raffinerie vers le bon tenant. address = request.build_absolute_uri() host = address.partition('://')[2] sub_addr = host.partition('.')[0] if sub_addr == "m": return HttpResponseRedirect(address.replace("://m.", "://raffinerie.")) + 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.") + if not configuration.stripe_api_key or not configuration.stripe_test_api_key: + return HttpResponse( + "Pas d'information de configuration pour paiement en ligne.") - reponse_server_cashless = self.check_carte(uuid) - json_reponse = json.loads(reponse_server_cashless.json()) - liste_assets = json_reponse.get('liste_assets') - email = json_reponse.get('email') - + reponse_server_cashless = self.check_carte_serveur_cashless(carte.uuid) if reponse_server_cashless.status_code == 200: + json_reponse = json.loads(reponse_server_cashless.json()) + liste_assets = json_reponse.get('liste_assets') + email = json_reponse.get('email') + return render( request, self.template_name, { - 'numero_carte': str(uuid).split('-')[0].upper(), + 'numero_carte': carte.number, 'domain': sub_addr, 'informations_carte': reponse_server_cashless.text, 'liste_assets': liste_assets, @@ -116,4 +110,127 @@ class index_scan(View): return HttpResponse('Carte inconnue', status=status.HTTP_400_BAD_REQUEST) elif reponse_server_cashless.status_code == 500: # Serveur cashless hors ligne - return reponse_server_cashless \ No newline at end of file + return reponse_server_cashless + + def post(self, request, uuid): + carte = self.check_carte_local(uuid) + if carte.detail.origine != connection.tenant : + raise Http404 + + data = request.POST + reponse_server_cashless = self.check_carte_serveur_cashless(carte.uuid) + montant_recharge = float(data.get('thune')) + configuration = Configuration.get_solo() + + if data.get('numero_carte_cashless') == str(uuid).split('-')[0].upper() and \ + 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() + + art, created = Article.objects.get_or_create( + name="Recharge Stripe", + prix="1", + publish=False, + ) + + paiementStripe = Paiement_stripe.objects.create( + user=user_recharge, + detail=f"{art.name}", + total=float("{0:.2f}".format(montant_recharge)), + ) + + domain = get_domain(request) + absolute_domain = request.build_absolute_uri().partition('/qr')[0] + + if configuration.stripe_mode_test: + stripe.api_key = configuration.stripe_test_api_key + else: + stripe.api_key = configuration.stripe_api_key + + checkout_session = stripe.checkout.Session.create( + customer_email=f'{user_recharge.email}', + line_items=[{ + 'price_data': { + 'currency': 'eur', + + 'product_data': { + 'name': 'Recharge Cashless', + "images": [f'{carte.detail.img_url}', ], + }, + 'unit_amount': int("{0:.2f}".format(montant_recharge).replace('.', '')), + }, + 'quantity': 1, + + }], + payment_method_types=[ + 'card', + ], + mode='payment', + metadata={ + 'Carte': str(uuid).split('-')[0].upper() + }, + 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')}", + ) + + print(checkout_session.id) + paiementStripe.id_stripe = checkout_session.id + paiementStripe.status = Paiement_stripe.PENDING + paiementStripe.save() + + return HttpResponseRedirect(checkout_session.url) + + # Paiement = CreationPaiementMollie(commande, domain, + # description=f"Rechargez votre carte {sub_domain.capitalize()}", + # redirectUrl=f"{absolute_domain}/RechargementWebAfterMollie/{commande.uuid}", + # webhookUrl=f"{absolute_domain}/RechargementWebAfterMollie/{commande.uuid}", + # numero_carte_cashless=data.get('numero_carte_cashless')) + # + # if Paiement.is_send(): + # return HttpResponseRedirect(Paiement.is_send()) + +# +# def postPaimentRecharge(paiementStripe: Paiement_stripe): +# +# if paiementStripe.status == Paiement_stripe.PAID : +# +# sess = requests.Session() +# configuration = Configuration.get_solo() +# r = sess.post(f'{configuration.server_cashless}/wv/rechargementWeb', +# data={ +# 'number': numero_carte_cashless, +# 'qty': commande.total(), +# 'uuid_commande': commande_uuid, +# 'API_TIBILLET_BILLETERIE_VERS_CASHLESS': os.getenv( +# 'API_TIBILLET_BILLETERIE_VERS_CASHLESS'), +# }) +# +# sess.close() +# +# if r.status_code == 200: +# # la commande a été envoyé au serveur cashless, on la met en validée +# commande.status = 'V' +# commande.save() +# +# return HttpResponse( +# f"

Paiement validé, vous avez rechargé votre carte ! Disponible : {r.text}

") +# +# elif commande.status == "V": +# # Le paiement a bien été accepté par le passé et envoyé au serveur cashless. +# return HttpResponse( +# f"

Paiement bien validé, vous avez rechargé votre carte !

") +# +# return HttpResponse("

Paiement non valide. Contactez un responsable.

") diff --git a/DjangoFiles/TiBillet/urls_tenants.py b/DjangoFiles/TiBillet/urls_tenants.py index 5c0643a..2966a0d 100644 --- a/DjangoFiles/TiBillet/urls_tenants.py +++ b/DjangoFiles/TiBillet/urls_tenants.py @@ -34,6 +34,11 @@ urlpatterns = [ re_path(r'api/', include('ApiBillet.urls')), re_path(r'qr/', include('QrcodeCashless.urls')), + # pour carte GEN1 Bisik + re_path(r'(?P^\w{5}$)', include('QrcodeCashless.urls')), + + re_path(r'stripe/', include('PaiementStripe.urls')), + path('', include('BaseBillet.urls')), diff --git a/Docker/Development/docker-compose.yml b/Docker/Development/docker-compose.yml index 37b9528..8aec317 100644 --- a/Docker/Development/docker-compose.yml +++ b/Docker/Development/docker-compose.yml @@ -4,6 +4,8 @@ services: container_name: tibillet_postgres image: postgres:11.5-alpine restart: always + ports: + - 5432:5432 volumes: - "../../Postgres/dbdata:/var/lib/postgresql/data" - "/etc/localtime:/etc/localtime:ro" diff --git a/Docker/Dockerfile/dockerfile b/Docker/Dockerfile/dockerfile index fb82ab8..fe3b3c5 100644 --- a/Docker/Dockerfile/dockerfile +++ b/Docker/Dockerfile/dockerfile @@ -58,6 +58,7 @@ RUN pip install django-stdimage # RUN pip install -U social-auth-app-django # RUN pip install -U django-templated-mail +RUN pip install stripe