fix redirection and shop stuff

sync
Raz 8 months ago
parent 69d838d245
commit 22b6d71169
  1. 7
      padelclub_backend/settings.py
  2. 2
      padelclub_backend/settings_app.py
  3. 306
      shop/signals.py
  4. 18
      tournaments/custom_views.py
  5. 19
      tournaments/middleware.py

@ -57,6 +57,8 @@ MIDDLEWARE = [
'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware', 'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware',
'tournaments.middleware.ReferrerMiddleware', # Add this line
] ]
ROOT_URLCONF = 'padelclub_backend.urls' ROOT_URLCONF = 'padelclub_backend.urls'
@ -154,7 +156,10 @@ AUTHENTICATION_BACKENDS = [
] ]
CSRF_COOKIE_SECURE = True # if using HTTPS CSRF_COOKIE_SECURE = True # if using HTTPS
SESSION_COOKIE_SECURE = True # Si vous utilisez HTTPS if DEBUG: # Development environment
SESSION_COOKIE_SECURE = False
else: # Production environment
SESSION_COOKIE_SECURE = True
from .settings_local import * from .settings_local import *
from .settings_app import * from .settings_app import *

@ -51,4 +51,4 @@ SHOP_MANAGERS = [
# ('Xavier Rousset', 'xavier@padelclub.app'), # ('Xavier Rousset', 'xavier@padelclub.app'),
] ]
SHOP_SITE_ROOT_URL = 'https://padelclub.app' SHOP_SITE_ROOT_URL = 'https://padelclub.app'
SHOP_SUPPORT_EMAIL = 'shop-support@padelclub.app' SHOP_SUPPORT_EMAIL = 'shop@padelclub.app'

