В этой статье представлен простой способ интеграции с Stripe. Мы рассматриваем разовые выплаты без токенизации.

В этой статье я пропущу основы настройки Angular и Node, поскольку для этого есть множество ресурсов.

Я люблю излагать свои аргументы с помощью шагов / пунктов, которые были у меня в дни консультирования. Поехали:

  1. Установите полосу для узла: https://www.npmjs.com/package/stripe
  2. Создайте учетную запись для Stripe на www.stripe.com и убедитесь, что через панель управления вы можете получить доступ к вашему публичному ключу (для angular) и секретному ключу (для node). Подробнее об этих ключах позже.
  3. Пока вы находитесь на панели управления Stripe.com, также создайте веб-перехватчик для приема всех статусов, связанных с намерением платежа (не стесняйтесь читать о намерении платежа здесь - https://stripe.com/docs/payments/payment-intents/ сеть ). Как только веб-перехватчик будет создан, вы также получите секретный ключ для него. Подробнее об этом ключе позже.

Обратите внимание на эти ключи в Stripe. Ключ Publishable будет использоваться в Angular, а секретный ключ (снимок экрана слева) вместе с секретом подписи (снимок экрана справа) будет использоваться в приложении вашего узла.

Угловой код

Чтобы упростить задачу, поместите полоску PK в свой файл конфигурации и обратитесь к этому ключу из своего кода.

  1. Отредактируйте свой index.html и включите этот JS-файл - ‹script type =” text / javascript ”src =” https://js.stripe.com/v3/ '›‹/script› . Пока вы здесь, убедитесь, что ваше окно просмотра настроено так: ‹meta name =” viewport ”content =” width = device-width, initial-scale = 1 '›
  2. Вот код для пользовательского интерфейса - HTML-часть. Как видите, Stripe позаботится обо всем и ничего не оставляет вашему воображению. Если вы проверите страницу, вы обнаружите, что Stripe действительно генерирует iframe.
<form>
<input id=”cardholder-name” placeholder=”Full Name” />
<div>Credit or debit card</div>
<div id=”card-element”></div>
</div>
<div style=”text-align:center”>
<button mat-flat-button color=”accent” id=”card-button” (click)=”submitPayment();”>Pay £{{orderTotal}}</button>
</div>
</form>

В приведенном выше коде создателем денег (буквально) является div с id = "card-element". Во время выполнения Stripe добавляет элементы, соответствующие стандарту PCI DSS, и волшебным образом отображает форму оплаты картой вместе с проверками :-).

3. Вот код для страницы angular для отображения элементов Stripe и при нажатии кнопки отправки платежа. Я предполагаю, что ваш метод инициализации вызовет метод createPaymentIntent. Исходя из вашего бизнес-кейса, не стесняйтесь создавать платежное намерение, когда захотите. Прежде чем копировать и вставлять код в свои проекты, прочтите комментарии.

//insert this line of code immediately after the import statements and before any decorators and the declaration of the component class
declare var Stripe: any;
async createPaymentIntent() {
 this.client_secret = …; //call your node endpoint here to create payment intent and then return the client secret OR to simply return the client secret if a payment intent has been created before. This implementation is entirely up to you. My endpoint is sending a JSON object like so { client_secret: paymentIntent.client_secret, ...}
 
this.stripe = Stripe(environment.stripePK); //the Stripe class will be picked up from the JS you included in index.html
//the three lines of code below generate the stripe payment fields
this.elements = this.stripe.elements();
 this.cardElement = this.elements.create('card');
 this.cardElement.mount('#card-element');
 
}
//call this function on click of the submit payment button 
async submitPayment() {
 var cardholderName = ( < HTMLInputElement > document.getElementById('cardholder-name')).value;
 var cardButton = document.getElementById('card-button');
 var clientSecret = this.client_secret; 
//from my node endpoint I am returning the client secret in the form of a JSON object {client_secret : 'client secret returned by Stripe'}
 
this.stripe.handleCardPayment(
  clientSecret.client_secret, this.cardElement, {
   payment_method_data: {
    billing_details: {
     name: cardholderName
    }
   }
  }
 ).then(function(result) {
  if (result.error) {
   //error - result.error.message
  } else {
   //success
  }
 });
}

