This commit is contained in:
pscb-dev 2025-11-20 14:29:22 +03:00
commit d5ed07ae40
29 changed files with 1593 additions and 0 deletions

310
README.md Normal file
View File

@ -0,0 +1,310 @@
# PSCB PHP SDK (beta)
- [Общая информация](#общая-информация)
- [Требования](#требования)
- [Описание](#описание)
- [Структура компонента SDK](#структура-компонента-sdk)
- [Методы работы с платежами](#методы-работы-с-платежами)
- [Вызов платежной формы](#вызов-платежной-формы)
- [Пример вызова платежной формы:](#пример-вызова-платежной-формы)
- [Создание платежа СБП](#создание-платежа-сбп)
- [Пример использования:](#пример-использования-1)
- [Подтверждение предавторизации](#подтверждение-предавторизации)
- [Пример использования:](#пример-использования-2)
- [Отмена предавторизации](#отмена-предиавторизации)
- [Пример использования:](#пример-использования-3)
- [Возврат платежа](#возврат-платежа)
- [Пример использования:](#пример-использования-4)
- [Обработка нотификаций](#обработка-нотификаций)
- [Подключение](#подключение)
- [Примеры использования](#примеры-использования)
- [Вопросы и ответы](#вопросы-и-ответы)
## Общая информация
Библиотека является дополнением к API интернет-эквайринга ПСКБ и позволяет интегрировать прием платежей картами и СБП в PHP-проекты с минимальными усилиями.
### Требования
PHP 8.0+
### Описание
SDK включает 2 базовых компонента, которые предназначены для следующих целей:
- `SDK_PayModul` методы работы с платежами
- `SDK_Callback` обработка нотификаций
Для работы с SDK вам понадобятся:
- `marketPlace` идентификатор Магазина
- `secretKey` секретный ключ, используемый для аутентификации
Параметры `marketPlace` и `secretKey` доступны в [Кабинете мерчанта](https://oos.pscb.ru/auth) в разделе "Профиль". Параметр `secretKey` отличается для тестового и боевого окружения Системы.
### Структура компонента SDK
| Файл/каталог | Описание |
|--------------| --- |
| `README.md` | Cодержит информацию про доступные для передачи параметры в методы класса |
| `events` | Отображает ответы и результаты выполнения от API (путь хранения выбирается самостоятельно) |
| `logs` | Отображает ответы и результаты выполнения от SDK (путь хранения выбирается самостоятельно) |
| `src` | Каталог с исходными кодами SDK |
## Методы работы с платежами
### Вызов платежной формы
#### Пример вызова платежной формы:
```php
<?php
//Подключение библиотеки
include 'payment.class.php';
//Основные параметры платежа
$data = array(
"marketPlace" => 47607,
"secretKey" => '111111',
"orderId" => 2000,
"request_url"=>" https://oosdemo.pscb.ru ",
"hold" => true // Активируем создание двухстадийного платежа картой
);
//Параметры для чека
$products = array(
array(
"object" => 'Товар1',
"quantity" => 1,
"price" => 2,
"amount" => 2
),
);
//Указание путей для сохранения логов и событий
//Вместо logs и events установите свой путь для сохранения, например /var/log
$M = new SetWay();
$M->SetLogsAndEvensWay('logs','events');
//Создание экземпляра платежной формы и ее запуск
$PayForm = new ClassPay($data);
$PayForm->CreatePayment($products);
?>
```
### Создание платежа СБП
Для создания платежа через СБП используйте класс `ClassInvoicing`.
#### Пример использования:
```php
<?php
// ... подключение библиотеки и настройка путей для логов ...
$data = array(
"marketPlace" => 47607,
"orderId" => 6026,
"request_url"=>"https://oosdemo.pscb.ru",
"secretKey" => '111111',
"sbpRedirectUrl"=>"https://your-site.com/sbp-callback" //URL - для сайтов, schema - для мобильных приложений
);
$products = array(
array(
"object" => 'Товар1',
"quantity" => 1,
"price" => 2,
"amount" => 2
),
);
$InvoicingPay = new ClassInvoicing($data);
$result = $InvoicingPay->CreatePayment($products);
?>
```
### Подтверждение предавторизации
Для подтверждения двухстадийного платежа картой используйте класс `ClassConfirm`.
#### Пример использования:
```php
<?php
// ... подключение библиотеки и настройка путей для логов ...
$data = array(
"marketPlace" => 47607,
"orderId" => 6026,
"request_url"=>"https://oosdemo.pscb.ru",
"secretKey" => '111111'
);
$products = array(
array(
"object" => 'Товар1',
"quantity" => 1,
"price" => 2,
"amount" => 2
),
);
$ConfirmPay = new ClassConfirm($data);
$result = $ConfirmPay->CreatePayment($products);
?>
```
### Отмена предавторизации
Для отмены двухстадийного платежа картой используйте класс `ClassReject`.
#### Пример использования:
```php
<?php
// ... подключение библиотеки и настройка путей для логов ...
$data = array(
"marketPlace" => 47607,
"orderId" => 6026,
"request_url"=>"https://oosdemo.pscb.ru",
"secretKey" => '111111'
);
$RejectPay = new ClassReject($data);
$result = $RejectPay->CancelPayment();
?>
```
### Возврат платежа
Для возврата платежа используйте класс `ClassRefund`.
#### Пример использования:
```php
<?php
// ... подключение библиотеки и настройка путей для логов ...
$data = array(
"marketPlace" => 47607,
"orderId" => 6026,
"request_url"=>"https://oosdemo.pscb.ru",
"secretKey" => '111111',
"partialRefund"=> true // Укажите false для полного возврата
);
$products = array(
array(
"object" => 'Товар1',
"quantity" => 1,
"price" => 2,
"amount" => 2
),
);
$RefundPay = new ClassRefund($data);
$result = $RefundPay->CreatePayment($products);
?>
```
## Обработка нотификаций
Сценарий работы с нотификациями позволяет получать уведомления об изменении статусов платежей. Для обработки нотификаций используйте класс `CallbackClass`.
### Подключение
```php
<?php
include 'Src/CallbackClass/CallbackClass.php';
$callback = new CallbackClass();
$result = $callback->processNotification($_POST);
?>
```
### Примеры использования
```php
<?php
// ... подключение библиотеки ...
$callback = new CallbackClass();
$notificationData = $callback->processNotification($_POST);
if ($notificationData['status'] == 'success') {
// Обработка успешного платежа
} else {
// Обработка ошибки
}
?>
```
## Вопросы и ответы
**Q: Как изменить пути для сохранения логов?**
A: Используйте метод `SetLogsAndEvensWay` класса `SetWay`:
```php
$M = new SetWay();
$M->SetLogsAndEvensWay('/custom/logs/path', '/custom/events/path');
```
**Q: Как проверить корректность URL для запросов?**
A: SDK автоматически проверяет URL на соответствие допустимым доменам: oos.pscb.ru или oosdemo.pscb.ru.
**Q: Как обрабатывать ошибки?**
A: Все ошибки записываются в соответствующие log-файлы в указанной директории. Также можно анализировать возвращаемые значения методов.
**Q: Как настроить обратный редирект после успешной оплаты через СБП?**
A: Используйте параметр `sbpRedirectUrl` при создании платежа:
```php
$data = array(
// ... другие параметры ...
"sbpRedirectUrl" ="https://your-site.com/success"
);
```
**Q: Как настроить язык платежной формы?**
A: Используйте параметр `displayLanguage`:
```php
$data = array(
// ... другие параметры ...
"displayLanguage" ="en" // Доступные значения: "ru", "en"
);
```
**Q: Как включить режим отладки?**
A: Добавьте параметр `debug` со значением `true`:
```php
$data = array(
// ... другие параметры ...
"debug" =true
);
```
**Q: Какой формат данных требуется для позиций чека?**
A: Каждая позиция чека должна содержать следующие поля:
```php
array(
"object" ='Название товара',
"quantity" =1, // Количество
"price" =100.50, // Цена за единицу
"amount" =100.50 // Общая сумма
)
```
**Q: Как обрабатывать повторные платежи с одинаковым `orderId`?**
A: SDK автоматически проверяет уникальность `orderId`. При попытке создать платеж с уже существующим `orderId` будет возвращена ошибка.
**Q: Как создавать установочные платежи для сохранения реквизитов карты?**
A: Для сохранения реквизитов карты/создания установочных рекуррентных платежей используйте параметр `recurrentable`:
```php
$data = array(
// ... другие параметры ...
"recurrentable" = true
);
```
**Q: Как получить QR-код для оплаты?**
A: Для получения QR-кода установите параметры `requestQrCodeImage` и `requestQrCodeImageUrl` в `true`:
```php
$data = array(
// ... другие параметры ...
"requestQrCodeImage" =true,
"requestQrCodeImageUrl" =true
);
```

View File

@ -0,0 +1,4 @@
<?php
include 'callbackDir/index.php';
?>

View File

@ -0,0 +1,103 @@
<?php
class CallingCallback
{
public $merchant_key;
public $orderId;
public $amount;
public $state;
public $marketPlace;
public $paymentMethod;
private $array;
public $string;
public $WayLog;
public $WayEvents;
public function __construct($array = '')
{
session_start();
$this->WayLog = trim($_SESSION['log_way']);
$this->WayEvents = trim($_SESSION['events_way']);
if (!is_array($array)) {
file_put_contents($this->WayLog.'/callback.log',PHP_EOL.'Массив данных не был передан в конструктор', FILE_APPEND);
exit;
}
$this->array = $array;
$this->merchant_key = $this->array['secretKey'];
$this->orderId = $this->array["orderId"];
}
function decrypt_aes128_ecb_pkcs5($encrypted, $merchant_key)
{
$key_md5_binary = hash("md5", $merchant_key, true);
$decrypted = openssl_decrypt($encrypted, "AES-128-ECB", $key_md5_binary,OPENSSL_RAW_DATA);
return $decrypted;
}
public function processGetCallback($choise = true)
{
if ($_SERVER['REQUEST_METHOD'] === 'POST')
{
$encrypted_request = file_get_contents('php://input');
$decrypted_request = $this->decrypt_aes128_ecb_pkcs5($encrypted_request, $this->merchant_key);
$fp = fopen($this->WayLog.'/callback.log', 'a');
fwrite($fp, 'Содержимое пришедшее от callback: '.$decrypted_request. "\n");
$data_array = json_decode($decrypted_request, true);
//Разбор полученного содержимого
foreach ($data_array["payments"] as $payment)
{
foreach ($payment as $key => $value)
{
$keys = ['orderId','marketPlace','amount','paymentMethod'];
if ((in_array($key, $keys))) {
$ValueInsideJSON[] = $value;
}
}
break;
}
$this->string = (string) $this->orderId;
if($choise)
{
file_put_contents($this->WayEvents.'/CallbackPayment.json', PHP_EOL.$decrypted_request, FILE_APPEND);
return $decrypted_request;
}
if(!$choise)
{
file_put_contents($this->WayEvents.'/CallbackPayment.json', PHP_EOL.$decrypted_request, FILE_APPEND);
$fp = fopen($this->WayLog.'/callback.log', 'a');
fwrite($fp,' Пришедшие данные для сравнения содержат: '.implode(', ', $ValueInsideJSON)."\n");
return $ValueInsideJSON;
}
fclose($fp);
}
}
public function processSendCallback($response)
{
$responseAnswer = json_encode(['payments' => $response]);
$fp = fopen($this->WayLog.'/callback.log', 'a');
fwrite($fp,'Ответ отправлен успешно: '.$responseAnswer."\n");
http_response_code(200);
header('Content-Type: application/json');
echo $responseAnswer;
}
}
?>

5
Src/LogWay/1.php Normal file
View File

@ -0,0 +1,5 @@
<?php
session_start();
$_SESSION['log_way'] = 'logs';
$_SESSION['events_way'] = 'events';
?>

13
Src/LogWay/WayLog.php Normal file
View File

@ -0,0 +1,13 @@
<?php
class SetWay
{
public function __construct() {
session_start();
}
public function SetLogsAndEvensWay($valueLog = '',$valueEvents = '') {
$_SESSION['log_way'] = $valueLog;
$_SESSION['events_way'] = $valueEvents;
}
}
?>

View File

@ -0,0 +1,88 @@
<?php
class CreatingAndTransmittingParametersForConfirm {
// private int $marketPlace;
private $secretKey;
private $items_receipt;
private $message;
private $request_url;
// private $confirmAmount;
private $jsonString;
public function __construct($jsonString)
{
$this->jsonString = $jsonString;
$this->secretKey = $this->jsonString['secretKey'] ?? null;
// $this->confirmAmount = $this->jsonString['confirmAmount'] ?? null;
$this->items_receipt = [];
$this->message = [];
$this->request_url = $this->jsonString['domain'] ?? null;
}
public function addItemToReceipt(string $text, int $quantity, float $price, float $amount)
{
$this->items_receipt[] = [
"text" => $text,
"quantity" => $quantity,
"price" => $price,
"amount" => $amount,
"tax" => "vat110",
"type" => "full_prepayment",
"object" => "commodity",
"unit" => "шт."
];
}
public function processPayment($jsonString)
{
$sum = 0;
foreach ($this->items_receipt as $item)
{
$sum += $item['amount'];
}
$receipt_info = [];
$this->message = [
"marketPlace"=> $this->jsonString['marketPlace'],
"orderId"=> $this->jsonString['orderId'],
"confirmAmount"=> $sum,
];
$receipt_info["fdReceipt"] = ["taxSystem" => "", "items" => $this->items_receipt];
$receipt_info["data"] = $receipt_info;
// $array1 = $jsonString;
$this->message = array_merge($this->message + $receipt_info["data"]);
// $resultArray = array_merge($array1, $this->message);
// print_r($resultArray);
$messageTxt = json_encode($this->message);
// print_r($messageTxt);
$signature = hash('sha256', $messageTxt.$this->secretKey);
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => "https://" .$this->request_url. "/merchantApi/confirmPayment",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $messageTxt,
CURLOPT_HTTPHEADER => [
"Signature: $signature",
"Content-Type: application/json"
]
]);
$res = curl_exec($ch);
curl_close($ch);
return $res;
}
}
?>

View File

@ -0,0 +1,123 @@
<?php
// spl_autoload_register(function ($class) {
include 'Confirm/index.php'; // Предполагается, что каждый класс находится в отдельном файле
// });
class ClassConfirm
{
public $config;
private $array;
public $WayLog;
public $WayEvents;
public $Domain;
public function __construct($array = '')
{
session_start();
$this->WayLog = trim($_SESSION['log_way']);
$this->WayEvents = trim($_SESSION['events_way']);
if (!is_array($array)) {
file_put_contents($this->WayLog.'/confirmation.log',PHP_EOL.'Массив данных не был передан в конструктор', FILE_APPEND);
exit;
}
$this->array = $array;
if(empty($this->array['request_url']))
{
file_put_contents($this->WayLog.'/confirmation.log',PHP_EOL.'Нет адреса для запроса', FILE_APPEND);
exit;
}
if((strpos($this->array['request_url'], 'https://oos-stage.pscb.ru/')===false)&&(strpos($this->array['request_url'], 'https://oos.pscb.ru/')===false)&&(strpos($this->array['request_url'], 'https://oosdemo.pscb.ru/')===false))
{
file_put_contents($this->WayLog.'/confirmation.log',PHP_EOL.' Не Cоответствующий URL', FILE_APPEND);
exit;
}
$parsed_url = parse_url($this->array['request_url']?? null);
$this->config = [
'domain' => $parsed_url['host'],
'orderId'=> $this->array["orderId"],
'marketPlace'=> $this->array['marketPlace'],
'secretKey'=> $this->array['secretKey'],
// 'confirmAmount' => $this->array['confirmAmount'],
];
}
function CreatePayment($product = '')
{
if (!is_array($product)) {
file_put_contents($this->WayLog.'/confirmation.log',PHP_EOL.'Массив данных чека не был передан', FILE_APPEND);
exit;
}
$paymentParams = new CreatingAndTransmittingParametersForConfirm($this->config);
foreach ($product as $key1 => $productt)
{
foreach ($productt as $key2 => $value)
{
if($key2 == 0 || $key2 == 1)
{
file_put_contents($this->WayLog.'/confirmation.log',PHP_EOL.'В price либо amount передано значение с《,》необходимо указать не целочисленное значение через《.》', FILE_APPEND);
exit;
}
}
}
$count = count($product);
file_put_contents($this->WayLog.'/confirmation.log',PHP_EOL.'orderId: '.$this->config['orderId'].' Позиций в чеке: '.$count, FILE_APPEND);
foreach($product as $prod)
{
if((!empty($prod["object"]))&&(!empty($prod["quantity"]))&&(!empty($prod["price"]))&&(!empty($prod["amount"])))
{
$paymentParams->addItemToReceipt($prod["object"],$prod["quantity"], $prod["price"], $prod["amount"]);
}
else if((empty($prod["object"]))||(empty($prod["quantity"]))||(empty($prod["price"]))||(empty($prod["amount"])))
{
file_put_contents('logs'.'/confirmation.log',PHP_EOL.'Не указаны или указаны не все составляющие для чека', FILE_APPEND);
}
}
$res = $paymentParams->processPayment($this->config);
file_put_contents($this->WayEvents.'/ConfirmPayment.json', PHP_EOL.$res);
$res =json_decode($res);
foreach($res as $Part_res =>$Value_Part_res)
{
if($Part_res == 'errorDescription'&&!empty($Value_Part_res))
{
file_put_contents($this->WayLog.'/confirmation.log',PHP_EOL.'orderId: '.$this->config['orderId'].' '.$Value_Part_res, FILE_APPEND);
}
if($Part_res == 'errorDescription')
{
file_put_contents($this->WayLog.'/confirmation.log',PHP_EOL.'orderId: '.$this->config['orderId'].' Есть ошибка в переданных параметрах или повторный OrderID '.$Value_Part_res, FILE_APPEND);
}
}
if(!empty($this->config['orderId']))
{
file_put_contents($this->WayLog.'/confirmation.log',PHP_EOL.'orderId: '.$this->config['orderId'].' Получена команда на запуск модуля', FILE_APPEND);
}
if(empty($this->config['orderId']))
{
file_put_contents($this->WayLog.'/confirmation.log',PHP_EOL.'Получена команда на запуск модуля', FILE_APPEND);
}
// var_dump($res);
return $res;
}
}
?>

View File

@ -0,0 +1,164 @@
<?php
class PaymentParams
{
private $order_id;
private $merchant_id;
private $merchant_key;
private $request_url;
private $success_url;
private $fail_url;
private $showOrderId;
private $hold;
private $nonce;
private $items_receipt;
private $send_receipt;
private $message;
private $messageText;
private $params;
private $config;
public function __construct($config)
{
$this->config = $config ?? null;
$this->order_id = $this->config['orderId'] ?? null;
$this->merchant_id = $this->config['merchant_id'] ?? null;
$this->merchant_key = $this->config['merchant_key'] ?? null;
$this->request_url = $this->config['domain'] ?? null;
$this->success_url = $this->config['success_url'] ?? null;
$this->fail_url = $this->config['fail_url'] ?? null;
$this->nonce = sha1(time() . "order-123");
$this->items_receipt = [];
$this->send_receipt = true; // Добавляем инициализацию свойства
$this->message = '';
$this->params = [];
$optionalFields =
[
"showOrderId","details","paymentMethod","customerAccount","customerComment",
"customerEmail","customerPhone","displayLanguage","recurrentable","debug",
"fdReceipt","hold","merchantData","templates","ac","merchantData",
"sbpSubscriptionPurpose","sbpRedirectUrl"
];
foreach($optionalFields as $field)
{
$this->{$field} = $this->config[$field] ?? null;
}
}
public function addItemToReceipt(string $text, int $quantity, float $price, float $amount)
{
$this->items_receipt[] = [
"text" => $text,
"quantity" => $quantity,
"price" => $price,
"amount" => $amount,
"tax" => "vat110",
"type" => "full_prepayment",
"object" => "commodity",
"unit" => "шт."
];
}
public function generateReceipt()
{
$sum = 0;
foreach ($this->items_receipt as $item)
{
$sum += $item['amount'] ?? null;
}
// Формирование чека по 54-ФЗ
if($this->send_receipt)
{
$optionalFields =
[
"showOrderId","details","paymentMethod","customerAccount","customerComment",
"customerEmail","customerPhone","fail_url","success_url","displayLanguage",
"recurrentable","debug","fdReceipt"
];
$this->message = [
"nonce" => $this->nonce,
"amount" => $sum ?? null,
"orderId" => $this->order_id ?? null,
// "showOrderId" => $this->showOrderId,
];
foreach ($optionalFields as $field) {
if ($this->{$field} !== null) {
$this->message = array_merge($this->message, [$field => $this->{$field}]);
}
}
$dataFields = ["debug","fdReceipt","hold","merchantData","templates","ac","merchantData","sbpSubscriptionPurpose","sbpRedirectUrl"];
foreach ($dataFields as $field)
{
if ($this->{$field} !== null)
{
$this->message = array_merge($this->message,
[
"data" =>
[
$field => $this->{$field},
]
]);
}
}
$receipt_info = [];
$receipt_info['fdReceipt'] = ["taxSystem" => "", "items" => $this->items_receipt];
$this->message['data'] += $receipt_info;
}
$this->messageText = json_encode($this->message);
$this->params = [
"url" => "https://" .$this->request_url. "/pay",
"marketPlace" => $this->merchant_id,
"message" => base64_encode($this->messageText),
"signature" => hash('sha256', $this->messageText . $this->merchant_key)
];
}
public function renderPaymentForm(array $params): string
{
if (isset($params))
{
?>
<style>
#paymentForm
{
display: none; /* Скрыть форму */
}
</style>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function() {
document.getElementById('paymentForm').submit();
});
</script>
<?php
}
$html = '<form id="paymentForm" method="post" action="'. $params['url'] .'">';
$html .= '<input type="hidden" name="marketPlace" value="'. $params['marketPlace'] .'">';
$html .= '<input type="hidden" name="message" value="'. $params['message'] .'">';
$html .= '<input type="hidden" name="signature" value="'. $params['signature'] .'">';
$html .= '<input type="submit" value="Оплатить">';
$html .= '</form>';
return $html;
}
public function getParams(): array
{
return $this->params;
}
}
?>

View File

@ -0,0 +1,139 @@
<?php
// spl_autoload_register(function ($class) {
include 'Pay/index.php';
class ClassPay
{
public $config;
private $array;
// public $Way = 'logs/';
public $WayLog;
public $WayEvents;
public $Domain;
public function __construct($array = '')
{
session_start();
$this->WayLog = trim($_SESSION['log_way']);
$this->WayEvents = trim($_SESSION['events_way']);
if (!is_array($array)) {
file_put_contents($this->WayLog.'/payment.log',PHP_EOL.'Массив данных не был передан в конструктор', FILE_APPEND);
exit;
}
$this->array = $array;
if(empty($this->array['request_url']))
{
file_put_contents($this->WayLog.'/payment.log',PHP_EOL.'Нет адреса для запроса', FILE_APPEND);
exit;
}
if((strpos($this->array['request_url'], 'https://oos-stage.pscb.ru/')===false)&&(strpos($this->array['request_url'], 'https://oos.pscb.ru/')===false)&&(strpos($this->array['request_url'], 'https://oosdemo.pscb.ru/')===false))
{
file_put_contents($this->WayLog.'/payment.log',PHP_EOL.' Не Cоответствующий URL', FILE_APPEND);
exit;
}
$parsed_url= parse_url($this->array['request_url']?? null);
$this->config = [
'domain' => $parsed_url['host'],
'orderId'=> $this->array["orderId"]?? null,
'merchant_id'=> $this->array['marketPlace']?? null,
'merchant_key'=> $this->array['secretKey']?? null,
'request_url'=> $this->array['request_url']?? null,
'success_url'=>$this->array['success_url']?? null,
'fail_url'=>$this->array['fail_url']?? null,
'amount'=>0,
'showOrderId' =>$this->array['showOrderId']?? null,
'details' => $this->array['details']?? null,
'paymentMethod'=>$this->array['paymentMethod']?? null,
'customerAccount'=>$this->array['customerAccount']?? null,
'customerComment'=>$this->array['customerComment']?? null,
'customerEmail'=> $this->array['customerEmail']?? null,
'customerPhone'=>$this->array['customerPhone']?? null,
'displayLanguage'=>$this->array['displayLanguage']?? null,
'recurrentable'=>$this->array['recurrentable']?? null,
'debug'=>$this->array['debug']?? null,
'hold' =>$this->array['hold']?? false,
];
// echo $Domain;
}
function CreatePayment($product = '')
{
if (!is_array($product))
{
file_put_contents($this->WayLog.'/payment.log',PHP_EOL.'Массив данных для чека не был передан', FILE_APPEND);
exit;
}
$paymentParams = new PaymentParams($this->config);
foreach ($product as $key1 => $productt)
{
foreach ($productt as $key2 => $value)
{
if($key2 == 0 || $key2 == 1)
{
file_put_contents($this->WayLog.'/payment.log',PHP_EOL.'В price либо amount передано значение с《,》необходимо указать не целочисленное значение через《.》', FILE_APPEND);
exit;
}
}
}
// print_r($product);
$count = count($product);
file_put_contents($this->WayLog.'/payment.log',PHP_EOL.'orderId: '.$this->config['orderId'].' Позиций в чеке: '.$count, FILE_APPEND);
foreach($product as $prod)
{
if((!empty($prod["object"]))&&(!empty($prod["quantity"]))&&(!empty($prod["price"]))&&(!empty($prod["amount"])))
{
$paymentParams->addItemToReceipt($prod["object"],$prod["quantity"], $prod["price"], $prod["amount"]);
}
else if((empty($prod["object"]))||(empty($prod["quantity"]))||(empty($prod["price"]))||(empty($prod["amount"])))
{
file_put_contents('logs'.'/payment.log',PHP_EOL.'Не указаны или указаны не все составляющие для чека', FILE_APPEND);
}
}
$paymentParams->generateReceipt();
$html = $paymentParams->renderPaymentForm($paymentParams->getParams());
file_put_contents($this->WayEvents.'/CreatePayResult.json', PHP_EOL.$html, FILE_APPEND);
if ('logs'=== $this->WayLog)
{
$N = 1;
$N.= strlen($this->WayLog);
}
else
if ('logs'!== $this->WayLog)
{
$N = 0;
$N.= strlen($this->WayLog);
$N.= strlen('logs');
}
if(!empty($this->config['orderId']))
{
file_put_contents($this->WayLog.'/payment.log',PHP_EOL.'orderId: '.$this->config['orderId'].' Получена команда на запуск модуля ', FILE_APPEND);
}
if(empty($this->config['orderId']))
{
file_put_contents($this->WayLog.'/payment.log',PHP_EOL.'Получена команда на запуск модуля ', FILE_APPEND);
}
echo $html;
return $html;
}
}
?>

View File

@ -0,0 +1,121 @@
<?php
class CreatingAndTransmittingParametersForInvoicing
{
private int $marketPlace;
private string $secretKey;
private $message;
private $items_receipt;
private $jsonString;
private $request_url;
private $sbpRedirectUrl;
public function __construct($jsonString)
{
$this->jsonString = $jsonString;
$this->marketPlace = $this->jsonString['marketPlace'] ?? null;
$this->secretKey = $this->jsonString['secretKey'] ?? null;
$this->request_url = $this->jsonString['domain'] ?? null;
$this->sbpRedirectUrl = $this->jsonString['sbpRedirectUrl'] ?? null;
$this->items_receipt = [];
$optionalFields =
[
"marketPlace","amount","orderId","paymentMethod","showOrderId",
"details","customerAccount","customerComment","customerEmail",
"customerPhone","expirationFromNow","expirationDateTime",
"recurrentable","nonce",
"user","userPhone","debug","sbpSubscriptionPurpose",
];
foreach($optionalFields as $field)
{
$this->{$field} = $this->jsonString[$field] ?? null;
}
}
public function addItemToReceipt(string $text, int $quantity, float $price, float $amount)
{
$this->items_receipt[] = [
"text" => $text,
"quantity" => $quantity,
"price" => $price,
"amount" => $amount,
"tax" => "vat110",
"type" => "full_prepayment",
"object" => "commodity",
"unit" => "шт."
];
}
public function processPayment2()
{
$sum = 0;
foreach ($this->items_receipt as $item)
{
$sum += $item['amount'];
}
$receipt_info = [];
$receipt_info_fd = [];
if ($this->marketPlace != null)
{
$this->message = [
"marketPlace"=> $this->jsonString['marketPlace'],
"orderId"=> $this->jsonString['orderId'],
"amount"=> (int)$sum,
"requestQrCodeImageUrl"=> false,
];
}
$optionalFields =
[
"marketPlace","amount","orderId","paymentMethod","showOrderId",
"details","customerAccount","customerComment","customerEmail",
"customerPhone","expirationFromNow","expirationDateTime",
"recurrentable","nonce"
];
foreach ($optionalFields as $field) {
if ($this->{$field} !== null) {
$this->message = array_merge($this->message, [$field => $this->{$field}]);
}
}
$this->message = array_merge($this->message, ["requestQrCodeImageUrl"=> false]);
$receipt_info_fd["fdReceipt"] = ["taxSystem" => "", "items" => $this->items_receipt];
$receipt_info["data"] = ["requestQrCodeImageUrl"=> false,"requestQrCodeImage"=> false,"fdReceipt"=>$receipt_info_fd["fdReceipt"],"sbpRedirectUrl"=>filter_var($this->sbpRedirectUrl, FILTER_VALIDATE_URL) ? $this->sbpRedirectUrl : null];
$this->message = array_merge($this->message + $receipt_info);
$newJsonString = json_encode($this->message);
$values = json_decode($newJsonString, true);
$messageTxt = json_encode($values);
$signature = hash('sha256', $messageTxt.$this->secretKey);
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => "https://".$this->request_url."/merchantApi/pay",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $messageTxt,
CURLOPT_HTTPHEADER => [
"Signature: $signature",
"Content-Type: application/json"
]
]);
$res = curl_exec($ch);
return $res;
}
}
?>

View File

@ -0,0 +1,131 @@
<?php
include 'Invoicing/index.php';
class ClassInvoicing
{
public $config;
private $array;
public $WayLog;
public $WayEvents;
public function __construct($array = '')
{
session_start();
$this->WayLog = trim($_SESSION['log_way']);
$this->WayEvents = trim($_SESSION['events_way']);
if (!is_array($array)) {
file_put_contents($this->WayLog.'/Invoicing.log',PHP_EOL.'Массив данных не был передан в конструктор', FILE_APPEND);
exit;
}
$this->array = $array;
if(empty($this->array['request_url']))
{
file_put_contents($this->WayLog.'/Invoicing.log',PHP_EOL.'Нет адреса для запроса', FILE_APPEND);
exit;
}
if((strpos($this->array['request_url'], 'https://oos-stage.pscb.ru/')===false)&&(strpos($this->array['request_url'], 'https://oos.pscb.ru/')===false)&&(strpos($this->array['request_url'], 'https://oosdemo.pscb.ru/')===false))
{
file_put_contents($this->WayLog.'/Invoicing.log',PHP_EOL.' Не Cоответствующий URL', FILE_APPEND);
exit;
}
$parsed_url= parse_url($this->array['request_url']?? null);
$this->config = [
'domain' => $parsed_url['host'],
'orderId'=> $this->array["orderId"],
'marketPlace'=> $this->array['marketPlace'],
'secretKey'=> $this->array['secretKey'],
'amount'=> $this->array['amount']?? null,
'paymentMethod'=> "sbp",
'details'=> $this->array['details']?? null,
'customerEmail'=> $this->array['customerEmail']?? null,
'sbpRedirectUrl'=> $this->array['sbpRedirectUrl']?? null,
'requestQrCodeImage'=> false,
'requestQrCodeImageUrl'=> false,
];
}
function CreatePayment($product = '')
{
if (!is_array($product)) {
file_put_contents($this->WayLog.'/Invoicing.log',PHP_EOL.'Массив данных для чека не был передан', FILE_APPEND);
exit;
}
$paymentParams = new CreatingAndTransmittingParametersForInvoicing($this->config);
foreach ($product as $key1 => $productt)
{
foreach ($productt as $key2 => $value)
{
if($key2 == 0 || $key2 == 1)
{
file_put_contents($this->WayLog.'/Invoicing.log',PHP_EOL.'В price либо amount передано значение с《,》необходимо указать не целочисленное значение через《.》', FILE_APPEND);
exit;
}
}
}
$count = count($product);
file_put_contents($this->WayLog.'/Invoicing.log',PHP_EOL.'orderId: '.$this->config['orderId'].' Позиций в чеке: '.$count, FILE_APPEND);
foreach($product as $prod)
{
if((!empty($prod["object"]))&&(!empty($prod["quantity"]))&&(!empty($prod["price"]))&&(!empty($prod["amount"])))
{
$paymentParams->addItemToReceipt($prod["object"],$prod["quantity"], $prod["price"], $prod["amount"]);
}
else if((empty($prod["object"]))||(empty($prod["quantity"]))||(empty($prod["price"]))||(empty($prod["amount"])))
{
file_put_contents('logs'.'/Invoicing.log',PHP_EOL.'Не указаны или указаны не все составляющие для чека', FILE_APPEND);
}
}
$res = $paymentParams->processPayment2();
file_put_contents($this->WayEvents.'/CreateInvoicing.json', PHP_EOL.$res);
$res = json_decode($res);
$url = $res->payment->qrCodePayload;
if(!empty($url))
{
header("Location: $url");
echo($url);
exit;
}
foreach($res as $Part_res =>$Value_Part_res)
{
if($Part_res == 'errorDescription'&&!empty($Value_Part_res))
{
file_put_contents($this->WayLog.'/Invoicing.log',PHP_EOL.'orderId: '.$this->config['orderId'].' '.$Value_Part_res, FILE_APPEND);
}
if($Part_res == 'errorDescription')
{
file_put_contents($this->WayLog.'/Invoicing.log',PHP_EOL.'orderId: '.$this->config['orderId'].' Есть ошибка в переданных параметрах или повторный OrderID '.$Value_Part_res, FILE_APPEND);
}
}
return $res;
if(!empty($this->config['orderId']))
{
file_put_contents($this->WayLog.'/Invoicing.log', PHP_EOL.$this->config['orderId'].' Получена команда на запуск модуля', FILE_APPEND);
}
if(empty($this->config['orderId']))
{
file_put_contents($this->WayLog.'/Invoicing.log', PHP_EOL.'Получена команда на запуск модуля', FILE_APPEND);
}
}
}
?>

View File

@ -0,0 +1,90 @@
<?php
class CreatingAndTransmittingParametersForRefund {
private int $marketPlace;
private string $secretKey;
private $items_receipt;
private $items_receipt2;
private $items_receipt3;
private $message;
private $jsonString;
private $request_url;
public function __construct($jsonString)
{
$this->jsonString = $jsonString;
$this->marketPlace = $this->jsonString['marketPlace'] ?? null;;
$this->secretKey = $this->jsonString['secretKey'] ?? null;
$this->request_url = $this->jsonString['domain'] ?? null;
$this->items_receipt = [];
$this->items_receipt2 = [];
$this->message = [];
}
public function addItemToReceipt(string $text, int $quantity, float $price, float $amount)
{
$this->items_receipt[] = [
"text" => $text,
"quantity" => $quantity,
"price" => $price,
"amount" => $amount,
"tax" => "vat110",
"type" => "full_prepayment",
"object" => "commodity",
"unit" => "шт."
];
}
public function processPayment() {
$sum = 0;
foreach ($this->items_receipt as $item)
{
$sum += $item['amount'];
}
$receipt_info = [];
$this->message = [
"marketPlace"=> $this->jsonString['marketPlace'],
"orderId"=> $this->jsonString['orderId'],
"partialRefund"=> $this->jsonString['partialRefund'],
"refundSum"=>$sum
];
$receipt_info["fdReceipt"] = ["taxSystem" => "", "items" => $this->items_receipt];
$receipt_info["data"] = $receipt_info;
// $array1 = $jsonString;
// $this->message = array_merge($this->message + $receipt_info);
// $resultArray = array_merge($array1, $this->message);
// print_r($resultArray);
$messageTxt = json_encode($this->message);
$signature = hash('sha256', $messageTxt.$this->secretKey);
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => "https://" .$this->request_url. "/merchantApi/refundPayment",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $messageTxt,
CURLOPT_HTTPHEADER => [
"Signature: $signature",
"Content-Type: application/json"
]
]);
$res = curl_exec($ch);
curl_close($ch);
return $res;
}
}
?>

View File

@ -0,0 +1,119 @@
<?php
include 'Refund/index.php';
class ClassRefund
{
public $config;
private $array;
public $WayLog;
public $WayEvents;
public $Domain;
public function __construct($array = '')
{
session_start();
$this->WayLog = trim($_SESSION['log_way']);
$this->WayEvents = trim($_SESSION['events_way']);
if (!is_array($array)) {
file_put_contents($this->WayLog.'/refund.log',PHP_EOL.'Массив данных не был передан в конструктор', FILE_APPEND);
exit;
}
$this->array = $array;
if(empty($this->array['request_url']))
{
file_put_contents($this->WayLog.'/refund.log',PHP_EOL.'Нет адреса для запроса', FILE_APPEND);
exit;
}
if((strpos($this->array['request_url'], 'https://oos-stage.pscb.ru/')===false)&&(strpos($this->array['request_url'], 'https://oos.pscb.ru/')===false)&&(strpos($this->array['request_url'], 'https://oosdemo.pscb.ru/')===false))
{
file_put_contents($this->WayLog.'/refund.log',PHP_EOL.' Не Cоответствующий URL', FILE_APPEND);
exit;
}
$parsed_url= parse_url($this->array['request_url']?? null);
$this->config = [
'domain' => $parsed_url['host'],
'orderId'=> $this->array["orderId"],
'marketPlace'=> $this->array['marketPlace'],
'secretKey'=> $this->array['secretKey'],
'partialRefund'=>$this->array['partialRefund'] ?? false
];
}
function CreatePayment($product = '')
{
if (!is_array($product)) {
file_put_contents($this->WayLog.'/refund.log',PHP_EOL.'Массив данных для чека не был передан', FILE_APPEND);
exit;
}
$paymentParams = new CreatingAndTransmittingParametersForRefund($this->config);
foreach ($product as $key1 => $productt)
{
foreach ($productt as $key2 => $value)
{
if($key2 == 0 || $key2 == 1)
{
file_put_contents($this->WayLog.'/refund.log',PHP_EOL.'В price либо amount передано значение с《,》необходимо указать не целочисленное значение через《.》', FILE_APPEND);
exit;
}
}
}
$count = count($product);
file_put_contents($this->WayLog.'/refund.log',PHP_EOL.'orderId: '.$this->config['orderId'].' Позиций в чеке: '.$count, FILE_APPEND);
foreach($product as $prod)
{
if((!empty($prod["object"]))&&(!empty($prod["quantity"]))&&(!empty($prod["price"]))&&(!empty($prod["amount"])))
{
$paymentParams->addItemToReceipt($prod["object"],$prod["quantity"], $prod["price"], $prod["amount"]);
}
else if((empty($prod["object"]))||(empty($prod["quantity"]))||(empty($prod["price"]))||(empty($prod["amount"])))
{
file_put_contents('logs'.'/refund.log',PHP_EOL.'Не указаны или указаны не все составляющие для чека', FILE_APPEND);
}
}
$res = $paymentParams->processPayment();
file_put_contents($this->WayEvents.'/RefundPayment.json', PHP_EOL.$res);
$res =json_decode($res);
foreach($res as $Part_res =>$Value_Part_res)
{
if($Part_res == 'errorDescription'&&!empty($Value_Part_res))
{
file_put_contents($this->WayLog.'/refund.log',PHP_EOL.'orderId: '.$this->config['orderId'].' '.$Value_Part_res, FILE_APPEND);
}
if($Part_res == 'errorDescription')
{
file_put_contents($this->WayLog.'/refund.log',PHP_EOL.'orderId: '.$this->config['orderId'].' Есть ошибка в переданных параметрах или повторный OrderID '.$Value_Part_res, FILE_APPEND);
}
}
return $res;
if(!empty($this->config['orderId']))
{
file_put_contents($this->WayLog.'/refund.log',PHP_EOL.'orderId: '.$this->config['orderId'].' Получена команда на запуск модуля', FILE_APPEND);
}
if(empty($this->config['orderId']))
{
file_put_contents($this->WayLog.'/refund.log',PHP_EOL.'Получена команда на запуск модуля', FILE_APPEND);
}
}
}
?>

View File

@ -0,0 +1,40 @@
<?php
class СancelTransmitting
{
private int $marketPlace;
private string $secretKey;
private $jsonString;
private $request_url;
public function __construct($jsonString)
{
$this->jsonString = $jsonString;
$this->secretKey = $this->jsonString['secretKey'] ?? null;;
$this->request_url = $this->jsonString['domain'] ?? null;
}
public function rejectPayment()
{
$messageTxt = json_encode($this->jsonString);
$signature = hash('sha256', $messageTxt . $this->secretKey);
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => "https://" .$this->request_url. "/merchantApi/rejectPayment",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $messageTxt,
CURLOPT_HTTPHEADER => [
"Signature: $signature",
"Content-Type: application/json"
]
]);
$res = curl_exec($ch);
return $res;
}
}
?>

View File

@ -0,0 +1,85 @@
<?php
include 'Reject/index.php';
class ClassReject
{
public $config;
private $array;
public $WayLog;
public $WayEvents;
public $Domain;
public function __construct($array = '')
{
session_start();
$this->WayLog = trim($_SESSION['log_way']);
$this->WayEvents = trim($_SESSION['events_way']);
if (!is_array($array)) {
file_put_contents($this->WayLog.'/cancellation.log',PHP_EOL.'Массив данных не был передан в конструктор', FILE_APPEND);
exit;
}
$this->array = $array;
if(empty($this->array['request_url']))
{
file_put_contents($this->WayLog.'/cancellation.log',PHP_EOL.'Нет адреса для запроса', FILE_APPEND);
exit;
}
if((strpos($this->array['request_url'], 'https://oos-stage.pscb.ru/')===false)&&(strpos($this->array['request_url'], 'https://oos.pscb.ru/')===false)&&(strpos($this->array['request_url'], 'https://oosdemo.pscb.ru/')===false))
{
file_put_contents($this->WayLog.'/cancellation.log',PHP_EOL.' Не Cоответствующий URL', FILE_APPEND);
exit;
}
$parsed_url= parse_url($this->array['request_url']?? null);
$this->config = [
'domain' => $parsed_url['host'],
'orderId'=> $this->array["orderId"],
'marketPlace'=> $this->array['marketPlace'],
'secretKey'=> $this->array['secretKey']
];
}
function CancelPayment()
{
$paymentParams = new СancelTransmitting($this->config);
$res = $paymentParams->rejectPayment();
file_put_contents($this->WayEvents.'/RejectPayment.json', PHP_EOL.$res);
$res =json_decode($res);
foreach($res as $Part_res =>$Value_Part_res)
{
if($Part_res == 'errorDescription'&&!empty($Value_Part_res))
{
file_put_contents($this->WayLog.'/cancellation.log',PHP_EOL.'orderId: '.$this->config['orderId'].' '.$Value_Part_res, FILE_APPEND);
}
if($Part_res == 'errorDescription')
{
file_put_contents($this->WayLog.'/cancellation.log',PHP_EOL.'orderId: '.$this->config['orderId'].' Есть ошибка в переданных параметрах или повторный OrderID '.$Value_Part_res, FILE_APPEND);
}
}
if(!empty($this->config['orderId']))
{
file_put_contents($this->WayLog.'/cancellation.log',PHP_EOL.'orderId: '.$this->config['orderId'].' Получена команда на запуск модуля', FILE_APPEND);
}
if(empty($this->config['orderId']))
{
file_put_contents($this->WayLog.'/cancellation.log',PHP_EOL.'Получена команда на запуск модуля', FILE_APPEND);
}
return $res;
}
}
?>

View File

View File

View File

View File

View File

View File

49
index.php Normal file
View File

@ -0,0 +1,49 @@
<?php
include 'payment.class.php';
$data = array(
"marketPlace" => 47607,//демо
// "marketPlace" => 402938079, //прод
"secretKey" => '111111',//демо
// "secretKey" => 'ue4z4L00IREoygx52RQH28l62dN6V685',
// "secretKey" => '63f779a3b37db5d8e5ddbde00e4ef66d7354cb5572bc3f2f71ebfba14a2d82bc',
"orderId" => 3204,
// "request_url"=>"https://oos.pscb.ru/cabinet/payments", //прод
"request_url"=>"https://oos-stage.pscb.ru/cabinet/payments",//демо
"sbpRedirectUrl"=>"ht111234",
// "hold" => true,
);
$products = array(
array(
"object" => 'Товар1',
"quantity" => 1,
"price" => 2,
"amount" => 2
),
array(
"object" => 'Товар2',
"quantity" => 1,
"price" => 2,
"amount" => 2
),
);
$M = new SetWay();
$M->SetLogsAndEvensWay('logs','events');
$PayForm = new ClassPay($data);
$PayForm->CreatePayment($products);
// $ConfirmPay = new ClassConfirm($data);
// $ConfirmPay->CreatePayment($products);
// $RefundPay = new ClassRefund($data);
// $RefundPay->CreatePayment($products);
// $InvoicingPay = new ClassInvoicing($data);
// $InvoicingPay->CreatePayment($products);
?>

0
logs/Invoicing.log Normal file
View File

0
logs/callback.log Normal file
View File

0
logs/cancellation.log Normal file
View File

0
logs/confirmation.log Normal file
View File

0
logs/payment.log Normal file
View File

0
logs/refund.log Normal file
View File

9
payment.class.php Normal file
View File

@ -0,0 +1,9 @@
<?php
include 'Src/PayFormClass/PayFormClass.php';
include 'Src/PayConfirmClass/ConfirmClass.php';
include 'Src/PayInvoicingClass/InvoicingClass.php';
include 'Src/PayRefundClass/RefundClass.php';
include 'Src/PayRejectClass/RejectClass.php';
include 'Src/CallbackClass/CallbackClass.php';
include 'Src/LogWay/WayLog.php';
?>