Полоса «элемент карты» не отображается. Почему?

#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 ()), и теперь он работает.