Оплата полосой всегда проходит успешно, и сумма платежа не может быть изменена

#javascript #php #laravel #stripe-payments

Вопрос:

Я долгое время пытаюсь внедрить Stripe в свое приложение Laravel, но столкнулся с множеством проблем. Я каким-то образом реализовал логику, но я не могу или не знаю, как я могу отправить общую сумму текущего заказа для создания PaymentIntent, все платежи хранятся с суммой по умолчанию 500, настроенной в контроллере. Я должен упомянуть, что после успешного ответа от stripe текущий заказ должен быть сохранен в базе данных с информацией о доставке пользователя, которая указана в первой форме, и все заказанные продукты, сохраненные в сеансе. Позвольте мне показать вам это для лучшего понимания.

Вот такой вид (revieworder.blade.php) где у меня есть 2 формы, одна с информацией о доставке пользователя, форма оплаты в полоску и список товаров в корзине из сеанса:

 <ul class="list-group mb-3">
    <?php $total = 0 ?>
    @if(session('cart'))
        @foreach(session('cart') as $id => $details)
        <?php $total  = $details['price'] * $details['quantity'] ?>
            <li class="list-group-item d-flex justify-content-between lh-condensed">
                <img src="../img/{{ $details['image'] }}" alt="{{ $details['name'] }}" width="60" height="60">
                <div>
                    <h6 class="my-0">{{ $details['name'] }}</h6>
                    <small class="text-muted">{{ __('Quantity') }}: {{ $details['quantity'] }}</small><br>
                    <small class="text-muted">{{ __('Unit price') }}: {{ $details['price'] }} RON</small>
                </div>
                <span class="text-muted">{{ $details['price'] * $details['quantity'] }} RON</span>
            </li>
        @endforeach
    @endif
    <li class="list-group-item d-flex justify-content-between">
        <span>Total (RON)</span>
        <strong id="total">{{ $total.' RON' }}</strong>
    </li>
</ul>


<form id="payment-form">
     @csrf
     <div id="card-element"><!--Stripe.js injects the Card Element--></div>
     <button id="submit" class="submit-id">
          <div class="spinner hidden" id="spinner"></div>
          <span id="button-text">Pay now</span>
      </button>
      <p id="card-error" role="alert"></p>
      <p class="result-message hidden">
      </p>
</form>

<script>
//Stripe script
var stripe = Stripe("pk_test_XXX");

// The items the customer wants to buy
var purchase = {
  items: [{id: "prod"}]   //sessions cart
};
console.log(purchase);

var elements = stripe.elements();

    var style = {
      base: { //some styling },
      invalid: {
        fontFamily: 'Arial, sans-serif',
        color: "#fa755a"
      }
    };

    var card = elements.create("card", { style: style });
    // Stripe injects an iframe into the DOM
    card.mount("#card-element");

    card.on("change", function (event) {
      // Disable the Pay button if there are no card details in the Element
      document.querySelector("button").disabled = event.empty;
      document.querySelector("#card-error").textContent = event.error ? event.error.message : "";
    });
// Disable the button until we have Stripe set up on the page
document.getElementsByClassName("submit-id").disabled = true;

$('#payment-form').submit(function(){
    fetch("{{ url(app()->getLocale().'/revieworder') }}", {
    method: "POST",
    headers: {
        "Content-Type": "application/json",
        'X-CSRF-TOKEN': "{{ csrf_token() }}"
    },
    body: JSON.stringify(purchase)
    })
    .then(function(data) {
        $('#payment-form').submit(function(event) {
        event.preventDefault();
        // Complete payment when the submit button is clicked
        payWithCard(stripe, card, data.clientSecret);
        });
    });

    // Calls stripe.confirmCardPayment
    var payWithCard = function(stripe, card, clientSecret) {
    loading(true);
    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 succeeded!
            // The order should be stored in the database
            orderComplete(result.paymentIntent.id);
        }
        });
    };

    // Shows a success message when the payment is complete
    var orderComplete = function(paymentIntentId) {
    loading(false);
    document
        .querySelector(".result-message a")
        .setAttribute(
        "href",
        "https://dashboard.stripe.com/test/payments/"   paymentIntentId
        );
    document.querySelector(".result-message").classList.remove("hidden");
    document.getElementsByClassName("submit-id").disabled = true;
    };

    // Show the customer the error from Stripe if their card fails to charge
    var showError = function(errorMsgText) {
    loading(false);
    var errorMsg = document.querySelector("#card-error");
    errorMsg.textContent = errorMsgText;
    setTimeout(function() {
        errorMsg.textContent = "";
    }, 4000);
    };

    // Show a spinner on payment submission
    var loading = function(isLoading) {
    if (isLoading) {
        // Disable the button and show a spinner
        document.getElementsByClassName("submit-id").disabled = true;
        document.querySelector("#spinner").classList.remove("hidden");
        document.querySelector("#button-text").classList.add("hidden");
    } else {
        document.getElementsByClassName("submit-id").disabled = false;
        document.querySelector("#spinner").classList.add("hidden");
        document.querySelector("#button-text").classList.remove("hidden");
    }
    };
});

