feat(lpj): Tambah peran admin, sesuaikan alur status, dan peningkatan UI

Ringkas: perluas akses untuk peran admin , rapikan alur status permohonan/pembayaran/SPK, pindahkan sumber LPJ ke relasi penilai, perbaiki parsing/formatting rupiah, dan tambah konten cetak “Catatan yang Perlu Diperhatikan”.

- Perizinan & akses

  - Izinkan admin melewati filter cabang pada listing Debitur dan Permohonan.
  - Tambah peran admin pada konfigurasi module.json di beberapa menu/fitur.
  - Izinkan admin membuat Debitur dan mengakses aksi yang sebelumnya eksklusif untuk administrator dan pemohon-ao .
- Alur bisnis & status

  - Ubah status setelah proses pembatalan/penanganan pembayaran dari done menjadi proses-laporan agar konsisten dengan alur pelaporan.
  - Nonaktifkan blokir navigasi saat status proses-laporan di PenilaiController (redirect/JSON error dikomentari) agar proses lanjutan tetap bisa diakses bila diperlukan.
  - Setelah generate SPK, set Permohonan.status dan PenawaranTender.status menjadi registrasi-final untuk menandai finalisasi registrasi.
  - Pada pembuatan permohonan, jika pengguna admin , tetapkan status = preregister untuk proses pra-registrasi.
  - Hapus set default branch_id dari PermohonanRequest sehingga pengisian cabang dilakukan eksplisit melalui form (terutama untuk admin).
- Data LPJ & referensi relasi

  - Sumber data LPJ dipindah dari permohonan->penilaian->lpj ke permohonan->penilai->lpj baik di controller ( PenilaianController ) maupun view ( penilaian/otorisator/show.blade.php ) untuk menyesuaikan struktur relasi terbaru.
- Dokumen pembayaran

  - Ubah cara deteksi “Bukti Bayar” dari documents menjadi dokumenjaminan dan ambil detail berdasarkan name = 'Bukti Bayar' , lalu gunakan dokumen_jaminan yang terenkode JSON sebagai sumber pemrosesan berikutnya.
  - Pada UI approval pembayaran, benahi rendering nominal_bayar (hindari pemutusan baris) dan tampilkan tombol otorisator jika status_bayar !== 'sudah_bayar' || !approve_bayar .
- UI & formatting rupiah

  - Perbaiki fungsi calculateTotal() pada form-penilai.blade.php agar parsing angka mendukung pemisah ribuan titik dan desimal koma, serta formatting konsisten dengan id-ID .
  - Aktifkan kembali fallback tampilan status utama di penilai/index.blade.php .
  - Tambahkan blok “Catatan yang Perlu Diperhatikan” pada print-out-sederhana.blade.php , mendukung input string/array dan memformat poin dengan awalan “- ”.
Perubahan berkas (ringkas):

- app/Http/Controllers/DebitureController.php : tambah peran admin pada pengecualian filter cabang.
- app/Http/Controllers/PembayaranController.php : set status = 'proses-laporan' dalam proses terkait pembayaran.
- app/Http/Controllers/PenilaiController.php : longgarkan blokir saat proses-laporan (redirect/JSON error dikomentari).
- app/Http/Controllers/PenilaianController.php : gunakan permohonan->penilai->lpj untuk menghitung NPW.
- app/Http/Controllers/PermohonanController.php :
  - set status = 'preregister' untuk user admin saat create,
  - tambah peran admin pada pengecualian filter cabang,
  - ubah pencarian “Bukti Bayar” ke dokumenjaminan dan gunakan dokumen_jaminan (JSON).
