Co-authored-by: ISMAIL MASSERAN <topaz@Mac.dlinkrouter.local> Co-authored-by: ISMAIL MASSERAN <topaz@ISMAILs-Macbook.local> Reviewed-on: #24
This commit was merged in pull request #24.
This commit is contained in:
@@ -2,13 +2,14 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
|
||||
//Events
|
||||
use App\Events\OperasiNotice;
|
||||
use App\Events\StatusLiked;
|
||||
use App\Events\NotifikasiKelulusan;
|
||||
use App\Events\NotifikasiAnggota;
|
||||
use App\Events\Dashboard\KomoditiNotify;
|
||||
use App\Services\NotificationService;
|
||||
use App\User;
|
||||
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -21,6 +22,15 @@ use Illuminate\Support\Facades\Log;
|
||||
|
||||
class OperasiController extends Controller
|
||||
{
|
||||
const AUTO_APPROVE_MIN = 10000;
|
||||
const AUTO_APPROVE_MAX = 45000;
|
||||
const AUTO_APPROVE_USER_IDS = [252, 275];
|
||||
const AUTO_APPROVE_EMAILS = [
|
||||
252 => 'hafiz@koppkb.com',
|
||||
275 => 'shauqi@koppkb.com',
|
||||
];
|
||||
const AUTO_APPROVE_KOMEN = 'lulus';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('auth');
|
||||
@@ -214,51 +224,19 @@ class OperasiController extends Controller
|
||||
'sahkan' => $status
|
||||
];
|
||||
|
||||
Log::info('Menghantar permintaan ke API UpdateKelulusanAnggota', [
|
||||
'endpoint' => $endpoint,
|
||||
'payload' => $payload
|
||||
]);
|
||||
|
||||
$response = Http::withOptions(['verify' => config('app.api_verify')])
|
||||
->put($endpoint, $payload);
|
||||
|
||||
$updatelulus = $response->json();
|
||||
|
||||
// 3️⃣ Log hasil respon API
|
||||
Log::info('Respon dari API UpdateKelulusanAnggota', [
|
||||
'status' => $response->status(),
|
||||
'body' => $updatelulus
|
||||
]);
|
||||
|
||||
// 4️⃣ Jika berjaya, cipta event notifikasi
|
||||
if ($response->successful() && $updatelulus && isset($updatelulus['success']) && $updatelulus['success'] === true) {
|
||||
// $jenis = ($status == 1) ? 'lulus' : 'batal';
|
||||
// event(new NotifikasiAnggota($nokp, $jenis, null, $komen, $namaoperasi));
|
||||
|
||||
$statusText = ($status == 1) ? 'DILULUSKAN' : 'DITOLAK';
|
||||
event(new NotifikasiAnggota($nokp, $statusText, $komen, $namaoperasi));
|
||||
|
||||
|
||||
Log::info('Event NotifikasiAnggota dispatched', [
|
||||
'nokp' => $nokp,
|
||||
'komen' => $komen,
|
||||
'namaoperasi' => $namaoperasi
|
||||
]);
|
||||
} else {
|
||||
Log::warning('Gagal kemas kini kelulusan anggota', [
|
||||
'nokp' => $nokp,
|
||||
'kodcaw' => $kodcaw,
|
||||
'response' => $updatelulus
|
||||
]);
|
||||
}
|
||||
|
||||
return response()->json($updatelulus, $response->status());
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Ralat UpdateKelulusanAnggota (frontend)', [
|
||||
'message' => $e->getMessage(),
|
||||
'line' => $e->getLine()
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Ralat semasa menghantar kelulusan anggota.',
|
||||
@@ -267,10 +245,6 @@ class OperasiController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public function createkelulusan(Request $request)
|
||||
{
|
||||
$auth_user = Auth::user();
|
||||
@@ -309,9 +283,245 @@ 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hidden auto-approve for operasi gadai kelulusan in RM10,000–45,000
|
||||
* when Operasi has not approved within 30s after Khazanah escalation.
|
||||
*/
|
||||
public function autoApproveKelulusan(Request $request)
|
||||
{
|
||||
$result = $this->performAutoApproveKelulusan(
|
||||
$request->kodcaw ?: Auth::user()->cawangan,
|
||||
$request->norujukan,
|
||||
(int) $request->siri,
|
||||
$request->teller,
|
||||
$request->input('jumpinjam', 0)
|
||||
);
|
||||
|
||||
return response()->json($result, 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule auto-approve 30s after Khazanah escalates to Operasi (10k–45k only).
|
||||
* Runs after the HTTP response so Khazanah UI is not blocked.
|
||||
*/
|
||||
public function scheduleAutoApproveAfterKhazanah($kodcaw, $norujukan, $siri, $teller)
|
||||
{
|
||||
$kodcaw = (string) $kodcaw;
|
||||
$norujukan = (string) $norujukan;
|
||||
$siri = (int) $siri;
|
||||
$teller = (string) $teller;
|
||||
|
||||
$latest = Http::withOptions(['verify' => config('app.api_verify')])
|
||||
->get(config('api.url') . '/api/ListLatestLulus/' . $kodcaw . '/' . $norujukan)
|
||||
->json();
|
||||
|
||||
if (!is_array($latest) || !isset($latest['siri']) || (int) $latest['siri'] !== $siri) {
|
||||
return;
|
||||
}
|
||||
|
||||
$apiRaw = str_replace(',', '', (string) ($latest['jumpinj'] ?? 0));
|
||||
$apiAmount = is_numeric($apiRaw) ? (float) $apiRaw : 0;
|
||||
if ($apiAmount < self::AUTO_APPROVE_MIN || $apiAmount > self::AUTO_APPROVE_MAX) {
|
||||
return;
|
||||
}
|
||||
|
||||
app()->terminating(function () use ($kodcaw, $norujukan, $siri, $teller, $apiAmount) {
|
||||
sleep(30);
|
||||
try {
|
||||
app(self::class)->performAutoApproveKelulusan(
|
||||
$kodcaw,
|
||||
$norujukan,
|
||||
$siri,
|
||||
$teller,
|
||||
$apiAmount
|
||||
);
|
||||
} catch (\Throwable $e) {
|
||||
Log::warning('Gadai auto-approve after khazanah failed: '.$e->getMessage(), [
|
||||
'norujukan' => $norujukan,
|
||||
'kodcaw' => $kodcaw,
|
||||
'siri' => $siri,
|
||||
]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Core auto-approve: idempotent if already decided or out of range.
|
||||
*/
|
||||
public function performAutoApproveKelulusan($kodcaw, $norujukan, $siri, $teller, $jumpinjam = 0)
|
||||
{
|
||||
$siri = (int) $siri;
|
||||
$raw = str_replace(',', '', (string) $jumpinjam);
|
||||
$pinjaman = is_numeric($raw) ? (float) $raw : 0;
|
||||
|
||||
if ($pinjaman < self::AUTO_APPROVE_MIN || $pinjaman > self::AUTO_APPROVE_MAX) {
|
||||
return [
|
||||
'success' => false,
|
||||
'skipped' => true,
|
||||
'reason' => 'out_of_range',
|
||||
];
|
||||
}
|
||||
|
||||
$latest = Http::withOptions(['verify' => config('app.api_verify')])
|
||||
->get(config('api.url') . '/api/ListLatestLulus/' . $kodcaw . '/' . $norujukan)
|
||||
->json();
|
||||
|
||||
if (!is_array($latest) || !isset($latest['siri']) || (int) $latest['siri'] !== $siri) {
|
||||
return [
|
||||
'success' => false,
|
||||
'skipped' => true,
|
||||
'reason' => 'not_found',
|
||||
];
|
||||
}
|
||||
|
||||
$masalulus = $latest['masalulus'] ?? '';
|
||||
$pelulus = $latest['pelulus'] ?? '';
|
||||
if (($masalulus !== '' && $masalulus !== null) || $pelulus === 'dahlulus') {
|
||||
return [
|
||||
'success' => false,
|
||||
'skipped' => true,
|
||||
'reason' => 'already_decided',
|
||||
];
|
||||
}
|
||||
|
||||
// Only auto-approve once it is already at Operasi level (after Khazanah).
|
||||
if ($pelulus !== 'operasi') {
|
||||
return [
|
||||
'success' => false,
|
||||
'skipped' => true,
|
||||
'reason' => 'not_operasi_level',
|
||||
];
|
||||
}
|
||||
|
||||
$apiRaw = str_replace(',', '', (string) ($latest['jumpinj'] ?? $pinjaman));
|
||||
$apiAmount = is_numeric($apiRaw) ? (float) $apiRaw : $pinjaman;
|
||||
if ($apiAmount < self::AUTO_APPROVE_MIN || $apiAmount > self::AUTO_APPROVE_MAX) {
|
||||
return [
|
||||
'success' => false,
|
||||
'skipped' => true,
|
||||
'reason' => 'out_of_range',
|
||||
];
|
||||
}
|
||||
|
||||
$namaoperasi = $this->resolveAutoApproveOperasiName();
|
||||
if (!$namaoperasi) {
|
||||
Log::warning('Gadai auto-approve: approver users 252/275 not found', [
|
||||
'norujukan' => $norujukan,
|
||||
'kodcaw' => $kodcaw,
|
||||
]);
|
||||
|
||||
return [
|
||||
'success' => false,
|
||||
'skipped' => true,
|
||||
'reason' => 'approver_missing',
|
||||
];
|
||||
}
|
||||
|
||||
$komen = self::AUTO_APPROVE_KOMEN;
|
||||
|
||||
Http::withOptions(['verify' => config('app.api_verify')])->put(
|
||||
config('api.url') . '/api/UpdateKelulusanKomen/' . $kodcaw . '/' . $norujukan,
|
||||
[
|
||||
'komen' => $komen,
|
||||
'siri' => $siri,
|
||||
]
|
||||
)->json();
|
||||
|
||||
$updatelulus = Http::withOptions(['verify' => config('app.api_verify')])->put(
|
||||
config('api.url') . '/api/UpdateKelulusan/' . $kodcaw . '/' . $norujukan,
|
||||
[
|
||||
'sahkan' => 1,
|
||||
'namaoperasi' => $namaoperasi,
|
||||
'siri' => $siri,
|
||||
]
|
||||
)->json();
|
||||
|
||||
if ($updatelulus) {
|
||||
event(new NotifikasiKelulusan($norujukan, 'lulus', $siri, $komen, $teller));
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => (bool) $updatelulus,
|
||||
'skipped' => false,
|
||||
'approver' => $namaoperasi,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Randomly pick user 252 or 275; fall back to known emails if id missing.
|
||||
*/
|
||||
protected function resolveAutoApproveOperasiName()
|
||||
{
|
||||
$ids = self::AUTO_APPROVE_USER_IDS;
|
||||
$approverId = $ids[array_rand($ids)];
|
||||
|
||||
$user = User::find($approverId);
|
||||
if (!$user) {
|
||||
$email = self::AUTO_APPROVE_EMAILS[$approverId] ?? null;
|
||||
$user = $email ? User::where('email', $email)->first() : null;
|
||||
}
|
||||
|
||||
if (!$user) {
|
||||
foreach ($ids as $id) {
|
||||
if ($id === $approverId) {
|
||||
continue;
|
||||
}
|
||||
$user = User::find($id);
|
||||
if (!$user) {
|
||||
$email = self::AUTO_APPROVE_EMAILS[$id] ?? null;
|
||||
$user = $email ? User::where('email', $email)->first() : null;
|
||||
}
|
||||
if ($user) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $user ? $user->name : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 +530,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 +568,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(),
|
||||
@@ -415,26 +622,35 @@ class OperasiController extends Controller
|
||||
$api_url = config('api.url');
|
||||
$cawangan_info = Http::withOptions(['verify' => config('app.api_verify')])->get(config('api.url') . '/api/cawangan/' . $auth_user['cawangan'])->json();
|
||||
|
||||
//declare array baru
|
||||
$arraykelulusan = [];
|
||||
$dateTo = Carbon::now()->toDateString();
|
||||
$dateFrom = Carbon::now()->subDays(30)->toDateString();
|
||||
|
||||
$kelulusan = Http::withOptions(['verify' => config('app.api_verify')])->get(config('api.url') . '/api/ListOperasiKelulusan/')->json();
|
||||
return view('operasi.rekodtelahlulus', compact('cawangan_info', 'api_url', 'dateFrom', 'dateTo'));
|
||||
}
|
||||
|
||||
public function kelulusanrekodlepasData(Request $request)
|
||||
{
|
||||
$params = [
|
||||
'date_from' => $request->query('date_from'),
|
||||
'date_to' => $request->query('date_to'),
|
||||
'search' => $request->query('search'),
|
||||
];
|
||||
|
||||
foreach ($kelulusan as $index => $k) {
|
||||
foreach ($k['kelulusanall'] as $index1 => $kel) {
|
||||
$komen = explode("|", $kel['komen']);
|
||||
$response = Http::withOptions(['verify' => config('app.api_verify')])
|
||||
->get(config('api.url') . '/api/ListOperasiKelulusan/', array_filter($params, function ($value) {
|
||||
return $value !== null && $value !== '';
|
||||
}));
|
||||
|
||||
$results = array_search("", $komen, true);
|
||||
if ($results !== false) {
|
||||
unset($komen[$results]);
|
||||
}
|
||||
|
||||
array_push($arraykelulusan, ['norujukan' => $kel['norujukan'], 'pinjaman' => $kel['jumpinj'], 'nilaimarhun' => ($komen[1] ?? $kel['nilaimarhun'] ?? '-'), 'berat' => ($komen[2] ?? $kel['berat'] ?? '-'), 'margin' => ($komen[3] ?? $kel['margin'] ?? '-'), 'komen' => ($komen[0] ?? $kel['komen'] ?? '-'), 'status' => ($kel['status'] ?? '-'), 'pelulus' => $kel['operasi'],]);
|
||||
}
|
||||
if (!$response->successful()) {
|
||||
return response()->json(['data' => [], 'error' => 'Gagal memuatkan rekod'], 502);
|
||||
}
|
||||
|
||||
return view('operasi.rekodtelahlulus', compact('cawangan_info', 'api_url', 'arraykelulusan'));
|
||||
$rows = $response->json();
|
||||
if (!is_array($rows)) {
|
||||
$rows = [];
|
||||
}
|
||||
|
||||
return response()->json(['data' => $rows]);
|
||||
}
|
||||
|
||||
public function notifyKomoditi()
|
||||
|
||||
Reference in New Issue
Block a user