forked from apoloz/alfa-bank-sdk
doc(update)
This commit is contained in:
263
README.md
263
README.md
@@ -8,210 +8,163 @@
|
||||
## Требования
|
||||
|
||||
- PHP 8.2+
|
||||
- Расширение OpenSSL
|
||||
- [Saloon](https://docs.saloon.dev) v3.0+
|
||||
- [Spatie Laravel Data](https://spatie.be/docs/laravel-data)
|
||||
|
||||
## Установка
|
||||
## Подключение и Безопасность
|
||||
|
||||
```bash
|
||||
composer require apoloz/alfa-bank-sdk
|
||||
SDK поддерживает две разные модели безопасности, используемые в API Альфа-Банка.
|
||||
|
||||
### 1. Подключение к СБП (Pay-in)
|
||||
|
||||
**Шаги для получения доступа:**
|
||||
1. Генерируете пару ключей: `openssl req -x509 -newkey rsa:2048 -keyout client.key -out client.crt -nodes -days 3650`.
|
||||
2. Отправляете `client.crt` менеджеру банка (acquiring@alfabank.ru).
|
||||
3. Получаете от банка `alias` (key-name) и `TermNo`.
|
||||
|
||||
**Поток данных и подпись:**
|
||||
* **Transport**: Обязательный **MTLS**. Вы должны передать `client.crt` и `client.key` в конфигурацию Guzzle/Saloon.
|
||||
* **Payload**: Тело запроса канонизируется по алгоритму **JCS**.
|
||||
* **Signature**: SHA256withRSA подпись JCS-строки помещается в заголовок `Authorization`.
|
||||
|
||||
**SDK делает это автоматически**:
|
||||
```php
|
||||
// В config/alfa-bank.php
|
||||
'sbp' => [
|
||||
'alias' => 'my-company-alias',
|
||||
'private_key' => storage_path('certs/client.key'),
|
||||
'cert' => storage_path('certs/client.crt'),
|
||||
],
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Архитектура и потоки данных
|
||||
### 2. Подключение к BaaS (Номинальные счета)
|
||||
|
||||
Библиотека обеспечивает строгую типизацию на всех этапах. Вы работаете только с объектами (DTO), а SDK берет на себя всю сложность протоколов банка.
|
||||
**Шаги для получения доступа:**
|
||||
1. Регистрация в личном кабинете партнера.
|
||||
2. Получение `client_id` и `client_secret` для OAuth2.
|
||||
3. Регистрация публичного ключа для проверки подписей выплат.
|
||||
|
||||
### 1. Жизненный цикл запроса (BaaS)
|
||||
**Поток данных и подпись:**
|
||||
* **Auth**: Стандартный OAuth2 Bearer Token.
|
||||
* **Payload Signature**: Для критических операций (выплаты, идентификация) требуется `digestSignatures`. Это массив CMS-подписей (PKCS7) в формате Base64, которыми подписываются финансовые поля.
|
||||
|
||||
**Пример формирования CMS в SDK:**
|
||||
```php
|
||||
use Apoloz\AlfaBank\Utils\CmsSigner;
|
||||
|
||||
$payload = json_encode($dataToSign);
|
||||
$signature = CmsSigner::sign($payload, $privateKey, $certificate);
|
||||
|
||||
// $signature помещается в массив digestSignatures
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Архитектура и Потоки данных
|
||||
|
||||
### Гибридный поток: СБП -> Номинальный счет
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant App as Приложение
|
||||
participant DTO as Request DTO
|
||||
participant SDK as Connector
|
||||
participant API as Alfa Bank
|
||||
participant Client as Покупатель
|
||||
participant SBP as SDK (SBP Connector)
|
||||
participant API as Alfa Bank API
|
||||
participant BaaS as SDK (BaaS Connector)
|
||||
|
||||
App->>DTO: 1. Создание данных
|
||||
App->>SDK: 2. send(Request)
|
||||
SDK->>SDK: 3. Маппинг полей (PascalCase)
|
||||
SDK->>SDK: 4. Подпись/Шифрование
|
||||
SDK->>API: 5. HTTPS + mTLS
|
||||
API-->>SDK: 6. JSON Ответ
|
||||
SDK->>SDK: 7. Валидация ошибок
|
||||
SDK->>App: 8. Возврат Response DTO
|
||||
```
|
||||
Note over SBP, API: MTLS + JCS Signature
|
||||
SBP->>API: 1. GetQrCodeRequest(NominalAcc)
|
||||
API-->>SBP: 2. QR Payload (URL)
|
||||
Client->>API: 3. Оплата в приложении (СБП)
|
||||
|
||||
### 2. Безопасность СБП (Body Signing)
|
||||
Для СБП реализована автоматическая каноникализация JSON (JCS) с рекурсивной сортировкой ключей перед подписью RSA-SHA256.
|
||||
|
||||
---
|
||||
|
||||
## Настройка и Безопасность
|
||||
|
||||
Альфа-Банк требует **два набора ключей**:
|
||||
1. **Транспортные (mTLS):** Для установки защищенного соединения.
|
||||
2. **Прикладные (Signing):** Для цифровой подписи реестров и платежей.
|
||||
|
||||
### Быстрый старт (Laravel)
|
||||
|
||||
1. Опубликуйте конфиг:
|
||||
```bash
|
||||
php artisan vendor:publish --tag=alfa-bank-config
|
||||
```
|
||||
|
||||
2. Настройте `.env`:
|
||||
```env
|
||||
ALFA_BAAS_CERT_PATH=/path/to/transport.crt
|
||||
ALFA_BAAS_KEY_PATH=/path/to/transport.key
|
||||
ALFA_BAAS_CLIENT_ID=your_id
|
||||
ALFA_BAAS_CLIENT_SECRET=your_secret
|
||||
```
|
||||
|
||||
3. Проверьте соединение:
|
||||
```bash
|
||||
php artisan alfa:check
|
||||
Note over API, BaaS: Webhook with Signature
|
||||
API->>BaaS: 4. Webhook (Входящий платеж)
|
||||
|
||||
Note over BaaS, API: OAuth2 + CMS Signature
|
||||
BaaS->>API: 5. IdentifyTransactionRequest(beneficiaryId)
|
||||
API-->>BaaS: 6. 200 OK (Зачислено)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Примеры использования
|
||||
|
||||
### 1. Авторизация и получение счетов
|
||||
```php
|
||||
use Apoloz\AlfaBank\Laravel\Facades\AlfaBank;
|
||||
use Apoloz\AlfaBank\Requests\Accounts\GetAccountsRequest;
|
||||
|
||||
// SDK сам получит токен и применит его
|
||||
$accounts = AlfaBank::send(new GetAccountsRequest());
|
||||
|
||||
foreach ($accounts as $account) {
|
||||
echo $account->number . ": " . $account->openDate;
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Стандартный платеж (BaaS)
|
||||
```php
|
||||
use Apoloz\AlfaBank\Requests\Payments\CreatePaymentRequest;
|
||||
use Apoloz\AlfaBank\Data\Payments\PaymentData;
|
||||
|
||||
$data = new PaymentData(
|
||||
amount: 1500.00,
|
||||
date: date('Y-m-d'),
|
||||
externalId: 'INV-2026-001',
|
||||
operationCode: '01',
|
||||
payeeAccount: '40702...',
|
||||
payeeBankBic: '044525593',
|
||||
payeeName: 'ООО Партнер',
|
||||
payerAccount: '40702...',
|
||||
payerBankBic: '044525593',
|
||||
payerBankCorrAccount: '30101...',
|
||||
payerInn: '7700000000',
|
||||
payerName: 'Моя Компания',
|
||||
priority: '5',
|
||||
purpose: 'Оплата по счету №1'
|
||||
);
|
||||
|
||||
$response = AlfaBank::send(new CreatePaymentRequest($data));
|
||||
echo "Платеж создан: " . $response->id;
|
||||
```
|
||||
|
||||
### 3. СБП: Генерация QR-кода
|
||||
### 1. СБП: Прием платежа на номинальный счет
|
||||
```php
|
||||
use Apoloz\AlfaBank\Laravel\Facades\Sbp;
|
||||
use Apoloz\AlfaBank\Sbp\Requests\GetQrCodeRequest;
|
||||
use Apoloz\AlfaBank\Sbp\Data\QrCodeRequestData;
|
||||
|
||||
$payload = new QrCodeRequestData(
|
||||
termNo: '90080567',
|
||||
amount: '10000', // 100.00 руб
|
||||
paymentPurpose: 'Заказ №5'
|
||||
);
|
||||
|
||||
$response = Sbp::send(new GetQrCodeRequest($payload));
|
||||
echo "Отсканируйте код: " . $response->payload;
|
||||
```
|
||||
|
||||
### 4. Работа с выписками (Пагинация)
|
||||
```php
|
||||
use Apoloz\AlfaBank\Requests\Statement\GetTransactionsRequest;
|
||||
|
||||
// Автоматическая итерация через все страницы
|
||||
$paginator = AlfaBank::paginate(new GetTransactionsRequest(
|
||||
accountNumber: '40702...',
|
||||
executeDateFrom: '2026-01-01',
|
||||
executeDateTo: '2026-01-18'
|
||||
$response = Sbp::send(new GetQrCodeRequest(
|
||||
new QrCodeRequestData(
|
||||
termNo: '90080567',
|
||||
amount: '10000', // 100.00 RUB
|
||||
paymentPurpose: 'Пополнение кошелька #123'
|
||||
)
|
||||
));
|
||||
|
||||
foreach ($paginator->items() as $transaction) {
|
||||
echo "Транзакция {" . $transaction->uuid . ": " . $transaction->amount['amount'] . " RUB\n";
|
||||
}
|
||||
echo "QR URL: " . $response->dto()->payload;
|
||||
```
|
||||
|
||||
### 5. Самозанятые (Справочники и выплаты)
|
||||
### 2. Идентификация платежа (BaaS)
|
||||
Когда платеж пришел на номинальный счет, его нужно привязать к бенефициару:
|
||||
|
||||
```php
|
||||
use Apoloz\AlfaBank\Requests\SelfEmployed\GetActivitiesRequest;
|
||||
use Apoloz\AlfaBank\Requests\NominalAccounts\Identification\IdentifyTransactionRequest;
|
||||
use Apoloz\AlfaBank\Data\NominalAccounts\Identification\IdentifyRequestData;
|
||||
use Apoloz\AlfaBank\Data\NominalAccounts\Identification\AmountDistributionData;
|
||||
|
||||
// Получение списка разрешенных видов деятельности
|
||||
$activities = AlfaBank::send(new GetActivitiesRequest());
|
||||
$data = new IdentifyRequestData(
|
||||
transactionId: '1220112MOCO#DS4001415',
|
||||
accountNumber: '40702810...',
|
||||
amountDistribution: AmountDistributionData::collect([
|
||||
['beneficiaryId' => 'BEN-001', 'amount' => '100.00']
|
||||
], DataCollection::class),
|
||||
digestSignatures: ... // CMS подпись
|
||||
);
|
||||
|
||||
foreach ($activities as $activity) {
|
||||
echo "{$activity->code}: {$activity->name}\n";
|
||||
}
|
||||
AlfaBank::send(new IdentifyTransactionRequest($data));
|
||||
```
|
||||
|
||||
### 6. Номинальные счета (Полный цикл)
|
||||
Сценарий создания бенефициара и выплаты с подписью:
|
||||
|
||||
### 3. Работа с номинальными счетами (Бенефициары)
|
||||
```php
|
||||
use Apoloz\AlfaBank\Requests\NominalAccounts\Beneficiaries\CreateBeneficiaryRequest;
|
||||
use Apoloz\AlfaBank\Requests\NominalAccounts\Payouts\CreatePayoffRequest;
|
||||
|
||||
// 1. Создание бенефициара с CMS подписью
|
||||
$response = $baas->send(new CreateBeneficiaryRequest($beneficiaryData));
|
||||
// Регистрация нового бенефициара (Физлицо/Юрлицо)
|
||||
$response = AlfaBank::send(new CreateBeneficiaryRequest($beneficiaryData));
|
||||
$id = $response->dto()->requestId;
|
||||
|
||||
// 2. Инициирование выплаты
|
||||
$payoff = $baas->send(new CreatePayoffRequest($payoffData));
|
||||
echo "Статус выплаты: " . $payoff->dto()->status;
|
||||
// Запуск скоринга (верификации)
|
||||
AlfaBank::send(new ScoreBeneficiaryRequest($id));
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Продвинутые возможности
|
||||
|
||||
### Диагностика без Laravel
|
||||
### Автоматическая пагинация
|
||||
```php
|
||||
use Apoloz\AlfaBank\AlfaBank;
|
||||
$paginator = AlfaBank::paginate(new GetTransactionsRequest(...));
|
||||
|
||||
$ok = AlfaBank::check(
|
||||
certificatePath: 'cert.pem',
|
||||
privateKeyPath: 'key.pem',
|
||||
clientId: '...',
|
||||
clientSecret: '...'
|
||||
);
|
||||
```
|
||||
|
||||
### Логирование с маскировкой данных
|
||||
SDK автоматически скрывает номера карт, токены и подписи в логах.
|
||||
```php
|
||||
$connector = AlfaBank::getFacadeRoot();
|
||||
$connector->withLogging(Log::channel('daily')->getLogger());
|
||||
```
|
||||
|
||||
### Обработка Webhooks (Laravel)
|
||||
```php
|
||||
// routes/api.php
|
||||
Route::alfaWebhooks('/webhooks/alfa');
|
||||
|
||||
// Listener
|
||||
public function handle(AlfaWebhookReceived $event) {
|
||||
$data = $event->webhook->data;
|
||||
// $data будет объектом TransactionWebhookData или SbpPaymentWebhookData
|
||||
foreach ($paginator->items() as $transaction) {
|
||||
// Каждая итерация автоматически подгружает следующую страницу при необходимости
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
### Webhook Handling (Laravel)
|
||||
```php
|
||||
// Регистрация роута
|
||||
Route::alfaWebhooks('/api/alfa/webhooks');
|
||||
|
||||
// Обработка в Listener
|
||||
public function handle(AlfaWebhookReceived $event) {
|
||||
if ($event->webhook->object === 'ul_transaction_default') {
|
||||
$tx = $event->webhook->data; // TransactionWebhookData
|
||||
Log::info("Пришел платеж на сумму: " . $tx->amount['amount']);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Лицензия
|
||||
|
||||
MIT. Автор: Anatoliy Poloz.
|
||||
MIT. Автор: Anatoliy Poloz.
|
||||
|
||||
Reference in New Issue
Block a user