#javascript #python #django #stripe-payments
Вопрос:
Полностью схожу с ума из-за этого…
Я создаю сайт электронной коммерции с помощью django. Я использую Stripe в качестве Поставщика платежных шлюзов. Я не понимаю…Полоса «элемент карты» не отображается. Почему?
Для информации, элемент карты правильно отображался в предыдущие дни. Я мог бы имитировать платежи, которые были записаны в моем аккаунте Stripe… Дело в том, что я проверил старые версии своего кода, которые раньше работали (на случай, если с тех пор я допустил ошибку). Но ни один из них не работает… Это сводит меня с ума.
Что-нибудь не так с моим кодом ? Есть идеи ?
checkout.html
{% extends 'main.html' %}
{% load static %}
{% block content %}
<script src="https://js.stripe.com/v3/"></script>
<div class="container">
<div class="row">
<div class="col d-flex justify-content-center align-items-center">
<h3 class="text-primary fw-bold">PAIEMENT PAR CARTE</h3>
</div>
</div>
<div class="row ">
<div class="col d-flex justify-content-center align-items-center">
<form id="payment-form" method='POST' class="col">
{% csrf_token %}
<div class="form-control" id="card-element"></div>
<div class="sr-field-error" id="card-errors" role="alert"></div>
<button id="payer-submit" class="btn btn-primary">
<div class="spinner-border spinner-border-sm text-light d-none" id="spinner" role="status"></div>
<span class="text-white" id="button-text">Pay</span>
<span class="text-white" id="order-amount"></span>
</button>
</form>
</div>
</div>
<div class="row ">
<div class="col d-flex justify-content-center align-items-center">
<form id="payload" method='POST' class="col" action="/payment/payment-bycard-complete">
{% csrf_token %}
<input id ="data-payload" type="hidden" name="payload"/>
</form>
</div>
</div>
</div>
<script type="text/javascript" src="{% static '/js/stripe.js' %}"></script>
{% endblock content %}
stripe.js
document.getElementById("payer-submit").disabled = true;
fetch("/payment/bycard", {
method: "POST",
headers: {
"Content-Type": "application/json",
}
})
.then(function(result) {
return result.json();
})
.then(function(data) {
return setupElements(data);
})
.then(function({ stripe, card, clientSecret }) {
document.getElementById("payer-submit").disabled = false;
// Handle form submission.
var form = document.getElementById("payment-form");
form.addEventListener("submit", function(event) {
event.preventDefault();
// Initiate payment when the submit button is clicked
pay(stripe, card, clientSecret);
});
});
// Set up Stripe.js and Elements to use in checkout form
var setupElements = function(data) {
stripe = Stripe(data.publishableKey);
var elements = stripe.elements();
var style = {
base: {
color: "#32325d",
fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
fontSmoothing: "antialiased",
fontSize: "16px",
"::placeholder": {
color: "#aab7c4"
}
},
invalid: {
color: "#fa755a",
iconColor: "#fa755a"
}
};
var card = elements.create("card", { style: style });
card.mount("#card-element");
return {
stripe: stripe,
card: card,
clientSecret: data.clientSecret
};
};
/*
* Calls stripe.confirmCardPayment which creates a pop-up modal to
* prompt the user to enter extra authentication details without leaving your page
*/
var pay = function(stripe, card, clientSecret) {
changeLoadingState(true);
// Initiate the payment.
// If authentication is required, confirmCardPayment will automatically display a modal
stripe
.confirmCardPayment(clientSecret, {
payment_method: {
card: card
}
})
.then(function(result) {
if (result.error) {
// Show error to your customer
showError(result.error.message);
} else {
// The payment has been processed!
orderComplete(clientSecret);
}
});
};
/* ------- Post-payment helpers ------- */
/* Shows a success / error message when the payment is complete */
var orderComplete = function(clientSecret) {
//// Just for the purpose of the sample, show the PaymentIntent response object
stripe.retrievePaymentIntent(clientSecret).then(function(result) {
// var paymentIntent = result.paymentIntent;
// var paymentIntentJson = JSON.stringify(paymentIntent, null, 2);
// post data and show new page
// var input = document.getElementById("data-payload");
// input.value = paymentIntentJson;
var form2 =document.getElementById("payload");
form2.submit();
changeLoadingState(false);
});
};
var showError = function(errorMsgText) {
changeLoadingState(false);
var errorMsg = document.querySelector(".sr-field-error");
errorMsg.textContent = errorMsgText;
setTimeout(function() {
errorMsg.textContent = "";
}, 4000);
};
// Show a spinner on payment submission
var changeLoadingState = function(isLoading) {
if (isLoading) {
document.getElementById("payer-submit").disabled = true;
document.querySelector("#spinner").classList.remove("d-none");
document.querySelector("#button-text").classList.add("d-none");
} else {
document.getElementById("payer-submit").disabled = false;
document.querySelector("#spinner").classList.add("d-none");
document.querySelector("#button-text").classList.remove("d-none");
}
};
views.py
import stripe
from django.shortcuts import render, redirect
from django.views.decorators.csrf import csrf_exempt
from django.http import JsonResponse
from django.contrib import messages
from core.settings import STRIPE_SECRET_KEY, STRIPE_PUBLISHABLE_KEY
from core.utils import display_price_in_euro_string
from basket.basket import Basket
from payment.checkout import calculate_order
from payment.save_order import create_invoice_xls, save_order_in_db, save_ordered_items_in_db, save_stripe_payment_in_db
from payment.send_mail import send_order_confirmation
def checkout(request):
if not request.session.get('cart', None):
return redirect('store:all_products')
elif not request.session.get('shipping-form', None):
return redirect('address:create_shipping_address')
else:
calculate_order(request)
context = {
'shipping_fees_in_euros': display_price_in_euro_string(request.session['order']['shipping_fees_in_cent']),
'cart_price_with_discount_in_euros': display_price_in_euro_string(request.session['order']['cart_price_in_cent_with_discount']),
'cart_price_without_discount_in_euros': display_price_in_euro_string(request.session['order']['cart_price_in_cent_without_discount']),
'order_total_in_euros': display_price_in_euro_string(request.session['order']['order_total_in_cent']),
'cart_discount_in_euros': display_price_in_euro_string(request.session['order']['cart_discount_in_cent']),
}
return render(request, 'payment/checkout.html', context)
@csrf_exempt
def create_stripe_payment_intent(request):
try:
total_to_pay = request.session['order']['order_total_in_cent']
stripe.api_key = STRIPE_SECRET_KEY
if request.method == "POST":
# Create a PaymentIntent with the order amount and currency
# https://stripe.com/docs/api/payment_intents/create
intent = stripe.PaymentIntent.create(
amount = total_to_pay,
currency = "eur",
metadata = {
"Adresse de livraison": request.session['shipping-form']['id'],
"Adresse de facturation": request.session['billing-form']['id'],
"Montant commande TTC (centimes)": request.session['order']['order_total_in_cent'],
"Panier avant réduction TTC (centimes)": request.session['order']['cart_price_in_cent_without_discount'],
"Panier après réduction TTC (centimes)": request.session['order']['cart_price_in_cent_with_discount'],
"Frais de livraison TTC (centimes)": request.session['order']['shipping_fees_in_cent'],
"TVA (centimes)": request.session['order']['tva_in_cent'],
"Montant commande HT (centimes)": request.session['order']['order_total_in_cent_HT'],
"SESSION KEY": request.session.session_key,
"PANIER": str(request.session['cart']),
},
receipt_email = 'monoi@laposte.net',
)
request.session['order']['stripe-intent'] = {}
request.session['order']['stripe-intent']['client-secret'] = intent.client_secret
request.session['order']['stripe-intent']['id'] = intent.id
request.session.modified = True
try:
return JsonResponse({
'publishableKey': STRIPE_PUBLISHABLE_KEY,
'clientSecret': intent.client_secret
})
except Exception as e:
return JsonResponse({'error': str(e)}, status = 403)
else:
return redirect('payment:checkout')
except:
return redirect('payment:checkout')
def payment_bycard_complete(request):
stripe.api_key = STRIPE_SECRET_KEY
payment_intent = stripe.PaymentIntent.retrieve(
request.session['order']['stripe-intent']['id'],
)
if payment_intent.status == "succeeded":
save_order_in_db(request, "STRIPE")
save_ordered_items_in_db(request)
save_stripe_payment_in_db(request)
is_invoice = create_invoice_xls(request)
is_mail = send_order_confirmation(request)
basket = Basket(request)
basket.clear()
request.session.flush()
messages.success(request, 'Merci pour votre achat')
return redirect('home_page:home')
else:
return redirect('home_page:error')
Versions :
Django 3.1.6
stripe 2.60.0
EDIT
Console
Promise { <state>: "pending" }
<state>: "fulfilled"
<value>: Object { publishableKey: "pk_test_51Ia5dlE8XikcpErQEGGuA56itbGvPLmnZSNALSKvVGK2syFR21CvPoYMCJtOjb2DArvAKT1hd1z2KSS4wZmpDqre00ZppDWLLl", clientSecret: "pi_3JPkJfE8XikcpErQ0NuBgyfq_secret_C94xiK71RDMFaZImXYc12c1rn" }
Uncaught (in promise) TypeError: Response.json: Body has already been consumed.
<anonymous> http://127.0.0.1:8000/static/js/stripe.js:16
promise callback* http://127.0.0.1:8000/static/js/stripe.js:13
stripe.js:16:21
Согласно отладчику :
В
.then(function(result) {
return result.json();
})
возвращаемый результат.ошибки json()
ПРАВКА 2
У меня был console.log(result.json()) до возврата result.json(), который, я думаю, не разрешен при извлечении. Я удалил этот console.log(result.json()).
Есть еще кое-что, чего я не понимаю … Мой код хорошо работает в Chrome (я могу ввести номер кредитной карты и т.д.), Но не в Firefox. Есть какие-нибудь идеи ?
Комментарии:
1. Вы проверили консоль своего браузера на наличие ошибок?
Ответ №1:
У меня был console.log(result.json()) перед возвращением result.json(), что запрещено при извлечении. Я удалил этот console.log(result.json ()), и теперь он работает.