diff --git a/app/Http/Controllers/GadaianController.php b/app/Http/Controllers/GadaianController.php
index 128855f2..57787a7f 100644
--- a/app/Http/Controllers/GadaianController.php
+++ b/app/Http/Controllers/GadaianController.php
@@ -298,7 +298,7 @@ class GadaianController extends Controller
}
if ($caraTerima === 'ONLINE' && !$this->hasMatchingBorangOnlinePrint($request)) {
- return redirect()->back()->with('error', 'Sila cetak borang pengesahan pelanggan sebelum tekan Terima.');
+ return $this->gadaiStoreResult($request, false, 'Sila cetak borang pengesahan pelanggan sebelum tekan Terima.');
}
//$total_nilai_marhun = $request->total_nilai_marhun;
@@ -320,6 +320,27 @@ class GadaianController extends Controller
$keuntungan12bulan = $keuntungan_sebln * 12;
$hargajualan = $request->pinjaman + $keuntungan12bulan;
+
+ // BSAS commodity order must succeed before finalizing gadai.
+ $bsas = Http::withOptions(['verify' => config('app.api_verify')])
+ ->timeout(60)
+ ->post(config('api.url') . '/api/komuditi/bsas/order', [
+ 'norujukan' => $request->norujukan_gadai,
+ 'kodcaw' => $auth_user['cawangan'],
+ 'pinjaman' => round((float) $request->pinjaman, 2),
+ 'hargajualan' => round((float) $hargajualan, 2),
+ 'nama_pelanggan' => $request->nama_pelanggan ?: $request->nama_akaun,
+ 'teller' => $auth_user['name'],
+ ]);
+
+ if (!$bsas->successful()) {
+ $body = $bsas->json();
+ $msg = is_array($body) && isset($body['message'])
+ ? $body['message']
+ : 'Gagal pembelian komoditi BSAS. Sila cuba lagi.';
+ return $this->gadaiStoreResult($request, false, $msg);
+ }
+
//Log::info('DEBUG NOKP:' . $request->nokp);
$gadai = Http::withOptions(['verify' => config('app.api_verify')])->put(config('api.url') . '/api/gadai/norujukan/' . $auth_user['cawangan'] . '/' . $request->norujukan_gadai, [
'kodcaw' => $auth_user['cawangan'],
@@ -344,14 +365,6 @@ class GadaianController extends Controller
'rebate' => $this->parseMoney($request->rebate),
])->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']
- ]);
-
if ($caraTerima === 'ONLINE') {
$online = Http::withOptions(['verify' => config('app.api_verify')])
->asForm()
@@ -374,7 +387,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);
+ return $this->gadaiStoreResult($request, false, $msg);
}
$this->notifyPcPembiayaanOnlinePending($auth_user, $request, $pinjamanAmt);
@@ -392,6 +405,33 @@ class GadaianController extends Controller
$request->session()->flash('message', 'Gadai berjaya. Pembiayaan online menunggu semakan PC.');
}
+ return $this->gadaiStoreResult($request, true);
+ }
+
+ /**
+ * JSON for AJAX Terima (BSAS progress UI); normal redirect otherwise.
+ */
+ protected function gadaiStoreResult(Request $request, bool $ok, string $message = null)
+ {
+ if ($request->ajax() || $request->wantsJson()) {
+ if (!$ok) {
+ return response()->json([
+ 'ok' => false,
+ 'message' => $message ?: 'Gadai tidak berjaya.',
+ ], 422);
+ }
+
+ return response()->json([
+ 'ok' => true,
+ 'message' => $message ?: 'Gadai berjaya.',
+ 'redirect' => route('customer_info'),
+ ]);
+ }
+
+ if (!$ok) {
+ return redirect()->back()->with('error', $message ?: 'Gadai tidak berjaya.');
+ }
+
return redirect()->route('customer_info');
}
@@ -671,13 +711,31 @@ class GadaianController extends Controller
// $pembayaran_segera = "https://spare.arrahn.com.my/pembayaransegera";
$pembayaran_segera = "https://pay.arrahn.com.my";
- $komoditi = Http::withOptions(['verify' => config('app.api_verify')])
- ->get($api_url . '/api/komuditi/check')
- ->json();
- $product = Http::withOptions(['verify' => config('app.api_verify')])
- ->get($api_url . '/api/komuditi/description', ['kodproduk' => $komoditi['kodproduct']])
- ->json();
- $kuantiti = $gadai_detail['pinjaman'] / $komoditi['nilai'];
+ $bsasSag = Http::withOptions(['verify' => config('app.api_verify')])
+ ->get($api_url . '/api/komuditi/bsas/order/norujukan/' . urlencode($norujukan));
+
+ $komoditi = [];
+ $product = [];
+ $kuantiti = 0;
+
+ if ($bsasSag->successful() && is_array($bsasSag->json())) {
+ $bsasPayload = $bsasSag->json();
+ $komoditi = $bsasPayload['komoditi'] ?? [];
+ $product = $bsasPayload['product'] ?? [];
+ $kuantiti = (float) ($bsasPayload['kuantiti'] ?? 0);
+ }
+
+ if (!is_array($komoditi)) {
+ $komoditi = [];
+ }
+ if (!is_array($product)) {
+ $product = [
+ 'product_code' => $komoditi['kodproduct'] ?? '',
+ 'kodproduk' => $komoditi['kodproduct'] ?? '',
+ 'description' => '',
+ 'unit' => 'TAN',
+ ];
+ }
if ($gadai_detail['tagbaru'] == 1) {
$cawangan_info = Http::withOptions(['verify' => config('app.api_verify')])
diff --git a/app/Http/Controllers/KomuditiController.php b/app/Http/Controllers/KomuditiController.php
index 72474dbf..8c672266 100644
--- a/app/Http/Controllers/KomuditiController.php
+++ b/app/Http/Controllers/KomuditiController.php
@@ -55,4 +55,122 @@ class KomuditiController extends Controller
return redirect()->route('komuditi');
}
+
+ /**
+ * Dummy BSAS eCert layout preview (2-page A4).
+ */
+ public function previewBsasEcert()
+ {
+ $cert = [
+ 'ecert_no' => 'CPO13OCT26-0000136-025',
+ 'seller' => 'KOPERASI PERMODALAN KELANTAN BERHAD',
+ 'buyer' => 'WAN MOHAMAD AIMAN',
+ 'bid_no' => '1',
+ 'report_time' => '13:39:23.751',
+ 'report_date' => '13 OCTOBER 2026',
+ 'value_date' => '13 OCTOBER 2026',
+ 'product' => 'CPO-MSIA-09',
+ 'unit' => 'Tonnage',
+ 'volume' => '.72562358',
+ 'currency' => 'MYR',
+ 'price' => '5,256.72',
+ 'price_myr' => '5,256.72',
+ 'value' => '3,200.00',
+ 'txn_type' => '-',
+ 'murabaha' => '3,814.40',
+ 'lines' => [
+ [
+ 'supplier' => 'POA RESOURCES BERHAD',
+ 'volume' => '.72562358',
+ ],
+ ],
+ ];
+
+ return view('print.bsas_ecert', [
+ 'cert' => $cert,
+ 'isDummy' => true,
+ ]);
+ }
+
+ /**
+ * Live BSAS eCert from stored bsas_orders.ecert_response.
+ */
+ public function showBsasEcert($uuid)
+ {
+ $response = Http::withOptions(['verify' => config('app.api_verify')])
+ ->get(config('api.url') . '/api/komuditi/bsas/order/' . urlencode($uuid) . '/ecert');
+
+ if ($response->status() === 404) {
+ abort(404, $response->json('message') ?: 'eCert tidak dijumpai.');
+ }
+
+ if (!$response->successful()) {
+ abort(502, 'Gagal memuatkan eCert BSAS.');
+ }
+
+ $payload = $response->json();
+ $ecert = $payload['ecert'] ?? null;
+
+ if (!is_array($ecert) || empty($ecert)) {
+ abort(404, 'eCert belum tersedia untuk order ini.');
+ }
+
+ return view('print.bsas_ecert', [
+ 'cert' => $this->mapBsasEcertToView($ecert, $payload),
+ 'isDummy' => false,
+ ]);
+ }
+
+ /**
+ * Map stored otcXML / eCert JSON into print view fields.
+ */
+ protected function mapBsasEcertToView(array $ecert, array $orderMeta = []): array
+ {
+ $reporting = trim((string) ($ecert['REPORTINGTIMEDATE'] ?? ''));
+ $reportTime = '-';
+ $reportDate = '-';
+ if ($reporting !== '') {
+ $parts = explode(' ', $reporting, 2);
+ $reportTime = $parts[0] ?? '-';
+ $reportDate = isset($parts[1]) ? strtoupper($parts[1]) : '-';
+ }
+
+ $lines = [];
+ foreach (($ecert['LINE'] ?? []) as $line) {
+ if (!is_array($line)) {
+ continue;
+ }
+ $lines[] = [
+ 'supplier' => $line['SUPPLIER'] ?? '-',
+ 'volume' => $line['VOLUME'] ?? ($ecert['PVOLUME'] ?? '-'),
+ ];
+ }
+
+ if (empty($lines)) {
+ $lines[] = [
+ 'supplier' => '-',
+ 'volume' => $ecert['PVOLUME'] ?? '-',
+ ];
+ }
+
+ return [
+ 'ecert_no' => $ecert['ECERTNO'] ?? ($orderMeta['e_cert_no'] ?? '-'),
+ 'seller' => $ecert['SELLER'] ?? 'KOPERASI PERMODALAN KELANTAN BERHAD',
+ 'buyer' => $ecert['BUYER'] ?? ($orderMeta['otc_counter_party'] ?? '-'),
+ 'bid_no' => $orderMeta['serial_number'] ?? '1',
+ 'report_time' => $reportTime,
+ 'report_date' => $reportDate,
+ 'value_date' => isset($ecert['VALUEDATE']) ? strtoupper((string) $ecert['VALUEDATE']) : '-',
+ 'product' => $ecert['PNAME'] ?? ($orderMeta['product_code'] ?? '-'),
+ 'unit' => 'Tonnage',
+ 'volume' => $ecert['PVOLUME'] ?? '-',
+ 'currency' => $ecert['CURRENCY'] ?? 'MYR',
+ 'price' => $ecert['PRICE'] ?? '-',
+ 'price_myr' => $ecert['PRICE_MYR_EQUIVALENT'] ?? ($ecert['PRICE'] ?? '-'),
+ 'value' => $ecert['TOTALVALUE'] ?? '-',
+ 'txn_type' => '-',
+ 'murabaha' => $ecert['MURABAHAVALUE'] ?? ($orderMeta['otc_murabaha_value'] ?? '-'),
+ 'lines' => $lines,
+ ];
+ }
}
diff --git a/app/Http/Controllers/PembiayaanOnlineController.php b/app/Http/Controllers/PembiayaanOnlineController.php
index a8a24bfb..d4ed7e13 100644
--- a/app/Http/Controllers/PembiayaanOnlineController.php
+++ b/app/Http/Controllers/PembiayaanOnlineController.php
@@ -585,15 +585,37 @@ class PembiayaanOnlineController extends Controller
$pembayaran_segera = 'https://pay.arrahn.com.my';
- $komoditi = $this->api()->get($api_url . '/api/komuditi/check')->json();
- $product = $this->api()
- ->get($api_url . '/api/komuditi/description', [
- 'kodproduk' => is_array($komoditi) ? ($komoditi['kodproduct'] ?? '') : '',
- ])
- ->json();
+ // Prefer per-Terima BSAS order; fall back to legacy daily KomuditiPurchase.
+ $bsasSag = $this->api()
+ ->get($api_url . '/api/komuditi/bsas/order/norujukan/' . urlencode($norujukan));
- $nilai = is_array($komoditi) ? (float) ($komoditi['nilai'] ?? 0) : 0;
- $kuantiti = $nilai > 0 ? ((float) ($gadai_detail['pinjaman'] ?? 0) / $nilai) : 0;
+ if ($bsasSag->successful() && is_array($bsasSag->json())) {
+ $bsasPayload = $bsasSag->json();
+ $komoditi = $bsasPayload['komoditi'] ?? [];
+ $product = $bsasPayload['product'] ?? [];
+ $kuantiti = (float) ($bsasPayload['kuantiti'] ?? 0);
+ } else {
+ $komoditi = $this->api()->get($api_url . '/api/komuditi/check')->json();
+ $product = $this->api()
+ ->get($api_url . '/api/komuditi/description', [
+ 'kodproduk' => is_array($komoditi) ? ($komoditi['kodproduct'] ?? '') : '',
+ ])
+ ->json();
+
+ $nilai = is_array($komoditi) ? (float) ($komoditi['nilai'] ?? 0) : 0;
+ $kuantiti = $nilai > 0 ? ((float) ($gadai_detail['pinjaman'] ?? 0) / $nilai) : 0;
+ }
+
+ if (!is_array($komoditi)) {
+ $komoditi = [];
+ }
+ if (!is_array($product)) {
+ $product = [
+ 'kodproduk' => $komoditi['kodproduct'] ?? '',
+ 'description' => '',
+ 'unit' => 'TAN',
+ ];
+ }
if (($gadai_detail['tagbaru'] ?? 0) == 1) {
$cawangan_info = $this->api()
diff --git a/docker/php/Dockerfile b/docker/php/Dockerfile
index e2a2c4f8..6e3300d6 100644
--- a/docker/php/Dockerfile
+++ b/docker/php/Dockerfile
@@ -2,7 +2,14 @@ FROM php:7.4-fpm AS base
WORKDIR /var/www/html
-RUN apt-get update \
+# php:7.4-fpm is Debian 11 (bullseye); after LTS end, packages live on archive.debian.org
+RUN sed -i \
+ -e 's|http://deb.debian.org/debian|http://archive.debian.org/debian|g' \
+ -e 's|http://security.debian.org/debian-security|http://archive.debian.org/debian-security|g' \
+ -e 's|http://deb.debian.org/debian-security|http://archive.debian.org/debian-security|g' \
+ /etc/apt/sources.list \
+ && printf 'Acquire::Check-Valid-Until "false";\n' > /etc/apt/apt.conf.d/99no-check-valid-until \
+ && apt-get update \
&& apt-get install -y --no-install-recommends \
git \
pkg-config \
diff --git a/public/img/svg/logo-arrahn-new.svg b/public/img/svg/logo-arrahn-new.svg
new file mode 100644
index 00000000..149be9fa
--- /dev/null
+++ b/public/img/svg/logo-arrahn-new.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/public/img/logo-arrahn.svg b/public/img/svg/logo-arrahn-old.svg
similarity index 100%
rename from public/img/logo-arrahn.svg
rename to public/img/svg/logo-arrahn-old.svg
diff --git a/public/img/svg/logo-kopkb.svg b/public/img/svg/logo-kopkb.svg
new file mode 100644
index 00000000..5c3ea85b
--- /dev/null
+++ b/public/img/svg/logo-kopkb.svg
@@ -0,0 +1,161 @@
+
+
+
+
diff --git a/resources/views/components/print/bsas/footer.blade.php b/resources/views/components/print/bsas/footer.blade.php
new file mode 100644
index 00000000..a914fef2
--- /dev/null
+++ b/resources/views/components/print/bsas/footer.blade.php
@@ -0,0 +1,50 @@
+@props([
+ 'note' => '',
+ 'page' => null,
+ 'total' => null,
+])
+
+
+
+
diff --git a/resources/views/components/print/bsas/header.blade.php b/resources/views/components/print/bsas/header.blade.php
new file mode 100644
index 00000000..724754a1
--- /dev/null
+++ b/resources/views/components/print/bsas/header.blade.php
@@ -0,0 +1,63 @@
+@props([
+ 'company' => 'Koperasi Permodalan Kelantan Berhad',
+ 'leftLogo' => null,
+ 'rightLogo' => null,
+])
+
+@php
+ $leftLogo = $leftLogo ?? asset('img/svg/logo-kopkb.svg');
+ $rightLogo = $rightLogo ?? asset('img/svg/logo-arrahn-new.svg');
+@endphp
+
+
+
+ {{ $company }}
+
+
Sedang memproses pembelian komoditi...
' + + 'Sila tunggu, proses ini boleh mengambil masa 10–30 saat.
' + + '