from ._base import * @csrf_exempt def stripe_webhook(request): payload = request.body sig_header = request.META.get("HTTP_STRIPE_SIGNATURE") try: event = stripe.Webhook.construct_event(payload, sig_header, settings.STRIPE_WEBHOOK_SECRET) if event["type"] == "checkout.session.completed": session = event["data"]["object"] session_id = session["id"] stripe_ip = request.META.get("REMOTE_ADDR") # IP detectada # 🔹 Actualizar la IP de Stripe en el log StripeLog.objects.filter(session_id=session_id).update(stripe_ip=stripe_ip, timestamp=now()) return JsonResponse({"success": True}) except stripe.error.SignatureVerificationError: return JsonResponse({"success": False, "message": "Firma de webhook no válida."}, status=400) def get_pending_battlepay_orders(account_id): """Órdenes Battlepay PENDING de una cuenta de juego.""" with connections['acore_auth'].cursor() as cursor: cursor.execute( "SELECT id, reference, product_id, product_name, price_eur, status, created_at " "FROM battlepay_orders WHERE account_id = %s AND status = 'PENDING' " "ORDER BY created_at DESC", [account_id], ) cols = [c[0] for c in cursor.description] return [dict(zip(cols, row)) for row in cursor.fetchall()] def _mark_order_paid_by_reference(reference): """Marca una orden como PAID solo si estaba PENDING. Devuelve filas afectadas.""" with connections['acore_auth'].cursor() as cursor: cursor.execute( "UPDATE battlepay_orders SET status = 'PAID', paid_at = UNIX_TIMESTAMP() " "WHERE reference = %s AND status = 'PENDING'", [reference], ) return cursor.rowcount def battlepay_view(request): """Lista las órdenes Battlepay pendientes de la cuenta de juego seleccionada.""" account_id = request.session.get('account_id') if not account_id: if request.session.get('bnet_id'): return redirect('select-account') return redirect('login') orders = get_pending_battlepay_orders(account_id) return render(request, 'account/battlepay.html', { 'orders': orders, 'username': request.session.get('username'), }) def battlepay_pay_view(request): """Crea un checkout de SumUp para pagar una orden Battlepay pendiente.""" account_id = request.session.get('account_id') if not account_id: return redirect('login') if request.method != 'POST': return redirect('battlepay') reference = request.POST.get('reference', '').strip() # Validar que la orden pertenece a la cuenta y sigue pendiente with connections['acore_auth'].cursor() as cursor: cursor.execute( "SELECT product_name, price_eur FROM battlepay_orders " "WHERE reference = %s AND account_id = %s AND status = 'PENDING'", [reference, account_id], ) row = cursor.fetchone() if not row: return render(request, 'account/pago_sumup.html', {'error': 'Orden no encontrada o ya procesada.'}) product_name, price_eur = row try: checkout = crear_checkout_battlepay(reference, price_eur, product_name) except Exception as e: return render(request, 'account/pago_sumup.html', {'error': str(e)}) return render(request, 'account/pago_sumup.html', { 'checkout_id': checkout.get('id'), 'reference': reference, 'product_name': product_name, 'price_eur': price_eur, }) def pagar_sumup(request): """Alias de compatibilidad: envía al listado de órdenes Battlepay.""" return redirect('battlepay') @csrf_exempt def sumup_webhook(request): """Webhook de SumUp: marca la orden Battlepay como PAID al completarse el pago.""" if request.method != "POST": return JsonResponse({"error": "Método no permitido"}, status=405) try: data = json.loads(request.body or b'{}') except json.JSONDecodeError: return JsonResponse({"error": "JSON inválido"}, status=400) payload = data.get('payload') or data.get('data') or {} reference = data.get('checkout_reference') or payload.get('checkout_reference') status = (data.get('status') or payload.get('status') or '').upper() checkout_id = data.get('id') or payload.get('checkout_id') or payload.get('id') event_type = (data.get('event_type') or '').lower() # Si falta la referencia o el estado, consultarlo a la API de SumUp if (not reference or status not in ('PAID', 'SUCCESSFUL')) and checkout_id: try: checkout = obtener_checkout(checkout_id) reference = reference or checkout.get('checkout_reference') status = (checkout.get('status') or status).upper() except Exception as e: logger.error("SumUp webhook: no se pudo consultar el checkout %s: %s", checkout_id, e) pagado = status in ('PAID', 'SUCCESSFUL') or event_type == 'transaction.successful' if reference and pagado: try: afectadas = _mark_order_paid_by_reference(reference) except Exception as e: logger.error("SumUp webhook: error actualizando la orden %s: %s", reference, e) return JsonResponse({"error": "Error interno"}, status=500) if afectadas: return JsonResponse({"message": "Orden marcada como pagada"}, status=200) return JsonResponse({"message": "Orden no pendiente o inexistente"}, status=200) return JsonResponse({"message": "Evento ignorado"}, status=200)