diff --git a/padelclub_backend/settings.py b/padelclub_backend/settings.py index 24c7028..584d5aa 100644 --- a/padelclub_backend/settings.py +++ b/padelclub_backend/settings.py @@ -163,5 +163,13 @@ STRIPE_SECRET_KEY = 'sk_test_51R4LrTPEZkECCx48PkSbEYarhts7J7XNYpS1mJgows5z5dcv38 STRIPE_WEBHOOK_SECRET = 'your_webhook_secret' # Optional for later STRIPE_CURRENCY = 'eur' # Set to your preferred currency +# Add managers who should receive internal emails +MANAGERS = [ + ('Razmig Sarkissian', 'razmig@padelclub.app'), + # ('Laurent Morvillier', 'laurent@padelclub.app'), + # ('Xavier Rousset', 'xavier@padelclub.app'), +] +SITE_URL = 'https://padelclub.app' + from .settings_local import * from .settings_app import * diff --git a/shop/apps.py b/shop/apps.py index 1f05a2b..e044cad 100644 --- a/shop/apps.py +++ b/shop/apps.py @@ -4,3 +4,5 @@ from django.apps import AppConfig class ShopConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' name = 'shop' + def ready(self): + import shop.signals # Import signals to ensure they're connected diff --git a/shop/signals.py b/shop/signals.py new file mode 100644 index 0000000..8aa490f --- /dev/null +++ b/shop/signals.py @@ -0,0 +1,124 @@ +from django.db.models.signals import post_save, post_delete +from django.dispatch import receiver +from django.core.mail import send_mail +from django.conf import settings +from django.urls import reverse +from .models import Order, OrderItem, OrderStatus +from django.db import transaction + +@receiver([post_save, post_delete], sender=Order) +def send_order_notification(sender, instance, **kwargs): + print("send_order_notification") + """ + 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)) + +def _send_order_email(instance, **kwargs): + created = kwargs.get('created', False) + update_fields = kwargs.get('update_fields', None) + + # Determine the action type + if 'signal' in kwargs and kwargs['signal'] == post_delete: + action = "DELETED" + return + elif created: + action = "CREATED" + return + else: + action = "UPDATED" + print('updated', update_fields) + if update_fields and 'status' in update_fields: + action = "UPDATED" + + # Get order details + order_id = instance.id + status = instance.status + + print("status", status) + if status == OrderStatus.PENDING: + return + + total_price = instance.total_price + + # Generate admin URL + admin_url = f"{settings.SITE_URL}{reverse('admin:shop_order_change', args=[order_id])}" + + # Get customer info + if instance.user: + customer_info = f"Utilisateur: {instance.user.email}" + elif instance.guest_user: + customer_info = f"Invité: {instance.guest_user.email} ({instance.guest_user.phone})" + else: + customer_info = "Client inconnu" + + # Construire les détails des articles - obtenir une requête fraîche des articles de la commande + items_list = "" + if action != "DELETED": + # Utiliser une requête fraîche pour s'assurer d'avoir les données les plus récentes + order_items = OrderItem.objects.filter(order_id=order_id).select_related('product', 'color', 'size') + for item in order_items: + color = item.color.name if item.color 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 += item_line + + # Composer l'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 + + # Traduire le statut actuel + status_fr_map = { + "PENDING": "EN ATTENTE", + "PAID": "PAYÉE", + "SHIPPED": "EXPÉDIÉE", + "DELIVERED": "LIVRÉE", + "CANCELED": "ANNULÉE" + } + status_fr = status_fr_map.get(status, status) + + # Traduire le statut de paiement + payment_status_fr_map = { + "UNPAID": "NON PAYÉE", + "PAID": "PAYÉE", + "FAILED": "ÉCHOUÉE" + } + payment_status_fr = payment_status_fr_map.get(instance.payment_status, instance.payment_status) + + subject = f"Commande #{order_id} {action_fr}: {status_fr}" + message = f""" +La commande #{order_id} a été {action_fr.lower()} + +Statut: {status_fr} +Statut de paiement: {payment_status_fr} +Prix total: {total_price}€ + +{customer_info} + +Articles: +{items_list} + +Voir la commande dans le panneau d'administration: {admin_url} + +Ceci est un message automatique. Merci de ne pas répondre. + """ + + # Send email + recipient_list = [email for name, email in settings.MANAGERS] + if not recipient_list: + recipient_list = [settings.DEFAULT_FROM_EMAIL] + + send_mail( + subject=subject, + message=message, + from_email=settings.DEFAULT_FROM_EMAIL, + recipient_list=recipient_list, + fail_silently=False, + ) diff --git a/shop/views.py b/shop/views.py index 128a46e..73c34ea 100644 --- a/shop/views.py +++ b/shop/views.py @@ -251,6 +251,8 @@ def _handle_guest_checkout_post(request): def payment(request, order_id): """Handle payment for an existing order""" order = get_object_or_404(Order, id=order_id) + order.status = OrderStatus.PENDING + order.payment_status = 'PENDING' order_items = order.items.all() # Check for valid order @@ -297,6 +299,7 @@ def payment_success(request, order_id): cart.clear_cart(request) # Update order status + print("payment_success") order.status = OrderStatus.PAID order.payment_status = 'PAID' order.save() @@ -449,11 +452,6 @@ def simulate_payment_success(request): messages.error(request, "Could not create order from cart") return redirect('shop:view_cart') - # Set order as paid - order.status = OrderStatus.PAID - order.payment_status = 'PAID' - order.save() - # Clear the cart cart.clear_cart(request) @@ -468,9 +466,4 @@ def simulate_payment_failure(request): messages.error(request, "Could not create order from cart") return redirect('shop:view_cart') - # Set order as canceled - order.status = OrderStatus.CANCELED - order.payment_status = 'FAILED' - order.save() - return redirect('shop:payment_cancel', order_id=order.id)