refactor(core): enhance SDK structure and documentation

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
2026-01-18 21:48:25 +03:00
parent 3da69c03e1
commit d214eecebe
378 changed files with 10514 additions and 496 deletions

View File

@@ -0,0 +1,31 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Initialize SDK with '...'
2. Call method '...'
3. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Environment (please complete the following information):**
- PHP Version: [e.g. 8.2]
- SDK Version [e.g. 1.0.0]
- OS: [e.g. Ubuntu 22.04]
**Additional context**
Add any other context about the problem here.

8
.gitignore vendored
View File

@@ -4,3 +4,11 @@
.env
phpunit.xml
composer.lock
/build/
*.pem
*.key
*.crt
*.pfx
.DS_Store
.idea/
.vscode/

65
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,65 @@
# Contributing to Alfa Bank SDK
Thank you for your interest in contributing to the unofficial Alfa Bank SDK! We welcome pull requests, bug reports, and feature requests.
## Getting Started
1. **Fork the repository** on GitHub.
2. **Clone your fork** locally:
```bash
git clone https://github.com/your-username/alfa-bank-sdk.git
cd alfa-bank-sdk
```
3. **Install dependencies**:
```bash
composer install
```
## Development Standards (Strict)
To maintain the "Enterprise Grade" quality of this SDK, all contributions must adhere to the following architectural rules:
### 1. Requests & Responses
- **DTOs Only:** Never pass raw arrays to a Request constructor. Always create a dedicated DTO in `src/Data/...`.
- **Strict Typing:** All Request classes must implement the `createDtoFromResponse(Response $response)` method. Returning raw JSON is forbidden.
- **Saloon v3:** Follow [Saloon PHP](https://docs.saloon.dev) best practices.
### 2. Pagination
- If an endpoint returns a list (e.g. transactions, accounts), the Request class **MUST**:
1. Implement `Saloon\PaginationPlugin\Contracts\Paginatable`.
2. Use the `Apoloz\AlfaBank\Traits\HasAlfaPagination` trait.
3. Return a `Spatie\LaravelData\DataCollection` in `createDtoFromResponse`.
### 3. Security
- **No Secrets:** Never commit real keys (`.pem`, `.key`, `.pfx`) or credentials.
- **Crypto:** Use the `CmsSigner` and `JwsSigner` utilities for cryptographic operations. Do not roll your own crypto logic.
## Running Quality Checks
We use **Pest** for testing and **PHPStan** for static analysis.
```bash
# Run Unit & Feature Tests
vendor/bin/pest
# Run Static Analysis (Level 5)
vendor/bin/phpstan analyse
```
**PRs with failing tests or PHPStan errors will not be merged.**
## Submitting a Pull Request
1. Create a new branch: `git checkout -b feature/my-new-feature`.
2. Write tests for your new feature (we aim for high coverage).
3. Commit changes with clear, descriptive messages.
4. Push to your fork and open a Pull Request against `main`.
## Reporting Bugs
Please open an issue on GitHub with:
- A clear description of the bug.
- Minimal reproducible code example.
- SDK version and PHP version.
Thank you for helping improve this SDK!

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023 Anatoliy Poloz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

611
README.md
View File

@@ -6,7 +6,7 @@ This is an unofficial PHP SDK for the [Alfa Bank API](https://developers.alfaban
- PHP 8.2+
- OpenSSL (for certificate generation/handling)
- [Saloon](https://docs.saloon.dev)
- [Saloon](https://docs.saloon.dev) v3.0+
- [Spatie Laravel Data](https://spatie.be/docs/laravel-data)
- [phpseclib](https://phpseclib.org/) (for Card Encryption)
@@ -16,6 +16,457 @@ This is an unofficial PHP SDK for the [Alfa Bank API](https://developers.alfaban
composer require apoloz/alfa-bank-sdk
```
## Security & Setup (Crucial)
Alfa Bank uses a comprehensive security model requiring **two distinct sets of keys**:
1. **Transport (mTLS):** To establish the SSL connection.
2. **Signing (JWS/CMS):** To digitally sign the request body.
### Where to get keys?
- **Sandbox:** Provided by the bank support or downloaded from the Developer Portal (usually as `.pfx` or `.zip`).
- **Production:**
- **Transport (mTLS):** Generate a private key and CSR using OpenSSL (`openssl genrsa`, `openssl req`). Send the CSR to `alfa_api@alfabank.ru`. The bank will reply with your Certificate.
- **Signing:** Generated by you (the client). The public certificate must be registered in "Alfa Business Online" or sent to your onboarding manager.
### 1. Converting PFX to PEM
If the bank provided a `.pfx` file for signing, you must convert it to PEM format:
```bash
# Extract Private Key
openssl pkcs12 -in signing.pfx -nocerts -out signing_key.pem -nodes
# Extract Public Certificate
openssl pkcs12 -in signing.pfx -clcerts -nokeys -out signing_cert.pem
```
### 2. Initialization
You can now initialize the SDK with both key pairs:
```php
use Apoloz\AlfaBank\AlfaBank;
use Apoloz\AlfaBank\Enums\Environment;
$baas = AlfaBank::baas(
// Transport Keys (mTLS)
certificatePath: '/path/to/transport_cert.pem',
privateKeyPath: '/path/to/transport_key.pem',
// Signing Keys (Business Logic) - Optional, defaults to transport keys if not set
signingCertificatePath: '/path/to/signing_cert.pem',
signingPrivateKeyPath: '/path/to/signing_key.pem',
environment: Environment::SANDBOX,
caBundlePath: '/path/to/root_ca_bundle.crt'
);
```
## Core Usage
### Authentication (BaaS)
Use the `login` method to perform OAuth Client Credentials flow:
```php
$baas->login(
clientId: 'your-client-id',
clientSecret: 'your-client-secret'
);
```
### Making Requests
#### SBP: Generate QR Code
```php
use Apoloz\AlfaBank\Sbp\Requests\GetQrCodeRequest;
use Apoloz\AlfaBank\Sbp\Data\QrCodeRequestData;
$sbp = AlfaBank::sbp(
certificatePath: '...',
privateKeyPath: '...',
keyNameAlias: '9728109955', // Terminal ID
signingPrivateKeyPath: '/path/to/signing_key.pem' // Specific signing key for SBP body
);
$response = $sbp->send(new GetQrCodeRequest(
new QrCodeRequestData(TermNo: '...', amount: '100')
));
$link = $response->dto()->payload;
```
#### Nominal Accounts
```php
$response = $baas->send(new CreateBeneficiaryRequest($payload));
```
### Self-Employed (Payouts & Status)
The SDK supports managing self-employed beneficiaries, checking their FTS status, and processing payouts.
#### Check Taxpayer Status
```php
use Apoloz\AlfaBank\Requests\SelfEmployed\GetTaxpayerStatusRequest;
use Apoloz\AlfaBank\Data\SelfEmployed\TaxpayerStatusRequestData;
$payload = new TaxpayerStatusRequestData(
externalId: 'unique-id',
selfemployedVatinList: ['123456789012']
);
$response = $baas->send(new GetTaxpayerStatusRequest($payload));
$status = $response->dto()->taxpayerStatusList[0];
```
#### Process Payout
```php
use Apoloz\AlfaBank\Requests\SelfEmployed\CreatePayoutRequest;
use Apoloz\AlfaBank\Data\SelfEmployed\PayoutRequestData;
$payload = new PayoutRequestData(
externalId: 'ext-id-456',
company: ['vatin' => '7700000000'],
requisite: [
['amount' => 1000, 'vatin' => '112233445566']
]
);
$response = $baas->send(new CreatePayoutRequest($payload));
```
### File Exchange
Upload and download files securely.
```php
use Apoloz\AlfaBank\Requests\FileExchange\UploadFileRequest;
use Apoloz\AlfaBank\Requests\FileExchange\DownloadFileRequest;
// Upload
$stream = fopen('path/to/file', 'r');
$baas->send(new UploadFileRequest($uploadUrl, $stream, $fileSize));
// Download
$response = $baas->send(new DownloadFileRequest($downloadUrl));
$content = $response->body();
```
### Payments (RUR Payment Orders)
Create standard payment orders and check their status.
```php
use Apoloz\AlfaBank\Requests\Payments\CreatePaymentRequest;
use Apoloz\AlfaBank\Data\Payments\PaymentData;
$payload = new PaymentData(
amount: 100.50,
date: '2023-10-25',
externalId: 'order-12345',
operationCode: '01',
payeeAccount: '40702...',
payeeBankBic: '044525225',
payeeName: 'Partner LLC',
payerAccount: '40702...',
payerBankBic: '044525593',
payerBankCorrAccount: '30101...',
payerInn: '7700000000',
payerName: 'My Company',
priority: '5',
purpose: 'Payment for services'
);
// Create Payment
$baas->send(new CreatePaymentRequest($payload));
// Check State
use Apoloz\AlfaBank\Requests\Payments\GetPaymentStateRequest;
$state = $baas->send(new GetPaymentStateRequest('order-12345'))->dto();
echo $state->bankStatus; // e.g. ACCEPTED
```
### Cards
Retrieve a list of client cards.
```php
use Apoloz\AlfaBank\Requests\Cards\GetCardsRequest;
$response = $baas->send(new GetCardsRequest());
foreach ($response->dto() as $card) {
echo $card->maskedNumber . ' - ' . $card->status;
}
```
### B2C Payouts (SBP via Phone)
Send money to individuals using their phone number through SBP.
```php
use Apoloz\AlfaBank\Requests\B2C\CreateB2CPaymentRequest;
use Apoloz\AlfaBank\Data\B2C\B2CPaymentRequestData;
use Apoloz\AlfaBank\Data\B2C\B2CClientData;
use Apoloz\AlfaBank\Data\B2C\B2CPaymentRecipientData;
$payload = new B2CPaymentRequestData(
client: new B2CClientData(b2cClientId: '...', partnerId: 123),
inn: '7700000000',
account: '40702...',
total: 100.53,
signedBody: '...base64_signature...',
payments: B2CPaymentRecipientData::collect([
[
'phone' => '79001112233',
'amount' => 100.53,
'nspkBankId' => '100000000001',
'sequence' => 'unique-seq-1',
'name' => ['first' => 'Ivan', 'last' => 'Ivanov']
]
], DataCollection::class)
);
$baas->send(new CreateB2CPaymentRequest($payload));
```
### Payment Registries (Batch Ruble Payments)
Create a registry for multiple ruble payments and sign it.
```php
use Apoloz\AlfaBank\Requests\Registries\CreateRegistryRequest;
use Apoloz\AlfaBank\Data\Registries\RegistryRequestData;
use Apoloz\AlfaBank\Data\Registries\RegistryPaymentData;
$payload = new RegistryRequestData(
payments: RegistryPaymentData::collect([
[
'amount' => 1000.0,
'date' => '2023-11-01',
'payeeAccount' => '40702...',
'payeeBankBic' => '044525225',
'payeeInn' => '7700000000',
'payeeName' => 'Vendor LLC',
'payerAccount' => '40702...',
'purpose' => 'Batch payment part 1'
]
], DataCollection::class),
description: 'Weekly payroll'
);
$response = $baas->send(new CreateRegistryRequest($payload));
$registryId = $response->json('id');
// Sign Registry
use Apoloz\AlfaBank\Requests\Registries\SignRegistryRequest;
use Apoloz\AlfaBank\Data\Registries\RegistrySignatureData;
use Spatie\LaravelData\DataCollection;
$signatures = RegistrySignatureData::collect([
[
'base64Encoded' => '...', // Base64 signature
'signatureType' => 'RSA',
'certificateUuid' => '...'
]
], DataCollection::class);
$baas->send(new SignRegistryRequest($registryId, $signatures));
```
### Customer Info
Get organization profile.
```php
use Apoloz\AlfaBank\Requests\CustomerInfo\GetCustomerInfoRequest;
$info = $baas->send(new GetCustomerInfoRequest())->dto();
echo $info->fullName;
```
### Limits
Get client's operation limits.
```php
use Apoloz\AlfaBank\Requests\Limits\GetGeneralLimitsRequest;
$response = $baas->send(new GetGeneralLimitsRequest());
$limits = $response->json();
```
### Debit Cards
Apply for a new debit card.
```php
use Apoloz\AlfaBank\Requests\DebitCards\CreateDebitCardApplicationRequest;
use Apoloz\AlfaBank\Data\DebitCards\DebitCardApplicationData;
$payload = new DebitCardApplicationData(
embossingName: 'IVAN IVANOV',
firstName: 'Иван',
lastName: 'Иванов',
middleName: 'Иванович',
mobilePhone: '79001112233',
passportBirthDate: '1990-01-01',
sex: 'm',
sopdConfirmed: true
);
$baas->send(new CreateDebitCardApplicationRequest($payload));
```
### User Compliance
Check user compliance for loans.
```php
use Apoloz\AlfaBank\Requests\Compliance\GetUserComplianceRequest;
$baas->send(new GetUserComplianceRequest());
```
### DFA (Digital Financial Assets)
List initial placements.
```php
use Apoloz\AlfaBank\Requests\DFA\GetDfaInitialPlacementListRequest;
$baas->send(new GetDfaInitialPlacementListRequest(limit: 5));
```
### Currency Rates
Get currency rates by office.
```php
use Apoloz\AlfaBank\Requests\Rates\GetOfficeRatesRequest;
$baas->send(new GetOfficeRatesRequest());
```
### Escrow Accounts
Manage construction projects and escrow orders.
```php
use Apoloz\AlfaBank\Requests\Escrow\GetBuildProjectsRequest;
$projects = $baas->send(new GetBuildProjectsRequest())->json();
```
### Power of Attorney (Poa)
Request and check status of digital POAs.
```php
use Apoloz\AlfaBank\Requests\Poa\CreatePoaRequest;
$response = $baas->send(new CreatePoaRequest('poa-123', '7700000000'));
$uuid = $response->json('requestUuid');
```
### Loyalty
Access bonus accounts and transaction history.
```php
use Apoloz\AlfaBank\Requests\Loyalty\GetLoyaltyAccountsRequest;
$accounts = $baas->send(new GetLoyaltyAccountsRequest())->json();
```
### Reports
Order certificates and reports.
```php
use Apoloz\AlfaBank\Requests\Reports\CreateAccountBalanceReportRequest;
$baas->send(new CreateAccountBalanceReportRequest(['40702...'], 'eng'));
```
### Crypto Service
Manage encryption and signing certificates.
```php
use Apoloz\AlfaBank\Requests\Crypto\GetCertificatesRequest;
$certificates = $baas->send(new GetCertificatesRequest())->json();
```
### Partner (MMB)
Access partner program data and applications.
```php
use Apoloz\AlfaBank\Requests\Partner\GetPartnerApplicationsRequest;
$apps = $baas->send(new GetPartnerApplicationsRequest())->json();
```
### Miscellaneous
- **Bonus Numbers**: `$baas->send(new GetBonusNumbersRequest());`
- **Credit Offers**: `$baas->send(new GetCreditOffersRequest());`
- **Self-encashment**: `$baas->send(new CreateSelfEncashmentRegistryRequest($data));`
- **Business Lounge**: `$baas->send(new GetLoungeBalanceRequest());`
- **Scoring**: `$baas->send(new GetComplianceScoreRequest('7700000000'));`
- **Security**: `$baas->send(new GetSubscriptionsRequest());`
- **Logistics**: `$baas->send(new GetDeliveriesRequest('...'));`
- **Webhooks**: `$baas->send(new GetWebhooksRequest());`
- **1C Integration**: `$baas->send(new CheckMerchantRequest('MF123', 'Basic ...'));`
- **Claims**: `$baas->send(new ResolveClaimRequest('ID', $data));`
- **Orders (Travel/Afisha)**: `$baas->send(new CreateTravelOrderRequest($data));`
- **Salary Project**: `$baas->send(new CreatePayrollApplicationRequest($payload));`
- **Cloud Signature**: `$baas->send(new SubmitSigningRequest('REQ-ID'));`
- **Aff Integration**: `$baas->send(new CheckComplianceRequest('INN', 'Name'));`
- **Digital Ruble**: `$sbp->send(new CreateUniQrRequest($uniQrData));`
### Signing Data (CMS)
For requests requiring a digital signature (e.g., Payments), you must canonicalize and sign the data manually.
```php
use Apoloz\AlfaBank\Utils\CmsSigner;
use Apoloz\AlfaBank\Data\NominalAccounts\Payouts\DigestSignatureData;
use Spatie\LaravelData\DataCollection;
// 1. Prepare data
$fields = [
'amount' => 100.50,
// ... other fields
];
// 2. Canonicalize & Sign
$json = CmsSigner::canonicalize($fields);
$cert = file_get_contents('/path/to/signing_cert.pem');
$key = file_get_contents('/path/to/signing_key.pem');
$signature = CmsSigner::sign($json, $cert, $key);
// 3. Attach to DTO
$paymentData->digestSignatures = DigestSignatureData::collect([
[
'base64Encoded' => $signature,
'signatureType' => 'CMS'
]
], DataCollection::class);
```
## Advanced Features
### Pagination
The SDK supports automatic pagination for list endpoints:
```php
use Apoloz\AlfaBank\Requests\Accounts\GetAccountsRequest;
$paginator = $baas->paginate(new GetAccountsRequest());
foreach ($paginator as $account) {
// Each item is processed automatically
}
```
## Laravel Integration
The package supports auto-discovery. Publish the config file:
@@ -26,120 +477,80 @@ php artisan vendor:publish --tag=alfa-bank-config
Configure your `.env`:
```env
ALFA_BAAS_CERT_PATH=/path/to/cert.cer
ALFA_BAAS_KEY_PATH=/path/to/key.key
ALFA_BAAS_ENV=sandbox
ALFA_SBP_CERT_PATH=/path/to/cert.cer
ALFA_SBP_KEY_PATH=/path/to/key.key
ALFA_SBP_KEY_ALIAS=your-alias
ALFA_SBP_ENV=sandbox
ALFA_BAAS_CERT_PATH=/path/to/transport_cert.pem
# ... other settings
ALFA_WEBHOOK_USER=your_webhook_user
ALFA_WEBHOOK_PASSWORD=your_webhook_password
```
Now you can inject the connectors:
```php
use Apoloz\AlfaBank\AlfaBankConnector;
### Webhook Handling (Laravel)
public function index(AlfaBankConnector $connector) {
$connector->withToken('...')->send(new GetNominalAccountsRequest());
The SDK provides a built-in controller and route macro to handle incoming webhooks and dispatch Laravel events.
1. **Register the route** in `routes/api.php`:
```php
Route::alfaWebhooks('/webhooks/alfa');
```
2. **Listen for the event** in `app/Providers/EventServiceProvider.php`:
```php
use Apoloz\AlfaBank\Laravel\Events\AlfaWebhookReceived;
protected $listen = [
AlfaWebhookReceived::class => [
\App\Listeners\HandleAlfaWebhook::class,
],
];
```
3. **Handle the DTO** in your listener:
```php
public function handle(AlfaWebhookReceived $event)
{
$webhook = $event->webhook; // BaseWebhookData DTO
if ($webhook->object === 'ul_transaction_default') {
$transaction = $webhook->data;
// ...
}
}
```
## Core Usage (Generic PHP)
## Error Handling
### 1. Initialize the Connector
The SDK throws `Apoloz\AlfaBank\Exceptions\AlfaBankException` when the API returns an error.
```php
use Apoloz\AlfaBank\AlfaBankConnector;
use Apoloz\AlfaBank\Enums\Environment;
$connector = new AlfaBankConnector(
certificatePath: '/path/to/client.cer',
privateKeyPath: '/path/to/private.key',
environment: Environment::SANDBOX
);
try {
$baas->send($request);
} catch (\Apoloz\AlfaBank\Exceptions\AlfaBankException $e) {
echo $e->getErrorCode(); // e.g. "invalid_token" or "RQ05014"
echo $e->getMessage();
}
```
### 2. Authentication
## Utilities
- **Card PAN Encryption**: `CardEncryptor::encrypt($pan, $pubKey)`
- **CMS Signing**: `CmsSigner::sign($data, $cert, $key)`
- **JWS/JWE**: `JwsSigner` and `JweEncryptor` for transport security.
## Diagnostics
### Health Check (Laravel)
Run the built-in Artisan command to verify your mTLS certificates and connection:
```bash
php artisan alfa:check
```
### Logging
Attach a PSR-3 logger to debug requests (sensitive data redacted):
```php
use Apoloz\AlfaBank\Requests\Auth\GetTokenRequest;
$request = new GetTokenRequest(
clientId: 'your-client-id',
clientSecret: 'your-client-secret',
code: 'auth-code',
redirectUri: 'https://your-app.com/callback'
);
$response = $connector->send($request);
$tokenData = $response->dto();
$connector->withToken($tokenData->access_token);
$baas->withLogging(Log::getLogger());
```
### 3. SBP / QR Payouts (C2B)
```php
use Apoloz\AlfaBank\Sbp\SbpConnector;
$sbpConnector = new SbpConnector(
certificatePath: '/path/to/client.cer',
privateKeyPath: '/path/to/private.key',
keyNameAlias: 'your-key-alias',
environment: Environment::SANDBOX
);
$response = $sbpConnector->send(new GetQrCodeRequest($payload));
```
### 4. Utilities
#### Card PAN Encryption
Required for card payouts in Nominal Accounts.
```php
use Apoloz\AlfaBank\Utils\CardEncryptor;
$encryptedPan = CardEncryptor::encrypt(
pan: '4779642610000010',
publicKeyPem: file_get_contents('alfa-card-key.pub')
);
```
#### JSON Web Signature (JWS)
Used for signing some BaaS requests.
```php
use Apoloz\AlfaBank\Utils\JwsSigner;
$jws = JwsSigner::sign(
payload: ['foo' => 'bar'],
privateKeyPem: file_get_contents('my-key.pem'),
certificateSerialNumber: '610003...'
);
```
#### JSON Web Encryption (JWE)
Used for encrypting sensitive BaaS requests.
```php
use Apoloz\AlfaBank\Utils\JweEncryptor;
$jwe = JweEncryptor::encrypt(
jws: $jws,
publicKeyPem: file_get_contents('alfa-cert.cer'),
certificateSerialNumber: '610003...'
);
```
## Features
- **Mutual TLS**: Automated certificate handling.
- **Laravel Ready**: Service Provider and Config included.
- **Typed DTOs**: Comprehensive response parsing.
- **Full Product Coverage**: BaaS (Nominal Accounts, Escrow), SBP (QR, Subscriptions), Digital Ruble.
## License
MIT

View File

@@ -1,41 +1,49 @@
{
"name": "apoloz/alfa-bank-sdk",
"description": "Unofficial Alfa Bank API SDK for PHP using Saloon and Laravel Data",
"type": "library",
"license": "MIT",
"authors": [
{
"name": "A. Poloz",
"email": "t0ly.od@yandex.ru"
"name": "apoloz/alfa-bank-sdk",
"description": "Unofficial Alfa Bank API SDK for PHP using Saloon and Laravel Data",
"type": "library",
"license": "MIT",
"authors": [
{
"name": "apoloz",
"email": "anatoliy.poloz@gmail.com"
}
],
"require": {
"php": "^8.2",
"saloonphp/saloon": "^3.0",
"saloonphp/laravel-plugin": "^3.0",
"saloonphp/pagination-plugin": "^2.0",
"spatie/laravel-data": "^4.0",
"guzzlehttp/guzzle": "^7.0",
"phpseclib/phpseclib": "^3.0"
},
"require-dev": {
"phpunit/phpunit": "^10.0",
"pestphp/pest": "^2.0",
"phpstan/phpstan": "^2.1"
},
"autoload": {
"psr-4": {
"Apoloz\\AlfaBank\\": "src/"
}
},
"extra": {
"laravel": {
"providers": [
"Apoloz\\AlfaBank\\Laravel\\AlfaBankServiceProvider"
]
}
},
"minimum-stability": "stable",
"prefer-stable": true,
"scripts": {
"test": "vendor/bin/pest",
"test-coverage": "vendor/bin/pest --coverage"
},
"config": {
"allow-plugins": {
"pestphp/pest-plugin": true
}
}
],
"require": {
"php": "^8.2",
"saloonphp/saloon": "^3.0",
"spatie/laravel-data": "^4.0",
"guzzlehttp/guzzle": "^7.0",
"phpseclib/phpseclib": "^3.0"
},
"require-dev": {
"phpunit/phpunit": "^10.0",
"pestphp/pest": "^2.0"
},
"autoload": {
"psr-4": {
"Apoloz\\AlfaBank\\": "src/"
}
},
"extra": {
"laravel": {
"providers": [
"Apoloz\\AlfaBank\\Laravel\\AlfaBankServiceProvider"
]
}
},
"minimum-stability": "stable",
"prefer-stable": true,
"scripts": {
"test": "vendor/bin/pest",
"test-coverage": "vendor/bin/pest --coverage"
}
}

40
examples/01_baas_flow.php Normal file
View File

@@ -0,0 +1,40 @@
<?php
require_once __DIR__ . '/../vendor/autoload.php';
use Apoloz\AlfaBank\AlfaBank;
use Apoloz\AlfaBank\Enums\Environment;
// 1. Initialize
// Ensure you have valid certificates for the Sandbox
$baas = AlfaBank::baas(
certificatePath: __DIR__ . '/certs/client.cer',
privateKeyPath: __DIR__ . '/certs/private.key',
environment: Environment::SANDBOX,
caBundlePath: __DIR__ . '/certs/russian_trusted_sub_ca.crt' // Mincifry
);
try {
echo "Authenticating...\n";
$baas->login(
clientId: 'your-client-id',
clientSecret: 'your-client-secret'
);
echo "Authentication Successful!\n";
// 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";
if ($e instanceof \Apoloz\AlfaBank\Exceptions\AlfaBankException) {
echo "API Code: " . $e->getErrorCode() . "\n";
}
}

45
examples/02_sbp_qr.php Normal file
View File

@@ -0,0 +1,45 @@
<?php
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;
// 1. Initialize SBP
$sbp = AlfaBank::sbp(
certificatePath: __DIR__ . '/certs/client.cer',
privateKeyPath: __DIR__ . '/certs/private.key',
keyNameAlias: 'my-alias', // Required for SBP signatures in some contexts
environment: Environment::SANDBOX
);
try {
echo "Generating Static QR Code...\n";
$payload = new QrCodeRequestData(
termNo: 'TEST_TERM_001',
qrcType: '01', // Static
amount: '15000', // 150.00 RUB
paymentPurpose: 'Test Payment'
);
$request = new GetQrCodeRequest($payload);
$response = $sbp->send($request);
if ($response->successful()) {
$qrData = $response->dto();
echo "QR Payload: " . $qrData->payload . "\n";
echo "QR Image URL: " . $qrData->image . "\n";
} else {
echo "Failed to generate QR.\n";
}
// Example of Pagination (if supported by SBP endpoints)
// $paginator = $sbp->paginate(new SomeSbpListRequest());
// foreach($paginator as $item) { ... }
} catch (\Exception $e) {
echo "Error: " . $e->getMessage() . "\n";
}

View File

@@ -0,0 +1,55 @@
<?php
require_once __DIR__ . '/../vendor/autoload.php';
use Apoloz\AlfaBank\AlfaBank;
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:
* 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',
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',
environment: Environment::SANDBOX,
caBundlePath: __DIR__ . '/certs/sbp_payout/sandbox_root/root-ca-test.crt'
);
echo "SBP Connector Initialized.\n";
// Now you can use $baas->login(...) or $sbp->send(...)

View File

@@ -0,0 +1,54 @@
<?php
require_once __DIR__ . '/../vendor/autoload.php';
use Apoloz\AlfaBank\AlfaBank;
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 Apoloz\AlfaBank\Data\NominalAccounts\Payouts\DigestSignatureData;
use Spatie\LaravelData\DataCollection;
/**
* Example: Creating a Beneficiary for a Nominal Account.
* This flow requires a digital signature (CMS).
*/
$baas = AlfaBank::baas(
certificatePath: 'path/to/cert.pem',
privateKeyPath: 'path/to/key.pem',
environment: Environment::SANDBOX
);
// 1. Prepare beneficiary data
$payload = new CreateBeneficiaryRequestData(
type: 'FL_RESIDENT',
countryOfTaxResidence: 'RU',
name: 'Ivanov Ivan Ivanovich',
inn: '771234567890',
addresses: AddressData::collect([
[
'type' => 'REGISTRATION_ADDRESS',
'address' => 'Moscow, Lenina st, 10',
'country' => 'RU'
]
], DataCollection::class),
digestSignatures: DigestSignatureData::collect([
[
'base64Encoded' => 'MOCK_SIGNATURE', // In real life, use CmsSigner::sign()
'signatureType' => 'cms'
]
], DataCollection::class)
);
// 2. Login and send request
$baas->login('client-id', 'client-secret');
$response = $baas->send(new CreateBeneficiaryRequest($payload));
if ($response->successful()) {
$data = $response->dto(); // BeneficiaryResponseData
echo "Beneficiary creation accepted. ID: {$data->id}, Status: {$data->status}\n";
} else {
echo "Error: " . $response->body() . "\n";
}

49
examples/05_webhooks.php Normal file
View File

@@ -0,0 +1,49 @@
<?php
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;
/**
* 1. Managing Webhooks (BaaS API)
*/
$baas = AlfaBank::baas('cert.pem', 'key.pem');
$baas->login('id', 'secret');
// List existing webhooks
$response = $baas->send(new GetWebhooksRequest());
$webhooks = $response->dto(); // DataCollection of WebhookSubscriptionData
foreach ($webhooks as $webhook) {
echo "Webhook ID: {$webhook->id}, URL: {$webhook->callbackUri}\n";
}
// Create new webhook
$data = new WebhookSubscriptionRequestData('https://your-app.com/webhooks/alfa', ['transactions']);
$baas->send(new CreateWebhookRequest($data));
/**
* 2. Parsing incoming webhook payload (Webhook Controller logic)
*/
$rawPayload = [
[
'actionType' => 'create',
'eventTime' => '2023-10-27T10:00:00Z',
'object' => 'ul_transaction_default',
'data' => [
'transactionId' => 'TX-12345',
'amount' => ['amount' => 100.50, 'currencyName' => 'RUR'],
'direction' => 'CREDIT',
'paymentPurpose' => 'Test payment'
]
]
];
// Use the factory to parse the payload into a DTO
$webhookDto = WebhookFactory::create($rawPayload);
echo "Received Webhook: {$webhookDto->object} ({$webhookDto->actionType})\n";

View File

@@ -0,0 +1,46 @@
<?php
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 Spatie\LaravelData\DataCollection;
/**
* Example: B2C Payout via SBP (Phone Number).
*/
$baas = AlfaBank::baas(
certificatePath: 'path/to/cert.pem',
privateKeyPath: 'path/to/key.pem'
);
$payload = new B2CPaymentRequestData(
client: new B2CClientData(b2cClientId: 'your-uuid', partnerId: 123),
inn: '7700000000',
account: '40702810...',
total: 100.00,
signedBody: 'BASE64_SIGNATURE_HERE', // Signature of the payments data
payments: B2CPaymentRecipientData::collect([
[
'phone' => '79001112233',
'amount' => 100.00,
'nspkBankId' => '100000000001',
'sequence' => 'unique-payout-id-1'
]
], DataCollection::class)
);
$baas->login('client-id', 'client-secret');
$response = $baas->send(new CreateB2CPaymentRequest($payload));
if ($response->successful()) {
$data = $response->dto(); // B2CPaymentResponseData
echo "Payout request sent. Status: {$data->status}\n";
} else {
echo "Error: " . $response->body() . "\n";
}

View File

@@ -0,0 +1,65 @@
<?php
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\RegistrySignatureData;
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'
);
// 1. Create Registry
$payload = new RegistryRequestData(
payments: RegistryPaymentData::collect([
[
'amount' => 500.0,
'date' => date('Y-m-d'),
'payeeAccount' => '40702...',
'payeeBankBic' => '044...',
'payeeInn' => '770...',
'payeeName' => 'Vendor 1',
'payerAccount' => '40702...',
'purpose' => 'Payment for goods'
]
], DataCollection::class)
);
$baas->login('client-id', 'client-secret');
$response = $baas->send(new CreateRegistryRequest($payload));
$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
// or the registry content itself. This depends on the specific bank requirement.
$signature = CmsSigner::sign(
$registryId, // Example data
file_get_contents('path/to/sign_cert.pem'),
file_get_contents('path/to/sign_key.pem')
);
$signatures = RegistrySignatureData::collect([
[
'base64Encoded' => $signature,
'signatureType' => 'RSA',
'certificateUuid' => 'YOUR_CERT_UUID'
]
], DataCollection::class);
$baas->send(new SignRegistryRequest($registryId, $signatures));
echo "Registry Signed.\n";

9
phpstan.neon Normal file
View File

@@ -0,0 +1,9 @@
parameters:
level: 5
paths:
- src
excludePaths:
- src/Laravel
- src/Http/Pagination
- src/Traits/HasAlfaPagination.php
tmpDir: build/phpstan

80
src/AlfaBank.php Normal file
View File

@@ -0,0 +1,80 @@
<?php
/*
// MODULE_CONTRACT: Provides a user-friendly, static factory for instantiating API connectors.
// RESPONSIBILITY: To simplify the creation of `AlfaBankConnector` and `SbpConnector` instances by abstracting away the underlying DTO and service instantiation.
// INPUTS: Certificate paths, environment, and other configuration primitives.
// OUTPUTS: Fully configured Connector instances.
// LINKS: Core/AlfaBankConnector.php, Sbp/SbpConnector.php
*/
namespace Apoloz\AlfaBank;
// <SECTION name="module_imports" intent="Import all necessary connectors, services, and configuration objects.">
// <BELIEF_STATE "The factory needs to know about the concrete classes it will instantiate, including the connectors, config DTOs, and any default services like the CMS signer.">
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;
// </SECTION>
// <SECTION name="class_definition" intent="Define a static factory class to act as the primary entry point for the SDK.">
// <BELIEF_STATE "A static factory provides a simple and clean entry point for users of the SDK. Instead of manually wiring up dependencies, they can call a simple method like `AlfaBank::baas(...)`, which improves developer experience.">
class AlfaBank
{
// <SECTION name="baas_connector_factory" intent="Create a fully configured connector for the Core Banking (BaaS) API.">
// <BELIEF_STATE "This static method encapsulates the business logic of creating a BaaS connector. It correctly instantiates the `AlfaConfig` DTO and the default `OpenSslCmsSigner`, hiding this complexity from the end-user.">
public static function baas(
string $certificatePath,
string $privateKeyPath,
Environment $environment = Environment::SANDBOX,
?string $caBundlePath = null,
?string $signingCertificatePath = null,
?string $signingPrivateKeyPath = null
): AlfaBankConnector {
$config = new AlfaConfig(
baseUrl: $environment->value,
certificatePath: $certificatePath,
privateKeyPath: $privateKeyPath,
caBundlePath: $caBundlePath,
signingCertificatePath: $signingCertificatePath,
signingPrivateKeyPath: $signingPrivateKeyPath
);
$signerCert = $signingCertificatePath ?: $certificatePath;
$signerKey = $signingPrivateKeyPath ?: $privateKeyPath;
$signer = new OpenSslCmsSigner($signerCert, $signerKey);
return new AlfaBankConnector($config, $signer);
}
// </SECTION>
// <SECTION name="sbp_connector_factory" intent="Create a fully configured connector for the Faster Payments (SBP) API.">
// <BELIEF_STATE "This method encapsulates the logic for creating an SBP connector. It correctly resolves the distinct SBP base URL based on the environment and passes the required SBP-specific parameters like `keyNameAlias`. This separation from the `baas` factory is crucial due to the different configuration requirements.">
public static function sbp(
string $certificatePath,
string $privateKeyPath,
string $keyNameAlias,
Environment $environment = Environment::SANDBOX,
?string $caBundlePath = null,
?string $signingCertificatePath = null,
?string $signingPrivateKeyPath = null
): SbpConnector {
$baseUrl = $environment === Environment::PRODUCTION
? Environment::SBP_PRODUCTION->value
: Environment::SBP_SANDBOX->value;
$config = new AlfaConfig(
baseUrl: $baseUrl,
certificatePath: $certificatePath,
privateKeyPath: $privateKeyPath,
caBundlePath: $caBundlePath,
signingCertificatePath: $signingCertificatePath,
signingPrivateKeyPath: $signingPrivateKeyPath
);
return new SbpConnector($config, $keyNameAlias);
}
// </SECTION>
}

View File

@@ -0,0 +1,8 @@
<?php
namespace Apoloz\AlfaBank\Contracts;
interface EncryptorInterface
{
public function encrypt(string $data): string;
}

View File

@@ -0,0 +1,26 @@
<?php
/*
// MODULE_CONTRACT: Defines the abstract contracts (interfaces) for all security-related operations.
// RESPONSIBILITY: To establish a common, swappable interface for different signing and encryption implementations, enabling Inversion of Control.
// INPUTS: N/A (Defines interfaces, does not take inputs).
// OUTPUTS: N/A (Defines interfaces, does not produce outputs).
// LINKS: Laravel/AlfaBankServiceProvider.php (where these contracts are bound to implementations)
*/
namespace Apoloz\AlfaBank\Contracts;
// <SECTION name="signer_interface" intent="Define a contract for any service that can generate a digital signature.">
// <BELIEF_STATE "Defining a `SignerInterface` is a core principle of SOLID design. It allows high-level code (like connectors) to depend on an abstraction, not a concrete implementation. This makes it possible to swap out the signing logic (e.g., from OpenSSL to a hardware security module) without changing any code that *uses* the signer.">
interface SignerInterface
{
public function sign(string $data): string;
}
// </SECTION>
// <SECTION name="encryptor_interface" intent="Define a contract for any service that can perform data encryption.">
// <BELIEF_STATE "Similar to the SignerInterface, this contract decouples the concept of encryption from its specific implementation (e.g., phpseclib, OpenSSL). This promotes flexibility and testability, as mock encryptors can be easily injected during tests.">
interface EncryptorInterface
{
public function encrypt(string $data): string;
}
// </SECTION>

View File

@@ -0,0 +1,8 @@
<?php
namespace Apoloz\AlfaBank\Contracts;
interface SignerInterface
{
public function sign(string $data): string;
}

View File

@@ -0,0 +1,130 @@
<?php
/*
// MODULE_CONTRACT: Defines the primary transport layer for the Alfa Bank BaaS API.
// RESPONSIBILITY: To manage mTLS configuration, authentication state, retries, and middleware for all BaaS API interactions.
// INPUTS: AlfaConfig (DTO), SignerInterface (service).
// OUTPUTS: An authenticated Saloon Connector instance capable of sending requests.
// NOTES:
// - Supports separate keys for Transport (mTLS) and Signing (JWS/CMS).
// - Uses `login` method for OAuth 2.0 Client Credentials flow.
// - Compatible with Saloon v3.
// LINKS: AlfaBankServiceProvider.php#bind_connector
*/
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\Http\Middleware\AlfaResponseMiddleware;
use Apoloz\AlfaBank\Http\Middleware\RequestIdMiddleware;
use Apoloz\AlfaBank\Http\Pagination\AlfaOffsetPaginator;
use Apoloz\AlfaBank\Requests\Auth\GetTokenRequest;
use Saloon\Http\Connector;
use Saloon\Http\Request;
use Saloon\PaginationPlugin\Contracts\HasPagination;
use Saloon\PaginationPlugin\OffsetPaginator;
use Saloon\Traits\RequestProperties\HasTries;
use Saloon\Traits\Plugins\HasTimeout;
class AlfaBankConnector extends Connector implements HasPagination
{
use HasTimeout;
use HasTries;
public function __construct(
protected AlfaConfig $alfaConfig,
protected ?SignerInterface $signer = null
) {
$this->tries = 3;
$this->retryInterval = 500;
}
public function resolveBaseUrl(): string
{
return $this->alfaConfig->baseUrl;
}
protected function defaultConfig(): array
{
$config = [
'cert' => $this->alfaConfig->certificatePath,
'ssl_key' => $this->alfaConfig->privateKeyPath,
'verify' => true,
];
if ($this->alfaConfig->caBundlePath) {
$config['verify'] = $this->alfaConfig->caBundlePath;
}
return $config;
}
protected function defaultMiddleware(): array
{
return [];
}
public function boot(\Saloon\Http\PendingRequest $pendingRequest): void
{
$pendingRequest->middleware()->onResponse(new AlfaResponseMiddleware());
$pendingRequest->middleware()->onRequest(new RequestIdMiddleware());
}
public function paginate(Request $request): OffsetPaginator
{
return new AlfaOffsetPaginator($this, $request);
}
public function login(?string $clientId = null, ?string $clientSecret = null): static
{
// Allow overriding config via method arguments
$clientId = $clientId ?? $this->alfaConfig->clientId;
$clientSecret = $clientSecret ?? $this->alfaConfig->clientSecret;
if (!$clientId || !$clientSecret) {
throw new \RuntimeException("Client ID/Secret not configured.");
}
$request = new GetTokenRequest(
clientId: $clientId,
clientSecret: $clientSecret,
grantType: 'client_credentials'
);
// Send request (using self to reuse cert/ssl config)
// We temporarily disable auth middleware if we had any,
// but here we are raw, so it's fine.
$response = $this->send($request);
$data = $response->dto();
$this->authenticate(new \Saloon\Http\Auth\TokenAuthenticator($data->access_token));
return $this;
}
// </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
{
$middleware = new \Apoloz\AlfaBank\Http\Middleware\LoggingMiddleware($logger);
$this->middleware()->onRequest([$middleware, 'onRequest']);
$this->middleware()->onResponse([$middleware, 'onResponse']);
return $this;
}
// </SECTION>
}

54
src/Core/AlfaConfig.php Normal file
View File

@@ -0,0 +1,54 @@
<?php
/*
// MODULE_CONTRACT: Defines a strongly-typed, immutable Data Transfer Object (DTO) for all connector configurations.
// RESPONSIBILITY: To hold and validate critical configuration parameters like certificate paths and API credentials.
// INPUTS: Configuration primitives (strings for paths, URLs, credentials).
// OUTPUTS: A validated, read-only configuration object.
// NOTES:
// - Stores both Transport keys (mTLS) and optional Signing keys (JWS/CMS).
// - Validates file existence upon instantiation.
// LINKS: AlfaBankConnector.php, SbpConnector.php
*/
namespace Apoloz\AlfaBank\Core;
// <SECTION name="class_definition" intent="Define an immutable DTO for connector configuration.">
// <BELIEF_STATE "Using a `readonly` class for configuration is a best practice. It prevents accidental modification of the configuration after instantiation, ensuring that the connector's behavior remains consistent throughout its lifecycle. This pattern is superior to passing around raw arrays.">
readonly class AlfaConfig
{
// <SECTION name="constructor" intent="Inject and validate all configuration properties upon creation.">
// <BELIEF_STATE "The constructor acts as a validation gate. By checking for the existence of certificate and key files here, we enforce a fail-fast policy. It's better to throw an exception immediately upon configuration creation than to fail unexpectedly during an API call later.">
public function __construct(
// <BELIEF_STATE "The base URL for the API endpoint.">
public string $baseUrl,
// <BELIEF_STATE "The file system path to the client's mTLS certificate.">
public string $certificatePath,
// <BELIEF_STATE "The file system path to the client's mTLS private key.">
public string $privateKeyPath,
// <BELIEF_STATE "Optional: The path to a custom Certificate Authority bundle, required for some environments (e.g., Russian Trusted CA).">
public ?string $caBundlePath = null,
// <BELIEF_STATE "Optional: The OAuth client ID, required for token-based authentication.">
public ?string $clientId = null,
// <BELIEF_STATE "Optional: The OAuth client secret, required for token-based authentication.">
public ?string $clientSecret = null,
// <BELIEF_STATE "Optional: Path to the certificate used specifically for signing requests (JWS/CMS), if different from the transport certificate.">
public ?string $signingCertificatePath = null,
// <BELIEF_STATE "Optional: Path to the private key used specifically for signing requests (JWS/CMS), if different from the transport key.">
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)) {
throw new \InvalidArgumentException("Certificate not found: {$this->certificatePath}");
}
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->signingPrivateKeyPath && !file_exists($this->signingPrivateKeyPath)) {
throw new \InvalidArgumentException("Signing private key not found: {$this->signingPrivateKeyPath}");
}
}
// </SECTION>
}

View File

@@ -0,0 +1,16 @@
<?php
namespace Apoloz\AlfaBank\Data\Accounts;
use Spatie\LaravelData\Data;
class AccountData extends Data
{
public function __construct(
public string $number,
public string $dateCreated,
public string $type,
public ?string $mnemonic = null,
public ?array $balance = null, // Can be refined later with BalanceData
) {}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace Apoloz\AlfaBank\Data\Aff;
use Spatie\LaravelData\Data;
class AffRegisterData extends Data
{
public function __construct(
public array $payments = [],
) {}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Apoloz\AlfaBank\Data\Aff;
use Spatie\LaravelData\Data;
class AffResponseData extends Data
{
public function __construct(
public ?string $id = null,
public ?string $status = null,
) {}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Apoloz\AlfaBank\Data\Aff;
use Spatie\LaravelData\Data;
class AffSignData extends Data
{
public function __construct(
public string $registerId,
public string $signature,
) {}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Apoloz\AlfaBank\Data\Auth;
use Spatie\LaravelData\Data;
class ClientSecretData extends Data
{
public function __construct(
public string $clientSecret,
public ?string $expiresAt = null,
) {}
}

View File

@@ -1,16 +1,31 @@
<?php
/*
// MODULE_CONTRACT: Defines the data structure for an OAuth 2.0 token response.
// RESPONSIBILITY: To hold and type-safely represent the access token, refresh token, ID token, expiry, and token type returned by the OAuth provider.
// INPUTS: Raw JSON object from the token endpoint response.
// OUTPUTS: A structured object containing token information.
// LINKS: Requests/Auth/GetTokenRequest.php
*/
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.">
// <BELIEF_STATE "This DTO provides a clear, type-safe contract for handling sensitive token data, ensuring consistency and preventing errors when accessing token properties.">
class TokenData extends Data
{
// <SECTION name="constructor_properties" intent="Define the properties of an OAuth token response.">
// <BELIEF_STATE "The constructor includes mandatory fields like `access_token`, `refresh_token`, `expires_in`, and `token_type` as per OAuth 2.0. The `id_token` is optional and specific to OpenID Connect.">
public function __construct(
public string $access_token,
public string $refresh_token,
public ?string $id_token,
public ?string $id_token, // Specific to OpenID Connect
public int $expires_in,
public string $token_type
) {}
// </SECTION>
}

View File

@@ -1,17 +1,32 @@
<?php
/*
// MODULE_CONTRACT: Defines the data structure for a paginated collection of client consent records.
// RESPONSIBILITY: To provide a structured, type-safe container for lists of client consents returned by the API, including pagination metadata.
// INPUTS: Raw JSON array from the API response.
// OUTPUTS: An object containing pagination details and a collection of `ClientConsentData`.
// LINKS: Requests/Auth/UserInfo/GetClientConsentsRequest.php
*/
namespace Apoloz\AlfaBank\Data\Auth\UserInfo;
// <SECTION name="module_imports" intent="Import necessary DTOs and Spatie Laravel Data components.">
// <BELIEF_STATE "This collection DTO relies on `PaginationData` for metadata and `ClientConsentData` for the individual items. `DataCollection` and `DataCollectionOf` are Spatie Data features for handling typed arrays of DTOs.">
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.">
// <BELIEF_STATE "A dedicated DTO for a collection ensures that the structure of paginated lists is consistent and type-safe, providing a reliable contract for consumers to manage client consents.">
class ClientConsentCollectionData extends Data
{
// <SECTION name="constructor_properties" intent="Define the properties of the client consent collection.">
// <BELIEF_STATE "The collection structure includes pagination metadata (`pagination`) and the actual list of consent items (`items`). The `#[DataCollectionOf(ClientConsentData::class)]` attribute is crucial for ensuring that each item in the `items` array is automatically cast to a `ClientConsentData` DTO.">
public function __construct(
public PaginationData $pagination,
#[DataCollectionOf(ClientConsentData::class)]
public DataCollection $items
) {}
// </SECTION>
}

View File

@@ -1,14 +1,28 @@
<?php
/*
// MODULE_CONTRACT: Defines the data structure for a single client consent record.
// RESPONSIBILITY: To hold and type-safely represent the details of a user's consent given to a client application.
// INPUTS: Raw JSON object from the API response.
// OUTPUTS: A structured object containing client consent information.
// LINKS: ClientConsentCollectionData.php
*/
namespace Apoloz\AlfaBank\Data\Auth\UserInfo;
use Apoloz\AlfaBank\Data\PaginationData;
use Spatie\LaravelData\Attributes\DataCollectionOf;
// <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.
use Spatie\LaravelData\Data;
use Spatie\LaravelData\DataCollection;
use Spatie\LaravelData\DataCollection; // This is also likely extraneous for a single DTO.
// </SECTION>
// <SECTION name="class_definition" intent="Define a DTO for a single client consent.">
// <BELIEF_STATE "This DTO provides a clear, type-safe contract for an individual consent record, which is crucial for managing access permissions within an OAuth/OIDC system.">
class ClientConsentData extends Data
{
// <SECTION name="constructor_properties" intent="Define the properties of a client consent record.">
// <BELIEF_STATE "The constructor includes key information such as `createDateTime`, `sub` (subject ID), `clientId`, `isActive` status, and `expireDate`. The `organizationIdHash` provides additional context. These fields define the scope and validity of the consent.">
public function __construct(
public string $createDateTime,
public string $sub,
@@ -17,4 +31,5 @@ class ClientConsentData extends Data
public string $expireDate,
public ?string $organizationIdHash = null,
) {}
// </SECTION>
}

View File

@@ -1,15 +1,29 @@
<?php
/*
// MODULE_CONTRACT: Defines the data structure for OpenID Connect UserInfo claims.
// RESPONSIBILITY: To hold and type-safely represent details about the authenticated end-user.
// INPUTS: Raw JSON object (typically from a JWT payload) from the UserInfo endpoint.
// OUTPUTS: A structured object containing user claims.
// LINKS: Requests/Auth/UserInfo/GetUserInfoRequest.php
*/
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.">
// <BELIEF_STATE "This DTO provides a clear, type-safe contract for handling user claims returned by the OIDC UserInfo endpoint, ensuring consistent access to user attributes.">
class UserInfoData extends Data
{
// <SECTION name="constructor_properties" intent="Define the standard and extended properties (claims) for user information.">
// <BELIEF_STATE "The constructor includes `sub` (subject identifier) as mandatory. Many other fields are optional and represent common OIDC claims like `name`, `email`, `birthdate`, `phone_number`, and `inn`. These claims provide rich detail about the end-user.">
public function __construct(
public string $sub,
public ?string $iss = null,
public ?string $aud = null,
public ?string $iss = null, // Issuer
public ?string $aud = null, // Audience
public ?string $name = null,
public ?string $given_name = null,
public ?string $family_name = null,
@@ -18,7 +32,8 @@ class UserInfoData extends Data
public ?string $gender = null,
public ?string $birthdate = null,
public ?string $phone_number = null,
public ?string $inn = null,
public ?string $inn = null, // Individual Taxpayer Number (Russia)
// Add more claims as needed based on the response
) {}
// </SECTION>
}

View File

@@ -0,0 +1,14 @@
<?php
namespace Apoloz\AlfaBank\Data\B2B_1C;
use Spatie\LaravelData\Data;
class MerchantData extends Data
{
public function __construct(
public string $merchantId,
public string $name,
public ?string $status = null,
) {}
}

View File

@@ -0,0 +1,15 @@
<?php
namespace Apoloz\AlfaBank\Data\B2B_1C;
use Spatie\LaravelData\Data;
class Payment1CData extends Data
{
public function __construct(
public string $paymentId,
public float $amount,
public string $currency,
public string $status,
) {}
}

View File

@@ -0,0 +1,14 @@
<?php
namespace Apoloz\AlfaBank\Data\B2B_1C;
use Spatie\LaravelData\Data;
class PaymentLinkData extends Data
{
public function __construct(
public string $qrId,
public string $payload,
public ?string $imageUrl = null,
) {}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Apoloz\AlfaBank\Data\B2C;
use Spatie\LaravelData\Data;
class B2CClientData extends Data
{
public function __construct(
public string $b2cClientId,
public int $partnerId,
) {}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace Apoloz\AlfaBank\Data\B2C;
use Spatie\LaravelData\Data;
class B2CPaymentRecipientData extends Data
{
public function __construct(
public string $phone,
public float $amount,
public string $nspkBankId,
public string $sequence,
public ?array $name = null, // ['first' => '...', 'last' => '...', 'middle' => '...']
public ?string $paymentDescription = null,
) {}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace Apoloz\AlfaBank\Data\B2C;
use Spatie\LaravelData\Attributes\DataCollectionOf;
use Spatie\LaravelData\Data;
use Spatie\LaravelData\DataCollection;
class B2CPaymentRequestData extends Data
{
public function __construct(
public B2CClientData $client,
public string $inn,
public string $account,
public float $total,
public string $signedBody,
#[DataCollectionOf(B2CPaymentRecipientData::class)]
public DataCollection $payments,
public bool $nameCheck = true,
) {}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace Apoloz\AlfaBank\Data\B2C;
use Spatie\LaravelData\Attributes\DataCollectionOf;
use Spatie\LaravelData\Data;
use Spatie\LaravelData\DataCollection;
class B2CPaymentResponseData extends Data
{
public function __construct(
public string $status,
public ?string $transactionId = null,
) {}
}
class B2CPaymentReportData extends Data
{
public function __construct(
public array $payments = [],
) {}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Apoloz\AlfaBank\Data\Bonus;
use Spatie\LaravelData\Data;
class BonusNumberData extends Data
{
public function __construct(
public string $cardNumber,
public string $bonusType,
) {}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace Apoloz\AlfaBank\Data\Cards;
use Spatie\LaravelData\Data;
class CardData extends Data
{
public function __construct(
public string $cardId,
public string $maskedNumber,
public string $status,
public ?string $expirationDate = null,
public ?string $paymentSystem = null,
public ?string $title = null,
public ?bool $isVirtual = null,
public ?bool $isActive = null,
) {}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Apoloz\AlfaBank\Data\Claims;
use Spatie\LaravelData\Data;
class ClaimResolvedData extends Data
{
public function __construct(
public string $status,
public ?string $comment = null,
) {}
}

View File

@@ -0,0 +1,14 @@
<?php
namespace Apoloz\AlfaBank\Data\CloudSignature;
use Spatie\LaravelData\Data;
class CloudSignatureResponseData extends Data
{
public function __construct(
public string $id,
public ?string $type = null,
public ?string $status = null,
) {}
}

View File

@@ -0,0 +1,14 @@
<?php
namespace Apoloz\AlfaBank\Data\CloudSignature;
use Spatie\LaravelData\Data;
class UserDnData extends Data
{
public function __construct(
public string $dn,
public ?string $commonName = null,
public ?string $organization = null,
) {}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Apoloz\AlfaBank\Data\Compliance;
use Spatie\LaravelData\Data;
class UserComplianceData extends Data
{
public function __construct(
public bool $isCompliant,
public ?int $score = null,
) {}
}

View File

@@ -8,16 +8,8 @@ class CertificateData extends Data
{
public function __construct(
public string $id,
public string $clientId,
public string $ownerName,
public string $fingerprint,
public string $beginDateTime,
public string $expireDateTime,
public string $certificateBody,
public string $type,
public string $algorithm,
public string $serialNumber,
public ?string $organizationName = null,
public ?string $status = null,
public string $status,
public ?string $thumbprint = null,
) {}
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace Apoloz\AlfaBank\Data\CustomerInfo;
use Spatie\LaravelData\Data;
class CustomerInfoData extends Data
{
public function __construct(
public string $organizationId,
public string $fullName,
public string $shortName,
public string $inn,
public array $kpps,
public string $ogrn,
public ?string $okpo = null,
public ?string $registrationDate = null,
public ?string $phone = null,
public ?string $email = null,
public ?string $status = null,
) {}
}

View File

@@ -0,0 +1,14 @@
<?php
namespace Apoloz\AlfaBank\Data\DFA;
use Spatie\LaravelData\Data;
class DfaInitialPlacementData extends Data
{
public function __construct(
public string $id,
public string $title,
public ?string $description = null,
) {}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace Apoloz\AlfaBank\Data\DebitCards;
use Spatie\LaravelData\Data;
class DebitCardApplicationData extends Data
{
public function __construct(
public string $embossingName,
public string $firstName,
public string $lastName,
public string $middleName,
public string $mobilePhone,
public string $passportBirthDate,
public string $sex, // 'f' or 'm'
public bool $sopdConfirmed,
public ?string $email = null,
public ?string $previousFormId = null,
) {}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Apoloz\AlfaBank\Data\DebitCards;
use Spatie\LaravelData\Data;
class DebitCardApplicationResponseData extends Data
{
public function __construct(
public string $formId,
public string $status,
) {}
}

View File

@@ -0,0 +1,14 @@
<?php
namespace Apoloz\AlfaBank\Data\Escrow;
use Spatie\LaravelData\Data;
class EscrowOrderData extends Data
{
public function __construct(
public string $id,
public string $status,
public ?string $date = null,
) {}
}

View File

@@ -0,0 +1,18 @@
<?php
namespace Apoloz\AlfaBank\Data\Escrow;
use Spatie\LaravelData\Data;
class EscrowProjectData extends Data
{
public function __construct(
public string $projectNumber,
public string $commercialName,
public ?string $buildingPermitNumber = null,
public ?string $regionCode = null,
public ?string $settlement = null,
public ?string $city = null,
public ?string $area = null,
) {}
}

View File

@@ -1,15 +1,30 @@
<?php
/*
// MODULE_CONTRACT: Defines the data structure for the response of a file download request.
// RESPONSIBILITY: To hold and type-safely represent the links necessary to perform a file download.
// INPUTS: Raw JSON object from the API response.
// OUTPUTS: An object containing a collection of file download links.
// LINKS: Requests/FileExchange/DownloadFileRequest.php
*/
namespace Apoloz\AlfaBank\Data\FileExchange;
// <SECTION name="module_imports" intent="Import necessary DTOs and Spatie Laravel Data components.">
// <BELIEF_STATE "This DTO represents a collection of `FileLinkData` objects, so `DataCollectionOf` is used for type safety.">
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.">
// <BELIEF_STATE "This DTO provides a clear, type-safe contract for handling file download instructions, ensuring that the process of retrieving files is well-defined.">
class DownloadFileResponseData extends Data
{
// <SECTION name="constructor_properties" intent="Define the properties of the file download response.">
// <BELIEF_STATE "The response primarily contains a `downloadFileLinks` property, which is a collection of `FileLinkData` objects, each detailing how to access a part of the file or its signature.">
public function __construct(
#[DataCollectionOf(FileLinkData::class)]
public DataCollection $downloadFileLinks,
) {}
// </SECTION>
}

View File

@@ -1,14 +1,29 @@
<?php
/*
// MODULE_CONTRACT: Defines the data structure for a single file link, typically for upload or download.
// RESPONSIBILITY: To hold and type-safely represent the URL, HTTP method, and optional detached signature link for file operations.
// INPUTS: Raw JSON object or internal input.
// OUTPUTS: A structured object containing file link details.
// LINKS: DownloadFileResponseData.php, UploadFileResponseData.php
*/
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.">
// <BELIEF_STATE "This DTO provides a clear, type-safe contract for representing file access points, crucial for orchestrating multi-step file exchange processes.">
class FileLinkData extends Data
{
// <SECTION name="constructor_properties" intent="Define the properties of a file link.">
// <BELIEF_STATE "The constructor includes the `url` for access, the `method` (e.g., GET, PUT) to use with the URL, and an optional `detachedSignatureLink` for cases where a signature file might be fetched separately.">
public function __construct(
public string $url,
public string $method,
public ?FileLinkData $detachedSignatureLink = null,
public ?FileLinkData $detachedSignatureLink = null, // Nested link for signatures
) {}
// </SECTION>
}

View File

@@ -1,15 +1,30 @@
<?php
/*
// MODULE_CONTRACT: Defines the data structure for the response of a file upload request.
// RESPONSIBILITY: To hold and type-safely represent the links necessary to perform a file upload.
// INPUTS: Raw JSON object from the API response.
// OUTPUTS: An object containing a collection of file upload links.
// LINKS: Requests/FileExchange/UploadFileRequest.php
*/
namespace Apoloz\AlfaBank\Data\FileExchange;
// <SECTION name="module_imports" intent="Import necessary DTOs and Spatie Laravel Data components.">
// <BELIEF_STATE "This DTO represents a collection of `FileLinkData` objects, so `DataCollectionOf` is used for type safety.">
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.">
// <BELIEF_STATE "This DTO provides a clear, type-safe contract for handling file upload instructions, ensuring that the process of sending files is well-defined.">
class UploadFileResponseData extends Data
{
// <SECTION name="constructor_properties" intent="Define the properties of the file upload response.">
// <BELIEF_STATE "The response primarily contains an `uploadFileLinks` property, which is a collection of `FileLinkData` objects, each detailing how to upload a part of the file or its signature.">
public function __construct(
#[DataCollectionOf(FileLinkData::class)]
public DataCollection $uploadFileLinks,
) {}
// </SECTION>
}

View File

@@ -0,0 +1,17 @@
<?php
namespace Apoloz\AlfaBank\Data\Limits;
use Spatie\LaravelData\Data;
class LimitData extends Data
{
public function __construct(
public string $title,
public bool $isPersonal,
public mixed $max,
public mixed $rest,
public mixed $turnover,
public string $type,
) {}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace Apoloz\AlfaBank\Data\Limits;
use Spatie\LaravelData\Data;
class LimitDetailData extends Data
{
public function __construct(
public string $title,
public mixed $rest,
public mixed $max,
) {}
}
class LimitsResponseData extends Data
{
public function __construct(
public array $oneTime,
public array $day,
public array $month,
) {}
}

View File

@@ -0,0 +1,15 @@
<?php
namespace Apoloz\AlfaBank\Data\Loans;
use Spatie\LaravelData\Data;
class CreditOfferData extends Data
{
public function __construct(
public string $id,
public float $amount,
public string $status,
public ?string $description = null,
) {}
}

View File

@@ -0,0 +1,14 @@
<?php
namespace Apoloz\AlfaBank\Data\Logistics;
use Spatie\LaravelData\Data;
class DeliveryData extends Data
{
public function __construct(
public string $id,
public string $status,
public ?string $date = null,
) {}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace Apoloz\AlfaBank\Data\Logistics;
use Spatie\LaravelData\Data;
class LogisticsActionData extends Data
{
public function __construct(
public array $parameters = [],
) {}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Apoloz\AlfaBank\Data\Lounge;
use Spatie\LaravelData\Data;
class LoungeBalanceData extends Data
{
public function __construct(
public int $totalVisits,
public int $remainingVisits,
) {}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Apoloz\AlfaBank\Data\Loyalty;
use Spatie\LaravelData\Data;
class LoyaltyAccountData extends Data
{
public function __construct(
public string $type,
public string $number,
) {}
}

View File

@@ -0,0 +1,14 @@
<?php
namespace Apoloz\AlfaBank\Data\Loyalty;
use Spatie\LaravelData\Data;
class LoyaltyFilterData extends Data
{
public function __construct(
public string $startDate,
public string $endDate,
public array $references = [],
) {}
}

View File

@@ -0,0 +1,15 @@
<?php
namespace Apoloz\AlfaBank\Data\Loyalty;
use Spatie\LaravelData\Data;
class LoyaltyTransactionData extends Data
{
public function __construct(
public string $id,
public float $amount,
public string $date,
public ?string $description = null,
) {}
}

View File

@@ -1,14 +1,29 @@
<?php
/*
// MODULE_CONTRACT: Defines the data structure for an address.
// RESPONSIBILITY: To hold and type-safely represent address details.
// INPUTS: Raw JSON object from the API response or internal input.
// OUTPUTS: A structured object containing address information.
// LINKS: CreateBeneficiaryRequestData.php (uses this DTO)
*/
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.">
// <BELIEF_STATE "This DTO provides a clear, type-safe contract for address data, ensuring consistency whenever address information is exchanged.">
class AddressData extends Data
{
// <SECTION name="constructor_properties" intent="Define the properties of an address.">
// <BELIEF_STATE "The constructor captures the `type` of address (e.g., legal, postal), the `address` string itself, and an optional `country`.">
public function __construct(
public string $type,
public string $address,
public ?string $country = null,
) {}
// </SECTION>
}

View File

@@ -1,13 +1,27 @@
<?php
/*
// MODULE_CONTRACT: Defines the data structure for a specific beneficiary's balance.
// RESPONSIBILITY: To hold and type-safely represent the financial balance details of a beneficiary for a given account and date.
// INPUTS: Raw JSON object from the API response.
// OUTPUTS: A structured object containing beneficiary balance information.
// LINKS: Requests/NominalAccounts/Beneficiaries/GetBeneficiaryBalanceRequest.php
*/
namespace Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries;
// <SECTION name="module_imports" intent="Import necessary DTOs and Spatie Laravel Data components.">
// <BELIEF_STATE "This DTO represents a balance which can be composed of multiple `WalletBalanceData` objects. `DataCollectionOf` is essential for auto-casting.">
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.">
// <BELIEF_STATE "A dedicated DTO ensures the balance information is always accessed in a type-safe and consistent manner, preventing common errors when dealing with financial data.">
class BeneficiaryBalanceData extends Data
{
// <SECTION name="constructor_properties" intent="Define the properties related to a beneficiary's balance.">
// <BELIEF_STATE "Properties like `beneficiaryId`, `accountNumber`, and `date` are key identifiers for the balance. The `balances` property is a collection of `WalletBalanceData`, enabling a detailed breakdown of the balance across different wallet types.">
public function __construct(
public string $beneficiaryId,
public string $accountNumber,
@@ -15,4 +29,5 @@ class BeneficiaryBalanceData extends Data
#[DataCollectionOf(WalletBalanceData::class)]
public ?DataCollection $balances = null,
) {}
// </SECTION>
}

View File

@@ -1,17 +1,33 @@
<?php
/*
// MODULE_CONTRACT: Defines a paginated collection of beneficiary transaction data.
// RESPONSIBILITY: To provide a strongly-typed, paginatable structure for lists of transactions associated with a beneficiary, integrating pagination metadata and a collection of individual transaction DTOs.
// INPUTS: Raw array data representing a paginated list of beneficiary transactions from the API.
// OUTPUTS: An instantiated DTO containing pagination metadata and a `DataCollection` of `BeneficiaryTransactionData` objects.
// LINKS: Data/PaginationData.php, Data/NominalAccounts/Beneficiaries/BeneficiaryTransactionData.php, Requests/NominalAccounts/Beneficiaries/GetBeneficiaryTransactionsRequest.php
*/
namespace Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries;
// <SECTION name="module_imports" intent="Import necessary classes for pagination, data collection, and Laravel Data.">
// <BELIEF_STATE "These imports are crucial for constructing a robust paginated data structure. `PaginationData` brings in metadata for navigation, `DataCollectionOf` and `DataCollection` enable type-safe handling of multiple transaction items, and `Data` provides the foundational capabilities for data object mapping.">
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.">
// <BELIEF_STATE "The `BeneficiaryTransactionCollectionData` DTO is designed to encapsulate both the list of `BeneficiaryTransactionData` and their associated pagination information. This promotes a consistent and easy-to-use structure when dealing with potentially large sets of transaction data, enhancing developer experience by providing structured access to both data and metadata.">
class BeneficiaryTransactionCollectionData extends Data
{
// <SECTION name="constructor_properties" intent="Define the properties of the paginated collection DTO.">
// <BELIEF_STATE "The constructor uses PHP 8's property promotion to define `pagination` for metadata and `transactionsList` for the actual transaction items. `@DataCollectionOf` ensures that `transactionsList` is a type-safe collection of `BeneficiaryTransactionData` objects, enforcing data integrity and predictability. Both are nullable to handle cases where no transactions are found or pagination info is absent.">
public function __construct(
public ?PaginationData $pagination = null,
#[DataCollectionOf(BeneficiaryTransactionData::class)]
public ?DataCollection $transactionsList = null,
) {}
// </SECTION>
}
// </SECTION>

View File

@@ -1,14 +1,30 @@
<?php
/*
// MODULE_CONTRACT: Defines the data structure for a single beneficiary transaction record.
// RESPONSIBILITY: To provide a strongly-typed structure for individual transaction details related to a beneficiary, ensuring consistency and ease of consumption for API responses.
// INPUTS: Raw array data representing a single beneficiary transaction from the API.
// OUTPUTS: An instantiated DTO with properties mapped from the input array.
// LINKS: Data/NominalAccounts/Beneficiaries/BeneficiaryTransactionCollectionData.php
*/
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.">
// <BELIEF_STATE "The `BeneficiaryTransactionData` DTO encapsulates the core details of a single transaction. It defines essential properties like `type` and `amount` as mandatory, while `comment` is optional, reflecting the common structure of transaction records.">
class BeneficiaryTransactionData extends Data
{
// <SECTION name="constructor_properties" intent="Define the properties of the transaction DTO.">
// <BELIEF_STATE "Properties are defined directly in the constructor for conciseness and immutability. `type` and `amount` are crucial for any transaction and are thus required. `comment` is nullable as it may not always be present in transaction records.">
public function __construct(
public string $type,
public string $amount,
public ?string $comment = null,
) {}
// </SECTION>
}
// </SECTION>

View File

@@ -1,14 +1,28 @@
<?php
/*
// MODULE_CONTRACT: Defines the data structure for the request payload when creating a new beneficiary.
// RESPONSIBILITY: To hold and validate all necessary information for beneficiary registration, including personal details, addresses, and signatures.
// INPUTS: Raw data array for beneficiary details.
// OUTPUTS: A structured, type-safe object for the `CreateBeneficiaryRequest` payload.
// LINKS: Requests/NominalAccounts/Beneficiaries/CreateBeneficiaryRequest.php
*/
namespace Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries;
// <SECTION name="module_imports" intent="Import necessary DTOs and Spatie Laravel Data components for complex nested data structures.">
// <BELIEF_STATE "This DTO has several nested DTOs and collections (`AddressData`, `DigestSignatureData`, `DocumentData`, `PersonalInformationData`). `DataCollectionOf` and `Data` ensure that these are all correctly typed and mapped.">
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 a DTO for creating a new beneficiary.">
// <BELIEF_STATE "This DTO serves as a robust contract for the complex payload required to create a beneficiary. Type-safety here prevents malformed requests from even being constructed.">
class CreateBeneficiaryRequestData extends Data
{
// <SECTION name="constructor_properties" intent="Define all properties for the beneficiary creation request, including nested DTOs and collections.">
// <BELIEF_STATE "The constructor meticulously lists all possible fields, making it clear what data is expected. Mandatory fields are non-nullable, while optional ones are nullable. Collections like `addresses` and `digestSignatures` are type-hinted with `DataCollection` and use `#[DataCollectionOf]` to ensure each item is itself a DTO.">
public function __construct(
public string $type,
public string $countryOfTaxResidence,
@@ -31,4 +45,5 @@ class CreateBeneficiaryRequestData extends Data
#[DataCollectionOf(DocumentData::class)]
public ?DataCollection $documents = null,
) {}
// </SECTION>
}

View File

@@ -1,13 +1,28 @@
<?php
/*
// MODULE_CONTRACT: Defines the data structure for the response when creating a new beneficiary.
// RESPONSIBILITY: To provide a structured, type-safe object representing the outcome of a beneficiary creation request.
// INPUTS: Raw JSON object from the API response.
// OUTPUTS: An object containing the request ID and status of the creation operation.
// LINKS: Requests/NominalAccounts/Beneficiaries/CreateBeneficiaryRequest.php
*/
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.">
// <BELIEF_STATE "This DTO provides a clear, type-safe contract for the API's response to a beneficiary creation request, allowing developers to easily access the `requestId` and `status`.">
class CreateBeneficiaryResponseData extends Data
{
// <SECTION name="constructor_properties" intent="Define the properties of the beneficiary creation response.">
// <BELIEF_STATE "The response primarily contains a `requestId` for tracking the operation and a `status` indicating its immediate outcome.">
public function __construct(
public string $requestId,
public string $status,
) {}
// </SECTION>
}

View File

@@ -1,11 +1,25 @@
<?php
/*
// MODULE_CONTRACT: Defines the data structure for an identification document.
// RESPONSIBILITY: To hold and type-safely represent details of a document like passport or ID card.
// INPUTS: Raw JSON object from the API response or internal input.
// OUTPUTS: A structured object containing document information.
// LINKS: CreateBeneficiaryRequestData.php (uses this DTO)
*/
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.">
// <BELIEF_STATE "This DTO provides a clear, type-safe contract for document data, critical for KYC (Know Your Customer) and AML (Anti-Money Laundering) compliance.">
class DocumentData extends Data
{
// <SECTION name="constructor_properties" intent="Define the properties of an identification document.">
// <BELIEF_STATE "The constructor includes fields common to identification documents, such as `type`, `number`, `issueDate`, and `organization`. Optional fields allow flexibility for various document types.">
public function __construct(
public string $type,
public string $number,
@@ -15,4 +29,5 @@ class DocumentData extends Data
public ?string $expireDate = null,
public ?string $division = null,
) {}
// </SECTION>
}

View File

@@ -1,11 +1,25 @@
<?php
/*
// MODULE_CONTRACT: Defines the data structure for a beneficiary's personal identification information.
// RESPONSIBILITY: To hold and type-safely represent an individual's personal details like name, INN, birthdate, etc.
// INPUTS: Raw JSON object from the API response or internal input.
// OUTPUTS: A structured object containing personal information.
// LINKS: CreateBeneficiaryRequestData.php (uses this DTO)
*/
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.">
// <BELIEF_STATE "This DTO provides a clear, type-safe contract for personal information, ensuring consistency and validation when handling sensitive data.">
class PersonalInformationData extends Data
{
// <SECTION name="constructor_properties" intent="Define the properties of an individual's personal information.">
// <BELIEF_STATE "The constructor includes common personal identifiers. All fields are marked as nullable, indicating they might be optional depending on the specific beneficiary type or API call. This flexibility is important when dealing with diverse data requirements.">
public function __construct(
public ?string $inn = null,
public ?string $firstName = null,
@@ -16,4 +30,5 @@ class PersonalInformationData extends Data
public ?string $birthPlace = null,
public ?string $snils = null,
) {}
// </SECTION>
}

View File

@@ -1,14 +1,28 @@
<?php
/*
// MODULE_CONTRACT: Defines the data structure for the request payload when creating a new requisite.
// RESPONSIBILITY: To hold and validate all necessary information for registering a new payment requisite for a beneficiary.
// INPUTS: Payment type, digest signatures, and various optional requisite details (PAN, account number, phone, etc.).
// OUTPUTS: A structured, type-safe object for the `AddRequisiteRequest` payload.
// LINKS: Requests/NominalAccounts/Beneficiaries/Requisites/AddRequisiteRequest.php
*/
namespace Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries\Requisites;
// <SECTION name="module_imports" intent="Import necessary DTOs and Spatie Laravel Data components.">
// <BELIEF_STATE "This DTO requires `DigestSignatureData` as a collection for security, utilizing `DataCollectionOf` for type safety.">
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 a DTO for creating a new requisite.">
// <BELIEF_STATE "This DTO ensures the request payload for creating a requisite is strictly typed and complete, preventing malformed requests for a critical financial operation.">
class CreateRequisiteRequestData extends Data
{
// <SECTION name="constructor_properties" intent="Define all properties for the requisite creation request.">
// <BELIEF_STATE "The constructor includes mandatory fields like `type` and `digestSignatures`. Optional fields cover various payment methods (`pan`, `phoneNumber`, `accountNumber`) and identifiers (`bankId`, `bik`, `name`, `inn`, `kpp`, `beneficiaryId`, `isMain`).">
public function __construct(
public string $type,
#[DataCollectionOf(DigestSignatureData::class)]
@@ -24,4 +38,5 @@ class CreateRequisiteRequestData extends Data
public ?string $kpp = null,
public ?bool $isMain = null,
) {}
// </SECTION>
}

View File

@@ -1,16 +1,30 @@
<?php
/*
// MODULE_CONTRACT: Defines the data structure for a single payment requisite.
// RESPONSIBILITY: To hold and type-safely represent the details of a registered payment method (e.g., bank account, card, phone).
// INPUTS: Raw JSON object from the API response.
// OUTPUTS: A structured object containing requisite details.
// LINKS: Requests/NominalAccounts/Beneficiaries/Requisites/GetRequisitesRequest.php
*/
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.">
// <BELIEF_STATE "This DTO provides a clear, type-safe contract for requisite data, crucial for managing payment methods reliably.">
class RequisiteData extends Data
{
// <SECTION name="constructor_properties" intent="Define the properties of a payment requisite.">
// <BELIEF_STATE "The constructor includes a mix of mandatory (`type`, `isMain`, `isActive`) and optional fields (`id`, `pan`, `phoneNumber`, `accountNumber`, `bankId`, `bik`, `name`, `inn`, `kpp`). These fields describe the payment method and its current status.">
public function __construct(
public ?string $id = null,
public string $type,
public bool $isMain,
public bool $isActive,
public ?string $id = null, // Requisite ID might be generated on creation
public ?string $pan = null,
public ?string $phoneNumber = null,
public ?string $bankId = null,
@@ -20,4 +34,5 @@ class RequisiteData extends Data
public ?string $inn = null,
public ?string $kpp = null,
) {}
// </SECTION>
}

View File

@@ -1,19 +1,33 @@
<?php
/*
// MODULE_CONTRACT: Defines the data structure for the request payload when updating an existing requisite.
// RESPONSIBILITY: To hold and validate necessary information for modifying a payment requisite.
// INPUTS: Digest signatures, and various optional requisite details (PAN, account number, phone, etc.).
// OUTPUTS: A structured, type-safe object for the `UpdateRequisiteRequest` payload.
// LINKS: Requests/NominalAccounts/Beneficiaries/Requisites/UpdateRequisiteRequest.php
*/
namespace Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries\Requisites;
// <SECTION name="module_imports" intent="Import necessary DTOs and Spatie Laravel Data components.">
// <BELIEF_STATE "This DTO requires `DigestSignatureData` as a collection for security, utilizing `DataCollectionOf` for type safety.">
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 a DTO for updating an existing requisite.">
// <BELIEF_STATE "This DTO ensures the request payload for updating a requisite is strictly typed and complete, supporting partial updates through nullable fields.">
class UpdateRequisiteRequestData extends Data
{
// <SECTION name="constructor_properties" intent="Define all properties for the requisite update request.">
// <BELIEF_STATE "The constructor includes mandatory `digestSignatures` for security. Optional fields allow for specific updates to `pan`, `keyId`, `phoneNumber`, `bankId`, `accountNumber`, `bik`, `isMain` status, and `isActive` status. The flexibility with nullable fields allows partial updates.">
public function __construct(
#[DataCollectionOf(DigestSignatureData::class)]
public DataCollection $digestSignatures,
public ?string $pan = null,
public ?string $keyId = null,
public ?string $keyId = null, // Specific identifier for some requisite types
public ?string $phoneNumber = null,
public ?string $bankId = null,
public ?string $accountNumber = null,
@@ -21,4 +35,5 @@ class UpdateRequisiteRequestData extends Data
public ?bool $isMain = null,
public ?bool $isActive = null,
) {}
// </SECTION>
}

View File

@@ -1,14 +1,28 @@
<?php
/*
// MODULE_CONTRACT: Defines the data structure for the request payload when updating an existing beneficiary.
// RESPONSIBILITY: To hold and validate all necessary information for updating a beneficiary, including partial changes.
// INPUTS: Raw data array for updated beneficiary details.
// OUTPUTS: A structured, type-safe object for the `UpdateBeneficiaryRequest` payload.
// LINKS: Requests/NominalAccounts/Beneficiaries/UpdateBeneficiaryRequest.php
*/
namespace Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries;
// <SECTION name="module_imports" intent="Import necessary DTOs and Spatie Laravel Data components.">
// <BELIEF_STATE "This DTO handles complex nested structures (`DigestSignatureData`, `AddressData`, `DocumentData`, `PersonalInformationData`), requiring `DataCollectionOf` for typed arrays.">
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 a DTO for updating an existing beneficiary.">
// <BELIEF_STATE "This DTO provides a robust contract for updating beneficiary details. By making most fields nullable, it supports partial updates (PATCH-like behavior) even if the API uses PUT.">
class UpdateBeneficiaryRequestData extends Data
{
// <SECTION name="constructor_properties" intent="Define all properties for the beneficiary update request, including nested DTOs and collections.">
// <BELIEF_STATE "Similar to `CreateBeneficiaryRequestData`, this constructor lists all updatable fields. Mandatory fields are `type` and `digestSignatures`. Most other fields are nullable to allow for partial updates, reflecting the flexibility often needed in update operations.">
public function __construct(
public string $type,
#[DataCollectionOf(DigestSignatureData::class)]
@@ -24,4 +38,5 @@ class UpdateBeneficiaryRequestData extends Data
public ?DataCollection $documents = null,
public ?bool $isActive = null,
) {}
// </SECTION>
}

View File

@@ -1,14 +1,29 @@
<?php
/*
// MODULE_CONTRACT: Defines the data structure for a specific wallet's balance.
// RESPONSIBILITY: To hold and type-safely represent the free and held amounts within a financial wallet.
// INPUTS: Raw JSON object from the API response.
// OUTPUTS: A structured object containing wallet balance details.
// LINKS: BeneficiaryBalanceData.php (uses this DTO)
*/
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.">
// <BELIEF_STATE "This DTO provides a precise, type-safe contract for individual wallet balances, distinguishing between funds that are `free` (available) and `held` (blocked).">
class WalletBalanceData extends Data
{
// <SECTION name="constructor_properties" intent="Define the properties of a wallet balance.">
// <BELIEF_STATE "The constructor captures the `walletType` (e.g., nominal, tax), the `freeBalance` (funds available for use), and the `heldBalance` (funds currently blocked or reserved). This granular detail is crucial for financial applications.">
public function __construct(
public string $walletType,
public string $freeBalance,
public string $heldBalance,
) {}
// </SECTION>
}

View File

@@ -1,18 +1,33 @@
<?php
/*
// MODULE_CONTRACT: Represents a paginated collection of BeneficiaryData objects.
// RESPONSIBILITY: To provide a structured, type-safe container for lists of beneficiaries returned by the API, including pagination metadata.
// INPUTS: Raw JSON array from the API response.
// OUTPUTS: An object containing pagination details and a collection of `BeneficiaryData`.
// LINKS: Requests/NominalAccounts/Beneficiaries/GetBeneficiariesRequest.php
*/
namespace Apoloz\AlfaBank\Data\NominalAccounts;
// <SECTION name="module_imports" intent="Import necessary DTOs and Spatie Laravel Data components.">
// <BELIEF_STATE "This collection DTO relies on `PaginationData` for metadata and `BeneficiaryData` for the individual items. `DataCollection` and `DataCollectionOf` are Spatie Data features for handling typed arrays of DTOs.">
use Apoloz\AlfaBank\Data\PaginationData;
use Spatie\LaravelData\Data;
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.">
// <BELIEF_STATE "A dedicated DTO for a collection ensures that the structure of paginated lists is consistent and type-safe, providing a reliable contract for consumers.">
class BeneficiaryCollectionData extends Data
{
// <SECTION name="constructor_properties" intent="Define the properties of the beneficiary collection.">
// <BELIEF_STATE "The collection structure includes pagination metadata (`pagination`), the associated `accountNumber`, and the actual list of beneficiaries (`beneficiaries`). The `#[DataCollectionOf(BeneficiaryData::class)]` attribute is crucial for ensuring that each item in the `beneficiaries` array is automatically cast to a `BeneficiaryData` DTO.">
public function __construct(
public PaginationData $pagination,
public string $accountNumber,
#[DataCollectionOf(BeneficiaryData::class)]
public DataCollection $beneficiaries
) {}
// </SECTION>
}

View File

@@ -1,18 +1,32 @@
<?php
/*
// MODULE_CONTRACT: Defines the core data structure for a single beneficiary.
// RESPONSIBILITY: To hold and type-safely represent all attributes of a beneficiary, as returned by the API.
// INPUTS: Raw JSON object from the API response.
// OUTPUTS: A structured object containing beneficiary details.
// LINKS: BeneficiaryCollectionData.php
*/
namespace Apoloz\AlfaBank\Data\NominalAccounts;
use Apoloz\AlfaBank\Data\PaginationData;
use Spatie\LaravelData\Data;
// <SECTION name="module_imports" intent="Import necessary DTOs and Spatie Laravel Data components.">
// <BELIEF_STATE "This DTO may contain nested DTOs (e.g., for personal information, addresses, documents) or simple arrays, requiring appropriate Spatie Data attributes if they were themselves DTOs. It also references `PaginationData` due to a namespace mismatch in the original, but this file is primarily about the single beneficiary.">
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.">
// <BELIEF_STATE "This DTO provides a comprehensive, type-safe representation of a beneficiary, which is essential for consistent data handling across the SDK.">
class BeneficiaryData extends Data
{
// <SECTION name="constructor_properties" intent="Define all properties that describe a beneficiary.">
// <BELIEF_STATE "The constructor includes a wide range of properties covering identification, personal information, contact details, and status. While some are typed as `array` here, in a more refined design, these would likely be nested DTOs (e.g., `PersonalInformationData`, `AddressData`). The `isBeneficiary` and `isVpr` flags represent specific statuses or roles.">
public function __construct(
public string $beneficiaryId,
public string $type,
public ?array $personalInformation = null,
public ?array $personalInformation = null, // Could be PersonalInformationData DTO
public ?string $inn = null,
public ?string $firstName = null,
public ?string $lastName = null,
@@ -21,11 +35,12 @@ class BeneficiaryData extends Data
public ?string $countryOfTaxResidence = null,
public ?string $phoneNumber = null,
public ?string $email = null,
public ?array $addresses = null,
public ?array $documents = null,
public ?array $addresses = null, // Could be DataCollectionOf(AddressData::class)
public ?array $documents = null, // Could be DataCollectionOf(DocumentData::class)
public ?bool $isActive = null,
public ?array $balances = null,
public ?array $balances = null, // Could be DataCollectionOf(WalletBalanceData::class)
public ?bool $isBeneficiary = null,
public ?bool $isVpr = null,
) {}
// </SECTION>
}

View File

@@ -1,11 +1,25 @@
<?php
/*
// MODULE_CONTRACT: Defines the data structure for the status of a counterparty-related request.
// RESPONSIBILITY: To hold and type-safely represent the outcome and details of an asynchronous operation involving counterparties (beneficiaries or universal recipients).
// INPUTS: Raw JSON object from the API response.
// OUTPUTS: A structured object containing request status information.
// LINKS: Requests/NominalAccounts/GetCounterpartyRequestStatusRequest.php
*/
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.">
// <BELIEF_STATE "This DTO provides a clear, type-safe contract for tracking the status of asynchronous operations, which is common in complex banking APIs.">
class CounterpartyRequestStatusData extends Data
{
// <SECTION name="constructor_properties" intent="Define the properties of a counterparty request status.">
// <BELIEF_STATE "The `requestId` and `status` are fundamental for tracking any asynchronous operation. Optional fields like `beneficiaryId`, `universalRecipientId`, `description`, and `resultData` provide granular details about the outcome and associated entities.">
public function __construct(
public string $requestId,
public string $status,
@@ -14,4 +28,5 @@ class CounterpartyRequestStatusData extends Data
public ?string $description = null,
public ?string $resultData = null,
) {}
// </SECTION>
}

View File

@@ -1,17 +1,32 @@
<?php
/*
// MODULE_CONTRACT: Defines the data structure for a paginated collection of DealData objects.
// RESPONSIBILITY: To provide a structured, type-safe container for lists of deals returned by the API, including pagination metadata.
// INPUTS: Raw JSON array from the API response.
// OUTPUTS: An object containing pagination details and a collection of `DealData`.
// LINKS: Requests/NominalAccounts/Deals/GetDealsRequest.php
*/
namespace Apoloz\AlfaBank\Data\NominalAccounts\Deals;
// <SECTION name="module_imports" intent="Import necessary DTOs and Spatie Laravel Data components.">
// <BELIEF_STATE "This collection DTO relies on `PaginationData` for metadata and `DealData` for the individual items. `DataCollection` and `DataCollectionOf` are Spatie Data features for handling typed arrays of DTOs.">
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.">
// <BELIEF_STATE "A dedicated DTO for a collection ensures that the structure of paginated lists is consistent and type-safe, providing a reliable contract for consumers to manage deals.">
class DealCollectionData extends Data
{
// <SECTION name="constructor_properties" intent="Define the properties of the deal collection.">
// <BELIEF_STATE "The collection structure includes pagination metadata (`pagination`) and the actual list of deals (`deals`). The `#[DataCollectionOf(DealData::class)]` attribute is crucial for ensuring that each item in the `deals` array is automatically cast to a `DealData` DTO.">
public function __construct(
public PaginationData $pagination,
#[DataCollectionOf(DealData::class)]
public DataCollection $deals
) {}
// </SECTION>
}

View File

@@ -1,15 +1,30 @@
<?php
/*
// MODULE_CONTRACT: Defines the data structure for a single deal.
// RESPONSIBILITY: To hold and type-safely represent the core attributes of a deal, such as its ID, status, and expiration.
// INPUTS: Raw JSON object from the API response.
// OUTPUTS: A structured object containing deal details.
// LINKS: DealCollectionData.php, Requests/NominalAccounts/Deals/GetDealRequest.php
*/
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.">
// <BELIEF_STATE "This DTO provides a comprehensive, type-safe representation of a deal, essential for consistent data handling across the SDK.">
class DealData extends Data
{
// <SECTION name="constructor_properties" intent="Define all properties that describe a deal.">
// <BELIEF_STATE "The constructor includes mandatory fields such as `dealId` (unique identifier), `status` (current state), `expireDate`, and `isValid` (indicating payment readiness).">
public function __construct(
public string $dealId,
public string $status,
public string $expireDate,
public bool $isValid,
) {}
// </SECTION>
}

View File

@@ -1,11 +1,25 @@
<?php
/*
// MODULE_CONTRACT: Defines the data structure for a single payoff within a deal.
// RESPONSIBILITY: To hold and type-safely represent a specific payment made as part of a deal.
// INPUTS: Raw JSON object from the API response.
// OUTPUTS: A structured object containing deal payoff details.
// LINKS: Requests/NominalAccounts/Deals/GetDealPayoffsRequest.php
*/
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.">
// <BELIEF_STATE "This DTO provides a clear, type-safe contract for individual payment records related to a deal, crucial for tracking financial flows within deals.">
class DealPayoffData extends Data
{
// <SECTION name="constructor_properties" intent="Define the properties of a deal payoff.">
// <BELIEF_STATE "The constructor includes key identifiers like `stepId`, `payoffId`, `payoffType`, `deponentId`, `recipientId`, and financial details (`amount`, `status`). These fields are essential for understanding the specific payment within the context of a deal.">
public function __construct(
public string $stepId,
public string $payoffId,
@@ -15,4 +29,5 @@ class DealPayoffData extends Data
public string $amount,
public string $status,
) {}
// </SECTION>
}

View File

@@ -1,14 +1,29 @@
<?php
/*
// MODULE_CONTRACT: Defines the data structure for the status of a deal-related request.
// RESPONSIBILITY: To hold and type-safely represent the outcome and details of an asynchronous operation related to deals.
// INPUTS: Raw JSON object from the API response.
// OUTPUTS: A structured object containing request status information.
// LINKS: Requests/NominalAccounts/Deals/GetDealRequestStatusRequest.php
*/
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.">
// <BELIEF_STATE "This DTO provides a clear, type-safe contract for tracking the status of asynchronous deal operations, which is common for complex business processes.">
class DealRequestStatusData extends Data
{
// <SECTION name="constructor_properties" intent="Define the properties of a deal request status.">
// <BELIEF_STATE "The `requestId` and `status` are fundamental for tracking any asynchronous operation. An optional `description` can provide further details about the status.">
public function __construct(
public string $requestId,
public string $status,
public ?string $description = null,
) {}
// </SECTION>
}

View File

@@ -1,16 +1,30 @@
<?php
/*
// MODULE_CONTRACT: Defines the data structure for the request payload to perform an action on a deal contractor.
// RESPONSIBILITY: To hold and validate all necessary information for actions such as adding or managing contractors within a deal step.
// INPUTS: Action type, deal ID, step ID, beneficiary ID, signatures, and optional financial details.
// OUTPUTS: A structured, type-safe object for the `ManageContractorRequest` payload.
// LINKS: Requests/NominalAccounts/Deals/Steps/ManageContractorRequest.php
*/
namespace Apoloz\AlfaBank\Data\NominalAccounts\Deals\Steps;
// <SECTION name="module_imports" intent="Import necessary DTOs and Spatie Laravel Data components for complex nested data structures.">
// <BELIEF_STATE "This DTO orchestrates several other DTOs and collections (`DigestSignatureData`, `ContractorAmountData`), requiring `DataCollectionOf` for typed arrays.">
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 a DTO for performing an action on a deal contractor.">
// <BELIEF_STATE "This DTO provides a robust contract for managing contractors within deal steps. It ensures that critical financial and security-related data is strictly typed and correctly structured for actions like adding funds or changing status.">
class ContractorActionRequestData extends Data
{
// <SECTION name="constructor_properties" intent="Define all properties for the contractor action request.">
// <BELIEF_STATE "The constructor includes mandatory fields like `action`, `dealId`, `stepId`, `beneficiaryId`, and `digestSignatures`. Optional fields like `amount`, `purpose`, `amounts` (for detailed distribution), `keepOnNominalAccount`, and `requisiteId` provide flexibility for various contractor management scenarios.">
public function __construct(
public string $action,
public string $action, // e.g., ADD_AMOUNT, REMOVE_AMOUNT, SET_REQUISITE
public string $dealId,
public string $stepId,
public string $beneficiaryId,
@@ -19,8 +33,9 @@ class ContractorActionRequestData extends Data
public ?string $amount = null,
public ?string $purpose = null,
#[DataCollectionOf(ContractorAmountData::class)]
public ?DataCollection $amounts = null,
public ?DataCollection $amounts = null, // For detailed amount distribution
public ?bool $keepOnNominalAccount = null,
public ?string $requisiteId = null,
) {}
// </SECTION>
}

View File

@@ -1,13 +1,28 @@
<?php
/*
// MODULE_CONTRACT: Defines the data structure for a specific amount allocated to a contractor's wallet.
// RESPONSIBILITY: To hold and type-safely represent an amount designated for a particular wallet type (e.g., nominal, tax).
// INPUTS: Raw JSON object or internal input.
// OUTPUTS: A structured object containing amount and wallet type.
// LINKS: ContractorActionRequestData.php (uses this DTO)
*/
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.">
// <BELIEF_STATE "This DTO provides a precise, type-safe contract for specifying how funds are distributed across different wallet types for a contractor within a deal step, ensuring granular control over financial flows.">
class ContractorAmountData extends Data
{
// <SECTION name="constructor_properties" intent="Define the properties of a contractor amount allocation.">
// <BELIEF_STATE "The constructor includes optional fields for `walletType` (e.g., 'NOMINAL', 'TAX') and the `amount` to be allocated. Both are optional to allow for flexible usage, potentially being part of a larger distribution scheme where these properties might be inferred or contextually dependent.">
public function __construct(
public ?string $walletType = null,
public ?string $amount = null,
) {}
// </SECTION>
}

View File

@@ -1,20 +1,35 @@
<?php
/*
// MODULE_CONTRACT: Defines the data structure for the request payload to perform an action on a deal step.
// RESPONSIBILITY: To hold and validate all necessary information for actions such as completing or canceling a step within a deal.
// INPUTS: Deal ID, action type, signatures, and optional step ID and description.
// OUTPUTS: A structured, type-safe object for the `ManageStepRequest` payload.
// LINKS: Requests/NominalAccounts/Deals/Steps/ManageStepRequest.php
*/
namespace Apoloz\AlfaBank\Data\NominalAccounts\Deals\Steps;
// <SECTION name="module_imports" intent="Import necessary DTOs and Spatie Laravel Data components.">
// <BELIEF_STATE "This DTO requires `DigestSignatureData` as a collection for security, utilizing `DataCollectionOf` for type safety.">
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 a DTO for performing an action on a deal step.">
// <BELIEF_STATE "This DTO provides a robust contract for managing the lifecycle of deal steps. It ensures that critical operational and security data is strictly typed and correctly structured for actions like completion or cancellation.">
class StepActionRequestData extends Data
{
// <SECTION name="constructor_properties" intent="Define all properties for the step action request.">
// <BELIEF_STATE "The constructor includes mandatory fields like `dealId`, `action` (e.g., 'COMPLETE', 'CANCEL'), and `digestSignatures`. Optional fields like `stepId` (if targeting a specific step within the deal) and `description` provide flexibility and context for the action.">
public function __construct(
public string $dealId,
public string $action,
public string $action, // e.g., COMPLETE, CANCEL
#[DataCollectionOf(DigestSignatureData::class)]
public DataCollection $digestSignatures,
public ?string $stepId = null,
public ?string $description = null,
) {}
// </SECTION>
}

View File

@@ -1,11 +1,25 @@
<?php
/*
// MODULE_CONTRACT: Defines the data structure for the response of a step action request within a deal.
// RESPONSIBILITY: To hold and type-safely represent the outcome and status of an action performed on a deal step.
// INPUTS: Raw JSON object from the API response.
// OUTPUTS: A structured object containing step action status information.
// LINKS: Requests/NominalAccounts/Deals/Steps/ManageStepRequest.php
*/
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.">
// <BELIEF_STATE "This DTO provides a clear, type-safe contract for tracking the status of actions performed on deal steps, which can be asynchronous operations.">
class StepActionResponseData extends Data
{
// <SECTION name="constructor_properties" intent="Define the properties of a step action response.">
// <BELIEF_STATE "The constructor includes key identifiers such as `dealId`, `stepId`, `stepNumber`, and `requestId`. The `status` and `description` provide details about the action's outcome. All fields are optional to accommodate various response scenarios.">
public function __construct(
public ?string $dealId = null,
public ?string $stepId = null,
@@ -14,4 +28,5 @@ class StepActionResponseData extends Data
public ?string $status = null,
public ?string $requestId = null,
) {}
// </SECTION>
}

View File

@@ -1,13 +1,27 @@
<?php
/*
// MODULE_CONTRACT: Defines the data structure for a contractor associated with a deal step.
// RESPONSIBILITY: To hold and type-safely represent details of a beneficiary acting as a contractor within a specific deal step.
// INPUTS: Raw JSON object from the API response.
// OUTPUTS: A structured object containing contractor details for a deal step.
// LINKS: Requests/NominalAccounts/Deals/Steps/GetStepContractorsRequest.php
*/
namespace Apoloz\AlfaBank\Data\NominalAccounts\Deals\Steps;
// <SECTION name="module_imports" intent="Import necessary DTOs and Spatie Laravel Data components.">
// <BELIEF_STATE "This DTO uses `ContractorAmountData` within a collection, requiring `DataCollectionOf` for type safety.">
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.">
// <BELIEF_STATE "This DTO provides a clear, type-safe contract for contractor details, including their role, associated amounts, and other relevant information within the context of a deal step.">
class StepContractorData extends Data
{
// <SECTION name="constructor_properties" intent="Define the properties of a step contractor.">
// <BELIEF_STATE "The constructor includes the `beneficiaryId`, `role` (e.g., 'DEBTOR', 'CREDITOR'), `amount`, `purpose`, `requisiteId`, and `keepOnNominalAccount` flag. The `amounts` property, if present, is a collection of `ContractorAmountData` for detailed amount distribution.">
public function __construct(
public ?string $beneficiaryId = null,
public ?string $role = null,
@@ -18,4 +32,5 @@ class StepContractorData extends Data
#[DataCollectionOf(ContractorAmountData::class)]
public ?DataCollection $amounts = null,
) {}
// </SECTION>
}

View File

@@ -1,11 +1,25 @@
<?php
/*
// MODULE_CONTRACT: Defines the data structure for a single step within a deal.
// RESPONSIBILITY: To hold and type-safely represent the details of a specific stage in a multi-step deal process.
// INPUTS: Raw JSON object from the API response.
// OUTPUTS: A structured object containing deal step details.
// LINKS: Requests/NominalAccounts/Deals/Steps/GetStepRequest.php
*/
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.">
// <BELIEF_STATE "This DTO provides a clear, type-safe contract for a deal step, which is a critical component for defining and tracking complex business processes within a deal.">
class StepData extends Data
{
// <SECTION name="constructor_properties" intent="Define the properties of a deal step.">
// <BELIEF_STATE "The constructor includes key identifiers like `stepId` and `stepNumber`, along with `description`, `status`, and `isValid` to provide a comprehensive overview of the step's current state and details.">
public function __construct(
public string $stepId,
public int $stepNumber,
@@ -13,4 +27,5 @@ class StepData extends Data
public string $status,
public bool $isValid,
) {}
// </SECTION>
}

View File

@@ -1,14 +1,29 @@
<?php
/*
// MODULE_CONTRACT: Defines the data structure for the response of a deal validation request.
// RESPONSIBILITY: To hold and type-safely represent the outcome of checking a deal's validity.
// INPUTS: Raw JSON object from the API response.
// OUTPUTS: A structured object containing deal validation status.
// LINKS: Requests/NominalAccounts/Deals/ValidateDealRequest.php
*/
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.">
// <BELIEF_STATE "This DTO provides a clear, type-safe contract for understanding whether a deal is considered valid for further operations, including an optional description for validation failures.">
class ValidateDealResponseData extends Data
{
// <SECTION name="constructor_properties" intent="Define the properties of a deal validation response.">
// <BELIEF_STATE "The constructor includes the `dealId` for context, a boolean `isValid` to indicate the validation outcome, and an optional `description` to provide details for invalid deals.">
public function __construct(
public string $dealId,
public bool $isValid,
public ?array $description = null,
public ?array $description = null, // Can be a string or array of error messages
) {}
// </SECTION>
}

View File

@@ -1,13 +1,28 @@
<?php
/*
// MODULE_CONTRACT: Defines the data structure for distributing an amount to a beneficiary.
// RESPONSIBILITY: To hold and type-safely represent how a specific portion of a transaction amount is allocated to a beneficiary.
// INPUTS: Raw JSON object or internal input.
// OUTPUTS: A structured object containing beneficiary amount distribution details.
// LINKS: IdentifyRequestData.php (uses this DTO)
*/
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.">
// <BELIEF_STATE "This DTO provides a precise, type-safe contract for specifying how parts of a transaction's total amount should be allocated to different beneficiaries, crucial for accounting accuracy.">
class AmountDistributionData extends Data
{
// <SECTION name="constructor_properties" intent="Define the properties of an amount distribution entry.">
// <BELIEF_STATE "The constructor specifies the `beneficiaryId` to whom the amount is distributed and the exact `amount` being allocated. Both are mandatory to ensure accurate financial allocation.">
public function __construct(
public string $beneficiaryId,
public string $amount,
) {}
// </SECTION>
}

View File

@@ -1,14 +1,28 @@
<?php
/*
// MODULE_CONTRACT: Defines the data structure for the request payload when identifying an unidentified transaction.
// RESPONSIBILITY: To hold and validate all necessary information for associating an unidentified transaction with specific beneficiaries.
// INPUTS: Transaction ID, account number, amount distribution details, and digest signatures.
// OUTPUTS: A structured, type-safe object for the `IdentifyTransactionRequest` payload.
// LINKS: Requests/NominalAccounts/Identification/IdentifyTransactionRequest.php
*/
namespace Apoloz\AlfaBank\Data\NominalAccounts\Identification;
// <SECTION name="module_imports" intent="Import necessary DTOs and Spatie Laravel Data components for complex nested structures.">
// <BELIEF_STATE "This DTO orchestrates several other DTOs and collections (`AmountDistributionData`, `DigestSignatureData`), requiring `DataCollectionOf` for typed arrays.">
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 a DTO for identifying an unidentified transaction.">
// <BELIEF_STATE "This DTO provides a robust contract for the complex payload required to identify a transaction. It ensures that critical financial and cryptographic data is correctly structured.">
class IdentifyRequestData extends Data
{
// <SECTION name="constructor_properties" intent="Define all properties for the transaction identification request.">
// <BELIEF_STATE "The constructor meticulously lists all mandatory fields. `transactionId` and `accountNumber` pinpoint the transaction. `amountDistribution` and `digestSignatures` are critical for the financial and security aspects of the identification process, each being a typed collection.">
public function __construct(
public string $transactionId,
public string $accountNumber,
@@ -17,4 +31,5 @@ class IdentifyRequestData extends Data
#[DataCollectionOf(DigestSignatureData::class)]
public DataCollection $digestSignatures,
) {}
// </SECTION>
}

View File

@@ -1,13 +1,28 @@
<?php
/*
// MODULE_CONTRACT: Defines the data structure for the response of a transaction identification request.
// RESPONSIBILITY: To hold and type-safely represent the outcome and status of an identification operation.
// INPUTS: Raw JSON object from the API response.
// OUTPUTS: A structured object containing identification request status information.
// LINKS: Requests/NominalAccounts/Identification/IdentifyTransactionRequest.php, Requests/NominalAccounts/Identification/GetIdentifyStatusRequest.php
*/
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.">
// <BELIEF_STATE "This DTO provides a clear, type-safe contract for tracking the status of an identification request, which might be asynchronous.">
class IdentifyResponseData extends Data
{
// <SECTION name="constructor_properties" intent="Define the properties of an identification request response.">
// <BELIEF_STATE "The `identifyId` serves as a unique identifier for the specific identification operation, and `status` indicates its current state.">
public function __construct(
public string $identifyId,
public string $status,
) {}
// </SECTION>
}

View File

@@ -1,11 +1,25 @@
<?php
/*
// MODULE_CONTRACT: Defines the data structure for payer information within an unidentified transaction.
// RESPONSIBILITY: To hold and type-safely represent the details of the party who initiated a transaction that needs identification.
// INPUTS: Raw JSON object from the API response.
// OUTPUTS: A structured object containing payer details.
// LINKS: UnidentifiedTransactionData.php (uses this DTO)
*/
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.">
// <BELIEF_STATE "This DTO provides a clear, type-safe contract for payer information, which is critical for identifying the origin of an unidentified transaction.">
class PayerData extends Data
{
// <SECTION name="constructor_properties" intent="Define the properties of a payer.">
// <BELIEF_STATE "The constructor includes various optional fields for identifying a payer, such as `inn`, `kpp`, `accountNumber`, `name`, and bank details (`bankAccount`, `bankBik`, `bankName`). All are optional as not all information may be available for an unidentified transaction.">
public function __construct(
public ?string $inn = null,
public ?string $kpp = null,
@@ -15,4 +29,5 @@ class PayerData extends Data
public ?string $bankBik = null,
public ?string $bankName = null,
) {}
// </SECTION>
}

View File

@@ -1,18 +1,33 @@
<?php
/*
// MODULE_CONTRACT: Defines the data structure for the request payload when refunding an unidentified transaction.
// RESPONSIBILITY: To hold and validate all necessary information for initiating a refund for an unidentified transaction.
// INPUTS: Account number, transaction ID, and digest signatures.
// OUTPUTS: A structured, type-safe object for the `RefundUnidentifiedTransactionRequest` payload.
// LINKS: Requests/NominalAccounts/Identification/RefundUnidentifiedTransactionRequest.php
*/
namespace Apoloz\AlfaBank\Data\NominalAccounts\Identification;
// <SECTION name="module_imports" intent="Import necessary DTOs and Spatie Laravel Data components.">
// <BELIEF_STATE "This DTO requires `DigestSignatureData` as a collection, so `DataCollectionOf` is used.">
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 a DTO for refunding an unidentified transaction.">
// <BELIEF_STATE "This DTO ensures the refund request payload is strictly typed and complete, preventing malformed requests for a critical financial operation.">
class RefundUnidentifiedTransactionRequestData extends Data
{
// <SECTION name="constructor_properties" intent="Define all properties for the refund request.">
// <BELIEF_STATE "The constructor includes mandatory fields: `accountNumber` and `id` to target the transaction, and `digestSignatures` for security and authorization.">
public function __construct(
public string $accountNumber,
public string $id,
#[DataCollectionOf(DigestSignatureData::class)]
public DataCollection $digestSignatures,
) {}
// </SECTION>
}

View File

@@ -1,13 +1,28 @@
<?php
/*
// MODULE_CONTRACT: Defines the data structure for the response of a refund request for an unidentified transaction.
// RESPONSIBILITY: To hold and type-safely represent the outcome and status of an initiated refund operation.
// INPUTS: Raw JSON object from the API response.
// OUTPUTS: A structured object containing refund request status information.
// LINKS: Requests/NominalAccounts/Identification/RefundUnidentifiedTransactionRequest.php
*/
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.">
// <BELIEF_STATE "This DTO provides a clear, type-safe contract for tracking the status of a refund request, which is a critical financial operation.">
class RefundUnidentifiedTransactionResponseData extends Data
{
// <SECTION name="constructor_properties" intent="Define the properties of a refund request response.">
// <BELIEF_STATE "The `refundId` serves as a unique identifier for the specific refund operation, and `status` indicates its current state.">
public function __construct(
public string $refundId,
public string $status,
) {}
// </SECTION>
}

View File

@@ -1,13 +1,27 @@
<?php
/*
// MODULE_CONTRACT: Defines the data structure for a paginated collection of unidentified transactions.
// RESPONSIBILITY: To provide a structured, type-safe container for lists of unidentified transactions, including pagination metadata.
// INPUTS: Raw JSON array from the API response.
// OUTPUTS: An object containing pagination details and a collection of `UnidentifiedTransactionData`.
// LINKS: Requests/NominalAccounts/Identification/GetUnidentifiedTransactionsRequest.php
*/
namespace Apoloz\AlfaBank\Data\NominalAccounts\Identification;
// <SECTION name="module_imports" intent="Import necessary DTOs and Spatie Laravel Data components.">
// <BELIEF_STATE "This collection DTO relies on `UnidentifiedTransactionData` for individual items. `DataCollection` and `DataCollectionOf` are Spatie Data features for handling typed arrays of DTOs.">
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.">
// <BELIEF_STATE "A dedicated DTO for a collection ensures that the structure of paginated lists is consistent and type-safe, providing a reliable contract for consumers to manage unidentified transactions.">
class UnidentifiedTransactionCollectionData extends Data
{
// <SECTION name="constructor_properties" intent="Define the properties of the unidentified transaction collection.">
// <BELIEF_STATE "The collection structure includes pagination metadata (`offset`, `limit`, `totalCount`) and the actual list of `unidentifiedTransactions`. The `#[DataCollectionOf(UnidentifiedTransactionData::class)]` attribute is crucial for ensuring that each item is automatically cast to its respective DTO.">
public function __construct(
public int $offset,
public int $limit,
@@ -15,4 +29,5 @@ class UnidentifiedTransactionCollectionData extends Data
#[DataCollectionOf(UnidentifiedTransactionData::class)]
public ?DataCollection $unidentifiedTransactions = null,
) {}
// </SECTION>
}

View File

@@ -1,17 +1,32 @@
<?php
/*
// MODULE_CONTRACT: Defines the data structure for a single unidentified transaction.
// RESPONSIBILITY: To hold and type-safely represent the details of a transaction that requires further identification.
// INPUTS: Raw JSON object from the API response.
// OUTPUTS: A structured object containing unidentified transaction details.
// LINKS: UnidentifiedTransactionCollectionData.php
*/
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.">
// <BELIEF_STATE "This DTO provides a clear, type-safe contract for transactions awaiting identification, which is critical for their eventual processing.">
class UnidentifiedTransactionData extends Data
{
// <SECTION name="constructor_properties" intent="Define the properties of an unidentified transaction.">
// <BELIEF_STATE "The constructor includes core transaction details like `id`, `amount`, and optional fields such as `documentNumber`, `date`, `purpose`, and `payer` information. The `payer` field is itself a nested DTO, ensuring detailed payer information is structured.">
public function __construct(
public string $id,
public string $amount,
public ?string $documentNumber = null,
public ?string $date = null,
public ?string $purpose = null,
public ?PayerData $payer = null,
public ?PayerData $payer = null, // Nested DTO for payer details
) {}
// </SECTION>
}

View File

@@ -1,13 +1,28 @@
<?php
/*
// MODULE_CONTRACT: Defines the data structure for a single nominal account.
// RESPONSIBILITY: To hold and type-safely represent the core details of a nominal account, such as its number and active status.
// INPUTS: Raw JSON object from the API response.
// OUTPUTS: A structured object containing nominal account information.
// LINKS: Requests/NominalAccounts/GetNominalAccountsRequest.php
*/
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.">
// <BELIEF_STATE "This DTO provides a simple, type-safe contract for basic nominal account information, ensuring consistency in how account details are presented.">
class NominalAccountData extends Data
{
// <SECTION name="constructor_properties" intent="Define the properties of a nominal account.">
// <BELIEF_STATE "The constructor captures the `accountNumber` as the primary identifier and an `isActive` flag indicating the account's current status.">
public function __construct(
public string $accountNumber,
public bool $isActive,
) {}
// </SECTION>
}

View File

@@ -1,20 +1,37 @@
<?php
/*
// MODULE_CONTRACT: Defines the data structure for a detailed payoff record.
// RESPONSIBILITY: To hold and type-safely represent comprehensive information about a payoff, including payer, recipient, and financial details.
// INPUTS: Raw JSON object from the API response.
// OUTPUTS: A structured object containing detailed payoff information.
// LINKS: Requests/NominalAccounts/Payouts/GetPayoffRequest.php
*/
namespace Apoloz\AlfaBank\Data\NominalAccounts\Payouts;
// <SECTION name="module_imports" intent="Import necessary DTOs and Spatie Laravel Data components for complex nested data structures.">
// <BELIEF_STATE "This DTO uses nested `PayerInfoData` and `RecipientInfoData` DTOs to represent the parties involved in the payoff, requiring their imports.">
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.">
// <BELIEF_STATE "This DTO provides a comprehensive, type-safe contract for a complete payoff record, which is essential for audit trails and detailed reporting.">
class DetailedPayoffData extends Data
{
// <SECTION name="constructor_properties" intent="Define all properties that describe a detailed payoff.">
// <BELIEF_STATE "The constructor includes a wide array of optional fields covering deal context (`dealId`, `stepId`), payment method (`paymentType`, `requisiteType`), involved parties (`payer`, `recipient`), financial details (`amount`, `purpose`), and status. The nested DTOs (`PayerInfoData`, `RecipientInfoData`) ensure detailed party information is also structured.">
public function __construct(
public ?string $dealId = null,
public ?string $stepId = null,
public ?string $paymentType = null,
public ?string $requisiteType = null,
public ?array $payer = null,
public ?array $recipient = null,
public ?PayerInfoData $payer = null,
public ?RecipientInfoData $recipient = null,
public ?string $amount = null,
public ?string $purpose = null,
public ?string $status = null,
) {}
// </SECTION>
}

View File

@@ -1,13 +1,28 @@
<?php
/*
// MODULE_CONTRACT: Defines the data structure for a cryptographic digest signature.
// RESPONSIBILITY: To hold and type-safely represent a base64-encoded signature and its type.
// INPUTS: Raw JSON object or internal input.
// OUTPUTS: A structured object containing signature details.
// LINKS: PayoffRequestData.php (uses this DTO), CreateBeneficiaryRequestData.php (uses this DTO)
*/
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.">
// <BELIEF_STATE "This DTO provides a clear, type-safe contract for handling digital signatures, which are critical for the authenticity and integrity of financial transactions.">
class DigestSignatureData extends Data
{
// <SECTION name="constructor_properties" intent="Define the properties of a digest signature.">
// <BELIEF_STATE "The constructor includes the `base64Encoded` string of the signature and the `signatureType` (e.g., 'CMS', 'XMLDSig') to indicate the cryptographic standard used. Both are mandatory.">
public function __construct(
public string $base64Encoded,
public string $signatureType,
) {}
// </SECTION>
}

View File

@@ -1,13 +1,27 @@
<?php
/*
// MODULE_CONTRACT: Defines the data structure for the request payload when creating a new payoff.
// RESPONSIBILITY: To hold and validate all necessary information for initiating a payment from a nominal account.
// INPUTS: Payment type, account number, recipient details, amount, purpose, and digest signatures.
// OUTPUTS: A structured, type-safe object for the `CreatePayoffRequest` payload.
// LINKS: Requests/NominalAccounts/Payouts/CreatePayoffRequest.php
*/
namespace Apoloz\AlfaBank\Data\NominalAccounts\Payouts;
// <SECTION name="module_imports" intent="Import necessary DTOs and Spatie Laravel Data components for complex nested data structures.">
// <BELIEF_STATE "This DTO orchestrates several other DTOs and collections (`RecipientData`, `PayoutRequisiteData`, `DigestSignatureData`), requiring `DataCollectionOf` for typed arrays.">
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 payoff request.">
// <BELIEF_STATE "This DTO provides a robust contract for the complex payload required to initiate a payment. It ensures that all financial and security-critical data is strictly typed and correctly structured.">
class PayoffRequestData extends Data
{
// <SECTION name="constructor_properties" intent="Define all properties for the payoff request.">
// <BELIEF_STATE "The constructor includes mandatory fields like `type`, `accountNumber`, `recipient`, `payoutRequisite`, `amount`, `purpose`, and `digestSignatures`. Nested DTOs (`RecipientData`, `PayoutRequisiteData`) ensure detailed sub-structures are also type-safe. Optional fields like `deponent`, `requisites`, and `tax` provide flexibility for different payment scenarios.">
public function __construct(
public string $type,
public string $accountNumber,
@@ -18,7 +32,8 @@ class PayoffRequestData extends Data
#[DataCollectionOf(DigestSignatureData::class)]
public DataCollection $digestSignatures,
public ?string $deponent = null,
public ?array $requisites = null,
public ?array $tax = null,
public ?array $requisites = null, // Can be nested DTOs if defined
public ?array $tax = null, // Can be nested DTOs if defined
) {}
// </SECTION>
}

Some files were not shown because too many files have changed in this diff Show More