feat: mandatory IC scan upload on customer register and customer_info

This commit is contained in:
2026-10-27 13:31:33 +08:00
parent 05f1700087
commit 510b118a23
10 changed files with 480 additions and 15 deletions
@@ -312,6 +312,61 @@ class CustomersController extends Controller
return response()->json($response->json() ?? ['stored' => false], $response->status()); return response()->json($response->json() ?? ['stored' => false], $response->status());
} }
/**
* Upload scanned IC / passport document for the current customer.
*/
public function storeIcScan(Request $request)
{
$icno = preg_replace('/[^0-9A-Za-z]/', '', (string) ($request->input('icno') ?: Session::get('noic')));
if ($icno === '') {
return response()->json(['error' => 'No. IC diperlukan.', 'stored' => false], 422);
}
list($scanPayload, $scanError) = $this->scanIcPayloadFromRequest($request);
if ($scanError) {
return response()->json(['error' => $scanError, 'stored' => false], 422);
}
$response = Http::withOptions(['verify' => config('app.api_verify')])
->post(config('api.url') . '/api/customers/' . $icno . '/ic-scan', $scanPayload);
return response()->json($response->json() ?? ['stored' => false], $response->status());
}
public function showIcScan(Request $request)
{
$icno = preg_replace('/[^0-9A-Za-z]/', '', (string) ($request->query('icno') ?: Session::get('noic')));
if ($icno === '') {
abort(404);
}
$response = Http::withOptions(['verify' => config('app.api_verify')])
->get(config('api.url') . '/api/customers/' . $icno . '/ic-scan');
$payload = $response->json();
$file = is_array($payload) ? ($payload['file'] ?? null) : null;
if (!$response->successful() || !$file || empty($file['data'])) {
abort(404);
}
$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($file['data']);
}
$type = $file['type'] ?? 'application/octet-stream';
$filename = $file['filename'] ?? 'scan-ic';
return response($binary, 200, [
'Content-Type' => $type,
'Content-Disposition' => 'inline; filename="' . $filename . '"',
]);
}
/** /**
* Show the form for creating a new resource. * Show the form for creating a new resource.
* *
@@ -330,6 +385,11 @@ class CustomersController extends Controller
*/ */
public function store(Request $request) public function store(Request $request)
{ {
list($scanPayload, $scanError) = $this->scanIcPayloadFromRequest($request);
if ($scanError) {
return redirect()->back()->with('error', $scanError)->withInput();
}
if ($request->idtype == 'nokp') { if ($request->idtype == 'nokp') {
$nokpbaru = $request->noic; $nokpbaru = $request->noic;
$nokplama = ''; $nokplama = '';
@@ -415,6 +475,10 @@ class CustomersController extends Controller
$customer_payload['photo_mime'] = $request->input('photo_mime') ?: 'image/jpeg'; $customer_payload['photo_mime'] = $request->input('photo_mime') ?: 'image/jpeg';
} }
$customer_payload['file_base64'] = $scanPayload['file_base64'];
$customer_payload['file_mime'] = $scanPayload['file_mime'];
$customer_payload['filename'] = $scanPayload['filename'];
$customer_info = Http::withOptions(['verify' => config('app.api_verify')])->post(config('api.url') . '/api/customers/create/' . $auth_user['cawangan'], $customer_payload); $customer_info = Http::withOptions(['verify' => config('app.api_verify')])->post(config('api.url') . '/api/customers/create/' . $auth_user['cawangan'], $customer_payload);
Session::put('customer_info', $customer_info); Session::put('customer_info', $customer_info);
@@ -692,6 +756,34 @@ class CustomersController extends Controller
]); ]);
} }
private function scanIcPayloadFromRequest(Request $request)
{
if (!$request->hasFile('scan_ic')) {
return [null, 'Sila muat naik scan dokumen IC / Passport.'];
}
$file = $request->file('scan_ic');
if (!$file->isValid()) {
return [null, 'Fail scan IC tidak sah.'];
}
if ($file->getSize() > 4 * 1024 * 1024) {
return [null, 'Saiz fail scan IC maksimum 4MB.'];
}
$mime = strtolower((string) ($file->getMimeType() ?: ''));
$allowed = ['image/jpeg', 'image/jpg', 'image/png', 'application/pdf'];
if (!in_array($mime, $allowed, true)) {
return [null, 'Format fail scan IC mestilah JPG, PNG atau PDF.'];
}
return [[
'file_base64' => base64_encode(file_get_contents($file->getRealPath())),
'file_mime' => $mime,
'filename' => $file->getClientOriginalName(),
], null];
}
private function printBlank($value) private function printBlank($value)
{ {
if ($value === null) { if ($value === null) {
@@ -164,6 +164,9 @@ class GadaianController extends Controller
$noic = $request->noic; $noic = $request->noic;
$customers_info = Http::withOptions(['verify' => config('app.api_verify')])->get(config('api.url') . '/api/customers/' . $noic)->json(); $customers_info = Http::withOptions(['verify' => config('app.api_verify')])->get(config('api.url') . '/api/customers/' . $noic)->json();
$customer_info = $customers_info; $customer_info = $customers_info;
if (!is_array($customer_info) || empty($customer_info['has_scan_ic'])) {
return redirect()->route('customer_info')->with('error', 'Sila muat naik scan dokumen IC sebelum daftar pembiayaan.');
}
$limit_pinjaman_semasa = 0; $limit_pinjaman_semasa = 0;
$auth_user = Auth::user(); $auth_user = Auth::user();
if ($request->session()->get('page_reload') == null) { if ($request->session()->get('page_reload') == null) {
@@ -0,0 +1,19 @@
<div class="ic-scan-register-field px-3 pb-2">
<div class="row form-group mb-0">
<div class="col-md-4">
Scan IC / Passport <span class="text-danger">*</span>
</div>
<div class="col-md-8">
<input class="form-control-file"
type="file"
name="scan_ic"
id="{{ $scanFieldId }}"
accept=".jpg,.jpeg,.png,.pdf,image/jpeg,image/png,application/pdf">
<small class="form-text text-muted">Wajib. JPG, PNG atau PDF (maks 4MB).</small>
<div class="ic-scan-register-preview mt-2 d-none">
<img src="" alt="Preview scan IC" style="max-width:180px;max-height:120px;object-fit:contain;border:1px solid #d0d5dd;border-radius:4px;background:#fff;">
<span class="ic-scan-register-filename small text-muted d-block"></span>
</div>
</div>
</div>
</div>
@@ -0,0 +1,80 @@
<script>
function requireScanIcFromForm(formEl, submitSelector) {
var input = formEl ? formEl.querySelector('input[name="scan_ic"]') : null;
var file = input && input.files && input.files[0] ? input.files[0] : null;
if (!file) {
$(submitSelector).prop('disabled', false);
Swal.fire({
icon: 'error',
title: 'Amaran!',
text: 'Sila muat naik scan dokumen IC / Passport'
});
if (typeof event !== 'undefined' && event) {
event.preventDefault();
}
return false;
}
if (file.size > 4 * 1024 * 1024) {
$(submitSelector).prop('disabled', false);
Swal.fire({
icon: 'error',
title: 'Amaran!',
text: 'Saiz fail scan IC maksimum 4MB'
});
if (typeof event !== 'undefined' && event) {
event.preventDefault();
}
return false;
}
var type = (file.type || '').toLowerCase();
if (['image/jpeg', 'image/jpg', 'image/png', 'application/pdf'].indexOf(type) === -1) {
$(submitSelector).prop('disabled', false);
Swal.fire({
icon: 'error',
title: 'Amaran!',
text: 'Format fail mestilah JPG, PNG atau PDF'
});
if (typeof event !== 'undefined' && event) {
event.preventDefault();
}
return false;
}
return true;
}
$(document).on('change', 'input[name="scan_ic"]', function () {
var file = this.files && this.files[0] ? this.files[0] : null;
var wrap = this.closest('.ic-scan-register-field');
if (!wrap) {
return;
}
var preview = wrap.querySelector('.ic-scan-register-preview');
var img = wrap.querySelector('.ic-scan-register-preview img');
var nameEl = wrap.querySelector('.ic-scan-register-filename');
if (!file) {
if (preview) {
preview.classList.add('d-none');
}
return;
}
if (preview) {
preview.classList.remove('d-none');
}
if (nameEl) {
nameEl.textContent = file.name;
}
if (!img) {
return;
}
if ((file.type || '') === 'application/pdf') {
img.classList.add('d-none');
return;
}
img.classList.remove('d-none');
var reader = new FileReader();
reader.onload = function (e) {
img.src = e.target.result;
};
reader.readAsDataURL(file);
});
</script>
@@ -0,0 +1,204 @@
@php
$hasScanIc = !empty($customer_info['has_scan_ic']);
$scanIcMime = strtolower((string) ($customer_info['scan_ic_mime'] ?? ''));
$scanIcIsPdf = strpos($scanIcMime, 'pdf') !== false;
$scanIcNoic = !empty($customer_info['kpbaru']) ? $customer_info['kpbaru'] : ($customer_info['kplama'] ?? '');
$scanIcPreviewUrl = $hasScanIc
? route('customer.showIcScan', ['icno' => $scanIcNoic, 't' => $customer_info['scan_ic'] ?? time()])
: '';
@endphp
<style>
.ic-scan-card {
border: 1px dashed #c5cdd6;
border-radius: 8px;
background: #f8f9fb;
padding: 16px;
margin: 0 15px 18px;
}
.ic-scan-card.is-missing {
border-color: #e0a800;
background: #fff8e8;
}
.ic-scan-preview {
max-width: 220px;
max-height: 140px;
object-fit: contain;
border: 1px solid #d0d5dd;
border-radius: 4px;
background: #fff;
}
</style>
<div id="ic-scan-card" class="ic-scan-card {{ $hasScanIc ? '' : 'is-missing' }}">
<div class="d-flex flex-wrap align-items-start justify-content-between">
<div>
<b>Scan Dokumen IC / Passport <span class="text-danger">*</span></b>
<div class="text-muted small mt-1">
Wajib dimuat naik sebelum daftar pembiayaan. Format JPG, PNG atau PDF (maks 4MB).
</div>
<div id="ic-scan-status" class="mt-2">
@if ($hasScanIc)
<span class="badge badge-success">Telah dimuat naik</span>
@else
<span class="badge badge-warning">Belum dimuat naik</span>
@endif
</div>
</div>
<div class="mt-2 mt-md-0">
<input type="file" id="ic_scan_file" accept=".jpg,.jpeg,.png,.pdf,image/jpeg,image/png,application/pdf" class="d-none">
<button type="button" class="btn btn-outline-primary btn-sm" id="ic_scan_pick">
<i class="fas fa-upload mr-1"></i>{{ $hasScanIc ? 'Muat naik semula' : 'Pilih fail' }}
</button>
<button type="button" class="btn btn-primary btn-sm d-none" id="ic_scan_upload">Muat Naik</button>
</div>
</div>
<div id="ic-scan-preview-wrap" class="mt-3 {{ $hasScanIc ? '' : 'd-none' }}">
@if ($hasScanIc && $scanIcIsPdf)
<a id="ic-scan-pdf-link" href="{{ $scanIcPreviewUrl }}" target="_blank" rel="noopener">Lihat fail PDF</a>
<img id="ic-scan-preview-img" src="" alt="Preview scan IC" class="ic-scan-preview d-none">
@else
<a id="ic-scan-pdf-link" href="{{ $scanIcPreviewUrl }}" target="_blank" rel="noopener" class="{{ $hasScanIc ? 'd-none' : 'd-none' }}">Lihat fail PDF</a>
<img id="ic-scan-preview-img"
src="{{ $hasScanIc ? $scanIcPreviewUrl : '' }}"
alt="Preview scan IC"
class="ic-scan-preview {{ $hasScanIc ? '' : 'd-none' }}">
@endif
<div id="ic-scan-filename" class="small text-muted mt-1">{{ $customer_info['scan_ic_filename'] ?? '' }}</div>
</div>
</div>
<script>
window.hasScanIc = @json($hasScanIc);
(function() {
var fileInput = document.getElementById('ic_scan_file');
var pickBtn = document.getElementById('ic_scan_pick');
var uploadBtn = document.getElementById('ic_scan_upload');
var previewWrap = document.getElementById('ic-scan-preview-wrap');
var previewImg = document.getElementById('ic-scan-preview-img');
var pdfLink = document.getElementById('ic-scan-pdf-link');
var filenameEl = document.getElementById('ic-scan-filename');
var statusEl = document.getElementById('ic-scan-status');
var card = document.getElementById('ic-scan-card');
var selectedFile = null;
var storeUrl = @json(route('customer.storeIcScan'));
var previewUrl = @json(route('customer.showIcScan', ['icno' => $scanIcNoic]));
var csrf = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
var icno = @json($scanIcNoic);
function showUploadedState(filename, mime) {
window.hasScanIc = true;
card.classList.remove('is-missing');
statusEl.innerHTML = '<span class="badge badge-success">Telah dimuat naik</span>';
pickBtn.innerHTML = '<i class="fas fa-upload mr-1"></i>Muat naik semula';
uploadBtn.classList.add('d-none');
previewWrap.classList.remove('d-none');
filenameEl.textContent = filename || '';
var url = previewUrl + (previewUrl.indexOf('?') === -1 ? '?' : '&') + 't=' + Date.now();
if ((mime || '').indexOf('pdf') !== -1) {
previewImg.classList.add('d-none');
pdfLink.classList.remove('d-none');
pdfLink.setAttribute('href', url);
} else {
pdfLink.classList.add('d-none');
previewImg.classList.remove('d-none');
previewImg.src = url;
}
}
pickBtn.addEventListener('click', function() {
fileInput.click();
});
fileInput.addEventListener('change', function() {
selectedFile = fileInput.files && fileInput.files[0] ? fileInput.files[0] : null;
if (!selectedFile) {
uploadBtn.classList.add('d-none');
return;
}
if (selectedFile.size > 4 * 1024 * 1024) {
selectedFile = null;
fileInput.value = '';
Swal.fire({
icon: 'error',
title: 'Fail terlalu besar',
text: 'Saiz fail maksimum 4MB.'
});
return;
}
uploadBtn.classList.remove('d-none');
previewWrap.classList.remove('d-none');
filenameEl.textContent = selectedFile.name;
if (selectedFile.type === 'application/pdf') {
previewImg.classList.add('d-none');
pdfLink.classList.remove('d-none');
pdfLink.setAttribute('href', URL.createObjectURL(selectedFile));
} else {
pdfLink.classList.add('d-none');
previewImg.classList.remove('d-none');
var reader = new FileReader();
reader.onload = function(e) {
previewImg.src = e.target.result;
};
reader.readAsDataURL(selectedFile);
}
});
uploadBtn.addEventListener('click', function() {
if (!selectedFile) {
Swal.fire({
icon: 'warning',
title: 'Tiada fail',
text: 'Sila pilih scan dokumen IC terlebih dahulu.'
});
return;
}
var formData = new FormData();
formData.append('icno', icno);
formData.append('scan_ic', selectedFile);
uploadBtn.disabled = true;
uploadBtn.textContent = 'Memuat naik...';
fetch(storeUrl, {
method: 'POST',
headers: {
'X-CSRF-TOKEN': csrf,
'Accept': 'application/json'
},
body: formData
}).then(function(res) {
return res.json().then(function(body) {
return { ok: res.ok, body: body };
});
}).then(function(result) {
uploadBtn.disabled = false;
uploadBtn.textContent = 'Muat Naik';
if (!result.ok || !result.body || !result.body.stored) {
throw new Error((result.body && (result.body.error || result.body.message)) || 'Gagal memuat naik scan IC.');
}
showUploadedState(selectedFile.name, selectedFile.type);
selectedFile = null;
fileInput.value = '';
Swal.fire({
icon: 'success',
title: 'Berjaya',
text: 'Scan dokumen IC telah dimuat naik.'
});
}).catch(function(err) {
uploadBtn.disabled = false;
uploadBtn.textContent = 'Muat Naik';
Swal.fire({
icon: 'error',
title: 'Tidak berjaya',
text: err.message || 'Gagal memuat naik scan IC.'
});
});
});
})();
</script>
+27 -8
View File
@@ -21,6 +21,9 @@
<div class="card"> <div class="card">
<div class="card-body"> <div class="card-body">
@if(session()->has('error'))
<div class="alert alert-danger">{{ session('error') }}</div>
@endif
<div class="text-center"> <div class="text-center">
<h5 class="text-uppercase">masukkan nombor kad pengenalan</h5> <h5 class="text-uppercase">masukkan nombor kad pengenalan</h5>
<form name="frmsearch" onsubmit="verifynokp()" action="{{ route('customer.search') }}" method="GET"> <form name="frmsearch" onsubmit="verifynokp()" action="{{ route('customer.search') }}" method="GET">
@@ -84,7 +87,7 @@
<h5 class="modal-title" id="ModalLabel">Daftar Pelanggan</h5> <h5 class="modal-title" id="ModalLabel">Daftar Pelanggan</h5>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<form action="{{ route('customer.store') }}" onsubmit="verifycustomer()" method="POST"> <form action="{{ route('customer.store') }}" onsubmit="verifycustomer()" method="POST" enctype="multipart/form-data">
@csrf @csrf
<div class="row form-group"> <div class="row form-group">
<div class="col-md-6"> <div class="col-md-6">
@@ -195,7 +198,7 @@
</div> </div>
</div> </div>
</div> </div>
@include('customers.partials.ic_scan_register_field', ['scanFieldId' => 'scan_ic_manual'])
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<input type="text" hidden name="idtype" value="nokp"> <input type="text" hidden name="idtype" value="nokp">
@@ -210,7 +213,7 @@
<div class="modal fade" id="daftar_pelanggan_mykad_reader" tabindex="-1" data-backdrop="static" aria-labelledby="ModalLabel" aria-hidden="true"> <div class="modal fade" id="daftar_pelanggan_mykad_reader" tabindex="-1" data-backdrop="static" aria-labelledby="ModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg"> <div class="modal-dialog modal-lg">
<div class="modal-content"> <div class="modal-content">
<form id="form-mykad-reader" action="{{ route('customer.store') }}" onsubmit="verifycustomerMyKadReader()" method="POST"> <form id="form-mykad-reader" action="{{ route('customer.store') }}" onsubmit="verifycustomerMyKadReader()" method="POST" enctype="multipart/form-data">
@csrf @csrf
<div class="modal-header"> <div class="modal-header">
<h5 class="modal-title" id="ModalLabel">Daftar Pelanggan</h5> <h5 class="modal-title" id="ModalLabel">Daftar Pelanggan</h5>
@@ -336,7 +339,7 @@
</div> </div>
</div> </div>
</div> </div>
@include('customers.partials.ic_scan_register_field', ['scanFieldId' => 'scan_ic_mykad'])
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<input type="text" hidden name="idtype" value="nokp"> <input type="text" hidden name="idtype" value="nokp">
@@ -355,7 +358,7 @@
<h5 class="modal-title" id="ModalLabel">Daftar Pelanggan</h5> <h5 class="modal-title" id="ModalLabel">Daftar Pelanggan</h5>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<form action="{{ route('customer.store') }}" onsubmit="verifycustomerpassport()" method="POST"> <form action="{{ route('customer.store') }}" onsubmit="verifycustomerpassport()" method="POST" enctype="multipart/form-data">
@csrf @csrf
<div class="row form-group"> <div class="row form-group">
<div class="col-md-6"> <div class="col-md-6">
@@ -461,6 +464,7 @@
</div> </div>
</div> </div>
</div> </div>
@include('customers.partials.ic_scan_register_field', ['scanFieldId' => 'scan_ic_passport'])
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<input type="text" hidden name="idtype" value="passport"> <input type="text" hidden name="idtype" value="passport">
@@ -474,6 +478,7 @@
</div> </div>
</div> </div>
</div> </div>
@include('customers.partials.ic_scan_register_script')
<script> <script>
var api_url = "{{ api_url_for_browser() }}"; var api_url = "{{ api_url_for_browser() }}";
var search = "<?php echo $search ?>"; var search = "<?php echo $search ?>";
@@ -550,15 +555,20 @@
file.trigger("click"); file.trigger("click");
}); });
$('input[type="file"]').change(function(e) { $('input[type="file"]').change(function(e) {
if (this.name === 'scan_ic' || !e.target.files || !e.target.files[0]) {
return;
}
var fileName = e.target.files[0].name; var fileName = e.target.files[0].name;
$("#file").val(fileName); $("#file").val(fileName);
var preview = document.getElementById("preview");
if (!preview) {
return;
}
var reader = new FileReader(); var reader = new FileReader();
reader.onload = function(e) { reader.onload = function(e) {
// get loaded data and render thumbnail. preview.src = e.target.result;
document.getElementById("preview").src = e.target.result;
}; };
// read the image file as a data URL.
reader.readAsDataURL(this.files[0]); reader.readAsDataURL(this.files[0]);
}); });
@@ -808,6 +818,9 @@
} }
} }
} }
if (!requireScanIcFromForm(document.querySelector('#daftar_pelanggan form'), '#daftar_pelanggan #terima_ic')) {
return false;
}
return true; return true;
} }
@@ -950,6 +963,9 @@
} }
} }
} }
if (!requireScanIcFromForm(document.getElementById('form-mykad-reader'), '#daftar_pelanggan_mykad_reader #terima_ic')) {
return false;
}
return true; return true;
} }
@@ -1090,6 +1106,9 @@
} }
} }
} }
if (!requireScanIcFromForm(document.querySelector('#passport_pelanggan form'), '#terima_passport')) {
return false;
}
return true; return true;
} }
@@ -24,6 +24,9 @@
@if(session()->has('message')) @if(session()->has('message'))
<div class="alert alert-success">{{ session('message') }}</div> <div class="alert alert-success">{{ session('message') }}</div>
@endif @endif
@if(session()->has('error'))
<div class="alert alert-danger">{{ session('error') }}</div>
@endif
@if(!empty($customer_info['photo_base64'])) @if(!empty($customer_info['photo_base64']))
<div class="form-group row col-md-12"> <div class="form-group row col-md-12">
@@ -37,6 +40,8 @@
</div> </div>
@endif @endif
@include('customers.partials.ic_scan_upload')
<div class="form-group row col-md-12"> <div class="form-group row col-md-12">
<div class="col-md-6"> <div class="col-md-6">
<div class="form-group row"> <div class="form-group row">
@@ -443,6 +448,14 @@
var tagarrahnbid = "{{ $cawangan_info['tagarrahnbid'] }}"; var tagarrahnbid = "{{ $cawangan_info['tagarrahnbid'] }}";
var min_komoditi = "{{ $min_komoditi }}"; var min_komoditi = "{{ $min_komoditi }}";
$('#daftar_gadai').on('click',function(){ $('#daftar_gadai').on('click',function(){
if (!window.hasScanIc) {
Swal.fire({
icon: 'warning',
title: 'Scan IC diperlukan',
text: 'Sila muat naik scan dokumen IC sebelum daftar pembiayaan.'
});
return;
}
$("#daftar_gadai").prop('disabled', true); $("#daftar_gadai").prop('disabled', true);
var noic = $('#noic').val(); var noic = $('#noic').val();
var iclama = "{{ $customer_info['kplama'] }}"; var iclama = "{{ $customer_info['kplama'] }}";
+27 -7
View File
@@ -23,6 +23,9 @@
<div class="card"> <div class="card">
<div class="card-body"> <div class="card-body">
@if(session()->has('error'))
<div class="alert alert-danger">{{ session('error') }}</div>
@endif
<div class="text-center"> <div class="text-center">
<h5 class="text-uppercase">masukkan nombor kad pengenalan</h5> <h5 class="text-uppercase">masukkan nombor kad pengenalan</h5>
<form name="frmsearch" onsubmit="verifynokp()" action="{{ route('customer.search') }}" method="GET"> <form name="frmsearch" onsubmit="verifynokp()" action="{{ route('customer.search') }}" method="GET">
@@ -102,7 +105,7 @@
<h5 class="modal-title" id="ModalLabel">Daftar Pelanggan</h5> <h5 class="modal-title" id="ModalLabel">Daftar Pelanggan</h5>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<form name="form-store" action="{{ route('customer.store') }}" onsubmit="verifycustomer()" method="POST"> <form name="form-store" action="{{ route('customer.store') }}" onsubmit="verifycustomer()" method="POST" enctype="multipart/form-data">
@csrf @csrf
<div class="row form-group"> <div class="row form-group">
<div class="col-md-6"> <div class="col-md-6">
@@ -215,6 +218,7 @@
</div> </div>
</div> </div>
</div> </div>
@include('customers.partials.ic_scan_register_field', ['scanFieldId' => 'scan_ic_manual'])
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<input type="text" hidden name="idtype" value="nokp"> <input type="text" hidden name="idtype" value="nokp">
@@ -229,7 +233,7 @@
<div class="modal fade" id="daftar_pelanggan_mykad_reader" tabindex="-1" data-backdrop="static" aria-labelledby="ModalLabel" aria-hidden="true"> <div class="modal fade" id="daftar_pelanggan_mykad_reader" tabindex="-1" data-backdrop="static" aria-labelledby="ModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg"> <div class="modal-dialog modal-lg">
<div class="modal-content"> <div class="modal-content">
<form id="form-mykad-reader" action="{{ route('customer.store') }}" onsubmit="verifycustomerMyKadReader()" method="POST"> <form id="form-mykad-reader" action="{{ route('customer.store') }}" onsubmit="verifycustomerMyKadReader()" method="POST" enctype="multipart/form-data">
@csrf @csrf
<div class="modal-header"> <div class="modal-header">
<h5 class="modal-title" id="ModalLabel">Daftar Pelanggan</h5> <h5 class="modal-title" id="ModalLabel">Daftar Pelanggan</h5>
@@ -356,7 +360,7 @@
</div> </div>
</div> </div>
</div> </div>
@include('customers.partials.ic_scan_register_field', ['scanFieldId' => 'scan_ic_mykad'])
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<input type="text" hidden name="idtype" value="nokp"> <input type="text" hidden name="idtype" value="nokp">
@@ -375,7 +379,7 @@
<h5 class="modal-title" id="ModalLabel">Daftar Pelanggan</h5> <h5 class="modal-title" id="ModalLabel">Daftar Pelanggan</h5>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<form name="form-store" action="{{ route('customer.store') }}" onsubmit="verifycustomerpassport()" method="POST"> <form name="form-store" action="{{ route('customer.store') }}" onsubmit="verifycustomerpassport()" method="POST" enctype="multipart/form-data">
@csrf @csrf
<div class="row form-group"> <div class="row form-group">
<div class="col-md-6"> <div class="col-md-6">
@@ -482,6 +486,7 @@
</div> </div>
</div> </div>
</div> </div>
@include('customers.partials.ic_scan_register_field', ['scanFieldId' => 'scan_ic_passport'])
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<input type="text" hidden name="idtype" value="passport"> <input type="text" hidden name="idtype" value="passport">
@@ -496,6 +501,7 @@
</div> </div>
</div> </div>
@include('customers.partials.ic_scan_register_script')
<script> <script>
var isAnggota = @json($isAnggota ?? false); var isAnggota = @json($isAnggota ?? false);
var isPelanggan = @json($isPelanggan ?? false); var isPelanggan = @json($isPelanggan ?? false);
@@ -629,15 +635,20 @@
file.trigger("click"); file.trigger("click");
}); });
$('input[type="file"]').change(function(e) { $('input[type="file"]').change(function(e) {
if (this.name === 'scan_ic' || !e.target.files || !e.target.files[0]) {
return;
}
var fileName = e.target.files[0].name; var fileName = e.target.files[0].name;
$("#file").val(fileName); $("#file").val(fileName);
var preview = document.getElementById("preview");
if (!preview) {
return;
}
var reader = new FileReader(); var reader = new FileReader();
reader.onload = function(e) { reader.onload = function(e) {
// get loaded data and render thumbnail. preview.src = e.target.result;
document.getElementById("preview").src = e.target.result;
}; };
// read the image file as a data URL.
reader.readAsDataURL(this.files[0]); reader.readAsDataURL(this.files[0]);
}); });
@@ -887,6 +898,9 @@
} }
} }
} }
if (!requireScanIcFromForm(document.querySelector('#daftar_pelanggan form'), '#daftar_pelanggan #terima_ic')) {
return false;
}
return true; return true;
} }
@@ -1029,6 +1043,9 @@
} }
} }
} }
if (!requireScanIcFromForm(document.getElementById('form-mykad-reader'), '#daftar_pelanggan_mykad_reader #terima_ic')) {
return false;
}
return true; return true;
} }
@@ -1169,6 +1186,9 @@
} }
} }
} }
if (!requireScanIcFromForm(document.querySelector('#passport_pelanggan form'), '#terima_passport')) {
return false;
}
return true; return true;
} }
@@ -25,6 +25,9 @@
@if(session()->has('message')) @if(session()->has('message'))
<div class="alert alert-success">{{ session('message') }}</div> <div class="alert alert-success">{{ session('message') }}</div>
@endif @endif
@if(session()->has('error'))
<div class="alert alert-danger">{{ session('error') }}</div>
@endif
@if(!empty($customer_info['photo_base64'])) @if(!empty($customer_info['photo_base64']))
<div class="form-group row col-md-12"> <div class="form-group row col-md-12">
@@ -38,6 +41,8 @@
</div> </div>
@endif @endif
@include('customers.partials.ic_scan_upload')
<div class="form-group row col-md-12"> <div class="form-group row col-md-12">
<div class="col-md-6"> <div class="col-md-6">
<div class="form-group row"> <div class="form-group row">
@@ -723,6 +728,14 @@
if ($(this).prop('disabled')) { if ($(this).prop('disabled')) {
return; return;
} }
if (!window.hasScanIc) {
Swal.fire({
icon: 'warning',
title: 'Scan IC diperlukan',
text: 'Sila muat naik scan dokumen IC sebelum daftar pembiayaan.'
});
return;
}
$("#daftar_gadai").prop('disabled', true); $("#daftar_gadai").prop('disabled', true);
var bakiLelong = Number(@json((float) $bakilelong)); var bakiLelong = Number(@json((float) $bakilelong));
+2
View File
@@ -144,6 +144,8 @@ Route::get('/customer/otp',['as'=>'customer.otp','uses'=>'CustomersController@ge
Route::get('/getwakil',['as'=>'wakil.search','uses'=>'PenebusanController@getWakil'])->middleware('auth','teller'); Route::get('/getwakil',['as'=>'wakil.search','uses'=>'PenebusanController@getWakil'])->middleware('auth','teller');
Route::get('/cari',['as'=>'wakil.caricustomer','uses'=>'CustomersController@cari'])->middleware('auth','teller'); Route::get('/cari',['as'=>'wakil.caricustomer','uses'=>'CustomersController@cari'])->middleware('auth','teller');
Route::post('/customer/mykad-photo',['as'=>'customer.storeMykadPhoto','uses'=>'CustomersController@storeMykadPhotoIfMissing'])->middleware('auth','teller'); Route::post('/customer/mykad-photo',['as'=>'customer.storeMykadPhoto','uses'=>'CustomersController@storeMykadPhotoIfMissing'])->middleware('auth','teller');
Route::post('/customer/ic-scan',['as'=>'customer.storeIcScan','uses'=>'CustomersController@storeIcScan'])->middleware('auth','teller');
Route::get('/customer/ic-scan',['as'=>'customer.showIcScan','uses'=>'CustomersController@showIcScan'])->middleware('auth','teller');
Route::post('/createwakil',['as'=>'wakil.create','uses'=>'PenebusanController@createWakil'])->middleware('auth','teller'); Route::post('/createwakil',['as'=>'wakil.create','uses'=>'PenebusanController@createWakil'])->middleware('auth','teller');
Route::get('/firstwakil',['as'=>'wakil.first','uses'=>'PenebusanController@getfirstWakil'])->middleware('auth','teller'); Route::get('/firstwakil',['as'=>'wakil.first','uses'=>'PenebusanController@getfirstWakil'])->middleware('auth','teller');
Route::get('/history',['as'=>'gadai.history','uses'=>'GadaianController@history'])->middleware('auth','teller'); Route::get('/history',['as'=>'gadai.history','uses'=>'GadaianController@history'])->middleware('auth','teller');