@ -8,43 +8,41 @@ from django.db import transaction
@receiver([post_save, post_delete], sender=Order) @receiver([post_save, post_delete], sender=Order)
def send_order_notification(sender, instance, **kwargs): def send_order_notification(sender, instance, **kwargs):
print("send_order_notification") """Send an email notification when an order is created, updated, or deleted."""
"""
Send an email notification when an order is created, updated, or deleted.
"""
# Use transaction.on_commit to ensure database operations are complete
transaction.on_commit(lambda: _send_order_email(instance, **kwargs)) transaction.on_commit(lambda: _send_order_email(instance, **kwargs))
def _send_order_email(instance, **kwargs): def _send_order_email(instance, **kwargs):
created = kwargs.get('created', False) # Skip processing for PENDING orders
update_fields = kwargs.get('update_fields', None) if instance.status == OrderStatus.PENDING:
# Determine the action type
if 'signal' in kwargs and kwargs['signal'] == post_delete:
action = "DELETED"
return
elif created:
action = "CREATED"
return return
else:
action = "UPDATED"
print('updated', update_fields)
if update_fields and 'status' in update_fields:
action = "UPDATED"
# Get order details # Determine action type
order_id = instance.id action = _determine_action_type(kwargs)
status = instance.status if action in ["DELETED", "CREATED"]:
return # No emails for these actions
print("status", status) # Build common email components
if status == OrderStatus.PENDING: order_details = _get_order_details(instance)
return items_list = _build_items_list(instance.id, action)
total_price = instance.total_price # Send internal notification
_send_internal_notification(instance, action, order_details, items_list)
# Generate admin URL # Send customer notification if applicable
admin_url = f"{settings.SHOP_SITE_ROOT_URL}{reverse('admin:shop_order_change', args=[order_id])}" if order_details['customer_email']:
_send_customer_notification(instance, order_details, items_list)
def _determine_action_type(kwargs):
"""Determine the action type from signal kwargs."""
if 'signal' in kwargs and kwargs['signal'] == post_delete:
return "DELETED"
elif kwargs.get('created', False):
return "CREATED"
else:
return "UPDATED"
def _get_order_details(instance):
"""Extract and build order details dictionary."""
# Get customer info # Get customer info
customer_email = None customer_email = None
if instance.user: if instance.user:
@ -56,60 +54,65 @@ def _send_order_email(instance, **kwargs):
else: else:
customer_info = "Client inconnu" customer_info = "Client inconnu"
# Build order item details # Translate statuses
status_fr_map = {
"PENDING": "EN ATTENTE", "PAID": "PAYÉE",
"SHIPPED": "EXPÉDIÉE", "DELIVERED": "LIVRÉE", "CANCELED": "ANNULÉE"
}
payment_status_fr_map = {
"UNPAID": "NON PAYÉE", "PAID": "PAYÉE", "FAILED": "ÉCHOUÉE"
}
return {
'order_id': instance.id,
'status': instance.status,
'status_fr': status_fr_map.get(instance.status, instance.status),
'payment_status': instance.payment_status,
'payment_status_fr': payment_status_fr_map.get(instance.payment_status, instance.payment_status),
'total_price': instance.total_price,
'customer_info': customer_info,
'customer_email': customer_email,
'date_ordered': instance.date_ordered,
'admin_url': f"{settings.SHOP_SITE_ROOT_URL}{reverse('admin:shop_order_change', args=[instance.id])}"
}
def _build_items_list(order_id, action):
"""Build the list of order items."""
items_list = "" items_list = ""
if action != "DELETED": if action != "DELETED":
# Use a fresh query to ensure we have the most recent data
order_items = OrderItem.objects.filter(order_id=order_id).select_related('product', 'color', 'size') order_items = OrderItem.objects.filter(order_id=order_id).select_related('product', 'color', 'size')
for item in order_items: for item in order_items:
color = item.color.name if item.color else "N/A" color = item.color.name if item.color else "N/A"
size = item.size.name if item.size else "N/A" size = item.size.name if item.size else "N/A"
item_line = f"- {item.quantity}x {item.product.title} (Couleur: {color}, Taille: {size}, Prix: {item.price}€)\n" items_list += f"- {item.quantity}x {item.product.title} (Couleur: {color}, Taille: {size}, Prix: {item.price}€)\n"
items_list += item_line return items_list
# Compose the email
if action == "CREATED":
action_fr = "CRÉÉE"
elif action == "UPDATED":
action_fr = "MISE À JOUR"
elif action == "DELETED":
action_fr = "SUPPRIMÉE"
else:
action_fr = action
# Translate current status def _translate_action(action):
status_fr_map = { """Translate action to French."""
"PENDING": "EN ATTENTE", translations = {
"PAID": "PAYÉE", "CREATED": "CRÉÉE", "UPDATED": "MISE À JOUR", "DELETED": "SUPPRIMÉE"
"SHIPPED": "EXPÉDIÉE",
"DELIVERED": "LIVRÉE",
"CANCELED": "ANNULÉE"
} }
status_fr = status_fr_map.get(status, status) return translations.get(action, action)
# Translate payment status def _send_internal_notification(instance, action, order_details, items_list):
payment_status_fr_map = { """Send notification email to shop managers."""
"UNPAID": "NON PAYÉE", action_fr = _translate_action(action)
"PAID": "PAYÉE",
"FAILED": "ÉCHOUÉE"
}
payment_status_fr = payment_status_fr_map.get(instance.payment_status, instance.payment_status)
# Send internal notification email subject = f"Commande #{order_details['order_id']} {action_fr}: {order_details['status_fr']}"
subject = f"Commande #{order_id} {action_fr}: {status_fr}"
message = f""" message = f"""
La commande #{order_id} a été {action_fr.lower()} La commande #{order_details['order_id']} a été {action_fr.lower()}
Statut: {status_fr} Statut: {order_details['status_fr']}
Statut de paiement: {payment_status_fr} Statut de paiement: {order_details['payment_status_fr']}
Prix total: {total_price} Prix total: {order_details['total_price']}
{customer_info} {order_details['customer_info']}
Articles: Articles:
{items_list} {items_list}
Voir la commande dans le panneau d'administration: {admin_url} Voir la commande dans le panneau d'administration: {order_details['admin_url']}
Ceci est un message automatique. Merci de ne pas répondre. Ceci est un message automatique. Merci de ne pas répondre.
""" """
@ -127,20 +130,93 @@ Ceci est un message automatique. Merci de ne pas répondre.
fail_silently=False, fail_silently=False,
) )
# Only send customer email for PAID status and if we have customer email def _send_customer_notification(instance, order_details, items_list):
if status == OrderStatus.PAID and customer_email and instance.payment_status == "PAID": """Send appropriate notification email to customer based on order status."""
# Generate customer-facing URLs # Common email variables
shop_url = f"{settings.SHOP_SITE_ROOT_URL}/shop" contact_email = settings.SHOP_SUPPORT_EMAIL
contact_email = f"{settings.SHOP_SUPPORT_EMAIL}" shop_url = f"{settings.SHOP_SITE_ROOT_URL}/shop"
date_formatted = order_details['date_ordered'].strftime('%d/%m/%Y')
# Determine email content based on status and payment status
email_content = _get_customer_email_content(
instance.status,
order_details['payment_status'],
order_details['order_id'],
date_formatted,
order_details['status_fr'],
order_details['total_price'],
items_list,
contact_email,
shop_url
)
# Skip if no email content returned
if not email_content:
return
# Send email to customer
send_mail(
subject=email_content['subject'],
message=email_content['message'],
from_email=settings.DEFAULT_FROM_EMAIL,
recipient_list=[order_details['customer_email']],
fail_silently=False,
)
# Create a customer receipt email def _get_customer_email_content(status, payment_status, order_id, date, status_fr,
customer_subject = f"Confirmation de votre commande #{order_id} - PadelClub" total_price, items_list, contact_email, shop_url):
customer_message = f""" """Get the appropriate customer email content based on order status."""
# Payment confirmation email
if status == OrderStatus.PAID and payment_status == "PAID":
return {
'subject': f"Confirmation de votre commande #{order_id} - PadelClub",
'message': _build_payment_confirmation_email(order_id, date, status_fr,
total_price, items_list,
contact_email, shop_url)
}
# Order status update email
elif status in [OrderStatus.SHIPPED, OrderStatus.DELIVERED, OrderStatus.CANCELED]:
status_message = {
OrderStatus.SHIPPED: "Votre commande a été expédiée et est en cours de livraison.",
OrderStatus.DELIVERED: "Votre commande a été livrée. Nous espérons que vous apprécierez vos produits !",
OrderStatus.CANCELED: "Votre commande a été annulée. Si vous n'êtes pas à l'origine de cette annulation, veuillez nous contacter immédiatement."
}.get(status, "")
return {
'subject': f"Mise à jour de votre commande #{order_id} - PadelClub",
'message': _build_status_update_email(order_id, date, status_message, status_fr,
total_price, items_list, contact_email)
}
# Payment issue notification
elif payment_status == "FAILED":
return {
'subject': f"Problème de paiement pour votre commande #{order_id} - PadelClub",
'message': _build_payment_issue_email(order_id, date, total_price,
items_list, contact_email, shop_url)
}
# Payment reminder for unpaid orders
elif payment_status == "UNPAID" and status != OrderStatus.PENDING:
return {
'subject': f"Rappel de paiement pour votre commande #{order_id} - PadelClub",
'message': _build_payment_reminder_email(order_id, date, total_price,
items_list, contact_email)
}
# No email needed
return None
def _build_payment_confirmation_email(order_id, date, status_fr, total_price, items_list, contact_email, shop_url):
"""Build payment confirmation email message."""
return f"""
Bonjour, Bonjour,
Nous vous remercions pour votre commande sur PadelClub ! Nous vous remercions pour votre commande sur PadelClub !
Récapitulatif de votre commande #{order_id} du {instance.date_ordered.strftime('%d/%m/%Y')} : Récapitulatif de votre commande #{order_id} du {date} :
Statut: {status_fr} Statut: {status_fr}
Prix total: {total_price} Prix total: {total_price}
@ -159,13 +235,75 @@ Visitez notre boutique pour découvrir d'autres produits :
Merci de votre confiance et à bientôt sur PadelClub ! Merci de votre confiance et à bientôt sur PadelClub !
L'équipe PadelClub L'équipe PadelClub
""" """
# Send email to customer def _build_status_update_email(order_id, date, status_message, status_fr, total_price, items_list, contact_email):
send_mail( """Build status update email message."""
subject=customer_subject, return f"""
message=customer_message, Bonjour,
from_email=settings.DEFAULT_FROM_EMAIL,
recipient_list=[customer_email], Mise à jour concernant votre commande PadelClub #{order_id} du {date} :
fail_silently=False,
) {status_message}
Statut actuel: {status_fr}
Prix total: {total_price}
Détail de votre commande :
{items_list}
Pour toute question concernant votre commande, n'hésitez pas à contacter notre service client :
{contact_email}
Merci de votre confiance et à bientôt sur PadelClub !
L'équipe PadelClub
"""
def _build_payment_issue_email(order_id, date, total_price, items_list, contact_email, shop_url):
"""Build payment issue email message."""
return f"""
Bonjour,
Nous avons rencontré un problème lors du traitement du paiement de votre commande PadelClub #{order_id}.
Détails de la commande :
Date: {date}
Prix total: {total_price}
Articles:
{items_list}
Veuillez vérifier vos informations de paiement et réessayer. Si le problème persiste, n'hésitez pas à contacter notre service client :
{contact_email}
Vous pouvez également visiter notre boutique pour finaliser votre achat :
{shop_url}
Merci de votre compréhension.
L'équipe PadelClub
"""
def _build_payment_reminder_email(order_id, date, total_price, items_list, contact_email):
"""Build payment reminder email message."""
return f"""
Bonjour,
Nous vous rappelons que votre commande PadelClub #{order_id} du {date} n'a pas encore été payée.
Détails de la commande :
Prix total: {total_price}
Articles:
{items_list}
Pour finaliser votre commande, veuillez procéder au paiement dès que possible.
Si vous rencontrez des difficultés ou si vous avez des questions, n'hésitez pas à contacter notre service client :
{contact_email}
Merci de votre confiance.
L'équipe PadelClub
"""

@ -8,12 +8,20 @@ class CustomLoginView(auth_views.LoginView):
authentication_form = EmailOrUsernameAuthenticationForm authentication_form = EmailOrUsernameAuthenticationForm
def get_success_url(self): def get_success_url(self):
next_url = self.request.POST.get('next') # First check the 'next' parameter which has higher priority
print("CustomLoginView", "next_url", next_url, self.request.GET) next_url = self.request.POST.get('next') or self.request.GET.get('next')
if next_url: if next_url and next_url.strip():
return next_url return next_url
else:
return reverse('index') # Then check if we have a stored referrer URL
referrer = self.request.session.get('login_referrer')
if referrer:
# Clear the stored referrer to prevent reuse
del self.request.session['login_referrer']
return referrer
# Fall back to default
return reverse('index')
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
messages.get_messages(request).used = True messages.get_messages(request).used = True

@ -0,0 +1,19 @@
from django.conf import settings
from django.urls import resolve, reverse
class ReferrerMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
# Check if the user is anonymous and going to the login page
if not request.user.is_authenticated and request.path == reverse('login'):
# Get the referring URL from the HTTP_REFERER header
referrer = request.META.get('HTTP_REFERER')
# Only store referrer if it exists and is not the login page itself
if referrer and 'login' not in referrer:
request.session['login_referrer'] = referrer
response = self.get_response(request)
return response
Loading…
Cancel
Save