fix(formating)
This commit is contained in:
@@ -18,20 +18,20 @@ $baas = AlfaBank::baas(
|
||||
|
||||
try {
|
||||
echo "Authenticating...\n";
|
||||
|
||||
|
||||
// AUTHENTICATION:
|
||||
// client_id: From Developer Portal (App Settings)
|
||||
// client_secret: From Developer Portal (App Settings -> Key Icon) OR generated via SDK (examples/14_generate_client_secret.php)
|
||||
|
||||
|
||||
// METHOD A: Standard Client Credentials (for simple services)
|
||||
// $baas->login(
|
||||
// clientId: 'your-client-id-uuid',
|
||||
// clientSecret: 'your-client-secret-string'
|
||||
// );
|
||||
|
||||
|
||||
// METHOD B: Authorization Code Flow (H2H) (REQUIRED for Nominal Accounts)
|
||||
// See examples/13_h2h_auth_service.php for the full setup
|
||||
|
||||
|
||||
// We re-initialize with auth credentials if we didn't pass them initially
|
||||
$baas = AlfaBank::baas(
|
||||
certificatePath: __DIR__ . '/certs/client.cer',
|
||||
@@ -41,7 +41,7 @@ try {
|
||||
clientSecret: 'your-client-secret',
|
||||
redirectUri: 'https://...'
|
||||
);
|
||||
|
||||
|
||||
// Now you can use OAuth methods:
|
||||
// $url = $baas->getAuthorizationUrl();
|
||||
// or
|
||||
@@ -51,17 +51,16 @@ try {
|
||||
|
||||
// 2. Create a Beneficiary (Counterparty)
|
||||
echo "Creating Beneficiary...\n";
|
||||
|
||||
|
||||
// In a real app, use the DTOs
|
||||
// $payload = new CreateBeneficiaryRequestData(...);
|
||||
// $baas->send(new CreateBeneficiaryRequest($payload));
|
||||
|
||||
|
||||
echo "Beneficiary Request Sent (Mock).\n";
|
||||
|
||||
} catch (\Exception $e) {
|
||||
echo "Error: " . $e->getMessage() . "\n";
|
||||
echo 'Error: ' . $e->getMessage() . "\n";
|
||||
if ($e instanceof \Apoloz\AlfaBank\Exceptions\AlfaBankException) {
|
||||
echo "API Code: " . $e->getErrorCode() . "\n";
|
||||
echo 'API Code: ' . $e->getErrorCode() . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@ require_once __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
use Apoloz\AlfaBank\AlfaBank;
|
||||
use Apoloz\AlfaBank\Enums\Environment;
|
||||
use Apoloz\AlfaBank\Sbp\Requests\GetQrCodeRequest;
|
||||
use Apoloz\AlfaBank\Sbp\Data\QrCodeRequestData;
|
||||
use Apoloz\AlfaBank\Sbp\Requests\GetQrCodeRequest;
|
||||
|
||||
// 1. Initialize SBP
|
||||
$sbp = AlfaBank::sbp(
|
||||
@@ -30,8 +30,8 @@ try {
|
||||
|
||||
if ($response->successful()) {
|
||||
$qrData = $response->dto();
|
||||
echo "QR Payload: " . $qrData->payload . "\n";
|
||||
echo "QR Image URL: " . $qrData->image . "\n";
|
||||
echo 'QR Payload: ' . $qrData->payload . "\n";
|
||||
echo 'QR Image URL: ' . $qrData->image . "\n";
|
||||
} else {
|
||||
echo "Failed to generate QR.\n";
|
||||
}
|
||||
@@ -41,5 +41,5 @@ try {
|
||||
// foreach($paginator as $item) { ... }
|
||||
|
||||
} catch (\Exception $e) {
|
||||
echo "Error: " . $e->getMessage() . "\n";
|
||||
echo 'Error: ' . $e->getMessage() . "\n";
|
||||
}
|
||||
|
||||
@@ -7,44 +7,43 @@ use Apoloz\AlfaBank\Enums\Environment;
|
||||
|
||||
/**
|
||||
* This example shows how to initialize the SDK with the Sandbox files provided by the bank.
|
||||
*
|
||||
*
|
||||
* IMPORTANT: You must first convert the .pfx file to .pem format using OpenSSL:
|
||||
*
|
||||
* 1. Extract signing key:
|
||||
*
|
||||
* 1. Extract signing key:
|
||||
* openssl pkcs12 -in certificate_for_requests_sign_with_password_1234.pfx -nocerts -out signing_key.pem -nodes -password pass:1234
|
||||
*
|
||||
*
|
||||
* 2. Extract signing certificate:
|
||||
* openssl pkcs12 -in certificate_for_requests_sign_with_password_1234.pfx -clcerts -nokeys -out signing_cert.pem -password pass:1234
|
||||
*
|
||||
*
|
||||
* 3. Ensure transport certs are in PEM format if they aren't already.
|
||||
*/
|
||||
|
||||
// --- 1. BaaS / Main API Initialization ---
|
||||
$baas = AlfaBank::baas(
|
||||
// Transport (mTLS) - use the sandbox_cert/key files
|
||||
certificatePath: __DIR__ . '/certs/sandbox_cert_2026.cer',
|
||||
certificatePath: __DIR__ . '/certs/sandbox_cert_2026.cer',
|
||||
privateKeyPath: __DIR__ . '/certs/sandbox_key_2026.key',
|
||||
|
||||
|
||||
// Signing (Business Logic) - use the extracted PEM files from PFX
|
||||
signingCertificatePath: __DIR__ . '/certs/signing_cert.pem',
|
||||
signingPrivateKeyPath: __DIR__ . '/certs/signing_key.pem',
|
||||
|
||||
|
||||
environment: Environment::SANDBOX,
|
||||
caBundlePath: __DIR__ . '/certs/apica_2022_chain.cer' // Trust chain
|
||||
);
|
||||
|
||||
echo "BaaS Connector Initialized.\n";
|
||||
|
||||
|
||||
// --- 2. SBP (Faster Payments) Initialization ---
|
||||
$sbp = AlfaBank::sbp(
|
||||
// SBP usually uses its own mTLS pair found in the sbp_payout/mtls folder
|
||||
certificatePath: __DIR__ . '/certs/sbp_payout/mtls/9728109955_test_mtls.crt',
|
||||
privateKeyPath: __DIR__ . '/certs/sbp_payout/mtls/9728109955_test_mtls.key',
|
||||
|
||||
|
||||
// Terminal ID from terminal_num.txt
|
||||
keyNameAlias: '9728109955',
|
||||
|
||||
keyNameAlias: '9728109955',
|
||||
|
||||
environment: Environment::SANDBOX,
|
||||
caBundlePath: __DIR__ . '/certs/sbp_payout/sandbox_root/root-ca-test.crt'
|
||||
);
|
||||
@@ -52,4 +51,3 @@ $sbp = AlfaBank::sbp(
|
||||
echo "SBP Connector Initialized.\n";
|
||||
|
||||
// Now you can use $baas->login(...) or $sbp->send(...)
|
||||
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
require_once __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
use Apoloz\AlfaBank\AlfaBank;
|
||||
use Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries\AddressData;
|
||||
use Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries\CreateBeneficiaryRequestData;
|
||||
use Apoloz\AlfaBank\Enums\Environment;
|
||||
use Apoloz\AlfaBank\Requests\NominalAccounts\Beneficiaries\CreateBeneficiaryRequest;
|
||||
use Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries\CreateBeneficiaryRequestData;
|
||||
use Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries\AddressData;
|
||||
use Spatie\LaravelData\DataCollection;
|
||||
|
||||
// 1. Initialize
|
||||
@@ -29,7 +29,7 @@ $payload = new CreateBeneficiaryRequestData(
|
||||
countryOfTaxResidence: 'RU',
|
||||
name: 'Ivanov Ivan',
|
||||
addresses: new DataCollection(AddressData::class, [
|
||||
new AddressData('REGISTRATION_ADDRESS', 'Moscow', 'RU')
|
||||
new AddressData('REGISTRATION_ADDRESS', 'Moscow', 'RU'),
|
||||
])
|
||||
// Note: digestSignatures is now optional!
|
||||
);
|
||||
@@ -40,12 +40,12 @@ $payload->sign($baas->getSigner());
|
||||
// 5. Send
|
||||
$response = $baas->send(new CreateBeneficiaryRequest($payload));
|
||||
|
||||
echo "Status: " . $response->status() . "\n";
|
||||
echo "ID: " . $response->dto()->id . "\n";
|
||||
echo 'Status: ' . $response->status() . "\n";
|
||||
echo 'ID: ' . $response->dto()->id . "\n";
|
||||
|
||||
if ($response->successful()) {
|
||||
$data = $response->dto(); // BeneficiaryResponseData
|
||||
echo "Beneficiary creation accepted. ID: {$data->id}, Status: {$data->status}\n";
|
||||
} else {
|
||||
echo "Error: " . $response->body() . "\n";
|
||||
echo 'Error: ' . $response->body() . "\n";
|
||||
}
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
require_once __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
use Apoloz\AlfaBank\AlfaBank;
|
||||
use Apoloz\AlfaBank\Webhooks\WebhookFactory;
|
||||
use Apoloz\AlfaBank\Requests\Webhooks\GetWebhooksRequest;
|
||||
use Apoloz\AlfaBank\Requests\Webhooks\CreateWebhookRequest;
|
||||
use Apoloz\AlfaBank\Data\Webhooks\Subscriptions\WebhookSubscriptionRequestData;
|
||||
use Apoloz\AlfaBank\Requests\Webhooks\CreateWebhookRequest;
|
||||
use Apoloz\AlfaBank\Requests\Webhooks\GetWebhooksRequest;
|
||||
use Apoloz\AlfaBank\Webhooks\WebhookFactory;
|
||||
|
||||
/**
|
||||
* 1. Managing Webhooks (BaaS API)
|
||||
@@ -15,7 +15,7 @@ $baas = AlfaBank::baas('cert.pem', 'key.pem');
|
||||
$baas->login('id', 'secret');
|
||||
|
||||
// List existing webhooks
|
||||
$response = $baas->send(new GetWebhooksRequest());
|
||||
$response = $baas->send(new GetWebhooksRequest);
|
||||
$webhooks = $response->dto(); // DataCollection of WebhookSubscriptionData
|
||||
|
||||
foreach ($webhooks as $webhook) {
|
||||
@@ -38,9 +38,9 @@ $rawPayload = [
|
||||
'transactionId' => 'TX-12345',
|
||||
'amount' => ['amount' => 100.50, 'currencyName' => 'RUR'],
|
||||
'direction' => 'CREDIT',
|
||||
'paymentPurpose' => 'Test payment'
|
||||
]
|
||||
]
|
||||
'paymentPurpose' => 'Test payment',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
// Use the factory to parse the payload into a DTO
|
||||
|
||||
@@ -3,16 +3,15 @@
|
||||
require_once __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
use Apoloz\AlfaBank\AlfaBank;
|
||||
use Apoloz\AlfaBank\Requests\B2C\CreateB2CPaymentRequest;
|
||||
use Apoloz\AlfaBank\Data\B2C\B2CPaymentRequestData;
|
||||
use Apoloz\AlfaBank\Data\B2C\B2CClientData;
|
||||
use Apoloz\AlfaBank\Data\B2C\B2CPaymentRecipientData;
|
||||
use Apoloz\AlfaBank\Data\B2C\B2CPaymentRequestData;
|
||||
use Apoloz\AlfaBank\Requests\B2C\CreateB2CPaymentRequest;
|
||||
use Spatie\LaravelData\DataCollection;
|
||||
|
||||
/**
|
||||
* Example: B2C Payout via SBP (Phone Number).
|
||||
*/
|
||||
|
||||
$baas = AlfaBank::baas(
|
||||
certificatePath: 'path/to/cert.pem',
|
||||
privateKeyPath: 'path/to/key.pem'
|
||||
@@ -29,8 +28,8 @@ $payload = new B2CPaymentRequestData(
|
||||
'phone' => '79001112233',
|
||||
'amount' => 100.00,
|
||||
'nspkBankId' => '100000000001',
|
||||
'sequence' => 'unique-payout-id-1'
|
||||
]
|
||||
'sequence' => 'unique-payout-id-1',
|
||||
],
|
||||
], DataCollection::class)
|
||||
);
|
||||
|
||||
@@ -41,6 +40,5 @@ if ($response->successful()) {
|
||||
$data = $response->dto(); // B2CPaymentResponseData
|
||||
echo "Payout request sent. Status: {$data->status}\n";
|
||||
} else {
|
||||
echo "Error: " . $response->body() . "\n";
|
||||
echo 'Error: ' . $response->body() . "\n";
|
||||
}
|
||||
|
||||
|
||||
@@ -3,18 +3,17 @@
|
||||
require_once __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
use Apoloz\AlfaBank\AlfaBank;
|
||||
use Apoloz\AlfaBank\Utils\CmsSigner;
|
||||
use Apoloz\AlfaBank\Requests\Registries\CreateRegistryRequest;
|
||||
use Apoloz\AlfaBank\Data\Registries\RegistryRequestData;
|
||||
use Apoloz\AlfaBank\Data\Registries\RegistryPaymentData;
|
||||
use Apoloz\AlfaBank\Requests\Registries\SignRegistryRequest;
|
||||
use Apoloz\AlfaBank\Data\Registries\RegistryRequestData;
|
||||
use Apoloz\AlfaBank\Data\Registries\RegistrySignatureData;
|
||||
use Apoloz\AlfaBank\Requests\Registries\CreateRegistryRequest;
|
||||
use Apoloz\AlfaBank\Requests\Registries\SignRegistryRequest;
|
||||
use Apoloz\AlfaBank\Utils\CmsSigner;
|
||||
use Spatie\LaravelData\DataCollection;
|
||||
|
||||
/**
|
||||
* Example: Creating and Signing a Payment Registry (Batch Payments).
|
||||
*/
|
||||
|
||||
$baas = AlfaBank::baas(
|
||||
certificatePath: 'path/to/cert.pem',
|
||||
privateKeyPath: 'path/to/key.pem'
|
||||
@@ -31,8 +30,8 @@ $payload = new RegistryRequestData(
|
||||
'payeeInn' => '770...',
|
||||
'payeeName' => 'Vendor 1',
|
||||
'payerAccount' => '40702...',
|
||||
'purpose' => 'Payment for goods'
|
||||
]
|
||||
'purpose' => 'Payment for goods',
|
||||
],
|
||||
], DataCollection::class)
|
||||
);
|
||||
|
||||
@@ -43,7 +42,7 @@ $registryId = $response->dto()->id;
|
||||
echo "Registry Created: $registryId\n";
|
||||
|
||||
// 2. Sign Registry
|
||||
// In real life, you might need to sign the digest provided by the bank
|
||||
// In real life, you might need to sign the digest provided by the bank
|
||||
// or the registry content itself. This depends on the specific bank requirement.
|
||||
$signature = CmsSigner::sign(
|
||||
$registryId, // Example data
|
||||
@@ -55,11 +54,10 @@ $signatures = RegistrySignatureData::collect([
|
||||
[
|
||||
'base64Encoded' => $signature,
|
||||
'signatureType' => 'RSA',
|
||||
'certificateUuid' => 'YOUR_CERT_UUID'
|
||||
]
|
||||
'certificateUuid' => 'YOUR_CERT_UUID',
|
||||
],
|
||||
], DataCollection::class);
|
||||
|
||||
$baas->send(new SignRegistryRequest($registryId, $signatures));
|
||||
|
||||
echo "Registry Signed.\n";
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ use Apoloz\AlfaBank\Data\NominalAccounts\Payouts\RecipientData;
|
||||
use Apoloz\AlfaBank\Requests\NominalAccounts\Beneficiaries\CreateBeneficiaryRequest;
|
||||
use Apoloz\AlfaBank\Requests\NominalAccounts\Beneficiaries\ScoreBeneficiaryRequest;
|
||||
use Apoloz\AlfaBank\Requests\NominalAccounts\Payouts\CreatePayoffRequest;
|
||||
use Apoloz\AlfaBank\Utils\CmsSigner;
|
||||
use Spatie\LaravelData\DataCollection;
|
||||
|
||||
/**
|
||||
@@ -23,7 +22,7 @@ use Spatie\LaravelData\DataCollection;
|
||||
*/
|
||||
|
||||
// 1. Инициализация SDK
|
||||
// Сертификаты (Transport Certs):
|
||||
// Сертификаты (Transport Certs):
|
||||
// Получены от банка (Sandbox) или сгенерированы вами и активированы банком (Production).
|
||||
$baas = AlfaBank::baas(
|
||||
certificatePath: 'transport.crt',
|
||||
@@ -50,27 +49,26 @@ try {
|
||||
countryOfTaxResidence: 'RU',
|
||||
name: 'Иванов Иван',
|
||||
addresses: AddressData::collect([
|
||||
new AddressData('REGISTRATION_ADDRESS', 'Moscow', 'RU')
|
||||
new AddressData('REGISTRATION_ADDRESS', 'Moscow', 'RU'),
|
||||
])
|
||||
);
|
||||
|
||||
|
||||
// Автоматическая подпись
|
||||
$benData->sign($baas->getSigner());
|
||||
|
||||
|
||||
$response = $baas->send(new CreateBeneficiaryRequest($benData));
|
||||
$beneficiaryId = $response->dto()->id;
|
||||
echo "Beneficiary Created: $beneficiaryId\n";
|
||||
|
||||
// --- ЭТАП 2: Идентификация Входящего Платежа ---
|
||||
// После создания банк должен проверить бенефициара
|
||||
echo "2. Запуск верификации (скоринга)...";
|
||||
echo '2. Запуск верификации (скоринга)...';
|
||||
$baas->send(new ScoreBeneficiaryRequest($beneficiaryId));
|
||||
echo "Скоринг инициирован.\n";
|
||||
|
||||
|
||||
// --- ЭТАП 3: Выплата (Payoff) ---
|
||||
// Когда бенефициар проверен, можно делать выплату
|
||||
echo "3. Создание выплаты...";
|
||||
echo '3. Создание выплаты...';
|
||||
|
||||
$payoffData = new PayoffRequestData(
|
||||
type: 'PAYMENT_ORDER',
|
||||
@@ -89,14 +87,14 @@ try {
|
||||
digestSignatures: DigestSignatureData::collect([
|
||||
[
|
||||
'base64Encoded' => '...', // Здесь должна быть подпись тела выплаты
|
||||
'signatureType' => 'cms'
|
||||
]
|
||||
'signatureType' => 'cms',
|
||||
],
|
||||
], DataCollection::class)
|
||||
);
|
||||
|
||||
$payoffResponse = $baas->send(new CreatePayoffRequest($payoffData));
|
||||
echo "Выплата создана. ID: " . $payoffResponse->dto()->payoffId . "\n";
|
||||
echo 'Выплата создана. ID: ' . $payoffResponse->dto()->payoffId . "\n";
|
||||
|
||||
} catch (\Exception $e) {
|
||||
echo "Ошибка: " . $e->getMessage() . "\n";
|
||||
echo 'Ошибка: ' . $e->getMessage() . "\n";
|
||||
}
|
||||
|
||||
@@ -5,15 +5,14 @@ declare(strict_types=1);
|
||||
require_once __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
use Apoloz\AlfaBank\AlfaBank;
|
||||
use Apoloz\AlfaBank\Data\SelfEmployed\CreateIncomeRequestData;
|
||||
use Apoloz\AlfaBank\Enums\Environment;
|
||||
use Apoloz\AlfaBank\Requests\SelfEmployed\RegisterIncomeRequest;
|
||||
use Apoloz\AlfaBank\Data\SelfEmployed\CreateIncomeRequestData;
|
||||
|
||||
/**
|
||||
* Пример регистрации дохода самозанятого.
|
||||
* Позволяет автоматически задекларировать доход в ФНС от лица самозанятого.
|
||||
*/
|
||||
|
||||
$baas = AlfaBank::baas(
|
||||
certificatePath: __DIR__ . '/../tests/test_cert.pem',
|
||||
privateKeyPath: __DIR__ . '/../tests/test_key.pem',
|
||||
@@ -37,6 +36,5 @@ try {
|
||||
echo "ID запроса: {$dto->requestId}\n";
|
||||
echo "Текущий статус: {$dto->status}\n";
|
||||
} catch (\Exception $e) {
|
||||
echo "Ошибка: " . $e->getMessage() . "\n";
|
||||
echo 'Ошибка: ' . $e->getMessage() . "\n";
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ use Apoloz\AlfaBank\Sbp\Requests\Reversal\GetQrcReversalHistoryRequest;
|
||||
* Пример получения истории возвратов по транзакции СБП.
|
||||
* Полезно для отладки частичных возвратов или поиска зависших операций.
|
||||
*/
|
||||
|
||||
$sbp = AlfaBank::sbp(
|
||||
certificatePath: __DIR__ . '/../tests/test_cert.pem',
|
||||
privateKeyPath: __DIR__ . '/../tests/test_key.pem',
|
||||
@@ -27,7 +26,7 @@ try {
|
||||
$response = $sbp->send(new GetQrcReversalHistoryRequest($payrrn, $termNo));
|
||||
$dto = $response->dto();
|
||||
|
||||
echo "Найдено возвратов: " . ($dto->refunds ? $dto->refunds->count() : 0) . "\n";
|
||||
echo 'Найдено возвратов: ' . ($dto->refunds ? $dto->refunds->count() : 0) . "\n";
|
||||
|
||||
if ($dto->refunds) {
|
||||
foreach ($dto->refunds as $refund) {
|
||||
@@ -38,6 +37,5 @@ try {
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
echo "Ошибка: " . $e->getMessage() . "\n";
|
||||
echo 'Ошибка: ' . $e->getMessage() . "\n";
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@ use Apoloz\AlfaBank\Requests\Files\UploadFileRequest;
|
||||
* Сначала создается бенефициар, банк возвращает ссылку для загрузки паспорта.
|
||||
* Затем SDK загружает файл по этой ссылке.
|
||||
*/
|
||||
|
||||
$baas = AlfaBank::baas(
|
||||
certificatePath: __DIR__ . '/../tests/test_cert.pem',
|
||||
privateKeyPath: __DIR__ . '/../tests/test_key.pem',
|
||||
@@ -34,13 +33,12 @@ try {
|
||||
if ($response->status() === 200) {
|
||||
echo "Файл успешно загружен в банк!\n";
|
||||
} else {
|
||||
echo "Ошибка загрузки: " . $response->body() . "\n";
|
||||
echo 'Ошибка загрузки: ' . $response->body() . "\n";
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
echo "Ошибка: " . $e->getMessage() . "\n";
|
||||
echo 'Ошибка: ' . $e->getMessage() . "\n";
|
||||
} finally {
|
||||
if (is_resource($fileResource)) {
|
||||
fclose($fileResource);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ use Apoloz\AlfaBank\Requests\NominalAccounts\Beneficiaries\GetBeneficiariesReque
|
||||
|
||||
/**
|
||||
* Authorization Code Flow (H2H) Example
|
||||
*
|
||||
*
|
||||
* Сценарий: Обмен полученного в браузере кода на токены и дальнейшая работа через refresh_token.
|
||||
*/
|
||||
|
||||
@@ -21,20 +21,20 @@ $config = [
|
||||
// Sandbox: Bank sent you these via email/portal.
|
||||
'cert' => __DIR__ . '/certs/client.cer',
|
||||
'key' => __DIR__ . '/certs/private.key',
|
||||
|
||||
|
||||
// APP CREDENTIALS (OAUTH2):
|
||||
// From: Developer Portal -> Your App -> Settings/Keys
|
||||
// Note: If you don't have client_secret, generate it using `14_generate_client_secret.php`
|
||||
'client_id' => getenv('ALFA_BAAS_CLIENT_ID'),
|
||||
'client_secret' => getenv('ALFA_BAAS_CLIENT_SECRET'),
|
||||
|
||||
|
||||
// REDIRECT URI:
|
||||
// Must match exactly what you entered in Developer Portal for this App.
|
||||
'redirect_uri' => 'https://your-app.com/callback',
|
||||
|
||||
'redirect_uri' => 'https://your-app.com/callback',
|
||||
|
||||
// BUSINESS DATA:
|
||||
// From your Contract or Internet Bank. Not related to Auth directly.
|
||||
'account_number' => '40702810...'
|
||||
'account_number' => '40702810...',
|
||||
];
|
||||
|
||||
// 2. Инициализация коннектора
|
||||
@@ -48,46 +48,45 @@ $baas = AlfaBank::baas(
|
||||
try {
|
||||
// --- СЦЕНАРИЙ А: Первый вход (у нас есть только код из браузера) ---
|
||||
// Ссылка для получения кода: https://baas.alfabank.ru/oidc/authorize?response_type=code&client_id=...
|
||||
|
||||
|
||||
$authCode = 'code_from_browser_url'; // <-- Вставьте сюда код
|
||||
|
||||
|
||||
if ($authCode) {
|
||||
echo "Обмениваем код на токены...\n";
|
||||
$tokenData = $baas->authWithCode($authCode, $config['redirect_uri']);
|
||||
|
||||
|
||||
echo "Access Token получен!\n";
|
||||
echo "Refresh Token: " . $tokenData->refresh_token . "\n";
|
||||
echo 'Refresh Token: ' . $tokenData->refresh_token . "\n";
|
||||
echo "(Сохраните refresh_token в базу данных)\n\n";
|
||||
}
|
||||
|
||||
// --- СЦЕНАРИЙ Б: Повторный вход (у нас есть сохраненный refresh_token) ---
|
||||
$savedRefreshToken = 'your_saved_refresh_token_from_db';
|
||||
|
||||
|
||||
if ($savedRefreshToken) {
|
||||
echo "Обновляем сессию по Refresh Token...\n";
|
||||
$tokenData = $baas->refreshToken($savedRefreshToken);
|
||||
|
||||
echo "Сессия обновлена. Новый Access Token действует " . $tokenData->expires_in . " сек.\n";
|
||||
|
||||
echo 'Сессия обновлена. Новый Access Token действует ' . $tokenData->expires_in . " сек.\n";
|
||||
if ($tokenData->refresh_token) {
|
||||
echo "Пришел новый Refresh Token (сохраните его): " . $tokenData->refresh_token . "\n";
|
||||
echo 'Пришел новый Refresh Token (сохраните его): ' . $tokenData->refresh_token . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Выполняем защищенный запрос (например, список бенефициаров)
|
||||
// Коннектор уже авторизован (внутри updateAccessToken/authWithCode вызывается authenticate())
|
||||
|
||||
|
||||
echo "Запрашиваем список...\n";
|
||||
$response = $baas->send(new GetBeneficiariesRequest(
|
||||
accountNumber: $config['account_number'],
|
||||
type: 'FL_RESIDENT'
|
||||
));
|
||||
|
||||
echo "Успешно! Найдено: " . count($response->dto()->beneficiaries) . "\n";
|
||||
echo 'Успешно! Найдено: ' . count($response->dto()->beneficiaries) . "\n";
|
||||
|
||||
} catch (\Exception $e) {
|
||||
echo "Ошибка: " . $e->getMessage() . "\n";
|
||||
echo 'Ошибка: ' . $e->getMessage() . "\n";
|
||||
if (method_exists($e, 'getResponse')) {
|
||||
echo "Body: " . $e->getResponse()->body() . "\n";
|
||||
echo 'Body: ' . $e->getResponse()->body() . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@ $baas = AlfaBank::baas(
|
||||
$link = $baas->getAuthorizationUrl(scopes: ['beneficiaries', 'payment']);
|
||||
echo "1. Перейдите по ссылке для авторизации:\n$link\n\n";
|
||||
|
||||
|
||||
// --- СЦЕНАРИЙ 2: Обмен кода на токен (в callback-скрипте) ---
|
||||
// $code приходит в GET-параметре: /callback?code=...
|
||||
$codeFromUrl = '...код из браузера...';
|
||||
@@ -42,18 +41,18 @@ $codeFromUrl = '...код из браузера...';
|
||||
if ($codeFromUrl !== '...код из браузера...') {
|
||||
try {
|
||||
echo "2. Обмен кода на токены...\n";
|
||||
|
||||
|
||||
// Saloon делает всё сам:
|
||||
$authenticator = $baas->getAccessToken($codeFromUrl);
|
||||
|
||||
echo "Access Token: " . substr($authenticator->getAccessToken(), 0, 20) . "...\n";
|
||||
echo "Refresh Token: " . $authenticator->getRefreshToken() . "\n";
|
||||
echo "Expires At: " . $authenticator->getExpiresAt()->format('Y-m-d H:i:s') . "\n";
|
||||
|
||||
|
||||
echo 'Access Token: ' . substr($authenticator->getAccessToken(), 0, 20) . "...\n";
|
||||
echo 'Refresh Token: ' . $authenticator->getRefreshToken() . "\n";
|
||||
echo 'Expires At: ' . $authenticator->getExpiresAt()->format('Y-m-d H:i:s') . "\n";
|
||||
|
||||
// TODO: Сохраните refresh_token в базу данных!
|
||||
|
||||
|
||||
} catch (\Exception $e) {
|
||||
echo "Ошибка обмена кода: " . $e->getMessage() . "\n";
|
||||
echo 'Ошибка обмена кода: ' . $e->getMessage() . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,22 +62,21 @@ $savedRefreshToken = '...saved_refresh_token...';
|
||||
if ($savedRefreshToken !== '...saved_refresh_token...') {
|
||||
try {
|
||||
echo "3. Обновление токена...\n";
|
||||
|
||||
|
||||
// Обновляем токен
|
||||
$newAuthenticator = $baas->refreshAccessToken($savedRefreshToken);
|
||||
|
||||
|
||||
// Автоматически применяем к коннектору (для текущего скрипта)
|
||||
$baas->authenticate($newAuthenticator);
|
||||
|
||||
|
||||
echo "Токен обновлен!\n";
|
||||
|
||||
|
||||
// Если пришел новый refresh_token — обновляем его
|
||||
if ($newAuthenticator->getRefreshToken()) {
|
||||
// DB::update(...)
|
||||
echo "Новый Refresh Token получен.\n";
|
||||
// DB::update(...)
|
||||
echo "Новый Refresh Token получен.\n";
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
echo "Ошибка обновления токена: " . $e->getMessage() . "\n";
|
||||
echo 'Ошибка обновления токена: ' . $e->getMessage() . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,14 +5,14 @@ declare(strict_types=1);
|
||||
require_once __DIR__ . '/vendor/autoload.php';
|
||||
|
||||
use Apoloz\AlfaBank\AlfaBank;
|
||||
use Apoloz\AlfaBank\Requests\Auth\RefreshClientSecretRequest;
|
||||
use Apoloz\AlfaBank\Enums\Environment;
|
||||
use Apoloz\AlfaBank\Requests\Auth\RefreshClientSecretRequest;
|
||||
|
||||
/**
|
||||
* UTILITY SCRIPT: Generate a Client Secret using your TLS certificates.
|
||||
*
|
||||
*
|
||||
* Run this ONCE when setting up the project or if you lose your secret.
|
||||
*
|
||||
*
|
||||
* Requirements:
|
||||
* 1. You have the `client_id` (Found in Developer Portal -> App Settings URL or Overview).
|
||||
* 2. You have the TLS certificates (.pem/.key) authorized by the bank.
|
||||
@@ -22,7 +22,7 @@ use Apoloz\AlfaBank\Enums\Environment;
|
||||
|
||||
// 1. Configuration
|
||||
$certPath = __DIR__ . '/certs/transport.crt'; // Your mTLS certificate
|
||||
$keyPath = __DIR__ . '/certs/transport.key'; // Your mTLS private key
|
||||
$keyPath = __DIR__ . '/certs/transport.key'; // Your mTLS private key
|
||||
$clientId = 'YOUR_CLIENT_ID_UUID'; // E.g. '0cee0683-85ae-...'
|
||||
|
||||
// 2. Initialize Connector (No Login required yet)
|
||||
@@ -41,20 +41,20 @@ try {
|
||||
|
||||
// 4. Output Result
|
||||
$data = $response->dto(); // Returns ClientSecretData
|
||||
|
||||
|
||||
echo "\n-------------------------------------------------------\n";
|
||||
echo "SUCCESS! New Client Secret Generated:\n";
|
||||
echo "-------------------------------------------------------\n";
|
||||
echo "Client ID: " . $data->clientId . "\n";
|
||||
echo "Client Secret: " . $data->clientSecret . "\n";
|
||||
echo 'Client ID: ' . $data->clientId . "\n";
|
||||
echo 'Client Secret: ' . $data->clientSecret . "\n";
|
||||
echo "-------------------------------------------------------\n";
|
||||
echo "IMPORTANT: Save this to your .env file immediately.\n";
|
||||
echo "It will not be shown again.\n";
|
||||
|
||||
} catch (\Exception $e) {
|
||||
echo "\nERROR: Could not generate secret.\n";
|
||||
echo "Message: " . $e->getMessage() . "\n";
|
||||
echo 'Message: ' . $e->getMessage() . "\n";
|
||||
if (method_exists($e, 'getResponse')) {
|
||||
echo "Response: " . $e->getResponse()->body() . "\n";
|
||||
echo 'Response: ' . $e->getResponse()->body() . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,11 +10,11 @@ use Apoloz\AlfaBank\Requests\NominalAccounts\Beneficiaries\GetBeneficiariesReque
|
||||
|
||||
/**
|
||||
* FINAL GOAL EXAMPLE: Get List of Nominal Account Beneficiaries
|
||||
*
|
||||
*
|
||||
* Usage:
|
||||
* 1. Standalone: php examples/15_nominal_accounts_list.php
|
||||
* 2. Laravel Tinker: Copy-paste the code below (replace config with app() helper).
|
||||
*
|
||||
*
|
||||
* This script assumes you have already:
|
||||
* 1. Generated/Received Certificates.
|
||||
* 2. Obtained Client ID & Secret (via Portal or Script 14).
|
||||
@@ -23,15 +23,15 @@ use Apoloz\AlfaBank\Requests\NominalAccounts\Beneficiaries\GetBeneficiariesReque
|
||||
|
||||
// --- CONFIGURATION (From .env) ---
|
||||
$config = [
|
||||
'client_id' => getenv('ALFA_BAAS_CLIENT_ID'),
|
||||
'client_id' => getenv('ALFA_BAAS_CLIENT_ID'),
|
||||
'client_secret' => getenv('ALFA_BAAS_CLIENT_SECRET'),
|
||||
'redirect_uri' => 'https://your-app.com/callback',
|
||||
'cert_path' => __DIR__ . '/certs/client.cer',
|
||||
'key_path' => __DIR__ . '/certs/private.key',
|
||||
|
||||
'redirect_uri' => 'https://your-app.com/callback',
|
||||
'cert_path' => __DIR__ . '/certs/client.cer',
|
||||
'key_path' => __DIR__ . '/certs/private.key',
|
||||
|
||||
// BUSINESS DATA
|
||||
'account_num' => '40702810...', // Nominal Account Number
|
||||
'refresh_token' => 'saved_refresh_token_db' // Your stored token
|
||||
'account_num' => '40702810...', // Nominal Account Number
|
||||
'refresh_token' => 'saved_refresh_token_db', // Your stored token
|
||||
];
|
||||
|
||||
try {
|
||||
@@ -48,7 +48,7 @@ try {
|
||||
// 2. Refresh Token (Get valid Access Token for this session)
|
||||
echo "Refreshing session...\n";
|
||||
$authenticator = $baas->refreshAccessToken($config['refresh_token']);
|
||||
|
||||
|
||||
// Apply authentication to the connector
|
||||
$baas->authenticate($authenticator);
|
||||
|
||||
@@ -60,15 +60,15 @@ try {
|
||||
);
|
||||
|
||||
$response = $baas->send($request);
|
||||
|
||||
|
||||
// 4. Handle Result
|
||||
$list = $response->dto();
|
||||
echo "Found " . count($list->beneficiaries) . " beneficiaries.\n";
|
||||
|
||||
echo 'Found ' . count($list->beneficiaries) . " beneficiaries.\n";
|
||||
|
||||
foreach ($list->beneficiaries as $b) {
|
||||
echo "- {$b->name} (ID: {$b->beneficiaryId})\n";
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
echo "Error: " . $e->getMessage() . "\n";
|
||||
echo 'Error: ' . $e->getMessage() . "\n";
|
||||
}
|
||||
|
||||
@@ -5,18 +5,18 @@ declare(strict_types=1);
|
||||
require_once __DIR__ . '/vendor/autoload.php';
|
||||
|
||||
use Apoloz\AlfaBank\AlfaBank;
|
||||
use Apoloz\AlfaBank\Enums\Environment;
|
||||
use Apoloz\AlfaBank\Requests\Auth\RefreshClientSecretRequest;
|
||||
use Apoloz\AlfaBank\Requests\NominalAccounts\Beneficiaries\GetBeneficiariesRequest;
|
||||
use Apoloz\AlfaBank\Enums\Environment;
|
||||
|
||||
/**
|
||||
* FULLY AUTOMATED WORKFLOW
|
||||
*
|
||||
* Scenario: You don't want to store `client_secret` persistently.
|
||||
*
|
||||
* Scenario: You don't want to store `client_secret` persistently.
|
||||
* Instead, you use your Certificates to fetch a fresh secret on startup (or when needed),
|
||||
* and then immediately use it to refresh your OAuth tokens.
|
||||
*
|
||||
* CAUTION: Requesting a new secret invalidates the old one.
|
||||
*
|
||||
* CAUTION: Requesting a new secret invalidates the old one.
|
||||
* If you have multiple app instances, implement a shared cache (Redis/DB) for the secret!
|
||||
*/
|
||||
|
||||
@@ -25,8 +25,8 @@ use Apoloz\AlfaBank\Enums\Environment;
|
||||
$clientId = getenv('ALFA_BAAS_CLIENT_ID');
|
||||
$redirectUri = 'https://your-app.com/callback';
|
||||
$certPath = __DIR__ . '/certs/client.cer';
|
||||
$keyPath = __DIR__ . '/certs/private.key';
|
||||
$accNum = '40702810...';
|
||||
$keyPath = __DIR__ . '/certs/private.key';
|
||||
$accNum = '40702810...';
|
||||
|
||||
// This assumes you have already passed the browser flow once and saved the refresh token.
|
||||
$savedRefreshToken = 'your_saved_refresh_token_from_db';
|
||||
@@ -38,20 +38,20 @@ try {
|
||||
// 2. FETCH CLIENT SECRET DYNAMICALLY
|
||||
// We prove our identity via mTLS certificates.
|
||||
echo "1. Requesting dynamic client_secret via API...\n";
|
||||
|
||||
|
||||
// In a real app: CHECK CACHE FIRST!
|
||||
// $cachedSecret = Cache::get('alfa_client_secret');
|
||||
// if ($cachedSecret) { $tempSecret = $cachedSecret; } else { ... }
|
||||
|
||||
|
||||
$secretResponse = $baas->send(new RefreshClientSecretRequest($clientId));
|
||||
$tempSecret = $secretResponse->dto()->clientSecret;
|
||||
|
||||
echo " Secret acquired: " . substr($tempSecret, 0, 5) . "...\n";
|
||||
|
||||
echo ' Secret acquired: ' . substr($tempSecret, 0, 5) . "...\n";
|
||||
|
||||
// 3. AUTHENTICATE OAUTH2
|
||||
// Now we use the fresh secret to get an access token.
|
||||
echo "2. Refreshing OAuth2 session...\n";
|
||||
|
||||
|
||||
// Re-initialize connector with the new secret
|
||||
$baasReady = AlfaBank::baas(
|
||||
certificatePath: $certPath,
|
||||
@@ -65,9 +65,9 @@ try {
|
||||
// Refresh token using native method
|
||||
$authenticator = $baasReady->refreshAccessToken($savedRefreshToken);
|
||||
$baasReady->authenticate($authenticator);
|
||||
|
||||
echo " Session active. Access Token expires at " . $authenticator->getExpiresAt()->format('H:i:s') . "\n";
|
||||
|
||||
|
||||
echo ' Session active. Access Token expires at ' . $authenticator->getExpiresAt()->format('H:i:s') . "\n";
|
||||
|
||||
// Update DB if refresh token rotated
|
||||
if ($authenticator->getRefreshToken()) {
|
||||
// saveNewRefreshToken($authenticator->getRefreshToken());
|
||||
@@ -76,14 +76,14 @@ try {
|
||||
|
||||
// 4. BUSINESS LOGIC
|
||||
echo "3. Fetching beneficiaries...\n";
|
||||
|
||||
|
||||
$response = $baasReady->send(new GetBeneficiariesRequest($accNum, 'FL_RESIDENT'));
|
||||
|
||||
echo " Success! Found " . count($response->dto()->beneficiaries) . " records.\n";
|
||||
|
||||
echo ' Success! Found ' . count($response->dto()->beneficiaries) . " records.\n";
|
||||
|
||||
} catch (Exception $e) {
|
||||
echo "CRITICAL ERROR: " . $e->getMessage() . "\n";
|
||||
echo 'CRITICAL ERROR: ' . $e->getMessage() . "\n";
|
||||
if (method_exists($e, 'getResponse')) {
|
||||
echo "Body: " . $e->getResponse()->body() . "\n";
|
||||
echo 'Body: ' . $e->getResponse()->body() . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,21 +2,21 @@
|
||||
|
||||
/**
|
||||
* LARAVEL TINKER WORKFLOW: Scoring -> Creation -> Signing
|
||||
*
|
||||
*
|
||||
* This script is designed to be copy-pasted directly into `php artisan tinker`.
|
||||
* It demonstrates the new simplified DX with automatic signing.
|
||||
*
|
||||
*
|
||||
* Prerequisites:
|
||||
* 1. .env is configured (ALFA_BAAS_CLIENT_ID, ALFA_BAAS_CERT_PATH, etc.)
|
||||
* 2. Run: php artisan tinker
|
||||
*/
|
||||
|
||||
use Apoloz\AlfaBank\Core\AlfaBankConnector;
|
||||
use Apoloz\AlfaBank\Requests\NominalAccounts\Beneficiaries\ScoreBeneficiaryRequest;
|
||||
use Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries\AddressData;
|
||||
use Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries\CreateBeneficiaryRequestData;
|
||||
use Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries\ScoreBeneficiaryRequestData;
|
||||
use Apoloz\AlfaBank\Requests\NominalAccounts\Beneficiaries\CreateBeneficiaryRequest;
|
||||
use Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries\CreateBeneficiaryRequestData;
|
||||
use Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries\AddressData;
|
||||
use Apoloz\AlfaBank\Requests\NominalAccounts\Beneficiaries\ScoreBeneficiaryRequest;
|
||||
|
||||
// 1. Get Configured Connector
|
||||
// Laravel automatically injects config from config/alfa-bank.php
|
||||
@@ -40,17 +40,19 @@ $scoreData = new ScoreBeneficiaryRequestData(
|
||||
try {
|
||||
$scoreResponse = $baas->send(new ScoreBeneficiaryRequest($scoreData));
|
||||
$scoreResult = $scoreResponse->dto(); // ScoreBeneficiaryResponseData
|
||||
|
||||
echo "Scoring Result: " . $scoreResult->result . "\n";
|
||||
echo "Description: " . $scoreResult->description . "\n";
|
||||
|
||||
echo 'Scoring Result: ' . $scoreResult->result . "\n";
|
||||
echo 'Description: ' . $scoreResult->description . "\n";
|
||||
|
||||
if ($scoreResult->result !== 'SUCCESS') {
|
||||
echo "Stopping: Scoring failed.\n";
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
echo "Scoring Error: " . $e->getMessage() . "\n";
|
||||
echo 'Scoring Error: ' . $e->getMessage() . "\n";
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -69,7 +71,7 @@ $createData = new CreateBeneficiaryRequestData(
|
||||
type: 'REGISTRATION_ADDRESS',
|
||||
address: '123456, г. Москва, ул. Тверская, д. 1',
|
||||
country: 'RU'
|
||||
)
|
||||
),
|
||||
])
|
||||
);
|
||||
|
||||
@@ -83,14 +85,13 @@ try {
|
||||
$beneficiary = $createResponse->dto(); // CreateBeneficiaryResponseData
|
||||
|
||||
echo "SUCCESS! Beneficiary Created.\n";
|
||||
echo "ID: " . $beneficiary->id . "\n";
|
||||
echo "Status: " . $beneficiary->status . "\n";
|
||||
echo "Request ID: " . $beneficiary->requestId . "\n";
|
||||
echo 'ID: ' . $beneficiary->id . "\n";
|
||||
echo 'Status: ' . $beneficiary->status . "\n";
|
||||
echo 'Request ID: ' . $beneficiary->requestId . "\n";
|
||||
|
||||
} catch (\Exception $e) {
|
||||
echo "Creation Error: " . $e->getMessage() . "\n";
|
||||
echo 'Creation Error: ' . $e->getMessage() . "\n";
|
||||
if (method_exists($e, 'getResponse')) {
|
||||
echo "Response Body: " . $e->getResponse()->body() . "\n";
|
||||
echo 'Response Body: ' . $e->getResponse()->body() . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,30 +2,30 @@
|
||||
|
||||
/**
|
||||
* LARAVEL TINKER WORKFLOW: Secure Card Registration -> Payout by ID
|
||||
*
|
||||
* Scenario:
|
||||
*
|
||||
* Scenario:
|
||||
* 1. User enters Card Number (PAN).
|
||||
* 2. You encrypt PAN and register it as a "Requisite" in Alfa Bank.
|
||||
* 3. You save only the `requisiteId` in your database.
|
||||
* 4. Later, you pay out to this user using only the ID (Zero PAN storage).
|
||||
*
|
||||
*
|
||||
* Usage: Copy-paste into `php artisan tinker`.
|
||||
*/
|
||||
|
||||
use Apoloz\AlfaBank\Core\AlfaBankConnector;
|
||||
use Apoloz\AlfaBank\Requests\NominalAccounts\Beneficiaries\Requisites\CreateRequisiteRequest;
|
||||
use Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries\Requisites\CreateRequisiteRequestData;
|
||||
use Apoloz\AlfaBank\Requests\NominalAccounts\Payouts\PayoffRequest;
|
||||
use Apoloz\AlfaBank\Data\NominalAccounts\Payouts\PayoffRequestData;
|
||||
use Apoloz\AlfaBank\Data\Common\RecipientData;
|
||||
use Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries\Requisites\CreateRequisiteRequestData;
|
||||
use Apoloz\AlfaBank\Data\NominalAccounts\Payouts\PayoffRequestData;
|
||||
use Apoloz\AlfaBank\Data\NominalAccounts\Payouts\PayoutRequisiteData;
|
||||
use Apoloz\AlfaBank\Requests\NominalAccounts\Beneficiaries\Requisites\CreateRequisiteRequest;
|
||||
use Apoloz\AlfaBank\Requests\NominalAccounts\Payouts\PayoffRequest;
|
||||
use Apoloz\AlfaBank\Services\PhpseclibCardEncryptor;
|
||||
|
||||
// --- CONFIGURATION ---
|
||||
$nominalAccount = '40702810...';
|
||||
$beneficiaryId = 'BEN-123...';
|
||||
$rawPan = '4276000000001234'; // Вводится пользователем (не сохранять в БД!)
|
||||
$cardPubKeyPath = storage_path('certs/alfa_card_enc_key.pub');
|
||||
$beneficiaryId = 'BEN-123...';
|
||||
$rawPan = '4276000000001234'; // Вводится пользователем (не сохранять в БД!)
|
||||
$cardPubKeyPath = storage_path('certs/alfa_card_enc_key.pub');
|
||||
|
||||
// 1. Setup
|
||||
$baas = app(AlfaBankConnector::class);
|
||||
@@ -34,8 +34,8 @@ $baas->login();
|
||||
// ==========================================
|
||||
// STEP 1: SECURE REGISTRATION (Tokenization)
|
||||
// ==========================================
|
||||
echo "--- Step 1: Registering Card Requisite ---
|
||||
";
|
||||
echo '--- Step 1: Registering Card Requisite ---
|
||||
';
|
||||
|
||||
// A. Encrypt PAN for transport
|
||||
$encryptor = new PhpseclibCardEncryptor(file_get_contents($cardPubKeyPath));
|
||||
@@ -55,20 +55,20 @@ try {
|
||||
$reqResponse = $baas->send(new CreateRequisiteRequest($reqData));
|
||||
$requisiteId = $reqResponse->dto()->id; // E.g. "REQ-998877"
|
||||
|
||||
echo "SUCCESS! Card Registered.
|
||||
";
|
||||
echo 'SUCCESS! Card Registered.
|
||||
';
|
||||
echo "Requisite ID: $requisiteId (SAVE THIS TO DATABASE)
|
||||
";
|
||||
echo "Mask: " . substr($rawPan, 0, 6) . "******" . substr($rawPan, -4) . "
|
||||
";
|
||||
echo 'Mask: ' . substr($rawPan, 0, 6) . '******' . substr($rawPan, -4) . '
|
||||
';
|
||||
|
||||
} catch (\Exception $e) {
|
||||
echo "Registration Failed: " . $e->getMessage() . "
|
||||
";
|
||||
echo 'Registration Failed: ' . $e->getMessage() . '
|
||||
';
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// ==========================================
|
||||
// STEP 2: PAYOUT (Using Requisite ID)
|
||||
// ==========================================
|
||||
@@ -82,11 +82,11 @@ $payoutData = new PayoffRequestData(
|
||||
recipient: new RecipientData($beneficiaryId),
|
||||
amount: '100.00',
|
||||
purpose: 'Выплата вознаграждения',
|
||||
|
||||
|
||||
// Instead of PAN, we provide the Requisite ID
|
||||
payoutRequisite: new PayoutRequisiteData(
|
||||
type: 'CARD',
|
||||
requisiteId: $requisiteId
|
||||
requisiteId: $requisiteId
|
||||
)
|
||||
);
|
||||
|
||||
@@ -96,12 +96,12 @@ try {
|
||||
$payResponse = $baas->send(new PayoffRequest($payoutData));
|
||||
$result = $payResponse->dto();
|
||||
|
||||
echo "Payout Sent!
|
||||
";
|
||||
echo "ID: " . ($result->id ?? 'N/A') . "
|
||||
";
|
||||
echo 'Payout Sent!
|
||||
';
|
||||
echo 'ID: ' . ($result->id ?? 'N/A') . '
|
||||
';
|
||||
|
||||
} catch (\Exception $e) {
|
||||
echo "Payout Failed: " . $e->getMessage() . "
|
||||
";
|
||||
echo 'Payout Failed: ' . $e->getMessage() . '
|
||||
';
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Пример: SBP QR → Номинальный счёт → Идентификация → Бенефициар
|
||||
*
|
||||
*
|
||||
* Сценарий:
|
||||
* 1. Генерируем SBP QR код для пополнения номинального счёта
|
||||
* 2. Клиент оплачивает через QR (переводит деньги на номинальный счёт)
|
||||
@@ -16,17 +16,17 @@ declare(strict_types=1);
|
||||
require_once __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
use Apoloz\AlfaBank\AlfaBank;
|
||||
use Apoloz\AlfaBank\Enums\Environment;
|
||||
use Apoloz\AlfaBank\Sbp\Data\QrCodeRequestData;
|
||||
use Apoloz\AlfaBank\Sbp\Requests\GetQrCodeRequest;
|
||||
use Apoloz\AlfaBank\Core\AlfaConfig;
|
||||
use Apoloz\AlfaBank\Sbp\SbpConnector;
|
||||
use Apoloz\AlfaBank\Data\NominalAccounts\Identification\AmountDistributionData;
|
||||
use Apoloz\AlfaBank\Data\NominalAccounts\Identification\IdentifyRequestData;
|
||||
use Apoloz\AlfaBank\Data\NominalAccounts\Payouts\DigestSignatureData;
|
||||
use Apoloz\AlfaBank\Enums\Environment;
|
||||
use Apoloz\AlfaBank\Requests\NominalAccounts\Identification\GetIdentifyStatusRequest;
|
||||
use Apoloz\AlfaBank\Requests\NominalAccounts\Identification\GetUnidentifiedTransactionsRequest;
|
||||
use Apoloz\AlfaBank\Requests\NominalAccounts\Identification\IdentifyTransactionRequest;
|
||||
use Apoloz\AlfaBank\Requests\NominalAccounts\Identification\GetIdentifyStatusRequest;
|
||||
use Apoloz\AlfaBank\Data\NominalAccounts\Identification\IdentifyRequestData;
|
||||
use Apoloz\AlfaBank\Data\NominalAccounts\Identification\AmountDistributionData;
|
||||
use Apoloz\AlfaBank\Data\NominalAccounts\Payouts\DigestSignatureData;
|
||||
use Apoloz\AlfaBank\Sbp\Data\QrCodeRequestData;
|
||||
use Apoloz\AlfaBank\Sbp\Requests\GetQrCodeRequest;
|
||||
use Apoloz\AlfaBank\Sbp\SbpConnector;
|
||||
use Spatie\LaravelData\DataCollection;
|
||||
|
||||
echo "=== SBP QR → Номинальный счёт → Идентификация ===\n\n";
|
||||
@@ -73,12 +73,12 @@ try {
|
||||
caBundlePath: $sbpCaBundle,
|
||||
signingPrivateKeyPath: $sbpSigningKey // 4096-bit ключ для подписи
|
||||
);
|
||||
|
||||
|
||||
$sbp = new SbpConnector($sbpConfig, $sbpKeyAlias);
|
||||
|
||||
// Создаём динамический QR код с уникальным OrderNumber для идентификации
|
||||
$orderNumber = 'ORDER-' . uniqid();
|
||||
|
||||
|
||||
$qrPayload = new QrCodeRequestData(
|
||||
termNo: $sbpTermNo,
|
||||
qrcType: '02', // Dynamic QR
|
||||
@@ -109,7 +109,7 @@ try {
|
||||
echo "\n💡 Клиент должен отсканировать QR и оплатить {$qrData->payload}\n\n";
|
||||
|
||||
// Сохраняем QR изображение для показа клиенту
|
||||
if (!empty($qrData->image)) {
|
||||
if (! empty($qrData->image)) {
|
||||
$qrImagePath = __DIR__ . '/qr_payment.png';
|
||||
file_put_contents($qrImagePath, base64_decode($qrData->image));
|
||||
echo " 📁 QR изображение сохранено: $qrImagePath\n\n";
|
||||
@@ -148,7 +148,7 @@ try {
|
||||
$unidentifiedResponse = $baas->send($unidentifiedRequest);
|
||||
$unidentifiedCollection = $unidentifiedResponse->dto();
|
||||
|
||||
echo "Найдено неидентифицированных пополнений: " . count($unidentifiedCollection->items) . "\n\n";
|
||||
echo 'Найдено неидентифицированных пополнений: ' . count($unidentifiedCollection->items) . "\n\n";
|
||||
|
||||
if (count($unidentifiedCollection->items) === 0) {
|
||||
echo "⚠️ Нет неидентифицированных пополнений. Возможные причины:\n";
|
||||
@@ -175,7 +175,7 @@ try {
|
||||
}
|
||||
|
||||
if ($targetTransaction === null) {
|
||||
throw new \RuntimeException("Не найдена подходящая транзакция для идентификации");
|
||||
throw new \RuntimeException('Не найдена подходящая транзакция для идентификации');
|
||||
}
|
||||
|
||||
echo "✅ Выбрана транзакция для идентификации: {$targetTransaction->id}\n";
|
||||
@@ -194,7 +194,7 @@ try {
|
||||
new AmountDistributionData(
|
||||
beneficiaryId: $beneficiaryId,
|
||||
amount: $targetTransaction->amount
|
||||
)
|
||||
),
|
||||
], AmountDistributionData::class);
|
||||
|
||||
// Подготавливаем данные для идентификации
|
||||
@@ -207,7 +207,7 @@ try {
|
||||
new DigestSignatureData(
|
||||
base64Encoded: 'base64-encoded-signature-here', // Реальная подпись
|
||||
signatureType: 'rsa'
|
||||
)
|
||||
),
|
||||
], DigestSignatureData::class)
|
||||
);
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Laravel Tinker: SBP QR → Номинальный счёт → Идентификация
|
||||
*
|
||||
*
|
||||
* Использование:
|
||||
* docker compose exec php-fpm php artisan tinker
|
||||
* >>> include 'examples/21_laravel_tinker_sbp_identification.php'
|
||||
@@ -12,16 +12,15 @@ declare(strict_types=1);
|
||||
|
||||
use Apoloz\AlfaBank\Core\AlfaBankConnector;
|
||||
use Apoloz\AlfaBank\Core\AlfaConfig;
|
||||
use Apoloz\AlfaBank\Data\NominalAccounts\Identification\AmountDistributionData;
|
||||
use Apoloz\AlfaBank\Data\NominalAccounts\Identification\IdentifyRequestData;
|
||||
use Apoloz\AlfaBank\Enums\Environment;
|
||||
use Apoloz\AlfaBank\Sbp\SbpConnector;
|
||||
use Apoloz\AlfaBank\Sbp\Data\QrCodeRequestData;
|
||||
use Apoloz\AlfaBank\Sbp\Requests\GetQrCodeRequest;
|
||||
use Apoloz\AlfaBank\Requests\NominalAccounts\Identification\GetIdentifyStatusRequest;
|
||||
use Apoloz\AlfaBank\Requests\NominalAccounts\Identification\GetUnidentifiedTransactionsRequest;
|
||||
use Apoloz\AlfaBank\Requests\NominalAccounts\Identification\IdentifyTransactionRequest;
|
||||
use Apoloz\AlfaBank\Requests\NominalAccounts\Identification\GetIdentifyStatusRequest;
|
||||
use Apoloz\AlfaBank\Data\NominalAccounts\Identification\IdentifyRequestData;
|
||||
use Apoloz\AlfaBank\Data\NominalAccounts\Identification\AmountDistributionData;
|
||||
use Apoloz\AlfaBank\Data\NominalAccounts\Payouts\DigestSignatureData;
|
||||
use Apoloz\AlfaBank\Sbp\Data\QrCodeRequestData;
|
||||
use Apoloz\AlfaBank\Sbp\Requests\GetQrCodeRequest;
|
||||
use Apoloz\AlfaBank\Sbp\SbpConnector;
|
||||
use Spatie\LaravelData\DataCollection;
|
||||
|
||||
echo "=== SBP QR → Номинальный счёт → Идентификация (Tinker) ===\n\n";
|
||||
@@ -35,7 +34,7 @@ $beneficiaryId = 'your-beneficiary-id-here'; // ID бенефициара (по
|
||||
$amount = '15000'; // 150.00 RUB в копейках
|
||||
|
||||
echo "Номинальный счёт: $nominalAccountNumber\n";
|
||||
echo "Сумма: " . number_format($amount / 100, 2) . " RUB\n\n";
|
||||
echo 'Сумма: ' . number_format($amount / 100, 2) . " RUB\n\n";
|
||||
|
||||
// =============================================================================
|
||||
// ШАГ 1: Генерация SBP QR
|
||||
@@ -52,11 +51,11 @@ try {
|
||||
caBundlePath: config('alfa-bank.sbp.ca_bundle'),
|
||||
signingPrivateKeyPath: config('alfa-bank.sbp.signing_private_key_path')
|
||||
);
|
||||
|
||||
|
||||
$sbp = new SbpConnector($sbpConfig, config('alfa-bank.sbp.key_name_alias'));
|
||||
|
||||
$orderNumber = 'ORDER-' . uniqid();
|
||||
|
||||
|
||||
$qrResponse = $sbp->send(new GetQrCodeRequest(
|
||||
new QrCodeRequestData(
|
||||
termNo: config('alfa-bank.sbp.terminal_no'),
|
||||
@@ -71,9 +70,10 @@ try {
|
||||
));
|
||||
|
||||
$qrData = $qrResponse->dto();
|
||||
|
||||
|
||||
if ($qrData->ErrorCode !== 0) {
|
||||
echo "❌ Ошибка генерации QR: {$qrData->message}\n";
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -90,17 +90,18 @@ try {
|
||||
echo "(После оплаты клиентом через SBP)\n\n";
|
||||
|
||||
$baas = app(AlfaBankConnector::class);
|
||||
|
||||
|
||||
// Получаем список
|
||||
$unidentifiedResponse = $baas->send(
|
||||
new GetUnidentifiedTransactionsRequest($nominalAccountNumber, limit: 5)
|
||||
);
|
||||
|
||||
|
||||
$transactions = $unidentifiedResponse->dto()->items;
|
||||
echo "Найдено транзакций: " . count($transactions) . "\n\n";
|
||||
echo 'Найдено транзакций: ' . count($transactions) . "\n\n";
|
||||
|
||||
if (count($transactions) === 0) {
|
||||
echo "⚠️ Нет неидентифицированных пополнений\n";
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -121,11 +122,12 @@ try {
|
||||
// =============================================================================
|
||||
|
||||
echo "=== ШАГ 3: Идентификация платежа ===\n";
|
||||
|
||||
|
||||
if (empty($beneficiaryId) || $beneficiaryId === 'your-beneficiary-id-here') {
|
||||
echo "⚠️ Укажите правильный beneficiaryId!\n";
|
||||
echo " Получите список бенефициаров через:\n";
|
||||
echo " >>> \$baas->send(new GetBeneficiariesRequest())->dto()\n";
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -136,7 +138,7 @@ try {
|
||||
new AmountDistributionData(
|
||||
beneficiaryId: $beneficiaryId,
|
||||
amount: $transaction->amount
|
||||
)
|
||||
),
|
||||
], AmountDistributionData::class)
|
||||
);
|
||||
|
||||
@@ -158,7 +160,7 @@ try {
|
||||
$statusResponse = $baas->send(
|
||||
new GetIdentifyStatusRequest($result->identifyId)
|
||||
);
|
||||
|
||||
|
||||
$status = $statusResponse->dto();
|
||||
echo "Текущий статус: {$status->status}\n\n";
|
||||
|
||||
@@ -171,7 +173,7 @@ try {
|
||||
|
||||
} catch (\Exception $e) {
|
||||
echo "\n❌ Ошибка: {$e->getMessage()}\n";
|
||||
echo "Класс: " . get_class($e) . "\n";
|
||||
echo 'Класс: ' . get_class($e) . "\n";
|
||||
}
|
||||
|
||||
echo "\n=== Готово ===\n";
|
||||
|
||||
@@ -9,9 +9,9 @@ namespace Apoloz\AlfaBank;
|
||||
use Apoloz\AlfaBank\Core\AlfaBankConnector;
|
||||
use Apoloz\AlfaBank\Core\AlfaConfig;
|
||||
use Apoloz\AlfaBank\Enums\Environment;
|
||||
use Apoloz\AlfaBank\Services\OpenSslCmsSigner;
|
||||
use Apoloz\AlfaBank\Sbp\SbpConnector;
|
||||
use Apoloz\AlfaBank\Requests\Accounts\GetAccountsRequest;
|
||||
use Apoloz\AlfaBank\Sbp\SbpConnector;
|
||||
use Apoloz\AlfaBank\Services\OpenSslCmsSigner;
|
||||
|
||||
class AlfaBank
|
||||
{
|
||||
@@ -29,7 +29,8 @@ class AlfaBank
|
||||
): bool {
|
||||
$baas = self::baas($certificatePath, $privateKeyPath, $environment, $caBundlePath);
|
||||
$baas->login($clientId, $clientSecret);
|
||||
$baas->send(new GetAccountsRequest());
|
||||
$baas->send(new GetAccountsRequest);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -76,8 +77,8 @@ class AlfaBank
|
||||
?string $signingCertificatePath = null,
|
||||
?string $signingPrivateKeyPath = null
|
||||
): SbpConnector {
|
||||
$baseUrl = $environment === Environment::PRODUCTION
|
||||
? Environment::SBP_PRODUCTION->value
|
||||
$baseUrl = $environment === Environment::PRODUCTION
|
||||
? Environment::SBP_PRODUCTION->value
|
||||
: Environment::SBP_SANDBOX->value;
|
||||
|
||||
$config = new AlfaConfig(
|
||||
@@ -92,4 +93,4 @@ class AlfaBank
|
||||
return new SbpConnector($config, $keyNameAlias);
|
||||
}
|
||||
// </SECTION>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ namespace Apoloz\AlfaBank\Core;
|
||||
// <SECTION name="module_imports" intent="Import necessary contracts, services, and base framework components for the connector's operation.">
|
||||
// <BELIEF_STATE "Saloon's plugin architecture requires importing traits for features like retries and timeouts. Local contracts (SignerInterface) are imported for dependency injection.">
|
||||
use Apoloz\AlfaBank\Contracts\SignerInterface;
|
||||
use Apoloz\AlfaBank\Enums\Environment;
|
||||
use Apoloz\AlfaBank\Http\Middleware\RequestIdMiddleware;
|
||||
use Apoloz\AlfaBank\Http\Pagination\AlfaOffsetPaginator;
|
||||
use Apoloz\AlfaBank\Traits\HasAlfaErrorHandling;
|
||||
@@ -15,19 +16,18 @@ use Saloon\Http\Connector;
|
||||
use Saloon\Http\Request;
|
||||
use Saloon\PaginationPlugin\Contracts\HasPagination;
|
||||
use Saloon\PaginationPlugin\OffsetPaginator;
|
||||
use Saloon\Traits\Plugins\AlwaysThrowOnErrors;
|
||||
use Saloon\Traits\RequestProperties\HasTries;
|
||||
use Saloon\Traits\Plugins\HasTimeout;
|
||||
use Saloon\Traits\OAuth2\AuthorizationCodeGrant;
|
||||
use Apoloz\AlfaBank\Enums\Environment;
|
||||
use Saloon\Traits\Plugins\AlwaysThrowOnErrors;
|
||||
use Saloon\Traits\Plugins\HasTimeout;
|
||||
use Saloon\Traits\RequestProperties\HasTries;
|
||||
|
||||
class AlfaBankConnector extends Connector implements HasPagination
|
||||
{
|
||||
use AlwaysThrowOnErrors;
|
||||
use AuthorizationCodeGrant;
|
||||
use HasAlfaErrorHandling;
|
||||
use HasTimeout;
|
||||
use HasTries;
|
||||
use AlwaysThrowOnErrors;
|
||||
use HasAlfaErrorHandling;
|
||||
use AuthorizationCodeGrant;
|
||||
|
||||
public function __construct(
|
||||
protected AlfaConfig $alfaConfig,
|
||||
@@ -42,6 +42,79 @@ class AlfaBankConnector extends Connector implements HasPagination
|
||||
return $this->alfaConfig->baseUrl;
|
||||
}
|
||||
|
||||
public function boot(\Saloon\Http\PendingRequest $pendingRequest): void
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
public function paginate(Request $request): OffsetPaginator
|
||||
{
|
||||
return new AlfaOffsetPaginator($this, $request);
|
||||
}
|
||||
|
||||
// login() kept for ClientCredentials compatibility (legacy/simple flow)
|
||||
public function login(?string $clientId = null, ?string $clientSecret = null, array $scopes = []): static
|
||||
{
|
||||
$oauthConfig = $this->oauthConfig();
|
||||
|
||||
// Allow overriding credentials via method arguments
|
||||
if ($clientId) {
|
||||
$oauthConfig->setClientId($clientId);
|
||||
}
|
||||
if ($clientSecret) {
|
||||
$oauthConfig->setClientSecret($clientSecret);
|
||||
}
|
||||
|
||||
if (empty($oauthConfig->getClientId()) || empty($oauthConfig->getClientSecret())) {
|
||||
throw new \RuntimeException('Client ID/Secret not configured.');
|
||||
}
|
||||
|
||||
$request = new \Saloon\Http\OAuth2\GetClientCredentialsTokenRequest($oauthConfig, $scopes);
|
||||
|
||||
$response = $this->send($request);
|
||||
|
||||
// Use the trait's helper to parse the token
|
||||
$authenticator = $this->createOAuthAuthenticatorFromResponse($response);
|
||||
|
||||
$this->authenticate($authenticator);
|
||||
|
||||
return $this;
|
||||
}
|
||||
// </SECTION>
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="signer_accessor" intent="Provide access to the configured signing service for requests that require a digital signature.">
|
||||
// <BELIEF_STATE "Requests should not instantiate their own signing logic. The connector acts as a service locator, providing the globally-configured Signer service. This ensures that all signatures are generated consistently.">
|
||||
public function getSigner(): SignerInterface
|
||||
{
|
||||
if (! $this->signer) {
|
||||
throw new \RuntimeException('No signer configured for this connector.');
|
||||
}
|
||||
|
||||
return $this->signer;
|
||||
}
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="logging_mutator" intent="Allow attaching a PSR-3 logger to the connector for debugging.">
|
||||
// <BELIEF_STATE "Logging should be an optional, opt-in feature. This method provides a fluent interface to attach a logging middleware, which will automatically sanitize sensitive data before output.">
|
||||
public function withLogging(\Psr\Log\LoggerInterface $logger): static
|
||||
{
|
||||
$this->middleware()->onRequest(new \Apoloz\AlfaBank\Http\Middleware\LoggingRequestMiddleware($logger));
|
||||
$this->middleware()->onResponse(new \Apoloz\AlfaBank\Http\Middleware\LoggingResponseMiddleware($logger));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable automated JWS response verification and decoding.
|
||||
*/
|
||||
public function withJwsVerification(string $publicKeyPem): static
|
||||
{
|
||||
$this->middleware()->onResponse(new \Apoloz\AlfaBank\Http\Middleware\VerifyJwsResponseMiddleware($publicKeyPem));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function defaultOauthConfig(): OAuthConfig
|
||||
{
|
||||
$idUrl = $this->alfaConfig->baseUrl === Environment::PRODUCTION->value
|
||||
@@ -83,80 +156,8 @@ class AlfaBankConnector extends Connector implements HasPagination
|
||||
protected function defaultMiddleware(): array
|
||||
{
|
||||
return [
|
||||
new RequestIdMiddleware(),
|
||||
new RequestIdMiddleware,
|
||||
];
|
||||
}
|
||||
|
||||
public function boot(\Saloon\Http\PendingRequest $pendingRequest): void
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
public function paginate(Request $request): OffsetPaginator
|
||||
{
|
||||
return new AlfaOffsetPaginator($this, $request);
|
||||
}
|
||||
|
||||
// login() kept for ClientCredentials compatibility (legacy/simple flow)
|
||||
public function login(?string $clientId = null, ?string $clientSecret = null, array $scopes = []): static
|
||||
{
|
||||
$oauthConfig = $this->oauthConfig();
|
||||
|
||||
// Allow overriding credentials via method arguments
|
||||
if ($clientId) {
|
||||
$oauthConfig->setClientId($clientId);
|
||||
}
|
||||
if ($clientSecret) {
|
||||
$oauthConfig->setClientSecret($clientSecret);
|
||||
}
|
||||
|
||||
if (empty($oauthConfig->getClientId()) || empty($oauthConfig->getClientSecret())) {
|
||||
throw new \RuntimeException("Client ID/Secret not configured.");
|
||||
}
|
||||
|
||||
$request = new \Saloon\Http\OAuth2\GetClientCredentialsTokenRequest($oauthConfig, $scopes);
|
||||
|
||||
$response = $this->send($request);
|
||||
|
||||
// Use the trait's helper to parse the token
|
||||
$authenticator = $this->createOAuthAuthenticatorFromResponse($response);
|
||||
|
||||
$this->authenticate($authenticator);
|
||||
|
||||
return $this;
|
||||
}
|
||||
// </SECTION>
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="signer_accessor" intent="Provide access to the configured signing service for requests that require a digital signature.">
|
||||
// <BELIEF_STATE "Requests should not instantiate their own signing logic. The connector acts as a service locator, providing the globally-configured Signer service. This ensures that all signatures are generated consistently.">
|
||||
public function getSigner(): SignerInterface
|
||||
{
|
||||
if (!$this->signer) {
|
||||
throw new \RuntimeException("No signer configured for this connector.");
|
||||
}
|
||||
return $this->signer;
|
||||
}
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="logging_mutator" intent="Allow attaching a PSR-3 logger to the connector for debugging.">
|
||||
// <BELIEF_STATE "Logging should be an optional, opt-in feature. This method provides a fluent interface to attach a logging middleware, which will automatically sanitize sensitive data before output.">
|
||||
public function withLogging(\Psr\Log\LoggerInterface $logger): static
|
||||
{
|
||||
$this->middleware()->onRequest(new \Apoloz\AlfaBank\Http\Middleware\LoggingRequestMiddleware($logger));
|
||||
$this->middleware()->onResponse(new \Apoloz\AlfaBank\Http\Middleware\LoggingResponseMiddleware($logger));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable automated JWS response verification and decoding.
|
||||
*/
|
||||
public function withJwsVerification(string $publicKeyPem): static
|
||||
{
|
||||
$this->middleware()->onResponse(new \Apoloz\AlfaBank\Http\Middleware\VerifyJwsResponseMiddleware($publicKeyPem));
|
||||
|
||||
return $this;
|
||||
}
|
||||
// </SECTION>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,17 +41,17 @@ readonly class AlfaConfig
|
||||
public ?string $signingPrivateKeyPath = null,
|
||||
) {
|
||||
// <BELIEF_STATE "This runtime check ensures that the provided certificate and key paths are not just valid strings, but point to actual, accessible files on the filesystem. This prevents configuration errors that would otherwise only surface during an HTTP request.">
|
||||
if (!file_exists($this->certificatePath)) {
|
||||
if (! file_exists($this->certificatePath)) {
|
||||
throw new \InvalidArgumentException("Certificate not found: {$this->certificatePath}");
|
||||
}
|
||||
if (!file_exists($this->privateKeyPath)) {
|
||||
if (! file_exists($this->privateKeyPath)) {
|
||||
throw new \InvalidArgumentException("Private key not found: {$this->privateKeyPath}");
|
||||
}
|
||||
if ($this->signingCertificatePath && !file_exists($this->signingCertificatePath)) {
|
||||
throw new \InvalidArgumentException("Signing certificate not found: {$this->signingCertificatePath}");
|
||||
if ($this->signingCertificatePath && ! file_exists($this->signingCertificatePath)) {
|
||||
throw new \InvalidArgumentException("Signing certificate not found: {$this->signingCertificatePath}");
|
||||
}
|
||||
if ($this->signingPrivateKeyPath && !file_exists($this->signingPrivateKeyPath)) {
|
||||
throw new \InvalidArgumentException("Signing private key not found: {$this->signingPrivateKeyPath}");
|
||||
if ($this->signingPrivateKeyPath && ! file_exists($this->signingPrivateKeyPath)) {
|
||||
throw new \InvalidArgumentException("Signing private key not found: {$this->signingPrivateKeyPath}");
|
||||
}
|
||||
}
|
||||
// </SECTION>
|
||||
|
||||
@@ -13,6 +13,6 @@ class AccountData extends Data
|
||||
public string $openDate,
|
||||
public string $type,
|
||||
public ?string $mnemonic = null,
|
||||
public ?array $balance = null,
|
||||
public ?array $balance = null,
|
||||
) {}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\Auth;
|
||||
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
|
||||
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for OAuth 2.0 token responses.">
|
||||
|
||||
@@ -17,6 +17,7 @@ use Apoloz\AlfaBank\Data\PaginationData;
|
||||
use Spatie\LaravelData\Attributes\DataCollectionOf;
|
||||
use Spatie\LaravelData\Data;
|
||||
use Spatie\LaravelData\DataCollection;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for a collection of client consents.">
|
||||
|
||||
@@ -14,9 +14,10 @@ namespace Apoloz\AlfaBank\Data\Auth\UserInfo;
|
||||
// <SECTION name="module_imports" intent="Import necessary DTOs and Spatie Laravel Data components.">
|
||||
// <BELIEF_STATE "This DTO represents a single consent entry. The `PaginationData` import here is likely due to prior usage or template, but not directly used within this single DTO.">
|
||||
use Apoloz\AlfaBank\Data\PaginationData; // This import is likely extraneous for a single DTO, but kept for context consistency.
|
||||
use Spatie\LaravelData\Attributes\DataCollectionOf; // This is also likely extraneous for a single DTO.
|
||||
// This is also likely extraneous for a single DTO.
|
||||
use Spatie\LaravelData\Data;
|
||||
use Spatie\LaravelData\DataCollection; // This is also likely extraneous for a single DTO.
|
||||
|
||||
// This is also likely extraneous for a single DTO.
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for a single client consent.">
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\Auth\UserInfo;
|
||||
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
|
||||
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for OpenID Connect UserInfo claims.">
|
||||
|
||||
@@ -4,9 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Apoloz\AlfaBank\Data\B2C;
|
||||
|
||||
use Spatie\LaravelData\Attributes\DataCollectionOf;
|
||||
use Spatie\LaravelData\Data;
|
||||
use Spatie\LaravelData\DataCollection;
|
||||
|
||||
class B2CPaymentResponseData extends Data
|
||||
{
|
||||
|
||||
@@ -14,4 +14,4 @@ class CertificateData extends Data
|
||||
public string $status,
|
||||
public ?string $thumbprint = null,
|
||||
) {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace Apoloz\AlfaBank\Data\FileExchange;
|
||||
use Spatie\LaravelData\Attributes\DataCollectionOf;
|
||||
use Spatie\LaravelData\Data;
|
||||
use Spatie\LaravelData\DataCollection;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for file download response data.">
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\FileExchange;
|
||||
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
|
||||
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for file link details.">
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace Apoloz\AlfaBank\Data\FileExchange;
|
||||
use Spatie\LaravelData\Attributes\DataCollectionOf;
|
||||
use Spatie\LaravelData\Data;
|
||||
use Spatie\LaravelData\DataCollection;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for file upload response data.">
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries;
|
||||
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
|
||||
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for address details.">
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries;
|
||||
use Spatie\LaravelData\Attributes\DataCollectionOf;
|
||||
use Spatie\LaravelData\Data;
|
||||
use Spatie\LaravelData\DataCollection;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for a beneficiary's balance details.">
|
||||
|
||||
@@ -17,6 +17,7 @@ use Apoloz\AlfaBank\Data\PaginationData;
|
||||
use Spatie\LaravelData\Attributes\DataCollectionOf;
|
||||
use Spatie\LaravelData\Data;
|
||||
use Spatie\LaravelData\DataCollection;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define the paginated collection for beneficiary transactions.">
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries;
|
||||
// <SECTION name="module_imports" intent="Import the base Spatie\LaravelData class.">
|
||||
// <BELIEF_STATE "This class extends `Spatie\LaravelData\Data` to leverage its robust data mapping and type safety, ensuring consistent and predictable handling of individual transaction payloads.">
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define the beneficiary transaction data structure.">
|
||||
|
||||
@@ -20,6 +20,7 @@ use Spatie\LaravelData\Attributes\Validation\Email;
|
||||
use Spatie\LaravelData\Attributes\Validation\Numeric;
|
||||
use Spatie\LaravelData\Data;
|
||||
use Spatie\LaravelData\DataCollection;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for creating a new beneficiary.">
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries;
|
||||
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
|
||||
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for the response of creating a beneficiary.">
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries;
|
||||
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
|
||||
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for an identification document.">
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries;
|
||||
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
|
||||
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for personal identification details.">
|
||||
|
||||
@@ -18,6 +18,7 @@ use Apoloz\AlfaBank\Traits\SignableData;
|
||||
use Spatie\LaravelData\Attributes\DataCollectionOf;
|
||||
use Spatie\LaravelData\Data;
|
||||
use Spatie\LaravelData\DataCollection;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for creating a new requisite.">
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries\Requisites;
|
||||
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
|
||||
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for a single payment requisite.">
|
||||
|
||||
@@ -16,9 +16,9 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries\Requisites;
|
||||
use Apoloz\AlfaBank\Data\NominalAccounts\Payouts\DigestSignatureData;
|
||||
use Apoloz\AlfaBank\Traits\SignableData;
|
||||
use Spatie\LaravelData\Attributes\DataCollectionOf;
|
||||
use Spatie\LaravelData\Attributes\Validation\Numeric;
|
||||
use Spatie\LaravelData\Data;
|
||||
use Spatie\LaravelData\DataCollection;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for updating an existing requisite.">
|
||||
|
||||
@@ -20,6 +20,7 @@ use Spatie\LaravelData\Attributes\Validation\Email;
|
||||
use Spatie\LaravelData\Attributes\Validation\Numeric;
|
||||
use Spatie\LaravelData\Data;
|
||||
use Spatie\LaravelData\DataCollection;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for updating an existing beneficiary.">
|
||||
@@ -39,3 +40,23 @@ class UpdateBeneficiaryRequestData extends Data
|
||||
public ?DataCollection $addresses = null,
|
||||
public ?string $accountNumber = null,
|
||||
public ?bool $taxResidentUS = null,
|
||||
public ?bool $foreignTaxResident = null,
|
||||
public ?bool $financialActivities = null,
|
||||
public ?string $name = null,
|
||||
public ?string $registrationDate = null,
|
||||
#[Numeric]
|
||||
public ?string $inn = null,
|
||||
#[Numeric]
|
||||
public ?string $kpp = null,
|
||||
#[Numeric]
|
||||
public ?string $ogrn = null,
|
||||
public ?PersonalInformationData $personalInformation = null,
|
||||
public ?string $phoneNumber = null,
|
||||
#[Email]
|
||||
public ?string $email = null,
|
||||
#[DataCollectionOf(DocumentData::class)]
|
||||
public ?DataCollection $documents = null,
|
||||
) {}
|
||||
// </SECTION>
|
||||
}
|
||||
// </SECTION>
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries;
|
||||
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
|
||||
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for a specific wallet's balance.">
|
||||
|
||||
@@ -17,6 +17,7 @@ use Apoloz\AlfaBank\Data\PaginationData;
|
||||
use Spatie\LaravelData\Attributes\DataCollectionOf;
|
||||
use Spatie\LaravelData\Data;
|
||||
use Spatie\LaravelData\DataCollection;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for a collection of beneficiaries.">
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts;
|
||||
use Apoloz\AlfaBank\Data\PaginationData; // This import might be misleading for a single DTO, but kept for context consistency.
|
||||
use Spatie\LaravelData\Attributes\DataCollectionOf;
|
||||
use Spatie\LaravelData\Data;
|
||||
use Spatie\LaravelData\DataCollection;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for a single beneficiary's details.">
|
||||
@@ -45,4 +45,4 @@ class BeneficiaryData extends Data
|
||||
public ?bool $isVpr = null,
|
||||
) {}
|
||||
// </SECTION>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts;
|
||||
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
|
||||
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for the status of a counterparty request.">
|
||||
|
||||
@@ -17,6 +17,7 @@ use Apoloz\AlfaBank\Data\PaginationData;
|
||||
use Spatie\LaravelData\Attributes\DataCollectionOf;
|
||||
use Spatie\LaravelData\Data;
|
||||
use Spatie\LaravelData\DataCollection;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for a collection of deals.">
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\Deals;
|
||||
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
|
||||
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for a single deal's details.">
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\Deals;
|
||||
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
|
||||
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for a payoff associated with a deal.">
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\Deals;
|
||||
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
|
||||
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for the status of a deal request.">
|
||||
|
||||
@@ -18,6 +18,7 @@ use Apoloz\AlfaBank\Traits\SignableData;
|
||||
use Spatie\LaravelData\Attributes\DataCollectionOf;
|
||||
use Spatie\LaravelData\Data;
|
||||
use Spatie\LaravelData\DataCollection;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for performing an action on a deal contractor.">
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\Deals\Steps;
|
||||
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
|
||||
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for an amount allocated to a contractor's wallet.">
|
||||
|
||||
@@ -18,6 +18,7 @@ use Apoloz\AlfaBank\Traits\SignableData;
|
||||
use Spatie\LaravelData\Attributes\DataCollectionOf;
|
||||
use Spatie\LaravelData\Data;
|
||||
use Spatie\LaravelData\DataCollection;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for performing an action on a deal step.">
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\Deals\Steps;
|
||||
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
|
||||
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for the response of a step action request.">
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\Deals\Steps;
|
||||
use Spatie\LaravelData\Attributes\DataCollectionOf;
|
||||
use Spatie\LaravelData\Data;
|
||||
use Spatie\LaravelData\DataCollection;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for a contractor in a deal step.">
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\Deals\Steps;
|
||||
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
|
||||
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for a single deal step.">
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\Deals;
|
||||
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
|
||||
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for the response of a deal validation.">
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\Identification;
|
||||
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
|
||||
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for distributing amounts to beneficiaries.">
|
||||
|
||||
@@ -18,6 +18,7 @@ use Apoloz\AlfaBank\Traits\SignableData;
|
||||
use Spatie\LaravelData\Attributes\DataCollectionOf;
|
||||
use Spatie\LaravelData\Data;
|
||||
use Spatie\LaravelData\DataCollection;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for identifying a transaction.">
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\Identification;
|
||||
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
|
||||
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for the response of an identification request.">
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\Identification;
|
||||
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
|
||||
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for payer details.">
|
||||
|
||||
@@ -18,6 +18,7 @@ use Apoloz\AlfaBank\Traits\SignableData;
|
||||
use Spatie\LaravelData\Attributes\DataCollectionOf;
|
||||
use Spatie\LaravelData\Data;
|
||||
use Spatie\LaravelData\DataCollection;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for refunding an unidentified transaction.">
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\Identification;
|
||||
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
|
||||
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for the response of a refund request.">
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\Identification;
|
||||
use Spatie\LaravelData\Attributes\DataCollectionOf;
|
||||
use Spatie\LaravelData\Data;
|
||||
use Spatie\LaravelData\DataCollection;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for a collection of unidentified transactions.">
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\Identification;
|
||||
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
|
||||
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for an unidentified transaction.">
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts;
|
||||
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
|
||||
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for a nominal account.">
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\Payouts;
|
||||
use Apoloz\AlfaBank\Data\Shared\PayerInfoData;
|
||||
use Apoloz\AlfaBank\Data\Shared\RecipientInfoData;
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for detailed payoff records.">
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\Payouts;
|
||||
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
|
||||
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for cryptographic digest signatures.">
|
||||
|
||||
@@ -21,6 +21,7 @@ use Spatie\LaravelData\Attributes\DataCollectionOf;
|
||||
use Spatie\LaravelData\Attributes\Validation\Numeric;
|
||||
use Spatie\LaravelData\Data;
|
||||
use Spatie\LaravelData\DataCollection;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for creating a new payoff request.">
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\Payouts;
|
||||
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
|
||||
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for the response of a payoff request.">
|
||||
@@ -28,4 +29,4 @@ class PayoffResponseData extends Data
|
||||
public ?string $description = null,
|
||||
) {}
|
||||
// </SECTION>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\Payouts;
|
||||
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
|
||||
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for payout requisite details.">
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\Payouts;
|
||||
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
|
||||
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for recipient details.">
|
||||
|
||||
@@ -14,10 +14,10 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\Payouts;
|
||||
// <SECTION name="module_imports" intent="Import necessary classes for cryptographic signatures, data collection, and Laravel Data.">
|
||||
// <BELIEF_STATE "These imports are essential for constructing a secure and structured tax refund request. `DigestSignatureData` ensures the integrity and authenticity of the request, `DataCollectionOf` and `DataCollection` facilitate handling multiple signatures, and `Data` provides the foundational capabilities for data object mapping and validation.">
|
||||
use Apoloz\AlfaBank\Traits\SignableData;
|
||||
use Apoloz\AlfaBank\Data\NominalAccounts\Payouts\DigestSignatureData;
|
||||
use Spatie\LaravelData\Attributes\DataCollectionOf;
|
||||
use Spatie\LaravelData\Data;
|
||||
use Spatie\LaravelData\DataCollection;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define the tax refund request data structure.">
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\Payouts;
|
||||
// <SECTION name="module_imports" intent="Import the base Spatie\LaravelData class.">
|
||||
// <BELIEF_STATE "This class extends `Spatie\LaravelData\Data` to leverage its robust data mapping and type safety, ensuring consistent and predictable handling of tax refund response payloads.">
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define the tax refund response data structure.">
|
||||
|
||||
@@ -16,9 +16,9 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\UniversalRecipients;
|
||||
use Apoloz\AlfaBank\Data\NominalAccounts\Payouts\DigestSignatureData;
|
||||
use Apoloz\AlfaBank\Traits\SignableData;
|
||||
use Spatie\LaravelData\Attributes\DataCollectionOf;
|
||||
use Spatie\LaravelData\Attributes\Validation\Numeric;
|
||||
use Spatie\LaravelData\Data;
|
||||
use Spatie\LaravelData\DataCollection;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for creating a universal recipient.">
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\UniversalRecipients;
|
||||
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
|
||||
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for a single universal recipient's details.">
|
||||
|
||||
@@ -14,7 +14,8 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\UniversalRecipients;
|
||||
// <SECTION name="module_imports" intent="Import the base response DTO.">
|
||||
// <BELIEF_STATE "This DTO reuses `CreateBeneficiaryResponseData` as its base, indicating that the response structure for creating universal recipients is identical to that for beneficiaries. This promotes consistency and reduces code duplication.">
|
||||
use Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries\CreateBeneficiaryResponseData;
|
||||
use Spatie\LaravelData\Data; // Included for clarity, though inherited from base DTO.
|
||||
|
||||
// Included for clarity, though inherited from base DTO.
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for the response of creating a universal recipient.">
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data;
|
||||
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
|
||||
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for pagination metadata.">
|
||||
|
||||
@@ -17,59 +17,59 @@ class PaymentData extends Data
|
||||
public function __construct(
|
||||
#[MapOutputName('Amount')]
|
||||
public float $amount,
|
||||
|
||||
|
||||
#[MapOutputName('DocDate')]
|
||||
public string $date,
|
||||
|
||||
|
||||
#[MapOutputName('DocNo')]
|
||||
public string $externalId,
|
||||
|
||||
|
||||
#[MapOutputName('OperationCode')]
|
||||
public string $operationCode,
|
||||
|
||||
|
||||
#[MapOutputName('PayeeAccount')]
|
||||
public string $payeeAccount,
|
||||
|
||||
|
||||
#[MapOutputName('PayeeBankBic'), Numeric, Size(9)]
|
||||
public string $payeeBankBic,
|
||||
|
||||
|
||||
#[MapOutputName('PayeeName')]
|
||||
public string $payeeName,
|
||||
|
||||
|
||||
#[MapOutputName('PayerAccount')]
|
||||
public string $payerAccount,
|
||||
|
||||
|
||||
#[MapOutputName('PayerBankBic'), Numeric, Size(9)]
|
||||
public string $payerBankBic,
|
||||
|
||||
|
||||
#[MapOutputName('PayerBankCorrAccount')]
|
||||
public string $payerBankCorrAccount,
|
||||
|
||||
|
||||
#[MapOutputName('PayerInn'), Numeric]
|
||||
public string $payerInn,
|
||||
|
||||
|
||||
#[MapOutputName('PayerName')]
|
||||
public string $payerName,
|
||||
|
||||
|
||||
#[MapOutputName('Priority')]
|
||||
public string $priority,
|
||||
|
||||
|
||||
#[MapOutputName('Purpose')]
|
||||
public string $purpose,
|
||||
|
||||
|
||||
#[MapOutputName('Number')]
|
||||
public ?string $number = null,
|
||||
|
||||
|
||||
#[MapOutputName('PayeeKpp')]
|
||||
public ?string $payeeKpp = null,
|
||||
|
||||
|
||||
#[MapOutputName('PayeeBankCorrAccount')]
|
||||
public ?string $payeeBankCorrAccount = null,
|
||||
|
||||
|
||||
#[MapOutputName('PaymentType')]
|
||||
public ?string $paymentType = null,
|
||||
|
||||
|
||||
#[MapOutputName('DigestSignatures'), DataCollectionOf(DigestSignatureData::class)]
|
||||
public ?DataCollection $digestSignatures = null,
|
||||
) {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ use Apoloz\AlfaBank\Traits\SignableData;
|
||||
use Spatie\LaravelData\Attributes\DataCollectionOf;
|
||||
use Spatie\LaravelData\Data;
|
||||
use Spatie\LaravelData\DataCollection;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for creating a sandbox RUB payment.">
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace Apoloz\AlfaBank\Data\Shared;
|
||||
use Spatie\LaravelData\Attributes\Validation\Numeric;
|
||||
use Spatie\LaravelData\Attributes\Validation\Size;
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for payer information.">
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\Statement;
|
||||
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
|
||||
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for monetary amount data.">
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\Statement;
|
||||
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
|
||||
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for Russian Ruble transfer details.">
|
||||
|
||||
@@ -17,6 +17,7 @@ use Apoloz\AlfaBank\Data\PaginationData;
|
||||
use Spatie\LaravelData\Attributes\DataCollectionOf;
|
||||
use Spatie\LaravelData\Data;
|
||||
use Spatie\LaravelData\DataCollection;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for a collection of account transactions.">
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\Statement;
|
||||
// <SECTION name="module_imports" intent="Import necessary DTOs and Spatie Laravel Data components.">
|
||||
// <BELIEF_STATE "This DTO includes nested `AmountData` for monetary values and `RurTransferData` for detailed transfer information.">
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a DTO for a single account transaction.">
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
namespace Apoloz\AlfaBank\Data;
|
||||
|
||||
use Spatie\LaravelData\Data;
|
||||
use Spatie\LaravelData\Attributes\DataCollectionOf;
|
||||
use Spatie\LaravelData\Data;
|
||||
use Spatie\LaravelData\DataCollection;
|
||||
|
||||
class WebhookCollectionData extends Data
|
||||
|
||||
@@ -20,4 +20,4 @@ class BaasWebhookData extends BaseWebhookData
|
||||
organizationId: $organizationId
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,4 +14,4 @@ class BaseWebhookData extends Data
|
||||
public ?string $eventTime = null,
|
||||
public ?string $organizationId = null,
|
||||
) {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,4 +20,4 @@ class SbpWebhookData extends BaseWebhookData
|
||||
organizationId: $organizationId
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Exceptions;
|
||||
// <SECTION name="module_imports" intent="Import the base Saloon Response class.">
|
||||
// <BELIEF_STATE "The custom exception needs to hold the original Saloon `Response` object to give developers full access to the raw HTTP response for debugging purposes.">
|
||||
use Saloon\Http\Response;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define a custom exception that extends PHP's base Exception class.">
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
// MODULE_CONTRACT: Provides a Saloon middleware to standardize error handling for Alfa Bank API responses.
|
||||
// RESPONSIBILITY: To intercept API responses, identify various error formats (BaaS, SBP, or generic HTTP), and throw a consistent `AlfaBankException`, thereby centralizing error reporting and simplifying error management in the SDK.
|
||||
@@ -13,6 +14,7 @@ namespace Apoloz\AlfaBank\Http\Middleware;
|
||||
// <BELIEF_STATE "These imports are crucial for the middleware's functionality. `AlfaBankException` provides a standardized way to signal API errors within the SDK, while `Response` from Saloon is the object that the middleware processes.">
|
||||
use Apoloz\AlfaBank\Exceptions\AlfaBankException;
|
||||
use Saloon\Http\Response;
|
||||
|
||||
// </SECTION>
|
||||
|
||||
// <SECTION name="class_definition" intent="Define the Alfa Bank API response error handling middleware.">
|
||||
@@ -24,7 +26,7 @@ class AlfaResponseMiddleware
|
||||
public function __invoke(Response $response): void
|
||||
{
|
||||
$contentType = $response->header('Content-Type') ?? '';
|
||||
|
||||
|
||||
if (str_contains($contentType, 'application/json')) {
|
||||
$data = $response->json();
|
||||
|
||||
@@ -38,10 +40,10 @@ class AlfaResponseMiddleware
|
||||
}
|
||||
|
||||
// 2. Handle SBP specific errors
|
||||
if (isset($data['ErrorCode']) && (string)$data['ErrorCode'] !== '0') {
|
||||
if (isset($data['ErrorCode']) && (string) $data['ErrorCode'] !== '0') {
|
||||
throw new AlfaBankException(
|
||||
$response,
|
||||
(string)$data['ErrorCode'],
|
||||
(string) $data['ErrorCode'],
|
||||
$data['message'] ?? 'No message'
|
||||
);
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ class LoggingMiddleware implements RequestMiddleware, ResponseMiddleware
|
||||
if (isset($headers['Authorization'])) {
|
||||
$headers['Authorization'] = 'Bearer *****';
|
||||
}
|
||||
|
||||
return $headers;
|
||||
}
|
||||
// </SECTION>
|
||||
@@ -53,7 +54,9 @@ class LoggingMiddleware implements RequestMiddleware, ResponseMiddleware
|
||||
// <BELIEF_STATE "This protected recursive helper method inspects the request or response body for predefined sensitive keys (e.g., `pan`, `client_secret`). If a sensitive key is found, its value is replaced with a mask. The method recursively processes nested arrays, ensuring that sensitive data is masked even within complex JSON structures, thereby enhancing log security.">
|
||||
protected function maskBody(mixed $body): mixed
|
||||
{
|
||||
if (!is_array($body)) return $body;
|
||||
if (! is_array($body)) {
|
||||
return $body;
|
||||
}
|
||||
|
||||
$sensitiveKeys = ['pan', 'cvc', 'digestSignatures', 'client_secret', 'refresh_token', 'access_token'];
|
||||
|
||||
@@ -64,6 +67,7 @@ class LoggingMiddleware implements RequestMiddleware, ResponseMiddleware
|
||||
$body[$key] = $this->maskBody($value);
|
||||
}
|
||||
}
|
||||
|
||||
return $body;
|
||||
}
|
||||
// </SECTION>
|
||||
|
||||
@@ -25,12 +25,15 @@ class LoggingRequestMiddleware implements RequestMiddleware
|
||||
if (isset($headers['Authorization'])) {
|
||||
$headers['Authorization'] = 'Bearer *****';
|
||||
}
|
||||
|
||||
return $headers;
|
||||
}
|
||||
|
||||
protected function maskBody(mixed $body): mixed
|
||||
{
|
||||
if (!is_array($body)) return $body;
|
||||
if (! is_array($body)) {
|
||||
return $body;
|
||||
}
|
||||
|
||||
$sensitiveKeys = ['pan', 'cvc', 'digestSignatures', 'client_secret', 'refresh_token', 'access_token'];
|
||||
|
||||
@@ -41,6 +44,7 @@ class LoggingRequestMiddleware implements RequestMiddleware
|
||||
$body[$key] = $this->maskBody($value);
|
||||
}
|
||||
}
|
||||
|
||||
return $body;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,9 @@ class LoggingResponseMiddleware implements ResponseMiddleware
|
||||
|
||||
protected function maskBody(mixed $body): mixed
|
||||
{
|
||||
if (!is_array($body)) return $body;
|
||||
if (! is_array($body)) {
|
||||
return $body;
|
||||
}
|
||||
|
||||
$sensitiveKeys = ['pan', 'cvc', 'digestSignatures', 'client_secret', 'refresh_token', 'access_token'];
|
||||
|
||||
@@ -32,6 +34,7 @@ class LoggingResponseMiddleware implements ResponseMiddleware
|
||||
$body[$key] = $this->maskBody($value);
|
||||
}
|
||||
}
|
||||
|
||||
return $body;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ class RequestIdMiddleware implements RequestMiddleware
|
||||
{
|
||||
public function __invoke(PendingRequest $pendingRequest): void
|
||||
{
|
||||
if (!$pendingRequest->headers()->get('X-Request-ID')) {
|
||||
if (! $pendingRequest->headers()->get('X-Request-ID')) {
|
||||
$pendingRequest->headers()->add('X-Request-ID', Uuid::v4());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,8 +17,8 @@ class VerifyJwsResponseMiddleware
|
||||
{
|
||||
$contentType = $response->header('Content-Type');
|
||||
|
||||
if (str_contains((string)$contentType, 'application/jose')) {
|
||||
if (!$this->publicKey) {
|
||||
if (str_contains((string) $contentType, 'application/jose')) {
|
||||
if (! $this->publicKey) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
@@ -26,12 +26,12 @@ class VerifyJwsResponseMiddleware
|
||||
$decoded = JwsSigner::verify($jws, $this->publicKey);
|
||||
|
||||
if ($decoded) {
|
||||
// In Saloon v3, we can't easily "fake" an existing response object in a type-safe way
|
||||
// In Saloon v3, we can't easily "fake" an existing response object in a type-safe way
|
||||
// without internal access. We will wrap the data and the user should use $response->json().
|
||||
// However, for the sake of PHPStan and clean architecture, we should use the response's
|
||||
// internal body repository if we really need to overwrite it, or better -
|
||||
// However, for the sake of PHPStan and clean architecture, we should use the response's
|
||||
// internal body repository if we really need to overwrite it, or better -
|
||||
// let the user handle the decoded data from a custom DTO.
|
||||
// To fix the immediate error, we'll return the response as is,
|
||||
// To fix the immediate error, we'll return the response as is,
|
||||
// but JWS verification is still performed.
|
||||
return $response;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ class AlfaOffsetPaginator extends OffsetPaginator
|
||||
protected function isLastPage(Response $response): bool
|
||||
{
|
||||
$items = $this->getPageItems($response, $this->request);
|
||||
|
||||
|
||||
return count($items) < $this->perPageLimit;
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ class AlfaOffsetPaginator extends OffsetPaginator
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
// Fallback to raw json if DTO fails
|
||||
echo "DTO Error: " . $e->getMessage() . "\n";
|
||||
echo 'DTO Error: ' . $e->getMessage() . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,13 +52,21 @@ class AlfaOffsetPaginator extends OffsetPaginator
|
||||
$json = $response->json();
|
||||
|
||||
// Common keys in Alfa API
|
||||
if (isset($json['transactions'])) return $json['transactions'];
|
||||
if (isset($json['payments'])) return $json['payments'];
|
||||
if (isset($json['accounts'])) return $json['accounts'];
|
||||
|
||||
if (isset($json['transactions'])) {
|
||||
return $json['transactions'];
|
||||
}
|
||||
if (isset($json['payments'])) {
|
||||
return $json['payments'];
|
||||
}
|
||||
if (isset($json['accounts'])) {
|
||||
return $json['accounts'];
|
||||
}
|
||||
|
||||
// If it's a direct array (some endpoints)
|
||||
if (array_is_list($json)) return $json;
|
||||
if (array_is_list($json)) {
|
||||
return $json;
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user