DONE: add notification for gadaian and pendahuluan
This commit is contained in:
@@ -29,6 +29,7 @@ use Carbon\Carbon;
|
||||
use PDF;
|
||||
use DateTime;
|
||||
use App\Helper;
|
||||
use App\Services\NotificationService;
|
||||
use Log;
|
||||
|
||||
class KhazanahController extends Controller
|
||||
@@ -1084,6 +1085,7 @@ class KhazanahController extends Controller
|
||||
|
||||
if($test == 'success'){
|
||||
event(new PendahuluanSerahan("Lulus","pendahuluan",$auth_user['cawangan'],$request->teller));
|
||||
$this->notifyTellerAliranTunai('Lulus', 'pendahuluan', $auth_user['cawangan'], $request->teller, $amount);
|
||||
return redirect()->route('khazanah.pendahulu');
|
||||
}else{
|
||||
return redirect()->route('khazanah.pendahulu')->with('error','Permohonan tidak berjaya! Permohonan Semula perlu melebihi 1 minit.');
|
||||
@@ -1109,6 +1111,7 @@ class KhazanahController extends Controller
|
||||
|
||||
if($test == 'success'){
|
||||
event(new PendahuluanSerahan("Lulus","serahan",$auth_user['cawangan'],$request->teller));
|
||||
$this->notifyTellerAliranTunai('Lulus', 'serahan', $auth_user['cawangan'], $request->teller, $request->amt);
|
||||
return redirect()->route('khazanah.serahan');
|
||||
}else{
|
||||
return redirect()->route('khazanah.serahan')->with('error','Permohonan tidak berjaya! Permohonan Semula perlu melebihi 1 minit.');
|
||||
@@ -2848,10 +2851,43 @@ class KhazanahController extends Controller
|
||||
]);
|
||||
|
||||
event(new PendahuluanSerahan("Batal","all",$auth_user['cawangan'],$kodlaluan));
|
||||
$this->notifyTellerAliranTunai('Batal', 'all', $kodcaw, $kodlaluan);
|
||||
|
||||
return response('Berjaya');
|
||||
}
|
||||
|
||||
/**
|
||||
* Inbox for the teller waiting on aliran tunai. Failures must not block approval.
|
||||
*
|
||||
* @param string $pengesahan
|
||||
* @param string $jenis
|
||||
* @param string $kodcaw
|
||||
* @param string $teller
|
||||
* @param mixed $amaun
|
||||
* @return void
|
||||
*/
|
||||
protected function notifyTellerAliranTunai($pengesahan, $jenis, $kodcaw, $teller, $amaun = 0)
|
||||
{
|
||||
try {
|
||||
$raw = str_replace(',', '', (string) $amaun);
|
||||
$amount = is_numeric($raw) ? (float) $raw : 0;
|
||||
|
||||
app(NotificationService::class)->notifyAliranTunaiDecided($kodcaw, $teller, [
|
||||
'pengesahan' => $pengesahan,
|
||||
'jenis' => $jenis,
|
||||
'amaun' => $amount,
|
||||
'kodlaluan' => $teller,
|
||||
'khazanah' => Auth::user() ? Auth::user()->name : '',
|
||||
]);
|
||||
} catch (\Throwable $e) {
|
||||
Log::warning('Aliran tunai teller notification failed: '.$e->getMessage(), [
|
||||
'kodcaw' => $kodcaw,
|
||||
'teller' => $teller,
|
||||
'jenis' => $jenis,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function SuratAkuanGadaian(Request $request)
|
||||
{
|
||||
$auth_user = Auth::user();
|
||||
|
||||
@@ -9,6 +9,7 @@ use App\Events\StatusLiked;
|
||||
use App\Events\NotifikasiKelulusan;
|
||||
use App\Events\NotifikasiAnggota;
|
||||
use App\Events\Dashboard\KomoditiNotify;
|
||||
use App\Services\NotificationService;
|
||||
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -309,9 +310,48 @@ class OperasiController extends Controller
|
||||
|
||||
event(new StatusLiked($auth_user['cawangan'], $auth_user['name']));
|
||||
|
||||
$this->notifyGadaiAboveTenThousand($auth_user, $request, $cawangan_info);
|
||||
|
||||
return response()->json($siri, 201);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inbox for PC/PPC and operasi when teller mohon kelulusan gadai >= RM10,000.
|
||||
*/
|
||||
protected function notifyGadaiAboveTenThousand($auth_user, Request $request, $cawangan_info)
|
||||
{
|
||||
$raw = str_replace(',', '', (string) $request->input('jumpinjam', 0));
|
||||
$pinjaman = is_numeric($raw) ? (float) $raw : 0;
|
||||
if ($pinjaman < NotificationService::GADAI_KELULUSAN_MIN) {
|
||||
return;
|
||||
}
|
||||
|
||||
$status = strtolower((string) $request->input('status', ''));
|
||||
if (strpos($status, 'tebus') !== false) {
|
||||
return;
|
||||
}
|
||||
|
||||
$namaCaw = '';
|
||||
if (is_array($cawangan_info)) {
|
||||
$namaCaw = isset($cawangan_info['details_caw']) ? $cawangan_info['details_caw'] : '';
|
||||
}
|
||||
|
||||
try {
|
||||
app(NotificationService::class)->notifyGadaiKelulusan($auth_user['cawangan'], [
|
||||
'norujukan' => $request->norujukan,
|
||||
'pinjaman' => $pinjaman,
|
||||
'teller' => $request->teller ?: $auth_user['name'],
|
||||
'cawangan_nama' => $namaCaw,
|
||||
'status' => $request->status,
|
||||
]);
|
||||
} catch (\Throwable $e) {
|
||||
Log::warning('Gadai kelulusan notification failed: '.$e->getMessage(), [
|
||||
'norujukan' => $request->norujukan,
|
||||
'cawangan' => $auth_user['cawangan'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function createkelulusanAnggota(Request $request)
|
||||
{
|
||||
@@ -320,8 +360,6 @@ class OperasiController extends Controller
|
||||
$api_url = config('api.url');
|
||||
$current = Carbon::now();
|
||||
|
||||
Log::info('createkelulusanAnggota', $request->all());
|
||||
|
||||
// Dapatkan maklumat cawangan
|
||||
$cawangan_info = Http::withOptions(['verify' => config('app.api_verify')])
|
||||
->get($api_url . '/api/cawangan/' . $auth_user['cawangan'])
|
||||
@@ -360,7 +398,6 @@ class OperasiController extends Controller
|
||||
'body' => $response->body(),
|
||||
]);
|
||||
} catch (\Throwable $th) {
|
||||
Log::error('❌ createkelulusanAnggota error: ' . $th->getMessage());
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => $th->getMessage(),
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace App\Services;
|
||||
|
||||
use App\StaffNotification;
|
||||
use App\User;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class NotificationService
|
||||
{
|
||||
@@ -12,6 +13,10 @@ class NotificationService
|
||||
const TYPE_PEMBIAYAAN_BATCH_OPERASI = 'pembiayaan_online.batch_operasi';
|
||||
const TYPE_PEMBIAYAAN_REJECTED_PC = 'pembiayaan_online.rejected_pc';
|
||||
const TYPE_PEMBIAYAAN_PAID_PC = 'pembiayaan_online.paid_pc';
|
||||
const TYPE_GADAI_KELULUSAN = 'gadai.kelulusan';
|
||||
const TYPE_ALIRAN_TUNAI_PENDING = 'aliran_tunai.pending_khazanah';
|
||||
const TYPE_ALIRAN_TUNAI_DECIDED = 'aliran_tunai.decided_teller';
|
||||
const GADAI_KELULUSAN_MIN = 10000;
|
||||
|
||||
/**
|
||||
* Create one inbox row per staff matching role + branch.
|
||||
@@ -70,6 +75,10 @@ class NotificationService
|
||||
$role = isset($audience['role']) ? $audience['role'] : null;
|
||||
$data = isset($input['data']) && is_array($input['data']) ? $input['data'] : [];
|
||||
|
||||
if ($type === self::TYPE_ALIRAN_TUNAI_PENDING && $kodcaw) {
|
||||
return $this->notifyAliranTunaiPending($kodcaw, $data);
|
||||
}
|
||||
|
||||
$payload = $this->payloadForType($type, $kodcaw, $data);
|
||||
|
||||
if (!empty($input['title'])) {
|
||||
@@ -93,6 +102,90 @@ class NotificationService
|
||||
return collect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gadai >= RM10,000: inbox for PC/PPC at the branch and all operasi.
|
||||
*
|
||||
* @param string $kodcaw
|
||||
* @param array $data
|
||||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
public function notifyGadaiKelulusan($kodcaw, array $data)
|
||||
{
|
||||
$pinjaman = isset($data['pinjaman']) ? (float) $data['pinjaman'] : 0;
|
||||
if ($pinjaman < self::GADAI_KELULUSAN_MIN) {
|
||||
return collect();
|
||||
}
|
||||
|
||||
$payload = $this->payloadForType(self::TYPE_GADAI_KELULUSAN, $kodcaw, $data);
|
||||
|
||||
$created = collect();
|
||||
foreach (['pc', 'ppc'] as $role) {
|
||||
$created = $created->merge(
|
||||
$this->notifyRoleAtCawangan($role, $kodcaw, array_merge($payload, [
|
||||
'url' => '/kelulusan',
|
||||
]))
|
||||
);
|
||||
}
|
||||
|
||||
return $created->merge(
|
||||
$this->notifyRole('operasi', array_merge($payload, [
|
||||
'url' => '/operasi/kelulusan',
|
||||
]))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Teller pendahuluan/serahan: inbox for PC/PPC at the branch.
|
||||
*
|
||||
* @param string $kodcaw
|
||||
* @param array $data
|
||||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
public function notifyAliranTunaiPending($kodcaw, array $data)
|
||||
{
|
||||
$payload = $this->payloadForType(self::TYPE_ALIRAN_TUNAI_PENDING, $kodcaw, $data);
|
||||
|
||||
$created = collect();
|
||||
foreach (['pc', 'ppc'] as $role) {
|
||||
$created = $created->merge($this->notifyRoleAtCawangan($role, $kodcaw, $payload));
|
||||
}
|
||||
|
||||
return $created;
|
||||
}
|
||||
|
||||
/**
|
||||
* Khazanah lulus/batal: inbox for the teller who requested cash.
|
||||
*
|
||||
* @param string $kodcaw
|
||||
* @param string $tellerName
|
||||
* @param array $data
|
||||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
public function notifyAliranTunaiDecided($kodcaw, $tellerName, array $data)
|
||||
{
|
||||
$tellerName = trim((string) $tellerName);
|
||||
if ($tellerName === '') {
|
||||
return collect();
|
||||
}
|
||||
|
||||
$payload = $this->payloadForType(self::TYPE_ALIRAN_TUNAI_DECIDED, $kodcaw, $data);
|
||||
|
||||
$user = User::query()
|
||||
->where('name', $tellerName)
|
||||
->where('cawangan', $kodcaw)
|
||||
->first();
|
||||
|
||||
if (!$user) {
|
||||
$user = User::query()->where('name', $tellerName)->first();
|
||||
}
|
||||
|
||||
if (!$user) {
|
||||
return collect();
|
||||
}
|
||||
|
||||
return collect([$this->notifyUser($user, $kodcaw, $user->roles, $payload)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
* @param string|null $kodcaw
|
||||
@@ -223,6 +316,78 @@ class NotificationService
|
||||
];
|
||||
}
|
||||
|
||||
if ($type === self::TYPE_ALIRAN_TUNAI_PENDING) {
|
||||
$jenis = $this->aliranTunaiJenis($data);
|
||||
$amaun = $this->aliranTunaiAmaun($data, $jenis);
|
||||
$teller = isset($data['kodlaluan']) ? trim((string) $data['kodlaluan']) : '';
|
||||
$label = $jenis === 'serahan' ? 'serahan' : 'pendahuluan';
|
||||
|
||||
return [
|
||||
'type' => $type,
|
||||
'cawangan' => $kodcaw,
|
||||
'title' => $jenis === 'serahan' ? 'Permohonan serahan modal' : 'Permohonan pendahuluan',
|
||||
'body' => sprintf(
|
||||
'%s mohon %s RM %s',
|
||||
$teller !== '' ? $teller : 'Teller',
|
||||
$label,
|
||||
number_format($amaun, 2)
|
||||
),
|
||||
'url' => $jenis === 'serahan' ? '/serahan' : '/pendahuluan',
|
||||
'data' => $data,
|
||||
];
|
||||
}
|
||||
|
||||
if ($type === self::TYPE_ALIRAN_TUNAI_DECIDED) {
|
||||
$jenis = $this->aliranTunaiJenis($data);
|
||||
$amaun = $this->aliranTunaiAmaun($data, $jenis);
|
||||
$lulus = isset($data['pengesahan']) && strcasecmp((string) $data['pengesahan'], 'Lulus') === 0;
|
||||
$label = 'Pendahuluan';
|
||||
if ($jenis === 'serahan') {
|
||||
$label = 'Serahan';
|
||||
} elseif ($jenis === 'all') {
|
||||
$label = 'Aliran tunai';
|
||||
}
|
||||
|
||||
if ($lulus) {
|
||||
$title = $label.' diluluskan';
|
||||
$body = sprintf('%s RM %s telah diluluskan', $label, number_format($amaun, 2));
|
||||
} else {
|
||||
$title = $label.' tidak diluluskan';
|
||||
$body = sprintf('Permohonan %s tidak diluluskan', strtolower($label));
|
||||
}
|
||||
|
||||
return [
|
||||
'type' => $type,
|
||||
'cawangan' => $kodcaw,
|
||||
'title' => $title,
|
||||
'body' => $body,
|
||||
'url' => '/aliran_tunai',
|
||||
'data' => $data,
|
||||
];
|
||||
}
|
||||
|
||||
if ($type === self::TYPE_GADAI_KELULUSAN) {
|
||||
$norujukan = !empty($data['norujukan']) ? $data['norujukan'] : 'gadai';
|
||||
$amaun = number_format(isset($data['pinjaman']) ? (float) $data['pinjaman'] : 0, 2);
|
||||
$teller = isset($data['teller']) ? trim((string) $data['teller']) : '';
|
||||
$namaCaw = !empty($data['cawangan_nama']) ? $data['cawangan_nama'] : $kodcaw;
|
||||
|
||||
return [
|
||||
'type' => $type,
|
||||
'cawangan' => $kodcaw,
|
||||
'title' => 'Kelulusan gadai melebihi RM 10,000',
|
||||
'body' => sprintf(
|
||||
'%s — %s (RM %s)%s',
|
||||
$namaCaw,
|
||||
$norujukan,
|
||||
$amaun,
|
||||
$teller !== '' ? ' — '.$teller : ''
|
||||
),
|
||||
'url' => '/kelulusan',
|
||||
'data' => $data,
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'type' => $type,
|
||||
'cawangan' => $kodcaw,
|
||||
@@ -233,6 +398,46 @@ class NotificationService
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return string pendahuluan|serahan|all
|
||||
*/
|
||||
protected function aliranTunaiJenis(array $data)
|
||||
{
|
||||
if (!empty($data['jenis'])) {
|
||||
$jenis = strtolower(trim((string) $data['jenis']));
|
||||
if ($jenis === 'serahan' || $jenis === 'pendahuluan' || $jenis === 'all') {
|
||||
return $jenis;
|
||||
}
|
||||
}
|
||||
|
||||
$modal = isset($data['modal']) ? (float) $data['modal'] : 0;
|
||||
$serahan = isset($data['serahan']) ? (float) $data['serahan'] : 0;
|
||||
if ($serahan > 0 && $modal <= 0) {
|
||||
return 'serahan';
|
||||
}
|
||||
|
||||
return 'pendahuluan';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param string $jenis
|
||||
* @return float
|
||||
*/
|
||||
protected function aliranTunaiAmaun(array $data, $jenis)
|
||||
{
|
||||
if (isset($data['amaun']) && is_numeric($data['amaun'])) {
|
||||
return (float) $data['amaun'];
|
||||
}
|
||||
|
||||
if ($jenis === 'serahan') {
|
||||
return isset($data['serahan']) ? (float) $data['serahan'] : 0;
|
||||
}
|
||||
|
||||
return isset($data['modal']) ? (float) $data['modal'] : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create one inbox row for a specific user.
|
||||
*
|
||||
|
||||
@@ -204,7 +204,7 @@
|
||||
/>
|
||||
|
||||
<div class="title">
|
||||
<h1>Borang Pengesahan Penerimaan Pembiayaan<br>Secara Online (Akaun Bank)</h1>
|
||||
<h1>Borang Pengesahan Penerimaan Pembiayaan<br>Secara Atas Talian (Online)</h1>
|
||||
<p>Untuk diisi dan ditandatangani oleh pelanggan semasa transaksi gadai.</p>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -246,9 +246,8 @@
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="radio" name="cara_terima" id="cara_terima_online" value="ONLINE">
|
||||
<label class="form-check-label" for="cara_terima_online">Online (Akaun Bank)</label>
|
||||
<label class="form-check-label" for="cara_terima_online">Atas Talian (Online)</label>
|
||||
</div>
|
||||
<small class="form-text text-muted">Pilihan Online untuk pembiayaan RM5,000 – RM50,000 sahaja.</small>
|
||||
</div>
|
||||
</div>
|
||||
<div id="bank_online_section" style="display:none;">
|
||||
|
||||
@@ -283,7 +283,7 @@
|
||||
});
|
||||
|
||||
</script>
|
||||
@elseif($auth_user['role_harian'] == 'teller')
|
||||
@elseif($auth_user['role_harian'] == 'teller' || $auth_user['roles'] == 'teller')
|
||||
<li class="nav-item dropdown" style="margin-right:10px;">
|
||||
<a id="navbarDropdown"
|
||||
class="nav-link"
|
||||
@@ -295,60 +295,13 @@
|
||||
v-pre
|
||||
style="color: {{ isset($cawangan_info['details_caw']) && $cawangan_info['details_caw'] == 'Putatan' ? 'white' : (isset($cawangan_info['details_caw']) && $cawangan_info['details_caw'] == 'Putatan 2' ? 'black' : '#1abc9c') }};">
|
||||
<i id="bell" class="fa fa-bell"></i>
|
||||
<span id="staff-notification-badge" class="staff-notification-badge"></span>
|
||||
</a>
|
||||
|
||||
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdown">
|
||||
<div id="divbiasa">
|
||||
<a class="dropdown-item" id="gadailinkz" href="#">
|
||||
Tiada Data
|
||||
</a>
|
||||
</div>
|
||||
<div class="dropdown-menu dropdown-menu-right staff-notification-menu" aria-labelledby="navbarDropdown">
|
||||
@include('layouts.partials.notification_inbox')
|
||||
</div>
|
||||
</li>
|
||||
|
||||
{{-- <script>
|
||||
|
||||
// Enable pusher logging - don't include this in production
|
||||
// Pusher.logToConsole = true;
|
||||
|
||||
var pusher = new Pusher("{{ env('PUSHER_APP_KEY') }}", {
|
||||
cluster: 'ap1',
|
||||
encrypted: true
|
||||
});
|
||||
|
||||
var channel = pusher.subscribe('notifikasi-pembayaran');
|
||||
channel.bind('trigger-pembayaran', function(data) {
|
||||
let message = JSON.stringify(data);
|
||||
|
||||
$('#bell').css("color", "red");
|
||||
$('#gadailinkz').text("Khazanah Serah Marhun Teller");
|
||||
// $("#gadailinkz").attr("href", "{{ url('kelulusan') }}");
|
||||
|
||||
const Toast = Swal.mixin({
|
||||
toast: true,
|
||||
position: 'top-end',
|
||||
showConfirmButton: false,
|
||||
timer: 5000,
|
||||
timerProgressBar: true,
|
||||
didOpen: (toast) => {
|
||||
toast.addEventListener('mouseenter', Swal.stopTimer)
|
||||
toast.addEventListener('mouseleave', Swal.resumeTimer)
|
||||
}
|
||||
});
|
||||
|
||||
Toast.fire({
|
||||
icon: 'error',
|
||||
title: 'Notifikasi Pembayaran!'
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
$("#navbarDropdown").click(function(){
|
||||
$('#bell').css("color", "grey");
|
||||
});
|
||||
|
||||
</script> --}}
|
||||
|
||||
@endif
|
||||
|
||||
|
||||
|
||||
@@ -54,8 +54,10 @@
|
||||
@if($pendingCount > 0)
|
||||
<form method="post"
|
||||
action="{{ route('pembiayaan.online.operasi.approve.batch', ['kodcaw' => $kodcaw, 'batchId' => $batch['id']]) }}"
|
||||
class="d-inline"
|
||||
onsubmit="return confirm('Luluskan semua {{ $pendingCount }} rekod menunggu dalam batch ini?');">
|
||||
class="d-inline js-swal-confirm"
|
||||
data-title="Lulus Semua Menunggu?"
|
||||
data-html="Luluskan semua <b>{{ $pendingCount }}</b> rekod menunggu dalam batch <b>{{ $batch['batch_no'] ?? '-' }}</b>?"
|
||||
data-confirm="Ya, Lulus Semua">
|
||||
@csrf
|
||||
<button type="submit" class="btn btn-success btn-sm">Lulus Semua Menunggu ({{ $pendingCount }})</button>
|
||||
</form>
|
||||
@@ -116,8 +118,10 @@
|
||||
@if(in_array($st, ['IN_BATCH', 'OPS_REVIEW'], true))
|
||||
<form method="post"
|
||||
action="{{ route('pembiayaan.online.operasi.approve', ['kodcaw' => $kodcaw, 'id' => $line['id']]) }}"
|
||||
class="d-inline"
|
||||
onsubmit="return confirm('Luluskan rekod {{ $line['norujukan'] ?? '' }}?');">
|
||||
class="d-inline js-swal-confirm"
|
||||
data-title="Luluskan Rekod?"
|
||||
data-html="Luluskan rekod <b>{{ $line['norujukan'] ?? '-' }}</b>?"
|
||||
data-confirm="Ya, Lulus">
|
||||
@csrf
|
||||
<input type="hidden" name="batch_id" value="{{ $batch['id'] }}">
|
||||
<button type="submit" class="btn btn-success btn-sm">Lulus</button>
|
||||
@@ -133,7 +137,7 @@
|
||||
class="btn btn-dark btn-sm btn-paid"
|
||||
data-id="{{ $line['id'] }}"
|
||||
data-norujukan="{{ $line['norujukan'] ?? '' }}">
|
||||
Dibayar + Bukti
|
||||
Tanda sebagai dibayar
|
||||
</button>
|
||||
<button type="button"
|
||||
class="btn btn-outline-danger btn-sm btn-reject"
|
||||
@@ -226,12 +230,12 @@
|
||||
<div class="form-group">
|
||||
<label>Bukti Bayaran <span class="text-danger">*</span></label>
|
||||
<input type="file" name="bukti" class="form-control-file" accept=".pdf,.jpg,.jpeg,.png,.gif" required>
|
||||
<small class="text-muted">PDF / imej slip pindahan bank</small>
|
||||
<small class="text-muted">PDF / imej slip bank</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Batal</button>
|
||||
<button type="submit" class="btn btn-dark">Simpan sebagai dibayar</button>
|
||||
<button type="submit" class="btn btn-dark">Simpan</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@@ -267,7 +271,7 @@
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Batal</button>
|
||||
<button type="submit" class="btn btn-dark">Simpan semua sebagai dibayar</button>
|
||||
<button type="submit" class="btn btn-dark">Simpan</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@@ -316,5 +320,25 @@
|
||||
$('#paidNorujukan').text($(this).data('norujukan'));
|
||||
$('#paidModal').modal('show');
|
||||
});
|
||||
|
||||
$(document).on('submit', '.js-swal-confirm', function (e) {
|
||||
e.preventDefault();
|
||||
var form = this;
|
||||
Swal.fire({
|
||||
title: $(form).attr('data-title') || 'Pengesahan',
|
||||
html: $(form).attr('data-html') || 'Teruskan tindakan ini?',
|
||||
icon: 'question',
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: '#3085d6',
|
||||
cancelButtonColor: '#d33',
|
||||
confirmButtonText: $(form).attr('data-confirm') || 'Ya',
|
||||
cancelButtonText: 'Batal',
|
||||
allowOutsideClick: false
|
||||
}).then(function (result) {
|
||||
if (result.isConfirmed) {
|
||||
form.submit();
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
|
||||
@@ -36,6 +36,17 @@
|
||||
$lineRows = collect($lines);
|
||||
$verifiedCount = $lineRows->where('status', 'VERIFIED_PC')->count();
|
||||
$unverifiedCount = $lineRows->count() - $verifiedCount;
|
||||
$slotArr = is_array($slot) ? $slot : [];
|
||||
$slotName = $slotArr['slot'] ?? 'BATCH1';
|
||||
$slotCutoff = $slotArr['cutoff'] ?? '11:00';
|
||||
$slotProses = $slotArr['proses'] ?? '12:30';
|
||||
$slotLewat = !empty($slotArr['lewat']);
|
||||
$slotJadual = $slotArr['jadual'] ?? [
|
||||
['slot' => 'BATCH1', 'label' => 'Batch 1', 'mula' => '00:00', 'cutoff' => '11:00', 'proses' => '12:30'],
|
||||
['slot' => 'BATCH2', 'label' => 'Batch 2', 'mula' => '11:00', 'cutoff' => '15:00', 'proses' => '16:30'],
|
||||
];
|
||||
$slotBakiMinit = (int) ($slotArr['baki_minit'] ?? 0);
|
||||
$slotHampirTamat = !$slotLewat && $slotBakiMinit > 0 && $slotBakiMinit <= 30;
|
||||
@endphp
|
||||
|
||||
@if($isClosed)
|
||||
@@ -59,6 +70,66 @@
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="alert {{ $slotLewat ? 'alert-warning' : ($slotHampirTamat ? 'alert-warning' : 'alert-info') }} mb-3">
|
||||
<div class="d-flex justify-content-between align-items-start flex-wrap">
|
||||
<div class="mb-2 mr-3">
|
||||
<strong>Jadual Slot Batch</strong>
|
||||
<div class="mt-1">
|
||||
PC / PPC sila semak dan <b>hantar senarai sebelum tamat slot</b>.
|
||||
Rekod yang dihantar selepas cutoff mungkin diproses pada slot atau hari berikutnya.
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-2 text-md-right">
|
||||
@if($slotLewat)
|
||||
Slot semasa: <b>{{ $slotName }}</b> (selepas cutoff {{ $slotCutoff }})
|
||||
@else
|
||||
Slot semasa: <b>{{ $slotName }}</b>
|
||||
· Hantar sebelum <b>{{ $slotCutoff }}</b>
|
||||
<div class="small" id="slotCountdown"
|
||||
data-cutoff="{{ $slotCutoff }}"
|
||||
data-lewat="{{ $slotLewat ? '1' : '0' }}">
|
||||
@if($slotBakiMinit > 0)
|
||||
Baki masa: {{ intdiv($slotBakiMinit, 60) }}j {{ $slotBakiMinit % 60 }}m
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-responsive mb-0">
|
||||
<table class="table table-sm table-bordered mb-0 bg-white">
|
||||
<thead class="thead-light">
|
||||
<tr>
|
||||
<th>Slot</th>
|
||||
<th>Hantar senarai sebelum</th>
|
||||
<th>Proses Operasi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($slotJadual as $row)
|
||||
@php
|
||||
$rowSlot = $row['slot'] ?? '';
|
||||
$isCurrent = $rowSlot === $slotName && !$slotLewat;
|
||||
$isDone = $slotLewat
|
||||
|| ($slotName === 'BATCH2' && $rowSlot === 'BATCH1');
|
||||
@endphp
|
||||
<tr class="{{ $isCurrent ? 'table-primary' : '' }}">
|
||||
<td>
|
||||
{{ $row['label'] ?? $rowSlot }}
|
||||
@if($isCurrent)
|
||||
<span class="badge badge-primary">Semasa</span>
|
||||
@elseif($isDone)
|
||||
<span class="badge badge-secondary">Tamat</span>
|
||||
@endif
|
||||
</td>
|
||||
<td>{{ $row['cutoff'] ?? '-' }}</td>
|
||||
<td>~ {{ $row['proses'] ?? '-' }}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-4">
|
||||
<div class="card">
|
||||
@@ -85,7 +156,7 @@
|
||||
<div class="col-md-4">
|
||||
<div class="card">
|
||||
<div class="card-body text-center">
|
||||
<div class="text-muted">Queue PC</div>
|
||||
<div class="text-muted">Senarai Pelanggan menunggu semakan</div>
|
||||
<h4 class="mb-0">{{ count($lines) }} rekod</h4>
|
||||
<small>
|
||||
{{ $verifiedCount }} sudah sah
|
||||
@@ -96,11 +167,19 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card">
|
||||
<div class="card {{ $slotLewat || $slotHampirTamat ? 'border-warning' : '' }}">
|
||||
<div class="card-body text-center">
|
||||
<div class="text-muted">Slot Cadangan</div>
|
||||
<h4 class="mb-0">{{ $slot['slot'] ?? '-' }}</h4>
|
||||
<small>{{ $slot['nota'] ?? '' }}</small>
|
||||
<div class="text-muted">Slot Semasa</div>
|
||||
<h4 class="mb-0">{{ $slotName }}</h4>
|
||||
<small>
|
||||
@if($slotLewat)
|
||||
Cutoff {{ $slotCutoff }} sudah tamat<br>
|
||||
Masih boleh hantar; proses mungkin esok
|
||||
@else
|
||||
Hantar sebelum <b>{{ $slotCutoff }}</b>
|
||||
· Proses ~{{ $slotProses }}
|
||||
@endif
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -115,10 +194,15 @@
|
||||
<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.
|
||||
@if($slotLewat)
|
||||
Cutoff {{ $slotName }} ({{ $slotCutoff }}) sudah tamat — hantar sekarang jika perlu; Operasi mungkin proses esok.
|
||||
@else
|
||||
Sila hantar senarai <b>{{ $slotName }}</b> sebelum <b>{{ $slotCutoff }}</b>.
|
||||
@endif
|
||||
</p>
|
||||
<form id="formSubmitBatch" method="post" action="{{ route('pembiayaan.online.pc.submit') }}">
|
||||
@csrf
|
||||
<input type="hidden" name="slot" value="{{ $slot['slot'] ?? 'BATCH1' }}">
|
||||
<input type="hidden" name="slot" value="{{ $slotName }}">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover table-sm text-center" id="queueTable">
|
||||
<thead class="thead-dark">
|
||||
@@ -440,17 +524,46 @@
|
||||
});
|
||||
|
||||
$('#btnSubmitBatch').on('click', function () {
|
||||
if ($('.row-check:not(:disabled):checked').length === 0) return;
|
||||
if (!confirm('Hantar rekod yang sudah disahkan ke Operasi?')) return;
|
||||
var n = $('.row-check:not(:disabled):checked').length;
|
||||
if (n === 0) return;
|
||||
Swal.fire({
|
||||
title: 'Hantar Batch ke Operasi?',
|
||||
html: n + ' rekod yang sudah SAH akan dihantar sebagai <b>{{ $slotName }}</b>.'
|
||||
+ '<br>Sila hantar sebelum cutoff <b>{{ $slotCutoff }}</b>.',
|
||||
icon: 'question',
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: '#3085d6',
|
||||
cancelButtonColor: '#d33',
|
||||
confirmButtonText: 'Ya, Hantar',
|
||||
cancelButtonText: 'Batal',
|
||||
allowOutsideClick: false
|
||||
}).then(function (result) {
|
||||
if (result.isConfirmed) {
|
||||
$('#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;
|
||||
Swal.fire({
|
||||
title: 'Batal Semakan?',
|
||||
html: 'Batal semakan <b>' + (sag || 'rekod ini') + '</b>?'
|
||||
+ '<br>Rekod ini tidak boleh dihantar sehingga disemak semula.',
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: '#3085d6',
|
||||
cancelButtonColor: '#d33',
|
||||
confirmButtonText: 'Ya, Batal',
|
||||
cancelButtonText: 'Tutup',
|
||||
allowOutsideClick: false
|
||||
}).then(function (result) {
|
||||
if (result.isConfirmed) {
|
||||
$('#formUnverify').attr('action', "{{ url('/pembiayaan-online/pc/lines') }}/" + id + "/unverify");
|
||||
$('#formUnverify').submit();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('.btn-verify').on('click', function () {
|
||||
@@ -513,5 +626,32 @@
|
||||
$('#editKodbank').on('change', function () {
|
||||
$('#editNamabank').val($('#editKodbank option:selected').data('nama') || '');
|
||||
});
|
||||
|
||||
function pad2(n) {
|
||||
return n < 10 ? '0' + n : String(n);
|
||||
}
|
||||
|
||||
function tickSlotCountdown() {
|
||||
var el = document.getElementById('slotCountdown');
|
||||
if (!el) return;
|
||||
if (el.getAttribute('data-lewat') === '1') return;
|
||||
var cutoff = el.getAttribute('data-cutoff') || '';
|
||||
var parts = cutoff.split(':');
|
||||
if (parts.length < 2) return;
|
||||
var now = new Date();
|
||||
var end = new Date(now.getFullYear(), now.getMonth(), now.getDate(), parseInt(parts[0], 10), parseInt(parts[1], 10), 0);
|
||||
var diff = end - now;
|
||||
if (diff <= 0) {
|
||||
el.textContent = 'Cutoff telah tamat — sila muat semula halaman';
|
||||
return;
|
||||
}
|
||||
var h = Math.floor(diff / 3600000);
|
||||
var m = Math.floor((diff % 3600000) / 60000);
|
||||
var s = Math.floor((diff % 60000) / 1000);
|
||||
el.textContent = 'Baki masa: ' + h + 'j ' + pad2(m) + 'm ' + pad2(s) + 's';
|
||||
}
|
||||
|
||||
tickSlotCountdown();
|
||||
setInterval(tickSlotCountdown, 1000);
|
||||
</script>
|
||||
@endsection
|
||||
|
||||
@@ -131,7 +131,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
{{-- <div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">Tutup Modal Online (EOD)</h5>
|
||||
</div>
|
||||
@@ -153,7 +153,7 @@
|
||||
</form>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div> --}}
|
||||
</div>
|
||||
|
||||
<div class="col-md-7 mb-3">
|
||||
|
||||
@@ -195,7 +195,7 @@
|
||||
/>
|
||||
|
||||
<div class="title">
|
||||
<h1>Borang Pengesahan Penerimaan Pembiayaan<br>Secara Online (Akaun Bank)</h1>
|
||||
<h1>Borang Pengesahan Penerimaan Pembiayaan<br>Secara Atas Talian (Online)</h1>
|
||||
<p>Untuk diisi dan ditandatangani oleh pelanggan semasa transaksi gadai.</p>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user