|
7 | 7 | <a href="https://brj.app">BRJ organisation</a> |
8 | 8 | </div> |
9 | 9 | <hr> |
10 | | -Fio bank payment authorizator |
11 | | -============================= |
| 10 | + |
| 11 | +# Fio Bank Payment Authorizator |
12 | 12 |
|
13 | 13 |  |
14 | 14 |
|
15 | | -Simple package for search payments in your bank account by API and authorize new orders. |
| 15 | +A PHP library for seamless integration with Fio Bank's API, enabling automatic retrieval of bank transactions and authorization of orders based on variable symbols. Perfect for e-commerce platforms, billing systems, and any application requiring automated payment verification. |
| 16 | + |
| 17 | +## :sparkles: Key Features |
| 18 | + |
| 19 | +- **Automatic Transaction Retrieval** - Fetches transactions from the last month via Fio Bank's REST API |
| 20 | +- **Variable Symbol Matching** - Authorizes orders by matching variable symbols in transactions |
| 21 | +- **Smart Symbol Detection** - Searches for variable symbols in message fields when not found in the dedicated field |
| 22 | +- **Built-in Caching** - Optional Nette Cache integration to reduce API calls (15-minute cache expiration) |
| 23 | +- **CSV Parsing** - Efficiently parses Fio Bank's CSV response format |
| 24 | +- **Extensible Architecture** - Implements `BaseAuthorizator` interface for consistent behavior across different bank integrations |
| 25 | +- **Type-Safe** - Fully typed PHP 8.1+ codebase with strict types |
| 26 | + |
| 27 | +## :building_construction: Architecture |
| 28 | + |
| 29 | +The library follows a clean, layered architecture with clear separation of concerns: |
| 30 | + |
| 31 | +``` |
| 32 | +┌─────────────────────────────────────────────────────────────────────┐ |
| 33 | +│ Your Application │ |
| 34 | +└─────────────────────────────────────────────────────────────────────┘ |
| 35 | + │ |
| 36 | + ▼ |
| 37 | +┌─────────────────────────────────────────────────────────────────────┐ |
| 38 | +│ FioPaymentAuthorizator │ |
| 39 | +│ ┌─────────────────────────────────────────────────────────────┐ │ |
| 40 | +│ │ • Manages API communication │ │ |
| 41 | +│ │ • Handles caching layer │ │ |
| 42 | +│ │ • Provides authOrders() method for bulk authorization │ │ |
| 43 | +│ └─────────────────────────────────────────────────────────────┘ │ |
| 44 | +└─────────────────────────────────────────────────────────────────────┘ |
| 45 | + │ |
| 46 | + ┌──────────────┴──────────────┐ |
| 47 | + ▼ ▼ |
| 48 | +┌───────────────────────────────┐ ┌───────────────────────────────┐ |
| 49 | +│ TransactionResult │ │ FioPaymentException │ |
| 50 | +│ ┌─────────────────────────┐ │ │ ┌─────────────────────────┐ │ |
| 51 | +│ │ • Account metadata │ │ │ │ • API errors │ │ |
| 52 | +│ │ • IBAN, BIC │ │ │ │ • Empty responses │ │ |
| 53 | +│ │ • Balance information │ │ │ │ • Service unavailable │ │ |
| 54 | +│ │ • Date range │ │ │ └─────────────────────────┘ │ |
| 55 | +│ │ • Transaction list │ │ └───────────────────────────────┘ |
| 56 | +│ └─────────────────────────┘ │ |
| 57 | +└───────────────────────────────┘ |
| 58 | + │ |
| 59 | + ▼ |
| 60 | +┌───────────────────────────────┐ |
| 61 | +│ Transaction │ |
| 62 | +│ ┌─────────────────────────┐ │ |
| 63 | +│ │ • Transaction ID │ │ |
| 64 | +│ │ • Date, Price, Currency │ │ |
| 65 | +│ │ • Variable/Constant/ │ │ |
| 66 | +│ │ Specific symbols │ │ |
| 67 | +│ │ • Account details │ │ |
| 68 | +│ │ • Messages & comments │ │ |
| 69 | +│ └─────────────────────────┘ │ |
| 70 | +└───────────────────────────────┘ |
| 71 | +``` |
| 72 | + |
| 73 | +## :jigsaw: Components |
| 74 | + |
| 75 | +### FioPaymentAuthorizator |
| 76 | + |
| 77 | +The main entry point of the library. Extends `BaseAuthorizator` from the `baraja-core/bank-transaction-authorizator` package. |
| 78 | + |
| 79 | +**Responsibilities:** |
| 80 | +- Constructs API URLs with the provided private key |
| 81 | +- Downloads transaction data from Fio Bank's REST API |
| 82 | +- Manages static and persistent caching |
| 83 | +- Normalizes and validates API responses |
| 84 | +- Provides the `authOrders()` method for bulk authorization (inherited from BaseAuthorizator) |
16 | 85 |
|
17 | | -📦 Installation |
18 | | ---------------- |
| 86 | +### TransactionResult |
| 87 | + |
| 88 | +A value object representing the complete API response, containing: |
| 89 | + |
| 90 | +| Property | Type | Description | |
| 91 | +|----------|------|-------------| |
| 92 | +| `accountId` | `int` | Bank account number | |
| 93 | +| `bankId` | `int` | Bank identifier (routing number) | |
| 94 | +| `currency` | `string` | Account currency (e.g., CZK, EUR) | |
| 95 | +| `iban` | `string` | International Bank Account Number | |
| 96 | +| `bic` | `string` | Bank Identifier Code (SWIFT) | |
| 97 | +| `openingBalance` | `float` | Balance at the start of the period | |
| 98 | +| `closingBalance` | `float` | Balance at the end of the period | |
| 99 | +| `dateStart` | `DateTimeInterface` | Start of the transaction period | |
| 100 | +| `dateEnd` | `DateTimeInterface` | End of the transaction period | |
| 101 | +| `idFrom` | `int` | First transaction ID in the response | |
| 102 | +| `idTo` | `int` | Last transaction ID in the response | |
| 103 | +| `transactions` | `Transaction[]` | Array of transaction objects | |
| 104 | + |
| 105 | +### Transaction |
| 106 | + |
| 107 | +Represents a single bank transaction with comprehensive details: |
| 108 | + |
| 109 | +| Property | Type | Description | |
| 110 | +|----------|------|-------------| |
| 111 | +| `id` | `int` | Unique transaction identifier | |
| 112 | +| `date` | `DateTimeInterface` | Transaction date | |
| 113 | +| `price` | `float` | Transaction amount (positive for incoming, negative for outgoing) | |
| 114 | +| `currency` | `string` | Transaction currency | |
| 115 | +| `toAccount` | `?string` | Counterparty account number | |
| 116 | +| `toAccountName` | `?string` | Counterparty account name | |
| 117 | +| `toBankCode` | `?int` | Counterparty bank code | |
| 118 | +| `toBankName` | `?string` | Counterparty bank name | |
| 119 | +| `constantSymbol` | `?int` | Constant symbol (KS) | |
| 120 | +| `variableSymbol` | `?int` | Variable symbol (VS) | |
| 121 | +| `specificSymbol` | `?int` | Specific symbol (SS) | |
| 122 | +| `userNotice` | `?string` | User notice/reference | |
| 123 | +| `toMessage` | `?string` | Message for recipient | |
| 124 | +| `type` | `?string` | Transaction type | |
| 125 | +| `sender` | `?string` | Sender identification | |
| 126 | +| `message` | `?string` | General message | |
| 127 | +| `comment` | `?string` | Additional comment | |
| 128 | +| `bic` | `?string` | Counterparty BIC/SWIFT code | |
| 129 | +| `idTransaction` | `?int` | Alternative transaction ID | |
| 130 | + |
| 131 | +**Key Methods:** |
| 132 | +- `isVariableSymbol(int $vs): bool` - Checks if transaction matches a variable symbol |
| 133 | +- `isContainVariableSymbolInMessage(int|string $vs): bool` - Searches for VS in message fields |
| 134 | + |
| 135 | +### FioPaymentException |
| 136 | + |
| 137 | +Custom exception class for handling Fio-specific errors: |
| 138 | +- Empty API responses |
| 139 | +- Invalid API keys |
| 140 | +- Service unavailability |
| 141 | +- Malformed data |
| 142 | + |
| 143 | +## :package: Installation |
19 | 144 |
|
20 | 145 | It's best to use [Composer](https://getcomposer.org) for installation, and you can also find the package on |
21 | 146 | [Packagist](https://packagist.org/packages/baraja-core/fio-payment-authorizator) and |
22 | 147 | [GitHub](https://github.com/baraja-core/fio-payment-authorizator). |
23 | 148 |
|
24 | 149 | To install, simply use the command: |
25 | 150 |
|
26 | | -``` |
| 151 | +```shell |
27 | 152 | $ composer require baraja-core/fio-payment-authorizator |
28 | 153 | ``` |
29 | 154 |
|
30 | 155 | You can use the package manually by creating an instance of the internal classes, or register a DIC extension to link the services directly to the Nette Framework. |
31 | 156 |
|
32 | | -And create service by Neon: |
| 157 | +### Requirements |
33 | 158 |
|
34 | | -```yaml |
35 | | -services: |
36 | | - - FioPaymentAuthorizator(%fio.privateKey%) |
| 159 | +- PHP 8.1 or higher |
| 160 | +- `baraja-core/bank-transaction-authorizator` ^2.0 (installed automatically) |
| 161 | +- Optional: `nette/caching` for persistent caching support |
37 | 162 |
|
38 | | -parameters: |
39 | | - fio: |
40 | | - privateKey: xxx |
41 | | -``` |
| 163 | +## :key: Obtaining API Key |
| 164 | + |
| 165 | +1. Log in to your [Fio Bank Internet Banking](https://ib.fio.cz/) |
| 166 | +2. Navigate to **Settings** > **API** |
| 167 | +3. Generate a new API token with read permissions |
| 168 | +4. Copy the token - this is your `privateKey` |
| 169 | + |
| 170 | +> **Security Note:** Never commit your API key to version control. Use environment variables or a secure configuration management system. |
42 | 171 |
|
43 | | -Use |
44 | | ---- |
| 172 | +## :rocket: Basic Usage |
45 | 173 |
|
46 | | -In presenter use very simply: |
| 174 | +### Standalone Usage |
47 | 175 |
|
48 | 176 | ```php |
49 | | -/** @var FioPaymentAuthorizator $fio **/ |
50 | | -$fio = $this->context->getByType(FioPaymentAuthorizator::class); |
| 177 | +use Baraja\FioPaymentAuthorizator\FioPaymentAuthorizator; |
| 178 | +use Baraja\FioPaymentAuthorizator\Transaction; |
51 | 179 |
|
52 | | -// Or simply: |
| 180 | +// Create instance with your API key |
| 181 | +$fio = new FioPaymentAuthorizator('your-private-api-key'); |
53 | 182 |
|
54 | | -$fio = new FioPaymentAuthorizator('private-key'); |
| 183 | +// Get all transactions from the last month |
| 184 | +$result = $fio->process(); |
55 | 185 |
|
56 | | -dump($fio->process()); // Get last month bank data as TransactionResult. |
| 186 | +// Access account information |
| 187 | +echo 'Account: ' . $result->getIban() . PHP_EOL; |
| 188 | +echo 'Currency: ' . $result->getCurrency() . PHP_EOL; |
| 189 | +echo 'Opening Balance: ' . $result->getOpeningBalance() . PHP_EOL; |
| 190 | +echo 'Closing Balance: ' . $result->getClosingBalance() . PHP_EOL; |
57 | 191 |
|
58 | | -// Check account and authorize new orders |
| 192 | +// Iterate through transactions |
| 193 | +foreach ($result->getTransactions() as $transaction) { |
| 194 | + echo sprintf( |
| 195 | + "[%s] %s %s - VS: %s\n", |
| 196 | + $transaction->getDate()->format('Y-m-d'), |
| 197 | + $transaction->getPrice(), |
| 198 | + $transaction->getCurrency(), |
| 199 | + $transaction->getVariableSymbol() ?? 'N/A' |
| 200 | + ); |
| 201 | +} |
| 202 | +``` |
| 203 | + |
| 204 | +### Order Authorization |
| 205 | + |
| 206 | +The library can automatically authorize orders based on variable symbols: |
59 | 207 |
|
60 | | -$unauthorizedVariables = []; |
| 208 | +```php |
| 209 | +// Array of variable symbols from unpaid orders |
| 210 | +$unauthorizedVariables = [123456, 789012, 345678]; |
61 | 211 |
|
| 212 | +// Authorize orders - the callback is called for each matched transaction |
62 | 213 | $fio->authOrders( |
63 | 214 | $unauthorizedVariables, |
64 | 215 | function (Transaction $transaction): void { |
65 | | - // Do something... |
| 216 | + // Mark order as paid in your system |
| 217 | + $orderId = $transaction->getVariableSymbol(); |
| 218 | + |
| 219 | + // Example: Update order status in database |
| 220 | + $this->orderRepository->markAsPaid($orderId, [ |
| 221 | + 'transactionId' => $transaction->getId(), |
| 222 | + 'amount' => $transaction->getPrice(), |
| 223 | + 'paidAt' => $transaction->getDate(), |
| 224 | + ]); |
| 225 | + } |
| 226 | +); |
| 227 | +``` |
| 228 | + |
| 229 | +### Using with Nette Framework |
| 230 | + |
| 231 | +Register the service in your `config.neon`: |
| 232 | + |
| 233 | +```yaml |
| 234 | +parameters: |
| 235 | + fio: |
| 236 | + privateKey: %env.FIO_API_KEY% |
| 237 | + |
| 238 | +services: |
| 239 | + - Baraja\FioPaymentAuthorizator\FioPaymentAuthorizator(%fio.privateKey%) |
| 240 | +``` |
| 241 | +
|
| 242 | +Then inject it in your presenter or service: |
| 243 | +
|
| 244 | +```php |
| 245 | +final class PaymentPresenter extends Nette\Application\UI\Presenter |
| 246 | +{ |
| 247 | + public function __construct( |
| 248 | + private FioPaymentAuthorizator $fio, |
| 249 | + ) { |
66 | 250 | } |
| 251 | + |
| 252 | + public function actionAuthorize(): void |
| 253 | + { |
| 254 | + $result = $this->fio->process(); |
| 255 | + // Process transactions... |
| 256 | + } |
| 257 | +} |
| 258 | +``` |
| 259 | + |
| 260 | +### Enabling Caching |
| 261 | + |
| 262 | +To reduce API calls and improve performance, enable caching by providing a Nette Cache storage: |
| 263 | + |
| 264 | +```yaml |
| 265 | +services: |
| 266 | + - Baraja\FioPaymentAuthorizator\FioPaymentAuthorizator( |
| 267 | + privateKey: %fio.privateKey% |
| 268 | + storage: @cacheStorage |
| 269 | + ) |
| 270 | +``` |
| 271 | + |
| 272 | +Or manually: |
| 273 | + |
| 274 | +```php |
| 275 | +use Nette\Caching\Storages\FileStorage; |
| 276 | + |
| 277 | +$storage = new FileStorage('/path/to/cache'); |
| 278 | +$fio = new FioPaymentAuthorizator('your-private-api-key', $storage); |
| 279 | +``` |
| 280 | + |
| 281 | +The cache expires after 15 minutes and is tagged with `fio`, `bank`, and `payment` for easy invalidation. |
| 282 | + |
| 283 | +## :mag: Advanced Usage |
| 284 | + |
| 285 | +### Checking Variable Symbol in Messages |
| 286 | + |
| 287 | +Some payment systems (especially international transfers) may include the variable symbol in the message field instead of the dedicated VS field. The library handles this automatically: |
| 288 | + |
| 289 | +```php |
| 290 | +$transaction = $result->getTransactions()[0]; |
| 291 | + |
| 292 | +// This checks both the VS field AND message fields |
| 293 | +if ($transaction->isVariableSymbol(123456)) { |
| 294 | + echo 'Variable symbol found!'; |
| 295 | +} |
| 296 | + |
| 297 | +// Check only in message fields |
| 298 | +if ($transaction->isContainVariableSymbolInMessage(123456)) { |
| 299 | + echo 'Found in message content'; |
| 300 | +} |
| 301 | +``` |
| 302 | + |
| 303 | +### Filtering Transactions |
| 304 | + |
| 305 | +```php |
| 306 | +$transactions = $fio->getTransactions(); |
| 307 | + |
| 308 | +// Filter incoming payments only |
| 309 | +$incoming = array_filter( |
| 310 | + $transactions, |
| 311 | + fn(Transaction $t) => $t->getPrice() > 0 |
| 312 | +); |
| 313 | + |
| 314 | +// Filter by date range |
| 315 | +$startDate = new DateTime('2024-01-01'); |
| 316 | +$filtered = array_filter( |
| 317 | + $transactions, |
| 318 | + fn(Transaction $t) => $t->getDate() >= $startDate |
| 319 | +); |
| 320 | + |
| 321 | +// Filter by specific bank |
| 322 | +$fioBankCode = 2010; |
| 323 | +$fioTransfers = array_filter( |
| 324 | + $transactions, |
| 325 | + fn(Transaction $t) => $t->getToBankCode() === $fioBankCode |
67 | 326 | ); |
68 | 327 | ``` |
69 | 328 |
|
70 | | -📄 License |
71 | | ------------ |
| 329 | +### Error Handling |
| 330 | + |
| 331 | +```php |
| 332 | +use Baraja\FioPaymentAuthorizator\FioPaymentException; |
| 333 | + |
| 334 | +try { |
| 335 | + $result = $fio->process(); |
| 336 | +} catch (FioPaymentException $e) { |
| 337 | + // Handle Fio-specific errors |
| 338 | + if (str_contains($e->getMessage(), 'API key')) { |
| 339 | + // Invalid API key |
| 340 | + $this->logger->error('Invalid Fio API key'); |
| 341 | + } elseif (str_contains($e->getMessage(), 'down')) { |
| 342 | + // Service temporarily unavailable |
| 343 | + $this->logger->warning('Fio API temporarily unavailable'); |
| 344 | + } |
| 345 | +} |
| 346 | +``` |
| 347 | + |
| 348 | +## :warning: API Rate Limits |
| 349 | + |
| 350 | +Fio Bank API has rate limiting in place: |
| 351 | +- **30 seconds** minimum interval between requests |
| 352 | +- The built-in caching helps respect this limit |
| 353 | +- Consider implementing a queue system for high-traffic applications |
| 354 | + |
| 355 | +## :books: Related Packages |
| 356 | + |
| 357 | +- [`baraja-core/bank-transaction-authorizator`](https://github.com/baraja-core/bank-transaction-authorizator) - Base package providing the `BaseAuthorizator` interface |
| 358 | +- Works with other bank authorizators following the same interface |
| 359 | + |
| 360 | +## :busts_in_silhouette: Author |
| 361 | + |
| 362 | +**Jan Barasek** - [https://baraja.cz](https://baraja.cz) |
| 363 | + |
| 364 | +## :page_facing_up: License |
72 | 365 |
|
73 | | -`baraja-core/fio-payment-authorizator` is licensed under the MIT license. See the [LICENSE](https://github.com/baraja-core/template/blob/master/LICENSE) file for more details. |
| 366 | +`baraja-core/fio-payment-authorizator` is licensed under the MIT license. See the [LICENSE](https://github.com/baraja-core/fio-payment-authorizator/blob/master/LICENSE) file for more details. |
0 commit comments