- app/Http/Controllers/SpkController.php : set status = 'registrasi-final' pada Permohonan dan PenawaranTender setelah generate SPK.
- app/Http/Requests/PermohonanRequest.php : hilangkan set default branch_id .
- module.json : tambahkan admin pada beberapa daftar roles .
- resources/views/component/form-penilai.blade.php : dukungan parsing/formatting rupiah dengan pemisah lokal.
- resources/views/debitur/components/debitur.blade.php : perluas akses cabang untuk admin di form Debitur.
- resources/views/debitur/index.blade.php : izinkan admin membuat Debitur.
- resources/views/pembayaran/approval.blade.php : perbaiki render nominal dan visibilitas tombol otorisator.
- resources/views/penilai/components/print-out-sederhana.blade.php : tambah bagian “Catatan yang Perlu Diperhatikan”.
- resources/views/penilai/index.blade.php : gunakan data.status sebagai fallback tampilan status.
- resources/views/penilaian/otorisator/show.blade.php : konsisten gunakan permohonan->penilai->lpj .
- resources/views/permohonan/form.blade.php : penataan ulang kelas Tailwind dan penambahan field Cabang untuk administrator / admin .
This commit is contained in:
Daeng Deni Mardaeni
2025-11-12 17:42:45 +07:00
parent 89329de198
commit b2cfffc5d5
17 changed files with 137 additions and 34 deletions

View File

