From e3e7694b54160177291dc3b7be8a16be553a9d20 Mon Sep 17 00:00:00 2001 From: ISMAIL MASSERAN Date: Mon, 26 Oct 2026 12:49:57 +0800 Subject: [PATCH] DONE: remove cache, and remove dto financing --- app/Http/Controllers/GadaiController.php | 47 +--- app/Http/Controllers/MarhunController.php | 42 +-- app/Http/Controllers/ShorakaController.php | 9 +- .../ShorakaFinancingController.php | 168 ++++++++++++ .../Controllers/ShorakaGadaiController.php | 16 +- app/Services/ShorakaGadaiService.php | 3 +- app/Services/ShorakaNewGadaiService.php | 259 ------------------ app/ShorakaFinancing.php | 16 ++ app/Support/v1/GadaiV1.php | 13 +- app/Support/v1/Penebusan.php | 3 +- app/Support/v2/GadaiV2.php | 13 +- app/Support/v2/Penebusan.php | 3 +- routes/web.php | 4 + 13 files changed, 216 insertions(+), 380 deletions(-) create mode 100644 app/Http/Controllers/ShorakaFinancingController.php delete mode 100644 app/Services/ShorakaNewGadaiService.php create mode 100644 app/ShorakaFinancing.php diff --git a/app/Http/Controllers/GadaiController.php b/app/Http/Controllers/GadaiController.php index 9d795c6..1894cdd 100644 --- a/app/Http/Controllers/GadaiController.php +++ b/app/Http/Controllers/GadaiController.php @@ -55,10 +55,6 @@ class GadaiController extends Controller $cawangan = Cawangan::on('mysql7')->where('kodcaw','=',$cawangan_code)->first(); $gadaiTransaction = Gadai::on($cawangan['mysql'])->where('t_gadai','=',$date)->orderBy('sirig', 'desc')->first(); - $serial = app(\App\Services\ShorakaNewGadaiService::class)->latestSerial($cawangan_code, $date); - if ($serial > (int) ($gadaiTransaction->sirig ?? 0)) { - $gadaiTransaction = ['sirig' => $serial]; - } }catch(\Exception $e){ Log::debug($e); Log::debug($cawangan_code); @@ -115,7 +111,7 @@ class GadaiController extends Controller $gadai_all = []; foreach($cawangan_all as $index=>$cawangan){ - $gadai = collect(array_filter([app(\App\Services\ShorakaNewGadaiService::class)->find($cawangan->kodcaw, $norujukan)])); + $gadai = Gadai::on($cawangan['mysql'])->where('norujukan','=',$norujukan)->get(); if(sizeof($gadai) != 0){ array_push($gadai_all,$gadai); } @@ -134,7 +130,7 @@ class GadaiController extends Controller $gadai_all = []; foreach($cawangan_all as $index=>$cawangan){ - $gadai = collect(array_filter([app(\App\Services\ShorakaNewGadaiService::class)->find($cawangan->kodcaw, $norujukan)])); + $gadai = Gadai::on($cawangan['mysql'])->where('norujukan','=',$norujukan)->get(); if(sizeof($gadai) != 0){ array_push($gadai_all,$gadai); } @@ -156,22 +152,12 @@ class GadaiController extends Controller public function showOneGadaibyRujukanAndCawangan($kodcaw,$norujukan){ $cawangan = Cawangan::on('mysql7')->where('kodcaw','=',$kodcaw)->first(); - $gadai = collect(array_filter([app(\App\Services\ShorakaNewGadaiService::class)->find($cawangan->kodcaw, $norujukan)])); + $gadai = Gadai::on($cawangan['mysql'])->where('norujukan','=',$norujukan)->get(); return response()->json($gadai); } public function create($kodcaw,Request $request){ - if ($request->boolean('shoraka_new')) { - $this->validate($request, ['nokp' => 'required|string', 'nopelanggan' => 'required']); - return response()->json(app(\App\Services\ShorakaNewGadaiService::class)->reserve( - $kodcaw, $request->only(['nokp', 'nopelanggan']) - ), 201); - } - - if (app(\App\Services\ShorakaNewGadaiService::class)->pending($kodcaw, (string) $request->norujukan)) { - abort(409, 'Nombor rujukan sedang digunakan. Sila dapatkan nombor baharu.'); - } $master = new MasterServices($kodcaw); $response = $master->createGadai($request); @@ -246,10 +232,6 @@ class GadaiController extends Controller if (\App\ShorakaTransaction::where('norujukan', $norujukan)->exists()) { abort(409, 'Kontrak telah dihantar ke Shoraka dan tidak boleh diubah.'); } - $temporary = app(\App\Services\ShorakaNewGadaiService::class)->pending($kodcaw, $norujukan); - if ($temporary && (string) $temporary['gadai']['nokp'] !== (string) $request->nokp) { - abort(409, 'Pelanggan tidak sepadan dengan borang gadaian sementara.'); - } $request->merge(['kodcaw' => $kodcaw, 'norujukan' => $norujukan]); $master = new MasterServices($kodcaw); $response = $master->createMarhunGadai($norujukan, $request); @@ -266,13 +248,7 @@ class GadaiController extends Controller public function checkNorujukan(Request $request){ $cawangan = Cawangan::on('mysql7')->where('kodcaw','=',$request->kodcaw)->first(); - $gadai = app(\App\Services\ShorakaNewGadaiService::class)->find($request->kodcaw, $request->norujukan); - if (!$gadai && \App\ShorakaTransaction::where('norujukan', $request->norujukan)->exists()) { - abort(409, 'Transaksi Shoraka wujud tetapi maklumat sementara tiada. Hubungi operasi; jangan daftar semula.'); - } - if ($gadai && $gadai->nokp !== $request->nokp) { - $gadai = null; - } + $gadai = Gadai::on($cawangan['mysql'])->where([['norujukan','=',$request->norujukan],['nokp','=',$request->nokp]])->first(); return response()->json($gadai); } @@ -395,16 +371,9 @@ class GadaiController extends Controller } public function batalGadai($kodcaw, $norujukan,Request $request){ - $temporary = app(\App\Services\ShorakaNewGadaiService::class); - $order = \App\ShorakaTransaction::where('norujukan', $norujukan)->first(); - if ($order && !empty($order->request_payload['_new_gadai'])) { + if (\App\ShorakaTransaction::where('norujukan', $norujukan)->exists()) { abort(409, 'Transaksi Shoraka telah dihantar. Semakan operasi diperlukan sebelum pembatalan.'); } - if ($temporary->pending($kodcaw, $norujukan)) { - $temporary->abandon($kodcaw, $norujukan); - return response('Batal Berjaya', 200); - } - $current = Carbon::now(); $current = new Carbon(); @@ -459,8 +428,7 @@ class GadaiController extends Controller } public function cetakSAG($kodcaw,$norujukan,Request $request){ - if (\App\ShorakaTransaction::where('norujukan', $norujukan)->exists() - || app(\App\Services\ShorakaNewGadaiService::class)->pending($kodcaw, $norujukan)) { + if (\App\ShorakaTransaction::where('norujukan', $norujukan)->exists()) { app(\App\Services\ShorakaGadaiService::class)->assertCompleted($kodcaw, $norujukan); } @@ -488,8 +456,7 @@ class GadaiController extends Controller } public function serahMarhun($kodcaw,$norujukan){ - if (\App\ShorakaTransaction::where('norujukan', $norujukan)->exists() - || app(\App\Services\ShorakaNewGadaiService::class)->pending($kodcaw, $norujukan)) { + if (\App\ShorakaTransaction::where('norujukan', $norujukan)->exists()) { app(\App\Services\ShorakaGadaiService::class)->assertCompleted($kodcaw, $norujukan); } diff --git a/app/Http/Controllers/MarhunController.php b/app/Http/Controllers/MarhunController.php index 2df9169..38b94db 100644 --- a/app/Http/Controllers/MarhunController.php +++ b/app/Http/Controllers/MarhunController.php @@ -26,9 +26,6 @@ class MarhunController extends Controller $marhun_all = []; foreach($cawangan_all as $index=>$cawangan){ $marhun = Marhun::on($cawangan['mysql'])->where('norujukan','=',$norujukan)->get(); - if ($marhun->isEmpty()) { - $marhun = app(\App\Services\ShorakaNewGadaiService::class)->items($cawangan->kodcaw, $norujukan); - } if(sizeof($marhun) != 0){ array_push($marhun_all,$marhun); } @@ -43,9 +40,6 @@ class MarhunController extends Controller $marhun = Marhun::on($cawangan['mysql'])->where('norujukan',$request->norujukan)->distinct()->pluck('karat')->toArray(); - if (app(\App\Services\ShorakaNewGadaiService::class)->pending($request->kodcaw, $request->norujukan)) { - $marhun = app(\App\Services\ShorakaNewGadaiService::class)->items($request->kodcaw, $request->norujukan)->pluck('karat')->unique()->all(); - } $mutu = HargaEmas::on('mysql7')->whereIn('karat',$marhun)->pluck('keterangan')->toArray(); return response()->json($mutu); @@ -66,7 +60,7 @@ class MarhunController extends Controller public function create($kodcaw,Request $request) { $order = \App\ShorakaTransaction::where('norujukan', $request->norujukan)->first(); - if ($order && !empty($order->request_payload['_new_gadai'])) { + if ($order) { abort(409, 'Kontrak Shoraka telah dihantar dan tidak boleh diubah.'); } @@ -107,10 +101,6 @@ class MarhunController extends Controller }; $cawangan = Cawangan::on('mysql7')->where('kodcaw','=',$kodcaw)->first(); - $temporary = app(\App\Services\ShorakaNewGadaiService::class); - if ($temporary->pending($kodcaw, $request->norujukan)) { - return response()->json($temporary->changeItem($kodcaw, $request->norujukan, $marhunToCreate), 201); - } $marhun = Marhun::on($cawangan['mysql'])->create($marhunToCreate); $audit = new Audit(); @@ -143,17 +133,10 @@ class MarhunController extends Controller public function deletemarhun($kodcaw,$norujukan,Request $request) { $order = \App\ShorakaTransaction::where('norujukan', $norujukan)->first(); - if ($order && !empty($order->request_payload['_new_gadai'])) { + if ($order) { abort(409, 'Kontrak Shoraka telah dihantar dan tidak boleh diubah.'); } - $temporary = app(\App\Services\ShorakaNewGadaiService::class); - if ($temporary->pending($kodcaw, $norujukan)) { - $temporary->changeItem($kodcaw, $norujukan, [], $request->recno, true); - return response('Deleted Successfully', 200); - } - - $current = Carbon::now(); $current = new Carbon(); @@ -179,7 +162,7 @@ class MarhunController extends Controller public function editmarhun($kodcaw,$norujukan,Request $request) { $order = \App\ShorakaTransaction::where('norujukan', $norujukan)->first(); - if ($order && !empty($order->request_payload['_new_gadai'])) { + if ($order) { abort(409, 'Kontrak Shoraka telah dihantar dan tidak boleh diubah.'); } @@ -190,17 +173,6 @@ class MarhunController extends Controller $harga = HargaEmas::on('mysql7')->where('karat',$request->karat)->first(); $nilai_marhun = $request->berat * $harga['harga']; - $temporary = app(\App\Services\ShorakaNewGadaiService::class); - if ($temporary->pending($kodcaw, $norujukan)) { - $temporary->changeItem($kodcaw, $norujukan, [ - 'karat' => $request->karat, 'marhun' => $request->marhun, 'nota' => $request->nota, - 'tag_permata' => $request->tag_permata, - 'berat_batu_permata' => $request->berat_batu_permata ?: null, - 'berat' => $request->berat, 'harga' => $harga['harga'], 'n_marhun' => $nilai_marhun, - 'bil' => $request->kuantiti, - ], $request->recno); - return response()->json(true); - } $cawangan = Cawangan::on('mysql7')->where('kodcaw','=',$kodcaw)->first(); // Lock the parent first so concurrent edits to this SAG are serialized. @@ -299,9 +271,6 @@ class MarhunController extends Controller $marhuns = Marhun::on($cawangan['mysql'])->where('norujukan',$request->norujukan)->get(); - if ($marhuns->isEmpty()) { - $marhuns = app(\App\Services\ShorakaNewGadaiService::class)->items($request->kodcaw, $request->norujukan); - } $totalnilaimarhun = 0; foreach($marhuns as $index=>$marhun){ @@ -315,11 +284,6 @@ class MarhunController extends Controller public function getMarhunCaw($kodcaw,$norujukan) { - $temporary = app(\App\Services\ShorakaNewGadaiService::class); - if ($temporary->pending($kodcaw, $norujukan)) { - return response()->json($temporary->items($kodcaw, $norujukan)->sum('n_marhun')); - } - $cawangan = Cawangan::on('mysql7')->where('kodcaw','=',$kodcaw)->first(); $data = Marhun::on($cawangan['mysql']) ->where('norujukan','=', $norujukan) diff --git a/app/Http/Controllers/ShorakaController.php b/app/Http/Controllers/ShorakaController.php index 4f19c01..4f5e6e0 100644 --- a/app/Http/Controllers/ShorakaController.php +++ b/app/Http/Controllers/ShorakaController.php @@ -58,15 +58,10 @@ class ShorakaController extends Controller 'ownership_doc_no' => $payload['ownership_doc_no'], 'order_amount' => $payload['order_amount'], 'murabaha_amount' => $payload['murabaha_amount'], - 'request_payload' => $request->attributes->get('shoraka_new') - ? array_merge($payload, ['_new_gadai' => true]) : $payload, + 'request_payload' => $payload, 'attempt_count' => 1, ]; - $create = function () use ($attributes) { return ShorakaTransaction::create($attributes); }; - $transaction = $request->attributes->get('shoraka_new') - ? app(\App\Services\ShorakaNewGadaiService::class)->claim( - $request->attributes->get('shoraka_kodcaw'), $validated['norujukan'], $payload, $create - ) : $create(); + $transaction = ShorakaTransaction::create($attributes); } catch (QueryException $exception) { $existing = ShorakaTransaction::where('norujukan', $validated['norujukan'])->first(); if ($existing) { diff --git a/app/Http/Controllers/ShorakaFinancingController.php b/app/Http/Controllers/ShorakaFinancingController.php new file mode 100644 index 0000000..32b63c7 --- /dev/null +++ b/app/Http/Controllers/ShorakaFinancingController.php @@ -0,0 +1,168 @@ +validate($request, [ + 'kodcaw' => 'nullable|string|max:30', + 'norujukan' => 'nullable|string|max:100', + 'state' => 'nullable|in:WAITING,PROCESSING,REVIEW,DONE', + 'date_from' => 'nullable|date_format:Y-m-d', + 'date_to' => 'nullable|date_format:Y-m-d', + 'per_page' => 'nullable|integer|min:1|max:100', + 'page' => 'nullable|integer|min:1', + 'branch_scope' => 'nullable|string|max:30', + ]); + + try { + $query = ShorakaFinancing::query(); + foreach (['kodcaw', 'norujukan', 'state'] as $field) { + if ($request->filled($field)) { + $query->where($field, $request->input($field)); + } + } + if ($request->filled('date_from')) { + $query->where('created_at', '>=', $request->input('date_from') . ' 00:00:00'); + } + if ($request->filled('date_to')) { + $query->where('created_at', '<', Carbon::parse($request->input('date_to'))->addDay()->format('Y-m-d') . ' 00:00:00'); + } + $records = $query->orderByDesc('created_at')->orderByDesc('id') + ->paginate(min(100, max(1, (int) $request->input('per_page', 25)))); + $payload = [ + 'data' => $records->getCollection()->map(function (ShorakaFinancing $record) { + return $this->present($record, false); + })->values(), + 'total' => $records->total(), + 'current_page' => $records->currentPage(), + 'per_page' => $records->perPage(), + 'last_page' => $records->lastPage(), + ]; + if ($request->input('with_branches')) { + $branches = ShorakaFinancing::query(); + if ($request->filled('branch_scope')) { + $branches->where('kodcaw', $request->input('branch_scope')); + } + $payload['branches'] = $branches->distinct()->orderBy('kodcaw')->pluck('kodcaw')->values(); + } + return response()->json($payload); + } catch (QueryException $exception) { + return $this->unavailable(); + } + } + + public function show(string $kodcaw, string $norujukan) + { + try { + $record = $this->find($kodcaw, $norujukan); + } catch (QueryException $exception) { + return $this->unavailable(); + } + if (!$record) { + return response()->json(['message' => 'Rekod pembiayaan tidak dijumpai.'], 404); + } + return response()->json(['data' => $this->present($record)]); + } + + public function store(string $kodcaw, string $norujukan, Request $request) + { + $this->validate($request, [ + 'teller' => 'required|string|max:255', + 'action' => 'required|string|max:30', + 'context' => 'present|array', + ]); + try { + $existing = $this->find($kodcaw, $norujukan); + if ($existing) { + return response()->json(['created' => false, 'data' => $this->present($existing)]); + } + $record = ShorakaFinancing::create([ + 'kodcaw' => $kodcaw, + 'norujukan' => $norujukan, + 'teller' => $request->input('teller'), + 'action' => $request->input('action'), + 'state' => 'WAITING', + 'context' => $request->input('context'), + ]); + return response()->json(['created' => true, 'data' => $this->present($record)], 201); + } catch (QueryException $exception) { + try { + $existing = $this->find($kodcaw, $norujukan); + } catch (QueryException $again) { + return $this->unavailable(); + } + if ($existing) { + return response()->json(['created' => false, 'data' => $this->present($existing)]); + } + return $this->unavailable(); + } + } + + public function update(string $kodcaw, string $norujukan, Request $request) + { + $this->validate($request, [ + 'state' => 'required|in:WAITING,PROCESSING,REVIEW,DONE', + 'expected_state' => 'nullable|in:WAITING,PROCESSING,REVIEW,DONE', + 'context' => 'nullable|array', + ]); + try { + $record = $this->find($kodcaw, $norujukan); + if (!$record) { + return response()->json(['message' => 'Rekod pembiayaan tidak dijumpai.'], 404); + } + if ($request->filled('expected_state')) { + $claimed = ShorakaFinancing::where('id', $record->id) + ->where('state', $request->input('expected_state')) + ->update(['state' => $request->input('state'), 'updated_at' => Carbon::now()]); + return response()->json([ + 'claimed' => $claimed === 1, + 'data' => $this->present($record->fresh()), + ]); + } + $fields = ['state' => $request->input('state')]; + if ($request->exists('context')) { + $fields['context'] = $request->input('context') ?? []; + } + $record->update($fields); + return response()->json(['claimed' => true, 'data' => $this->present($record->fresh())]); + } catch (QueryException $exception) { + return $this->unavailable(); + } + } + + private function find(string $kodcaw, string $norujukan): ?ShorakaFinancing + { + return ShorakaFinancing::where('kodcaw', $kodcaw)->where('norujukan', $norujukan)->first(); + } + + private function present(ShorakaFinancing $record, bool $withContext = true): array + { + $data = [ + 'id' => $record->id, + 'kodcaw' => $record->kodcaw, + 'norujukan' => $record->norujukan, + 'teller' => $record->teller, + 'action' => $record->action, + 'state' => $record->state, + 'created_at' => optional($record->created_at)->toDateTimeString(), + 'updated_at' => optional($record->updated_at)->toDateTimeString(), + ]; + if ($withContext) { + $data['context'] = $record->context ?? []; + } + return $data; + } + + private function unavailable() + { + return response()->json(['message' => 'Rekod pembiayaan Shoraka tidak tersedia.'], 503); + } +} diff --git a/app/Http/Controllers/ShorakaGadaiController.php b/app/Http/Controllers/ShorakaGadaiController.php index 990be02..ab9ac86 100644 --- a/app/Http/Controllers/ShorakaGadaiController.php +++ b/app/Http/Controllers/ShorakaGadaiController.php @@ -11,7 +11,13 @@ class ShorakaGadaiController extends ShorakaController { public function readiness(ShorakaService $shoraka) { - return response()->json(['provider' => 'shoraka', 'ready' => $shoraka->configured()]); + try { + \App\ShorakaFinancing::query()->limit(1)->exists(); + $storeReady = true; + } catch (\Throwable $exception) { + $storeReady = false; + } + return response()->json(['provider' => 'shoraka', 'ready' => $storeReady && $shoraka->configured()]); } public function showGadai(string $kodcaw, string $norujukan, ShorakaGadaiService $gadaiService) @@ -45,16 +51,8 @@ class ShorakaGadaiController extends ShorakaController || $gadai->cetak || $gadai->sttebus) { abort(409, 'Gadaian lama atau telah selesai tidak boleh dihantar sebagai order baharu.'); } - $temporary = app(\App\Services\ShorakaNewGadaiService::class)->pending($kodcaw, $norujukan); - if ($temporary && $gadai->exists) { - abort(409, 'Rujukan sementara bertindih dengan gadaian sedia ada. Semakan operasi diperlukan.'); - } - if ($temporary && !$temporary['prepared']) { - abort(409, 'Sila sahkan semula amaun gadaian selepas perubahan marhun.'); - } $request = new Request($gadaiService->payload($gadai)); $request->attributes->set('shoraka_kodcaw', $kodcaw); - $request->attributes->set('shoraka_new', !$gadai->exists); return $this->submit($request, $shoraka); } diff --git a/app/Services/ShorakaGadaiService.php b/app/Services/ShorakaGadaiService.php index 027ebd9..61d1b14 100644 --- a/app/Services/ShorakaGadaiService.php +++ b/app/Services/ShorakaGadaiService.php @@ -13,7 +13,7 @@ class ShorakaGadaiService public function gadai(string $kodcaw, string $norujukan): Gadai { $branch = Cawangan::on('mysql7')->where('kodcaw', $kodcaw)->firstOrFail(); - return app(ShorakaNewGadaiService::class)->find($kodcaw, $norujukan) + return Gadai::on($branch->mysql)->where('kodcaw', $kodcaw)->where('norujukan', $norujukan)->first() ?? abort(404, 'Maklumat gadaian tidak tersedia. Semakan diperlukan.'); } @@ -53,7 +53,6 @@ class ShorakaGadaiService if (!$order->kodcaw) { return; } - app(ShorakaNewGadaiService::class)->promote($order); $gadai = $this->gadai($order->kodcaw, $order->norujukan); if (!$gadai->exists) { return; diff --git a/app/Services/ShorakaNewGadaiService.php b/app/Services/ShorakaNewGadaiService.php deleted file mode 100644 index 7c7d4bf..0000000 --- a/app/Services/ShorakaNewGadaiService.php +++ /dev/null @@ -1,259 +0,0 @@ -cache()->get($this->key($branch, $reference)); - } - - private function put(string $branch, string $reference, array $data): void - { - if (!$this->cache()->put($this->key($branch, $reference), $data, self::TTL)) { - abort(503, 'Maklumat sementara tidak dapat disimpan.'); - } - } - - // File cache and these locks must be shared by every API worker serving a branch. - public function locked(string $key, callable $callback) - { - $directory = storage_path('framework/cache/shoraka-locks'); - if (!is_dir($directory) && !@mkdir($directory, 0700, true) && !is_dir($directory)) { - abort(503, 'Kunci transaksi tidak tersedia.'); - } - $handle = fopen($directory . '/' . hash('sha256', $key) . '.lock', 'c'); - if (!$handle) { - abort(503, 'Kunci transaksi tidak tersedia.'); - } - if (!flock($handle, LOCK_EX | LOCK_NB)) { - fclose($handle); - abort(409, 'Transaksi sedang diproses. Sila tunggu.'); - } - try { - return $callback(); - } finally { - flock($handle, LOCK_UN); - fclose($handle); - } - } - - public function reserve(string $branch, array $customer): Gadai - { - return $this->locked('reserve:' . $branch, function () use ($branch, $customer) { - $cawangan = Cawangan::on('mysql7')->where('kodcaw', $branch)->firstOrFail(); - $date = Carbon::now()->toDateString(); - $counter = 'shoraka:serial:' . $branch . ':' . $date; - $latest = Gadai::on($cawangan->mysql)->where('t_gadai', $date)->max('sirig'); - $highest = max((int) $latest, (int) $this->cache()->get($counter, 0)); - $releasedKey = 'shoraka:released:' . $branch . ':' . $date; - $released = $this->cache()->get($releasedKey, []); - sort($released, SORT_NUMERIC); - $serial = null; - while ($released) { - $candidate = (int) array_shift($released); - $candidateReference = strtoupper($branch) . Carbon::parse($date)->format('ymd') . '-' . sprintf('%04d', $candidate); - if (!ShorakaTransaction::where('norujukan', $candidateReference)->exists() - && !Gadai::on($cawangan->mysql)->where('norujukan', $candidateReference)->exists() - && !$this->pending($branch, $candidateReference)) { - $serial = $candidate; - $reference = $candidateReference; - break; - } - } - if (!$this->cache()->forever($releasedKey, $released)) { - abort(503, 'Nombor rujukan dibatalkan tidak dapat dikemas kini.'); - } - if ($serial === null) { - $serial = $highest; - do { - ++$serial; - $reference = strtoupper($branch) . Carbon::parse($date)->format('ymd') . '-' . sprintf('%04d', $serial); - } while (ShorakaTransaction::where('norujukan', $reference)->exists() - || Gadai::on($cawangan->mysql)->where('norujukan', $reference)->exists() - || $this->pending($branch, $reference)); - } - if (!$this->cache()->forever($counter, max($highest, $serial))) { - abort(503, 'Nombor rujukan tidak dapat ditempah.'); - } - $data = array_merge($customer, [ - 'kodcaw' => $branch, 'norujukan' => $reference, 'sirig' => $serial, - 't_gadai' => $date, 'masa' => Carbon::now()->toTimeString(), 'sttebus' => '', - 'cara_terima' => 'TUNAI', 'cetak' => 0, 'tagserah' => 0, 'tagkomuditi' => 0, - ]); - if ($cawangan->version === 'v2') { - $data['tagbaru'] = 1; - } - $this->put($branch, $reference, ['gadai' => $data, 'items' => [], 'next_item' => 1, 'revision' => 0, 'prepared' => false]); - return $this->find($branch, $reference); - }); - } - - public function abandon(string $branch, string $reference): void - { - // Use the reservation lock as well so release and allocation cannot race. - $this->locked('reserve:' . $branch, function () use ($branch, $reference) { - $this->locked($branch . ':' . $reference, function () use ($branch, $reference) { - $pending = $this->mutable($branch, $reference); - $cawangan = Cawangan::on('mysql7')->where('kodcaw', $branch)->firstOrFail(); - if (Gadai::on($cawangan->mysql)->where('norujukan', $reference)->exists()) { - abort(409, 'Gadaian telah disimpan dan nombor rujukan tidak boleh digunakan semula.'); - } - $releasedKey = 'shoraka:released:' . $branch . ':' . $pending['gadai']['t_gadai']; - $released = $this->cache()->get($releasedKey, []); - $released[] = (int) $pending['gadai']['sirig']; - if (!$this->cache()->forever($releasedKey, array_values(array_unique($released)))) { - abort(503, 'Nombor rujukan tidak dapat dilepaskan.'); - } - if (!$this->cache()->forget($this->key($branch, $reference))) { - abort(503, 'Maklumat sementara tidak dapat dibatalkan.'); - } - }); - }); - } - - public function latestSerial(string $branch, string $date): int - { - return (int) $this->cache()->get('shoraka:serial:' . $branch . ':' . $date, 0); - } - - public function claim(string $branch, string $reference, array $payload, callable $create) - { - return $this->locked($branch . ':' . $reference, function () use ($branch, $reference, $payload, $create) { - $pending = $this->mutable($branch, $reference); - if (!$pending['prepared'] - || number_format((float) ($pending['gadai']['pinjaman'] ?? 0), 2, '.', '') !== $payload['order_amount'] - || number_format((float) ($pending['gadai']['hargajualan'] ?? 0), 2, '.', '') !== $payload['murabaha_amount']) { - abort(409, 'Maklumat gadaian berubah. Sila sahkan semula sebelum penghantaran.'); - } - return $create(); // The unique transaction reference freezes further edits. - }); - } - - public function find(string $branch, string $reference) - { - $cawangan = Cawangan::on('mysql7')->where('kodcaw', $branch)->firstOrFail(); - $saved = Gadai::on($cawangan->mysql)->where('kodcaw', $branch)->where('norujukan', $reference)->first(); - if ($saved) { - return $saved; - } - $pending = $this->pending($branch, $reference); - if (!$pending) { - return null; - } - $model = (new Gadai())->setConnection($cawangan->mysql); - $model->setRawAttributes($pending['gadai']); - return $model; - } - - private function mutable(string $branch, string $reference): array - { - if (ShorakaTransaction::where('norujukan', $reference)->exists()) { - abort(409, 'Kontrak telah dihantar ke Shoraka dan tidak boleh diubah.'); - } - $pending = $this->pending($branch, $reference); - if (!$pending) { - abort(409, 'Maklumat sementara tamat. Semakan diperlukan.'); - } - return $pending; - } - - public function prepare(string $branch, string $reference, array $fields, int $revision): void - { - $this->locked($branch . ':' . $reference, function () use ($branch, $reference, $fields, $revision) { - $pending = $this->mutable($branch, $reference); - if (($pending['revision'] ?? 0) !== $revision) { - abort(409, 'Maklumat marhun berubah semasa pengiraan. Sila sahkan semula.'); - } - $pending['gadai'] = array_merge($pending['gadai'], $fields); - $pending['prepared'] = true; - $this->put($branch, $reference, $pending); - }); - } - - public function items(string $branch, string $reference) - { - return collect(array_values($this->pending($branch, $reference)['items'] ?? [])); - } - - public function changeItem(string $branch, string $reference, array $fields, $id = null, bool $delete = false) - { - return $this->locked($branch . ':' . $reference, function () use ($branch, $reference, $fields, $id, $delete) { - $pending = $this->mutable($branch, $reference); - if ($id !== null && !isset($pending['items'][$id])) { - abort(404, 'Marhun tidak dijumpai.'); - } - if ($id === null) { - $id = $pending['next_item']++; - } - $item = array_merge($pending['items'][$id] ?? [], $fields, ['recno' => (int) $id]); - if ($delete) { - unset($pending['items'][$id]); - } else { - $pending['items'][$id] = $item; - } - $pending['revision'] = ($pending['revision'] ?? 0) + 1; - $pending['prepared'] = false; // Reprice the contract after any collateral edit. - $this->put($branch, $reference, $pending); - return $item; - }); - } - - public function promote(ShorakaTransaction $order): void - { - if ($order->status !== 'Completed' || !$this->pending($order->kodcaw, $order->norujukan)) { - return; - } - $this->locked($order->kodcaw . ':' . $order->norujukan, function () use ($order) { - $pending = $this->pending($order->kodcaw, $order->norujukan); - $data = $pending['gadai']; - if (!$pending['prepared'] - || number_format((float) ($data['pinjaman'] ?? 0), 2, '.', '') !== $order->order_amount - || number_format((float) ($data['hargajualan'] ?? 0), 2, '.', '') !== $order->murabaha_amount) { - abort(409, 'Amaun gadaian tidak sepadan dengan Shoraka.'); - } - $branch = Cawangan::on('mysql7')->where('kodcaw', $order->kodcaw)->firstOrFail(); - $connection = (new Gadai())->setConnection($branch->mysql)->getConnection(); - $connection->transaction(function () use ($connection, $pending, $data, $order) { - $existing = $connection->table('gadai')->where('norujukan', $order->norujukan)->lockForUpdate()->first(); - if ($existing) { - if ($existing->kodcaw !== $order->kodcaw - || number_format((float) $existing->pinjaman, 2, '.', '') !== $order->order_amount - || number_format((float) $existing->hargajualan, 2, '.', '') !== $order->murabaha_amount) { - abort(409, 'Rujukan gadaian bertindih. Semakan diperlukan.'); - } - return; - } - $connection->table('gadai')->insert(array_merge($data, ['tagkomuditi' => 1])); - foreach ($pending['items'] as $item) { - unset($item['recno']); - $connection->table('marhun')->insert($item); - } - }); - \App\Audit::firstOrCreate([ - 'kodcaw' => $order->kodcaw, 'norujukan' => $order->norujukan, 'actions' => 'Daftar Gadai', - ], ['users' => $data['teller'] ?? '', 'new_data' => json_encode($data)]); - // Retain the cache briefly for idempotent reconciliation after a lost response. - }); - } -} diff --git a/app/ShorakaFinancing.php b/app/ShorakaFinancing.php new file mode 100644 index 0000000..bf919f7 --- /dev/null +++ b/app/ShorakaFinancing.php @@ -0,0 +1,16 @@ + 'array']; +} diff --git a/app/Support/v1/GadaiV1.php b/app/Support/v1/GadaiV1.php index fb094c9..aa0e74b 100644 --- a/app/Support/v1/GadaiV1.php +++ b/app/Support/v1/GadaiV1.php @@ -73,13 +73,10 @@ class GadaiV1 $old_data = Gadai::on($cawangan['mysql'])->where('norujukan','=',$norujukan)->first(); } - $temporary = app(\App\Services\ShorakaNewGadaiService::class); - $temporaryData = $temporary->pending($request->kodcaw, $norujukan); - $isTemporary = $temporaryData !== null; - $bil_marhun = ($isTemporary ? $temporary->items($request->kodcaw, $norujukan)->count() : Marhun::on($cawangan['mysql'])->where('norujukan','=',$norujukan)->count()); + $bil_marhun = Marhun::on($cawangan['mysql'])->where('norujukan','=',$norujukan)->count(); - $total_nilai_marhun = ($isTemporary ? $temporary->items($request->kodcaw, $norujukan)->sum('n_marhun') : Marhun::on($cawangan['mysql'])->where('norujukan','=',$norujukan)->sum('n_marhun')); - $total_berat = ($isTemporary ? $temporary->items($request->kodcaw, $norujukan)->sum('berat') : Marhun::on($cawangan['mysql'])->where('norujukan','=',$norujukan)->sum('berat')); + $total_nilai_marhun = Marhun::on($cawangan['mysql'])->where('norujukan','=',$norujukan)->sum('n_marhun'); + $total_berat = Marhun::on($cawangan['mysql'])->where('norujukan','=',$norujukan)->sum('berat'); $kadar_raw = KadarUpah::where('min','<=',$total_nilai_marhun)->where('max','>=',$total_nilai_marhun)->first(); $tawarruqservices = new Calculation(); @@ -117,10 +114,6 @@ class GadaiV1 'tempohbayar' => 0.00, 'lelong_tawarruq' => 1 ); - if ($isTemporary) { - $temporary->prepare($request->kodcaw, $norujukan, $gadaiFields, $temporaryData['revision'] ?? 0); - return response()->json(true); - } $gadai = Gadai::on($cawangan['mysql'])->where('norujukan', $norujukan)->update($gadaiFields); $new_data = Gadai::on($cawangan['mysql'])->where('norujukan','=',$norujukan)->first(); diff --git a/app/Support/v1/Penebusan.php b/app/Support/v1/Penebusan.php index e0a864a..4500d8e 100644 --- a/app/Support/v1/Penebusan.php +++ b/app/Support/v1/Penebusan.php @@ -946,8 +946,7 @@ class Penebusan $gadaiTransaction = Gadai::on($cawangan['mysql'])->where('t_gadai','=',$current->toDateString())->orderBy('sirig', 'desc')->first(); $gadaiTransaction = optional($gadaiTransaction)->toArray(); - $new_sirig = max((int) ($gadaiTransaction['sirig'] ?? 0), - app(\App\Services\ShorakaNewGadaiService::class)->latestSerial($kodcaw, $current->toDateString())) + 1; + $new_sirig = (int) ($gadaiTransaction['sirig'] ?? 0) + 1; $curent_year = substr($current->year,2,2); $curent_month = sprintf("%02d", $current->month); $current_day = sprintf("%02d", $current->day); diff --git a/app/Support/v2/GadaiV2.php b/app/Support/v2/GadaiV2.php index fa40cf5..7c17ca5 100644 --- a/app/Support/v2/GadaiV2.php +++ b/app/Support/v2/GadaiV2.php @@ -107,13 +107,10 @@ class GadaiV2 $old_data = Gadai::on($cawangan['mysql'])->where('norujukan','=',$norujukan)->first(); } - $temporary = app(\App\Services\ShorakaNewGadaiService::class); - $temporaryData = $temporary->pending($request->kodcaw, $norujukan); - $isTemporary = $temporaryData !== null; - $bil_marhun = ($isTemporary ? $temporary->items($request->kodcaw, $norujukan)->sum('bil') : Marhun::on($cawangan['mysql'])->where('norujukan','=',$norujukan)->sum('bil')); + $bil_marhun = Marhun::on($cawangan['mysql'])->where('norujukan','=',$norujukan)->sum('bil'); - $total_nilai_marhun = ($isTemporary ? $temporary->items($request->kodcaw, $norujukan)->sum('n_marhun') : Marhun::on($cawangan['mysql'])->where('norujukan','=',$norujukan)->sum('n_marhun')); - $total_berat = ($isTemporary ? $temporary->items($request->kodcaw, $norujukan)->sum('berat') : Marhun::on($cawangan['mysql'])->where('norujukan','=',$norujukan)->sum('berat')); + $total_nilai_marhun = Marhun::on($cawangan['mysql'])->where('norujukan','=',$norujukan)->sum('n_marhun'); + $total_berat = Marhun::on($cawangan['mysql'])->where('norujukan','=',$norujukan)->sum('berat'); $kadar_raw = $this->getKadarUpahAnggota($request->nokp, $total_nilai_marhun, $cawangan['group_id']); @@ -193,10 +190,6 @@ if (is_null($kadar_raw)) { } } - if ($isTemporary) { - $temporary->prepare($request->kodcaw, $norujukan, $gadaiFields, $temporaryData['revision'] ?? 0); - return 'true'; - } $gadai = Gadai::on($cawangan['mysql']) ->where('norujukan','=',$norujukan) ->update($gadaiFields); diff --git a/app/Support/v2/Penebusan.php b/app/Support/v2/Penebusan.php index c3a47cc..887fa4a 100644 --- a/app/Support/v2/Penebusan.php +++ b/app/Support/v2/Penebusan.php @@ -1224,8 +1224,7 @@ class Penebusan $gadaiTransaction = Gadai::on($cawangan['mysql'])->where('t_gadai','=',$current->toDateString())->orderBy('sirig', 'desc')->first(); $gadaiTransaction = optional($gadaiTransaction)->toArray(); - $new_sirig = max((int) ($gadaiTransaction['sirig'] ?? 0), - app(\App\Services\ShorakaNewGadaiService::class)->latestSerial($kodcaw, $current->toDateString())) + 1; + $new_sirig = (int) ($gadaiTransaction['sirig'] ?? 0) + 1; $curent_year = substr($current->year,2,2); $curent_month = sprintf("%02d", $current->month); $current_day = sprintf("%02d", $current->day); diff --git a/routes/web.php b/routes/web.php index e34f9ce..3312168 100644 --- a/routes/web.php +++ b/routes/web.php @@ -120,6 +120,10 @@ $router->group(['prefix'=>'api'], function () use ($router){ $router->get('gadai/online/search/detail',['uses'=>'GadaiController@searchGadaiOnline']); $router->get('shoraka/readiness', ['uses' => 'ShorakaGadaiController@readiness']); + $router->get('shoraka/financings', ['uses' => 'ShorakaFinancingController@index']); + $router->get('shoraka/financings/{kodcaw}/{norujukan}', ['uses' => 'ShorakaFinancingController@show']); + $router->post('shoraka/financings/{kodcaw}/{norujukan}', ['uses' => 'ShorakaFinancingController@store']); + $router->put('shoraka/financings/{kodcaw}/{norujukan}', ['uses' => 'ShorakaFinancingController@update']); $router->get('shoraka/gadai/{kodcaw}/{norujukan}', ['uses' => 'ShorakaGadaiController@showGadai']); $router->post('shoraka/gadai/{kodcaw}/{norujukan}/submit', ['uses' => 'ShorakaGadaiController@submitGadai']); $router->post('shoraka/gadai/{kodcaw}/{norujukan}/refresh', ['uses' => 'ShorakaGadaiController@refreshGadai']);