Обработчики платежной формы ЮKassa

28 сентября 2023

Если в платежной форме есть кнопка submit – после нажатия на эту кнопку данные передаются в обработчик. Для WordPress этот процесс немного более сложный – форма должна содержать дополнительные поля и обработчик должен быть сделан особым образом.
Читаем статью – WordPress – получаем данные из формы.

Поскольку при срабатывании события submit формы страница сайта перегружается, лучше разделить обработчик на 2 части.

Обработчик JavaScript

Обработчик JavaScript – срабатывает при нажатии на кнопку подтверждения платежа. Производит валидацию полей, запускает php-обработчик, в зависимости от результата запроса к АПИ Юкасса или перенаправляет пользователя на платежную страницу ЮKassa или выводит на экран ошибку создания платежа.
Если валидация не проходит – вместо запуска php-обработчика, выводим сообщение об ошибке и ждем реакции пользователя. Пользователь исправляет ошибку и снова нажимает кнопку. Процесс повторяется, страница при этом не перегружается.

function vh_payment_submit() {
  // ================ Валидация формы
  if( !document.getElementById( 'pay-term' ).checked ) {
    // чекбокс принятия условий платежа должен быть отмечен
    document.querySelector( '#term-error' ).innerHTML = 'Пожалуйста, примите условия платежа';
    return;
  }
  // ================= Валидация формы закончена
  // Платежные данные из экранной формы
  let paymentData = {
    method:       'bank_card',
    status:       'new',
    amount:       '100',
    description:  'Здесь описание платежа',
    site_url:     document.location.href,
  }
  // вместо кнопки загружается анимированная картинка выполнения процесса
  document.getElementById( "payment-button" ).innerHTML = '<img src="' + document.location.origin + '/wp-content/plugins/vh-payment/assets/load.gif">';
  const url = "/vh-payment/yookassa-new-payment.php";
  let fetch_options = {
    method: 'POST', 
    headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json'
    },
    body: JSON.stringify( paymentData ), // Тело запроса в JSON-формате
  }
  fetch( url, fetch_options )
  .then( function( response ) {
    if ( response.ok ) {
      return response.json();
    } else {
      throw new Error( 'Ошибка при выполнении запроса ' + 
      '(Err:' + response.status + ')'
      );
    }
  })
  .then( function( data ) { 
    // Запрос вернул данные 
      if( 'error' in data ) {
        document.getElementById( "errors" ).innerHTML = 
          '<h3>' + data.error  + '</h3>' + 
          '<span>' + data.details + '</span>';
      }
      if('redirectUrl' in data) {
        // перенаправление на страницу платежа
        window.location = data.redirectUrl; 
      }
    } )
  .catch( function( error ) {
    // Обработка ошибок
    document.getElementById( "errors" ).innerHTML = '<span>' + error  + '</span>';
  });
}

Обработчик php

Обработчик php – подключается к API ЮKassa, проверяет существование аккаунта магазина, формирует именованный массив с данными – платеж Юкасса, отправляет ЮKassa запрос и получает ответ, который возвращает в обработчик JavaScript.

<?php
  // yookassa-new-payment.php - ajax обработчик экранной платежной формы
  // 
  // Получаем входные данные из js обработчика формы
  // vh-payment-form.js

$input = json_decode( file_get_contents( "php://input" ), true );
// 
//  ====================================================================== Здесь должна быть проверка наличия и корректности входных данных
// 
//  Считаем что данные пришли и корректны
// 

