ronaldiputra / convert-qris-static-to-dynamic
Convert QRIS static payloads to dynamic QRIS payloads with amount and optional service fee.
Package info
github.com/ronaldiputra09/convert_qris_static_to_dynamic
pkg:composer/ronaldiputra/convert-qris-static-to-dynamic
Requires
- php: ^8.1
Requires (Dev)
- phpunit/phpunit: ^10.5 || ^11.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-09-21 14:09:26 UTC
README
Package PHP untuk mengubah payload QRIS statis menjadi QRIS dinamis. Bisa digunakan di PHP murni, Laravel, atau framework PHP lainnya.
Package ini menerima input berupa string payload QRIS. Jika input berasal dari gambar QR, decode gambar tersebut terlebih dahulu di aplikasi Anda, lalu kirim hasil string QRIS ke package ini.
Fitur
- Mengubah QRIS statis menjadi QRIS dinamis
- Menambahkan nominal transaksi
- Mendukung biaya layanan nominal tetap
- Mendukung biaya layanan persentase
- Memvalidasi payload QRIS
- Membaca informasi QRIS menjadi array
- Menghitung ulang checksum QRIS
- Tanpa dependency framework
Requirement
- PHP 8.1 atau lebih baru
- Composer
Instalasi
composer require ronaldiputra/convert-qris-static-to-dynamic
Quick Start
<?php require __DIR__.'/vendor/autoload.php'; use Ronaldiputra\ConvertQrisStaticToDynamic\QrisConverter; $payloadStatic = '000201010211...6304ABCD'; $payloadDynamic = QrisConverter::make()->convert( payload: $payloadStatic, amount: 50000, ); echo $payloadDynamic;
Output dari proses ini adalah string QRIS dinamis yang siap dijadikan QR code.
Convert Tanpa Fee
use Ronaldiputra\ConvertQrisStaticToDynamic\QrisConverter; $payloadDynamic = QrisConverter::make()->convert( payload: $payloadStatic, amount: 50000, );
Hasilnya adalah QRIS dinamis dengan nominal transaksi yang sudah ditentukan dan checksum baru yang valid.
Convert Dengan Fee Fixed
$payloadDynamic = QrisConverter::make()->convert( payload: $payloadStatic, amount: 50000, feeType: 'fixed', feeValue: 1000, );
Gunakan fixed jika biaya layanan berupa nominal tetap, misalnya 1000.
Convert Dengan Fee Percentage
$payloadDynamic = QrisConverter::make()->convert( payload: $payloadStatic, amount: 75000, feeType: 'percentage', feeValue: 2.5, );
Gunakan percentage jika biaya layanan berupa persen, misalnya 2.5.
Nilai feeType yang tersedia:
null: tanpa feefixed: fee nominal tetappercentage: fee persen
Validasi QRIS
$validation = QrisConverter::make()->validate($payload); if (! $validation['valid']) { foreach ($validation['errors'] as $error) { echo $error.PHP_EOL; } }
Return:
[
'valid' => true,
'errors' => [],
]
Validasi memastikan payload QRIS tidak kosong, formatnya dapat dibaca, data wajib tersedia, dan checksum-nya sesuai.
Parse QRIS
$parsed = QrisConverter::make()->parse($payload); echo $parsed['method']; // static atau dynamic echo $parsed['merchantName']; echo $parsed['amount'];
Contoh hasil parse:
[
'version' => '01',
'method' => 'static',
'merchantAccountInfo' => [],
'merchantCategoryCode' => '5812',
'currency' => '360',
'amount' => null,
'tipIndicator' => null,
'tipFixed' => null,
'tipPercentage' => null,
'countryCode' => 'ID',
'merchantName' => 'WARUNG TEST',
'merchantCity' => 'JAKARTA',
'postalCode' => '12345',
'additionalData' => null,
'crc' => 'ABCD',
'raw' => [],
]
Error Handling
convert() akan melempar InvalidQrisException jika payload, nominal, atau fee tidak valid.
use Ronaldiputra\ConvertQrisStaticToDynamic\Exceptions\InvalidQrisException; use Ronaldiputra\ConvertQrisStaticToDynamic\QrisConverter; try { $payloadDynamic = QrisConverter::make()->convert($payloadStatic, 50000); } catch (InvalidQrisException $exception) { echo $exception->getMessage(); }
Contoh error:
String QRIS wajib diisi.CRC tidak cocok: seharusnya XXXX, diterima YYYY.Nominal harus lebih besar dari nol.Jenis biaya layanan tidak valid.QRIS ini sudah bersifat dinamis.
Dokumentasi Laravel
Package ini bisa langsung dipakai di Laravel lewat service container karena class utamanya tidak membutuhkan konfigurasi tambahan.
1. Install Package
composer require ronaldiputra/convert-qris-static-to-dynamic
2. Buat Route
<?php use App\Http\Controllers\QrisConversionController; use Illuminate\Support\Facades\Route; Route::get('/qris', [QrisConversionController::class, 'index'])->name('qris.index'); Route::post('/qris/convert', [QrisConversionController::class, 'store'])->name('qris.convert');
3. Buat Form Request
php artisan make:request ConvertQrisRequest
<?php namespace App\Http\Requests; use Illuminate\Foundation\Http\FormRequest; use Illuminate\Validation\Rule; class ConvertQrisRequest extends FormRequest { public function authorize(): bool { return true; } public function rules(): array { return [ 'qris_payload' => ['required', 'string', 'max:4096'], 'amount' => ['required', 'integer', 'min:1'], 'fee_type' => ['nullable', Rule::in(['fixed', 'percentage'])], 'fee_value' => ['nullable', 'numeric', 'gt:0', 'required_with:fee_type'], ]; } }
4. Buat Controller
php artisan make:controller QrisConversionController
<?php namespace App\Http\Controllers; use App\Http\Requests\ConvertQrisRequest; use Illuminate\Http\RedirectResponse; use Illuminate\View\View; use Ronaldiputra\ConvertQrisStaticToDynamic\Exceptions\InvalidQrisException; use Ronaldiputra\ConvertQrisStaticToDynamic\QrisConverter; class QrisConversionController extends Controller { public function index(): View { return view('qris-converter'); } public function store(ConvertQrisRequest $request, QrisConverter $converter): RedirectResponse { $validated = $request->validated(); try { $dynamicPayload = $converter->convert( payload: $validated['qris_payload'], amount: (int) $validated['amount'], feeType: ($validated['fee_type'] ?? null) ?: null, feeValue: isset($validated['fee_value']) ? (float) $validated['fee_value'] : null, ); return back()->with('result', [ 'payload' => $dynamicPayload, 'parsed' => $converter->parse($dynamicPayload), ]); } catch (InvalidQrisException $exception) { return back() ->withInput() ->withErrors(['qris_payload' => $exception->getMessage()]); } } }
5. Buat Blade Form
Contoh sederhana memakai input payload string:
<form method="POST" action="{{ route('qris.convert') }}"> @csrf <label for="qris_payload">Payload QRIS Static</label> <textarea id="qris_payload" name="qris_payload" required>{{ old('qris_payload') }}</textarea> @error('qris_payload') <p>{{ $message }}</p> @enderror <label for="amount">Nominal</label> <input id="amount" name="amount" type="number" min="1" value="{{ old('amount', 50000) }}" required> @error('amount') <p>{{ $message }}</p> @enderror <label for="fee_type">Fee</label> <select id="fee_type" name="fee_type"> <option value="">Tanpa fee</option> <option value="fixed">Fixed</option> <option value="percentage">Percentage</option> </select> <label for="fee_value">Nilai fee</label> <input id="fee_value" name="fee_value" type="number" step="0.01" min="0"> <button type="submit">Convert to Dynamic QRIS</button> </form> @if (session('result')) <h2>Payload Dynamic</h2> <textarea readonly>{{ session('result.payload') }}</textarea> <h2>Info</h2> <ul> <li>Merchant: {{ session('result.parsed.merchantName') }}</li> <li>Method: {{ session('result.parsed.method') }}</li> <li>Amount: {{ session('result.parsed.amount') }}</li> <li>CRC: {{ session('result.parsed.crc') }}</li> </ul> @endif
6. Input Dari Gambar QRIS
Package ini tidak membaca gambar QR secara langsung. Alur yang disarankan:
- Upload gambar QRIS dari browser.
- Decode gambar menjadi string payload QRIS memakai JavaScript, misalnya
jsqr. - Kirim payload string ke field hidden
qris_payload. - Kirim payload tersebut ke package.
- Generate output QRIS dinamis menjadi gambar QR memakai library QR code pilihan Anda.
Contoh field:
<input type="file" accept="image/*" id="qris_image"> <input type="hidden" name="qris_payload" id="qris_payload">
Untuk generate QR output, Anda bisa memakai library QR code pilihan sendiri, atau generate di browser memakai package JavaScript seperti qrcode.
7. Test Laravel
Contoh feature test:
public function test_static_qris_payload_can_be_converted(): void { $response = $this->post('/qris/convert', [ 'qris_payload' => $this->staticPayload(), 'amount' => 50000, 'fee_type' => 'fixed', 'fee_value' => 1000, ]); $response ->assertRedirect() ->assertSessionHasNoErrors() ->assertSessionHas('result'); $result = session('result'); $this->assertSame('dynamic', $result['parsed']['method']); $this->assertSame('50000', $result['parsed']['amount']); $this->assertSame('fixed', $result['parsed']['tipIndicator']); $this->assertSame('1000', $result['parsed']['tipFixed']); }
API Reference
QrisConverter::make(): QrisConverter
Membuat instance converter.
convert(string $payload, int $amount, ?string $feeType = null, int|float|null $feeValue = null): string
Mengubah QRIS statis menjadi QRIS dinamis.
Parameter:
payload: string QRIS statisamount: nominal transaksi, minimal1feeType:null,fixed, ataupercentagefeeValue: nilai fee, wajib jikafeeTypediisi
validate(string $payload): array
Memvalidasi payload QRIS.
Return:
[
'valid' => bool,
'errors' => [],
]
parse(string $payload): array
Membaca payload QRIS menjadi array.
crc16(string $value): string
Menghitung checksum QRIS.
Catatan Penting
- Input harus berupa QRIS statis yang valid.
- QRIS dinamis tidak bisa dikonversi ulang.
- Amount dikirim sebagai angka tanpa titik ribuan, contoh
50000. - Fee fixed dikirim sebagai nominal, contoh
1000. - Fee percentage dikirim sebagai angka persen, contoh
2.5. - Output package adalah string payload QRIS, bukan file gambar.
- Untuk membuat gambar QR, gunakan generator QR code di aplikasi Anda.
Troubleshooting
QRIS ini sudah bersifat dinamis.
Payload input sudah berupa QRIS dinamis. Package hanya menerima QRIS statis.
CRC tidak cocok
Payload input rusak, terpotong, atau hasil copy tidak lengkap. Pastikan seluruh string QRIS dikirim secara utuh.
Gambar QRIS tidak bisa dipakai langsung
Package menerima string payload, bukan file gambar. Decode gambar QRIS terlebih dahulu menjadi string.