Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 510b118a23 | |||
| 05f1700087 | |||
| 1138e193ae | |||
| 464d3e8dbb | |||
| abccad3219 | |||
| 7ad3fd4f86 | |||
| 713d5a4923 | |||
| b76566a2d6 | |||
| 38f6db2e10 | |||
| f95bdf1214 | |||
| d614677601 | |||
| 7cd21ef610 | |||
| ca2a02e354 | |||
| 76176ed453 |
@@ -50,3 +50,5 @@ MYKAD_READER_PORT=17321
|
||||
MYKAD_READER_ENABLED_CAWANGAN=''
|
||||
|
||||
INTERNAL_NOTIFICATION_SECRET=
|
||||
|
||||
LOGVIEWER_PASSWORD=
|
||||
|
||||
@@ -7,6 +7,7 @@ APP_URL=https://ujrah.erahn.com.my
|
||||
API_URL=https://apiujrah.erahn.com.my
|
||||
|
||||
LOG_CHANNEL=stack
|
||||
LOGVIEWER_PASSWORD="$2y$10$k7eiUyZdm3BruwAaT1gbmelTm.PPgZptOEQT1nlBjyiR84a4KBMlm"
|
||||
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=192.168.1.216
|
||||
|
||||
+2
-5
@@ -4,17 +4,14 @@ APP_VERSION=v2.2-staging
|
||||
APP_KEY=base64:O1XZDqK4H6+3GdrODgCaLr2l+OoWvgVhYr0GJ1KizW8=
|
||||
APP_DEBUG=true
|
||||
APP_URL=https://staging.erahn.com.my
|
||||
API_URL=https://api-staging.erahn.com.my
|
||||
|
||||
HTTP_PORT=8091
|
||||
MYSQL_PUBLISH_PORT=3309
|
||||
|
||||
API_URL=https://api-staging.erahn.com.my
|
||||
API_URL_KOOP=https://api-staging.erahn.com.my
|
||||
API_URL_PKB=https://api-staging.erahn.com.my
|
||||
API_ARRAHNBID=http://lelong.test/api/
|
||||
|
||||
LOG_CHANNEL=stack
|
||||
LOG_LEVEL=debug
|
||||
LOGVIEWER_PASSWORD=test123
|
||||
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=mysql
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
APP_NAME=Laravel
|
||||
APP_ENV=local
|
||||
APP_KEY=base64:WRTHcFTq5YARKVdA8YDUzsh9Ue8vD63ivgZgXNNBiGo=
|
||||
APP_DEBUG=true
|
||||
APP_URL=http://ujrahkopkb.erahn.com.my
|
||||
API_URL=http://apiujrah-kopkb.erahn.com.my
|
||||
#API_ARRAHNBID=http://lelong.test/api/
|
||||
|
||||
LOG_CHANNEL=stack
|
||||
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=127.0.0.1
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=kaunter_erahn
|
||||
DB_USERNAME=spider
|
||||
DB_PASSWORD=G0dz!ll4
|
||||
|
||||
BROADCAST_DRIVER=pusher
|
||||
CACHE_DRIVER=file
|
||||
QUEUE_CONNECTION=sync
|
||||
SESSION_DRIVER=file
|
||||
SESSION_LIFETIME=120
|
||||
|
||||
REDIS_HOST=127.0.0.1
|
||||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
PUSHER_APP_ID=1132718
|
||||
PUSHER_APP_KEY=26b0ec2f297f94b7aa9b
|
||||
PUSHER_APP_SECRET=421b61fb5a8ecce477a6
|
||||
|
||||
MAIL_MAILER=smtp
|
||||
MAIL_HOST=smtp.mailtrap.io
|
||||
MAIL_PORT=2525
|
||||
MAIL_USERNAME=null
|
||||
MAIL_PASSWORD=null
|
||||
MAIL_ENCRYPTION=null
|
||||
MAIL_FROM_ADDRESS=null
|
||||
MAIL_FROM_NAME="${APP_NAME}"
|
||||
|
||||
AWS_ACCESS_KEY_ID=
|
||||
AWS_SECRET_ACCESS_KEY=
|
||||
AWS_DEFAULT_REGION=us-east-1
|
||||
AWS_BUCKET=
|
||||
|
||||
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
|
||||
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
|
||||
|
||||
MYKAD_READER_PORT=8085
|
||||
MYKAD_READER_ENABLED_CAWANGAN='' # IF NO CAWANGAN STATED, ALL CAWANGAN IS ENABLED
|
||||
@@ -1,6 +1,9 @@
|
||||
name: Deploy to Staging
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
image_tag:
|
||||
@@ -18,10 +21,22 @@ jobs:
|
||||
runs-on: host
|
||||
|
||||
steps:
|
||||
- name: Resolve image tag
|
||||
id: resolve
|
||||
run: |
|
||||
set -e
|
||||
if [ "${{ gitea.event_name }}" = "workflow_dispatch" ]; then
|
||||
IMAGE_TAG="${{ inputs.image_tag }}"
|
||||
else
|
||||
IMAGE_TAG="${{ gitea.ref_name }}"
|
||||
fi
|
||||
echo "IMAGE_TAG=${IMAGE_TAG}" >> "$GITHUB_OUTPUT"
|
||||
echo "Deploying image tag: ${IMAGE_TAG}"
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ inputs.image_tag }}
|
||||
ref: ${{ steps.resolve.outputs.IMAGE_TAG }}
|
||||
|
||||
- name: Login to Docker registry
|
||||
run: |
|
||||
@@ -33,28 +48,35 @@ jobs:
|
||||
- name: Verify image exists in registry
|
||||
run: |
|
||||
set -e
|
||||
IMAGE_TAG="${{ inputs.image_tag }}"
|
||||
IMAGE_TAG="${{ steps.resolve.outputs.IMAGE_TAG }}"
|
||||
IMAGE="${APP_IMAGE}:${IMAGE_TAG}"
|
||||
|
||||
echo "Checking if image exists: ${IMAGE}"
|
||||
if ! docker manifest inspect "${IMAGE}" > /dev/null 2>&1; then
|
||||
echo "ERROR: Image ${IMAGE} does not exist in registry!"
|
||||
# Tag pushes build in parallel — wait for the image to appear
|
||||
for i in $(seq 1 30); do
|
||||
if docker manifest inspect "${IMAGE}" > /dev/null 2>&1; then
|
||||
echo "✓ ${IMAGE} found"
|
||||
exit 0
|
||||
fi
|
||||
echo "Image not ready yet (attempt ${i}/30), waiting 20s..."
|
||||
sleep 20
|
||||
done
|
||||
|
||||
echo "ERROR: Image ${IMAGE} does not exist in registry after waiting!"
|
||||
echo "Run the Build Docker Image workflow first."
|
||||
exit 1
|
||||
fi
|
||||
echo "✓ ${IMAGE} found"
|
||||
|
||||
- name: Pull Docker image
|
||||
run: |
|
||||
set -e
|
||||
IMAGE_TAG="${{ inputs.image_tag }}"
|
||||
IMAGE_TAG="${{ steps.resolve.outputs.IMAGE_TAG }}"
|
||||
docker pull "${APP_IMAGE}:${IMAGE_TAG}"
|
||||
echo "✓ Image pulled successfully"
|
||||
|
||||
- name: Sync compose file and deploy
|
||||
run: |
|
||||
set -e
|
||||
IMAGE_TAG="${{ inputs.image_tag }}"
|
||||
IMAGE_TAG="${{ steps.resolve.outputs.IMAGE_TAG }}"
|
||||
|
||||
mkdir -p "${DEPLOY_DIR}/docker/nginx" "${DEPLOY_DIR}/public"
|
||||
cp docker-compose.staging.yml "${DEPLOY_DIR}/docker-compose.yml"
|
||||
@@ -62,15 +84,12 @@ jobs:
|
||||
find "${DEPLOY_DIR}/public" -mindepth 1 -delete
|
||||
cp -R public/. "${DEPLOY_DIR}/public/"
|
||||
|
||||
if [ ! -f "${DEPLOY_DIR}/.env.staging" ]; then
|
||||
if [ -f .env.staging ]; then
|
||||
cp .env.staging "${DEPLOY_DIR}/.env.staging"
|
||||
echo "Copied .env.staging from repo (first deploy). Edit ${DEPLOY_DIR}/.env.staging on the server if needed."
|
||||
else
|
||||
echo "ERROR: ${DEPLOY_DIR}/.env.staging is missing on the server"
|
||||
if [ ! -f .env.staging ]; then
|
||||
echo "ERROR: .env.staging is missing in the repository"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
cp .env.staging "${DEPLOY_DIR}/.env.staging"
|
||||
echo "✓ Synced .env.staging from repo"
|
||||
|
||||
cd "${DEPLOY_DIR}"
|
||||
|
||||
|
||||
@@ -5,15 +5,12 @@ namespace App\Http\Controllers\Auth;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Providers\RouteServiceProvider;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Illuminate\Support\Facades\Redirect;
|
||||
use Illuminate\Foundation\Auth\AuthenticatesUsers;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
|
||||
use App\Dashboard;
|
||||
use App\User;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class LoginController extends Controller
|
||||
{
|
||||
@@ -144,25 +141,26 @@ class LoginController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
public function logout(){
|
||||
$current = Carbon::now();
|
||||
$current = new Carbon();
|
||||
$current = $current->toDateString();
|
||||
public function logout(Request $request)
|
||||
{
|
||||
$auth_user = Auth::guard('web')->user();
|
||||
Auth::logout();
|
||||
Session::flush();
|
||||
$session = Http::withOptions(['verify' => config('app.api_verify')])->post(config('api.url') . '/api/logoutsession/' . $auth_user['cawangan'], [
|
||||
|
||||
Auth::guard('web')->logout();
|
||||
$request->session()->invalidate();
|
||||
$request->session()->regenerateToken();
|
||||
|
||||
if ($auth_user) {
|
||||
Http::withOptions(['verify' => config('app.api_verify')])->post(config('api.url') . '/api/logoutsession/' . $auth_user['cawangan'], [
|
||||
'id' => $auth_user['id'],
|
||||
'nama' => $auth_user['name'],
|
||||
'nokp' => $auth_user['no_kp'],
|
||||
'email' => $auth_user['email'],
|
||||
'taraf' => $auth_user['role_harian'],
|
||||
'tarikh' => $current,
|
||||
|
||||
|
||||
'tarikh' => now()->toDateString(),
|
||||
]);
|
||||
}
|
||||
|
||||
return Redirect::to('/');
|
||||
return redirect('/');
|
||||
}
|
||||
|
||||
public function GetRolesHarian(Request $request, $kodcaw){
|
||||
|
||||
@@ -312,6 +312,61 @@ class CustomersController extends Controller
|
||||
return response()->json($response->json() ?? ['stored' => false], $response->status());
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload scanned IC / passport document for the current customer.
|
||||
*/
|
||||
public function storeIcScan(Request $request)
|
||||
{
|
||||
$icno = preg_replace('/[^0-9A-Za-z]/', '', (string) ($request->input('icno') ?: Session::get('noic')));
|
||||
if ($icno === '') {
|
||||
return response()->json(['error' => 'No. IC diperlukan.', 'stored' => false], 422);
|
||||
}
|
||||
|
||||
list($scanPayload, $scanError) = $this->scanIcPayloadFromRequest($request);
|
||||
if ($scanError) {
|
||||
return response()->json(['error' => $scanError, 'stored' => false], 422);
|
||||
}
|
||||
|
||||
$response = Http::withOptions(['verify' => config('app.api_verify')])
|
||||
->post(config('api.url') . '/api/customers/' . $icno . '/ic-scan', $scanPayload);
|
||||
|
||||
return response()->json($response->json() ?? ['stored' => false], $response->status());
|
||||
}
|
||||
|
||||
public function showIcScan(Request $request)
|
||||
{
|
||||
$icno = preg_replace('/[^0-9A-Za-z]/', '', (string) ($request->query('icno') ?: Session::get('noic')));
|
||||
if ($icno === '') {
|
||||
abort(404);
|
||||
}
|
||||
|
||||
$response = Http::withOptions(['verify' => config('app.api_verify')])
|
||||
->get(config('api.url') . '/api/customers/' . $icno . '/ic-scan');
|
||||
|
||||
$payload = $response->json();
|
||||
$file = is_array($payload) ? ($payload['file'] ?? null) : null;
|
||||
if (!$response->successful() || !$file || empty($file['data'])) {
|
||||
abort(404);
|
||||
}
|
||||
|
||||
$raw = $file['data'];
|
||||
if (strpos($raw, 'base64,') !== false) {
|
||||
$raw = substr($raw, strpos($raw, 'base64,') + 7);
|
||||
}
|
||||
$binary = base64_decode($raw, true);
|
||||
if ($binary === false) {
|
||||
$binary = base64_decode($file['data']);
|
||||
}
|
||||
|
||||
$type = $file['type'] ?? 'application/octet-stream';
|
||||
$filename = $file['filename'] ?? 'scan-ic';
|
||||
|
||||
return response($binary, 200, [
|
||||
'Content-Type' => $type,
|
||||
'Content-Disposition' => 'inline; filename="' . $filename . '"',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
@@ -330,6 +385,11 @@ class CustomersController extends Controller
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
list($scanPayload, $scanError) = $this->scanIcPayloadFromRequest($request);
|
||||
if ($scanError) {
|
||||
return redirect()->back()->with('error', $scanError)->withInput();
|
||||
}
|
||||
|
||||
if ($request->idtype == 'nokp') {
|
||||
$nokpbaru = $request->noic;
|
||||
$nokplama = '';
|
||||
@@ -415,6 +475,10 @@ class CustomersController extends Controller
|
||||
$customer_payload['photo_mime'] = $request->input('photo_mime') ?: 'image/jpeg';
|
||||
}
|
||||
|
||||
$customer_payload['file_base64'] = $scanPayload['file_base64'];
|
||||
$customer_payload['file_mime'] = $scanPayload['file_mime'];
|
||||
$customer_payload['filename'] = $scanPayload['filename'];
|
||||
|
||||
$customer_info = Http::withOptions(['verify' => config('app.api_verify')])->post(config('api.url') . '/api/customers/create/' . $auth_user['cawangan'], $customer_payload);
|
||||
|
||||
Session::put('customer_info', $customer_info);
|
||||
@@ -692,6 +756,34 @@ class CustomersController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
private function scanIcPayloadFromRequest(Request $request)
|
||||
{
|
||||
if (!$request->hasFile('scan_ic')) {
|
||||
return [null, 'Sila muat naik scan dokumen IC / Passport.'];
|
||||
}
|
||||
|
||||
$file = $request->file('scan_ic');
|
||||
if (!$file->isValid()) {
|
||||
return [null, 'Fail scan IC tidak sah.'];
|
||||
}
|
||||
|
||||
if ($file->getSize() > 4 * 1024 * 1024) {
|
||||
return [null, 'Saiz fail scan IC maksimum 4MB.'];
|
||||
}
|
||||
|
||||
$mime = strtolower((string) ($file->getMimeType() ?: ''));
|
||||
$allowed = ['image/jpeg', 'image/jpg', 'image/png', 'application/pdf'];
|
||||
if (!in_array($mime, $allowed, true)) {
|
||||
return [null, 'Format fail scan IC mestilah JPG, PNG atau PDF.'];
|
||||
}
|
||||
|
||||
return [[
|
||||
'file_base64' => base64_encode(file_get_contents($file->getRealPath())),
|
||||
'file_mime' => $mime,
|
||||
'filename' => $file->getClientOriginalName(),
|
||||
], null];
|
||||
}
|
||||
|
||||
private function printBlank($value)
|
||||
{
|
||||
if ($value === null) {
|
||||
|
||||
@@ -164,6 +164,9 @@ class GadaianController extends Controller
|
||||
$noic = $request->noic;
|
||||
$customers_info = Http::withOptions(['verify' => config('app.api_verify')])->get(config('api.url') . '/api/customers/' . $noic)->json();
|
||||
$customer_info = $customers_info;
|
||||
if (!is_array($customer_info) || empty($customer_info['has_scan_ic'])) {
|
||||
return redirect()->route('customer_info')->with('error', 'Sila muat naik scan dokumen IC sebelum daftar pembiayaan.');
|
||||
}
|
||||
$limit_pinjaman_semasa = 0;
|
||||
$auth_user = Auth::user();
|
||||
if ($request->session()->get('page_reload') == null) {
|
||||
@@ -680,7 +683,11 @@ class GadaianController extends Controller
|
||||
$kuantiti = $gadai_detail['pinjaman'] / $komoditi['nilai'];
|
||||
|
||||
if ($gadai_detail['tagbaru'] == 1) {
|
||||
return view('print.sag_ujrah_3', compact('komoditi', 'product', 'kuantiti', 'gadai_detail', 'customer_detail', 'marhun_detail', 'cawangan_detail', 'api_url', 'pembayaran_segera', 'auth_username', 'mutu', 'kadar_ujrah', 'kakitangan'));
|
||||
$cawangan_info = Http::withOptions(['verify' => config('app.api_verify')])
|
||||
->get($api_url . '/api/cawangan/' . $kodcaw)->json();
|
||||
$pembiayaanOnlineEnabled = !empty(($cawangan_info['features'] ?? [])['pembiayaan_online']);
|
||||
|
||||
return view('print.sag_ujrah_3', compact('komoditi', 'product', 'kuantiti', 'gadai_detail', 'customer_detail', 'marhun_detail', 'cawangan_detail', 'api_url', 'pembayaran_segera', 'auth_username', 'mutu', 'kadar_ujrah', 'kakitangan'))->with('pembiayaanOnlineEnabled', $pembiayaanOnlineEnabled);
|
||||
} else {
|
||||
return view('print.sag', compact('gadai_detail', 'customer_detail', 'marhun_detail', 'cawangan_detail', 'api_url', 'pembayaran_segera', 'auth_username', 'mutu', 'kakitangan'));
|
||||
}
|
||||
|
||||
@@ -156,7 +156,6 @@ class PembiayaanOnlineController extends Controller
|
||||
'kodbank' => $request->input('kodbank'),
|
||||
'noakaun' => $request->input('noakaun'),
|
||||
'nama_bank' => $request->input('nama_bank'),
|
||||
'nama_akaun' => $request->input('nama_akaun'),
|
||||
'nota' => $request->input('nota'),
|
||||
'update_customer_bank' => true,
|
||||
];
|
||||
@@ -174,6 +173,19 @@ class PembiayaanOnlineController extends Controller
|
||||
$payload['bukti_akaun_type'] = $file->getMimeType() ?: 'application/octet-stream';
|
||||
}
|
||||
|
||||
if ($request->hasFile('borang')) {
|
||||
$file = $request->file('borang');
|
||||
if (!$file->isValid()) {
|
||||
return redirect()->back()->with('error', 'Fail borang pengesahan tidak sah.');
|
||||
}
|
||||
if ($file->getSize() > 4 * 1024 * 1024) {
|
||||
return redirect()->back()->with('error', 'Saiz fail maksimum 4MB.');
|
||||
}
|
||||
$payload['borang_data'] = base64_encode(file_get_contents($file->getRealPath()));
|
||||
$payload['borang_filename'] = $file->getClientOriginalName();
|
||||
$payload['borang_type'] = $file->getMimeType() ?: 'application/octet-stream';
|
||||
}
|
||||
|
||||
$res = $this->api()
|
||||
->asForm()
|
||||
->put($api_url . '/api/pembiayaan-online/' . $kodcaw . '/lines/' . $id, $payload);
|
||||
@@ -394,6 +406,22 @@ class PembiayaanOnlineController extends Controller
|
||||
return $this->streamBase64File($file, 'slip-bank-' . $id);
|
||||
}
|
||||
|
||||
/**
|
||||
* PC: view uploaded Borang Pengesahan Penerimaan Pembiayaan Secara Atas Talian.
|
||||
*/
|
||||
public function viewBorang($id)
|
||||
{
|
||||
$this->abortUnlessPembiayaanOnline();
|
||||
return $this->streamLineFile(
|
||||
$this->kodcaw(),
|
||||
$id,
|
||||
'/borang',
|
||||
'Borang pengesahan tidak dijumpai.',
|
||||
'Fail borang pengesahan kosong.',
|
||||
'borang-pengesahan-' . $id
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* PC: view SAG for a queue line (does not mark SAG as printed).
|
||||
*/
|
||||
@@ -426,6 +454,21 @@ class PembiayaanOnlineController extends Controller
|
||||
return $this->streamBase64File($file, 'slip-bank-' . $id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Operasi: view uploaded Borang Pengesahan Penerimaan Pembiayaan Secara Atas Talian.
|
||||
*/
|
||||
public function operasiViewBorang($kodcaw, $id)
|
||||
{
|
||||
return $this->streamLineFile(
|
||||
$kodcaw,
|
||||
$id,
|
||||
'/borang',
|
||||
'Borang pengesahan tidak dijumpai.',
|
||||
'Fail borang pengesahan kosong.',
|
||||
'borang-pengesahan-' . $id
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Operasi: view SAG for a batch line.
|
||||
*/
|
||||
@@ -434,6 +477,26 @@ class PembiayaanOnlineController extends Controller
|
||||
return $this->renderLineSag($kodcaw, $id);
|
||||
}
|
||||
|
||||
protected function streamLineFile($kodcaw, $id, $path, $missingMessage, $emptyMessage, $fallbackName)
|
||||
{
|
||||
$res = $this->api()
|
||||
->get(config('api.url') . '/api/pembiayaan-online/' . $kodcaw . '/lines/' . $id . $path);
|
||||
|
||||
if (!$res->successful()) {
|
||||
$body = $res->json();
|
||||
$msg = is_array($body) && isset($body['message']) ? $body['message'] : $missingMessage;
|
||||
return redirect()->back()->with('error', $msg);
|
||||
}
|
||||
|
||||
$payload = $res->json();
|
||||
$file = $payload['file'] ?? null;
|
||||
if (!$file || empty($file['data'])) {
|
||||
return redirect()->back()->with('error', $emptyMessage);
|
||||
}
|
||||
|
||||
return $this->streamBase64File($file, $fallbackName);
|
||||
}
|
||||
|
||||
protected function streamBase64File(array $file, $fallbackName)
|
||||
{
|
||||
$raw = $file['data'];
|
||||
@@ -533,6 +596,10 @@ class PembiayaanOnlineController extends Controller
|
||||
$kuantiti = $nilai > 0 ? ((float) ($gadai_detail['pinjaman'] ?? 0) / $nilai) : 0;
|
||||
|
||||
if (($gadai_detail['tagbaru'] ?? 0) == 1) {
|
||||
$cawangan_info = $this->api()
|
||||
->get($api_url . '/api/cawangan/' . $kodcaw)->json();
|
||||
$pembiayaanOnlineEnabled = !empty(($cawangan_info['features'] ?? [])['pembiayaan_online']);
|
||||
|
||||
return view('print.sag_ujrah_3', compact(
|
||||
'komoditi',
|
||||
'product',
|
||||
@@ -547,7 +614,7 @@ class PembiayaanOnlineController extends Controller
|
||||
'mutu',
|
||||
'kadar_ujrah',
|
||||
'kakitangan'
|
||||
));
|
||||
))->with('pembiayaanOnlineEnabled', $pembiayaanOnlineEnabled);
|
||||
}
|
||||
|
||||
return view('print.sag', compact(
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
|
||||
class LogViewerPassword
|
||||
{
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
$passwordHash = config('logviewer.password');
|
||||
|
||||
if (!is_string($passwordHash) || $passwordHash === '') {
|
||||
return response('Akses log belum dikonfigurasi.', 503)
|
||||
->header('Cache-Control', 'no-store');
|
||||
}
|
||||
|
||||
$provided = $request->getPassword();
|
||||
if ($request->getUser() !== 'logviewer' || !is_string($provided) ||
|
||||
!password_verify($provided, $passwordHash)) {
|
||||
return response('Kata laluan diperlukan untuk mengakses log.', 401, [
|
||||
'WWW-Authenticate' => 'Basic realm="Log Viewer", charset="UTF-8"',
|
||||
'Cache-Control' => 'no-store',
|
||||
]);
|
||||
}
|
||||
|
||||
$response = $next($request);
|
||||
$response->headers->set('Cache-Control', 'no-store');
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
@@ -45,6 +45,12 @@ class RoleAccess
|
||||
}
|
||||
break;
|
||||
|
||||
case 'masteradmin':
|
||||
if ($userRole == 'masteradmin') {
|
||||
return $next($request);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'penilai':
|
||||
if ($userRole == 'penilai') {
|
||||
return $next($request);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'password' => env('LOGVIEWER_PASSWORD'),
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Pattern and storage path settings
|
||||
|
||||
+3
-10
@@ -5,6 +5,8 @@ services:
|
||||
dockerfile: docker/php/Dockerfile
|
||||
target: development
|
||||
working_dir: /var/www/html
|
||||
ports:
|
||||
- "8081:8000"
|
||||
volumes:
|
||||
- ./:/var/www/html:cached
|
||||
environment:
|
||||
@@ -15,16 +17,7 @@ services:
|
||||
- "host.docker.internal:host-gateway"
|
||||
depends_on:
|
||||
- mysql
|
||||
|
||||
web:
|
||||
image: nginx:1.25-alpine
|
||||
ports:
|
||||
- "8081:80"
|
||||
volumes:
|
||||
- ./:/var/www/html:cached
|
||||
- ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
|
||||
depends_on:
|
||||
- app
|
||||
command: ["php", "artisan", "serve", "--host=0.0.0.0", "--port=8000"]
|
||||
|
||||
mysql:
|
||||
image: mysql:8.0
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
APP_NAME=Laravel
|
||||
APP_ENV=local
|
||||
APP_KEY=base64:FFRogE6mJj8FaDSSHl/KpXpzqi2M+P4plxVSRgVM8JI=
|
||||
APP_DEBUG=true
|
||||
APP_URL=http://kaunterv2.localhost
|
||||
API_URL=http://apiv2.localhost
|
||||
API_ARRAHNBID=http://lelong.localhost/api/
|
||||
|
||||
LOG_CHANNEL=stack
|
||||
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=database_zone2
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=kaunterpkb
|
||||
DB_USERNAME=root
|
||||
DB_PASSWORD=secret
|
||||
|
||||
BROADCAST_DRIVER=pusher
|
||||
CACHE_DRIVER=file
|
||||
QUEUE_CONNECTION=sync
|
||||
SESSION_DRIVER=file
|
||||
SESSION_LIFETIME=120
|
||||
|
||||
REDIS_HOST=127.0.0.1
|
||||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
PUSHER_APP_ID=1132718
|
||||
PUSHER_APP_KEY=26b0ec2f297f94b7aa9b
|
||||
PUSHER_APP_SECRET=421b61fb5a8ecce477a6
|
||||
|
||||
MAIL_MAILER=smtp
|
||||
MAIL_HOST=smtp.mailtrap.io
|
||||
MAIL_PORT=2525
|
||||
MAIL_USERNAME=null
|
||||
MAIL_PASSWORD=null
|
||||
MAIL_ENCRYPTION=null
|
||||
MAIL_FROM_ADDRESS=null
|
||||
MAIL_FROM_NAME="${APP_NAME}"
|
||||
|
||||
AWS_ACCESS_KEY_ID=
|
||||
AWS_SECRET_ACCESS_KEY=
|
||||
AWS_DEFAULT_REGION=us-east-1
|
||||
AWS_BUCKET=
|
||||
|
||||
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
|
||||
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
|
||||
|
||||
MYKAD_READER_PORT=8085
|
||||
MYKAD_READER_ENABLED_CAWANGAN='' # IF NO CAWANGAN STATED, ALL CAWANGAN IS ENABLED
|
||||
@@ -1,50 +0,0 @@
|
||||
APP_NAME=Laravel
|
||||
APP_ENV=local
|
||||
APP_KEY=base64:FFRogE6mJj8FaDSSHl/KpXpzqi2M+P4plxVSRgVM8JI=
|
||||
APP_DEBUG=true
|
||||
APP_URL=http://kaunterv2.localhost
|
||||
API_URL=http://apiv2.kgmk.localhost
|
||||
API_ARRAHNBID=http://lelong.localhost/api/
|
||||
|
||||
LOG_CHANNEL=stack
|
||||
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=database_zone_franchise
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=kaunter_koopguru
|
||||
DB_USERNAME=root
|
||||
DB_PASSWORD=secret
|
||||
|
||||
BROADCAST_DRIVER=pusher
|
||||
CACHE_DRIVER=file
|
||||
QUEUE_CONNECTION=sync
|
||||
SESSION_DRIVER=file
|
||||
SESSION_LIFETIME=120
|
||||
|
||||
REDIS_HOST=127.0.0.1
|
||||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
PUSHER_APP_ID=1132718
|
||||
PUSHER_APP_KEY=26b0ec2f297f94b7aa9b
|
||||
PUSHER_APP_SECRET=421b61fb5a8ecce477a6
|
||||
|
||||
MAIL_MAILER=smtp
|
||||
MAIL_HOST=smtp.mailtrap.io
|
||||
MAIL_PORT=2525
|
||||
MAIL_USERNAME=null
|
||||
MAIL_PASSWORD=null
|
||||
MAIL_ENCRYPTION=null
|
||||
MAIL_FROM_ADDRESS=null
|
||||
MAIL_FROM_NAME="${APP_NAME}"
|
||||
|
||||
AWS_ACCESS_KEY_ID=
|
||||
AWS_SECRET_ACCESS_KEY=
|
||||
AWS_DEFAULT_REGION=us-east-1
|
||||
AWS_BUCKET=
|
||||
|
||||
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
|
||||
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
|
||||
|
||||
MYKAD_READER_PORT=8085
|
||||
MYKAD_READER_ENABLED_CAWANGAN='' # IF NO CAWANGAN STATED, ALL CAWANGAN IS ENABLED
|
||||
@@ -1,50 +0,0 @@
|
||||
APP_NAME=Laravel
|
||||
APP_ENV=local
|
||||
APP_KEY=base64:FFRogE6mJj8FaDSSHl/KpXpzqi2M+P4plxVSRgVM8JI=
|
||||
APP_DEBUG=true
|
||||
APP_URL=http://kaunterv2.localhost
|
||||
API_URL=http://apiv2.krk.localhost
|
||||
API_ARRAHNBID=http://lelong.localhost/api/
|
||||
|
||||
LOG_CHANNEL=stack
|
||||
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=database_zone_franchise
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=kaunter_krk
|
||||
DB_USERNAME=root
|
||||
DB_PASSWORD=secret
|
||||
|
||||
BROADCAST_DRIVER=pusher
|
||||
CACHE_DRIVER=file
|
||||
QUEUE_CONNECTION=sync
|
||||
SESSION_DRIVER=file
|
||||
SESSION_LIFETIME=120
|
||||
|
||||
REDIS_HOST=127.0.0.1
|
||||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
PUSHER_APP_ID=1132718
|
||||
PUSHER_APP_KEY=26b0ec2f297f94b7aa9b
|
||||
PUSHER_APP_SECRET=421b61fb5a8ecce477a6
|
||||
|
||||
MAIL_MAILER=smtp
|
||||
MAIL_HOST=smtp.mailtrap.io
|
||||
MAIL_PORT=2525
|
||||
MAIL_USERNAME=null
|
||||
MAIL_PASSWORD=null
|
||||
MAIL_ENCRYPTION=null
|
||||
MAIL_FROM_ADDRESS=null
|
||||
MAIL_FROM_NAME="${APP_NAME}"
|
||||
|
||||
AWS_ACCESS_KEY_ID=
|
||||
AWS_SECRET_ACCESS_KEY=
|
||||
AWS_DEFAULT_REGION=us-east-1
|
||||
AWS_BUCKET=
|
||||
|
||||
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
|
||||
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
|
||||
|
||||
MYKAD_READER_PORT=8085
|
||||
MYKAD_READER_ENABLED_CAWANGAN='' # IF NO CAWANGAN STATED, ALL CAWANGAN IS ENABLED
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 166 KiB |
@@ -115,6 +115,9 @@
|
||||
</form>
|
||||
</div>
|
||||
<div class="card-footer text-center pt-0 px-lg-2 px-1">
|
||||
<p class="mb-3 text-sm">
|
||||
<a href="{{ route('dasar.privasi') }}" class="text-info font-weight-bold">Dasar Privasi</a>
|
||||
</p>
|
||||
<p class="mb-4 text-sm mx-auto">
|
||||
Masalah untuk log masuk?
|
||||
<a class="text-info text-gradient font-weight-bold">Hubungi
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<div class="ic-scan-register-field px-3 pb-2">
|
||||
<div class="row form-group mb-0">
|
||||
<div class="col-md-4">
|
||||
Scan IC / Passport <span class="text-danger">*</span>
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<input class="form-control-file"
|
||||
type="file"
|
||||
name="scan_ic"
|
||||
id="{{ $scanFieldId }}"
|
||||
accept=".jpg,.jpeg,.png,.pdf,image/jpeg,image/png,application/pdf">
|
||||
<small class="form-text text-muted">Wajib. JPG, PNG atau PDF (maks 4MB).</small>
|
||||
<div class="ic-scan-register-preview mt-2 d-none">
|
||||
<img src="" alt="Preview scan IC" style="max-width:180px;max-height:120px;object-fit:contain;border:1px solid #d0d5dd;border-radius:4px;background:#fff;">
|
||||
<span class="ic-scan-register-filename small text-muted d-block"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,80 @@
|
||||
<script>
|
||||
function requireScanIcFromForm(formEl, submitSelector) {
|
||||
var input = formEl ? formEl.querySelector('input[name="scan_ic"]') : null;
|
||||
var file = input && input.files && input.files[0] ? input.files[0] : null;
|
||||
if (!file) {
|
||||
$(submitSelector).prop('disabled', false);
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Amaran!',
|
||||
text: 'Sila muat naik scan dokumen IC / Passport'
|
||||
});
|
||||
if (typeof event !== 'undefined' && event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (file.size > 4 * 1024 * 1024) {
|
||||
$(submitSelector).prop('disabled', false);
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Amaran!',
|
||||
text: 'Saiz fail scan IC maksimum 4MB'
|
||||
});
|
||||
if (typeof event !== 'undefined' && event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
var type = (file.type || '').toLowerCase();
|
||||
if (['image/jpeg', 'image/jpg', 'image/png', 'application/pdf'].indexOf(type) === -1) {
|
||||
$(submitSelector).prop('disabled', false);
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Amaran!',
|
||||
text: 'Format fail mestilah JPG, PNG atau PDF'
|
||||
});
|
||||
if (typeof event !== 'undefined' && event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
$(document).on('change', 'input[name="scan_ic"]', function () {
|
||||
var file = this.files && this.files[0] ? this.files[0] : null;
|
||||
var wrap = this.closest('.ic-scan-register-field');
|
||||
if (!wrap) {
|
||||
return;
|
||||
}
|
||||
var preview = wrap.querySelector('.ic-scan-register-preview');
|
||||
var img = wrap.querySelector('.ic-scan-register-preview img');
|
||||
var nameEl = wrap.querySelector('.ic-scan-register-filename');
|
||||
if (!file) {
|
||||
if (preview) {
|
||||
preview.classList.add('d-none');
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (preview) {
|
||||
preview.classList.remove('d-none');
|
||||
}
|
||||
if (nameEl) {
|
||||
nameEl.textContent = file.name;
|
||||
}
|
||||
if (!img) {
|
||||
return;
|
||||
}
|
||||
if ((file.type || '') === 'application/pdf') {
|
||||
img.classList.add('d-none');
|
||||
return;
|
||||
}
|
||||
img.classList.remove('d-none');
|
||||
var reader = new FileReader();
|
||||
reader.onload = function (e) {
|
||||
img.src = e.target.result;
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,204 @@
|
||||
@php
|
||||
$hasScanIc = !empty($customer_info['has_scan_ic']);
|
||||
$scanIcMime = strtolower((string) ($customer_info['scan_ic_mime'] ?? ''));
|
||||
$scanIcIsPdf = strpos($scanIcMime, 'pdf') !== false;
|
||||
$scanIcNoic = !empty($customer_info['kpbaru']) ? $customer_info['kpbaru'] : ($customer_info['kplama'] ?? '');
|
||||
$scanIcPreviewUrl = $hasScanIc
|
||||
? route('customer.showIcScan', ['icno' => $scanIcNoic, 't' => $customer_info['scan_ic'] ?? time()])
|
||||
: '';
|
||||
@endphp
|
||||
|
||||
<style>
|
||||
.ic-scan-card {
|
||||
border: 1px dashed #c5cdd6;
|
||||
border-radius: 8px;
|
||||
background: #f8f9fb;
|
||||
padding: 16px;
|
||||
margin: 0 15px 18px;
|
||||
}
|
||||
.ic-scan-card.is-missing {
|
||||
border-color: #e0a800;
|
||||
background: #fff8e8;
|
||||
}
|
||||
.ic-scan-preview {
|
||||
max-width: 220px;
|
||||
max-height: 140px;
|
||||
object-fit: contain;
|
||||
border: 1px solid #d0d5dd;
|
||||
border-radius: 4px;
|
||||
background: #fff;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="ic-scan-card" class="ic-scan-card {{ $hasScanIc ? '' : 'is-missing' }}">
|
||||
<div class="d-flex flex-wrap align-items-start justify-content-between">
|
||||
<div>
|
||||
<b>Scan Dokumen IC / Passport <span class="text-danger">*</span></b>
|
||||
<div class="text-muted small mt-1">
|
||||
Wajib dimuat naik sebelum daftar pembiayaan. Format JPG, PNG atau PDF (maks 4MB).
|
||||
</div>
|
||||
<div id="ic-scan-status" class="mt-2">
|
||||
@if ($hasScanIc)
|
||||
<span class="badge badge-success">Telah dimuat naik</span>
|
||||
@else
|
||||
<span class="badge badge-warning">Belum dimuat naik</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-2 mt-md-0">
|
||||
<input type="file" id="ic_scan_file" accept=".jpg,.jpeg,.png,.pdf,image/jpeg,image/png,application/pdf" class="d-none">
|
||||
<button type="button" class="btn btn-outline-primary btn-sm" id="ic_scan_pick">
|
||||
<i class="fas fa-upload mr-1"></i>{{ $hasScanIc ? 'Muat naik semula' : 'Pilih fail' }}
|
||||
</button>
|
||||
<button type="button" class="btn btn-primary btn-sm d-none" id="ic_scan_upload">Muat Naik</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="ic-scan-preview-wrap" class="mt-3 {{ $hasScanIc ? '' : 'd-none' }}">
|
||||
@if ($hasScanIc && $scanIcIsPdf)
|
||||
<a id="ic-scan-pdf-link" href="{{ $scanIcPreviewUrl }}" target="_blank" rel="noopener">Lihat fail PDF</a>
|
||||
<img id="ic-scan-preview-img" src="" alt="Preview scan IC" class="ic-scan-preview d-none">
|
||||
@else
|
||||
<a id="ic-scan-pdf-link" href="{{ $scanIcPreviewUrl }}" target="_blank" rel="noopener" class="{{ $hasScanIc ? 'd-none' : 'd-none' }}">Lihat fail PDF</a>
|
||||
<img id="ic-scan-preview-img"
|
||||
src="{{ $hasScanIc ? $scanIcPreviewUrl : '' }}"
|
||||
alt="Preview scan IC"
|
||||
class="ic-scan-preview {{ $hasScanIc ? '' : 'd-none' }}">
|
||||
@endif
|
||||
<div id="ic-scan-filename" class="small text-muted mt-1">{{ $customer_info['scan_ic_filename'] ?? '' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
window.hasScanIc = @json($hasScanIc);
|
||||
|
||||
(function() {
|
||||
var fileInput = document.getElementById('ic_scan_file');
|
||||
var pickBtn = document.getElementById('ic_scan_pick');
|
||||
var uploadBtn = document.getElementById('ic_scan_upload');
|
||||
var previewWrap = document.getElementById('ic-scan-preview-wrap');
|
||||
var previewImg = document.getElementById('ic-scan-preview-img');
|
||||
var pdfLink = document.getElementById('ic-scan-pdf-link');
|
||||
var filenameEl = document.getElementById('ic-scan-filename');
|
||||
var statusEl = document.getElementById('ic-scan-status');
|
||||
var card = document.getElementById('ic-scan-card');
|
||||
var selectedFile = null;
|
||||
var storeUrl = @json(route('customer.storeIcScan'));
|
||||
var previewUrl = @json(route('customer.showIcScan', ['icno' => $scanIcNoic]));
|
||||
var csrf = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
|
||||
var icno = @json($scanIcNoic);
|
||||
|
||||
function showUploadedState(filename, mime) {
|
||||
window.hasScanIc = true;
|
||||
card.classList.remove('is-missing');
|
||||
statusEl.innerHTML = '<span class="badge badge-success">Telah dimuat naik</span>';
|
||||
pickBtn.innerHTML = '<i class="fas fa-upload mr-1"></i>Muat naik semula';
|
||||
uploadBtn.classList.add('d-none');
|
||||
previewWrap.classList.remove('d-none');
|
||||
filenameEl.textContent = filename || '';
|
||||
var url = previewUrl + (previewUrl.indexOf('?') === -1 ? '?' : '&') + 't=' + Date.now();
|
||||
if ((mime || '').indexOf('pdf') !== -1) {
|
||||
previewImg.classList.add('d-none');
|
||||
pdfLink.classList.remove('d-none');
|
||||
pdfLink.setAttribute('href', url);
|
||||
} else {
|
||||
pdfLink.classList.add('d-none');
|
||||
previewImg.classList.remove('d-none');
|
||||
previewImg.src = url;
|
||||
}
|
||||
}
|
||||
|
||||
pickBtn.addEventListener('click', function() {
|
||||
fileInput.click();
|
||||
});
|
||||
|
||||
fileInput.addEventListener('change', function() {
|
||||
selectedFile = fileInput.files && fileInput.files[0] ? fileInput.files[0] : null;
|
||||
if (!selectedFile) {
|
||||
uploadBtn.classList.add('d-none');
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedFile.size > 4 * 1024 * 1024) {
|
||||
selectedFile = null;
|
||||
fileInput.value = '';
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Fail terlalu besar',
|
||||
text: 'Saiz fail maksimum 4MB.'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
uploadBtn.classList.remove('d-none');
|
||||
previewWrap.classList.remove('d-none');
|
||||
filenameEl.textContent = selectedFile.name;
|
||||
|
||||
if (selectedFile.type === 'application/pdf') {
|
||||
previewImg.classList.add('d-none');
|
||||
pdfLink.classList.remove('d-none');
|
||||
pdfLink.setAttribute('href', URL.createObjectURL(selectedFile));
|
||||
} else {
|
||||
pdfLink.classList.add('d-none');
|
||||
previewImg.classList.remove('d-none');
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
previewImg.src = e.target.result;
|
||||
};
|
||||
reader.readAsDataURL(selectedFile);
|
||||
}
|
||||
});
|
||||
|
||||
uploadBtn.addEventListener('click', function() {
|
||||
if (!selectedFile) {
|
||||
Swal.fire({
|
||||
icon: 'warning',
|
||||
title: 'Tiada fail',
|
||||
text: 'Sila pilih scan dokumen IC terlebih dahulu.'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
var formData = new FormData();
|
||||
formData.append('icno', icno);
|
||||
formData.append('scan_ic', selectedFile);
|
||||
|
||||
uploadBtn.disabled = true;
|
||||
uploadBtn.textContent = 'Memuat naik...';
|
||||
|
||||
fetch(storeUrl, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': csrf,
|
||||
'Accept': 'application/json'
|
||||
},
|
||||
body: formData
|
||||
}).then(function(res) {
|
||||
return res.json().then(function(body) {
|
||||
return { ok: res.ok, body: body };
|
||||
});
|
||||
}).then(function(result) {
|
||||
uploadBtn.disabled = false;
|
||||
uploadBtn.textContent = 'Muat Naik';
|
||||
if (!result.ok || !result.body || !result.body.stored) {
|
||||
throw new Error((result.body && (result.body.error || result.body.message)) || 'Gagal memuat naik scan IC.');
|
||||
}
|
||||
showUploadedState(selectedFile.name, selectedFile.type);
|
||||
selectedFile = null;
|
||||
fileInput.value = '';
|
||||
Swal.fire({
|
||||
icon: 'success',
|
||||
title: 'Berjaya',
|
||||
text: 'Scan dokumen IC telah dimuat naik.'
|
||||
});
|
||||
}).catch(function(err) {
|
||||
uploadBtn.disabled = false;
|
||||
uploadBtn.textContent = 'Muat Naik';
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Tidak berjaya',
|
||||
text: err.message || 'Gagal memuat naik scan IC.'
|
||||
});
|
||||
});
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
@@ -21,6 +21,9 @@
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
@if(session()->has('error'))
|
||||
<div class="alert alert-danger">{{ session('error') }}</div>
|
||||
@endif
|
||||
<div class="text-center">
|
||||
<h5 class="text-uppercase">masukkan nombor kad pengenalan</h5>
|
||||
<form name="frmsearch" onsubmit="verifynokp()" action="{{ route('customer.search') }}" method="GET">
|
||||
@@ -84,7 +87,7 @@
|
||||
<h5 class="modal-title" id="ModalLabel">Daftar Pelanggan</h5>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form action="{{ route('customer.store') }}" onsubmit="verifycustomer()" method="POST">
|
||||
<form action="{{ route('customer.store') }}" onsubmit="verifycustomer()" method="POST" enctype="multipart/form-data">
|
||||
@csrf
|
||||
<div class="row form-group">
|
||||
<div class="col-md-6">
|
||||
@@ -195,7 +198,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@include('customers.partials.ic_scan_register_field', ['scanFieldId' => 'scan_ic_manual'])
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<input type="text" hidden name="idtype" value="nokp">
|
||||
@@ -210,7 +213,7 @@
|
||||
<div class="modal fade" id="daftar_pelanggan_mykad_reader" tabindex="-1" data-backdrop="static" aria-labelledby="ModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<form id="form-mykad-reader" action="{{ route('customer.store') }}" onsubmit="verifycustomerMyKadReader()" method="POST">
|
||||
<form id="form-mykad-reader" action="{{ route('customer.store') }}" onsubmit="verifycustomerMyKadReader()" method="POST" enctype="multipart/form-data">
|
||||
@csrf
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="ModalLabel">Daftar Pelanggan</h5>
|
||||
@@ -336,7 +339,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@include('customers.partials.ic_scan_register_field', ['scanFieldId' => 'scan_ic_mykad'])
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<input type="text" hidden name="idtype" value="nokp">
|
||||
@@ -355,7 +358,7 @@
|
||||
<h5 class="modal-title" id="ModalLabel">Daftar Pelanggan</h5>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form action="{{ route('customer.store') }}" onsubmit="verifycustomerpassport()" method="POST">
|
||||
<form action="{{ route('customer.store') }}" onsubmit="verifycustomerpassport()" method="POST" enctype="multipart/form-data">
|
||||
@csrf
|
||||
<div class="row form-group">
|
||||
<div class="col-md-6">
|
||||
@@ -461,6 +464,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@include('customers.partials.ic_scan_register_field', ['scanFieldId' => 'scan_ic_passport'])
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<input type="text" hidden name="idtype" value="passport">
|
||||
@@ -474,6 +478,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@include('customers.partials.ic_scan_register_script')
|
||||
<script>
|
||||
var api_url = "{{ api_url_for_browser() }}";
|
||||
var search = "<?php echo $search ?>";
|
||||
@@ -550,15 +555,20 @@
|
||||
file.trigger("click");
|
||||
});
|
||||
$('input[type="file"]').change(function(e) {
|
||||
if (this.name === 'scan_ic' || !e.target.files || !e.target.files[0]) {
|
||||
return;
|
||||
}
|
||||
var fileName = e.target.files[0].name;
|
||||
$("#file").val(fileName);
|
||||
|
||||
var preview = document.getElementById("preview");
|
||||
if (!preview) {
|
||||
return;
|
||||
}
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
// get loaded data and render thumbnail.
|
||||
document.getElementById("preview").src = e.target.result;
|
||||
preview.src = e.target.result;
|
||||
};
|
||||
// read the image file as a data URL.
|
||||
reader.readAsDataURL(this.files[0]);
|
||||
});
|
||||
|
||||
@@ -808,6 +818,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!requireScanIcFromForm(document.querySelector('#daftar_pelanggan form'), '#daftar_pelanggan #terima_ic')) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -950,6 +963,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!requireScanIcFromForm(document.getElementById('form-mykad-reader'), '#daftar_pelanggan_mykad_reader #terima_ic')) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1090,6 +1106,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!requireScanIcFromForm(document.querySelector('#passport_pelanggan form'), '#terima_passport')) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,9 @@
|
||||
@if(session()->has('message'))
|
||||
<div class="alert alert-success">{{ session('message') }}</div>
|
||||
@endif
|
||||
@if(session()->has('error'))
|
||||
<div class="alert alert-danger">{{ session('error') }}</div>
|
||||
@endif
|
||||
|
||||
@if(!empty($customer_info['photo_base64']))
|
||||
<div class="form-group row col-md-12">
|
||||
@@ -37,6 +40,8 @@
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@include('customers.partials.ic_scan_upload')
|
||||
|
||||
<div class="form-group row col-md-12">
|
||||
<div class="col-md-6">
|
||||
<div class="form-group row">
|
||||
@@ -443,6 +448,14 @@
|
||||
var tagarrahnbid = "{{ $cawangan_info['tagarrahnbid'] }}";
|
||||
var min_komoditi = "{{ $min_komoditi }}";
|
||||
$('#daftar_gadai').on('click',function(){
|
||||
if (!window.hasScanIc) {
|
||||
Swal.fire({
|
||||
icon: 'warning',
|
||||
title: 'Scan IC diperlukan',
|
||||
text: 'Sila muat naik scan dokumen IC sebelum daftar pembiayaan.'
|
||||
});
|
||||
return;
|
||||
}
|
||||
$("#daftar_gadai").prop('disabled', true);
|
||||
var noic = $('#noic').val();
|
||||
var iclama = "{{ $customer_info['kplama'] }}";
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
@if(session()->has('error'))
|
||||
<div class="alert alert-danger">{{ session('error') }}</div>
|
||||
@endif
|
||||
<div class="text-center">
|
||||
<h5 class="text-uppercase">masukkan nombor kad pengenalan</h5>
|
||||
<form name="frmsearch" onsubmit="verifynokp()" action="{{ route('customer.search') }}" method="GET">
|
||||
@@ -102,7 +105,7 @@
|
||||
<h5 class="modal-title" id="ModalLabel">Daftar Pelanggan</h5>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form name="form-store" action="{{ route('customer.store') }}" onsubmit="verifycustomer()" method="POST">
|
||||
<form name="form-store" action="{{ route('customer.store') }}" onsubmit="verifycustomer()" method="POST" enctype="multipart/form-data">
|
||||
@csrf
|
||||
<div class="row form-group">
|
||||
<div class="col-md-6">
|
||||
@@ -215,6 +218,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@include('customers.partials.ic_scan_register_field', ['scanFieldId' => 'scan_ic_manual'])
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<input type="text" hidden name="idtype" value="nokp">
|
||||
@@ -229,7 +233,7 @@
|
||||
<div class="modal fade" id="daftar_pelanggan_mykad_reader" tabindex="-1" data-backdrop="static" aria-labelledby="ModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<form id="form-mykad-reader" action="{{ route('customer.store') }}" onsubmit="verifycustomerMyKadReader()" method="POST">
|
||||
<form id="form-mykad-reader" action="{{ route('customer.store') }}" onsubmit="verifycustomerMyKadReader()" method="POST" enctype="multipart/form-data">
|
||||
@csrf
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="ModalLabel">Daftar Pelanggan</h5>
|
||||
@@ -356,7 +360,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@include('customers.partials.ic_scan_register_field', ['scanFieldId' => 'scan_ic_mykad'])
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<input type="text" hidden name="idtype" value="nokp">
|
||||
@@ -375,7 +379,7 @@
|
||||
<h5 class="modal-title" id="ModalLabel">Daftar Pelanggan</h5>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form name="form-store" action="{{ route('customer.store') }}" onsubmit="verifycustomerpassport()" method="POST">
|
||||
<form name="form-store" action="{{ route('customer.store') }}" onsubmit="verifycustomerpassport()" method="POST" enctype="multipart/form-data">
|
||||
@csrf
|
||||
<div class="row form-group">
|
||||
<div class="col-md-6">
|
||||
@@ -482,6 +486,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@include('customers.partials.ic_scan_register_field', ['scanFieldId' => 'scan_ic_passport'])
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<input type="text" hidden name="idtype" value="passport">
|
||||
@@ -496,6 +501,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@include('customers.partials.ic_scan_register_script')
|
||||
<script>
|
||||
var isAnggota = @json($isAnggota ?? false);
|
||||
var isPelanggan = @json($isPelanggan ?? false);
|
||||
@@ -629,15 +635,20 @@
|
||||
file.trigger("click");
|
||||
});
|
||||
$('input[type="file"]').change(function(e) {
|
||||
if (this.name === 'scan_ic' || !e.target.files || !e.target.files[0]) {
|
||||
return;
|
||||
}
|
||||
var fileName = e.target.files[0].name;
|
||||
$("#file").val(fileName);
|
||||
|
||||
var preview = document.getElementById("preview");
|
||||
if (!preview) {
|
||||
return;
|
||||
}
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
// get loaded data and render thumbnail.
|
||||
document.getElementById("preview").src = e.target.result;
|
||||
preview.src = e.target.result;
|
||||
};
|
||||
// read the image file as a data URL.
|
||||
reader.readAsDataURL(this.files[0]);
|
||||
});
|
||||
|
||||
@@ -887,6 +898,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!requireScanIcFromForm(document.querySelector('#daftar_pelanggan form'), '#daftar_pelanggan #terima_ic')) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1029,6 +1043,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!requireScanIcFromForm(document.getElementById('form-mykad-reader'), '#daftar_pelanggan_mykad_reader #terima_ic')) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1169,6 +1186,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!requireScanIcFromForm(document.querySelector('#passport_pelanggan form'), '#terima_passport')) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
@if(session()->has('message'))
|
||||
<div class="alert alert-success">{{ session('message') }}</div>
|
||||
@endif
|
||||
@if(session()->has('error'))
|
||||
<div class="alert alert-danger">{{ session('error') }}</div>
|
||||
@endif
|
||||
|
||||
@if(!empty($customer_info['photo_base64']))
|
||||
<div class="form-group row col-md-12">
|
||||
@@ -38,6 +41,8 @@
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@include('customers.partials.ic_scan_upload')
|
||||
|
||||
<div class="form-group row col-md-12">
|
||||
<div class="col-md-6">
|
||||
<div class="form-group row">
|
||||
@@ -723,6 +728,14 @@
|
||||
if ($(this).prop('disabled')) {
|
||||
return;
|
||||
}
|
||||
if (!window.hasScanIc) {
|
||||
Swal.fire({
|
||||
icon: 'warning',
|
||||
title: 'Scan IC diperlukan',
|
||||
text: 'Sila muat naik scan dokumen IC sebelum daftar pembiayaan.'
|
||||
});
|
||||
return;
|
||||
}
|
||||
$("#daftar_gadai").prop('disabled', true);
|
||||
|
||||
var bakiLelong = Number(@json((float) $bakilelong));
|
||||
@@ -801,9 +814,12 @@
|
||||
}
|
||||
});
|
||||
|
||||
var pembiayaanOnlineEnabled = @json(!empty(($cawangan_info['features'] ?? [])['pembiayaan_online']));
|
||||
|
||||
var tablegadai = initErahnDatatable('#myTable', {
|
||||
order: [[1, 'desc']],
|
||||
columnDefs: [
|
||||
{ targets: 2, visible: pembiayaanOnlineEnabled, className: pembiayaanOnlineEnabled ? '' : 'no-export' },
|
||||
{ targets: 0, orderable: false, width: '40px' },
|
||||
{ targets: -1, orderable: false, searchable: false, width: '70px' }
|
||||
]
|
||||
@@ -811,6 +827,7 @@
|
||||
|
||||
var xtawarruq = initErahnDatatable('#xtawarruq', {
|
||||
columnDefs: [
|
||||
{ targets: 2, visible: pembiayaanOnlineEnabled, className: pembiayaanOnlineEnabled ? '' : 'no-export' },
|
||||
{ targets: 0, orderable: false, width: '40px' }
|
||||
]
|
||||
});
|
||||
@@ -2067,7 +2084,8 @@
|
||||
harini.setHours(0, 0, 0, 0);
|
||||
|
||||
if ($("input[name='options']:checked").val() == 'belum_tebus') {
|
||||
let test1 = $('input[name="belum"]:checked').closest('tr').children('td:eq(2)').text();
|
||||
let selectedRow = $('input[name="belum"]:checked').closest('tr');
|
||||
let test1 = selectedRow.length ? selectedRow.closest('table').DataTable().row(selectedRow).data()[3] : '';
|
||||
let tarikhgadai2 = new Date(test1);
|
||||
tarikhgadai2.setHours(0, 0, 0, 0);
|
||||
if (+harini !== +tarikhgadai2) {
|
||||
@@ -2484,7 +2502,8 @@
|
||||
}
|
||||
|
||||
if ($("input[name='options']:checked").val() == 'belum_tebus') {
|
||||
let test1 = $('input[name="belum"]:checked').closest('tr').children('td:eq(2)').text();
|
||||
let selectedRow = $('input[name="belum"]:checked').closest('tr');
|
||||
let test1 = selectedRow.length ? selectedRow.closest('table').DataTable().row(selectedRow).data()[3] : '';
|
||||
let tarikhgadai2 = new Date(test1);
|
||||
tarikhgadai2.setHours(0, 0, 0, 0);
|
||||
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ms">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Dasar Privasi | Kaunter arOS</title>
|
||||
<link rel="icon" href="{{ asset('img/icon_pkb.png') }}">
|
||||
<link href="{{ asset('css/login-v2.css') }}" rel="stylesheet">
|
||||
<style>
|
||||
body { background: #f4f7fb; color: #344767; }
|
||||
.privacy-container { max-width: 900px; margin: 0 auto; padding: 32px 20px; }
|
||||
.privacy-brand { display: flex; align-items: center; gap: 16px; margin-bottom: 24px; }
|
||||
.privacy-brand img { width: 60px; height: auto; }
|
||||
.privacy-card { background: #fff; border-radius: 16px; padding: 40px; box-shadow: 0 8px 32px rgba(24, 49, 83, .08); }
|
||||
.privacy-card h1 { font-size: 2rem; }
|
||||
.privacy-card h2 { font-size: 1.2rem; margin-top: 28px; }
|
||||
.privacy-card p, .privacy-card li { line-height: 1.8; }
|
||||
.privacy-card ul { padding-left: 24px; }
|
||||
.privacy-back { display: inline-block; margin-top: 24px; color: #075985; text-decoration: underline; }
|
||||
a:focus-visible { outline: 3px solid #075985; outline-offset: 4px; }
|
||||
@media (max-width: 576px) {
|
||||
.privacy-container { padding: 20px 16px; }
|
||||
.privacy-card { padding: 24px 20px; }
|
||||
.privacy-card h1 { font-size: 1.7rem; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main class="privacy-container">
|
||||
<div class="privacy-brand">
|
||||
<img src="{{ asset('img/icon_pkb.png') }}" alt="Logo ar-Rahnu">
|
||||
<span class="font-weight-bold">Kaunter arOS · ar-rahn Online System</span>
|
||||
</div>
|
||||
<article class="privacy-card" aria-labelledby="privacy-title">
|
||||
<h1 id="privacy-title">Dasar Privasi</h1>
|
||||
<p class="text-sm text-muted">Versi dasar: 1.0 · Tarikh kemas kini: <time datetime="2026-09-27">27 September 2026</time></p>
|
||||
<h2>1. Pengenalan</h2>
|
||||
<p>Selamat datang ke sistem Kaunter arOS Koperasi Permodalan Kelantan Berhad (KoPKB). Kami amat menghargai kepercayaan yang anda berikan untuk mengendalikan maklumat peribadi anda. Dasar Privasi ini digubal untuk membantu anda memahami bagaimana kami mengumpul, menggunakan, mendedahkan dan melindungi data peribadi anda bagi urusan Ar-Rahn, dengan mengambil kira keperluan Akta Perlindungan Data Peribadi 2010 (PDPA) dan amalan keselamatan maklumat yang berkaitan.</p>
|
||||
<p>Dasar ini terpakai kepada kakitangan, pentadbir dan mana-mana pihak yang diberi kuasa untuk mengakses atau menggunakan sistem Kaunter arOS KoPKB, serta pengendalian data pelanggan dalam perkhidmatan yang diuruskan melalui sistem ini.</p>
|
||||
|
||||
<h2>2. Data yang Dikumpul</h2>
|
||||
<p>Kami mengumpul dan memproses maklumat yang berkaitan dengan urusan sistem, termasuk:</p>
|
||||
<ul>
|
||||
<li><strong>Maklumat Pengenalan Peribadi:</strong> Nama penuh, nombor pengenalan, alamat, alamat e-mel dan nombor telefon pelanggan atau pengguna.</li>
|
||||
<li><strong>Maklumat Akaun:</strong> Maklumat akaun pengguna, cawangan dan peranan akses dalam sistem.</li>
|
||||
<li><strong>Data Teknikal:</strong> Maklumat seperti alamat IP, jenis pelayar dan log aktiviti sistem yang direkodkan bagi tujuan operasi dan keselamatan.</li>
|
||||
<li><strong>Data Transaksi:</strong> Rekod pembiayaan, gadaian, maklumat marhun, pembayaran, penebusan, lelongan dan dokumen sokongan berkaitan.</li>
|
||||
</ul>
|
||||
|
||||
<h2>3. Tujuan Penggunaan Data</h2>
|
||||
<p>Data anda digunakan untuk tujuan berikut:</p>
|
||||
<ul>
|
||||
<li><strong>Operasi Sistem:</strong> Menguruskan akaun pengguna dan memproses urusan pelanggan serta transaksi Ar-Rahn.</li>
|
||||
<li><strong>Pengesahan:</strong> Mengesahkan identiti dan mengawal akses pengguna mengikut peranan serta cawangan yang dibenarkan.</li>
|
||||
<li><strong>Komunikasi:</strong> Menyampaikan notis berkaitan urusan, makluman pentadbiran dan sokongan pelanggan.</li>
|
||||
<li><strong>Pelaporan dan Penambahbaikan:</strong> Menyediakan laporan operasi, menyokong audit serta menambah baik prestasi dan kualiti sistem.</li>
|
||||
</ul>
|
||||
|
||||
<h2>4. Perkongsian & Pendedahan Data</h2>
|
||||
<p>Kami tidak menjual data peribadi anda. Akses, perkongsian atau pendedahan data dihadkan kepada keperluan urusan yang berkaitan, termasuk:</p>
|
||||
<ul>
|
||||
<li><strong>Kakitangan yang Diberi Kuasa:</strong> Kakitangan dan pentadbir KoPKB yang memerlukan maklumat untuk menjalankan tugas.</li>
|
||||
<li><strong>Pembekal Perkhidmatan:</strong> Penyedia teknologi atau perkhidmatan yang menyokong pengehosan, penyelenggaraan sistem dan pemprosesan pembayaran, jika berkaitan.</li>
|
||||
<li><strong>Pematuhan Undang-undang:</strong> Pihak berkuasa atau pihak lain apabila pendedahan diperlukan oleh undang-undang atau perintah mahkamah.</li>
|
||||
</ul>
|
||||
|
||||
<h2>5. Keselamatan Data</h2>
|
||||
<p>Langkah keselamatan teknikal dan pentadbiran digunakan untuk membantu melindungi data yang dikendalikan melalui sistem, termasuk kawalan akses mengikut peranan pengguna dan pengesahan akaun.</p>
|
||||
<p>Pengguna hendaklah mengakses sistem melalui sambungan HTTPS yang selamat, menjaga kerahsiaan kata laluan, tidak berkongsi akaun dan log keluar selepas selesai menggunakan sistem. Sebarang aktiviti yang mencurigakan hendaklah dilaporkan kepada pentadbir sistem.</p>
|
||||
|
||||
<h2>6. Hak Pengguna</h2>
|
||||
<p>Anda boleh menghubungi kami untuk mengemukakan permohonan berkaitan data peribadi anda, termasuk:</p>
|
||||
<ul>
|
||||
<li><strong>Akses & Pembetulan:</strong> Memohon semakan dan pembetulan maklumat peribadi yang tidak tepat atau tidak terkini.</li>
|
||||
<li><strong>Pemadaman:</strong> Memohon pemadaman akaun atau data dalam keadaan yang sesuai, tertakluk kepada keperluan penyimpanan rekod transaksi, audit dan undang-undang.</li>
|
||||
<li><strong>Sekatan:</strong> Memohon supaya pemprosesan data tertentu dihadkan, tertakluk kepada keperluan perkhidmatan dan kewajipan yang terpakai.</li>
|
||||
</ul>
|
||||
<p>Permohonan akan dinilai mengikut keperluan yang terpakai. Pengesahan identiti mungkin diperlukan sebelum permohonan diproses.</p>
|
||||
|
||||
<h2>7. Tempoh Penyimpanan</h2>
|
||||
<p>Data disimpan selama diperlukan untuk pengendalian urusan Ar-Rahn, penyelenggaraan rekod pembiayaan dan transaksi, audit serta pematuhan undang-undang. Selepas keperluan penyimpanan berakhir, data akan diuruskan untuk pemadaman atau penyahkenalpastian mengikut prosedur organisasi yang terpakai.</p>
|
||||
|
||||
<h2>8. Kuki & Teknologi Penjejakan</h2>
|
||||
<p>Sistem Kaunter arOS menggunakan kuki (cookies) dan sesi untuk menyokong log masuk, mengekalkan sesi pengguna dan melindungi permintaan dalam sistem. Anda boleh menguruskan pilihan kuki melalui tetapan pelayar. Menyekat kuki boleh menyebabkan fungsi tertentu, termasuk log masuk, tidak berfungsi dengan baik.</p>
|
||||
|
||||
<h2>9. Perubahan Dasar</h2>
|
||||
<p>Dasar ini boleh dikemas kini dari semasa ke semasa apabila terdapat perubahan pada perkhidmatan, pengendalian sistem atau keperluan organisasi. Versi terkini akan dipaparkan pada halaman ini. Sebarang perubahan besar akan dimaklumkan melalui e-mel atau notis dalam sistem sebelum tarikh kuat kuasa baharu.</p>
|
||||
|
||||
<h2>10. Hubungi Kami</h2>
|
||||
<p>Jika anda mempunyai pertanyaan, komen atau permohonan berkaitan dasar ini dan pengendalian data peribadi dalam sistem Kaunter arOS, sila hubungi:</p>
|
||||
<p><strong>AFRINA ALIMI</strong><br>
|
||||
Koperasi Permodalan Kelantan Berhad (KoPKB)<br>
|
||||
E-mel: <a href="mailto:afrina@koppkb.com">afrina@koppkb.com</a>
|
||||
</p>
|
||||
|
||||
<a class="privacy-back" href="{{ route('login') }}">Kembali ke Log Masuk</a>
|
||||
</article>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
@@ -74,7 +74,7 @@
|
||||
id="batch_lines"
|
||||
class="table-sm text-center"
|
||||
:filename="'Batch_' . ($batch['batch_no'] ?? $batch['id'])"
|
||||
:columns="['Bil', 'Status', 'SAG', 'Pelanggan', 'No KP', 'Bank', 'No Akaun', 'Nama Akaun', 'Pinjaman (RM)', 'Rujukan Bayaran', 'Dokumen', 'Tindakan']"
|
||||
:columns="['Bil', 'Status', 'SAG', 'Pelanggan', 'No KP', 'Bank', 'No Akaun', 'Pinjaman (RM)', 'Rujukan Bayaran', 'Dokumen', 'Tindakan']"
|
||||
:skipExport="['Dokumen', 'Tindakan']"
|
||||
>
|
||||
@foreach($lines as $line)
|
||||
@@ -94,7 +94,6 @@
|
||||
<td>{{ $line['nokp'] ?? '-' }}</td>
|
||||
<td>{{ $line['nama_bank'] ?? $line['kodbank'] ?? '-' }}</td>
|
||||
<td>{{ $line['noakaun'] ?? '-' }}</td>
|
||||
<td class="text-left">{{ $line['nama_akaun'] ?? '-' }}</td>
|
||||
<td class="text-right">{{ number_format((float)($line['pinjaman'] ?? 0), 2) }}</td>
|
||||
<td>{{ $line['no_rujukan_bayaran'] ?? '-' }}</td>
|
||||
<td class="text-nowrap">
|
||||
@@ -113,6 +112,13 @@
|
||||
@else
|
||||
<span class="text-muted small">Tiada slip</span>
|
||||
@endif
|
||||
@if(!empty($line['borang_file_id']))
|
||||
<a class="btn btn-sm btn-outline-primary"
|
||||
href="{{ route('pembiayaan.online.operasi.borang', ['kodcaw' => $kodcaw, 'id' => $line['id']]) }}"
|
||||
target="_blank">
|
||||
Borang Pengesahan
|
||||
</a>
|
||||
@endif
|
||||
</td>
|
||||
<td class="text-nowrap">
|
||||
@if(in_array($st, ['IN_BATCH', 'OPS_REVIEW'], true))
|
||||
|
||||
@@ -70,6 +70,13 @@
|
||||
@else
|
||||
<span class="text-muted small">Tiada slip</span>
|
||||
@endif
|
||||
@if(!empty($line['borang_file_id']))
|
||||
<a class="btn btn-sm btn-outline-primary"
|
||||
href="{{ route('pembiayaan.online.pc.borang', ['id' => $line['id']]) }}"
|
||||
target="_blank">
|
||||
Borang Pengesahan
|
||||
</a>
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
|
||||
@@ -274,11 +274,11 @@
|
||||
data-nokp="{{ $line['nokp'] ?? '' }}"
|
||||
data-namabank="{{ $line['nama_bank'] ?? $line['kodbank'] ?? '' }}"
|
||||
data-noakaun="{{ $line['noakaun'] ?? '' }}"
|
||||
data-namaakaun="{{ $line['nama_akaun'] ?? '' }}"
|
||||
data-pinjaman="{{ number_format((float)($line['pinjaman'] ?? 0), 2) }}"
|
||||
data-nota="{{ $line['nota'] ?? '' }}"
|
||||
data-sebab="{{ $line['reject_reason'] ?? '' }}"
|
||||
data-bukti-akaun="{{ $line['bukti_akaun_file_id'] ?? '' }}">
|
||||
data-bukti-akaun="{{ $line['bukti_akaun_file_id'] ?? '' }}"
|
||||
data-borang-file="{{ $line['borang_file_id'] ?? '' }}">
|
||||
Semak
|
||||
</button>
|
||||
@endif
|
||||
@@ -286,11 +286,11 @@
|
||||
data-id="{{ $line['id'] }}"
|
||||
data-kodbank="{{ $line['kodbank'] ?? '' }}"
|
||||
data-noakaun="{{ $line['noakaun'] ?? '' }}"
|
||||
data-namaakaun="{{ $line['nama_akaun'] ?? '' }}"
|
||||
data-namabank="{{ $line['nama_bank'] ?? '' }}"
|
||||
data-nota="{{ $line['nota'] ?? '' }}"
|
||||
data-norujukan="{{ $line['norujukan'] ?? '' }}"
|
||||
data-bukti-akaun="{{ $line['bukti_akaun_file_id'] ?? '' }}">
|
||||
data-bukti-akaun="{{ $line['bukti_akaun_file_id'] ?? '' }}"
|
||||
data-borang-file="{{ $line['borang_file_id'] ?? '' }}">
|
||||
Edit
|
||||
</button>
|
||||
</td>
|
||||
@@ -390,10 +390,6 @@
|
||||
<label>No. Akaun</label>
|
||||
<input type="text" name="noakaun" id="editNoakaun" class="form-control" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Nama Akaun</label>
|
||||
<input type="text" name="nama_akaun" id="editNamaakaun" class="form-control">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Slip Bank / Bukti Akaun</label>
|
||||
<input type="file" name="bukti_akaun" id="editBuktiAkaun" class="form-control-file"
|
||||
@@ -405,6 +401,17 @@
|
||||
</div>
|
||||
<small class="text-muted">PDF / imej slip akaun bank pelanggan (maks 4MB)</small>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Borang Pengesahan Penerimaan Pembiayaan Secara Atas Talian (Online)</label>
|
||||
<input type="file" name="borang" id="editBorang" class="form-control-file"
|
||||
accept=".pdf,.jpg,.jpeg,.png,.gif">
|
||||
<div id="editBorangExisting" class="mt-2" style="display:none;">
|
||||
<a href="#" id="editBorangLink" class="btn btn-sm btn-outline-primary" target="_blank">
|
||||
Lihat borang sedia ada
|
||||
</a>
|
||||
</div>
|
||||
<small class="text-muted">PDF / imej borang yang ditandatangani pelanggan (maks 4MB). Kosongkan jika tidak mahu ganti fail sedia ada.</small>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Nota</label>
|
||||
<textarea name="nota" id="editNota" class="form-control" rows="2"></textarea>
|
||||
@@ -462,10 +469,6 @@
|
||||
<th>No Akaun</th>
|
||||
<td id="verifyNoakaun"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Nama Akaun</th>
|
||||
<td id="verifyNamaakaun"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Pinjaman</th>
|
||||
<td>RM <span id="verifyPinjaman"></span></td>
|
||||
@@ -485,9 +488,12 @@
|
||||
Saya sahkan maklumat pelanggan, bank dan amaun adalah betul.
|
||||
</label>
|
||||
</div>
|
||||
<a href="#" id="verifyBuktiAkaunLink" class="btn btn-sm btn-outline-primary" target="_blank" style="display:none;">
|
||||
<a href="#" id="verifyBuktiAkaunLink" class="btn btn-sm btn-outline-primary mb-2" target="_blank" style="display:none;">
|
||||
Lihat Bukti Akaun Bank
|
||||
</a>
|
||||
<a href="#" id="verifyBorangLink" class="btn btn-sm btn-outline-primary" target="_blank" style="display:none;">
|
||||
Lihat Borang Pengesahan
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<label class="d-block">Pratonton SAG</label>
|
||||
@@ -576,7 +582,6 @@
|
||||
$('#verifyNokp').text($(this).data('nokp') || '-');
|
||||
$('#verifyBank').text($(this).data('namabank') || '-');
|
||||
$('#verifyNoakaun').text($(this).data('noakaun') || '-');
|
||||
$('#verifyNamaakaun').text($(this).data('namaakaun') || '-');
|
||||
$('#verifyPinjaman').text($(this).data('pinjaman') || '0.00');
|
||||
$('#verifyNota').text($(this).data('nota') || '-');
|
||||
if (sebab) {
|
||||
@@ -592,6 +597,11 @@
|
||||
} else {
|
||||
$('#verifyBuktiAkaunLink').hide();
|
||||
}
|
||||
if ($(this).data('borangFile')) {
|
||||
$('#verifyBorangLink').attr('href', "{{ url('/pembiayaan-online/pc/lines') }}/" + id + "/borang").show();
|
||||
} else {
|
||||
$('#verifyBorangLink').hide();
|
||||
}
|
||||
$('#verifyModal').modal('show');
|
||||
});
|
||||
|
||||
@@ -605,10 +615,10 @@
|
||||
$('#editNorujukan').text($(this).data('norujukan'));
|
||||
$('#editKodbank').val($(this).data('kodbank'));
|
||||
$('#editNoakaun').val($(this).data('noakaun'));
|
||||
$('#editNamaakaun').val($(this).data('namaakaun'));
|
||||
$('#editNamabank').val($(this).data('namabank'));
|
||||
$('#editNota').val($(this).data('nota'));
|
||||
$('#editBuktiAkaun').val('');
|
||||
$('#editBorang').val('');
|
||||
$('#editSagFrame').attr('src', "{{ url('/pembiayaan-online/pc/lines') }}/" + id + "/sag");
|
||||
if ($(this).data('buktiAkaun')) {
|
||||
$('#editBuktiAkaunLink').attr('href', "{{ url('/pembiayaan-online/pc/lines') }}/" + id + "/bukti-akaun");
|
||||
@@ -616,6 +626,12 @@
|
||||
} else {
|
||||
$('#editBuktiAkaunExisting').hide();
|
||||
}
|
||||
if ($(this).data('borangFile')) {
|
||||
$('#editBorangLink').attr('href', "{{ url('/pembiayaan-online/pc/lines') }}/" + id + "/borang");
|
||||
$('#editBorangExisting').show();
|
||||
} else {
|
||||
$('#editBorangExisting').hide();
|
||||
}
|
||||
$('#editModal').modal('show');
|
||||
});
|
||||
|
||||
|
||||
@@ -258,7 +258,7 @@
|
||||
<th style="width:13%">No. KP</th>
|
||||
<th style="width:11%">Bank</th>
|
||||
<th style="width:13%">No. Akaun</th>
|
||||
<th>Nama Akaun</th>
|
||||
<th>No. Telefon</th>
|
||||
<th style="width:12%">Pinjaman (RM)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -271,7 +271,7 @@
|
||||
<td class="num">{{ $line['nokp'] ?? '-' }}</td>
|
||||
<td>{{ $line['nama_bank'] ?? ($line['kodbank'] ?? '-') }}</td>
|
||||
<td class="num">{{ $line['noakaun'] ?? '-' }}</td>
|
||||
<td>{{ $line['nama_akaun'] ?? '-' }}</td>
|
||||
<td>{{ !empty($line['telefon']) ? $line['telefon'] : '-' }}</td>
|
||||
<td class="amt">{{ number_format((float) ($line['pinjaman'] ?? 0), 2) }}</td>
|
||||
</tr>
|
||||
@empty
|
||||
@@ -306,7 +306,7 @@
|
||||
|
||||
<div class="signs">
|
||||
<div class="sign-box">
|
||||
<div class="role">Tandatangan Operasi</div>
|
||||
<div class="role">Disemak oleh</div>
|
||||
<div class="sign-line">
|
||||
<p>Nama: {{ $opsBy }}</p>
|
||||
<p>Jawatan: Operasi</p>
|
||||
@@ -314,10 +314,10 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="sign-box">
|
||||
<div class="role">Pengurus Besar</div>
|
||||
<div class="role">Disahkan oleh</div>
|
||||
<div class="sign-line">
|
||||
<p>Nama:</p>
|
||||
<p>Cop:</p>
|
||||
<p>Jawatan:</p>
|
||||
<p>Tarikh:</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1305,45 +1305,6 @@
|
||||
<tr>
|
||||
<td colspan="1"></td>
|
||||
<td colspan="1"><b>6.</b></td>
|
||||
<td colspan="2"><b>Pelanggan dengan ini bersetuju, memberi kuasa dan melantik
|
||||
Ar-Rahn sebagai wakil (wakil di bawah prinsip Wakalah) untuk menguruskan baki
|
||||
hasil lelongan yang menjadi hak Pelanggan,
|
||||
sekiranya ada, yang bernilai RM10.00 (Ringgit Malaysia: Sepuluh) atau kurang,
|
||||
dan tidak dituntut oleh Pelanggan dalam tempoh tuntutan yang ditetapkan oleh
|
||||
Ar-Rahn setelah usaha munasabah telah diambil untuk memaklumkan kepada
|
||||
Pelanggan.</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="1"></td>
|
||||
<td colspan="1"><b>7.</b></td>
|
||||
<td colspan="2">
|
||||
<b>
|
||||
Pelanggan selanjutnya bersetuju bahawa baki hasil lelongan tersebut boleh
|
||||
disalurkan oleh Ar-Rahn, bagi pihak Pelanggan, sebagai infaq kepada mana-mana
|
||||
institusi agama Islam, badan kebajikan atau institusi lain yang diluluskan
|
||||
oleh Jawatankuasa Syariah dan/atau pihak berkuasa yang berkaitan, tanpa
|
||||
sebarang liabiliti ke atas Ar-Rahn selepas penyaluran tersebut dibuat dengan
|
||||
jumlah tidak melebihi RM10.00.
|
||||
</b>
|
||||
|
||||
<div style="margin-top: 8px;">
|
||||
<span
|
||||
style="
|
||||
display: inline-block;
|
||||
width: 13px;
|
||||
height: 13px;
|
||||
border: 1px solid #000;
|
||||
margin-right: 6px;
|
||||
vertical-align: middle;
|
||||
"></span>
|
||||
<b>Tandakan (✓) jika tidak bersetuju.</b>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="1"></td>
|
||||
<td colspan="1"><b>8.</b></td>
|
||||
<td colspan="2"><b>Sekiranya Pelanggan mempunyai sebarang pertanyaan atau
|
||||
aduan, Pelanggan boleh menghubungi KoPKB sebagaimana berikut:</b></td>
|
||||
</tr>
|
||||
@@ -2112,6 +2073,7 @@
|
||||
</div>
|
||||
<div class="main-page" style="font-family: Arial, Helvetica, sans-serif;">
|
||||
<div class="sub-page" style="font-size: 11px;">
|
||||
@if ($pembiayaanOnlineEnabled ?? false)
|
||||
@php
|
||||
$caraTerimaBayaran = strtoupper(trim((string) ($gadai_detail['cara_terima'] ?? '')));
|
||||
@endphp
|
||||
@@ -2128,6 +2090,7 @@
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
{{-- HEADER SECTION --}}
|
||||
<table style="width: 100%; margin-top: 0;">
|
||||
<tr style="vertical-align: top;">
|
||||
|
||||
+13
-1
@@ -17,6 +17,8 @@ use Illuminate\Support\Facades\Storage;
|
||||
|
||||
Route::post('/internal/notifications', ['as' => 'internal.notifications.store', 'uses' => 'InternalNotificationController@store']);
|
||||
|
||||
Route::view('/dasar-privasi', 'dasar-privasi')->name('dasar.privasi');
|
||||
|
||||
Route::get('/health', function () {
|
||||
return response()->json(['status' => 'ok']);
|
||||
});
|
||||
@@ -61,7 +63,13 @@ Route::get('test', function () {
|
||||
return "event test je";
|
||||
});
|
||||
|
||||
Route::get('logs', '\Rap2hpoutre\LaravelLogViewer\LogViewerController@index');
|
||||
Route::get('logs', '\Rap2hpoutre\LaravelLogViewer\LogViewerController@index')
|
||||
->middleware([
|
||||
'auth',
|
||||
'role:admin,masteradmin,operasi',
|
||||
'throttle:10,1',
|
||||
\App\Http\Middleware\LogViewerPassword::class,
|
||||
]);
|
||||
Route::get('change-password', ['as'=>'user.password','uses'=>'ChangePasswordController@index']);
|
||||
Route::post('change-password', ['as'=>'change.password','uses'=>'ChangePasswordController@store']);
|
||||
|
||||
@@ -136,6 +144,8 @@ Route::get('/customer/otp',['as'=>'customer.otp','uses'=>'CustomersController@ge
|
||||
Route::get('/getwakil',['as'=>'wakil.search','uses'=>'PenebusanController@getWakil'])->middleware('auth','teller');
|
||||
Route::get('/cari',['as'=>'wakil.caricustomer','uses'=>'CustomersController@cari'])->middleware('auth','teller');
|
||||
Route::post('/customer/mykad-photo',['as'=>'customer.storeMykadPhoto','uses'=>'CustomersController@storeMykadPhotoIfMissing'])->middleware('auth','teller');
|
||||
Route::post('/customer/ic-scan',['as'=>'customer.storeIcScan','uses'=>'CustomersController@storeIcScan'])->middleware('auth','teller');
|
||||
Route::get('/customer/ic-scan',['as'=>'customer.showIcScan','uses'=>'CustomersController@showIcScan'])->middleware('auth','teller');
|
||||
Route::post('/createwakil',['as'=>'wakil.create','uses'=>'PenebusanController@createWakil'])->middleware('auth','teller');
|
||||
Route::get('/firstwakil',['as'=>'wakil.first','uses'=>'PenebusanController@getfirstWakil'])->middleware('auth','teller');
|
||||
Route::get('/history',['as'=>'gadai.history','uses'=>'GadaianController@history'])->middleware('auth','teller');
|
||||
@@ -204,6 +214,7 @@ Route::put('/pembiayaan-online/pc/lines/{id}',['as'=>'pembiayaan.online.pc.updat
|
||||
Route::post('/pembiayaan-online/pc/lines/{id}/verify',['as'=>'pembiayaan.online.pc.verify','uses'=>'PembiayaanOnlineController@verifyLine'])->middleware('auth','khazanah');
|
||||
Route::post('/pembiayaan-online/pc/lines/{id}/unverify',['as'=>'pembiayaan.online.pc.unverify','uses'=>'PembiayaanOnlineController@unverifyLine'])->middleware('auth','khazanah');
|
||||
Route::get('/pembiayaan-online/pc/lines/{id}/bukti-akaun',['as'=>'pembiayaan.online.pc.bukti.akaun','uses'=>'PembiayaanOnlineController@viewBuktiAkaun'])->middleware('auth','khazanah');
|
||||
Route::get('/pembiayaan-online/pc/lines/{id}/borang',['as'=>'pembiayaan.online.pc.borang','uses'=>'PembiayaanOnlineController@viewBorang'])->middleware('auth','khazanah');
|
||||
Route::get('/pembiayaan-online/pc/lines/{id}/sag',['as'=>'pembiayaan.online.pc.sag','uses'=>'PembiayaanOnlineController@viewSag'])->middleware('auth','khazanah');
|
||||
Route::post('/pembiayaan-online/pc/batches/submit',['as'=>'pembiayaan.online.pc.submit','uses'=>'PembiayaanOnlineController@submitBatch'])->middleware('auth','khazanah');
|
||||
Route::get('/pembiayaan-online/pc/batches/{batchId}',['as'=>'pembiayaan.online.pc.batch','uses'=>'PembiayaanOnlineController@showBatch'])->middleware('auth','khazanah');
|
||||
@@ -230,6 +241,7 @@ Route::post('/pembiayaan-online/operasi/{kodcaw}/batches/{batchId}/approve',['as
|
||||
Route::post('/pembiayaan-online/operasi/{kodcaw}/lines/{id}/paid',['as'=>'pembiayaan.online.operasi.paid','uses'=>'PembiayaanOnlineController@operasiMarkPaid'])->middleware('auth','operasi');
|
||||
Route::post('/pembiayaan-online/operasi/{kodcaw}/batches/{batchId}/paid',['as'=>'pembiayaan.online.operasi.paid.batch','uses'=>'PembiayaanOnlineController@operasiMarkPaidBatch'])->middleware('auth','operasi');
|
||||
Route::get('/pembiayaan-online/operasi/{kodcaw}/lines/{id}/bukti-akaun',['as'=>'pembiayaan.online.operasi.bukti.akaun','uses'=>'PembiayaanOnlineController@operasiViewBuktiAkaun'])->middleware('auth','operasi');
|
||||
Route::get('/pembiayaan-online/operasi/{kodcaw}/lines/{id}/borang',['as'=>'pembiayaan.online.operasi.borang','uses'=>'PembiayaanOnlineController@operasiViewBorang'])->middleware('auth','operasi');
|
||||
Route::get('/pembiayaan-online/operasi/{kodcaw}/lines/{id}/sag',['as'=>'pembiayaan.online.operasi.sag','uses'=>'PembiayaanOnlineController@operasiViewSag'])->middleware('auth','operasi');
|
||||
Route::get('/permohonan/rekod',['as'=>'permohonan.rekod','uses' => 'KhazanahController@RekodPermohonan'])->middleware('auth','khazanah');
|
||||
Route::post('/permohonan/simpan',['as'=>'permohonan.simpan','uses' => 'KhazanahController@SimpanPermohonan'])->middleware('auth','khazanah');
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Http\Middleware\LogViewerPassword;
|
||||
use Illuminate\Http\Request;
|
||||
use Tests\TestCase;
|
||||
|
||||
class LogViewerPasswordTest extends TestCase
|
||||
{
|
||||
public function test_missing_configuration_denies_access()
|
||||
{
|
||||
config(['logviewer.password' => null]);
|
||||
$response = $this->checkAccess();
|
||||
$this->assertSame(503, $response->getStatusCode());
|
||||
}
|
||||
|
||||
public function test_missing_or_incorrect_credentials_are_rejected()
|
||||
{
|
||||
config(['logviewer.password' => password_hash('test-only-secret', PASSWORD_DEFAULT)]);
|
||||
foreach ([[], ['PHP_AUTH_USER' => 'logs', 'PHP_AUTH_PW' => 'wrong'],
|
||||
['PHP_AUTH_USER' => 'other', 'PHP_AUTH_PW' => 'test-only-secret']] as $server) {
|
||||
$response = $this->checkAccess($server);
|
||||
$this->assertSame(401, $response->getStatusCode());
|
||||
$this->assertStringContainsString('Basic realm=', $response->headers->get('WWW-Authenticate'));
|
||||
}
|
||||
}
|
||||
|
||||
public function test_correct_credentials_allow_access_without_caching()
|
||||
{
|
||||
config(['logviewer.password' => password_hash('test-only-secret', PASSWORD_DEFAULT)]);
|
||||
$response = $this->checkAccess(['PHP_AUTH_USER' => 'logs', 'PHP_AUTH_PW' => 'test-only-secret']);
|
||||
$this->assertSame(200, $response->getStatusCode());
|
||||
$this->assertSame('allowed', $response->getContent());
|
||||
$this->assertStringContainsString('no-store', $response->headers->get('Cache-Control'));
|
||||
}
|
||||
|
||||
public function test_logs_route_has_auth_role_password_and_throttle_middleware()
|
||||
{
|
||||
$route = app('router')->getRoutes()->match(Request::create('/logs'));
|
||||
$middleware = $route->gatherMiddleware();
|
||||
$this->assertContains('auth', $middleware);
|
||||
$this->assertContains('role:admin,masteradmin', $middleware);
|
||||
$this->assertContains(LogViewerPassword::class, $middleware);
|
||||
$this->assertContains('throttle:10,1', $middleware);
|
||||
}
|
||||
|
||||
private function checkAccess(array $server = [])
|
||||
{
|
||||
$request = Request::create('/logs?dl=example', 'GET', [], [], [], $server);
|
||||
return (new LogViewerPassword)->handle($request, function () {
|
||||
return response('allowed');
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user