rikudou/skqrpayment
Laravel package for generating Slovak QR payment codes. Build payment strings with IBAN, amount, variable symbol, and recipient details, then render scannable QR codes for mobile banking apps. Simple, configurable, and easy to integrate.
1. Install
composer require rikudou/skqrpayment:^4.2.3
Pin to ^4.2.3 (or at minimum >=4.2.3) if you run PHP 8.4 — see the PHP version note in Gotchas.
2. Look here first
README.md — the only usage doc; confirm the exact class name/namespace before writing code (it is a single-class-style library, so the README is the whole API surface).src/QrPayment.php — the entire public API: setters for IBAN, amount, currency, variable/specific/constant symbol, due date, note, and a method that returns the QR payload string.composer.json — check the PHP version constraint and whether ext-* (e.g. mbstring, compression) is required.There is no service provider, no facade, no config file, no migrations. It is a framework-agnostic leaf dependency. In Laravel you simply new it (or resolve it from the container).
3. First use case — invoice → scannable Pay by Square QR
use Rikudou\QrPaymentSK\QrPayment; // verify FQCN against the README
$payment = new QrPayment();
$payment->setIban('SK3112000000198742637541'); // no spaces
$payment->setAmount(49.99); // check float vs string in README
$payment->setCurrency('EUR');
$payment->setVariableSymbol('2025001');
$payment->setDueDate(new \DateTimeImmutable('2025-06-30'));
$payment->setNote('Faktura 2025-001');
$payload = $payment->getQrString(); // Pay by Square string, or (string) $payment
The package does not render images — it only produces the payload. Pair it with any QR renderer:
composer require endroid/qr-code
use Endroid\QrCode\QrCode;
use Endroid\QrCode\Writer\PngWriter;
$qr = new QrCode($payload);
$qr->setSize(320);
$qr->setMargin(8); // quiet zone matters for scanners
$png = (new PngWriter())->write($qr)->getString();
That is the whole first milestone: a scannable QR that a Slovak banking app will accept.
Wrap it in a domain action. Don't sprinkle new QrPayment() across controllers. Build one class that maps your Invoice model to a payment and returns the payload:
final class BuildInvoiceQrPayload
{
public function __invoke(Invoice $invoice): string
{
$payment = new QrPayment();
$payment->setIban($invoice->bankAccount->iban);
$payment->setAmount(number_format($invoice->total, 2, '.', ''));
$payment->setCurrency('EUR');
$payment->setVariableSymbol((string) $invoice->number);
$payment->setDueDate($invoice->due_at);
$payment->setNote(mb_substr($invoice->label, 0, 60));
return $payment->getQrString();
}
}
Return a data URI from a Blade component so the same QR works in web views, PDFs, and emails:
public function render(): string
{
$png = (new PngWriter())->write(new QrCode($this->payload))->getString();
return 'data:image/png;base64,' . base64_encode($png);
}
Embed in mailables with $message->embedData($png, 'qr.png', 'image/png') — do not attach as a file, scanners expect a rendered image.
Cache the payload, not the image. Key on the invoice's stable identifier plus updated_at; the payload only changes when bank details or amount change. Images are cheap to regenerate and expensive to invalidate.
Bulk/queued generation. For month-end PDF runs, generate payloads in a queued job and write the PNG to storage; the library itself is pure CPU and safe under concurrency (stateless, no I/O).
Integration with existing PDF tooling. Pass the PNG bytes into dompdf/snappy via the data URI above. Keep the QR at ≥ 256 px in the rendered document.
Testing pattern. Golden-file your payloads:
$payload = (new BuildInvoiceQrPayload())(Invoice::factory()->make([...]));
$this->assertSame(file_get_contents(base_path('tests/fixtures/qr.txt')), $payload);
Better: decode with a reference implementation in a separate test and assert the decoded fields, so a library re-release that changes compression doesn't break CI.
Pin and upgrade deliberately. These are patch-only releases with no changelog surface beyond PR titles; bump the constraint in a dedicated dependency PR with your payload tests green, not as a side-effect of composer update.
Isolate the dependency. Because the package is a single leaf class, a one-file adapter (QrPayloadFactory) means swapping it out later is a day's work, not a refactor.
No config needed. If you want the library injectable for mocking, bind it in a service provider as a closure factory rather than a singleton — it carries mutable state across setters, so a singleton is a footgun.
config/skqrpayment.php. If your codebase assumes Laravel-style packages, this one will surprise you — resolve it manually or behind your own adapter.storage/logs/laravel.log and can fail suites that convert deprecations to exceptions (PHPUnit convertDeprecationsToExceptions, failOnDeprecation under Pest). This is a drop-in patch; no API change, no re-testing of payload fixtures required beyond your normal suite.IsoCodes\Iban or a regex, because a wrong IBAN produces a valid-looking QR that fails in the banking app, not at generation time.setAmount() wants 49.99 (float/string) or 4999 (cents) — the README is authoritative. Prefer passing number_format($x, 2, '.', '') and never a raw float, to dodge 49.989999 serialization in the payload.DateTimeInterface and are serialized as Ymd — timezone irrelevant, but passing a string will throw. Format at the boundary.'' or null. An empty note or specific symbol can change the payload or trigger a validation exception. Guard every optional setter with if (!empty(...)).[A-Za-z0-9 .,-/] before setting; don't let user-entered Slovak text flow straight through.trim(), lowercase/uppercase conversion, URL-encoding, or newline normalization will corrupt it. Store and transmit it byte-for-byte.composer.json with a ~ constraint given 37 stars and zero dependents — you are the QA team. v4.2.3 is purely a deprecation fix, so it is one of the safest bumps you'll get; use it to stay current on PHP 8.4 without payload risk.bysquare decoder to confirm the library's output, then check rendering (size/margin) — the two failure modes look identical to users.InvalidArgumentException-flavored. Catch at the boundary (e.g. a form request or job) and surface a validation error, rather than letting a bad IBAN produce a 500 halfway through PDF generation.EUR is accepted by Slovak banking apps — don't expose a currency selector in your UI.QrPayment only if you need to intercept payload generation, which is rarely wise for a spec-bound format).How can I help you explore Laravel packages today?