lukawar / laravel-bank-kit
Requires
- php: ^8.2
- endroid/qr-code: ^5.0
- illuminate/console: ^11.0
- illuminate/support: ^11.0
Requires (Dev)
- laravel/pint: ^1.29
- orchestra/testbench: ^9.0
- phpunit/phpunit: ^11.0
README
A Laravel package for generating Polish bank transfer files (ELIXIR format) and QR payment codes (Polish ZBP standard).
Requirements
- PHP 8.2+
- Laravel 11+
ext-iconv(for CP852 encoding in ELIXIR files)ext-gdorext-imagick(required only when using QR codes with embedded logos)
Installation
composer require lukawar/laravel-bank-kit
The package registers itself automatically via Laravel's package auto-discovery.
Publish the configuration file:
php artisan vendor:publish --tag=bank-kit-config
Configuration
config/bank-kit.php:
return [ // Default sender used in ELIXIR transfer files 'sender' => [ 'account' => env('BANK_KIT_SENDER_ACCOUNT', ''), 'name' => env('BANK_KIT_SENDER_NAME', ''), 'address' => env('BANK_KIT_SENDER_ADDRESS', ''), ], // QR code logo settings 'qr' => [ // null → no logo // 'default' → built-in black square logo // '/path/...' → custom image file (PNG/SVG recommended) 'logo_path' => env('BANK_KIT_QR_LOGO_PATH', null), 'logo_width' => env('BANK_KIT_QR_LOGO_WIDTH', 60), ], // Payment gateways (future use) 'gateways' => [], ];
.env variables:
| Variable | Default | Description |
|---|---|---|
BANK_KIT_SENDER_ACCOUNT |
— | NRB account number of the default sender |
BANK_KIT_SENDER_NAME |
— | Sender name |
BANK_KIT_SENDER_ADDRESS |
— | Sender address |
BANK_KIT_QR_LOGO_PATH |
null |
Logo path (null, 'default', or a path) |
BANK_KIT_QR_LOGO_WIDTH |
60 |
Logo width in pixels |
ELIXIR Transfer Files
Transfer types
| Class | ELIXIR code | Description |
|---|---|---|
StandardTransfer |
51 |
Standard domestic transfer |
SplitPaymentTransfer |
53 |
VAT split payment |
TaxOfficeTransfer |
71 |
Tax office payment (US) |
ZusTransfer |
51 |
Social insurance payment (ZUS) |
Standard transfer
use lukawar\BankKit\DTOs\StandardTransfer; use lukawar\BankKit\Formatters\ElixirFormatter; use lukawar\BankKit\Generators\ElixirFileGenerator; use Carbon\Carbon; $transfer = new StandardTransfer( senderAccount: '58249000050000460073649930', senderName: 'Firma Sp. z o.o.', senderAddress: 'ul. Przykładowa 1|00-001 Warszawa', recipientAccount: '12345678901234567890123456', recipientName: 'Kontrahent', recipientAddress: 'ul. Odbiorcza 2|00-002 Kraków', amountInGrosze: 531200, // 5312.00 PLN executionDate: Carbon::today(), title: 'Faktura VAT 1/2024', ); $generator = new ElixirFileGenerator(new ElixirFormatter()); $files = $generator->generate(collect([$transfer])); // $files[0] contains CP852-encoded file content ready to save file_put_contents('transfers.pli', $files[0]);
Split payment (MPP)
use lukawar\BankKit\DTOs\SplitPaymentTransfer; $transfer = new SplitPaymentTransfer( senderAccount: '58249000050000460073649930', senderName: 'Firma Sp. z o.o.', senderAddress: 'ul. Przykładowa 1|00-001 Warszawa', recipientAccount: '12345678901234567890123456', recipientName: 'Kontrahent', recipientAddress: 'ul. Odbiorcza 2|00-002 Kraków', amountInGrosze: 123400, executionDate: Carbon::today(), title: 'Faktura VAT 5/2024', );
Tax office transfer (US)
use lukawar\BankKit\DTOs\TaxOfficeTransfer; use lukawar\BankKit\Enums\TaxPeriodType; $transfer = new TaxOfficeTransfer( senderAccount: '58249000050000460073649930', senderName: 'Firma Sp. z o.o.', senderAddress: 'ul. Przykładowa 1|00-001 Warszawa', recipientAccount: '12345678901234567890123456', recipientName: 'Urząd Skarbowy', recipientAddress: 'ul. Skarbowa 1|00-001 Warszawa', amountInGrosze: 100000, executionDate: Carbon::today(), taxpayerNip: '1234567890', periodType: TaxPeriodType::Month, periodNumber: '03', formSymbol: 'PIT37', additionalInfo: 'DEKLARACJA', ); // Generated title: N1234567890|M03|PIT37|DEKLARACJA
Available TaxPeriodType values:
| Enum case | Value | Description |
|---|---|---|
Year |
R |
Annual |
Quarter |
K |
Quarterly |
Month |
M |
Monthly |
Decade |
D |
10-day |
Day |
J |
Daily |
None |
0 |
No period |
ZUS transfer
use lukawar\BankKit\DTOs\ZusTransfer; $transfer = new ZusTransfer( senderAccount: '58249000050000460073649930', senderName: 'Firma Sp. z o.o.', senderAddress: 'ul. Przykładowa 1|00-001 Warszawa', recipientAccount: '12345678901234567890123456', recipientName: 'ZUS', recipientAddress: 'ul. Składkowa 1|00-001 Warszawa', amountInGrosze: 150000, executionDate: Carbon::today(), contributionPeriod: 'MARZEC 2024', ); // Generated title: SKLADKA ZA MARZEC 2024
Multiple transfers & file splitting
The generator automatically splits transfers into multiple files when the collection exceeds 50 items (ELIXIR limit).
$files = $generator->generate(collect($transfers)); // array of file contents $extension = $generator->resolveExtension(collect($transfers)); // 'pli' or 'pls' foreach ($files as $index => $content) { file_put_contents("transfers_{$index}.{$extension}", $content); }
File extensions:
.pli— standard transfers only.pls— collection contains at least one split payment transfer
QR Payment Codes
Generates QR codes following the Polish Bank Association (ZBP) payment standard.
QR content format: |PL|{IBAN}|{AMOUNT_IN_GROSZE}|{RECIPIENT_NAME}|{TITLE}|||
Basic usage
use lukawar\BankKit\QrPayment\DTOs\QrPaymentData; use lukawar\BankKit\QrPayment\Formatters\PolishQrPaymentFormatter; use lukawar\BankKit\QrPayment\Generators\QrPaymentGenerator; use lukawar\BankKit\QrPayment\Renderers\EndroidSvgRenderer; $generator = new QrPaymentGenerator( new PolishQrPaymentFormatter(), new EndroidSvgRenderer(), ); $data = new QrPaymentData( iban: 'PL10105000997603123456789123', amountInGrosze: 53120, // 531.20 PLN recipientName: 'Firma Sp. z o.o.', title: 'Faktura VAT 1/2024', // optional ); $svg = $generator->generate($data, size: 300); // In a Laravel controller: return response($svg, 200, ['Content-Type' => $generator->mimeType()]);
PNG output
use lukawar\BankKit\QrPayment\Renderers\EndroidPngRenderer; $generator = new QrPaymentGenerator( new PolishQrPaymentFormatter(), new EndroidPngRenderer(), ); $png = $generator->generate($data);
With a logo in the center
use lukawar\BankKit\QrPayment\DTOs\QrLogo; $logo = new QrLogo( imagePath: '/path/to/logo.png', // PNG or SVG width: 60, // pixels ); $svg = $generator->generate($data, size: 300, logo: $logo);
Using the built-in black square default logo:
use lukawar\BankKit\QrPayment\Logos\BlackSquareLogoGenerator; use lukawar\BankKit\QrPayment\DTOs\QrLogo; $logoPath = (new BlackSquareLogoGenerator())->generate(); $logo = new QrLogo(imagePath: $logoPath, width: 60); $svg = $generator->generate($data, logo: $logo);
Or resolve logo from config (BANK_KIT_QR_LOGO_PATH=default):
use lukawar\BankKit\BankKitServiceProvider; $logo = BankKitServiceProvider::resolveLogoFromConfig(); $svg = $generator->generate($data, logo: $logo);
Via the BankKit facade
use lukawar\BankKit\Facades\BankKit; use lukawar\BankKit\QrPayment\DTOs\QrPaymentData; $data = new QrPaymentData( iban: 'PL10105000997603123456789123', amountInGrosze: 53120, recipientName: 'Firma Sp. z o.o.', title: 'Faktura VAT 1/2024', ); $svg = BankKit::generateQrPayment($data);
IBAN handling
QrPaymentData normalizes the IBAN automatically (removes spaces and dashes, uppercases) and validates the format on construction. An InvalidIbanException is thrown for invalid values.
// All of these produce the same normalized IBAN: PL10105000997603123456789123 new QrPaymentData(iban: 'pl 10 1050 0099 7603 1234 5678 9123', ...); new QrPaymentData(iban: 'PL10-1050-0099-7603-1234-5678-9123', ...);
Custom formatter or renderer
Implement the appropriate interface to plug in your own format or output type:
use lukawar\BankKit\QrPayment\Contracts\QrPaymentFormatterInterface; use lukawar\BankKit\QrPayment\DTOs\QrPaymentData; class SepaQrPaymentFormatter implements QrPaymentFormatterInterface { public function format(QrPaymentData $data): string { return implode("\n", [ 'BCD', '002', '1', 'SCT', '', $data->recipientName, $data->iban, 'EUR'.number_format($data->amountInGrosze / 100, 2, '.', ''), '', '', $data->title, ]); } } $generator = new QrPaymentGenerator( new SepaQrPaymentFormatter(), new EndroidSvgRenderer(), );
License
Proprietary.