</script>
 

А затем это контроллер, который обрабатывает секретный ключ клиента и платежный запрос (CheckoutController.php):

 public function create(){
        StripeStripe::setApiKey('sk_test_XXX');  

        header('Content-Type: application/json');
        try {
            $json_str = file_get_contents('php://input');
            $json_obj = json_decode($json_str);
            
            $paymentIntent = StripePaymentIntent::create([
                'amount' => "500",
                'currency' => 'ron',
            ]);
            $output = [
                'clientSecret' => $paymentIntent->client_secret,
            ];
            echo json_encode($output);
        } catch (Error $e) {
            http_response_code(500);
            echo json_encode(['error' => $e->getMessage()]);
        }
    }
 

Итак, одна из проблем заключается в том, что всякий раз, когда я оплачиваю заказ, независимо от того, какой номер кредитной карты я передаю, это всегда удается, и это серьезная ошибка. Во-вторых, мне нужно передать общую сумму текущего заказа, в противном случае все заказы получат общую сумму 500, значение по умолчанию. Я попытался передать элементы корзины сеанса в выборку, но это не сработало. Даже если я не могу отправить все товары из корзины в намерение, по крайней мере, общая цена должна соответствовать.

Если я что-то не понял достаточно ясно, пожалуйста, дайте мне знать. Я был бы очень признателен за любой совет. Спасибо!

**Редактировать:Бревна

Комментарии:

1. если вы находитесь в тестовой среде для stripe, у вас есть два номера кредитных карт: первый всегда успешный, а второй всегда неудачный. Прочитайте документацию, чтобы узнать, что это за цифры для вас.

2. Независимо от того, какой из них я вставляю, он всегда выполняется успешно, даже если это случайное число

3. тогда вы не слушаете ответ от stripe. вы всегда получаете от них ответ: внутри json у вас есть обратная связь (успешная или нет).

4. Функция выборки @LelioFaieta отправляет только сумму и валюту, никакой информации о карте, поэтому все тело ответа, полученное в качестве ответа, имеет статус ОК. Насколько я знаю, fetch несет ответственность за оплату. Я следил за всеми шагами из документов, понятия не имея, что может быть не так

Ответ №1:

Вы можете обновить платежный amount запрос через API (ссылка), прежде чем подтвердить его (либо на стороне сервера, либо на стороне клиента. Если вы столкнулись с ошибками при отправке этого сообщения, пожалуйста, поделитесь подробностями этой ошибки.

Вам нужно больше рассказать о том, что «это всегда удается», и о том, какой именно запрос вы делаете. Вы не показали, как вы используете Stripe.js. Вы должны использовать тестовые карты, которые предоставляет Stripe, для проверки случаев успеха и неудач. Если вы получаете результаты, отличные от указанных, вам нужно будет предоставить более подробную информацию о том, что именно вы делаете и какого результата вы ожидаете.

Комментарии:

1. Я понимаю. Ну, я реализовал Stripe из официальных документов, и в начале он отправлял запрос на отправку в контроллер, где создается PaymentIntent, сразу после загрузки страницы. Поэтому я завернул выборку и второе обещание в функцию jquery, чтобы отправлять данные только при заполнении платежной формы $('#payment-form').submit(function(){ } . Может быть, именно в этом я и ошибался. Тестирование всех трех тестовых карт, одна из которых для успешной оплаты при отклонении платежа всегда дает 200 сообщений OK /v1/payment_intents

2. Какую именно тестовую карту вы используете и как вы ее используете? Подтверждаете ли вы намерение произвести платеж? Если вы создаете намерение платежа без confirm=true этого, запрос должен быть выполнен успешно, да, так как попытка оплаты не предпринимается до тех пор, пока вы не подтвердите. Если вы, например, отправляете confirm=true , и payment_method= pm_card_chargeDeclined вы должны получить ошибку 402.