Cara Membuat Sistem Approval Bertingkat di Laravel
Apa Itu Approval Bertingkat?
Approval bertingkat adalah proses persetujuan yang dilakukan berdasarkan urutan tertentu.
Contohnya:
Pengajuan
↓
Supervisor
↓
Manager
↓
Direktur
↓
DisetujuiJika salah satu level menolak:
Pengajuan
↓
Supervisor
↓
DitolakSistem seperti ini membantu perusahaan membuat proses persetujuan lebih terstruktur dan mudah dilacak.
Contoh Status Approval
Pengajuan dapat memiliki status:
draft
pending
approved
rejected
cancelledSedangkan setiap level approval dapat memiliki:
pending
approved
rejected1. Membuat Tabel Pengajuan
Contoh migration:
Schema::create('requests', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')
->constrained();
$table->string('title');
$table->text('description')->nullable();
$table->string('status')
->default('draft');
$table->timestamps();
});Kemudian:
php artisan migrate2. Membuat Tabel Approval
Buat tabel khusus untuk menyimpan setiap tahapan approval:
Schema::create('approvals', function (Blueprint $table) {
$table->id();
$table->foreignId('request_id')
->constrained();
$table->foreignId('approver_id')
->constrained('users');
$table->unsignedInteger('level');
$table->string('status')
->default('pending');
$table->text('notes')->nullable();
$table->timestamp('approved_at')
->nullable();
$table->timestamps();
});Strukturnya menjadi:
Request
↓
Approval Level 1
↓
Approval Level 2
↓
Approval Level 33. Membuat Model
Model Request:
class RequestModel extends Model
{
protected $fillable = [
'user_id',
'title',
'description',
'status',
];
public function approvals()
{
return $this->hasMany(Approval::class);
}
}Model Approval:
class Approval extends Model
{
protected $fillable = [
'request_id',
'approver_id',
'level',
'status',
'notes',
'approved_at',
];
public function approver()
{
return $this->belongsTo(
User::class,
'approver_id'
);
}
}4. Membuat Approval Saat Pengajuan Dibuat
Misalnya terdapat tiga level:
Level 1 → Supervisor
Level 2 → Manager
Level 3 → DirekturKetika pengajuan dibuat:
$requestModel = RequestModel::create([
'user_id' => auth()->id(),
'title' => $request->title,
'description' => $request->description,
'status' => 'pending',
]);Kemudian buat approval:
Approval::create([
'request_id' => $requestModel->id,
'approver_id' => $supervisorId,
'level' => 1,
]);
Approval::create([
'request_id' => $requestModel->id,
'approver_id' => $managerId,
'level' => 2,
]);
Approval::create([
'request_id' => $requestModel->id,
'approver_id' => $directorId,
'level' => 3,
]);5. Hanya Level Aktif yang Bisa Approve
Misalnya pengajuan masih berada di level 1.
Supervisor → Bisa approve
Manager → Belum bisa
Direktur → Belum bisaCek level aktif:
$currentLevel = $requestModel
->approvals()
->where('status', 'pending')
->min('level');Kemudian pastikan user adalah approver pada level tersebut.
$approval = $requestModel
->approvals()
->where('level', $currentLevel)
->where('approver_id', auth()->id())
->where('status', 'pending')
->first();Jika tidak ditemukan:
abort(403, 'Anda belum dapat melakukan approval.');6. Proses Approve
Contohnya:
DB::transaction(function () use ($approval) {
$approval->update([
'status' => 'approved',
'approved_at' => now(),
]);
$nextLevel = Approval::where(
'request_id',
$approval->request_id
)
->where('status', 'pending')
->min('level');
if (!$nextLevel) {
RequestModel::where(
'id',
$approval->request_id
)->update([
'status' => 'approved',
]);
}
});Jika masih ada level berikutnya, pengajuan tetap menunggu approval berikutnya.
7. Proses Reject
Jika approver menolak:
DB::transaction(function () use (
$approval,
$request
) {
$approval->update([
'status' => 'rejected',
'notes' => $request->notes,
]);
RequestModel::where(
'id',
$approval->request_id
)->update([
'status' => 'rejected',
]);
});Alurnya:
Level 1
↓
Approved
↓
Level 2
↓
Rejected
↓
Pengajuan Rejected8. Tambahkan Catatan Approval
Approver sebaiknya dapat memberikan alasan.
Contohnya:
Status : Rejected
Catatan:
Dokumen pendukung belum lengkap.Field:
$table->text('notes')->nullable();Dengan begitu, pengguna mengetahui alasan pengajuan ditolak.
9. Membuat Tampilan Approval
Contoh sederhana:
Pengajuan Pembelian Laptop
✓ Supervisor
Disetujui
23 Agustus 2026
● Manager
Menunggu Approval
○ Direktur
Menunggu ApprovalTampilan seperti timeline akan memudahkan pengguna memahami posisi pengajuan.
10. Tambahkan Role dan Permission
Approval sebaiknya tidak hanya berdasarkan user ID.
Contohnya:
Supervisor
Manager
DirekturGunakan role atau permission untuk menentukan siapa yang dapat melakukan approval.
Contoh:
approval.purchase.supervisor
approval.purchase.manager
approval.purchase.directorHal ini lebih fleksibel jika struktur organisasi berubah.
11. Approval Berdasarkan Nominal
Approval bertingkat juga dapat ditentukan berdasarkan nilai transaksi.
Contohnya:
< Rp5 juta
→ Supervisor
Rp5 juta – Rp50 juta
→ Manager
> Rp50 juta
→ DirekturAlurnya:
Pengajuan
↓
Cek Nominal
↓
Tentukan Approval Level
↓
Buat WorkflowPendekatan ini cocok untuk sistem procurement dan pengajuan anggaran.
12. Approval Berdasarkan Cabang
Pada sistem multi-cabang:
Cabang Bekasi
↓
Supervisor Bekasi
↓
Manager Regional
↓
DirekturTambahkan branch_id pada pengajuan dan approval jika diperlukan.
Contoh:
$table->foreignId('branch_id')
->nullable()
->constrained();Dengan demikian, pengajuan dapat diarahkan ke approver berdasarkan cabang.
13. Gunakan Database Transaction
Approval sangat berkaitan dengan perubahan status.
Karena itu gunakan:
DB::transaction(function () {
// Update approval
// Update request
});Jika salah satu proses gagal, perubahan dapat dibatalkan.
14. Hindari Approval Ganda
Dua request dapat masuk hampir bersamaan.
Gunakan transaction dan locking jika proses approval sangat kritis.
Contohnya:
$approval = Approval::where(
'id',
$approvalId
)
->lockForUpdate()
->firstOrFail();Kemudian periksa kembali:
if ($approval->status !== 'pending') {
abort(
409,
'Approval sudah diproses.'
);
}Hal ini mencegah satu approval diproses dua kali.
15. Kirim Notifikasi
Setelah Supervisor melakukan approval:
Supervisor
↓
Approve
↓
Manager mendapatkan notifikasiLaravel Notification dapat digunakan untuk:
Email.
Database notification.
Slack.
WhatsApp melalui integrasi.
Push notification.
Contoh:
$manager->notify(
new ApprovalRequiredNotification(
$requestModel
)
);16. Gunakan Queue untuk Notifikasi
Jika notifikasi membutuhkan proses eksternal, gunakan queue:
$manager->notify(
new ApprovalRequiredNotification(
$requestModel
)
);Notification dapat dibuat menggunakan queue agar proses approval tidak terlalu lama.
17. Audit Log
Setiap approval sebaiknya dicatat.
Contohnya:
User : Budi
Aktivitas : Approve
Pengajuan : PR-001
Level : Manager
Tanggal : 23 Agustus 2026
IP Address : 192.168.1.10Audit log membantu ketika perusahaan perlu mengetahui siapa yang menyetujui atau menolak sebuah pengajuan.
Contoh Alur Lengkap
User membuat pengajuan
↓
Status Pending
↓
Supervisor
↓
Approve
↓
Manager
↓
Approve
↓
Direktur
↓
Approve
↓
Status ApprovedJika ditolak:
Approver
↓
Reject
↓
Status RejectedApproval Bertingkat Bersama Ovla Media
Ovla Media dapat membantu membangun sistem workflow dan approval Laravel untuk:
Approval pembelian.
Approval reimbursement.
Approval cuti.
Approval anggaran.
Approval invoice.
Approval dokumen.
Sistem multi-cabang.
Role dan permission.
Audit log.
Notifikasi otomatis.
Workflow dapat dibuat berdasarkan level jabatan, nominal transaksi, cabang, departemen, maupun jenis pengajuan.
Kesimpulan
Sistem approval bertingkat Laravel dapat dibuat dengan memisahkan data pengajuan dan tahapan approval.
Struktur sederhananya:
Request
↓
Approval Level 1
↓
Approval Level 2
↓
Approval Level 3
↓
ApprovedKomponen penting yang sebaiknya digunakan:
Approval level.
Role dan permission.
Status approval.
Database transaction.
Locking untuk proses kritis.
Notifikasi.
Audit log.
Idempotency atau pencegahan approval ganda.
Dengan struktur tersebut, sistem dapat dikembangkan untuk berbagai proses bisnis tanpa harus membuat alur approval secara manual untuk setiap jenis pengajuan.
Artikel Terkait
Cara Membuat Invoice PDF Laravel dengan Nomor Otomatis
Invoice PDF dapat dibuat secara otomatis menggunakan Laravel untuk menghasilkan dokumen tagihan yang rapi dan mudah dikirim kepada pelanggan. Nomor invoice juga dapat dibuat secara otomatis berdasarkan transaksi sehingga setiap invoice memiliki identitas yang unik dan mudah dilacak
Cara Membuat Webhook Laravel yang Aman dengan Signature Verification
Webhook memungkinkan aplikasi menerima data secara otomatis dari layanan lain, seperti payment gateway, WhatsApp, marketplace, atau sistem pihak ketiga. Agar webhook tidak mudah dipalsukan, Laravel dapat menggunakan signature verification untuk memastikan request benar-benar berasal dari sumber yang dipercaya.
Cara Membuat Export Excel dengan Filter Tanggal di Laravel
Export Excel dengan filter tanggal memungkinkan pengguna mengunduh data berdasarkan periode tertentu. Fitur ini cocok untuk laporan transaksi, penjualan, pasien, pembayaran, absensi, dan data operasional lainnya di aplikasi Laravel.