Большой! Angular готов к работе с Stripe.

Узел

Вот где и происходит самое интересное. * закатывает глаза *

  1. В файле конфигурации сохраните секретный ключ вашей учетной записи Stripe и секретный ключ вашего веб-перехватчика.
  2. Создание платежного намерения. Я установил конечную точку, чтобы позаботиться об этом. Если вы видите приведенный выше код Angular в функции createPaymentIntent, эта конечная точка - это то, что я вызвал, чтобы получить секрет клиента, который будет управлять всем процессом на стороне клиента с помощью Stripe.
router.get(‘/stripe/createPaymentIntent/:orderId’, async (req, res) => {
try {
let order = …; //get your cart or order details here
const stripe = require(‘stripe’)(config.get(‘stripeSK’));
const paymentIntent = await stripe.paymentIntents.create({
amount: parseInt('order amount without decimals so 1000 for £10.00'),
currency: ‘gbp’,
});
res.send({ client_secret: paymentIntent.client_secret});
} catch (err) {
//handle any error(s)
}
res.end();
});

Код на данный момент поможет вам пройти полный платежный цикл. Однако многое из этого происходит на стороне клиента, поэтому, если сеть выходит из строя после оплаты заказа или клиент внезапно выключает свой компьютер или закрывает свою веб-страницу, что вы делаете? Что ж, не полагайтесь на своего клиента, вместо этого используйте веб-перехватчик, который вы настроили в Stripe, чтобы предоставить вам подтверждение того, был ли платеж успешным или нет.

Stripe предоставляет несколько способов подтвердить, прошел ли платеж из вашего бэкэнда. В этой статье я буду говорить только о веб-перехватчиках. Пожалуйста, прочтите https://stripe.com/docs/payments/payment-intents/web для получения дополнительной информации.

Веб-перехватчики Stripe - это круто! После того, как Stripe прерывает обработку платежа, прежде чем вернуть управление вашей системе, они вызывают созданный вами веб-перехватчик, чтобы вы могли выполнять обработку в фоновом режиме, когда клиент видит обновление от Stripe. Данные запроса, которые они отправляют вам, идут вместе с дайджестом, чтобы вы могли убедиться, что содержимое было доставлено Stripe!

Этот фрагмент кода должен быть помещен в index.js (или в любой другой исходный файл для Node) в вашем приложении node. Убедитесь, что вы разместили его ДО того, как ваш запрос будет обработан в любой форме. Чтобы вы могли подтвердить, является ли Stripe тем объектом, который отправил вам запрос, он должен быть передан в библиотеки Stripe в необработанном виде.

const app = express(); 
//Placing the code below this line ensures that the raw request sent by Stripe is processed - a virgin request if you will.
app.post(‘/stripe/chargeStatus/’, bodyParser.raw({type: ‘application/json’}), async (request, response) => {
try {
const endpointSecret = config.get(‘stripeWHSK’);//the webhook secret from Stripe
const stripe = require(‘stripe’)(config.get(‘stripeSK’));//The secret key from Stripe for your account
const sig = request.headers[‘stripe-signature’];
const body = request.body;
let event = null;
try {
//this is the money maker, if this fails either you are using the wrong keys OR your request is not raw OR someone other than Stripe sent you something :-S
event = stripe.webhooks.constructEvent(request.body, sig, endpointSecret);

} catch (err) {
// invalid signature
response.status(400).send(err.message);
return;
}
// if you’ve reached here you can take solace in the fact that the request was sent to you by Stripe and you can process it however you wish. 
let intent = null;
 switch (event[‘type’]) {
 case ‘payment_intent.succeeded’:
 intent = event.data.object;
 //successful payment
 break;
 case ‘payment_intent.payment_failed’:
 intent = event.data.object;
 const message = intent.last_payment_error && intent.last_payment_error.message;
  //unsuccessful payment
 break;
 }response.sendStatus(200);
} catch (err) {
logError(err);
response.status(400).send(err.message);
}
response.end();
});

Вот и все, ребята! Перезапустите серверы, запустите код и проверьте несколько сценариев!

Прочтите и дайте мне знать, если увидите что-нибудь необычное, и я исправлю это как можно скорее.

Будьте осторожны и удачного кодирования (* закатывает глаза * :-))