DONE: add line verification for pc/ppc to check customer detail, attach bank proof and sag preview on pc and operasi, printable list online payment using datatable component, set minimum_pinjaman to 1

This commit is contained in:
ISMAIL MASSERAN
2026-09-17 14:20:55 +08:00
parent 0b0c6f9f17
commit 2377f5b73a
11 changed files with 685 additions and 128 deletions
@@ -115,6 +115,19 @@ class PembiayaanOnlineController extends Controller
'update_customer_bank' => true,
];
if ($request->hasFile('bukti_akaun')) {
$file = $request->file('bukti_akaun');
if (!$file->isValid()) {
return redirect()->back()->with('error', 'Fail slip bank tidak sah.');
}
if ($file->getSize() > 4 * 1024 * 1024) {
return redirect()->back()->with('error', 'Saiz fail maksimum 4MB.');
}
$payload['bukti_akaun_data'] = base64_encode(file_get_contents($file->getRealPath()));
$payload['bukti_akaun_filename'] = $file->getClientOriginalName();
$payload['bukti_akaun_type'] = $file->getMimeType() ?: 'application/octet-stream';
}
$res = $this->api()
->asForm()
->put($api_url . '/api/pembiayaan-online/' . $kodcaw . '/lines/' . $id, $payload);
@@ -125,7 +138,55 @@ class PembiayaanOnlineController extends Controller
return redirect()->back()->with('error', $msg);
}
return redirect()->route('pembiayaan.online.pc')->with('message', 'Rekod dikemaskini.');
return redirect()->route('pembiayaan.online.pc')
->with('message', 'Rekod dikemaskini. Sila semak semula sebelum hantar ke Operasi.');
}
/**
* PC verifies one queue line before it can be submitted to Operasi.
*/
public function verifyLine(Request $request, $id)
{
$this->abortUnlessPembiayaanOnline();
$kodcaw = $this->kodcaw();
$api_url = config('api.url');
$auth_user = Auth::user();
$res = $this->api()
->asForm()
->post($api_url . '/api/pembiayaan-online/' . $kodcaw . '/lines/' . $id . '/verify', [
'pc_verified_by' => $auth_user['name'],
]);
if (!$res->successful()) {
$body = $res->json();
$msg = is_array($body) && isset($body['message']) ? $body['message'] : 'Gagal semak rekod.';
return redirect()->back()->with('error', $msg);
}
return redirect()->route('pembiayaan.online.pc')->with('message', 'Rekod disahkan. Boleh dipilih untuk hantar ke Operasi.');
}
/**
* Undo PC verification on a queue line.
*/
public function unverifyLine(Request $request, $id)
{
$this->abortUnlessPembiayaanOnline();
$kodcaw = $this->kodcaw();
$api_url = config('api.url');
$res = $this->api()
->asForm()
->post($api_url . '/api/pembiayaan-online/' . $kodcaw . '/lines/' . $id . '/unverify');
if (!$res->successful()) {
$body = $res->json();
$msg = is_array($body) && isset($body['message']) ? $body['message'] : 'Gagal batal semakan.';
return redirect()->back()->with('error', $msg);
}
return redirect()->route('pembiayaan.online.pc')->with('message', 'Semakan dibatalkan. Sila semak semula sebelum hantar.');
}
/**
@@ -259,17 +320,87 @@ class PembiayaanOnlineController extends Controller
return redirect()->back()->with('error', 'Fail bukti kosong.');
}
$raw = $bukti['data'];
return $this->streamBase64File($bukti, 'bukti-' . $id);
}
/**
* PC: view uploaded customer bank slip.
*/
public function viewBuktiAkaun($id)
{
$this->abortUnlessPembiayaanOnline();
$kodcaw = $this->kodcaw();
$res = $this->api()
->get(config('api.url') . '/api/pembiayaan-online/' . $kodcaw . '/lines/' . $id . '/bukti-akaun');
if (!$res->successful()) {
$body = $res->json();
$msg = is_array($body) && isset($body['message']) ? $body['message'] : 'Slip bank tidak dijumpai.';
return redirect()->back()->with('error', $msg);
}
$payload = $res->json();
$file = $payload['file'] ?? null;
if (!$file || empty($file['data'])) {
return redirect()->back()->with('error', 'Fail slip bank kosong.');
}
return $this->streamBase64File($file, 'slip-bank-' . $id);
}
/**
* PC: view SAG for a queue line (does not mark SAG as printed).
*/
public function viewSag($id)
{
$this->abortUnlessPembiayaanOnline();
return $this->renderLineSag($this->kodcaw(), $id);
}
/**
* Operasi: view uploaded customer bank slip.
*/
public function operasiViewBuktiAkaun($kodcaw, $id)
{
$res = $this->api()
->get(config('api.url') . '/api/pembiayaan-online/' . $kodcaw . '/lines/' . $id . '/bukti-akaun');
if (!$res->successful()) {
$body = $res->json();
$msg = is_array($body) && isset($body['message']) ? $body['message'] : 'Slip bank tidak dijumpai.';
return redirect()->back()->with('error', $msg);
}
$payload = $res->json();
$file = $payload['file'] ?? null;
if (!$file || empty($file['data'])) {
return redirect()->back()->with('error', 'Fail slip bank kosong.');
}
return $this->streamBase64File($file, 'slip-bank-' . $id);
}
/**
* Operasi: view SAG for a batch line.
*/
public function operasiViewSag($kodcaw, $id)
{
return $this->renderLineSag($kodcaw, $id);
}
protected function streamBase64File(array $file, $fallbackName)
{
$raw = $file['data'];
if (strpos($raw, 'base64,') !== false) {
$raw = substr($raw, strpos($raw, 'base64,') + 7);
}
$binary = base64_decode($raw, true);
if ($binary === false) {
$binary = base64_decode($bukti['data']);
$binary = base64_decode($file['data']);
}
$type = $bukti['type'] ?? 'application/octet-stream';
$filename = $bukti['filename'] ?? ('bukti-' . $id);
$type = $file['type'] ?? 'application/octet-stream';
$filename = $file['filename'] ?? $fallbackName;
return response($binary, 200, [
'Content-Type' => $type,
@@ -277,6 +408,115 @@ class PembiayaanOnlineController extends Controller
]);
}
protected function renderLineSag($kodcaw, $id)
{
$api_url = config('api.url');
$res = $this->api()->get($api_url . '/api/pembiayaan-online/' . $kodcaw . '/lines/' . $id);
if (!$res->successful()) {
$body = $res->json();
$msg = is_array($body) && isset($body['message']) ? $body['message'] : 'Rekod tidak dijumpai.';
return redirect()->back()->with('error', $msg);
}
$line = $res->json();
$norujukan = is_array($line) ? trim((string) ($line['norujukan'] ?? '')) : '';
if ($norujukan === '') {
return redirect()->back()->with('error', 'No. SAG tidak dijumpai.');
}
return $this->renderSagByNorujukan($kodcaw, $norujukan);
}
protected function renderSagByNorujukan($kodcaw, $norujukan)
{
$api_url = config('api.url');
$auth_user = Auth::user();
$auth_username = $auth_user['name'] ?? '';
$gadai = $this->api()
->get($api_url . '/api/gadai/norujukan/' . $kodcaw . '/' . $norujukan)
->json();
$gadai_detail = is_array($gadai) ? ($gadai[0] ?? null) : null;
if (!is_array($gadai_detail) || empty($gadai_detail['norujukan'])) {
return redirect()->back()->with('error', 'SAG tidak dijumpai.');
}
$kakitangan = \App\User::where([['role_harian', 'khazanah'], ['cawangan', $kodcaw]])->first();
$customer = $this->api()
->get($api_url . '/api/customers/' . ($gadai_detail['nokp'] ?? ''))
->json();
$customer_detail = is_array($customer) ? $customer : [];
$marhun = $this->api()
->get($api_url . '/api/marhun/' . $norujukan)
->json();
$marhun_detail = is_array($marhun) ? ($marhun[0] ?? []) : [];
if (!is_array($marhun_detail)) {
$marhun_detail = [];
}
$mutu = $this->api()
->get($api_url . '/api/marhun/mutu/sag', [
'kodcaw' => $kodcaw,
'norujukan' => $norujukan,
])
->json();
$cawangan = $this->api()
->get($api_url . '/api/cawangan/detail/' . $kodcaw)
->json();
$cawangan_detail = is_array($cawangan) ? ($cawangan[0] ?? []) : [];
$kadar_ujrah = $this->api()
->get($api_url . '/api/kadarujrah/by_group_id/', [
'kodcaw' => $cawangan_detail['kodcaw'] ?? $kodcaw,
])
->json();
$pembayaran_segera = 'https://pay.arrahn.com.my';
$komoditi = $this->api()->get($api_url . '/api/komuditi/check')->json();
$product = $this->api()
->get($api_url . '/api/komuditi/description', [
'kodproduk' => is_array($komoditi) ? ($komoditi['kodproduct'] ?? '') : '',
])
->json();
$nilai = is_array($komoditi) ? (float) ($komoditi['nilai'] ?? 0) : 0;
$kuantiti = $nilai > 0 ? ((float) ($gadai_detail['pinjaman'] ?? 0) / $nilai) : 0;
if (($gadai_detail['tagbaru'] ?? 0) == 1) {
return view('print.sag_ujrah_3', compact(
'komoditi',
'product',
'kuantiti',
'gadai_detail',
'customer_detail',
'marhun_detail',
'cawangan_detail',
'api_url',
'pembayaran_segera',
'auth_username',
'mutu',
'kadar_ujrah',
'kakitangan'
));
}
return view('print.sag', compact(
'gadai_detail',
'customer_detail',
'marhun_detail',
'cawangan_detail',
'api_url',
'pembayaran_segera',
'auth_username',
'mutu',
'kakitangan'
));
}
/**
* PC: tanda rekod PAID sebagai selesai semak / blast.
*/
@@ -131,7 +131,8 @@
@endforeach
</tr>
</thead>
<tbody></tbody>
<tbody>
{{ $slot }}
</tbody>
</table>
</div>
@@ -243,7 +243,7 @@
</tr>
<tr>
<th>Cara Terima Pembiayaan</th>
<td>Online (kredit ke akaun bank) — bukan tunai</td>
<td>Atas Talian (Online)</td>
</tr>
<tr>
<th>Teller</th>
+2 -1
View File
@@ -1302,7 +1302,8 @@
function toggleCaraTerima(pinjaman) {
var pembiayaanOnlineEnabled = $('#pembiayaan_online_enabled').val() === '1';
if (pembiayaanOnlineEnabled && pinjaman >= 5000 && pinjaman <= 50000) {
// MIN PINJAMAN = 1.00
if (pembiayaanOnlineEnabled && pinjaman >= 1 && pinjaman <= 50000) {
$('#cara_terima_section').show();
toggleBankOnlineSection();
} else {
@@ -67,24 +67,15 @@
@endif
</div>
</div>
<div class="card-body table-responsive">
<table class="table table-striped table-sm text-center">
<thead class="thead-dark">
<tr>
<th>Status</th>
<th>SAG</th>
<th>Pelanggan</th>
<th>No KP</th>
<th>Bank</th>
<th>No Akaun</th>
<th>Nama Akaun</th>
<th>Pinjaman (RM)</th>
<th>Rujukan Bayaran</th>
<th>Tindakan</th>
</tr>
</thead>
<tbody>
@forelse($lines as $line)
<div class="card-body">
<x-datatable
id="batch_lines"
class="table-sm text-center"
:filename="'Batch_' . ($batch['batch_no'] ?? $batch['id'])"
:columns="['Bil', 'Status', 'SAG', 'Pelanggan', 'No KP', 'Bank', 'No Akaun', 'Nama Akaun', 'Pinjaman (RM)', 'Rujukan Bayaran', 'Dokumen', 'Tindakan']"
:skipExport="['Dokumen', 'Tindakan']"
>
@foreach($lines as $line)
@php
$st = $line['status'] ?? '';
$badge = 'badge-secondary';
@@ -94,6 +85,7 @@
elseif (in_array($st, ['IN_BATCH', 'OPS_REVIEW'], true)) $badge = 'badge-primary';
@endphp
<tr>
<td>{{ $loop->iteration }}</td>
<td><span class="badge {{ $badge }}">{{ $st ?: '-' }}</span></td>
<td>{{ $line['norujukan'] ?? '-' }}</td>
<td class="text-left">{{ $line['nama_pelanggan'] ?? '-' }}</td>
@@ -103,6 +95,23 @@
<td class="text-left">{{ $line['nama_akaun'] ?? '-' }}</td>
<td class="text-right">{{ number_format((float)($line['pinjaman'] ?? 0), 2) }}</td>
<td>{{ $line['no_rujukan_bayaran'] ?? '-' }}</td>
<td class="text-nowrap">
<button type="button"
class="btn btn-sm btn-outline-dark btn-preview-sag"
data-url="{{ route('pembiayaan.online.operasi.sag', ['kodcaw' => $kodcaw, 'id' => $line['id']]) }}"
data-norujukan="{{ $line['norujukan'] ?? '' }}">
SAG
</button>
@if(!empty($line['bukti_akaun_file_id']))
<a class="btn btn-sm btn-outline-primary"
href="{{ route('pembiayaan.online.operasi.bukti.akaun', ['kodcaw' => $kodcaw, 'id' => $line['id']]) }}"
target="_blank">
Slip Bank
</a>
@else
<span class="text-muted small">Tiada slip</span>
@endif
</td>
<td class="text-nowrap">
@if(in_array($st, ['IN_BATCH', 'OPS_REVIEW'], true))
<form method="post"
@@ -139,19 +148,33 @@
@endif
</td>
</tr>
@empty
<tr>
<td colspan="10">Tiada rekod dalam batch.</td>
</tr>
@endforelse
</tbody>
</table>
@endforeach
</x-datatable>
</div>
</div>
</div>
</div>
</div>
{{-- SAG preview modal --}}
<div class="modal fade" id="sagPreviewModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-xl" role="document" style="max-width:1140px;">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Pratinjau SAG — <span id="sagPreviewTitle"></span></h5>
<button type="button" class="close" data-dismiss="modal"><span>&times;</span></button>
</div>
<div class="modal-body p-2">
<iframe id="sagPreviewFrame" title="Pratinjau SAG" src="about:blank"
style="width:100%;height:75vh;border:1px solid #dee2e6;background:#f8f9fa;"></iframe>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Tutup</button>
</div>
</div>
</div>
</div>
{{-- Reject modal --}}
<div class="modal fade" id="rejectModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog" role="document">
@@ -252,7 +275,28 @@
</div>
<script>
$('.btn-reject').on('click', function () {
var table = initErahnDatatable('#batch_lines', {
columnDefs: [
{ targets: 0, orderable: false, searchable: false, width: '40px' },
{ targets: [10, 11], orderable: false, searchable: false }
]
});
table.on('draw.dt', function () {
table.column(0, { search: 'applied', order: 'applied' }).nodes().each(function (cell, i) {
cell.innerHTML = i + 1;
});
}).draw();
$('#batch_lines').on('click', '.btn-preview-sag', function () {
$('#sagPreviewTitle').text($(this).data('norujukan') || '');
$('#sagPreviewFrame').attr('src', $(this).data('url'));
$('#sagPreviewModal').modal('show');
});
$('#sagPreviewModal').on('hidden.bs.modal', function () {
$('#sagPreviewFrame').attr('src', 'about:blank');
});
$('#batch_lines').on('click', '.btn-reject', function () {
var id = $(this).data('id');
$('#rejectForm').attr(
'action',
@@ -263,7 +307,7 @@
$('#rejectModal').modal('show');
});
$('.btn-paid').on('click', function () {
$('#batch_lines').on('click', '.btn-paid', function () {
var id = $(this).data('id');
$('#paidForm').attr(
'action',
@@ -40,6 +40,7 @@
<th>No Akaun</th>
<th>Pinjaman (RM)</th>
<th>Rujukan Bayaran</th>
<th>Dokumen</th>
</tr>
</thead>
<tbody>
@@ -53,6 +54,23 @@
<td>{{ $line['noakaun'] ?? '-' }}</td>
<td class="text-right">{{ number_format((float)($line['pinjaman'] ?? 0), 2) }}</td>
<td>{{ $line['no_rujukan_bayaran'] ?? '-' }}</td>
<td class="text-nowrap">
<button type="button"
class="btn btn-sm btn-outline-dark btn-preview-sag"
data-url="{{ route('pembiayaan.online.pc.sag', ['id' => $line['id']]) }}"
data-norujukan="{{ $line['norujukan'] ?? '' }}">
SAG
</button>
@if(!empty($line['bukti_akaun_file_id']))
<a class="btn btn-sm btn-outline-primary"
href="{{ route('pembiayaan.online.pc.bukti.akaun', ['id' => $line['id']]) }}"
target="_blank">
Slip Bank
</a>
@else
<span class="text-muted small">Tiada slip</span>
@endif
</td>
</tr>
@endforeach
</tbody>
@@ -62,4 +80,32 @@
</div>
</div>
</div>
<div class="modal fade" id="sagPreviewModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-xl" role="document" style="max-width:1140px;">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Pratinjau SAG — <span id="sagPreviewTitle"></span></h5>
<button type="button" class="close" data-dismiss="modal"><span>&times;</span></button>
</div>
<div class="modal-body p-2">
<iframe id="sagPreviewFrame" title="Pratinjau SAG" src="about:blank"
style="width:100%;height:75vh;border:1px solid #dee2e6;background:#f8f9fa;"></iframe>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Tutup</button>
</div>
</div>
</div>
</div>
<script>
$('.btn-preview-sag').on('click', function () {
$('#sagPreviewTitle').text($(this).data('norujukan') || '');
$('#sagPreviewFrame').attr('src', $(this).data('url'));
$('#sagPreviewModal').modal('show');
});
$('#sagPreviewModal').on('hidden.bs.modal', function () {
$('#sagPreviewFrame').attr('src', 'about:blank');
});
</script>
@endsection
@@ -33,6 +33,9 @@
if (is_object($pendingReq)) {
$pendingReq = json_decode(json_encode($pendingReq), true);
}
$lineRows = collect($lines);
$verifiedCount = $lineRows->where('status', 'VERIFIED_PC')->count();
$unverifiedCount = $lineRows->count() - $verifiedCount;
@endphp
@if($isClosed)
@@ -84,7 +87,11 @@
<div class="card-body text-center">
<div class="text-muted">Queue PC</div>
<h4 class="mb-0">{{ count($lines) }} rekod</h4>
<small>Jumlah RM {{ number_format((float)($queue['jumlah'] ?? 0), 2) }}</small>
<small>
{{ $verifiedCount }} sudah sah
/ {{ $unverifiedCount }} belum semak
&middot; Jumlah RM {{ number_format((float)($queue['jumlah'] ?? 0), 2) }}
</small>
</div>
</div>
</div>
@@ -101,10 +108,14 @@
<div class="card mb-4">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="mb-0">Senarai Menunggu (PENDING / REJECTED)</h5>
<h5 class="mb-0">Senarai Menunggu (PENDING / REJECTED / SAH)</h5>
<button type="button" class="btn btn-primary" id="btnSubmitBatch" disabled>Hantar Batch ke Operasi</button>
</div>
<div class="card-body">
<p class="small text-muted">
Semak setiap rekod <b>satu-satu</b> (maklumat pelanggan, bank, amaun).
Hanya rekod berstatus <span class="badge badge-success">SAH</span> boleh dipilih dan dihantar ke Operasi.
</p>
<form id="formSubmitBatch" method="post" action="{{ route('pembiayaan.online.pc.submit') }}">
@csrf
<input type="hidden" name="slot" value="{{ $slot['slot'] ?? 'BATCH1' }}">
@@ -112,7 +123,7 @@
<table class="table table-striped table-hover table-sm text-center" id="queueTable">
<thead class="thead-dark">
<tr>
<th><input type="checkbox" id="checkAll"></th>
<th><input type="checkbox" id="checkAll" title="Pilih semua yang sudah sah"></th>
<th>Status</th>
<th>SAG</th>
<th>Pelanggan</th>
@@ -126,15 +137,31 @@
</thead>
<tbody>
@forelse($lines as $line)
<tr class="{{ ($line['status'] ?? '') === 'REJECTED_PC' ? 'table-warning' : '' }}">
@php
$st = $line['status'] ?? '';
$isVerified = $st === 'VERIFIED_PC';
$isRejected = $st === 'REJECTED_PC';
$bankOk = !empty($line['kodbank']) && !empty($line['noakaun']);
@endphp
<tr class="{{ $isRejected ? 'table-warning' : ($isVerified ? 'table-success' : '') }}">
<td>
<input type="checkbox" class="row-check" name="ids[]" value="{{ $line['id'] }}">
<input type="checkbox"
class="row-check"
name="ids[]"
value="{{ $line['id'] }}"
{{ $isVerified ? '' : 'disabled' }}
title="{{ $isVerified ? '' : 'Sahkan rekod ini dahulu' }}">
</td>
<td>
@if(($line['status'] ?? '') === 'REJECTED_PC')
@if($isRejected)
<span class="badge badge-danger">REJECTED</span>
@elseif($isVerified)
<span class="badge badge-success">SAH</span>
@if(!empty($line['pc_verified_by']))
<div class="small text-muted">{{ $line['pc_verified_by'] }}</div>
@endif
@else
<span class="badge badge-secondary">PENDING</span>
<span class="badge badge-secondary">BELUM SEMAK</span>
@endif
</td>
<td>{{ $line['norujukan'] ?? '-' }}</td>
@@ -144,7 +171,33 @@
<td>{{ $line['noakaun'] ?? '-' }}</td>
<td class="text-right">{{ number_format((float)($line['pinjaman'] ?? 0), 2) }}</td>
<td class="text-left small">{{ $line['reject_reason'] ?? '-' }}</td>
<td>
<td class="text-nowrap">
@if($isVerified)
<button type="button"
class="btn btn-sm btn-outline-secondary btn-unverify"
data-id="{{ $line['id'] }}"
data-norujukan="{{ $line['norujukan'] ?? '' }}">
Batal
</button>
@else
<button type="button"
class="btn btn-sm btn-success btn-verify"
{{ $bankOk ? '' : 'disabled' }}
title="{{ $bankOk ? 'Semak maklumat pelanggan' : 'Lengkapkan maklumat bank dahulu' }}"
data-id="{{ $line['id'] }}"
data-norujukan="{{ $line['norujukan'] ?? '' }}"
data-nama="{{ $line['nama_pelanggan'] ?? '' }}"
data-nokp="{{ $line['nokp'] ?? '' }}"
data-namabank="{{ $line['nama_bank'] ?? $line['kodbank'] ?? '' }}"
data-noakaun="{{ $line['noakaun'] ?? '' }}"
data-namaakaun="{{ $line['nama_akaun'] ?? '' }}"
data-pinjaman="{{ number_format((float)($line['pinjaman'] ?? 0), 2) }}"
data-nota="{{ $line['nota'] ?? '' }}"
data-sebab="{{ $line['reject_reason'] ?? '' }}"
data-bukti-akaun="{{ $line['bukti_akaun_file_id'] ?? '' }}">
Semak
</button>
@endif
<button type="button" class="btn btn-sm btn-info btn-edit"
data-id="{{ $line['id'] }}"
data-kodbank="{{ $line['kodbank'] ?? '' }}"
@@ -152,7 +205,8 @@
data-namaakaun="{{ $line['nama_akaun'] ?? '' }}"
data-namabank="{{ $line['nama_bank'] ?? '' }}"
data-nota="{{ $line['nota'] ?? '' }}"
data-norujukan="{{ $line['norujukan'] ?? '' }}">
data-norujukan="{{ $line['norujukan'] ?? '' }}"
data-bukti-akaun="{{ $line['bukti_akaun_file_id'] ?? '' }}">
Edit
</button>
</td>
@@ -166,6 +220,9 @@
</table>
</div>
</form>
<form id="formUnverify" method="post" action="" class="d-none">
@csrf
</form>
</div>
</div>
@@ -221,8 +278,8 @@
{{-- Edit modal --}}
<div class="modal fade" id="editModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog" role="document">
<form method="post" id="editForm" action="">
<div class="modal-dialog modal-xl" role="document" style="max-width:1140px;">
<form method="post" id="editForm" action="" enctype="multipart/form-data">
@csrf
@method('PUT')
<div class="modal-content">
@@ -231,6 +288,8 @@
<button type="button" class="close" data-dismiss="modal"><span>&times;</span></button>
</div>
<div class="modal-body">
<div class="row">
<div class="col-md-4">
<div class="form-group">
<label>Bank</label>
<select name="kodbank" id="editKodbank" class="form-control" required>
@@ -251,10 +310,29 @@
<label>Nama Akaun</label>
<input type="text" name="nama_akaun" id="editNamaakaun" class="form-control">
</div>
<div class="form-group">
<label>Slip Bank / Bukti Akaun</label>
<input type="file" name="bukti_akaun" id="editBuktiAkaun" class="form-control-file"
accept=".pdf,.jpg,.jpeg,.png,.gif">
<div id="editBuktiAkaunExisting" class="mt-2" style="display:none;">
<a href="#" id="editBuktiAkaunLink" class="btn btn-sm btn-outline-primary" target="_blank">
Lihat slip sedia ada
</a>
</div>
<small class="text-muted">PDF / imej slip akaun bank pelanggan (maks 4MB)</small>
</div>
<div class="form-group">
<label>Nota</label>
<textarea name="nota" id="editNota" class="form-control" rows="2"></textarea>
</div>
<p class="small text-muted mb-0">Jika rekod sudah SAH, simpan akan batal semakan. Sila semak semula sebelum hantar.</p>
</div>
<div class="col-md-8">
<label class="d-block">Pratinjau SAG</label>
<iframe id="editSagFrame" title="Pratinjau SAG" src="about:blank"
style="width:100%;height:70vh;border:1px solid #dee2e6;background:#f8f9fa;"></iframe>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Tutup</button>
@@ -265,26 +343,149 @@
</div>
</div>
{{-- Verify one-by-one modal --}}
<div class="modal fade" id="verifyModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-xl" role="document" style="max-width:1140px;">
<form method="post" id="verifyForm" action="">
@csrf
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Semak Rekod — <span id="verifyNorujukan"></span></h5>
<button type="button" class="close" data-dismiss="modal"><span>&times;</span></button>
</div>
<div class="modal-body">
<p class="small text-muted">Bandingkan maklumat pelanggan dengan SAG / slip bank sebelum sahkan.</p>
<div class="row">
<div class="col-md-4">
<table class="table table-sm table-bordered mb-3">
<tr>
<th style="width:40%">SAG</th>
<td id="verifySag"></td>
</tr>
<tr>
<th>Pelanggan</th>
<td id="verifyNama"></td>
</tr>
<tr>
<th>No KP</th>
<td id="verifyNokp"></td>
</tr>
<tr>
<th>Bank</th>
<td id="verifyBank"></td>
</tr>
<tr>
<th>No Akaun</th>
<td id="verifyNoakaun"></td>
</tr>
<tr>
<th>Nama Akaun</th>
<td id="verifyNamaakaun"></td>
</tr>
<tr>
<th>Pinjaman</th>
<td>RM <span id="verifyPinjaman"></span></td>
</tr>
<tr>
<th>Nota</th>
<td id="verifyNota"></td>
</tr>
</table>
<div class="alert alert-warning py-2" id="verifySebabBox" style="display:none;">
<b>Sebab tolak Operasi:</b>
<div id="verifySebab"></div>
</div>
<div class="form-check mb-3">
<input type="checkbox" class="form-check-input" id="verifyConfirm" required>
<label class="form-check-label" for="verifyConfirm">
Saya sahkan maklumat pelanggan, bank dan amaun adalah betul.
</label>
</div>
<a href="#" id="verifyBuktiAkaunLink" class="btn btn-sm btn-outline-primary" target="_blank" style="display:none;">
Lihat Slip Bank
</a>
</div>
<div class="col-md-8">
<label class="d-block">Pratinjau SAG</label>
<iframe id="verifySagFrame" title="Pratinjau SAG" src="about:blank"
style="width:100%;height:70vh;border:1px solid #dee2e6;background:#f8f9fa;"></iframe>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Batal</button>
<button type="submit" class="btn btn-success">Sahkan Rekod Ini</button>
</div>
</div>
</form>
</div>
</div>
<script>
function syncSubmitButton() {
var n = $('.row-check:checked').length;
var n = $('.row-check:not(:disabled):checked').length;
$('#btnSubmitBatch').prop('disabled', n === 0);
$('#btnSubmitBatch').text(n ? ('Hantar Batch ke Operasi (' + n + ')') : 'Hantar Batch ke Operasi');
}
$('#checkAll').on('change', function () {
$('.row-check').prop('checked', this.checked);
$('.row-check:not(:disabled)').prop('checked', this.checked);
syncSubmitButton();
});
$(document).on('change', '.row-check', syncSubmitButton);
$(document).on('change', '.row-check', function () {
var enabled = $('.row-check:not(:disabled)');
$('#checkAll').prop('checked', enabled.length > 0 && enabled.filter(':checked').length === enabled.length);
syncSubmitButton();
});
$('#btnSubmitBatch').on('click', function () {
if ($('.row-check:checked').length === 0) return;
if (!confirm('Hantar rekod dipilih ke Operasi?')) return;
if ($('.row-check:not(:disabled):checked').length === 0) return;
if (!confirm('Hantar rekod yang sudah disahkan ke Operasi?')) return;
$('#formSubmitBatch').submit();
});
$('.btn-unverify').on('click', function () {
var id = $(this).data('id');
var sag = $(this).data('norujukan') || '';
if (!confirm('Batal semakan ' + sag + '? Rekod ini tidak boleh dihantar sehingga disemak semula.')) return;
$('#formUnverify').attr('action', "{{ url('/pembiayaan-online/pc/lines') }}/" + id + "/unverify");
$('#formUnverify').submit();
});
$('.btn-verify').on('click', function () {
var id = $(this).data('id');
var sebab = $(this).data('sebab') || '';
$('#verifyForm').attr('action', "{{ url('/pembiayaan-online/pc/lines') }}/" + id + "/verify");
$('#verifyNorujukan').text($(this).data('norujukan'));
$('#verifySag').text($(this).data('norujukan') || '-');
$('#verifyNama').text($(this).data('nama') || '-');
$('#verifyNokp').text($(this).data('nokp') || '-');
$('#verifyBank').text($(this).data('namabank') || '-');
$('#verifyNoakaun').text($(this).data('noakaun') || '-');
$('#verifyNamaakaun').text($(this).data('namaakaun') || '-');
$('#verifyPinjaman').text($(this).data('pinjaman') || '0.00');
$('#verifyNota').text($(this).data('nota') || '-');
if (sebab) {
$('#verifySebab').text(sebab);
$('#verifySebabBox').show();
} else {
$('#verifySebabBox').hide();
}
$('#verifyConfirm').prop('checked', false);
$('#verifySagFrame').attr('src', "{{ url('/pembiayaan-online/pc/lines') }}/" + id + "/sag");
if ($(this).data('buktiAkaun')) {
$('#verifyBuktiAkaunLink').attr('href', "{{ url('/pembiayaan-online/pc/lines') }}/" + id + "/bukti-akaun").show();
} else {
$('#verifyBuktiAkaunLink').hide();
}
$('#verifyModal').modal('show');
});
$('#verifyModal').on('hidden.bs.modal', function () {
$('#verifySagFrame').attr('src', 'about:blank');
});
$('.btn-edit').on('click', function () {
var id = $(this).data('id');
$('#editForm').attr('action', "{{ url('/pembiayaan-online/pc/lines') }}/" + id);
@@ -294,9 +495,21 @@
$('#editNamaakaun').val($(this).data('namaakaun'));
$('#editNamabank').val($(this).data('namabank'));
$('#editNota').val($(this).data('nota'));
$('#editBuktiAkaun').val('');
$('#editSagFrame').attr('src', "{{ url('/pembiayaan-online/pc/lines') }}/" + id + "/sag");
if ($(this).data('buktiAkaun')) {
$('#editBuktiAkaunLink').attr('href', "{{ url('/pembiayaan-online/pc/lines') }}/" + id + "/bukti-akaun");
$('#editBuktiAkaunExisting').show();
} else {
$('#editBuktiAkaunExisting').hide();
}
$('#editModal').modal('show');
});
$('#editModal').on('hidden.bs.modal', function () {
$('#editSagFrame').attr('src', 'about:blank');
});
$('#editKodbank').on('change', function () {
$('#editNamabank').val($('#editKodbank option:selected').data('nama') || '');
});
@@ -223,7 +223,7 @@
</tr>
<tr>
<th>Cara Terima Pembiayaan</th>
<td>Online (kredit ke akaun bank) — bukan tunai</td>
<td>Atas Talian (Online)</td>
</tr>
<tr>
<th>Teller</th>
+3
View File
@@ -6,6 +6,9 @@
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>
$(document).ready(function () {
if (window.self !== window.top) {
return;
}
window.print();
window.onfocus=function(){ window.close();}
});
@@ -395,6 +395,9 @@
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>
$(document).ready(function() {
if (window.self !== window.top) {
return;
}
window.print();
window.onfocus = function() {
window.close();
+6
View File
@@ -193,6 +193,10 @@ Route::get('/permohonan',['as'=>'permohonan.index','uses' => 'KhazanahController
// Pembiayaan Online — PC
Route::get('/pembiayaan-online/pc',['as'=>'pembiayaan.online.pc','uses'=>'PembiayaanOnlineController@index'])->middleware('auth','khazanah');
Route::put('/pembiayaan-online/pc/lines/{id}',['as'=>'pembiayaan.online.pc.update','uses'=>'PembiayaanOnlineController@updateLine'])->middleware('auth','khazanah');
Route::post('/pembiayaan-online/pc/lines/{id}/verify',['as'=>'pembiayaan.online.pc.verify','uses'=>'PembiayaanOnlineController@verifyLine'])->middleware('auth','khazanah');
Route::post('/pembiayaan-online/pc/lines/{id}/unverify',['as'=>'pembiayaan.online.pc.unverify','uses'=>'PembiayaanOnlineController@unverifyLine'])->middleware('auth','khazanah');
Route::get('/pembiayaan-online/pc/lines/{id}/bukti-akaun',['as'=>'pembiayaan.online.pc.bukti.akaun','uses'=>'PembiayaanOnlineController@viewBuktiAkaun'])->middleware('auth','khazanah');
Route::get('/pembiayaan-online/pc/lines/{id}/sag',['as'=>'pembiayaan.online.pc.sag','uses'=>'PembiayaanOnlineController@viewSag'])->middleware('auth','khazanah');
Route::post('/pembiayaan-online/pc/batches/submit',['as'=>'pembiayaan.online.pc.submit','uses'=>'PembiayaanOnlineController@submitBatch'])->middleware('auth','khazanah');
Route::get('/pembiayaan-online/pc/batches/{batchId}',['as'=>'pembiayaan.online.pc.batch','uses'=>'PembiayaanOnlineController@showBatch'])->middleware('auth','khazanah');
Route::get('/pembiayaan-online/pc/paid',['as'=>'pembiayaan.online.pc.paid','uses'=>'PembiayaanOnlineController@paidIndex'])->middleware('auth','khazanah');
@@ -217,6 +221,8 @@ Route::post('/pembiayaan-online/operasi/{kodcaw}/lines/{id}/reject',['as'=>'pemb
Route::post('/pembiayaan-online/operasi/{kodcaw}/batches/{batchId}/approve',['as'=>'pembiayaan.online.operasi.approve.batch','uses'=>'PembiayaanOnlineController@operasiApproveBatch'])->middleware('auth','operasi');
Route::post('/pembiayaan-online/operasi/{kodcaw}/lines/{id}/paid',['as'=>'pembiayaan.online.operasi.paid','uses'=>'PembiayaanOnlineController@operasiMarkPaid'])->middleware('auth','operasi');
Route::post('/pembiayaan-online/operasi/{kodcaw}/batches/{batchId}/paid',['as'=>'pembiayaan.online.operasi.paid.batch','uses'=>'PembiayaanOnlineController@operasiMarkPaidBatch'])->middleware('auth','operasi');
Route::get('/pembiayaan-online/operasi/{kodcaw}/lines/{id}/bukti-akaun',['as'=>'pembiayaan.online.operasi.bukti.akaun','uses'=>'PembiayaanOnlineController@operasiViewBuktiAkaun'])->middleware('auth','operasi');
Route::get('/pembiayaan-online/operasi/{kodcaw}/lines/{id}/sag',['as'=>'pembiayaan.online.operasi.sag','uses'=>'PembiayaanOnlineController@operasiViewSag'])->middleware('auth','operasi');
Route::get('/permohonan/rekod',['as'=>'permohonan.rekod','uses' => 'KhazanahController@RekodPermohonan'])->middleware('auth','khazanah');
Route::post('/permohonan/simpan',['as'=>'permohonan.simpan','uses' => 'KhazanahController@SimpanPermohonan'])->middleware('auth','khazanah');
Route::get('/permohonan/status/{mohonid}',['as'=>'permohonan.status','uses' => 'KhazanahController@StatusPermohonan'])->middleware('auth','khazanah');