diff --git a/app/Http/Controllers/AliranTunaiController.php b/app/Http/Controllers/AliranTunaiController.php
index 06b0820a..e6d616be 100644
--- a/app/Http/Controllers/AliranTunaiController.php
+++ b/app/Http/Controllers/AliranTunaiController.php
@@ -125,10 +125,10 @@ class AliranTunaiController extends Controller
$auth_user = Auth::user();
- $gadai = Http::withOptions(['verify' => config('app.api_verify')])->get(config('api.url') . '/api/gadai/norujukan/'. $auth_user['cawangan'] .'/' .$request->norujukan_gadai)->json();
+ $gadai = Http::withOptions(['verify' => config('app.api_verify')])->get(config('api.url') . '/api/gadai/norujukan/'. $auth_user['cawangan'] .'/' .$request->norujukan_gadai)->throw()->json();
$gadai_detail = $gadai[0];
- $getTunai2=Http::withOptions(['verify' => config('app.api_verify')])->get(config('api.url').'/api/GetCurrentTunai/'.$auth_user['cawangan'],['kodlaluan' => $teller])->json();
+ $getTunai2=Http::withOptions(['verify' => config('app.api_verify')])->get(config('api.url').'/api/GetCurrentTunai/'.$auth_user['cawangan'],['kodlaluan' => $teller])->throw()->json();
$keluar = $getTunai2['keluar'];
$bakiakhir = $getTunai2['baki'];
@@ -143,7 +143,7 @@ class AliranTunaiController extends Controller
'keluar' => $keluar,
'masuk' => $masuk,
'bakiakhir' => $bakiakhir
- ]);
+ ])->throw();
return response()->json($updateTunai,201);
@@ -153,13 +153,13 @@ class AliranTunaiController extends Controller
$auth_user = Auth::user();
- $gadai = Http::withOptions(['verify' => config('app.api_verify')])->get(config('api.url') . '/api/gadai/norujukan/'. $auth_user['cawangan'] .'/' .$request->norujukan)->json();
+ $gadai = Http::withOptions(['verify' => config('app.api_verify')])->get(config('api.url') . '/api/gadai/norujukan/'. $auth_user['cawangan'] .'/' .$request->norujukan)->throw()->json();
$gadai_detail = $gadai[0];
- $tebus = Http::withOptions(['verify' => config('app.api_verify')])->get(config('api.url') . '/api/listpenebusanhistory/'. $auth_user['cawangan'],['norujukan' => $request->norujukan])->json();
+ $tebus = Http::withOptions(['verify' => config('app.api_verify')])->get(config('api.url') . '/api/listpenebusanhistory/'. $auth_user['cawangan'],['norujukan' => $request->norujukan])->throw()->json();
$tebus_detail = $tebus[0];
- $getTunai2=Http::withOptions(['verify' => config('app.api_verify')])->get(config('api.url').'/api/GetCurrentTunai/'.$auth_user['cawangan'],['kodlaluan' => $tebus_detail['teller']])->json();
+ $getTunai2=Http::withOptions(['verify' => config('app.api_verify')])->get(config('api.url').'/api/GetCurrentTunai/'.$auth_user['cawangan'],['kodlaluan' => $tebus_detail['teller']])->throw()->json();
$keluar=$getTunai2['keluar'];
$baki=$getTunai2['baki'];
@@ -181,7 +181,7 @@ class AliranTunaiController extends Controller
'keluar'=>$keluar,
'masuk'=>$masuk,
'bakiakhir'=>$bakiakhir
- ]);
+ ])->throw();
}else{
@@ -199,7 +199,7 @@ class AliranTunaiController extends Controller
'keluar'=>$keluar,
'masuk'=>$masuk,
'bakiakhir'=>$bakiakhir
- ]);
+ ])->throw();
}
}
@@ -208,13 +208,13 @@ class AliranTunaiController extends Controller
$auth_user = Auth::user();
- $gadai = Http::withOptions(['verify' => config('app.api_verify')])->get(config('api.url') . '/api/gadai/norujukan/'. $auth_user['cawangan'] .'/' .$request->norujukan)->json();
+ $gadai = Http::withOptions(['verify' => config('app.api_verify')])->get(config('api.url') . '/api/gadai/norujukan/'. $auth_user['cawangan'] .'/' .$request->norujukan)->throw()->json();
$gadai_detail = $gadai[0];
- $tebus = Http::withOptions(['verify' => config('app.api_verify')])->get(config('api.url') . '/api/listpenebusanhistory/'. $auth_user['cawangan'],['norujukan' => $request->norujukan])->json();
+ $tebus = Http::withOptions(['verify' => config('app.api_verify')])->get(config('api.url') . '/api/listpenebusanhistory/'. $auth_user['cawangan'],['norujukan' => $request->norujukan])->throw()->json();
$tebus_detail = $tebus[0];
- $getTunai2=Http::withOptions(['verify' => config('app.api_verify')])->get(config('api.url').'/api/GetCurrentTunai/'.$auth_user['cawangan'],['kodlaluan' => $tebus_detail['teller']])->json();
+ $getTunai2=Http::withOptions(['verify' => config('app.api_verify')])->get(config('api.url').'/api/GetCurrentTunai/'.$auth_user['cawangan'],['kodlaluan' => $tebus_detail['teller']])->throw()->json();
$keluar=$getTunai2['keluar'];
$baki=$getTunai2['baki'];
@@ -228,7 +228,7 @@ class AliranTunaiController extends Controller
'keluar'=>$keluar,
'masuk'=>$masuk,
'bakiakhir'=>$bakiakhir
- ]);
+ ])->throw();
}
public function alirantunaiUpahBknTawarruq(Request $request){
diff --git a/app/Http/Controllers/GadaianController.php b/app/Http/Controllers/GadaianController.php
index 128855f2..3b92ff49 100644
--- a/app/Http/Controllers/GadaianController.php
+++ b/app/Http/Controllers/GadaianController.php
@@ -285,6 +285,11 @@ class GadaianController extends Controller
public function store(Request $request)
{
$auth_user = Auth::user();
+ $shoraka = app(\App\Services\ShorakaFinancingService::class);
+ if ($shoraka->local($request->norujukan_gadai)) {
+ return $shoraka->pendingResponse($request, $request->norujukan_gadai);
+ }
+ $shoraka->ensureReady();
$caraTerima = strtoupper((string) $request->input('cara_terima', 'TUNAI'));
$pinjamanAmt = round((float) $request->pinjaman, 2);
@@ -342,16 +347,20 @@ class GadaianController extends Controller
'nokp' => $request->nokp,
'kadar_rebate' => $this->parseMoney($request->kadar_rebate),
'rebate' => $this->parseMoney($request->rebate),
- ])->json();
+ ])->throw()->json();
- $komuditi = Http::withOptions(['verify' => config('app.api_verify')])->put(config('api.url') . '/api/komuditi/transaksi', [
- 'unit_komuditi' => round($request->pinjaman, 2),
- 'norujukan' => $request->norujukan_gadai,
- 'kodcaw' => $auth_user['cawangan'],
- 'teller' => $auth_user['name']
+ return $shoraka->hold($request, $request->norujukan_gadai, 'gadai', [
+ 'cara_terima' => $caraTerima,
+ 'pinjaman' => $pinjamanAmt,
]);
+ }
+ public function completeShorakaFinancing(Request $request)
+ {
+ $auth_user = Auth::user();
+ $caraTerima = $request->cara_terima;
+ $pinjamanAmt = round((float) $request->pinjaman, 2);
if ($caraTerima === 'ONLINE') {
$online = Http::withOptions(['verify' => config('app.api_verify')])
->asForm()
@@ -374,7 +383,7 @@ class GadaianController extends Controller
$msg = is_array($body) && isset($body['message'])
? $body['message']
: 'Gagal daftar pembiayaan online. Sila cuba lagi.';
- return redirect()->back()->with('error', $msg);
+ throw new \RuntimeException($msg);
}
$this->notifyPcPembiayaanOnlinePending($auth_user, $request, $pinjamanAmt);
@@ -594,6 +603,7 @@ class GadaianController extends Controller
public function cetakSAG(Request $request)
{
+ app(\App\Services\ShorakaFinancingService::class)->printData($request->norujukan_modal);
$auth_user = Auth::user();
$gadai = Http::withOptions(['verify' => config('app.api_verify')])->put(config('api.url') . '/api/gadai/norujukan/cetak/' . $auth_user['cawangan'] . '/' . $request->norujukan_modal);
@@ -614,6 +624,7 @@ class GadaianController extends Controller
}
foreach ($arraynorujukan as $index => $norujukan) {
+ app(\App\Services\ShorakaFinancingService::class)->printData($norujukan);
$gadai = Http::withOptions(['verify' => config('app.api_verify')])->put(config('api.url') . '/api/gadai/norujukan/serah/' . $auth_user['cawangan'] . '/' . $norujukan);
if ($gadai->failed()) {
@@ -671,6 +682,12 @@ class GadaianController extends Controller
// $pembayaran_segera = "https://spare.arrahn.com.my/pembayaransegera";
$pembayaran_segera = "https://pay.arrahn.com.my";
+ $shorakaPrint = app(\App\Services\ShorakaFinancingService::class)->printData($gadai_detail['norujukan']);
+ if ($shorakaPrint) {
+ $komoditi = $shorakaPrint['komoditi'];
+ $product = $shorakaPrint['product'];
+ $kuantiti = $shorakaPrint['kuantiti'];
+ } else {
$komoditi = Http::withOptions(['verify' => config('app.api_verify')])
->get($api_url . '/api/komuditi/check')
->json();
@@ -678,6 +695,7 @@ class GadaianController extends Controller
->get($api_url . '/api/komuditi/description', ['kodproduk' => $komoditi['kodproduct']])
->json();
$kuantiti = $gadai_detail['pinjaman'] / $komoditi['nilai'];
+ }
if ($gadai_detail['tagbaru'] == 1) {
$cawangan_info = Http::withOptions(['verify' => config('app.api_verify')])
diff --git a/app/Http/Controllers/PembiayaanOnlineController.php b/app/Http/Controllers/PembiayaanOnlineController.php
index 18ea958c..1971c53b 100644
--- a/app/Http/Controllers/PembiayaanOnlineController.php
+++ b/app/Http/Controllers/PembiayaanOnlineController.php
@@ -522,6 +522,12 @@ class PembiayaanOnlineController extends Controller
$pembayaran_segera = 'https://pay.arrahn.com.my';
+ $shorakaPrint = app(\App\Services\ShorakaFinancingService::class)->printData($gadai_detail['norujukan']);
+ if ($shorakaPrint) {
+ $komoditi = $shorakaPrint['komoditi'];
+ $product = $shorakaPrint['product'];
+ $kuantiti = $shorakaPrint['kuantiti'];
+ } else {
$komoditi = $this->api()->get($api_url . '/api/komuditi/check')->json();
$product = $this->api()
->get($api_url . '/api/komuditi/description', [
@@ -531,6 +537,7 @@ class PembiayaanOnlineController extends Controller
$nilai = is_array($komoditi) ? (float) ($komoditi['nilai'] ?? 0) : 0;
$kuantiti = $nilai > 0 ? ((float) ($gadai_detail['pinjaman'] ?? 0) / $nilai) : 0;
+ }
if (($gadai_detail['tagbaru'] ?? 0) == 1) {
$cawangan_info = $this->api()
diff --git a/app/Http/Controllers/PenebusanController.php b/app/Http/Controllers/PenebusanController.php
index 32ef7f7f..c5f5e446 100644
--- a/app/Http/Controllers/PenebusanController.php
+++ b/app/Http/Controllers/PenebusanController.php
@@ -271,6 +271,7 @@ class PenebusanController extends Controller
public function tambahpinjaman(Request $request)
{
+ app(\App\Services\ShorakaFinancingService::class)->ensureReady();
$api_url = config('api.url');
$current = Carbon::now();
$current = new Carbon();
@@ -405,33 +406,16 @@ class PenebusanController extends Controller
'upah12' => $keuntungan12bulan,
'hargajualan' => $hargajualan,
'kuantiti_marhun' => $request->kuantiti_marhun
- ])->json();
-
- $komuditi = Http::withOptions(['verify' => config('app.api_verify')])->put(config('api.url').'/api/komuditi/transaksi',[
- 'unit_komuditi' => round($request->pinjaman, 2),
- 'norujukan' => $norujukanbaru,
- 'kodcaw' => $auth_user['cawangan'],
- 'teller' => $auth_user['name']
- ]);
-
- ////////////////////////////
- ////Update History Gadaian///
- ////////////////////////////
-
- $updatehistorygadaian = Http::withOptions(['verify' => config('app.api_verify')])->put(config('api.url').'/api/gadai/updatehistory/'. $auth_user['cawangan'] .'/' . $norujukanbaru,[
- 'historygadaian' => $request->norujukan,
- 'jenistebus' => $request->jenistebus,
- ])->json();
-
-
- event(new TebusNotify('lulus',Auth::user()->cawangan));
- event(new GadaiNotify('lulus',Auth::user()->cawangan));
- $this->AliranTunaiController->alirantunaiTebus($request);
+ ])->throw()->json();
+ return app(\App\Services\ShorakaFinancingService::class)->hold(
+ $request, $norujukanbaru, 'refinance', ['update_history' => true]
+ );
}
public function tambahpinjaman_latest(Request $request)
{
+ app(\App\Services\ShorakaFinancingService::class)->ensureReady();
$api_url = config('api.url');
$current = Carbon::now();
$current = new Carbon();
@@ -475,17 +459,18 @@ class PenebusanController extends Controller
])->json();
- if($updatetebus['result'] == 'success'){
- event(new TebusNotify('lulus',Auth::user()->cawangan));
- event(new GadaiNotify('lulus',Auth::user()->cawangan));
- $this->AliranTunaiController->alirantunaiTebus($request);
+ if (($updatetebus['result'] ?? null) === 'success') {
+ abort_unless(!empty($updatetebus['norujukan_baru']), 502, 'Rujukan gadaian baharu tidak diterima.');
+ return app(\App\Services\ShorakaFinancingService::class)->hold(
+ $request, $updatetebus['norujukan_baru'], 'refinance'
+ );
}
- return response()->json($updatetebus['result'],200);
-
+ return response()->json($updatetebus['result'] ?? 'error', 200);
}
public function tebusautotawarruq(Request $request)
{
+ app(\App\Services\ShorakaFinancingService::class)->ensureReady();
$auth_user = Auth::user();
////////////////////////
@@ -515,17 +500,18 @@ class PenebusanController extends Controller
"noic" => $request->noic,
"jenisAT" => $request->jenisAT,
])->json();
- if($updatetebus['result'] == 'success'){
- $alirantunai = new AliranTunaiController();
- event(new TebusNotify('lulus',Auth::user()->cawangan));
- event(new GadaiNotify('lulus',Auth::user()->cawangan));
- $alirantunai->alirantunaiTebusAutoTawarruq($request);
+ if (($updatetebus['result'] ?? null) === 'success') {
+ abort_unless(!empty($updatetebus['norujukan_baru']), 502, 'Rujukan gadaian baharu tidak diterima.');
+ return app(\App\Services\ShorakaFinancingService::class)->hold(
+ $request, $updatetebus['norujukan_baru'], 'autotawarruq'
+ );
}
- return response()->json($updatetebus['result'],200);
+ return response()->json($updatetebus['result'] ?? 'error', 200);
}
public function tebusseparuh(Request $request)
{
+ app(\App\Services\ShorakaFinancingService::class)->ensureReady();
$api_url = config('api.url');
$current = Carbon::now();
$current = new Carbon();
@@ -666,39 +652,13 @@ class PenebusanController extends Controller
'upah12' => $keuntungan12bulan,
'hargajualan' => $hargajualan,
'kuantiti_marhun' => $request->kuantiti_marhun
- ])->json();
+ ])->throw()->json();
- $komuditi = Http::withOptions(['verify' => config('app.api_verify')])->put(config('api.url').'/api/komuditi/transaksi',[
- 'unit_komuditi' => round($request->pinjaman, 2),
- 'norujukan' => $norujukanbaru,
- 'kodcaw' => $auth_user['cawangan'],
- 'teller' => $auth_user['name']
- ]);
-
- ////////////////////////////
- ////Update History Gadaian///
- ////////////////////////////
-
- $updatehistorygadaian = Http::withOptions(['verify' => config('app.api_verify')])->put(config('api.url').'/api/gadai/updatehistory/'. $auth_user['cawangan'] .'/' . $norujukanbaru,[
- 'historygadaian' => $request->norujukan,
- 'jenistebus' => $request->jenistebus,
- ])->json();
-
-
- $alirantunai = new AliranTunaiController();
- event(new TebusNotify('lulus',Auth::user()->cawangan));
- event(new GadaiNotify('lulus',Auth::user()->cawangan));
-
- $alirantunai->alirantunaiTebus($request);
-
-
- return response()->json($updatemarhun,200);
-
+ return app(\App\Services\ShorakaFinancingService::class)->hold(
+ $request, $norujukanbaru, 'refinance', ['update_history' => true]
+ );
}
-
- //Wakil Function
-
public function getfirstWakil()
{
$auth_user = Auth::user();
diff --git a/app/Http/Controllers/ShorakaController.php b/app/Http/Controllers/ShorakaController.php
new file mode 100644
index 00000000..3c6dfb31
--- /dev/null
+++ b/app/Http/Controllers/ShorakaController.php
@@ -0,0 +1,73 @@
+cawangan)
+ ->orderByDesc('id')->limit(100)->get();
+ $cawangan_info = ['details_caw' => Auth::user()->cawangan, 'kodcaw' => Auth::user()->cawangan];
+ return view('shoraka.index', compact('records', 'cawangan_info'));
+ }
+
+ public function show(string $norujukan, ShorakaFinancingService $service)
+ {
+ $record = $service->local($norujukan);
+ $data = null;
+ $error = null;
+ try {
+ $data = $service->api()->get($service->url($norujukan))->throw()->json()['data'];
+ } catch (Throwable $exception) {
+ $error = 'Maklumat Shoraka tidak dapat diambil. Bayaran dan SAG masih ditahan.';
+ }
+ $cawangan_info = ['details_caw' => Auth::user()->cawangan, 'kodcaw' => Auth::user()->cawangan];
+ return view('shoraka.show', compact('norujukan', 'record', 'data', 'error', 'cawangan_info'));
+ }
+
+ public function submit(string $norujukan, ShorakaFinancingService $service)
+ {
+ $record = $service->local($norujukan);
+ abort_unless($record && $record->teller === Auth::user()->name, 403);
+ $response = $service->api()->post($service->url($norujukan, '/submit'));
+ return redirect()->route('shoraka.show', compact('norujukan'))
+ ->with('shoraka_message', $response->successful()
+ ? 'Order dihantar. Semak status sebelum menyelesaikan pembiayaan.'
+ : (($response->json()['message'] ?? null) ?: 'Order belum berjaya. Semak status sebelum cuba semula.'));
+ }
+
+ public function refresh(string $norujukan, ShorakaFinancingService $service)
+ {
+ try {
+ $response = $service->api()->post($service->url($norujukan, '/refresh'));
+ $message = $response->successful() ? 'Status dikemas kini.'
+ : (($response->json()['message'] ?? null) ?: 'Status tidak dapat dikemas kini.');
+ } catch (Throwable $exception) {
+ $message = 'Sambungan terganggu. Jangan hantar order semula.';
+ }
+ return redirect()->route('shoraka.show', compact('norujukan'))->with('shoraka_message', $message);
+ }
+
+ public function finish(Request $request, string $norujukan, ShorakaFinancingService $service)
+ {
+ return $service->finish($request, $norujukan);
+ }
+
+ public function certificate(string $norujukan, ShorakaFinancingService $service)
+ {
+ $response = $service->api()->get($service->url($norujukan, '/certificate'))->throw();
+ abort_unless(substr($response->body(), 0, 5) === '%PDF-', 502);
+ return response($response->body(), 200, [
+ 'Content-Type' => 'application/pdf',
+ 'Content-Disposition' => 'attachment; filename="sijil-shoraka.pdf"',
+ 'Cache-Control' => 'private, no-store',
+ ]);
+ }
+}
diff --git a/app/Services/ShorakaFinancingService.php b/app/Services/ShorakaFinancingService.php
new file mode 100644
index 00000000..ded8ecd7
--- /dev/null
+++ b/app/Services/ShorakaFinancingService.php
@@ -0,0 +1,153 @@
+cawangan)->exists();
+ $response = $this->api()->get(rtrim(config('api.url'), '/') . '/api/shoraka/readiness')->throw()->json();
+ abort_unless(!empty($response['ready']), 503, 'Shoraka belum dikonfigurasi. Pembiayaan baharu ditahan.');
+ }
+
+ public function api()
+ {
+ return Http::withOptions(['verify' => config('app.api_verify')])
+ ->acceptJson()->timeout(75);
+ }
+
+ public function url(string $reference, string $suffix = ''): string
+ {
+ return rtrim(config('api.url'), '/') . '/api/shoraka/gadai/'
+ . rawurlencode(Auth::user()->cawangan) . '/' . rawurlencode($reference) . $suffix;
+ }
+
+ public function local(string $reference)
+ {
+ return ShorakaFinancing::where('kodcaw', Auth::user()->cawangan)
+ ->where('norujukan', $reference)->first();
+ }
+
+ public function hold(Request $request, string $reference, string $action, array $extra = [])
+ {
+ $user = Auth::user();
+ $record = ShorakaFinancing::firstOrCreate(
+ ['kodcaw' => $user->cawangan, 'norujukan' => $reference],
+ [
+ 'teller' => $user->name, 'action' => $action, 'state' => 'WAITING',
+ 'context' => array_merge($request->except(['_token', 'password']), $extra),
+ ]
+ );
+ // A duplicate request only opens the saved workflow; it never replays registration.
+ if ($record->wasRecentlyCreated) {
+ try {
+ $this->api()->post($this->url($reference, '/submit'));
+ } catch (Throwable $exception) {
+ // The persisted workflow remains available after timeouts.
+ }
+ }
+ return $this->pendingResponse($request, $reference);
+ }
+
+ public function pendingResponse(Request $request, string $reference)
+ {
+ $url = route('shoraka.show', ['norujukan' => $reference]);
+ if ($request->ajax() || $request->expectsJson()) {
+ return response()->json(['shoraka_pending' => true, 'redirect' => $url], 202);
+ }
+ return redirect($url);
+ }
+
+ public function finish(Request $request, string $reference)
+ {
+ $record = $this->local($reference);
+ abort_unless($record && $record->teller === Auth::user()->name, 403,
+ 'Pembiayaan perlu diselesaikan oleh teller asal.');
+ if ($record->state === 'DONE') {
+ return redirect()->route('shoraka.show', ['norujukan' => $reference]);
+ }
+ abort_unless($record->state === 'WAITING', 409,
+ 'Penyelesaian telah diproses atau memerlukan semakan operasi. Jangan ulang bayaran.');
+
+ $this->api()->post($this->url($reference, '/refresh'))->throw();
+ $snapshot = $this->api()->get($this->url($reference))->throw()->json()['data'];
+ abort_unless(!empty($snapshot['can_complete']), 409,
+ 'Bayaran ditahan sehingga Shoraka Completed dan amaun sepadan.');
+
+ abort_unless(
+ number_format((float) ($record->context['pinjaman'] ?? 0), 2, '.', '')
+ === number_format((float) ($snapshot['order_amount'] ?? 0), 2, '.', ''),
+ 409, 'Amaun pembiayaan berubah. Semakan operasi diperlukan sebelum bayaran.'
+ );
+
+ $claimed = ShorakaFinancing::where('id', $record->id)->where('state', 'WAITING')
+ ->update(['state' => 'PROCESSING', 'updated_at' => now()]);
+ abort_unless($claimed === 1, 409, 'Penyelesaian sedang diproses.');
+
+ $saved = new Request($record->context);
+ $saved->setLaravelSession($request->session());
+ try {
+ if ($record->action === 'gadai') {
+ $result = app(GadaianController::class)->completeShorakaFinancing($saved);
+ } else {
+ if (!empty($record->context['update_history'])) {
+ $this->api()->put(rtrim(config('api.url'), '/') . '/api/gadai/updatehistory/'
+ . rawurlencode($record->kodcaw) . '/' . rawurlencode($reference), [
+ 'historygadaian' => $saved->norujukan,
+ 'jenistebus' => $saved->jenistebus,
+ ])->throw();
+ }
+ $cash = app(AliranTunaiController::class);
+ if ($record->action === 'autotawarruq') {
+ $cash->alirantunaiTebusAutoTawarruq($saved);
+ } else {
+ $cash->alirantunaiTebus($saved);
+ }
+ event(new \App\Events\Dashboard\TebusNotify('lulus', $record->kodcaw));
+ event(new GadaiNotify('lulus', $record->kodcaw));
+ $result = redirect()->route('shoraka.show', ['norujukan' => $reference]);
+ }
+ $record->update(['state' => 'DONE', 'context' => []]);
+ return $result;
+ } catch (Throwable $exception) {
+ // A failed remote payment response can be ambiguous. Never retry automatically.
+ $record->update(['state' => 'REVIEW']);
+ throw $exception;
+ }
+ }
+
+ public function printData(string $reference): ?array
+ {
+ $response = $this->api()->get($this->url($reference))->throw()->json()['data'];
+ $order = $response['order'] ?? null;
+ if (!$order) {
+ abort_if($this->local($reference), 409, 'SAG ditahan: transaksi Shoraka belum tersedia.');
+ return null; // Historical financing keeps its historical print path.
+ }
+ abort_unless(!empty($response['can_complete']), 409, 'SAG ditahan: Shoraka belum Completed.');
+ $details = $response['details'] ?? [];
+ $certificate = explode('|', $details['certificateDetails1'] ?? '')[0];
+ abort_unless($certificate !== '' && isset($details['unit'], $details['volume'], $details['commodityType']),
+ 409, 'Maklumat sijil belum lengkap. Semak status Shoraka dahulu.');
+ return [
+ 'komoditi' => ['no_sijil' => $certificate],
+ 'product' => [
+ 'kodproduk' => $details['commodityType'],
+ 'description' => $details['commodityType'] === '000-COPPER' ? 'Copper' : 'Plastic resin',
+ 'unit' => $details['unit'],
+ ],
+ 'kuantiti' => $details['volume'],
+ ];
+ }
+}
diff --git a/app/ShorakaFinancing.php b/app/ShorakaFinancing.php
new file mode 100644
index 00000000..3e1e8564
--- /dev/null
+++ b/app/ShorakaFinancing.php
@@ -0,0 +1,11 @@
+ 'array'];
+}
diff --git a/database/migrations/2026_10_05_120000_create_shoraka_financings_table.php b/database/migrations/2026_10_05_120000_create_shoraka_financings_table.php
new file mode 100644
index 00000000..1e4090bd
--- /dev/null
+++ b/database/migrations/2026_10_05_120000_create_shoraka_financings_table.php
@@ -0,0 +1,28 @@
+bigIncrements('id');
+ $table->string('kodcaw', 20);
+ $table->string('norujukan');
+ $table->string('teller');
+ $table->string('action', 30);
+ $table->string('state', 30)->default('WAITING');
+ $table->json('context');
+ $table->timestamps();
+ $table->unique(['kodcaw', 'norujukan']);
+ });
+ }
+
+ public function down()
+ {
+ Schema::dropIfExists('shoraka_financings');
+ }
+}
diff --git a/resources/views/callcenter/v2/index.blade.php b/resources/views/callcenter/v2/index.blade.php
index e0dab1a0..bd13e2bf 100644
--- a/resources/views/callcenter/v2/index.blade.php
+++ b/resources/views/callcenter/v2/index.blade.php
@@ -2814,25 +2814,25 @@
$.ajax({
method:'get',
- url: api + '/api/komuditi/check',
+ url: api + '/api/shoraka/readiness',
success:function(komoditi){
var check_komuditi = Object.keys(komoditi).length;
- if(check_komuditi == 0){
+ if (!komoditi.ready){
$("#terima_transaksi").prop('disabled', false);
Swal.fire({
icon: 'error',
- title: 'Unit Komuditi Berbaki Minumum',
- text: 'Sila Hubungi Operasi Untuk Membuat Pembelian Komuditi'
+ title: 'Shoraka Belum Tersedia',
+ text: 'Sila hubungi operasi untuk semakan sambungan Shoraka.'
});
event.preventDefault();
return false;
}else{
- if(Number(komoditi['unit_komuditi']) < pinjaman_baru){
+ if (!komoditi.ready){
$("#terima_transaksi").prop('disabled', false);
Swal.fire({
icon: 'error',
- title: 'Baki Unit Komuditi Tidak Mencukupi',
- text: 'Sila Hubungi Operasi Untuk Membuat Pembelian Komuditi'
+ title: 'Shoraka Belum Tersedia',
+ text: 'Sila hubungi operasi untuk semakan sambungan Shoraka.'
});
event.preventDefault();
return false;
diff --git a/resources/views/customers/v1/info.blade.php b/resources/views/customers/v1/info.blade.php
index 7a70644c..f1e2ddf1 100644
--- a/resources/views/customers/v1/info.blade.php
+++ b/resources/views/customers/v1/info.blade.php
@@ -461,25 +461,25 @@
}else{
$.ajax({
method:'get',
- url: api_url + '/api/komuditi/check',
+ url: api_url + '/api/shoraka/readiness',
success:function(data){
var check_komuditi = Object.keys(data).length;
- if(check_komuditi == 0){
+ if (!data.ready){
Swal.fire({
icon: 'error',
- title: 'Unit Komoditi Berbaki Minima',
- text: 'Sila Hubungi Operasi Untuk Membuat Pembelian Komoditi'
+ title: 'Shoraka Belum Tersedia',
+ text: 'Sila hubungi operasi untuk semakan sambungan Shoraka.'
});
$("#daftar_gadai").prop('disabled', false);
event.preventDefault();
return false;
}else{
- if(Number(data['unit_komuditi']) <= min_komoditi){
+ if (!data.ready){
$("#daftar_gadai").prop('disabled', false);
Swal.fire({
icon: 'error',
- title: 'Unit Komoditi Berbaki Minima',
- text: 'Sila Hubungi Operasi Untuk Membuat Pembelian Komoditi'
+ title: 'Shoraka Belum Tersedia',
+ text: 'Sila hubungi operasi untuk semakan sambungan Shoraka.'
});
event.preventDefault();
return false;
diff --git a/resources/views/customers/v2/info.blade.php b/resources/views/customers/v2/info.blade.php
index 9ab201a7..4d1cb40d 100644
--- a/resources/views/customers/v2/info.blade.php
+++ b/resources/views/customers/v2/info.blade.php
@@ -758,25 +758,25 @@
} else {
$.ajax({
method: 'get',
- url: api_url + '/api/komuditi/check',
+ url: api_url + '/api/shoraka/readiness',
success: function(data) {
var check_komuditi = Object.keys(data).length;
- if (check_komuditi == 0) {
+ if (!data.ready) {
Swal.fire({
icon: 'error',
- title: 'Unit Komoditi Berbaki Minima',
- text: 'Sila Hubungi Operasi Untuk Membuat Pembelian Komoditi'
+ title: 'Shoraka Belum Tersedia',
+ text: 'Sila hubungi operasi untuk semakan sambungan Shoraka.'
});
$("#daftar_gadai").prop('disabled', false);
event.preventDefault();
return false;
} else {
- if (Number(data['unit_komuditi']) <= min_komoditi) {
+ if (!data.ready) {
$("#daftar_gadai").prop('disabled', false);
Swal.fire({
icon: 'error',
- title: 'Unit Komoditi Berbaki Minima',
- text: 'Sila Hubungi Operasi Untuk Membuat Pembelian Komoditi'
+ title: 'Shoraka Belum Tersedia',
+ text: 'Sila hubungi operasi untuk semakan sambungan Shoraka.'
});
event.preventDefault();
return false;
diff --git a/resources/views/gadaian/v1/index.blade.php b/resources/views/gadaian/v1/index.blade.php
index a4be210d..7aa435ed 100644
--- a/resources/views/gadaian/v1/index.blade.php
+++ b/resources/views/gadaian/v1/index.blade.php
@@ -819,25 +819,25 @@
}else{
$.ajax({
method:'get',
- url: api_url + '/api/komuditi/check',
+ url: api_url + '/api/shoraka/readiness',
success:function(data){
var check_komuditi = Object.keys(data).length;
- if(check_komuditi == 0){
+ if (!data.ready){
$("#terima_gadai").prop('disabled', false);
Swal.fire({
icon: 'error',
- title: 'Unit Komuditi Berbaki Minumum',
- text: 'Sila Hubungi Operasi Untuk Membuat Pembelian Komuditi'
+ title: 'Shoraka Belum Tersedia',
+ text: 'Sila hubungi operasi untuk semakan sambungan Shoraka.'
});
event.preventDefault();
return false;
}else{
- if(Number(data['unit_komuditi']) < pinjaman){
+ if (!data.ready){
$("#terima_gadai").prop('disabled', false);
Swal.fire({
icon: 'error',
- title: 'Baki Unit Komuditi Tidak Mencukupi',
- text: 'Sila Hubungi Operasi Untuk Membuat Pembelian Komuditi'
+ title: 'Shoraka Belum Tersedia',
+ text: 'Sila hubungi operasi untuk semakan sambungan Shoraka.'
});
event.preventDefault();
return false;
diff --git a/resources/views/gadaian/v2/index.blade.php b/resources/views/gadaian/v2/index.blade.php
index 57a5ae45..b01646e6 100644
--- a/resources/views/gadaian/v2/index.blade.php
+++ b/resources/views/gadaian/v2/index.blade.php
@@ -1655,25 +1655,25 @@
}else{
$.ajax({
method:'get',
- url: api_url + '/api/komuditi/check',
+ url: api_url + '/api/shoraka/readiness',
success:function(data){
var check_komuditi = Object.keys(data).length;
- if(check_komuditi == 0){
+ if (!data.ready){
$("#terima_gadai").prop('disabled', false);
Swal.fire({
icon: 'error',
- title: 'Unit Komuditi Berbaki Minumum',
- text: 'Sila Hubungi Operasi Untuk Membuat Pembelian Komuditi'
+ title: 'Shoraka Belum Tersedia',
+ text: 'Sila hubungi operasi untuk semakan sambungan Shoraka.'
});
event.preventDefault();
return false;
}else{
- if(Number(data['unit_komuditi']) < pinjaman){
+ if (!data.ready){
$("#terima_gadai").prop('disabled', false);
Swal.fire({
icon: 'error',
- title: 'Baki Unit Komuditi Tidak Mencukupi',
- text: 'Sila Hubungi Operasi Untuk Membuat Pembelian Komuditi'
+ title: 'Shoraka Belum Tersedia',
+ text: 'Sila hubungi operasi untuk semakan sambungan Shoraka.'
});
event.preventDefault();
return false;
diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php
index d7d138b2..948c78c3 100644
--- a/resources/views/layouts/app.blade.php
+++ b/resources/views/layouts/app.blade.php
@@ -405,6 +405,7 @@
@endif
| No. rujukan | Teller | Penyelesaian pembiayaan | |
|---|---|---|---|
| {{ $record->norujukan }} | {{ $record->teller }} | +{{ ['WAITING' => 'Menunggu Shoraka / penyelesaian', 'PROCESSING' => 'Sedang diproses', 'REVIEW' => 'Perlu semakan operasi', 'DONE' => 'Selesai'][$record->state] ?? $record->state }} | +Buka | +
| Tiada transaksi. | |||
Jangan hantar order sekali lagi. Hubungi operasi untuk semakan dengan Shoraka.
+ @endif + @if($record && in_array($record->state, ['REVIEW', 'PROCESSING'])) +