@@ -129,7 +129,7 @@
// Retrieve data from the database
$query = Debiture::query();
if (!Auth::user()->hasAnyRole(['administrator'])) {
if (!Auth::user()->hasAnyRole(['administrator','admin'])) {
$query = $query->where('branch_id', Auth::user()->branch_id);
}

View File

@@ -245,7 +245,7 @@ class PembayaranController extends Controller
$permohonan->approve_bayar_by = null;
$permohonan->approve_bayar_at = null;
$permohonan->status = 'done';
$permohonan->status = 'proses-laporan';
$permohonan->save();
} else {
$persetujuanPenawaran = PersetujuanPenawaran::create(

View File

@@ -157,7 +157,7 @@ class PenilaiController extends Controller
$permohonan = $this->surveyorController->getPermohonanJaminanId($id, $documentId, $jaminanId);
if ($permohonan->status == 'proses-laporan') {
return redirect()->back()->with('error', 'Masih dalam proses laporan');
//return redirect()->back()->with('error', 'Masih dalam proses laporan');
}
$basicData = $this->surveyorController->getCommonData();
@@ -841,10 +841,10 @@ class PenilaiController extends Controller
$permohonan = Permohonan::findOrFail($id);
if ($permohonan->status === 'proses-laporan') {
return response()->json([
/*return response()->json([
'success' => false,
'message' => 'Masih proses laporan',
], 400);
], 400);*/
}
if ($permohonan->status === 'proses-paparan') {

View File

@@ -518,7 +518,7 @@ class PenilaianController extends Controller
$status = 'done';
$approvalField = null;
$lpj_ = optional(json_decode($permohonan->penilaian->lpj));
$lpj_ = optional(json_decode($permohonan->penilai->lpj));
$npw = $lpj_->total_nilai_pasar_wajar ?? 0;
$npw = str_replace('.', '', $npw);

View File

@@ -50,6 +50,9 @@
{
$validate = $request->validated();
if ($validate) {
if(auth()->user()->hasRole('admin')){
$validate['status'] = "preregister";
}
try {
// Process file upload
$filePath = null;
@@ -172,7 +175,7 @@
// Retrieve data from the database
$query = Permohonan::query();
if (!Auth::user()->hasAnyRole(['administrator'])) {
if (!Auth::user()->hasAnyRole(['administrator','admin'])) {
$query = $query->where('branch_id', Auth::user()->branch_id);
}
@@ -371,14 +374,21 @@
}
if ($permohonan->status == 'sudah_dibayar') {
$buktiBayar = $permohonan->documents->filter(function ($doc) {
return $doc->detail && $doc->detail->nama === 'Bukti Bayar';
$documents = $permohonan->dokumenjaminan->first(function ($doc) {
return $doc->detail && $doc->detail->contains('name', 'Bukti Bayar');
});
$buktiBayar = $documents->detail->filter(function ($detail) {
return $detail->name == 'Bukti Bayar';
})->first() ?? null;
if ($buktiBayar->isEmpty()) {
return redirect()->route('authorization.show', $id)->with('error', 'Bukti Bayar harus diunggah');
}
$dokumenJaminan = json_decode($buktiBayar->dokumen_jaminan);
$persetujuanPenawaran = PersetujuanPenawaran::firstOrCreate(
['permohonan_id' => $id],
[

View File

@@ -345,6 +345,19 @@ use Illuminate\Support\Facades\Auth;
$content = $pdf->download()->getOriginalContent();
Storage::put('public/'.$newFileNameWithPath,$content);
$permohonanModel = Permohonan::where('nomor_registrasi', $penawaran->nomor_registrasi)->first();
if ($permohonanModel) {
$permohonanModel->status = 'registrasi-final';
$permohonanModel->save();
}
$persetujuanPenawaran = PenawaranTender::where('id', $penawaran->id)->first();
if ($persetujuanPenawaran) {
$persetujuanPenawaran->status = 'registrasi-final';
$persetujuanPenawaran->save();
}
$data1['status'] = 'success';
$data1['spkpenawaran_path'] = $spkpenawaran_path;
$data1['message']['message_success'] = array('Generate SPK PDF successfully');

View File

@@ -48,7 +48,6 @@
),
'tanggal_permohonan' => date('Y-m-d'),
'user_id' => auth()->user()->id,
'branch_id' => auth()->user()->branch_id,
'status' => 'order'
]);
}

View File

@@ -308,7 +308,8 @@
"permission": "",
"roles": [
"administrator",
"pemohon-ao"
"pemohon-ao",
"admin"
]
},
{
@@ -320,7 +321,8 @@
"permission": "",
"roles": [
"administrator",
"pemohon-ao"
"pemohon-ao",
"admin"
]
},
{

View File

@@ -438,13 +438,18 @@
function calculateTotal() {
const parseInput = (value) => {
if (!value) return 0;
return parseFloat(value.replace(/[^0-9]/g, '')) || 0;
// keep the dot as decimal separator, remove thousand separators
const cleaned = value.replace(/[^0-9.,]/g, '').replace(/\./g, '').replace(/,/g, '.');
return parseFloat(cleaned) || 0;
};
// Function to format currency
function formatCurrency(value) {
// Ensure we have a valid number to format
const num = parseFloat(value.replace(/[^0-9]/g, '')) || 0;
//const num = parseFloat(value.replace(/[^0-9]/g, '')) || 0;
//return num.toLocaleString('id-ID');
let num = value.replace(/[^0-9.,]/g, '').replace(/\./g, '').replace(/,/g, '.');
num = parseFloat(num) || 0;
return num.toLocaleString('id-ID');
}

View File

@@ -10,7 +10,7 @@
<span class="text-danger">*</span>
</label>
<div class="flex flex-wrap items-baseline w-full">
@if(auth()->user()->hasRole('administrator'))
@if(auth()->user()->hasRole('administrator','admin'))
<select class="input tomselect w-full @error('branch_id') border-danger bg-danger-light @enderror" name="branch_id" id="branch_id">
<option value="">Pilih Cabang</option>
@foreach($branches as $branch)

View File

@@ -20,7 +20,7 @@
<div class="flex flex-wrap gap-2.5">
<div class="h-[24px] border border-r-gray-200"></div>
<a class="btn btn-sm btn-light" href="{{ route('debitur.export') }}"> Export to Excel </a>
@if(auth()->user()->hasAnyRole(['administrator', 'pemohon-ao']))
@if(auth()->user()->hasAnyRole(['administrator', 'pemohon-ao','admin']))
<a class="btn btn-sm btn-primary" href="{{ route('debitur.create') }}"> Tambah Debitur </a>
@endif
</div>

View File

@@ -282,8 +282,7 @@
nominal_bayar: {
title: 'Nominal Bayar',
render: (item, data) => {
return data.nominal_bayar ? `${window.formatRupiah(data.nominal_bayar)}` : `${window.formatRu
piah(data.biaya_final)}`;
return data.nominal_bayar ? `${window.formatRupiah(data.nominal_bayar)}` : `${window.formatRupiah(data.biaya_final)}`;
},
},
bukti_bayar: {
@@ -344,7 +343,7 @@ piah(data.biaya_final)}`;
var iconPembayaranOtorisator = '';
if (permohonan) {
if (permohonan.status_bayar !== 'sudah_bayar') {
if (permohonan.status_bayar !== 'sudah_bayar' || !permohonan.approve_bayar) {
iconPembayaranOtorisator = `<a class="btn btn-sm btn-icon btn-clear btn-primary" onclick="handlePembayaran(${permohonan.id},'otorisator')">
<i class="ki-filled ki-double-check"></i>
</a>

View File

@@ -603,6 +603,56 @@
</table>
</td>
</tr>
<tr>
<td>
<table>
<tr>
<td width="25%" style="vertical-align: top;">Catatan yang Perlu
Diperhatikan</td>
<td width="1%" style="vertical-align: top;">:</td>
<td style="vertical-align: top;">
@php
$keterangan = $lpjData['keterangan_penilai'] ?? '';
@endphp
@if (!empty($keterangan))
@if (is_array($keterangan))
@foreach ($keterangan as $item)
<table style="width: 100%; border-collapse: collapse;">
<tr>
<td>
@php
$items_ = explode('- ', $item);
@endphp
@foreach ($items_ as $item_)
@if(!empty($item_))
- {{ trim($item_) }}<br>
@endif
@endforeach
</td>
</tr>
</table>
@endforeach
@else
<table style="width: 100%; border-collapse: collapse;">
<tr>
<td>
@php
$items = explode('- ', $keterangan);
@endphp
@foreach ($items as $item)
- {{ trim($item) }}<br>
@endforeach
</td>
</tr>
</table>
@endif
@endif
</td>
</tr>
</table>
</td>
</tr>
</table>
</div>
@if($permohonan->is_mig)

View File

@@ -229,7 +229,7 @@
return `<span class="flex justify-center uppercase badge badge-sm badge-default">${data.penawaran?.status.replace(/-/g, ' ')}</span>`;
}
//return `<span class="flex justify-center uppercase badge badge-sm badge-default">${data.status.replace(/-/g, ' ')}</span>`;
return `<span class="flex justify-center uppercase badge badge-sm badge-default">${data.status.replace(/-/g, ' ')}</span>`;
},
},
actions: {

View File

@@ -159,11 +159,9 @@
@if ($dataHeader == 'pelaporan')
@php
@php
$lpj_ = optional(json_decode($permohonan->penilaian->lpj));
$npw = $lpj_->total_nilai_pasar_wajar ?? 0;
$npw = str_replace('.', '', $npw);
@endphp
$lpj_ = optional(json_decode($permohonan->penilai->lpj));
$npw = $lpj_->total_nilai_pasar_wajar ?? 0;
$npw = str_replace('.', '', $npw);
@endphp
<a class="btn btn-success"
href="{{ route('otorisator.view-laporan') }}?permohonanId={{ $permohonan->id }}&documentId={{ $documentId }}&jaminanId={{ $jenisJaminanId }}&statusLpj={{ true }}&header={{ $header ?? '' }}">

View File

@@ -5,17 +5,17 @@
@endsection
@section('content')
<div class="w-full grid gap-5 lg:gap-7.5 mx-auto">
<div class="card border border-agi-100 pb-2.5">
<div class="grid gap-5 mx-auto w-full lg:gap-7.5">
<div class="pb-2.5 border card border-agi-100">
@if(isset($permohonan->id))
<div class="card-header bg-agi-50" id="basic_settings">
<div class="card-title flex flex-row gap-1.5">
<div class="flex flex-row gap-1.5 card-title">
<a href="{{ route('permohonan.edit',array_merge(request()->query(),['permohonan'=>$permohonan->id])) }}" class="btn btn-xs {{ request()->routeIs('permohonan.edit') ? 'btn-outline btn-primary' : 'btn-light' }}">Data Permohonan</a>
<a href="{{ route('debitur.edit',array_merge(request()->query(),['debitur'=>$debitur->id,'permohonan_id' => $permohonan->id])) }}" class="btn btn-xs {{ request()->routeIs('debitur.edit') ? 'btn-outline btn-primary' : 'btn-light' }}">Data Debitur</a>
<a href="{{ route('debitur.jaminan.index',array_merge(request()->query(),['id'=>$debitur->id,'permohonan_id' => $permohonan->id])) }}" class="btn btn-xs {{ request()->routeIs('debitur.jaminan.index') ? 'btn-outline btn-primary' : 'btn-light' }}">Dokumen Jaminan</a>
<a href="{{ route('debitur.pemilik.index',array_merge(request()->query(),['id'=>$debitur->id,'permohonan_id' => $permohonan->id])) }}" class="btn btn-xs {{ request()->routeIs('debitur.pemilik.index') ? 'btn-outline btn-primary' : 'btn-light' }}">Pemilk Jaminan</a>
</div>
<div class="flex items-center gap-2">
<div class="flex gap-2 items-center">
@if(isset($debitur->id) && !isset($permohonan->id))
<a class="btn btn-sm btn-primary" href="{{ route('permohonan.create.debitur', $debitur->id) }}"> Buat Permohonan </a>
@endif
@@ -34,7 +34,7 @@
<h3 class="card-title">
{{ isset($permohonan->id) ? 'Edit' : 'Tambah' }} Permohonan
</h3>
<div class="flex items-center gap-2">
<div class="flex gap-2 items-center">
<a href="{{ route('permohonan.index') }}" class="btn btn-xs btn-info"><i class="ki-filled ki-exit-left"></i> Back</a>
</div>
</div>
@@ -50,6 +50,33 @@
<input type="hidden" name="debiture_id" value="{{ $debitur->id }}">
<div class="flex flex-wrap gap-2.5 items-baseline lg:flex-nowrap">
<label class="gap-1 form-label max-w-56">
Cabang
<span class="text-danger">*</span>
</label>
<div class="flex flex-wrap items-baseline w-full">
@if (auth()->user()->hasRole(['administrator','admin']))
<select class="input tomselect w-full @error('branch_id') border-danger bg-danger-light @enderror"
name="branch_id" id="branch_id">
<option value="">Pilih Cabang</option>
@foreach ($branches as $branch)
<option value="{{ $branch->id }}"
{{ (isset($debitur) && $branch->id == $debitur->branch_id) || old('branch_id') == $branch->id ? 'selected' : '' }}>
{{ $branch->name }}
</option>
@endforeach
</select>
@else
<input type="hidden" name="branch_id" value="{{ auth()->user()->branch_id }}">
<input type="text" class="w-full input" value="{{ auth()->user()->branch->name }}" readonly>
@endif
@error('branch_id')
<em class="text-sm alert text-danger">{{ $message }}</em>
@enderror
</div>
</div>
@php
$formFields = [
'tujuan_penilaian_id' => ['label' => 'Tujuan Penilaian', 'type' => 'select', 'options' => $tujuanPenilaian],
@@ -65,7 +92,7 @@
@endphp
@foreach($formFields as $field => $config)
<div id="{{ $field }}_wrapper" class="flex items-baseline flex-wrap lg:flex-nowrap gap-2.5">
<div id="{{ $field }}_wrapper" class="flex flex-wrap gap-2.5 items-baseline lg:flex-nowrap">
<label class="form-label max-w-56">{{ $config['label'] }}</label>
<div class="flex flex-wrap items-baseline w-full">
@if($config['type'] === 'select')
@@ -85,14 +112,14 @@
value="{{ old($field, $permohonan->$field ?? '') }}">
@endif
@error($field)
<em class="alert text-danger text-sm">{{ $message }}</em>
<em class="text-sm alert text-danger">{{ $message }}</em>
@enderror
</div>
</div>
@endforeach
@if(isset($permohonan) && $permohonan->status == 'revisi')
<div class="flex items-baseline flex-wrap lg:flex-nowrap gap-2.5">
<div class="flex flex-wrap gap-2.5 items-baseline lg:flex-nowrap">
Catatan : <br>
<em class="text-red-500">{{ $permohonan->keterangan }} {{ $permohonan->registrasi_catatan }}</em>
</div>

View File

@@ -22,7 +22,7 @@
<div class="flex flex-wrap gap-2.5">
<div class="h-[24px] border border-r-gray-200"></div>
<a class="btn btn-sm btn-light" href="{{ route('permohonan.export') }}"> Export to Excel </a>
@if(auth()->user()->hasAnyRole(['administrator', 'pemohon-ao']))
@if(auth()->user()->hasAnyRole(['administrator', 'pemohon-ao','admin']))
<a class="btn btn-sm btn-primary" href="{{ route('permohonan.create') }}"> Tambah Permohonan </a>
@endif
</div>