// $_SERVER['DOCUMENT_ROOT'] => D:/Common/WebSerwer/OSPanel-5.3.7/domains/site.ru
  $documentroot = $_SERVER['DOCUMENT_ROOT'];


  // $wpconfig = $_SERVER['DOCUMENT_ROOT'] . '/wp-config.php';
  // Подключение конфигурационного файла WordPress
  require( $documentroot . '/wp-config.php' );

  $yookassaShopId = get_option( 'yookassa_shop_id' );
  $yookassaSecretKey = get_option( 'yookassa_secret_key' );

  // Конфигурация 
  // магазина yookassa - $yookassaId/$yookassaKey
  // CloudPayments - $cpId/$cpAPI
  require( 'payment-config.php' );

  // загрузка SDK yookassa
  // $yookassalib = $documentroot . '/vh-payment/yookassa-sdk-php-master/lib/autoload.php';
  // путь относительно текущего каталога site.ru\vh-payment\

  $yookassalib = 'yookassa-sdk-php-master' . DIRECTORY_SEPARATOR . 'lib' . DIRECTORY_SEPARATOR . 'autoload.php';

  // 
  // Здесь нужно проверить наличие библиотеки yookassa
  // 


  require( $yookassalib );
  use YooKassa\Client;

	$yookassaClient = new Client();
	// $yookassaClient->setAuth( $yookassaId.'a', $yookassaKey );
	$yookassaClient->setAuth( $yookassaShopId, $yookassaSecretKey );
  // $error = Array();
  $payment = Array();
  try {
    // Информация о магазине
      $response = $yookassaClient->me();
  } catch (\Exception $e) {
      // Ошибка подключения к магазину yookassa
      $payment['error'] = 'Authorization yookassa';
      // Ошибка $yookassaId
      //  -- Login has illegal format. Error code: invalid_credentials. Parameter name: Authorization.
      // Ошибка $yookassaKey
      //  -- Error in shopId or secret key. Check their validity. You can reissue the key in the Merchant Profile. Error code: invalid_credentials.
      // $error['details'] = $e->getMessage(); 
      $payment['details'] = $e->getMessage(); 
      die( json_encode( $payment ) );
  }


  // # подключаемся к базе данных WordPress  
  $connection = "mysql:host=" . DB_HOST . ";dbname=" . DB_NAME;
  try {  
    $DBH = new PDO( $connection, DB_USER, DB_PASSWORD );  
    $DBH->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );  
  }  
  catch( PDOException $e ) {  
      echo "Хьюстон, у нас проблемы.";  
      // Error log file - https:\\site.ru\vh-payment\PDOErrors.txt
      file_put_contents( 'PDOErrors.txt', $e->getMessage(), FILE_APPEND );  
      $payment['error'] = 'PDO';
      $payment['details'] = $e->getMessage(); 
      die( json_encode( $payment ) );
  }
  
  // таблица wp_payments
  // $table_prefix определен в wp-config.php
  $table_name = $table_prefix . 'payments';

  $values = array(); 
	foreach( $input as $key => $value ) {
    // placeholder’s
		$values[] = ':' . $key; 
	}
  // Записывается информация о платеже - статус платежа - 'new'
  // INSERT INTO `wp_payments` 
  // (system, transaction, status, amount, description, recurrent, email, payer, site_url, uniquie) 
  // values 
  // (:system, :transaction, :status, :amount, :description, :recurrent, :email, :payer, :site_url, :uniquie)
	$sql = "INSERT INTO `" . $table_name . "` (" . join(', ', array_keys( $input )) . ") values (" . join( ', ', $values ) . ")"; 

	$STH = $DBH->prepare( $sql );  
	$STH->execute( $input );
  // получаем id добавленной записи (поле id в таблице БД)
	$id = $DBH->lastInsertId();

  // 
  // ========================================================================================================== Здесь создается платеж yooKassa
  // 

  $paymentargs = [
    'amount' => array(
        'value' => intval( $input['amount'] ),
        'currency' => 'RUB',
      ),
    'payment_method_data' => array(
        'type' => $input['method'],
      ),

    'confirmation' => array(
      'type' => 'redirect',
      'return_url' => $input['redirect'] . '?id=' . $id,
      ),
    'capture' => true,
    'description' => $input['description'],
    'metadata' => array(
      'id' => $id, 
      'uniquie' => $input['uniquie'],
      'email' => $input['email'],
      'payer' => $input['payer'], 
    ),
    'merchant_customer_id' => $input['email'], 
  ];

  $paymentargs['save_payment_method'] = false; 
  if ( $input['recurrent'] == 'y' ) {
    // рекуррентный платеж
    $paymentargs['save_payment_method'] = true; 
  }

  try {
    // Формируется платеж - вернется объект платежа 
    $response = $yookassaClient->createPayment( $paymentargs, uniqid('', false) );

    $sql = "UPDATE `" . $table_name . "` SET `transaction` = '" . $response->id . "', `status` = '" . $response->status . "' WHERE (`id` = '" . $id . "')"; 
    $payment['id'] = $id;
    $payment['transaction'] = $response->id;
    $payment['redirectUrl'] = $response->getConfirmation()->getConfirmationUrl();
    // // Платеж по QR коду
    // $json['qrcode'] = '/payment/qrcode.php?url=' . base64_encode( $response->getConfirmation()->getConfirmationData() ); 
    // $json['redirect'] = $response->getConfirmation()->getConfirmationData(); 
  } catch (\Exception $e) {
    $sql = "UPDATE `" . $table_name . "` SET `errorinfo` = '" . $e->getMessage() . "', `status` = 'error' WHERE (`id` = '" . $id . "')"; 
    $payment['error'] = 'Payment yookassa';
    $payment['details'] = $e->getMessage();
  }

  $STH = $DBH->prepare($sql);  
	$STH->execute();

  die( json_encode( $payment ) );

Для упрощения некоторые части обработчика (типа валидации входных данных, отработка некоторых ошибок) отсутствуют.
Кроме формирования данных для платежа и запроса в Юкасса этот обработчик помещает платежную информацию в базу данных сайта. Это несколько усложняет скрипт зато дает возможность выводить для пользователя информацию по результатам платежа, вести статистику и собирать данные для дальнейшего использования в плагинах списка плательщиков, проведения компаний по сбору средств и т.д.

Если нет времени и желания разбираться самостоятельно – обращайтесь

Наверх