From 16f363f95aa5ea4eed5b1f884aa4f0f5a024fc67 Mon Sep 17 00:00:00 2001 From: ISMAIL MASSERAN Date: Sun, 13 Sep 2026 08:06:43 +0800 Subject: [PATCH 1/5] DONE: add env.production --- .env.production | 65 +++++++++++++++++++++++++++++++++++++++++++++++++ .env.staging | 2 ++ 2 files changed, 67 insertions(+) create mode 100644 .env.production diff --git a/.env.production b/.env.production new file mode 100644 index 0000000..e218148 --- /dev/null +++ b/.env.production @@ -0,0 +1,65 @@ +APP_NAME=Lumen +APP_ENV=production +APP_KEY=WbPGkYNmXZ6ZQplGlvl0iZ7zyW1b09xa +APP_DEBUG=false +APP_URL=https://apiujrah.erahn.com.my +APP_TIMEZONE=Asia/Kuala_Lumpur + +LOG_CHANNEL=stack +LOG_SLACK_WEBHOOK_URL= + +DB_CONNECTION_2=mysql +DB_HOST_2=192.168.1.216 +DB_PORT_2=3306 +DB_DATABASE_2=erahn_xtra +DB_USERNAME_2=spider +DB_PASSWORD_2=arrahn@123 + +DB_CONNECTION_3=mysql +DB_HOST_3=192.168.1.216 +DB_PORT_3=3306 +DB_DATABASE_3=erahn_baling +DB_USERNAME_3=spider +DB_PASSWORD_3=arrahn@123 + +DB_CONNECTION_4=mysql +DB_HOST_4=192.168.1.216 +DB_PORT_4=3306 +DB_DATABASE_4=arrahn_ld +DB_USERNAME_4=spider +DB_PASSWORD_4=arrahn@123 + +DB_CONNECTION_5=mysql +DB_HOST_5=192.168.1.216 +DB_PORT_5=3306 +DB_DATABASE_5=erahn_segamat +DB_USERNAME_5=spider +DB_PASSWORD_5=arrahn@123 + +DB_CONNECTION_6=mysql +DB_HOST_6=192.168.1.216 +DB_PORT_6=3306 +DB_DATABASE_6=erahn_terengganu +DB_USERNAME_6=spider +DB_PASSWORD_6=arrahn@123 + +DB_CONNECTION_8=mysql +DB_HOST_8=192.168.1.216 +DB_PORT_8=3306 +DB_DATABASE_8=erahn_benoni +DB_USERNAME_8=spider +DB_PASSWORD_8=arrahn@123 + +DB_CONNECTION_7=mysql +DB_HOST_7=192.168.1.216 +DB_PORT_7=3306 +DB_DATABASE_7=master_erahn +DB_USERNAME_7=spider +DB_PASSWORD_7=arrahn@123 + +MAX_MUTUEMAS=true + +CACHE_DRIVER=file +QUEUE_CONNECTION=sync + +TENNANT_MASTER_DB=master_erahn \ No newline at end of file diff --git a/.env.staging b/.env.staging index 4f366ca..2cfabcb 100644 --- a/.env.staging +++ b/.env.staging @@ -10,6 +10,8 @@ APP_TIMEZONE=Asia/Kuala_Lumpur HTTP_PORT=8090 MYSQL_PUBLISH_PORT=3308 +MAX_MUTUEMAS=true + LOG_CHANNEL=stack LOG_LEVEL=debug LOG_SLACK_WEBHOOK_URL= -- 2.52.0 From 0b9ec1c0ee7ce0467880337c777eb3f19b1f9f48 Mon Sep 17 00:00:00 2001 From: ISMAIL MASSERAN Date: Thu, 17 Sep 2026 08:01:16 +0800 Subject: [PATCH 2/5] DONE: merged code annur with into one codebase --- .env.annur | 28 +++++ README.md | 2 +- app/Feature.php | 3 + app/Gadai.php | 4 +- app/Http/Controllers/GadaiController.php | 8 +- app/Http/Controllers/TebusController.php | 79 +++++++++++++- app/KadarRebet.php | 18 ++++ app/Support/v2/Calculation.php | 58 +++++++++- app/Support/v2/GadaiV2.php | 40 +++++-- app/Support/v2/Penebusan.php | 64 +++++++++-- app/Tebus.php | 3 +- app/TransaksiKeuntungan.php | 2 +- ..._09_13_100000_create_kadar_rebet_table.php | 31 ++++++ ...09_13_100001_add_annur_diskaun_columns.php | 102 ++++++++++++++++++ routes/web.php | 3 + 15 files changed, 414 insertions(+), 31 deletions(-) create mode 100644 .env.annur create mode 100644 app/KadarRebet.php create mode 100644 database/migrations/2026_09_13_100000_create_kadar_rebet_table.php create mode 100644 database/migrations/2026_09_13_100001_add_annur_diskaun_columns.php diff --git a/.env.annur b/.env.annur new file mode 100644 index 0000000..a1d3da7 --- /dev/null +++ b/.env.annur @@ -0,0 +1,28 @@ +APP_NAME=Lumen +APP_ENV=production +APP_KEY=WbPGkYNmXZ6ZQplGlvl0iZ7zyW1b09xa +APP_DEBUG=true +APP_URL=https://apiannurv2.erahn.com.my +APP_TIMEZONE=Asia/Kuala_Lumpur + +LOG_CHANNEL=stack +LOG_SLACK_WEBHOOK_URL= + +DB_CONNECTION_2=mysql +DB_HOST_2=192.168.1.216 +DB_PORT_2=3306 +DB_DATABASE_2=annur_tampoi +DB_USERNAME_2=spider +DB_PASSWORD_2=arrahn@123 + +DB_CONNECTION_7=mysql +DB_HOST_7=192.168.1.216 +DB_PORT_7=3306 +DB_DATABASE_7=master_annur +DB_USERNAME_7=spider +DB_PASSWORD_7=arrahn@123 + +CACHE_DRIVER=file +QUEUE_CONNECTION=sync + +TENNANT_MASTER_DB=master_annur \ No newline at end of file diff --git a/README.md b/README.md index bd2926b..cea8ad4 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Tebus=penyelesaian penuh/ansuran docker exec -i api_arrahn_staging_mysql mysql -uroot -proot erahn_test < erahn_test.sql ``` -## Disable the cawangan in arrahn_master_db +## Disable the cawangan in arrahn_master_db using feature flag ## Feature Flag 1. Register the flag in api_arrahn/app/Feature.php diff --git a/app/Feature.php b/app/Feature.php index 398ed5f..1cccc7e 100644 --- a/app/Feature.php +++ b/app/Feature.php @@ -5,6 +5,7 @@ namespace App; class Feature { const PEMBIAYAAN_ONLINE = 'pembiayaan_online'; + const REBET_ANNUR = 'rebet_annur'; /** * Known flag keys. New features: add a constant here, then INSERT rows for pilot kodcaw. @@ -15,6 +16,7 @@ class Feature { return [ self::PEMBIAYAAN_ONLINE, + self::REBET_ANNUR, ]; } @@ -40,6 +42,7 @@ class Feature { return [ self::PEMBIAYAAN_ONLINE => 'Pembiayaan Online', + self::REBET_ANNUR => 'Rebet / diskaun Annur', ]; } diff --git a/app/Gadai.php b/app/Gadai.php index ccb9ca1..be4a77e 100644 --- a/app/Gadai.php +++ b/app/Gadai.php @@ -78,7 +78,9 @@ class Gadai extends Model 'tagkomuditi', 'tempohbayar', 'lelong_tawarruq', - 'tag_tebus' + 'tag_tebus', + 'kadarrebet', + 'diskaun' ]; /** diff --git a/app/Http/Controllers/GadaiController.php b/app/Http/Controllers/GadaiController.php index c33f375..34195ee 100644 --- a/app/Http/Controllers/GadaiController.php +++ b/app/Http/Controllers/GadaiController.php @@ -537,7 +537,7 @@ class GadaiController extends Controller public function getLaporanGadai($kodcaw,$tarikh){ $cawangan = Cawangan::on('mysql7')->where('kodcaw','=',$kodcaw)->first(); - $gadai_data = Gadai::on($cawangan['mysql'])->select('cara_terima','t_gadai','norujukan','nokp','semakbarcode','masa','berat','nilaimarhun','pinjaman','upah12','percentpinj','teller','nokp','ujrah','onepercent') + $gadai_data = Gadai::on($cawangan['mysql'])->select('cara_terima','t_gadai','norujukan','nokp','semakbarcode','masa','berat','nilaimarhun','pinjaman','upah12','percentpinj','teller','nokp','ujrah','onepercent','kadarrebet','diskaun') ->where('t_gadai','=',$tarikh) ->orderBy('teller') ->orderBy('sirig') @@ -564,7 +564,9 @@ class GadaiController extends Controller "alamat1"=> $customer_info['alamat1'], "teller"=> $gadaiData['teller'], "onepercent"=> $gadaiData['onepercent'], - "ujrah"=> $gadaiData['ujrah'] + "ujrah"=> $gadaiData['ujrah'], + "kadarrebet"=> $gadaiData['kadarrebet'], + "diskaun"=> $gadaiData['diskaun'] ]); } } @@ -642,6 +644,8 @@ class GadaiController extends Controller "teller"=> $g->teller, "ujrah"=> $g->ujrah, "onepercent"=> $g->onepercent, + "kadarrebet"=> $g->kadarrebet, + "diskaun"=> $g->diskaun, "tagbaru"=> $g->tagbaru, "kodkerja"=> optional($customer)->kodkerja, "bangsa"=> optional($customer)->bangsa, diff --git a/app/Http/Controllers/TebusController.php b/app/Http/Controllers/TebusController.php index 512ccd8..90ced88 100644 --- a/app/Http/Controllers/TebusController.php +++ b/app/Http/Controllers/TebusController.php @@ -20,6 +20,7 @@ use App\Panjar; use App\HargaEmas; use App\Moratorium; use App\Audit; +use App\Feature; use App\LookupWakil; use App\StokAudit1; @@ -193,7 +194,7 @@ class TebusController extends Controller $cawangan = Cawangan::on('mysql7')->where('kodcaw','=',$kodcaw)->first(); $tebus_data = Tebus::on($cawangan['mysql']) - ->select('tebus.t_tebus', 'gad.t_gadai','gad.hargajualan','gad.bakihargajualan','gad.bakipjm as gadaibakipjm','tebus.nilaimarhun','tebus.tagterima', 'tebus.teller','tebus.jenistebus','tebus.pinjaman','tebus.bakiupah','tebus.bakipjm','gad.norujukan','gad.nokp','tebus.jbg','tebus.ujrah','tebus.onepercent','gad.tagbaru') + ->select('tebus.t_tebus', 'gad.t_gadai','gad.hargajualan','gad.bakihargajualan','gad.bakipjm as gadaibakipjm','tebus.nilaimarhun','tebus.tagterima', 'tebus.teller','tebus.jenistebus','tebus.pinjaman','tebus.bakiupah','tebus.bakipjm','gad.norujukan','gad.nokp','tebus.jbg','tebus.ujrah','tebus.onepercent','gad.tagbaru','tebus.diskaun_rebate') ->join('gadai as gad','gad.norujukan','=','tebus.norujukan') // ->join('online_arrahn.customer as cust', function($join) // { @@ -232,7 +233,8 @@ class TebusController extends Controller "nokp"=>$tebusData['nokp'], "jbg"=>$tebusData['jbg'], "ujrah"=>$trans['ujrah_rebet'], - "onepercent"=>$trans['onepercent_rebet'] + "onepercent"=>$trans['onepercent_rebet'], + "diskaun_rebate"=>$tebusData['diskaun_rebate'], ]); } @@ -274,7 +276,8 @@ class TebusController extends Controller 'tebus.jbg', 'tebus.ujrah', 'tebus.onepercent', - 'gad.tagbaru' + 'gad.tagbaru', + 'tebus.diskaun_rebate' ) ->join('gadai as gad', 'gad.norujukan', '=', 'tebus.norujukan') ->where('tebus.t_tebus', '>=', $request->mula) @@ -310,7 +313,8 @@ class TebusController extends Controller "jbg"=>$tebusData['jbg'], "ujrah"=>$trans['ujrah_rebet'], "onepercent"=>$trans['onepercent_rebet'], - "tagbaru"=>$tebusData['tagbaru'] + "tagbaru"=>$tebusData['tagbaru'], + "diskaun_rebate"=>$tebusData['diskaun_rebate'], ]); } @@ -1672,6 +1676,53 @@ class TebusController extends Controller return response($rebet); } + public function RebetPromoCalculation($kodcaw, Request $request) + { + $kodcaw = $request->kodcaw ?: $kodcaw; + if (!Feature::enabled($kodcaw, Feature::REBET_ANNUR)) { + return response(0); + } + + $cawangan = Cawangan::on('mysql7')->where('kodcaw', '=', $kodcaw)->first(); + + $rebet = Tebus::on($cawangan['mysql']) + ->join('gadai as db2', 'tebus.norujukan', '=', 'db2.norujukan') + ->where('tebus.t_tebus', '<=', $request->tarikh) + ->where('db2.hargajualan', '>', '0') + ->whereNotNull('db2.hargajualan') + ->sum('diskaun_rebate'); + + return response($rebet); + } + + public function PelarasanRebate($kodcaw, Request $request) + { + $kodcaw = $request->kodcaw ?: $kodcaw; + if (!Feature::enabled($kodcaw, Feature::REBET_ANNUR)) { + return response(0); + } + + $cawangan = Cawangan::on('mysql7') + ->where('kodcaw', $kodcaw) + ->first(); + + $tarikhLaporan = Carbon::parse($request->tarikh)->toDateString(); + $tarikhTamatPelarasan = '2026-09-02'; + $tarikhAkhir = $tarikhLaporan > $tarikhTamatPelarasan + ? $tarikhTamatPelarasan + : $tarikhLaporan; + + $rebet = Tebus::on($cawangan['mysql']) + ->join('gadai as db2', 'tebus.norujukan', '=', 'db2.norujukan') + ->whereDate('tebus.t_tebus', '>=', '2025-05-13') + ->whereDate('tebus.t_tebus', '<=', $tarikhAkhir) + ->where('db2.hargajualan', '>', 0) + ->whereDate('db2.t_gadai', '>', '2023-05-21') + ->sum('tebus.diskaun_rebate'); + + return response($rebet); + } + public function RebetCalculationLejer($kodcaw,Request $request) { $cawangan = Cawangan::on('mysql7')->where('kodcaw','=',$request->kodcaw)->first(); @@ -1687,6 +1738,26 @@ class TebusController extends Controller return response($rebet); } + public function RebetPromoCalculationLejer($kodcaw, Request $request) + { + $kodcaw = $request->kodcaw ?: $kodcaw; + if (!Feature::enabled($kodcaw, Feature::REBET_ANNUR)) { + return response(0); + } + + $cawangan = Cawangan::on('mysql7')->where('kodcaw', '=', $kodcaw)->first(); + + $rebet = Tebus::on($cawangan['mysql']) + ->join('gadai as db2', 'tebus.norujukan', '=', 'db2.norujukan') + ->where('tebus.t_tebus', '>=', $request->mula) + ->where('tebus.t_tebus', '<=', $request->hingga) + ->where('db2.hargajualan', '>', '0') + ->whereNotNull('db2.hargajualan') + ->sum('diskaun_rebate'); + + return response($rebet); + } + public function getUpahLamaToday($kodcaw,$norujukan) { $current = Carbon::now(); diff --git a/app/KadarRebet.php b/app/KadarRebet.php new file mode 100644 index 0000000..e1cd20d --- /dev/null +++ b/app/KadarRebet.php @@ -0,0 +1,18 @@ +one_percent = $this->getKadarUpah($nilaimarhun); @@ -66,8 +69,59 @@ class Calculation $ujrah_sebenar = (!empty($ujrah_sebenar)) ? $this->getRoundedMethod($ujrah_sebenar) : 0; $keuntungan = $onepercent + $ujrah_sebenar; + $annur = $this->kiraanDiskaunAnnur($kodcaw, $pembiayaan, $keuntungan); - return ['keuntungan' => $keuntungan,'onepercent' => $onepercent, 'ujrah' => $ujrah_sebenar]; + return [ + 'keuntungan' => $keuntungan, + 'onepercent' => $onepercent, + 'ujrah' => $ujrah_sebenar, + 'diskaun' => $annur['diskaun'], + 'kadarrebet' => $annur['kadarrebet'], + ]; + } + + /** + * Annur promotional discount. Other cawangan get 0 unless rebet_annur is enabled. + */ + public function kiraanDiskaunAnnur($kodcaw, float $pembiayaan = 0.0, float $keuntungan = 0.0) + { + $empty = ['kadarrebet' => 0, 'diskaun' => 0]; + + try { + if (!$kodcaw || !Feature::enabled($kodcaw, Feature::REBET_ANNUR)) { + return $empty; + } + } catch (\Exception $e) { + return $empty; + } + + $percent = $this->kiraanRebetAnnur($pembiayaan); + if ($percent <= 0 || $keuntungan <= 0) { + return ['kadarrebet' => $percent, 'diskaun' => 0]; + } + + return [ + 'kadarrebet' => $percent, + 'diskaun' => $this->getRoundedMethod($keuntungan * ($percent / 100)), + ]; + } + + private function kiraanRebetAnnur(float $pembiayaan = 0.0) + { + try { + if (!Schema::connection('mysql7')->hasTable('kadar_rebet')) { + return 0; + } + + $kadarrebet = KadarRebet::on('mysql7') + ->where('pembiayaan_min', '<=', $pembiayaan) + ->where('pembiayaan_max', '>=', $pembiayaan) + ->sum('kadarrebet'); + + return (float) $kadarrebet; + } catch (\Exception $e) { + return 0; + } } public function kiraanKeuntunganSebenar(float $pembiayaan = 0.0,float $nilaimarhun = 0.0,float $kadarujrah = 0.0,float $margin = 0.0){ diff --git a/app/Support/v2/GadaiV2.php b/app/Support/v2/GadaiV2.php index b3febe1..7c17ca5 100644 --- a/app/Support/v2/GadaiV2.php +++ b/app/Support/v2/GadaiV2.php @@ -5,6 +5,7 @@ namespace App\Support\v2; use App\Audit; use App\Cawangan; use App\Customer; +use App\Feature; use App\KadarUpah; use App\Support\v2\Calculation; use Carbon\Carbon; @@ -137,14 +138,13 @@ if (is_null($kadar_raw)) { $upah12 = $onepercentservices->getRoundedMethod($upah1 * 12); $ujrah = $onepercentservices->getRoundedMethod($keuntungan['ujrah']); $onepercent = $onepercentservices->getRoundedMethod($keuntungan['onepercent']); + $annur = $onepercentservices->kiraanDiskaunAnnur($request->kodcaw, $request->pinjaman, $keuntungan['keuntungan']); $hargajualan = $request->pinjaman + $upah12; $akrual = $this->kiraupahTawarruqStokAuditUjrahOnePercent(0.5,0,$kadar_raw,$request->pinjaman,$total_nilai_marhun,$margin_pinjam); - $gadai = Gadai::on($cawangan['mysql']) - ->where('norujukan','=',$norujukan) - ->update(array( + $gadaiFields = [ 'nilaimarhun' => $total_nilai_marhun, 'berat'=> $total_berat, 'pinjaman' => $request->pinjaman, @@ -176,7 +176,23 @@ if (is_null($kadar_raw)) { 'tagbaru' => 1, 'tunggakanujrah' => $akrual['ujrah'], 'tunggakanonepercent' => $akrual['keuntungan'], - )); + ]; + if (Feature::enabled($request->kodcaw, Feature::REBET_ANNUR)) { + $requestedKadar = (float) $request->input('kadar_rebate', 0); + $requestedDiskaun = (float) $request->input('rebate', 0); + + if ($requestedKadar > 0 || $requestedDiskaun > 0) { + $gadaiFields['kadarrebet'] = $requestedKadar; + $gadaiFields['diskaun'] = $requestedDiskaun; + } elseif (($request->transaction ?? '') === 'Daftar Gadai') { + $gadaiFields['kadarrebet'] = $annur['kadarrebet']; + $gadaiFields['diskaun'] = $annur['diskaun']; + } + } + + $gadai = Gadai::on($cawangan['mysql']) + ->where('norujukan','=',$norujukan) + ->update($gadaiFields); $new_data = Gadai::on($cawangan['mysql'])->where('norujukan','=',$norujukan)->first(); @@ -240,14 +256,15 @@ if (is_null($kadar_raw)) { } $bilang_bln = $tempoh - $gadai_data['tempohbayar']; - $upah = $onepercentservices->kiraanKeuntunganRebet($gadai_data['bakipjm'],$gadai_data['nilaimarhun'],$gadai_data['kadarupah'],$gadai_data['margin_semasa']); + $upah = $onepercentservices->kiraanKeuntunganRebet($gadai_data['bakipjm'],$gadai_data['nilaimarhun'],$gadai_data['kadarupah'],$gadai_data['margin_semasa'], $this->kodcaw); //$upahrebet_raw = $bilang_bln * $upah['keuntungan']; $onepercent = $onepercentservices->getRoundedMethod($bilang_bln * $upah['onepercent']); $ujrah = $onepercentservices->getRoundedMethod($bilang_bln * $upah['ujrah']); $upahrebet_raw = $onepercent + $ujrah; $upahrebet_raw = $onepercentservices->getRoundedMethod($upahrebet_raw); - + $upahrebet_raw = $upahrebet_raw - ($upah['diskaun'] ?? 0); + return $upahrebet_raw; } @@ -282,7 +299,7 @@ if (is_null($kadar_raw)) { $margin_semasa = ($gadai['bakipjm'] / $gadai['nilaimarhun']) * 100; - $keuntungan = $onepercent->kiraanKeuntunganRebet($gadai['bakipjm'],$gadai['nilaimarhun'],$gadai['kadarupah'],$gadai['margin_semasa']); + $keuntungan = $onepercent->kiraanKeuntunganRebet($gadai['bakipjm'],$gadai['nilaimarhun'],$gadai['kadarupah'],$gadai['margin_semasa'], $kodcaw); $ujrahasal = $onepercent->kiraanUjrahSebenar($gadai['nilaimarhun'],$gadai['kadarupah'],$gadai['percentpinj']); $onepercentasal = $gadai['pinjaman'] * (1/100); @@ -319,7 +336,7 @@ if (is_null($kadar_raw)) { $keun = $onepercent->getRoundedMethod($onepercentasal * $bilang_bln); $keuntungan_rebate = $onepercent->getRoundedMethod($keuntungan['onepercent'] * $bilang_bln); - $transaction_upah = TransaksiKeuntungan::on('mysql7')->create([ + $transactionUpahFields = [ 'norujukan' => $norujukan, 'bayaran_keuntungan' => $upahsemasa, 'bayaran_pembiayaan' => $baki_bayaran, @@ -333,7 +350,12 @@ if (is_null($kadar_raw)) { 'tempoh' => $gadai['tempoh'], 'beza_tempoh' => $bilang_bln, 'margin_semasa' => $margin_semasa, - ]); + ]; + if (Feature::enabled($kodcaw, Feature::REBET_ANNUR)) { + $transactionUpahFields['kadardiskaun'] = $keuntungan['diskaun'] ?? 0; + } + + $transaction_upah = TransaksiKeuntungan::on('mysql7')->create($transactionUpahFields); $transaksi_gadai = TransaksiGadai::on('mysql7')->create([ 'kodcaw' => $old_data['kodcaw'], diff --git a/app/Support/v2/Penebusan.php b/app/Support/v2/Penebusan.php index 6294831..0afe15d 100644 --- a/app/Support/v2/Penebusan.php +++ b/app/Support/v2/Penebusan.php @@ -5,6 +5,7 @@ namespace App\Support\v2; use App\Advansur; use App\Audit; use App\Cawangan; +use App\Feature; use App\KadarUpah; use App\Support\v2\Calculation; use Carbon\Carbon; @@ -39,6 +40,32 @@ class Penebusan $this->cawangan_info = $cawangan_info; } + private function diskaunAnnur($kodcaw, $gadai) + { + try { + if (!Feature::enabled($kodcaw, Feature::REBET_ANNUR)) { + return 0.0; + } + } catch (\Exception $e) { + return 0.0; + } + + return (float) ($gadai['diskaun'] ?? 0); + } + + private function tebusAnnurFields($kodcaw, $diskaun) + { + try { + if (!Feature::enabled($kodcaw, Feature::REBET_ANNUR)) { + return []; + } + } catch (\Exception $e) { + return []; + } + + return ['diskaun_rebate' => $diskaun]; + } + public function tebusTawarruq($kodcaw,$norujukan){ $onepercentservices = new Calculation(); @@ -53,7 +80,8 @@ class Penebusan $jeniskeuntungan = ($gadai_data['tagbaru'] == 1) ? 'onepercent' : 'asal'; $rebet = $this->rebetselepastawarruq($kodcaw,$norujukan,$jeniskeuntungan); - $harga_tebus = $gadai_data['bakihargajualan'] - $rebet; + $diskaun = $this->diskaunAnnur($kodcaw, $gadai_data); + $harga_tebus = $gadai_data['bakihargajualan'] - $rebet - $diskaun; // $hargatebus = round($harga_tebus,PHP_ROUND_HALF_UP); // $hargatebus = bcdiv(round($harga_tebus,2),1,1); @@ -485,6 +513,8 @@ class Penebusan $gadai = Gadai::on($cawangan['mysql'])->where('norujukan','=',$norujukan)->first(); + $diskaun = $this->diskaunAnnur($kodcaw, $gadai); + //check duplicate $data = Transaction::on('mysql7')->where('norujukan','=',$norujukan)->whereIn('trans_type', ['P', 'T', 'S'])->first(); @@ -502,7 +532,6 @@ class Penebusan $harga_tebus = $this->hargaTebusTawarruq($kodcaw,$norujukan,$request->jeniskeuntungan); $upah_tebus = $this->kiraupahTawarruq($norujukan); $upah_rebet = $this->kiraUpahRebetSebenar($kodcaw,$norujukan); - $upah_rebet_sebenar = $harga_tebus['harga'] - $gadai['bakipjm']; if($request->jeniskeuntungan == 'onepercent'){ $array_onepercent = $this->kiraupahUjrahOnePercent($kodcaw,$norujukan); @@ -514,10 +543,15 @@ class Penebusan $ujrah = $array_onepercent['ujrah']; $onepercent = $array_onepercent['onepercent']; } + + $harga_tebus['harga'] -= $diskaun; + $upah_rebet_sebenar = $harga_tebus['harga'] - $gadai['bakipjm']; } + $bayaran_keuntungan_bersih = max(0, $upah_rebet_sebenar); - $create_tebus = Tebus::on($cawangan['mysql'])->create([ + + $create_tebus = Tebus::on($cawangan['mysql'])->create(array_merge([ 'kodcaw'=> $kodcaw, 'norujukan'=> $norujukan, 'nopelanggan' => $request->nopelanggan, @@ -543,7 +577,7 @@ class Penebusan 'teller' => $request->teller, 'ujrah' => $ujrah_rebet, 'onepercent' => $onepercent_rebet, - ]); + ], $this->tebusAnnurFields($kodcaw, $diskaun))); $create_inoutmar = InOutMar::on($cawangan['mysql'])->create([ 'tarikh' => $current->toDateString(), @@ -561,7 +595,7 @@ class Penebusan $transaction_upah = TransaksiKeuntungan::on('mysql7')->create([ 'norujukan' => $norujukan, - 'bayaran_keuntungan' => $upah_tebus, + 'bayaran_keuntungan' => $bayaran_keuntungan_bersih, 'bayaran_pembiayaan' => $gadai['bakipjm'], 'keuntungan_rebet' => $upah_rebet_sebenar, 'tarikh_bayaran'=> $current, @@ -651,6 +685,8 @@ class Penebusan $gadai = Gadai::on($cawangan['mysql'])->where('norujukan','=',$norujukan)->first(); + $diskaun = $this->diskaunAnnur($kodcaw, $gadai); + //check duplicate $data = Transaction::on('mysql7')->where('norujukan','=',$norujukan)->where('trans_type','=','AT')->first(); @@ -668,7 +704,6 @@ class Penebusan $harga_tebus = $this->hargaTebusTawarruq($kodcaw,$norujukan,$request->jeniskeuntungan); $upah_tebus = $this->kiraupahTawarruq($norujukan); $upah_rebet = $this->kiraUpahRebetSebenar($kodcaw,$norujukan); - $upah_rebet_sebenar = $harga_tebus['harga'] - $gadai['bakipjm']; if($request->jeniskeuntungan == 'onepercent'){ $array_onepercent = $this->kiraupahUjrahOnePercent($kodcaw,$norujukan); @@ -681,6 +716,9 @@ class Penebusan $ujrah = $array_onepercent['ujrah']; $onepercent = $array_onepercent['onepercent']; } + + $harga_tebus['harga'] -= $diskaun; + $upah_rebet_sebenar = $harga_tebus['harga'] - $gadai['bakipjm']; } $update_gadai = Gadai::on($cawangan['mysql'])->where('norujukan','=',$norujukan)->update(array( @@ -690,7 +728,7 @@ class Penebusan // $upah_rebet = $this->kiraUpahRebet($kodcaw,$norujukan); - $create_tebus = Tebus::on($cawangan['mysql'])->create([ + $create_tebus = Tebus::on($cawangan['mysql'])->create(array_merge([ 'kodcaw'=> $kodcaw, 'norujukan'=> $norujukan, 'nopelanggan' => $request->nopelanggan, @@ -716,7 +754,7 @@ class Penebusan 'teller' => $request->teller, 'ujrah' => $ujrah_rebet, 'onepercent' => $onepercent_rebet, - ]); + ], $this->tebusAnnurFields($kodcaw, $diskaun))); $create_inoutmar = InOutMar::on($cawangan['mysql'])->create([ 'tarikh' => $current->toDateString(), @@ -734,9 +772,11 @@ class Penebusan $bayaran_pembiayaan = $request->totalbayaran - $request->bakiupah; + $bayaran_keuntungan_bersih = max(0, $upah_rebet_sebenar); + $transaction_upah = TransaksiKeuntungan::on('mysql7')->create([ 'norujukan' => $norujukan, - 'bayaran_keuntungan' => $upah_tebus, + 'bayaran_keuntungan' => $bayaran_keuntungan_bersih, 'bayaran_pembiayaan' => $bayaran_pembiayaan, 'keuntungan_rebet' => $upah_rebet_sebenar, 'tarikh_bayaran'=> $current, @@ -1131,12 +1171,16 @@ class Penebusan $onepercent_rebet = $array_onepercent_rebet['onepercent'] - $upah_rebet['onepercent']; $ujrah_rebet = $array_onepercent_rebet['ujrah'] - $upah_rebet['ujrah']; + $diskaun = $this->diskaunAnnur($kodcaw, $gadai); + $harga_tebus['harga'] -= $diskaun; $upah_rebet_sebenar = $harga_tebus['harga'] - $gadai['bakipjm']; + $bayaran_keuntungan_bersih = max(0, $upah_rebet_sebenar); + try{ TransaksiKeuntungan::on('mysql7')->create([ 'norujukan' => $norujukan, - 'bayaran_keuntungan' => $upah_tebus, + 'bayaran_keuntungan' => $bayaran_keuntungan_bersih, 'bayaran_pembiayaan' => $bayaran_pembiayaan, 'keuntungan_rebet' => $upah_rebet_sebenar, 'tarikh_bayaran'=> $current, diff --git a/app/Tebus.php b/app/Tebus.php index 4d01786..e161227 100644 --- a/app/Tebus.php +++ b/app/Tebus.php @@ -52,7 +52,8 @@ class Tebus extends Model 'pinjamanterkini', 'tarikhbyrn', 'ujrah', - 'onepercent' + 'onepercent', + 'diskaun_rebate' ]; /** diff --git a/app/TransaksiKeuntungan.php b/app/TransaksiKeuntungan.php index 2fa926e..d0e8a71 100644 --- a/app/TransaksiKeuntungan.php +++ b/app/TransaksiKeuntungan.php @@ -14,7 +14,7 @@ class TransaksiKeuntungan extends Model * @var array */ protected $fillable = [ - 'norujukan','bayaran_keuntungan','tarikh_bayaran','kodcaw','bayaran_pembiayaan','keuntungan_rebet','ujrah','ujrah_rebet','onepercent','onepercent_rebet','tempoh','beza_tempoh','margin_semasa','rounded' + 'norujukan','bayaran_keuntungan','tarikh_bayaran','kodcaw','bayaran_pembiayaan','keuntungan_rebet','ujrah','ujrah_rebet','onepercent','onepercent_rebet','tempoh','beza_tempoh','margin_semasa','rounded','kadardiskaun' ]; /** diff --git a/database/migrations/2026_09_13_100000_create_kadar_rebet_table.php b/database/migrations/2026_09_13_100000_create_kadar_rebet_table.php new file mode 100644 index 0000000..53289c4 --- /dev/null +++ b/database/migrations/2026_09_13_100000_create_kadar_rebet_table.php @@ -0,0 +1,31 @@ +hasTable('kadar_rebet')) { + return; + } + + Schema::connection('mysql7')->create('kadar_rebet', function (Blueprint $table) { + $table->increments('id'); + $table->decimal('pembiayaan_min', 12, 2)->default(0); + $table->decimal('pembiayaan_max', 12, 2)->default(0); + $table->decimal('kadarrebet', 8, 4)->default(0); + }); + } + + public function down() + { + Schema::connection('mysql7')->dropIfExists('kadar_rebet'); + } +} diff --git a/database/migrations/2026_09_13_100001_add_annur_diskaun_columns.php b/database/migrations/2026_09_13_100001_add_annur_diskaun_columns.php new file mode 100644 index 0000000..6cf52d3 --- /dev/null +++ b/database/migrations/2026_09_13_100001_add_annur_diskaun_columns.php @@ -0,0 +1,102 @@ +getPdo(); + return true; + } catch (\Exception $e) { + return false; + } + }); + } + + public function up() + { + foreach ($this->getActiveDB() as $dbase) { + if (Schema::connection($dbase)->hasTable('gadai')) { + $addKadar = !Schema::connection($dbase)->hasColumn('gadai', 'kadarrebet'); + $addDiskaun = !Schema::connection($dbase)->hasColumn('gadai', 'diskaun'); + if ($addKadar || $addDiskaun) { + Schema::connection($dbase)->table('gadai', function (Blueprint $table) use ($addKadar, $addDiskaun) { + if ($addKadar) { + $table->decimal('kadarrebet', 8, 4)->nullable()->default(0); + } + if ($addDiskaun) { + $table->decimal('diskaun', 12, 2)->nullable()->default(0); + } + }); + } + } + + if ( + Schema::connection($dbase)->hasTable('tebus') + && !Schema::connection($dbase)->hasColumn('tebus', 'diskaun_rebate') + ) { + Schema::connection($dbase)->table('tebus', function (Blueprint $table) { + $table->decimal('diskaun_rebate', 12, 2)->nullable()->default(0); + }); + } + } + + if ( + Schema::connection('mysql7')->hasTable('transaksi_keuntungan') + && !Schema::connection('mysql7')->hasColumn('transaksi_keuntungan', 'kadardiskaun') + ) { + Schema::connection('mysql7')->table('transaksi_keuntungan', function (Blueprint $table) { + $table->decimal('kadardiskaun', 12, 2)->nullable()->default(0); + }); + } + } + + public function down() + { + foreach ($this->getActiveDB() as $dbase) { + if (Schema::connection($dbase)->hasTable('gadai')) { + Schema::connection($dbase)->table('gadai', function (Blueprint $table) use ($dbase) { + $drops = []; + if (Schema::connection($dbase)->hasColumn('gadai', 'kadarrebet')) { + $drops[] = 'kadarrebet'; + } + if (Schema::connection($dbase)->hasColumn('gadai', 'diskaun')) { + $drops[] = 'diskaun'; + } + if ($drops) { + $table->dropColumn($drops); + } + }); + } + + if ( + Schema::connection($dbase)->hasTable('tebus') + && Schema::connection($dbase)->hasColumn('tebus', 'diskaun_rebate') + ) { + Schema::connection($dbase)->table('tebus', function (Blueprint $table) { + $table->dropColumn('diskaun_rebate'); + }); + } + } + + if ( + Schema::connection('mysql7')->hasTable('transaksi_keuntungan') + && Schema::connection('mysql7')->hasColumn('transaksi_keuntungan', 'kadardiskaun') + ) { + Schema::connection('mysql7')->table('transaksi_keuntungan', function (Blueprint $table) { + $table->dropColumn('kadardiskaun'); + }); + } + } +} diff --git a/routes/web.php b/routes/web.php index 4c2ff8f..2aa7084 100644 --- a/routes/web.php +++ b/routes/web.php @@ -580,6 +580,8 @@ $router->group(['prefix'=>'api'], function () use ($router){ $router->get('CalculationPendahuluanSerahan/{kodcaw}',['uses'=>'VaultController@CalculationPendahuluanSerahan']); $router->get('KeuntunganArRahn/{kodcaw}',['uses'=>'GadaiController@CalculationKeuntungan']); $router->get('RebetCalculation/{kodcaw}',['uses'=>'TebusController@RebetCalculation']); + $router->get('RebetPromoCalculation/{kodcaw}',['uses'=>'TebusController@RebetPromoCalculation']); + $router->get('PelarasanRebate/{kodcaw}',['uses'=>'TebusController@PelarasanRebate']); //-- Harta Semasa --// $router->get('PinjamanDiberi/{kodcaw}',['uses'=>'GadaiController@CalculationPinjamanDiberi']); @@ -610,6 +612,7 @@ $router->group(['prefix'=>'api'], function () use ($router){ $router->get('ModalOnlineLejer/{kodcaw}', ['uses' => 'VaultController@CalculationModalOnlineLejer']); $router->get('KeuntunganArRahnLejer/{kodcaw}',['uses'=>'GadaiController@CalculationKeuntunganLejer']); $router->get('RebetCalculationLejer/{kodcaw}',['uses'=>'TebusController@RebetCalculationLejer']); + $router->get('RebetPromoCalculationLejer/{kodcaw}',['uses'=>'TebusController@RebetPromoCalculationLejer']); $router->get('cajlelongLejer/{kodcaw}',['uses'=>'LelongController@cajlelongcalculationLejer']); // //-- Harta Semasa --// -- 2.52.0 From 510dc7dd6a510c4fd5d75a92a80d5e394b248d3a Mon Sep 17 00:00:00 2001 From: ISMAIL MASSERAN Date: Thu, 17 Sep 2026 14:21:16 +0800 Subject: [PATCH 3/5] 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 --- .../PembiayaanOnlineController.php | 37 +++ app/PembiayaanOnline.php | 2 + .../PembiayaanOnlineService.php | 274 +++++++++++++++++- ...pc_verified_to_pembiayaan_online_table.php | 74 +++++ routes/web.php | 4 + 5 files changed, 386 insertions(+), 5 deletions(-) create mode 100644 database/migrations/2026_09_17_100000_add_pc_verified_to_pembiayaan_online_table.php diff --git a/app/Http/Controllers/PembiayaanOnlineController.php b/app/Http/Controllers/PembiayaanOnlineController.php index 700fdd0..547736f 100644 --- a/app/Http/Controllers/PembiayaanOnlineController.php +++ b/app/Http/Controllers/PembiayaanOnlineController.php @@ -35,6 +35,14 @@ class PembiayaanOnlineController extends Controller return $this->respond($this->service->show($kodcaw, $norujukan)); } + /** + * GET /api/pembiayaan-online/{kodcaw}/lines/{id} + */ + public function showLine($kodcaw, $id) + { + return $this->respond($this->service->showLine($kodcaw, $id)); + } + /** * GET /api/pembiayaan-online/{kodcaw}/queue */ @@ -53,6 +61,7 @@ class PembiayaanOnlineController extends Controller foreach ([ 'kodbank', 'noakaun', 'nama_bank', 'nama_akaun', 'nota', 'bukti_akaun_file_id', 'borang_file_id', 'update_customer_bank', + 'bukti_akaun_data', 'bukti_akaun_filename', 'bukti_akaun_type', ] as $key) { if ($request->has($key)) { $input[$key] = $request->input($key); @@ -62,6 +71,26 @@ class PembiayaanOnlineController extends Controller return $this->respond($this->service->updateLine($kodcaw, $id, $input)); } + /** + * POST /api/pembiayaan-online/{kodcaw}/lines/{id}/verify + */ + public function verifyLine($kodcaw, $id, Request $request) + { + return $this->respond($this->service->verifyLine( + $kodcaw, + $id, + $request->input('pc_verified_by', '') + )); + } + + /** + * POST /api/pembiayaan-online/{kodcaw}/lines/{id}/unverify + */ + public function unverifyLine($kodcaw, $id) + { + return $this->respond($this->service->unverifyLine($kodcaw, $id)); + } + /** * GET /api/pembiayaan-online/{kodcaw}/batches */ @@ -177,6 +206,14 @@ class PembiayaanOnlineController extends Controller return $this->respond($this->service->getBukti($kodcaw, $id)); } + /** + * GET /api/pembiayaan-online/{kodcaw}/lines/{id}/bukti-akaun + */ + public function getBuktiAkaun($kodcaw, $id) + { + return $this->respond($this->service->getBuktiAkaun($kodcaw, $id)); + } + /** * GET /api/pembiayaan-online/{kodcaw}/paid?blast_sent=0 */ diff --git a/app/PembiayaanOnline.php b/app/PembiayaanOnline.php index a1bf1b3..079e3ee 100644 --- a/app/PembiayaanOnline.php +++ b/app/PembiayaanOnline.php @@ -32,6 +32,8 @@ class PembiayaanOnline extends Model 'paid_at', 'created_by', 'pc_submitted_by', + 'pc_verified_by', + 'pc_verified_at', 'ops_by', 'nota', 'blast_sent', diff --git a/app/Services/PembiayaanOnline/PembiayaanOnlineService.php b/app/Services/PembiayaanOnline/PembiayaanOnlineService.php index abd0231..27c2c24 100644 --- a/app/Services/PembiayaanOnline/PembiayaanOnlineService.php +++ b/app/Services/PembiayaanOnline/PembiayaanOnlineService.php @@ -16,9 +16,11 @@ use Illuminate\Support\Facades\Log; class PembiayaanOnlineService { - const MIN_PINJAMAN = 5000.00; + const MIN_PINJAMAN = 1.00; const MAX_PINJAMAN = 50000.00; - const PC_QUEUE_STATUSES = ['PENDING_PC', 'REJECTED_PC']; + const PC_QUEUE_STATUSES = ['PENDING_PC', 'REJECTED_PC', 'VERIFIED_PC']; + const PC_VERIFY_FROM_STATUSES = ['PENDING_PC', 'REJECTED_PC']; + const PC_SUBMITTABLE_STATUSES = ['VERIFIED_PC']; protected $modalOnlineService; @@ -258,6 +260,36 @@ class PembiayaanOnlineService ]; } + /** + * @return array{ok:bool,status:int,payload:mixed} + */ + public function showLine($kodcaw, $id) + { + $resolved = $this->resolveMysql($kodcaw); + if (!$resolved['ok']) { + return $resolved; + } + + $line = PembiayaanOnline::on($resolved['mysql']) + ->where('kodcaw', $kodcaw) + ->where('id', $id) + ->first(); + + if (!$line) { + return [ + 'ok' => false, + 'status' => 404, + 'payload' => ['message' => 'Pembiayaan online tidak dijumpai'], + ]; + } + + return [ + 'ok' => true, + 'status' => 200, + 'payload' => $line, + ]; + } + /** * @return array{ok:bool,status:int,payload:mixed} */ @@ -332,7 +364,7 @@ class PembiayaanOnlineService 'ok' => false, 'status' => 422, 'payload' => [ - 'message' => 'Hanya rekod PENDING_PC / REJECTED_PC boleh dikemaskini', + 'message' => 'Hanya rekod PENDING_PC / REJECTED_PC / VERIFIED_PC boleh dikemaskini', 'status' => $line->status, ], ]; @@ -368,6 +400,18 @@ class PembiayaanOnlineService $fields['borang_file_id'] = $input['borang_file_id']; } + if (!empty($input['bukti_akaun_data'])) { + $saved = $this->storeBuktiFile([ + 'data' => $input['bukti_akaun_data'], + 'filename' => $input['bukti_akaun_filename'] ?? $input['filename'] ?? null, + 'type' => $input['bukti_akaun_type'] ?? $input['type'] ?? null, + ]); + if (!$saved['ok']) { + return $saved; + } + $fields['bukti_akaun_file_id'] = $saved['payload']['id']; + } + if (empty($fields)) { return [ 'ok' => false, @@ -395,6 +439,12 @@ class PembiayaanOnlineService ? (bool) $input['update_customer_bank'] : true; + if ($line->status === 'VERIFIED_PC') { + $fields['status'] = !empty($line->reject_reason) ? 'REJECTED_PC' : 'PENDING_PC'; + $fields['pc_verified_by'] = null; + $fields['pc_verified_at'] = null; + } + try { DB::connection($mysql)->transaction(function () use ($mysql, $line, $fields, $updateCustomerBank) { PembiayaanOnline::on($mysql)->where('id', $line->id)->update($fields); @@ -433,6 +483,159 @@ class PembiayaanOnlineService } } + /** + * PC confirms one queue line before it can be submitted to Operasi. + * + * @return array{ok:bool,status:int,payload:mixed} + */ + public function verifyLine($kodcaw, $id, $pcBy) + { + $resolved = $this->resolveMysql($kodcaw); + if (!$resolved['ok']) { + return $resolved; + } + $mysql = $resolved['mysql']; + + $pcBy = trim((string) $pcBy); + if ($pcBy === '') { + return [ + 'ok' => false, + 'status' => 422, + 'payload' => ['message' => 'pc_verified_by diperlukan'], + ]; + } + + try { + return DB::connection($mysql)->transaction(function () use ($mysql, $kodcaw, $id, $pcBy) { + $line = PembiayaanOnline::on($mysql) + ->where('kodcaw', $kodcaw) + ->where('id', $id) + ->lockForUpdate() + ->first(); + + if (!$line) { + return [ + 'ok' => false, + 'status' => 404, + 'payload' => ['message' => 'Pembiayaan online tidak dijumpai'], + ]; + } + + if ($line->status === 'VERIFIED_PC') { + return [ + 'ok' => true, + 'status' => 200, + 'payload' => $line, + ]; + } + + if (!in_array($line->status, self::PC_VERIFY_FROM_STATUSES, true)) { + return [ + 'ok' => false, + 'status' => 422, + 'payload' => [ + 'message' => 'Hanya rekod PENDING_PC / REJECTED_PC boleh disemak', + 'status' => $line->status, + ], + ]; + } + + if (empty($line->kodbank) || empty($line->noakaun)) { + return [ + 'ok' => false, + 'status' => 422, + 'payload' => [ + 'message' => 'Maklumat bank tidak lengkap. Kemaskini bank sebelum semak.', + 'id' => $line->id, + 'norujukan' => $line->norujukan, + ], + ]; + } + + PembiayaanOnline::on($mysql)->where('id', $line->id)->update([ + 'status' => 'VERIFIED_PC', + 'pc_verified_by' => $pcBy, + 'pc_verified_at' => Carbon::now(), + ]); + + return [ + 'ok' => true, + 'status' => 200, + 'payload' => PembiayaanOnline::on($mysql)->where('id', $line->id)->first(), + ]; + }); + } catch (\Throwable $e) { + Log::error('PembiayaanOnline verifyLine failed: ' . $e->getMessage()); + return [ + 'ok' => false, + 'status' => 500, + 'payload' => ['message' => 'Gagal semak pembiayaan online'], + ]; + } + } + + /** + * Undo PC verification so the line must be checked again. + * + * @return array{ok:bool,status:int,payload:mixed} + */ + public function unverifyLine($kodcaw, $id) + { + $resolved = $this->resolveMysql($kodcaw); + if (!$resolved['ok']) { + return $resolved; + } + $mysql = $resolved['mysql']; + + try { + return DB::connection($mysql)->transaction(function () use ($mysql, $kodcaw, $id) { + $line = PembiayaanOnline::on($mysql) + ->where('kodcaw', $kodcaw) + ->where('id', $id) + ->lockForUpdate() + ->first(); + + if (!$line) { + return [ + 'ok' => false, + 'status' => 404, + 'payload' => ['message' => 'Pembiayaan online tidak dijumpai'], + ]; + } + + if ($line->status !== 'VERIFIED_PC') { + return [ + 'ok' => false, + 'status' => 422, + 'payload' => [ + 'message' => 'Hanya rekod VERIFIED_PC boleh dibatalkan semakan', + 'status' => $line->status, + ], + ]; + } + + PembiayaanOnline::on($mysql)->where('id', $line->id)->update([ + 'status' => !empty($line->reject_reason) ? 'REJECTED_PC' : 'PENDING_PC', + 'pc_verified_by' => null, + 'pc_verified_at' => null, + ]); + + return [ + 'ok' => true, + 'status' => 200, + 'payload' => PembiayaanOnline::on($mysql)->where('id', $line->id)->first(), + ]; + }); + } catch (\Throwable $e) { + Log::error('PembiayaanOnline unverifyLine failed: ' . $e->getMessage()); + return [ + 'ok' => false, + 'status' => 500, + 'payload' => ['message' => 'Gagal batal semakan pembiayaan online'], + ]; + } + } + /** * @return array{ok:bool,status:int,payload:mixed} */ @@ -573,12 +776,12 @@ class PembiayaanOnlineService } foreach ($lines as $line) { - if (!in_array($line->status, self::PC_QUEUE_STATUSES, true)) { + if (!in_array($line->status, self::PC_SUBMITTABLE_STATUSES, true)) { return [ 'ok' => false, 'status' => 422, 'payload' => [ - 'message' => 'Rekod bukan dalam queue PC', + 'message' => 'Rekod belum disemak PC. Sahkan satu-satu sebelum hantar ke Operasi.', 'id' => $line->id, 'norujukan' => $line->norujukan, 'status' => $line->status, @@ -869,6 +1072,8 @@ class PembiayaanOnlineService 'rejected_at' => $now, 'ops_by' => $opsBy, 'batch_id' => null, + 'pc_verified_by' => null, + 'pc_verified_at' => null, ]); $batch = null; @@ -1314,6 +1519,65 @@ class PembiayaanOnlineService ]; } + /** + * Get attached bank-account slip (bukti_akaun_file_id) for a line. + * + * @return array{ok:bool,status:int,payload:mixed} + */ + public function getBuktiAkaun($kodcaw, $id) + { + $resolved = $this->resolveMysql($kodcaw); + if (!$resolved['ok']) { + return $resolved; + } + + $line = PembiayaanOnline::on($resolved['mysql']) + ->where('kodcaw', $kodcaw) + ->where('id', $id) + ->first(); + + if (!$line) { + return [ + 'ok' => false, + 'status' => 404, + 'payload' => ['message' => 'Pembiayaan online tidak dijumpai'], + ]; + } + + if (empty($line->bukti_akaun_file_id)) { + return [ + 'ok' => false, + 'status' => 404, + 'payload' => ['message' => 'Slip bank belum dimuat naik'], + ]; + } + + $file = ARFiles::on('mysql7')->where('id', $line->bukti_akaun_file_id)->first(); + if (!$file) { + return [ + 'ok' => false, + 'status' => 404, + 'payload' => ['message' => 'Fail slip bank tidak dijumpai'], + ]; + } + + return [ + 'ok' => true, + 'status' => 200, + 'payload' => [ + 'pembiayaan_online_id' => $line->id, + 'norujukan' => $line->norujukan, + 'file' => [ + 'id' => $file->id, + 'filename' => $file->filename, + 'type' => $file->type, + 'tarikhmasa' => $file->tarikhmasa, + 'data' => $file->data, + ], + ], + ]; + } + /** * PC list of PAID lines awaiting blast / tally. * diff --git a/database/migrations/2026_09_17_100000_add_pc_verified_to_pembiayaan_online_table.php b/database/migrations/2026_09_17_100000_add_pc_verified_to_pembiayaan_online_table.php new file mode 100644 index 0000000..b98f47c --- /dev/null +++ b/database/migrations/2026_09_17_100000_add_pc_verified_to_pembiayaan_online_table.php @@ -0,0 +1,74 @@ +getPdo(); + + return true; + } catch (\Exception $e) { + return false; + } + } + ); + } + + public function up() + { + foreach ($this->getActiveDB() as $dbase) { + if (!Schema::connection($dbase)->hasTable('pembiayaan_online')) { + continue; + } + + Schema::connection($dbase)->table('pembiayaan_online', function (Blueprint $table) use ($dbase) { + if (!Schema::connection($dbase)->hasColumn('pembiayaan_online', 'pc_verified_by')) { + $table->string('pc_verified_by', 100) + ->nullable() + ->after('pc_submitted_by'); + } + + if (!Schema::connection($dbase)->hasColumn('pembiayaan_online', 'pc_verified_at')) { + $table->timestamp('pc_verified_at') + ->nullable() + ->after('pc_verified_by'); + } + }); + } + } + + public function down() + { + foreach ($this->getActiveDB() as $dbase) { + if (!Schema::connection($dbase)->hasTable('pembiayaan_online')) { + continue; + } + + Schema::connection($dbase)->table('pembiayaan_online', function (Blueprint $table) use ($dbase) { + $cols = []; + if (Schema::connection($dbase)->hasColumn('pembiayaan_online', 'pc_verified_at')) { + $cols[] = 'pc_verified_at'; + } + if (Schema::connection($dbase)->hasColumn('pembiayaan_online', 'pc_verified_by')) { + $cols[] = 'pc_verified_by'; + } + if (!empty($cols)) { + $table->dropColumn($cols); + } + }); + } + } +} diff --git a/routes/web.php b/routes/web.php index 2aa7084..39fc2c3 100644 --- a/routes/web.php +++ b/routes/web.php @@ -713,7 +713,11 @@ $router->group(['prefix'=>'api'], function () use ($router){ $router->get('pembiayaan-online/{kodcaw}/paid', ['uses' => 'PembiayaanOnlineController@paidQueue']); $router->post('pembiayaan-online/{kodcaw}/paid/blast', ['uses' => 'PembiayaanOnlineController@markBlastSent']); $router->put('pembiayaan-online/{kodcaw}/lines/{id}', ['uses' => 'PembiayaanOnlineController@updateLine']); + $router->post('pembiayaan-online/{kodcaw}/lines/{id}/verify', ['uses' => 'PembiayaanOnlineController@verifyLine']); + $router->post('pembiayaan-online/{kodcaw}/lines/{id}/unverify', ['uses' => 'PembiayaanOnlineController@unverifyLine']); $router->get('pembiayaan-online/{kodcaw}/lines/{id}/bukti', ['uses' => 'PembiayaanOnlineController@getBukti']); + $router->get('pembiayaan-online/{kodcaw}/lines/{id}/bukti-akaun', ['uses' => 'PembiayaanOnlineController@getBuktiAkaun']); + $router->get('pembiayaan-online/{kodcaw}/lines/{id}', ['uses' => 'PembiayaanOnlineController@showLine']); $router->get('pembiayaan-online/{kodcaw}/batches', ['uses' => 'PembiayaanOnlineController@listBatches']); $router->get('pembiayaan-online/{kodcaw}/batches/{batchId}', ['uses' => 'PembiayaanOnlineController@showBatch']); $router->post('pembiayaan-online/{kodcaw}/batches/submit', ['uses' => 'PembiayaanOnlineController@submitBatch']); -- 2.52.0 From 031985ce992fc68d553805c49474e568a477c7f1 Mon Sep 17 00:00:00 2001 From: ISMAIL MASSERAN Date: Sun, 20 Sep 2026 10:14:00 +0800 Subject: [PATCH 4/5] DONE: use annur api when feature enabled --- .env.docker | 2 + .env.example | 1 + .env.production | 2 + .env.tukar | 244 -------------------- app/Feature.php | 22 ++ app/Http/Controllers/CawanganController.php | 1 + app/Http/Controllers/LelongController.php | 13 +- config/app_parameter.php | 1 + 8 files changed, 33 insertions(+), 253 deletions(-) delete mode 100644 .env.tukar diff --git a/.env.docker b/.env.docker index fedbeed..ea8375c 100644 --- a/.env.docker +++ b/.env.docker @@ -4,6 +4,8 @@ APP_KEY=WbPGkYNmXZ6ZQplGlvl0iZ7zyW1b09xa APP_DEBUG=true APP_URL=http://localhost APP_TIMEZONE=Asia/Kuala_Lumpur +API_ARRAHNBID=http://lelong.test/api/ +API_ARRAHNBID_ANNUR=http://lelong-annur.test/api/ LOG_CHANNEL=stack LOG_LEVEL=debug diff --git a/.env.example b/.env.example index a4e9ab2..9f8a734 100644 --- a/.env.example +++ b/.env.example @@ -5,6 +5,7 @@ APP_DEBUG=true APP_URL=http://api_arrahn.test APP_TIMEZONE=Asia/Kuala_Lumpur API_ARRAHNBID=http://lelong.test/api/ +API_ARRAHNBID_ANNUR=http://lelong-annur.test/api/ LOG_CHANNEL=stack LOG_SLACK_WEBHOOK_URL= diff --git a/.env.production b/.env.production index e218148..90443a6 100644 --- a/.env.production +++ b/.env.production @@ -4,6 +4,8 @@ APP_KEY=WbPGkYNmXZ6ZQplGlvl0iZ7zyW1b09xa APP_DEBUG=false APP_URL=https://apiujrah.erahn.com.my APP_TIMEZONE=Asia/Kuala_Lumpur +API_ARRAHNBID=https://adminbid-kopkb.erahn.com.my/api/ +API_ARRAHNBID_ANNUR=https://adminbid-annur.erahn.com.my/api/ LOG_CHANNEL=stack LOG_SLACK_WEBHOOK_URL= diff --git a/.env.tukar b/.env.tukar deleted file mode 100644 index e2fe920..0000000 --- a/.env.tukar +++ /dev/null @@ -1,244 +0,0 @@ -APP_NAME=Lumen -APP_ENV=local -APP_KEY=WbPGkYNmXZ6ZQplGlvl0iZ7zyW1b09xa -APP_DEBUG=false -APP_URL=https://api.arrahn.com.my -APP_TIMEZONE=Asia/Kuala_Lumpur - - -LOG_CHANNEL=stack -LOG_SLACK_WEBHOOK_URL= - -DB_CONNECTION=mysql -DB_HOST=172.16.4.102 -DB_PORT=3306 -DB_DATABASE=arrahn_kb2 -DB_USERNAME=zone2 -DB_PASSWORD=G0dz!ll4@2020 - -DB_CONNECTION_2=mysql -DB_HOST_2=172.16.4.102 -DB_PORT_2=3306 -DB_DATABASE_2=arrahn_wcy -DB_USERNAME_2=zone2 -DB_PASSWORD_2=G0dz!ll4@2020 - -DB_CONNECTION_3=mysql -DB_HOST_3=172.16.4.102 -DB_PORT_3=3306 -DB_DATABASE_3=arrahn_1stop -DB_USERNAME_3=zone2 -DB_PASSWORD_3=G0dz!ll4@2020 - -DB_CONNECTION_4=mysql -DB_HOST_4=172.16.4.102 -DB_PORT_4=3306 -DB_DATABASE_4=arrahn_jlwt -DB_USERNAME_4=zone2 -DB_PASSWORD_4=G0dz!ll4@2020 - -DB_CONNECTION_5=mysql -DB_HOST_5=172.16.4.102 -DB_PORT_5=3306 -DB_DATABASE_5=arrahn_wb -DB_USERNAME_5=zone2 -DB_PASSWORD_5=G0dz!ll4@2020 - -DB_CONNECTION_6=mysql -DB_HOST_6=172.16.4.102 -DB_PORT_6=3306 -DB_DATABASE_6=arrahn_kls -DB_USERNAME_6=zone2 -DB_PASSWORD_6=G0dz!ll4@2020 - -DB_CONNECTION_7=mysql -DB_HOST_7=172.16.4.102 -DB_PORT_7=3306 -DB_DATABASE_7=online_arrahn -DB_USERNAME_7=zone2 -DB_PASSWORD_7=G0dz!ll4@2020 - -DB_CONNECTION_8=mysql -DB_HOST_8=172.16.4.102 -DB_PORT_8=3306 -DB_DATABASE_8=arrahn_pp -DB_USERNAME_8=zone2 -DB_PASSWORD_8=G0dz!ll4@2020 - -DB_CONNECTION_9=mysql -DB_HOST_9=172.16.4.102 -DB_PORT_9=3306 -DB_DATABASE_9=arrahn_mace -DB_USERNAME_9=zone2 -DB_PASSWORD_9=G0dz!ll4@2020 - -DB_CONNECTION_10=mysql -DB_HOST_10=172.16.4.102 -DB_PORT_10=3306 -DB_DATABASE_10=arrahn_pm -DB_USERNAME_10=zone2 -DB_PASSWORD_10=G0dz!ll4@2020 - -DB_CONNECTION_11=mysql -DB_HOST_11=172.16.4.102 -DB_PORT_11=3306 -DB_DATABASE_11=arrahn_gm -DB_USERNAME_11=zone2 -DB_PASSWORD_11=G0dz!ll4@2020 - -DB_CONNECTION_12=mysql -DB_HOST_12172.16.4.102 -DB_PORT_12=3306 -DB_DATABASE_12=arrahn_gcl -DB_USERNAME_12=zone2 -DB_PASSWORD_12=G0dz!ll4@2020 - -DB_CONNECTION_13=mysql -DB_HOST_13=172.16.4.102 -DB_PORT_13=3306 -DB_DATABASE_13=arrahn_jli -DB_USERNAME_13=zone2 -DB_PASSWORD_13=G0dz!ll4@2020 - -DB_CONNECTION_14=mysql -DB_HOST_14=172.16.4.102 -DB_PORT_14=3306 -DB_DATABASE_14=arrahn_rp -DB_USERNAME_14=zone2 -DB_PASSWORD_14=G0dz!ll4@2020 - -DB_CONNECTION_15=mysql -DB_HOST_15=172.16.4.102 -DB_PORT_15=3306 -DB_DATABASE_15=arrahn_ktn -DB_USERNAME_15=zone2 -DB_PASSWORD_15=G0dz!ll4@2020 - -DB_CONNECTION_16=mysql -DB_HOST_16=172.16.4.102 -DB_PORT_16=3306 -DB_DATABASE_16=arrahn_pg -DB_USERNAME_16=zone2 -DB_PASSWORD_16=G0dz!ll4@2020 - -DB_CONNECTION_17=mysql -DB_HOST_17=172.16.4.102 -DB_PORT_17=3306 -DB_DATABASE_17=arrahn_skudai -DB_USERNAME_17=zone2 -DB_PASSWORD_17=G0dz!ll4@2020 - -DB_CONNECTION_18=mysql -DB_HOST_18=172.16.4.102 -DB_PORT_18=3306 -DB_DATABASE_18=arrahn_pttn -DB_USERNAME_18=zone2 -DB_PASSWORD_18=G0dz!ll4@2020 - -DB_CONNECTION_19=mysql -DB_HOST_19=172.16.4.102 -DB_PORT_19=3306 -DB_DATABASE_19=arrahn_btg -DB_USERNAME_19=zone2 -DB_PASSWORD_19=G0dz!ll4@2020 - -DB_CONNECTION_20=mysql -DB_HOST_20=172.16.4.102 -DB_PORT_20=3306 -DB_DATABASE_20=arrahn_raub -DB_USERNAME_20=zone2 -DB_PASSWORD_20=G0dz!ll4@2020 - -DB_CONNECTION_21=mysql -DB_HOST_21=172.16.4.102 -DB_PORT_21=3306 -DB_DATABASE_21=arrahn_kgr -DB_USERNAME_21=zone2 -DB_PASSWORD_21=G0dz!ll4@2020 - -DB_CONNECTION_22=mysql -DB_HOST_22=172.16.4.102 -DB_PORT_22=3306 -DB_DATABASE_22=arrahn_sdk -DB_USERNAME_22=zone2 -DB_PASSWORD_22=G0dz!ll4@2020 - -DB_CONNECTION_23=mysql -DB_HOST_23=172.16.4.102 -DB_PORT_23=3306 -DB_DATABASE_23=arrahn_sp -DB_USERNAME_23=zone2 -DB_PASSWORD_23=G0dz!ll4@2020 - -DB_CONNECTION_24=mysql -DB_HOST_24=172.16.4.102 -DB_PORT_24=3306 -DB_DATABASE_24=arrahn_twu -DB_USERNAME_24=zone2 -DB_PASSWORD_24=G0dz!ll4@2020 - -DB_CONNECTION_25=mysql -DB_HOST_25=172.16.4.102 -DB_PORT_25=3306 -DB_DATABASE_25=arrahn_api2 -DB_USERNAME_25=zone2 -DB_PASSWORD_25=G0dz!ll4@2020 - -DB_CONNECTION_26=mysql -DB_HOST_26=172.16.4.102 -DB_PORT_26=3306 -DB_DATABASE_26=arrahn_kjg -DB_USERNAME_26=zone2 -DB_PASSWORD_26=G0dz!ll4@2020 - -DB_CONNECTION_27=mysql -DB_HOST_27=172.16.4.102 -DB_PORT_27=3306 -DB_DATABASE_27=arrahn_rl -DB_USERNAME_27=zone2 -DB_PASSWORD_27=G0dz!ll4@2020 - -DB_CONNECTION_28=mysql -DB_HOST_28=172.16.4.102 -DB_PORT_28=3306 -DB_DATABASE_28=arrahn_bfort -DB_USERNAME_28=zone2 -DB_PASSWORD_28=G0dz!ll4@2020 - -DB_CONNECTION_29=mysql -DB_HOST_29=172.16.4.102 -DB_PORT_29=3306 -DB_DATABASE_29=arrahn_kbelud -DB_USERNAME_29=zone2 -DB_PASSWORD_29=G0dz!ll4@2020 - -DB_CONNECTION_30=mysql -DB_HOST_30=172.16.4.102 -DB_PORT_30=3306 -DB_DATABASE_30=arrahn_tuaran -DB_USERNAME_30=zone2 -DB_PASSWORD_30=G0dz!ll4@2020 - -DB_CONNECTION_31=mysql -DB_HOST_31=172.16.4.102 -DB_PORT_31=3306 -DB_DATABASE_31=arrahn_kngau -DB_USERNAME_31=zone2 -DB_PASSWORD_31=G0dz!ll4@2020 - -DB_CONNECTION_32=mysql -DB_HOST_32=172.16.4.102 -DB_PORT_32=3306 -DB_DATABASE_32=arrahn_tm -DB_USERNAME_32=zone2 -DB_PASSWORD_32=G0dz!ll4@2020 - -DB_CONNECTION_33=mysql -DB_HOST_33=172.16.4.102 -DB_PORT_33=3306 -DB_DATABASE_33=arrahn_tmlh -DB_USERNAME_33=zone2 -DB_PASSWORD_33=G0dz!ll4@2020 - -CACHE_DRIVER=file -QUEUE_CONNECTION=sync diff --git a/app/Feature.php b/app/Feature.php index 1cccc7e..79efd1e 100644 --- a/app/Feature.php +++ b/app/Feature.php @@ -46,6 +46,28 @@ class Feature ]; } + /** + * Lelong portal base URL for this branch. rebet_annur branches (Annur/Tampoi) + * use API_ARRAHNBID_ANNUR; everyone else uses API_ARRAHNBID. + * + * Always returned with a trailing slash so callers can append 'portalApi'. + * + * @param string $kodcaw + * @return string + */ + public static function arrahnbidUrl($kodcaw) + { + $url = config('app_parameter.api_arrahnbid'); + if ($kodcaw && self::enabled($kodcaw, self::REBET_ANNUR)) { + $annur = config('app_parameter.api_arrahnbid_annur'); + if ($annur) { + $url = $annur; + } + } + + return rtrim((string) $url, '/') . '/'; + } + /** * Missing row is off (fail closed). * diff --git a/app/Http/Controllers/CawanganController.php b/app/Http/Controllers/CawanganController.php index f6f5df8..e01b692 100644 --- a/app/Http/Controllers/CawanganController.php +++ b/app/Http/Controllers/CawanganController.php @@ -26,6 +26,7 @@ class CawanganController extends Controller $data = $cawangan->toArray(); $data['features'] = Feature::mapFor($code_cawangan); + $data['api_arrahnbid'] = Feature::arrahnbidUrl($code_cawangan); return response()->json($data); } diff --git a/app/Http/Controllers/LelongController.php b/app/Http/Controllers/LelongController.php index d959f20..e2dbadb 100644 --- a/app/Http/Controllers/LelongController.php +++ b/app/Http/Controllers/LelongController.php @@ -11,6 +11,7 @@ use App\Negeri; use App\Lelong; use App\Transaction; use App\Cawangan; +use App\Feature; use App\Gadai; use App\TuntutBaki; use App\WTD; @@ -604,13 +605,7 @@ class LelongController extends Controller $cawangan = Cawangan::on('mysql7')->where('kodcaw','=',$request->kodcaw)->first(); if($cawangan['tagarrahnbid'] == 1){ - if(env('APP_ENV') != 'production'){ - $link = 'https://adminbid-kopkb.erahn.com.my/api/portalApi'; - }else{ - $link = 'https://adminbid-kopkb.erahn.com.my/api/portalApi'; - } - - $lelong = Http::withOptions(['verify' => true])->get($link,[ + $lelong = Http::withOptions(['verify' => true])->get(Feature::arrahnbidUrl($request->kodcaw).'portalApi',[ 'norujukan' => $request->norujukan ])->json(); $lelong = ($lelong != null) ? $lelong['lelong'] : []; @@ -656,7 +651,7 @@ class LelongController extends Controller $cawangan = Cawangan::on('mysql7')->where('kodcaw', '=', $request->kodcaw)->first(); if ($cawangan['tagarrahnbid'] == 0){ - $lelong = Http::withOptions(['verify' => true])->get(config('app_parameter.api_arrahnbid').'portalApi',[ + $lelong = Http::withOptions(['verify' => true])->get(Feature::arrahnbidUrl($request->kodcaw).'portalApi',[ 'norujukan' => $request->norujukan ])->json(); $lelong = ($lelong != null) ? $lelong['lelong'] : []; @@ -729,7 +724,7 @@ class LelongController extends Controller if($cawangan['tagarrahnbid'] == 1) { - $lelong = Http::withOptions(['verify' => true])->get(config('app_parameter.api_arrahnbid').'portalApi',['norujukan' => $request->norujukan])->json(); + $lelong = Http::withOptions(['verify' => true])->get(Feature::arrahnbidUrl($request->kodcaw).'portalApi',['norujukan' => $request->norujukan])->json(); $lelong = ($lelong != null) ? $lelong['lelong'] : []; }else{ $lelong = Lelong::on($cawangan['mysql'])->where([['norujukan',$request->norujukan]])->first(); diff --git a/config/app_parameter.php b/config/app_parameter.php index b9b4014..bf9e75b 100644 --- a/config/app_parameter.php +++ b/config/app_parameter.php @@ -3,6 +3,7 @@ return [ 'url' => env('APP_URL', 'http://localhost'), 'api_arrahnbid' => env('API_ARRAHNBID', 'http://lelong.test/api/'), + 'api_arrahnbid_annur' => env('API_ARRAHNBID_ANNUR', env('API_ARRAHNBID', 'http://lelong.test/api/')), 'api_v3' => env('API_V3', 'http://apiv3.localhost/api/') ]; -- 2.52.0 From 0cff8f4eafed4c1b9b3aa6ee48d66ef433467e66 Mon Sep 17 00:00:00 2001 From: ISMAIL MASSERAN Date: Sun, 20 Sep 2026 12:48:13 +0800 Subject: [PATCH 5/5] DONE: add fallback when clicking on detail gadaian due to missing lelong api, add cara terima column on laporan pembiayaan --- app/Http/Controllers/GadaiController.php | 3 +- app/Http/Controllers/LelongController.php | 42 +++++++++++++++++------ 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/app/Http/Controllers/GadaiController.php b/app/Http/Controllers/GadaiController.php index 34195ee..0c8006f 100644 --- a/app/Http/Controllers/GadaiController.php +++ b/app/Http/Controllers/GadaiController.php @@ -629,8 +629,7 @@ class GadaiController extends Controller "alamat1" => optional($customer)->alamat1, "t_gadai" => $g->t_gadai, "norujukan" => $g->norujukan, - "cara_terima" => $g->cara_terima, - "norujukan"=> $g->norujukan, + "cara_terima" => strtoupper((string) ($g->cara_terima ?: 'TUNAI')), "nokp"=> $g->nokp, "semakbarcode"=> $g->semakbarcode, diff --git a/app/Http/Controllers/LelongController.php b/app/Http/Controllers/LelongController.php index e2dbadb..e32dbfa 100644 --- a/app/Http/Controllers/LelongController.php +++ b/app/Http/Controllers/LelongController.php @@ -27,6 +27,7 @@ use App\Tunai; use App\Audit; use App\GlDetail; use App\Pembeli; +use Illuminate\Http\Client\ConnectionException; use Illuminate\Http\Request; use Illuminate\Support\Facades\Http; use App\Services\RingkasanHarianServices; @@ -605,10 +606,7 @@ class LelongController extends Controller $cawangan = Cawangan::on('mysql7')->where('kodcaw','=',$request->kodcaw)->first(); if($cawangan['tagarrahnbid'] == 1){ - $lelong = Http::withOptions(['verify' => true])->get(Feature::arrahnbidUrl($request->kodcaw).'portalApi',[ - 'norujukan' => $request->norujukan - ])->json(); - $lelong = ($lelong != null) ? $lelong['lelong'] : []; + $lelong = $this->fetchPortalLelong($request->kodcaw, $request->norujukan); if( $lelong == null ) { $lelong = Lelong::on($cawangan['mysql']) @@ -651,10 +649,7 @@ class LelongController extends Controller $cawangan = Cawangan::on('mysql7')->where('kodcaw', '=', $request->kodcaw)->first(); if ($cawangan['tagarrahnbid'] == 0){ - $lelong = Http::withOptions(['verify' => true])->get(Feature::arrahnbidUrl($request->kodcaw).'portalApi',[ - 'norujukan' => $request->norujukan - ])->json(); - $lelong = ($lelong != null) ? $lelong['lelong'] : []; + $lelong = $this->fetchPortalLelong($request->kodcaw, $request->norujukan); if( $lelong == null ) { $lelong = Lelong::on($cawangan['mysql']) @@ -724,8 +719,8 @@ class LelongController extends Controller if($cawangan['tagarrahnbid'] == 1) { - $lelong = Http::withOptions(['verify' => true])->get(Feature::arrahnbidUrl($request->kodcaw).'portalApi',['norujukan' => $request->norujukan])->json(); - $lelong = ($lelong != null) ? $lelong['lelong'] : []; + $lelong = $this->fetchPortalLelong($request->kodcaw, $request->norujukan); + $lelong = ($lelong != null) ? $lelong : []; }else{ $lelong = Lelong::on($cawangan['mysql'])->where([['norujukan',$request->norujukan]])->first(); } @@ -2004,4 +1999,31 @@ class LelongController extends Controller ], 200); } + /** + * Fetch lelong status from arrahnbid. Returns null when the portal is + * unreachable so callers can fall back to the local lelong table. + */ + private function fetchPortalLelong($kodcaw, $norujukan) + { + try { + $payload = Http::withOptions(['verify' => true]) + ->timeout(5) + ->get(Feature::arrahnbidUrl($kodcaw).'portalApi', [ + 'norujukan' => $norujukan, + ]) + ->json(); + + return ($payload != null) ? ($payload['lelong'] ?? null) : null; + } catch (ConnectionException $e) { + Log::warning('Arrahnbid portal unreachable; falling back to local lelong.', [ + 'kodcaw' => $kodcaw, + 'norujukan' => $norujukan, + 'url' => Feature::arrahnbidUrl($kodcaw).'portalApi', + 'error' => $e->getMessage(), + ]); + + return null; + } + } + } -- 2.52.0