diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..32264f9 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,16 @@ +.git +.gitea +node_modules +vendor +.env +.env.* +!.env.example +storage/logs +storage/framework/cache +storage/framework/sessions +storage/framework/views +storage/debugbar +npm-debug.log +Dockerfile +docker-compose.yml +docker-compose.staging.yml diff --git a/.env.staging b/.env.staging new file mode 100644 index 0000000..4f366ca --- /dev/null +++ b/.env.staging @@ -0,0 +1,84 @@ +APP_NAME=Lumen +APP_ENV=staging +APP_KEY=WbPGkYNmXZ6ZQplGlvl0iZ7zyW1b09xa +APP_DEBUG=true +APP_URL=http://127.0.0.1:8090 +APP_TIMEZONE=Asia/Kuala_Lumpur + +# Unique host ports — change these if they collide with other containers on the server. +# Host nginx should proxy the staging domain to 127.0.0.1:${HTTP_PORT} +HTTP_PORT=8090 +MYSQL_PUBLISH_PORT=3308 + +LOG_CHANNEL=stack +LOG_LEVEL=debug +LOG_SLACK_WEBHOOK_URL= + +DB_CONNECTION=mysql +DB_HOST=mysql +DB_PORT=3306 +DB_DATABASE=erahn_xtra +DB_USERNAME=root +DB_PASSWORD=root + +DB_CONNECTION_7=mysql +DB_HOST_7=mysql +DB_PORT_7=3306 +DB_DATABASE_7=master_erahn +DB_USERNAME_7=root +DB_PASSWORD_7=root + +DB_CONNECTION_2=mysql +DB_HOST_2=mysql +DB_PORT_2=3306 +DB_DATABASE_2=erahn_xtra +DB_USERNAME_2=root +DB_PASSWORD_2=root + +DB_CONNECTION_3=mysql +DB_HOST_3=mysql +DB_PORT_3=3306 +DB_DATABASE_3=erahn_baling +DB_USERNAME_3=root +DB_PASSWORD_3=root + +DB_CONNECTION_4=mysql +DB_HOST_4=mysql +DB_PORT_4=3306 +DB_DATABASE_4=arrahn_ld +DB_USERNAME_4=root +DB_PASSWORD_4=root + +DB_CONNECTION_5=mysql +DB_HOST_5=mysql +DB_PORT_5=3306 +DB_DATABASE_5=erahn_segamat +DB_USERNAME_5=root +DB_PASSWORD_5=root + +DB_CONNECTION_7=mysql +DB_HOST_7=mysql +DB_PORT_7=3306 +DB_DATABASE_7=master_erahn +DB_USERNAME_7=root +DB_PASSWORD_7=root + +DB_CONNECTION_6=mysql +DB_HOST_6=mysql +DB_PORT_6=3306 +DB_DATABASE_6=erahn_test +DB_USERNAME_6=root +DB_PASSWORD_6=root + +# DB_CONNECTION_8=mysql +# DB_HOST_8=mysql +# DB_PORT_8=3306 +# DB_DATABASE_8=arrahn_klanas +# DB_USERNAME_8=spider +# DB_PASSWORD_8=G0dz!ll42020 + +TENNANT_MASTER_DB=master_erahn +TENNANT_KAUNTER_DB=kaunter_erahn + +CACHE_DRIVER=file +QUEUE_CONNECTION=sync \ No newline at end of file diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml new file mode 100644 index 0000000..dc3a55e --- /dev/null +++ b/.gitea/workflows/build.yml @@ -0,0 +1,49 @@ +name: Build Docker Image + +on: + push: + branches: + - staging + tags: + - "v*" + workflow_dispatch: + +jobs: + build-backend: + runs-on: docker + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Login to Docker registry + run: | + echo "${{ secrets.REGISTRY_PASSWORD }}" | \ + docker login git.koppkb.com \ + -u "${{ secrets.REGISTRY_USERNAME }}" \ + --password-stdin + + - name: Build & push backend image + run: | + set -e + + IMAGE="git.koppkb.com/kopkb/api_arrahn" + TAGS="-t ${IMAGE}:${{ gitea.sha }}" + + if [ "${{ gitea.ref_type }}" = "tag" ] && echo "${{ gitea.ref_name }}" | grep -q '^v'; then + TAGS="${TAGS} -t ${IMAGE}:${{ gitea.ref_name }}" + fi + + if [ "${{ gitea.ref_name }}" = "staging" ]; then + TAGS="${TAGS} -t ${IMAGE}:staging" + fi + + echo "Building and pushing backend: ${TAGS}" + docker buildx build \ + --target staging \ + --platform linux/amd64 \ + --cache-from type=registry,ref=${IMAGE}:buildcache,ignore-error=true \ + --cache-to type=registry,ref=${IMAGE}:buildcache,mode=max \ + -f docker/php/Dockerfile \ + ${TAGS} \ + --push . diff --git a/.gitea/workflows/deploy-staging.yml b/.gitea/workflows/deploy-staging.yml new file mode 100644 index 0000000..8fd6daa --- /dev/null +++ b/.gitea/workflows/deploy-staging.yml @@ -0,0 +1,122 @@ +name: Deploy to Staging + +on: + workflow_dispatch: + inputs: + image_tag: + description: "Docker image tag to deploy (commit SHA, staging, or v*)" + required: true + default: "staging" + type: string + +env: + APP_IMAGE: git.koppkb.com/kopkb/api_arrahn + DEPLOY_DIR: /home/arrahn/Project/api_arrahn + +jobs: + deploy: + runs-on: host + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + ref: ${{ inputs.image_tag }} + + - name: Login to Docker registry + run: | + echo "${{ secrets.REGISTRY_PASSWORD }}" | \ + docker login git.koppkb.com \ + -u "${{ secrets.REGISTRY_USERNAME }}" \ + --password-stdin + + - name: Verify image exists in registry + run: | + set -e + IMAGE_TAG="${{ inputs.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!" + 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 }}" + docker pull "${APP_IMAGE}:${IMAGE_TAG}" + echo "✓ Image pulled successfully" + + - name: Sync compose file and deploy + run: | + set -e + IMAGE_TAG="${{ inputs.image_tag }}" + + mkdir -p "${DEPLOY_DIR}/docker/nginx" "${DEPLOY_DIR}/docker/mysql" + cp docker-compose.staging.yml "${DEPLOY_DIR}/docker-compose.yml" + cp docker/nginx/default.conf "${DEPLOY_DIR}/docker/nginx/default.conf" + cp -R docker/mysql/init "${DEPLOY_DIR}/docker/mysql/" + + 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" + exit 1 + fi + fi + + cd "${DEPLOY_DIR}" + + export APP_IMAGE + export IMAGE_TAG + + docker compose --env-file .env.staging -f docker-compose.yml pull app + docker compose --env-file .env.staging -f docker-compose.yml up -d --no-build --remove-orphans + + echo "✓ Deployed IMAGE_TAG=${IMAGE_TAG}" + + - name: Verify deployment + run: | + set -e + cd "${DEPLOY_DIR}" + + echo "Waiting for services to start..." + sleep 10 + + for SERVICE in app web mysql; do + STATUS=$(docker compose --env-file .env.staging -f docker-compose.yml ps --status running --format '{{.Name}}' "$SERVICE" 2>/dev/null || true) + if [ -z "$STATUS" ]; then + echo "ERROR: ${SERVICE} is not running" + docker compose --env-file .env.staging -f docker-compose.yml ps + docker compose --env-file .env.staging -f docker-compose.yml logs --tail=50 "$SERVICE" || true + exit 1 + fi + echo "✓ ${SERVICE} is running (${STATUS})" + done + + HTTP_PORT=$(grep -E '^HTTP_PORT=' .env.staging 2>/dev/null | cut -d= -f2- | tr -d '"' || true) + HTTP_PORT=${HTTP_PORT:-8090} + + check_health() { + NAME=$1 + URL=$2 + for i in 1 2 3 4 5 6; do + if curl -sf "$URL" > /dev/null; then + echo "✓ ${NAME} health check passed (${URL})" + return 0 + fi + echo "Waiting for ${NAME}... attempt ${i}/6" + sleep 5 + done + echo "ERROR: ${NAME} health check failed (${URL})" + docker compose --env-file .env.staging -f docker-compose.yml logs --tail=50 app web || true + return 1 + } + + check_health "api" "http://127.0.0.1:${HTTP_PORT}/health" diff --git a/app/.DS_Store b/app/.DS_Store index aba4526..c05d45c 100644 Binary files a/app/.DS_Store and b/app/.DS_Store differ diff --git a/app/Console/Commands/CawanganDebugConnections.php b/app/Console/Commands/CawanganDebugConnections.php index d4372f8..ec15539 100644 --- a/app/Console/Commands/CawanganDebugConnections.php +++ b/app/Console/Commands/CawanganDebugConnections.php @@ -80,7 +80,7 @@ class CawanganDebugConnections extends Command return $idToNameMap[$item['mysql']] !== $item['database']; }); } catch (\Throwable $th) { - dump(sprintf('Connection %s not found in table online_arrahn.arrahn_master_db but present in config. Make sure both of connection exist in both app/config and arrahn_master_db', $tested_connection)); + dump(sprintf('Connection %s not found in table %s.arrahn_master_db but present in config. Make sure both of connection exist in both app/config and arrahn_master_db', $tested_connection, config('tennant_database.master_db'))); return; } diff --git a/app/Helper.php b/app/Helper.php index 63fb7b7..ceccf4f 100644 --- a/app/Helper.php +++ b/app/Helper.php @@ -12,7 +12,7 @@ class Helper { $online_arrahn_connection = array_filter(config('database.connections'), function ($connection) { - if ($connection['database'] === 'online_arrahn') { + if ($connection['database'] === config('tennant_database.master_db')) { return $connection; } }); @@ -43,7 +43,7 @@ class Helper } }); - $non_cawangan_database = ['lelong', 'online_arrahn', 'kaunterpkb']; + $non_cawangan_database = ['lelong', config('tennant_database.master_db'), config('tennant_database.kaunter_db')]; $all_cawangan_db = array_filter($all_active_db_keys, function ($db_key) use ($non_cawangan_database) { $isNotCawangan = in_array(config('database.connections.' . $db_key . '.database'), $non_cawangan_database); @@ -74,7 +74,7 @@ class Helper } }); - $non_cawangan_database = ['lelong', 'online_arrahn', 'kaunterpkb']; + $non_cawangan_database = ['lelong', config('tennant_database.master_db'), config('tennant_database.kaunter_db')]; $all_cawangan_db = array_filter($all_inactive_db_keys, function ($db_key) use ($non_cawangan_database) { $isNotCawangan = in_array(config('database.connections.' . $db_key . '.database'), $non_cawangan_database); diff --git a/app/Http/Controllers/BackupStokAuditController.php b/app/Http/Controllers/BackupStokAuditController.php index 191806e..fb56b2a 100644 --- a/app/Http/Controllers/BackupStokAuditController.php +++ b/app/Http/Controllers/BackupStokAuditController.php @@ -331,7 +331,7 @@ class BackupStokAuditController extends Controller } public function kiraupahTawarruqStokAudit($tempoh,$tempohbayar,$kadarupah,$bakipinjaman){ - + $tempoh = ($tempoh > 12) ? 12 : $tempoh; $bilang_bln = $tempoh - $tempohbayar; if($bilang_bln > 12){ @@ -458,6 +458,7 @@ class BackupStokAuditController extends Controller public function kiraupahTawarruqStokAuditUjrahOnePercent($tempoh,$tempohbayar,$kadarupah,$bakipinjaman,$nilaimarhun,$margin_semasa){ $onepercentservices = new V2Calculation(); $upah = $onepercentservices->kiraanKeuntunganRebet($bakipinjaman,$nilaimarhun,$kadarupah,$margin_semasa); + $tempoh = ($tempoh > 12) ? 12 : $tempoh; $bilang_bln = $tempoh - $tempohbayar; $keuntungan_semasa = $bilang_bln * $upah['onepercent']; $ujrah_semasa = $bilang_bln * $upah['ujrah']; diff --git a/app/Http/Controllers/BarangkesController.php b/app/Http/Controllers/BarangkesController.php index dd4f10c..a5899f6 100644 --- a/app/Http/Controllers/BarangkesController.php +++ b/app/Http/Controllers/BarangkesController.php @@ -6,38 +6,190 @@ use App\Audit; use App\Polis; use App\Cawangan; use App\LookupAlasan; +use App\Palsu; +use App\Gadai; +use App\Pampasan; use Illuminate\Http\Request; use Carbon\Carbon; use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Http; +use Illuminate\Support\Facades\Log; class BarangkesController extends Controller { public function LaporanBarangKes(Request $request) { + $status = $request->status; - $cawangan = Cawangan::on('mysql7')->where('kodcaw', $request->kodcaw)->first(); + $cawangan = Cawangan::on('mysql7')->where('kodcaw', $request->kodcaw)->first(); - if (!$cawangan) { - return response()->json(['error' => 'Invalid kodcaw'], 403); + if (!$cawangan) { + return response()->json(['error' => 'Invalid kodcaw'], 403); + } + + $palsu_query = Palsu::on($cawangan['mysql']) + ->select([ + 'tarikh', + 'norujukan', + 'nota', + 'pembiayaan', + 'nilaimarhun', + 'jbg', + 'untung', + 'untungonepercent', + 'untungcajlain' + ]) + ->when($request->filled('tarikh_mula') && $request->filled('tarikh_akhir'), function ($query) use ($request) { + return $query->whereBetween('tarikh', [$request->tarikh_mula, $request->tarikh_akhir]); + }) + ->with(['tebus:norujukan', 'gadai:norujukan,nokp']); + + $palsu_array = $palsu_query->get()->toArray(); + $pampasan_array = Pampasan::on($cawangan['mysql'])->where('kodcaw', $request->kodcaw)->get()->toArray(); + + $indexedArray2 = collect($pampasan_array)->keyBy('norujukan'); + + $merged = collect($palsu_array)->map(function ($item) use ($indexedArray2) { + $id = $item['norujukan']; + $itemArray = $item; // Already an array from toArray() + $additional = $indexedArray2->get($id, []); + + // Add exists_in_tebus flag based on relationship + $itemArray['gadaian_sudah_tebus'] = !is_null($item['tebus']); + + // Add nokp customer from gadai relationship + $itemArray['nokp'] = $item['gadai']['nokp']; + + // Remove the tebus relationship data to keep response clean + unset($itemArray['tebus']); + unset($itemArray['gadai']); + + + return array_merge($itemArray, $additional); + })->values()->toArray(); + + $filteredResults = []; + + $sudahTuntutSecaraManual = [ + '011237240719-0015', + '011237240806-0011', + '011237240828-0001', + '011237240731-0026', + '011237240912-0009' + ]; + + // if ($status == 'dituntut') { + // foreach ($merged as $pampasan) { + // if (isset($pampasan['status']) && $pampasan['status'] == 1) { + // $filteredResults[] = $pampasan; + // } + // } + // } + if ($status == 'dituntut') { + foreach ($merged as $pampasan) { + if ( + (isset($pampasan['status']) && $pampasan['status'] == 1) + || in_array($pampasan['norujukan'], $sudahTuntutSecaraManual) + ) { + $filteredResults[] = $pampasan; + } + } + } + // if ($status == 'belum-tuntut') { + // foreach ($merged as $pampasan) { + // if (!isset($pampasan['status'])) { + // $filteredResults[] = $pampasan; + // } + // } + // } + if ($status == 'belum-tuntut') { + foreach ($merged as $pampasan) { + if ( + !isset($pampasan['status']) + && !in_array($pampasan['norujukan'], $sudahTuntutSecaraManual) + ) { + $filteredResults[] = $pampasan; + } + } + } + if ($status == 'all' || $status == null) { + $filteredResults = $merged; + } + + return response()->json($filteredResults); } - $query = DB::connection($cawangan['mysql'])->table('palsu') - ->select([ - 'tarikh', - 'norujukan', - 'nota', - 'pembiayaan', - 'nilaimarhun', - 'jbg', - 'untung', - 'untungonepercent', - 'untungcajlain' - ]) - ->whereBetween('tarikh', [$request->tarikh_mula, $request->tarikh_akhir]); + public function store(Request $request) //cara fifi ajar + { - $result = $query->get(); + $current = Carbon::now(); + $kodcaw = $request->kodcaw; + $cawangan = Cawangan::on('mysql7') + ->where('kodcaw', $kodcaw) + ->first(); - return response()->json($result); + $insert = Palsu::on($cawangan['mysql'])->create([ + 'kodcaw' => $request->kodcaw, + 'tarikh' => $current->toDateString(), + 'norujukan' => $request->norujukan, + 'teller' => $request->teller, + 'nota' => $request->nota ? $request->nota : '', + 'pembiayaan' => $request->pinjaman, + 'nilaimarhun' => $request->nilaimarhun, + 'jbg' => $request->jbg, + 'untung' => $request->tunggakan, + 'untungonepercent' => $request->tunggakanonepercent, + 'untungcajlain' => $request->tunggakanujrah, + ]); + + // return $insert; + + return response()->json([ + 'success' => true, + 'message' => 'Barang kes berjaya didaftar', + 'data' => $insert + ], 201); + } + + public function update(Request $request) + { + + $current = Carbon::now(); + $kodcaw = $request->kodcaw; + Log::info($request->all()); + + // Cari connection cawangan + $cawangan = Cawangan::on('mysql7') + ->where('kodcaw', $kodcaw) + ->first(); + + if (!$cawangan) { + return response()->json([ + 'success' => false, + 'message' => 'Cawangan tidak dijumpai', + ], 404); + } + + // Update direct (ikut norujukan) + $palsu = palsu::on($cawangan['mysql']) + ->where('norujukan', $request->norujukan) + ->update([ + 'kodcaw' => $request->kodcaw, + 'tarikh' => $request->tarikh, + 'teller' => $request->teller, + 'nota' => $request->nota ?? '', + 'pembiayaan' => $request->pinjaman, + 'nilaimarhun' => $request->nilaimarhun, + 'jbg' => $request->jbg, + 'untung' => $request->tunggakan, + 'untungonepercent' => $request->tunggakanonepercent, + 'untungcajlain' => $request->tunggakanujrah, + ]); + + return response()->json([ + 'success' => $palsu ? true : false, + 'message' => $palsu ? 'Rekod gadai berjaya dikemaskini' : 'Rekod tidak dijumpai', + ], 200); + } } -} \ No newline at end of file diff --git a/app/Http/Controllers/CustomerController.php b/app/Http/Controllers/CustomerController.php index 5b93b81..d672bb5 100644 --- a/app/Http/Controllers/CustomerController.php +++ b/app/Http/Controllers/CustomerController.php @@ -14,6 +14,7 @@ use App\Blacklist; use App\AuditCustomer; use Illuminate\Http\Request; use App\TuntutBaki; +use Illuminate\Support\Facades\Auth; use App\Anggota; use Carbon\Carbon; @@ -395,6 +396,7 @@ class CustomerController extends Controller // 'nota_arcc'=>$request->nota_arcc, 'telefon' => $request->telefon1, 'telefon2' => $request->telefon2, + 'telefon2' => $request->telefon2, )); return response()->json($customer_update, 200); @@ -419,6 +421,33 @@ class CustomerController extends Controller $customer->tag_anggota = 1; $customer->save(); + return response()->json([ + 'success' => true, + 'message' => 'Tag anggota berjaya dikemaskini.', + 'data' => $customer + ], 200); +} + } + + public function assignAnggota($noic, Request $request) +{ + // Semak sama ada pelanggan wujud + $customer = Customer::on('mysql7') + ->where('kpbaru', $noic) + ->orWhere('kplama', $noic) + ->first(); + + if (!$customer) { + return response()->json([ + 'success' => false, + 'message' => 'Pelanggan tidak dijumpai.' + ], 404); + } + + // Kemaskini tag_anggota + $customer->tag_anggota = 1; + $customer->save(); + return response()->json([ 'success' => true, 'message' => 'Tag anggota berjaya dikemaskini.', @@ -746,7 +775,7 @@ class CustomerController extends Controller $customer = Customer::on($cawangan['mysql']) ->where('kplama','=',$nokp) ->orWhere('kpbaru','=',$nokp) - ->rightJoin('online_arrahn.bank', 'bank.id', '=', 'customer.kodbank') + ->rightJoin(config('tennant_database.master_db') . '.bank', 'bank.id', '=', 'customer.kodbank') ->first(); if(!empty($customer)) @@ -860,6 +889,14 @@ class CustomerController extends Controller } + public function anggotaKoperasi(Request $request){ + + $anggota = Anggota::where('noic',$request->noic)->first(); + + return response()->json($anggota); + } + + public function showCustomerByEachCawangan($ic) { $cawangan_all = Cawangan::on('mysql7')->get(); @@ -939,6 +976,69 @@ class CustomerController extends Controller return response()->json($customer); } +public function AdminsearchCustomerBySAG(Request $request) +{ + // Ambil kodcaw dari user login + $kodcaw = $request->kodcaw; + // $norujukan = $request->input('norujukan'); + + // Cari connection untuk cawangan + $cawangan = Cawangan::on('mysql7')->where('kodcaw', $kodcaw)->first(); + if (!$cawangan) { + return response()->json([], 404); + } + + $gadai = optional(Gadai::on($cawangan['mysql'])->where('norujukan',$request->norujukan)->first())->toArray() ?? []; + + if(!empty($gadai)){ + $customer = optional(Customer::on('mysql7')->where(function ($query) use ($gadai) { + $query->where('kpbaru',$gadai['nokp']) + ->orWhere('kplama',$gadai['nokp']); + })->first())->toArray() ?? []; + }else{ + return response()->json(['success' => false,'message' => 'norujukan tidak dijumpainya'], 404); + } + + // cara fifi ajar + $result = [[ + 'id' => $customer['id'], + 'kodcaw' => $gadai['kodcaw'], + 'norujukan' => $gadai['norujukan'], + 'teller' => $gadai['teller'], + 'nota' => $customer['nota'], + 'pinjaman' => $gadai['pinjaman'], + 'nilaimarhun' => $gadai['nilaimarhun'], + 'jbg' => $gadai['jbg'], + 'tunggakan' => $gadai['tunggakan'], + 'tunggakanonepercent' => $gadai['tunggakanonepercent'], + 'tunggakanujrah' => $gadai['tunggakanujrah'], + 'nama' => $customer['nama'], + 'kplama' => $customer['kplama'], + 'kpbaru' => $customer['kpbaru'], + ]]; + + // saya buat sendiri + // Join customer + gadai ikut nokp + // $result = DB::connection($cawangan['mysql']) + // ->table('gadai') + // ->join('online_arrahn.customer as c', function($join) { + // $join->on('gadai.nokp', '=', 'c.kpbaru') + // ->orOn('gadai.nokp', '=', 'c.kplama'); + // }) + // ->where('norujukan', $request->norujukan) + // ->select( + // 'id', + // 'gadai.kodcaw','gadai.norujukan','gadai.teller', + // 'c.nota','gadai.pinjaman','gadai.nilaimarhun','gadai.jbg', + // 'gadai.tunggakan','gadai.tunggakanonepercent','gadai.tunggakanujrah', + // 'c.nama','c.kpbaru','c.kplama' + // ) + // ->take(5) + // ->get(); + + return response()->json($result); +} + public function changepassword(Request $request, $kodcaw, $id) { $current = Carbon::now(); @@ -1038,6 +1138,27 @@ class CustomerController extends Controller return response()->json($results); } + public function updateTagPdpa(Request $request) + { + $tarikh_cetak_pdpa = Carbon::now()->toDateString(); + + $no_ic = $request->input('no_ic'); + + $customer = Customer::where('kplama', $no_ic) + ->orWhere('kpbaru', $no_ic) + ->first(); + + if (!$customer) { + return response()->json(['error' => 'Customer not found.'], 404); + } + + $customer->tag_pdpa = $request->input('tag_pdpa'); + $customer->tarikh_cetak_pdpa = $tarikh_cetak_pdpa; + $customer->save(); + + return response()->json(['message' => 'Customer PDPA updated successfully.'], 200); + } + // public function createNotaArcc($kodcaw, Request $request) // { // $current = Carbon::now(); diff --git a/app/Http/Controllers/GadaiController.php b/app/Http/Controllers/GadaiController.php index 81bc8e9..942cc85 100644 --- a/app/Http/Controllers/GadaiController.php +++ b/app/Http/Controllers/GadaiController.php @@ -29,6 +29,7 @@ use App\KomuditiTransaksi; use App\Advansur; use App\HistoryEmasSandaran; use App\InOutMar; +use App\Services\Miscellaneous\StatistikService; use Illuminate\Http\Request; @@ -587,44 +588,78 @@ class GadaiController extends Controller public function getLaporanGadaiRangeDate($kodcaw,Request $request){ - $cawangan = Cawangan::on('mysql7')->where('kodcaw','=',$kodcaw)->first(); + $mula = $request->mula; + $akhir = $request->akhir; - $gadai_data = Gadai::on($cawangan['mysql'])->select('t_gadai','norujukan','nokp','semakbarcode','masa','berat','nilaimarhun','pinjaman','upah12','percentpinj','teller','nokp','ujrah','onepercent','tagbaru') - ->where('t_gadai','>=',$request->mula) - ->where('t_gadai','<=',$request->akhir) - ->orderBy('t_gadai') - ->orderBy('teller') - ->orderBy('sirig') - ->get(); + $cawangan = Cawangan::on('mysql7')->where('kodcaw', $kodcaw)->first(); - $gadai = []; + $gadai_data = Gadai::on($cawangan['mysql']) + ->whereBetween('t_gadai', [$request->mula, $request->akhir]) + ->orderBy('t_gadai') + ->orderBy('teller') + ->orderBy('sirig') + ->get(); - if($gadai_data){ - foreach($gadai_data as $index=>$gadaiData){ - $customer_info = Customer::on('mysql7')->where('kplama','=',$gadaiData['nokp'])->orWhere('kpbaru','=',$gadaiData['nokp'])->first(); - array_push($gadai,[ - "t_gadai"=> $gadaiData['t_gadai'], - "norujukan"=> $gadaiData['norujukan'], - "nama"=> $customer_info['nama'], - "nokp"=> $gadaiData['nokp'], - "semakbarcode"=> $gadaiData['semakbarcode'], - "masa"=> $gadaiData['masa'], - "berat"=> $gadaiData['berat'], - "nilaimarhun"=> $gadaiData['nilaimarhun'], - "pinjaman"=> $gadaiData['pinjaman'], - "upah12"=> $gadaiData['upah12'], - "percentpinj"=> $gadaiData['percentpinj'], - "alamat1"=> $customer_info['alamat1'], - "teller"=> $gadaiData['teller'], - "ujrah"=> $gadaiData['ujrah'], - "onepercent"=> $gadaiData['onepercent'], - "tagbaru"=> $gadaiData['tagbaru'] + $nokps = $gadai_data->pluck('nokp')->unique(); - ]); + $customers = Customer::on('mysql7') + ->where(function($query) use ($nokps) { + $query->whereIn('kpbaru', $nokps) + ->orWhereIn('kplama', $nokps); + }) + ->get() + ->flatMap(fn($c) => [ + $c->kpbaru => $c, + $c->kplama => $c + ]); + $gadai = $gadai_data->map(function ($g) use ($customers) { + + foreach($customers as $key=>$value){ + if($g->nokp == $value->kpbaru || $g->nokp == $value->kplama){ + $customer = $value; + } } - } - return response()->json($gadai); + return [ + + "nama" => optional($customer)->nama, + "alamat1" => optional($customer)->alamat1, + "t_gadai" => $g->t_gadai, + "norujukan" => $g->norujukan, + "norujukan"=> $g->norujukan, + + "nokp"=> $g->nokp, + "semakbarcode"=> $g->semakbarcode, + "masa"=> $g->masa, + "berat"=> $g->berat, + "nilaimarhun"=> $g->nilaimarhun, + "pinjaman"=> $g->pinjaman, + "upah12"=> $g->upah12, + "percentpinj"=> $g->percentpinj, + "alamat1"=> optional($customer)->alamat1, + "teller"=> $g->teller, + "ujrah"=> $g->ujrah, + "onepercent"=> $g->onepercent, + "tagbaru"=> $g->tagbaru, + "kodkerja"=> optional($customer)->kodkerja, + "bangsa"=> optional($customer)->bangsa, + + ]; + }); + // dd($gadai); + + $statistikService = new StatistikService($kodcaw,$mula,$akhir); + $reportgadai = $statistikService->LaporanStatistik($gadai); + // dd($nokps); + + return response()->json([ + 'gadai' => $gadai, + 'kodcaw' => $kodcaw, + 'mula' => $mula, + 'akhir' => $akhir, + 'statistik' => $reportgadai, + 'jumlah' => $gadai->count(), + ]); } public function getLaporanBatalGadai($kodcaw,$tarikh){ @@ -3871,11 +3906,13 @@ class GadaiController extends Controller public function updateTagLelong(Request $request){ $norujukan = $request->norujukan; $kodcaw = $request->kodcaw; + $t_lelong = $request->t_lelong; $cawangan = Cawangan::on('mysql7')->where('kodcaw',$request->kodcaw)->first(); $updateTag = Gadai::on($cawangan->mysql)->where('norujukan',$norujukan)->update([ - 'taglel'=>1 + 'taglel'=>1, + 't_lelong' => $t_lelong, ]); return response()->json('success'); @@ -3888,7 +3925,8 @@ class GadaiController extends Controller $cawangan = Cawangan::on('mysql7')->where('kodcaw',$request->kodcaw)->first(); $updateTag = Gadai::on($cawangan->mysql)->where('norujukan',$norujukan)->update([ - 'taglel'=>0 + 'taglel'=>0, + 't_lelong' => null, ]); return response()->json('success'); diff --git a/app/Http/Controllers/KelulusanController.php b/app/Http/Controllers/KelulusanController.php index ead5d4d..89e7647 100644 --- a/app/Http/Controllers/KelulusanController.php +++ b/app/Http/Controllers/KelulusanController.php @@ -98,6 +98,7 @@ class KelulusanController extends Controller { $harini = Carbon::now(); $harini = new Carbon; + $kelulusan = null; $cawangan = Cawangan::on('mysql7')->where('kodcaw','=',$kodcaw)->first(); $pengesahan = $request->pengesahan; @@ -195,7 +196,33 @@ class KelulusanController extends Controller $audit = new Audit(); $audit->users = (isset($request->namakhazanah) ? $request->namakhazanah : ''); - $audit->actions = "Pengesahan Kelulusan 75%"; + $audit->actions = $request->actions ?? "pengesahan kelulusan 75%"; + + // Only prepare detailed audit data for Pampasan approval + if($request->actions == 'Pengesahan Pembayaran Pampasan') { + // Prepare data for audit - ensure it's an array + $auditData = []; + + // If kelulusan is a scalar (update result), create array structure + if (is_scalar($kelulusan) || is_null($kelulusan)) { + $auditData = ['update_result' => $kelulusan]; + } else { + $auditData = $kelulusan; + } + + // Add namapelulus and norujukanasal to the audit data + if(isset($request->namaoperasi)) { + $auditData['namapelulus'] = !empty($request->namaoperasi) ? $request->namaoperasi : null; + } + if(isset($request->norujukan)) { + $auditData['norujukan'] = !empty($request->norujukan) ? $request->norujukan : null; + } + } else { + // For other actions, use simple kelulusan data + $auditData = $kelulusan; + } + + $audit->new_data = json_encode($auditData); $audit->kodcaw = $kodcaw; $audit->created_at = $harini; $audit->updated_at = $harini; @@ -323,9 +350,7 @@ public function create(REQUEST $request,$kodcaw,$norujukan,$roles) if($roles == "khazanah") { - $kelulusan=Mohon::on($cawangan['mysql']) - ->create([ - + $createData = [ 'tarikh'=> $harini->toDateString(), 'norujukan'=> $norujukan, 'siri' => $request->siri, @@ -339,10 +364,14 @@ public function create(REQUEST $request,$kodcaw,$norujukan,$roles) 'jenistebus' => $request->jenistebus, 'teller' => $request->teller, 'pelulus' => ($request->pelulus) ? $request->pelulus : '' + ]; + // Add peloperasi if status is Kelulusan Pengeluaran Pampasan + if($request->status == 'Kelulusan Pengeluaran Pampasan' && isset($request->peloperasi)) { + $createData['peloperasi'] = $request->peloperasi; + } - - ]); + $kelulusan=Mohon::on($cawangan['mysql'])->create($createData); } else if($roles == "operasi") { @@ -369,7 +398,7 @@ public function create(REQUEST $request,$kodcaw,$norujukan,$roles) $audit = new Audit(); $audit->users = (isset($request->teller) ? $request->teller : ''); - $audit->actions = "Minta Pengesahan kelulusan 75%"; + $audit->actions = $request->actions ?? "Minta Pengesahan kelulusan 75%"; $audit->new_data = json_encode($kelulusan); $audit->kodcaw = $kodcaw; $audit->created_at = $harini; diff --git a/app/Http/Controllers/LelongController.php b/app/Http/Controllers/LelongController.php index 2fadd77..d959f20 100644 --- a/app/Http/Controllers/LelongController.php +++ b/app/Http/Controllers/LelongController.php @@ -1069,44 +1069,79 @@ class LelongController extends Controller public function exportLelong(Request $request) { - $currentDate = Carbon::now(); - $currentDate = $currentDate->toDateString(); + $currentDate = Carbon::now()->toDateString(); - $cawangan = Cawangan::on('mysql7')->where('kodcaw', $request->kodcaw)->first(); + // --- Step 0: Dapatkan Cawangan --- + $cawangan = Cawangan::on('mysql7') + ->where('kodcaw', $request->kodcaw) + ->first(); - $batchlel = BatchLel::on($cawangan['mysql']) - ->select('batchno') - ->orderBy('batchno', 'desc') - ->first(); + if (!$cawangan) { + Log::error("Export Lelong gagal: cawangan tidak ditemui", ['kodcaw' => $request->kodcaw]); + return response()->json(['error' => 'Cawangan tidak ditemui'], 404); + } - $newBatchNo = $batchlel->batchno + 1; - - $newBatchLel = BatchLel::on($cawangan['mysql'])->create([ - 'kodcaw' => $request->kodcaw, - 'batchno' => $newBatchNo, - 'tarikh' => $request->tarikh, - 'tarikh2' => $request->tarikh, - 't_daftar' => $currentDate, - 'masadari' => $request->masadari, - 'masahingga' => $request->masahingga + Log::info("Mula Export Lelong", [ + 'kodcaw' => $cawangan->kodcaw, + 'nama_cawangan' => $cawangan->details_caw, ]); - $lelong = Lelong::on($cawangan['mysql']) - ->select('sirilel') - ->orderBy('batchno', 'desc') - ->first(); + // --- Step 1: Batch (Cegah duplicate) --- + $batchlel = BatchLel::on($cawangan['mysql']) + ->where('kodcaw', $request->kodcaw) + ->whereDate('tarikh', $request->tarikh) + ->where('masadari', $request->masadari) + ->where('masahingga', $request->masahingga) + ->first(); + + if (!$batchlel) { + $lastBatchNo = BatchLel::on($cawangan['mysql'])->max('batchno') ?? 0; + $newBatchNo = $lastBatchNo + 1; + + $batchlel = BatchLel::on($cawangan['mysql'])->create([ + 'kodcaw' => $request->kodcaw, + 'batchno' => $newBatchNo, + 'tarikh' => $request->tarikh, + 'tarikh2' => $request->tarikh, + 't_daftar' => $currentDate, + 'masadari' => $request->masadari, + 'masahingga' => $request->masahingga + ]); + + Log::info("Batch baru dicipta", ['batchno' => $newBatchNo]); + } else { + $newBatchNo = $batchlel->batchno; + Log::info("Batch sedia ada digunakan", ['batchno' => $newBatchNo]); + } + + // --- Step 2: Siri Lelong Terakhir --- + $lastSiriLelong = Lelong::on($cawangan['mysql'])->max('sirilel') ?? 0; + $lelong_arr = []; + + // --- Step 3: Cegah duplicate Lelong --- + $existingNorujukan = Lelong::on($cawangan['mysql']) + ->whereIn('norujukan', collect($request->lelongbid)->pluck('norujukan')) + ->pluck('norujukan') + ->toArray(); foreach ($request->lelongbid as $index) { + if (in_array($index['norujukan'], $existingNorujukan)) { + Log::warning("Skip Lelong duplicate", ['norujukan' => $index['norujukan']]); + continue; + } - $no_pembeli = Pembeli::on($cawangan['mysql'])->where('nokp', '=', $index['user_details']['nokp'])->select('nopembeli')->first(); - if ($no_pembeli) { - $no_pembeli_data = $no_pembeli->nopembeli; - } else { - $last_no_pembeli = Pembeli::on($cawangan['mysql'])->select('nopembeli')->orderBy('nopembeli', 'desc')->first(); - $no_pembeli_data = $last_no_pembeli->nopembeli + 1; + // --- Step 4: Semak / cipta pembeli --- + $no_pembeli = Pembeli::on($cawangan['mysql']) + ->where('nokp', $index['user_details']['nokp']) + ->value('nopembeli'); - $newPembeli = Pembeli::on($cawangan['mysql'])->create([ - 'nopembeli' => $no_pembeli_data, + if (!$no_pembeli) { + $last_no_pembeli = Pembeli::on($cawangan['mysql']) + ->max('nopembeli') ?? 0; + $no_pembeli = $last_no_pembeli + 1; + + Pembeli::on($cawangan['mysql'])->create([ + 'nopembeli' => $no_pembeli, 'nokp' => $index['user_details']['nokp'], 'nama' => $index['user_details']['name'], 'alamat1' => $index['user_details']['alamat'], @@ -1114,105 +1149,147 @@ class LelongController extends Controller ]); } - $update_gadai = Gadai::on($cawangan['mysql'])->where('norujukan','=',$index['norujukan'])->update(array( - 'sttebus' => "L", - 't_update' => $request->tarikh - )); + // --- Step 5: Update gadai --- + Gadai::on($cawangan['mysql']) + ->where('norujukan', $index['norujukan']) + ->update([ + 'sttebus' => "L", + 't_update' => $request->tarikh + ]); - $lelong_to_be_inserted = new Lelong(); - $lelong_to_be_inserted->batchno = $newBatchNo; - $lelong_to_be_inserted->sirilel = $lelong->sirilel + 1; - $lelong_to_be_inserted->kodcaw = $index['kodcaw']; - $lelong_to_be_inserted->norujukan = $index['norujukan']; - $lelong_to_be_inserted->t_lelong = $request->tarikh; - $lelong_to_be_inserted->hargaasas = $index['hargaasas']; - $lelong_to_be_inserted->hargajual = $index['hargajual']; - $lelong_to_be_inserted->glcode = "1000/010"; - $lelong_to_be_inserted->t_jual = $index['t_jual']; - $lelong_to_be_inserted->nopembeli = $no_pembeli_data; - $lelong_to_be_inserted->jbg = $index['jbg']; - $lelong_to_be_inserted->kadarupah = $index['kadarupah']; - $lelong_to_be_inserted->upahsimpan = $index['upahsimpan']; - $lelong_to_be_inserted->ansuran = $index['ansuran']; - $lelong_to_be_inserted->nilaimarhun = $index['nilaimarhun']; - $lelong_to_be_inserted->nilaimarhuns = $index['nmarhuns']; - $lelong_to_be_inserted->pinjaman = $index['pinjaman']; - $lelong_to_be_inserted->bakiupah = $index['bakiupah']; - $lelong_to_be_inserted->cajlelong = $index['cajlelong']; - $lelong_to_be_inserted->baki = $index['baki']; - $lelong_to_be_inserted->teller = $index['teller']; - $lelong_to_be_inserted->prkod = "01"; - $lelong_to_be_inserted->kodgl = "1000/013"; - $lelong_to_be_inserted->berat = $index['berat']; - $lelong_to_be_inserted->marhun = $index['marhun']; - $lelong_to_be_inserted->fasa = $index['fasa']; - $lelong_to_be_inserted->ujrah = $index['ujrah']; - $lelong_to_be_inserted->onepercent = $index['onepercent']; - $lelong_to_be_inserted->tagujrah = $index['tagujrah']; - - $lelong_arr[] = $lelong_to_be_inserted->attributesToArray(); + // --- Step 6: Simpan data Lelong --- + $lelong_arr[] = [ + 'batchno' => $newBatchNo, + 'sirilel' => ++$lastSiriLelong, + 'kodcaw' => $index['kodcaw'], + 'norujukan' => $index['norujukan'], + 't_lelong' => $request->tarikh, + 'hargaasas' => $index['hargaasas'], + 'hargajual' => $index['hargajual'], + 'glcode' => "1000/010", + 't_jual' => $index['t_jual'], + 'nopembeli' => $no_pembeli, + 'jbg' => $index['jbg'], + 'kadarupah' => $index['kadarupah'], + 'upahsimpan' => $index['upahsimpan'], + 'ansuran' => $index['ansuran'], + 'nilaimarhun' => $index['nilaimarhun'], + 'nilaimarhuns' => $index['nmarhuns'], + 'pinjaman' => $index['pinjaman'], + 'bakiupah' => $index['bakiupah'], + 'cajlelong' => $index['cajlelong'], + 'baki' => $index['baki'], + 'teller' => $index['teller'], + 'prkod' => "01", + 'kodgl' => "1000/013", + 'berat' => $index['berat'], + 'marhun' => $index['marhun'], + 'fasa' => $index['fasa'], + 'ujrah' => $index['ujrah'], + 'onepercent' => $index['onepercent'], + 'tagujrah' => $index['tagujrah'], + ]; } - Lelong::on($cawangan['mysql'])->insert($lelong_arr); - - foreach ($request->lelongbidmarhun as $data) { - $lelmarhun_to_be_inserted = new LelMarhun(); - $lelmarhun_to_be_inserted->kodcaw = $request->kodcaw; - $lelmarhun_to_be_inserted->norujukan = $data['norujukan']; - $lelmarhun_to_be_inserted->bil = $data['bil']; - $lelmarhun_to_be_inserted->marhun = $data['marhun']; - $lelmarhun_to_be_inserted->nota = $data['nota']; - $lelmarhun_to_be_inserted->karat = $data['karat']; - $lelmarhun_to_be_inserted->berat = $data['berat']; - $lelmarhun_to_be_inserted->harga = $data['harga']; - $lelmarhun_to_be_inserted->n_marhun = $data['n_marhun']; - $lelmarhun_to_be_inserted->hargaasas = $data['hargaasas']; - $lelmarhun_to_be_inserted->batch_no = $newBatchNo; - // $lelmarhun_to_be_inserted->beratasal = $; - - $lelmarhun_arr[] = $lelmarhun_to_be_inserted->attributesToArray(); - + if ($lelong_arr) { + Lelong::on($cawangan['mysql'])->insert($lelong_arr); + Log::info("Berjaya simpan lelong baru", ['total' => count($lelong_arr)]); } - LelMarhun::on($cawangan['mysql'])->insert($lelmarhun_arr); + // --- Step 7: LELMARHUN (cegah duplicate) --- + if ($request->lelongbidmarhun) { + $existingMarhun = LelMarhun::on($cawangan['mysql']) + ->whereIn('norujukan', collect($request->lelongbidmarhun)->pluck('norujukan')) + ->pluck('norujukan') + ->toArray(); - if ($request->tunai != null) { - $tunai = Tunai::on($cawangan['mysql'])->create([ - 'tarikh' => $request->tarikh, - 'kodcaw' => $request->kodcaw, - 'kodlaluan' => "LELONG", - 'masuk' => $request->tunai, - 'baki' => $request->tunai, - ]); + $lelmarhun_arr = collect($request->lelongbidmarhun) + ->reject(fn($data) => in_array($data['norujukan'], $existingMarhun)) + ->map(function ($data) use ($request, $newBatchNo) { + return [ + 'kodcaw' => $request->kodcaw, + 'norujukan' => $data['norujukan'], + 'bil' => $data['bil'], + 'marhun' => $data['marhun'], + 'nota' => $data['nota'], + 'karat' => $data['karat'], + 'berat' => $data['berat'], + 'harga' => $data['harga'], + 'n_marhun' => $data['n_marhun'], + 'hargaasas' => $data['hargaasas'], + 'batch_no' => $newBatchNo + ]; + }) + ->toArray(); + + if ($lelmarhun_arr) { + LelMarhun::on($cawangan['mysql'])->insert($lelmarhun_arr); + Log::info("LelMarhun baru disimpan", ['total' => count($lelmarhun_arr)]); + } } - if ($request->gldetail != null) { - $gldetail = GlDetail::on($cawangan['mysql'])->create([ - 'kodcaw' => $request->kodcaw, - 'tarikh' => $request->tarikh, - 'dtacct' => "1000/010", - 'ktacct' => "1000/020", - 'descpt' => "SERAHAN LELONG ONLINE, " . $request->tarikh, - 'amaun' => $request->gldetail, - 'teller' => "LELONG ONLINE", - 'serahan' => $request->gldetail, - ]); + // --- Step 8: GL dan Tunai (check duplicate descpt) --- + if ($request->tunai > 0) { + $existsTunai = Tunai::on($cawangan['mysql']) + ->where('kodcaw', $request->kodcaw) + ->where('tarikh', $request->tarikh) + ->where('kodlaluan', 'LELONG') + ->exists(); + + if (!$existsTunai) { + Tunai::on($cawangan['mysql'])->create([ + 'tarikh' => $request->tarikh, + 'kodcaw' => $request->kodcaw, + 'kodlaluan' => "LELONG", + 'masuk' => $request->tunai, + 'baki' => $request->tunai, + ]); + Log::info("Rekod Tunai lelong dimasukkan"); + } else { + Log::warning("Skip Tunai duplicate"); + } } - if ($request->gldetailcdm != null) { - GlDetail::on($cawangan['mysql'])->create([ - 'kodcaw' => $request->kodcaw, - 'tarikh' => $request->tarikh, - 'dtacct' => "1000/010", - 'ktacct' => "1000/020", - 'descpt' => "SERAHAN LELONG CDM, " . $request->tarikh, - 'amaun' => $request->gldetailcdm, - 'teller' => "LELONG ONLINE", - 'serahan' => $request->gldetailcdm, - ]); + $glDescs = [ + 'SERAHAN LELONG ONLINE' => $request->gldetail, + 'SERAHAN LELONG CDM' => $request->gldetailcdm, + ]; + + foreach ($glDescs as $desc => $amount) { + if ($amount > 0) { + $existsGl = GlDetail::on($cawangan['mysql']) + ->where('kodcaw', $request->kodcaw) + ->where('tarikh', $request->tarikh) + ->where('descpt', 'like', "%{$desc}%") + ->exists(); + + if (!$existsGl) { + GlDetail::on($cawangan['mysql'])->create([ + 'kodcaw' => $request->kodcaw, + 'tarikh' => $request->tarikh, + 'dtacct' => "1000/010", + 'ktacct' => "1000/020", + 'descpt' => "{$desc}, {$request->tarikh}", + 'amaun' => $amount, + 'teller' => "LELONG ONLINE", + 'serahan' => $amount, + ]); + Log::info("Rekod GL dimasukkan", ['desc' => $desc]); + } else { + Log::warning("Skip GL duplicate", ['desc' => $desc]); + } + } } - return response()->json("success"); + // --- Step 9: Log Akhir --- + Log::info('Berjaya Export Cawangan:', [ + 'kodcaw' => $cawangan->kodcaw, + 'nama_cawangan' => $cawangan->details_caw, + 'batch_baru' => $newBatchNo, + 'total_lelong' => count($lelong_arr), + ]); + + return response()->json(['status' => 'success']); } public function getRingkasanHarian(Request $request){ @@ -1318,42 +1395,53 @@ class LelongController extends Controller public function showAllLelongByCawanganBatchno($kodcaw) { - $item = array('PMT','batu','permata'); - $cawangan = Cawangan::on('mysql7')->where('kodcaw','=',$kodcaw)->first(); + $item = ['PMT', 'batu', 'permata']; + + // Semak kewujudan cawangan dulu + $cawangan = Cawangan::on('mysql7')->where('kodcaw', $kodcaw)->first(); + if (!$cawangan) { + return response()->json(['error' => 'Cawangan tidak dijumpai.'], 404); + } + + // Ambil data lelong $lelong_data = Lelong::on($cawangan['mysql']) - ->leftJoin('gadai', 'gadai.norujukan', '=', 'lelong.norujukan') - ->join('lelmarhun', 'lelmarhun.norujukan', '=', 'lelong.norujukan') - ->whereNull('upah12') - // ->where('lelong.marhun', 'like', '%PMT%') - // ->orWhere('lelong.marhun', 'like', '%batu%') - // ->orWhere('lelong.marhun', 'like', '%permata%') - ->Where(function ($query) use($item) { - for ($i = 0; $i < count($item); $i++){ - $query->orwhere('lelmarhun.nota', 'like', '%' . $item[$i] .'%'); - } - }) - ->orderBy('lelong.t_lelong','asc') - ->select('lelong.t_lelong','gadai.t_gadai','gadai.nokp','lelong.pinjaman','lelong.baki','lelong.batchno','lelong.norujukan') - ->whereNull('upah12') - ->distinct() - ->get(); - // dd($lelong_data); + ->leftJoin('gadai', 'gadai.norujukan', '=', 'lelong.norujukan') + ->join('lelmarhun', 'lelmarhun.norujukan', '=', 'lelong.norujukan') + ->whereNull('upah12') + ->where(function ($query) use ($item) { + foreach ($item as $i) { + $query->orWhere('lelmarhun.nota', 'like', '%' . $i . '%'); + } + }) + ->orderBy('lelong.t_lelong', 'asc') + ->select( + 'lelong.t_lelong', + 'gadai.t_gadai', + 'gadai.nokp', + 'lelong.pinjaman', + 'lelong.baki', + 'lelong.batchno', + 'lelong.norujukan' + ) + ->distinct() + ->get(); + + // Group by batch number $groupbybatch = $lelong_data->groupBy('batchno'); $lelong = []; - foreach($groupbybatch as $index=>$lelongData){ + foreach ($groupbybatch as $batchno => $lelongData) { $total_pembiayaan = $lelongData->sum('pinjaman'); - // dd($total_pembiayaan); - $total_lelong = $lelongData->count('norujukan'); - array_push($lelong,[ - // "upah12"=> $lelongData->upah12, - "t_lelong"=> $lelongData->groupBy('t_lelong'), - "batchno"=> $index, - "total_pembiayaan"=> $total_pembiayaan, - "total_lelong"=> $total_lelong, - "kodcaw"=> $kodcaw, - ]); - // dd($lelong); + $total_lelong = $lelongData->count(); + $t_lelong = optional($lelongData->first())->t_lelong; // elak error kalau kosong + + $lelong[] = [ + 't_lelong' => $t_lelong, + 'batchno' => $batchno, + 'total_pembiayaan' => $total_pembiayaan, + 'total_lelong' => $total_lelong, + 'kodcaw' => $kodcaw, + ]; } return response()->json($lelong); } @@ -1895,4 +1983,30 @@ class LelongController extends Controller return response()->json($arrayblm); } + public function getBakiLelongByTeller($kodcaw, Request $request) + { + $cawangan = Cawangan::on('mysql7')->where('kodcaw', $kodcaw)->first(); + + $date = $request->tarikh; + + $rugiLelong = TuntutBaki::on($cawangan['mysql']) + ->whereDate('tarikh', $date) + ->where('jumlah', '<', 0) + ->where('teller','=', $request->kodlaluan) + ->sum('jumlah'); + + $bakiLelong = TuntutBaki::on($cawangan['mysql']) + ->whereDate('tarikh', $date) + ->where('jumlah', '>', 0) + ->where('teller','=', $request->kodlaluan) + ->sum('jumlah'); + + return response()->json([ + 'tarikh' => $date, + 'cawangan' => $kodcaw, + 'rugi_lelong' => $rugiLelong, + 'baki_lelong' => $bakiLelong + ], 200); + } + } diff --git a/app/Http/Controllers/MarhunController.php b/app/Http/Controllers/MarhunController.php index 53c44d3..d35e7f1 100644 --- a/app/Http/Controllers/MarhunController.php +++ b/app/Http/Controllers/MarhunController.php @@ -203,7 +203,10 @@ class MarhunController extends Controller $marhun = Marhun::on($cawangan['mysql']) ->select('marhun.norujukan','gadai.nokp','customer.nama','marhun.marhun','marhun.nota','marhun.berat','marhun.karat','marhun.harga','marhun.n_marhun','marhun.t_gadai','marhun.tag_permata', 'marhun.berat_batu_permata') ->rightJoin('gadai', 'gadai.norujukan', '=', 'marhun.norujukan') - ->rightJoin('master_erahn.customer as customer', 'customer.kpbaru','=','gadai.nokp') + ->rightJoin('master_erahn.customer as customer', function($join) { + $join->on('customer.kpbaru', '=', 'gadai.nokp') + ->orOn('customer.kplama', '=', 'gadai.nokp'); + }) ->where('marhun.t_gadai','=',$tarikh) ->orderBy('marhun.t_gadai') ->get(); @@ -221,7 +224,10 @@ class MarhunController extends Controller $marhun = Marhun::on($cawangan['mysql']) ->select('marhun.norujukan','gadai.sttebus','gadai.pinjaman','gadai.nokp','customer.nama','marhun.marhun','marhun.nota','marhun.berat','marhun.karat','marhun.harga','marhun.n_marhun','marhun.t_gadai') ->rightJoin('gadai', 'gadai.norujukan', '=', 'marhun.norujukan') - ->rightJoin('master_erahn.customer as customer', 'customer.kpbaru','=','gadai.nokp') + ->rightJoin('master_erahn.customer as customer', function($join) { + $join->on('customer.kpbaru', '=', 'gadai.nokp') + ->orOn('customer.kplama', '=', 'gadai.nokp'); + }) ->where('marhun.t_gadai','<=',$tarikh) ->whereYear('marhun.t_gadai','=',$current->year) ->where('gadai.sttebus','=','') diff --git a/app/Http/Controllers/MaxPinjamanController.php b/app/Http/Controllers/MaxPinjamanController.php index 734d04b..ed996cd 100644 --- a/app/Http/Controllers/MaxPinjamanController.php +++ b/app/Http/Controllers/MaxPinjamanController.php @@ -2,14 +2,206 @@ namespace App\Http\Controllers; +use App\Audit; +use App\MaxMutuEmas; use App\MaxPinjaman; use Illuminate\Http\Request; - +use Illuminate\Support\Facades\Log; class MaxPinjamanController extends Controller { - public function getAllMaxPinjaman(){ - $pinjaman = MaxPinjaman::on('mysql7')->get(); + public function getAllMaxPinjaman(Request $request) + { + if (config('parameter.max_mutuemas')) { + $data = MaxMutuEmas::on('mysql7')->select('karat', 'teller', 'pc', 'operasi')->get(); + $calculateMargin = $this->calculateMaxPinjamanMutu($data, $request->mutu,$request->total_nilai_marhun); + + $pinjaman = [ + [ + "user_type" => "teller", + "max" => $calculateMargin['teller'], + "teller_pinjaman" => $calculateMargin['teller_pinjaman'] + + ], + [ + "user_type" => "khazanah", + "max" => $calculateMargin['pc'], + "pc_pinjaman" => $calculateMargin['pc_pinjaman'] + ], + [ + "user_type" => "operasi", + "max" => $calculateMargin['operasi'], + "operasi_pinjaman" => $calculateMargin['operasi_pinjaman'] + ] + ]; + } else { + $pinjaman = MaxPinjaman::on('mysql7')->get(); + } return response()->json($pinjaman); } + + public function calculateMaxPinjamanMutu($data, $mutu,$totalMarhun) + { + $totalMaxMarhunPC = 0; + $totalMaxMarhunTeller = 0; + $totalMaxMarhunOperasi = 0; + + if($mutu == null || $totalMarhun == 0){ + return [ + "pc" => 0, + "pc_pinjaman" => 0, + "teller" => 0, + "teller_pinjaman" => 0, + "operasi" => 0, + "operasi_pinjaman" => 0 + ]; + } + $mutuKarat = array_map(function($item) { + return $item[0]; + }, $mutu); + $mutuNilai = array_map(function($item) { + return $item[1]; + }, $mutu); + + foreach($mutuKarat as $index => $karat){ + $margin = $data->where('karat', $karat)->first(); + if($margin){ + $nilai = $mutuNilai[$index]; + $totalMaxMarhunPC += round(($margin->pc/100) * $nilai, 2); + $totalMaxMarhunTeller += round(($margin->teller/100) * $nilai, 2); + $totalMaxMarhunOperasi += round(($margin->operasi/100) * $nilai, 2); + } + } + + $totalMaxPC = $totalMarhun > 0 ? ($totalMaxMarhunPC / $totalMarhun) * 100 : 0; + $totalMaxTeller = $totalMarhun > 0 ? ($totalMaxMarhunTeller / $totalMarhun) * 100 : 0; + $totalMaxOperasi = $totalMarhun > 0 ? ($totalMaxMarhunOperasi / $totalMarhun) * 100 : 0; + return [ + "pc" => round($totalMaxPC,2), + "pc_pinjaman" => round(($totalMaxPC / 100) * $totalMarhun, 2), + "teller" => round($totalMaxTeller,2), + "teller_pinjaman" => round(($totalMaxTeller / 100) * $totalMarhun, 2), + "operasi" => round($totalMaxOperasi,2), + "operasi_pinjaman" => round(($totalMaxOperasi / 100) * $totalMarhun, 2) + ]; + } + + + public function getAllMaxMutuEmas(Request $request) + { + $maxmutuemas = MaxMutuEmas::on('mysql7')->get(); + return response()->json($maxmutuemas); + } + + public function getSpecificMaxMutuEmas(Request $request) + { + $karat = $request->karat; + $nilaimarhun = $request->nilaimarhun; + + $nilaimarhun = preg_replace('/[^0-9.]/', '', $nilaimarhun); // Remove non-numeric characters except decimal point + $nilaimarhun = is_numeric($nilaimarhun) ? (float)$nilaimarhun : 0; + + $maxmutuemas = MaxMutuEmas::on('mysql7')->where('karat', $karat)->first(); + + if($maxmutuemas && $nilaimarhun > 0){ + $maxmutuemas->maxteller = round(($maxmutuemas->teller/100) * $nilaimarhun, 2); + $maxmutuemas->maxpc = round(($maxmutuemas->pc/100) * $nilaimarhun, 2); + $maxmutuemas->maxoperasi = round(($maxmutuemas->operasi/100) * $nilaimarhun, 2); + } else if($maxmutuemas) { + $maxmutuemas->maxteller = 0; + $maxmutuemas->maxpc = 0; + $maxmutuemas->maxoperasi = 0; + } + + return response()->json($maxmutuemas); + } + + public function updateMaxMutuEmas(Request $request) + { + // Validate the request manually for Lumen + $validator = \Illuminate\Support\Facades\Validator::make($request->all(), [ + 'recno' => 'required|integer', + 'karat' => 'required|string|max:10', + 'keterangan' => 'required|string|max:255', + 'teller' => 'required|numeric|min:0|max:100', + 'pc' => 'required|numeric|min:0|max:100', + 'operasi' => 'required|numeric|min:0|max:100', + 'username' => 'required|string|max:255' + ], [ + 'recno.required' => 'Nombor rekod diperlukan.', + 'recno.integer' => 'Nombor rekod mesti berupa nombor.', + 'karat.required' => 'Karat diperlukan.', + 'karat.string' => 'Karat mesti berupa teks.', + 'karat.max' => 'Karat tidak boleh lebih dari 10 aksara.', + 'keterangan.required' => 'Keterangan diperlukan.', + 'keterangan.string' => 'Keterangan mesti berupa teks.', + 'keterangan.max' => 'Keterangan tidak boleh lebih dari 255 aksara.', + 'teller.required' => 'Peratus teller diperlukan.', + 'teller.numeric' => 'Peratus teller mesti berupa nombor.', + 'teller.min' => 'Peratus teller mestilah sekurang-kurangnya 0.', + 'teller.max' => 'Peratus teller tidak boleh melebihi 100.', + 'pc.required' => 'Peratus PC diperlukan.', + 'pc.numeric' => 'Peratus PC mesti berupa nombor.', + 'pc.min' => 'Peratus PC mestilah sekurang-kurangnya 0.', + 'pc.max' => 'Peratus PC tidak boleh melebihi 100.', + 'operasi.required' => 'Peratus operasi diperlukan.', + 'operasi.numeric' => 'Peratus operasi mesti berupa nombor.', + 'operasi.min' => 'Peratus operasi mestilah sekurang-kurangnya 0.', + 'operasi.max' => 'Peratus operasi tidak boleh melebihi 100.', + ]); + + if ($validator->fails()) { + return response()->json([ + 'status' => 'error', + 'message' => 'Pengesahan gagal', + 'errors' => $validator->errors() + ], 422); + } + + $recno = $request->recno; + $karat = $request->karat; + $keterangan = $request->keterangan; + $teller = $request->teller; + $pc = $request->pc; + $operasi = $request->operasi; + $username = $request->username; + + $current = \Carbon\Carbon::now(); + + $maxmutuemas = MaxMutuEmas::on('mysql7')->where('recno', $recno)->first(); + + if ($maxmutuemas) { + $oldmax = $maxmutuemas->toJson(); + + $maxmutuemas->karat = $karat; + $maxmutuemas->keterangan = $keterangan; + $maxmutuemas->teller = $teller; + $maxmutuemas->pc = $pc; + $maxmutuemas->operasi = $operasi; + $maxmutuemas->tarikhupdate = \Carbon\Carbon::now(); + $maxmutuemas->save(); + + Audit::create([ + 'users' => $username, + 'actions' => 'Penukaran Mutu Margin', + 'norujukan' => '-', + 'new_data' => $maxmutuemas->toJson(), + 'old_data' => $oldmax, + 'kodcaw' => 'OPERASI', + 'created_at' => $current, + 'updated_at' => $current, + ]); + + return response()->json([ + 'status' => 'success', + 'message' => 'Max Mutu Emas updated successfully', + 'data' => $maxmutuemas + ]); + } else { + return response()->json([ + 'status' => 'error', + 'message' => 'Record not found' + ], 404); + } + } } \ No newline at end of file diff --git a/app/Http/Controllers/PampasanController.php b/app/Http/Controllers/PampasanController.php new file mode 100644 index 0000000..cdbeb86 --- /dev/null +++ b/app/Http/Controllers/PampasanController.php @@ -0,0 +1,198 @@ +validate($request, [ + 'norujukan' => 'required|string', + 'kodcaw' => 'required|string', + 'jumlah_pampasan' => 'required|numeric', + 'denominasi' => 'required|array', + 'teller' => 'required|string', + ]); + + try { + $cawangan = $this->getCawangan($request->kodcaw); + + if (!$cawangan) { + return $this->errorResponse('Cawangan tidak dijumpai untuk kodcaw: ' . $request->kodcaw, 404); + } + + $pampasan = Pampasan::on($cawangan['mysql']) + ->where('norujukan', $validated['norujukan']) + ->first(); + + $pampasan->update([ + 'jumlah_pampasan' => $validated['jumlah_pampasan'], + 'denominasi' => isset($validated['denominasi']) ? json_encode($validated['denominasi']) : null, + 'teller' => $validated['teller'], + ]); + + return $this->successResponse('Pampasan berjaya dibayar.', $pampasan, 201); + } catch (\Exception $e) { + return $this->errorResponse('Database error: ' . $e->getMessage(), 500); + } + } + + public function updateStatusPampasan(Request $request) + { + $norujukan = $request->norujukan; + + $cawangan = $this->getCawangan($request->kodcaw); + + if (!$cawangan) { + return $this->errorResponse('Cawangan tidak dijumpai untuk kodcaw: ' . $request->kodcaw, 404); + } + + $tebus = Tebus::on($cawangan['mysql'])->where('norujukan', $norujukan)->first(); + + $pampasan = Pampasan::on($cawangan['mysql'])->where("norujukan", $norujukan)->first(); + + $pampasan->status = 1; + + $pampasan->save(); + + // Update corresponding palsu table record status to 1 + Palsu::on($cawangan['mysql']) + ->where('norujukan', $norujukan) + ->update(['status' => 1]); + + return $this->successResponse('Status Pampasan berjaya dituntut.', $pampasan, 201); + } + + public function getPampasan(Request $request) + { + $cawangan_connection = Cawangan::where('kodcaw', $request->kodcaw)->first()->mysql; + + $pampasan = Pampasan::on($cawangan_connection) + ->when($request->filled('norujukan'), function ($query) use ($request) { + return $query->where('norujukan', $request->norujukan); + }) + ->get(); + + + return $this->successResponse('Senarai pampasan', $pampasan, 201); + } + + public function updateAgreementPrintedAt(Request $request) + { + $validated = $this->validate($request, [ + 'norujukan' => 'required|string', + 'kodcaw' => 'required|string', + ]); + + try { + $cawangan = $this->getCawangan($validated['kodcaw']); + + if (!$cawangan) { + return $this->errorResponse('Cawangan tidak dijumpai untuk kodcaw: ' . $validated['kodcaw'], 404); + } + + $pampasan = Pampasan::on($cawangan['mysql'])->where('norujukan', $validated['norujukan'])->first(); + + if (!$pampasan) { + return $this->errorResponse('Pampasan tidak dijumpai untuk norujukan: ' . $validated['norujukan'], 404); + } + + $pampasan->agreement_printed_at = Carbon::now(); + $pampasan->save(); + + return $this->successResponse('Agreement printed timestamp berjaya dikemaskini.', $pampasan, 200); + } catch (\Exception $e) { + return $this->errorResponse('Database error: ' . $e->getMessage(), 500); + } + } + + public function initiatePampasan(Request $request) + { + $validated = $this->validate($request, [ + 'norujukan' => 'required|string', + 'kodcaw' => 'required|string', + 'teller' => 'required|string', + 'baucerno' => 'required|string', + ]); + + try { + $cawangan = $this->getCawangan($validated['kodcaw']); + + if (!$cawangan) { + return $this->errorResponse('Cawangan tidak dijumpai untuk kodcaw: ' . $validated['kodcaw'], 404); + } + + // Find the palsu record + $palsu = Palsu::on($cawangan['mysql'])->where('norujukan', $validated['norujukan'])->first(); + + if (!$palsu) { + return $this->errorResponse('Barang kes tidak dijumpai untuk norujukan: ' . $validated['norujukan'], 404); + } + + // Check if pampasan already exists for this norujukan + $existingPampasan = Pampasan::on($cawangan['mysql'])->where('norujukan', $validated['norujukan'])->first(); + + if ($existingPampasan) { + // If pampasan exists, just update the agreement_printed_at + $existingPampasan->agreement_printed_at = Carbon::now(); + $existingPampasan->save(); + + return $this->successResponse('Agreement printed timestamp berjaya dikemaskini untuk pampasan sedia ada.', $existingPampasan, 200); + } + + // Create new pampasan record based on palsu data + $pampasan = Pampasan::on($cawangan['mysql'])->create([ + 'norujukan' => $palsu->norujukan, + 'baucerno' => $validated['baucerno'], + 'kodcaw' => $palsu->kodcaw, + 'jumlah_pampasan' => $palsu->nilaimarhun, + 'teller' => $validated['teller'], + 'status' => 0, + 'agreement_printed_at' => Carbon::now(), + ]); + + return $this->successResponse('Pampasan berjaya daftar dari rekod barang kes.', $pampasan, 201); + } catch (\Exception $e) { + return $this->errorResponse('Database error: ' . $e->getMessage(), 500); + } + } + + private function getCawangan($kodcaw) + { + $cawangan = Cawangan::on('mysql7')->where('kodcaw', $kodcaw)->first(); + + if (!$cawangan) { + return null; + } + + return $cawangan; + } + + private function errorResponse($message, $statusCode = 404) + { + return response()->json([ + 'success' => false, + 'message' => $message, + ], $statusCode); + } + + private function successResponse($message, $data = null, $statusCode = 200) + { + return response()->json([ + 'success' => true, + 'message' => $message, + 'data' => $data, + ], $statusCode); + } +} diff --git a/app/Http/Controllers/Reports/AnalisaController.php b/app/Http/Controllers/Reports/AnalisaController.php index df7401b..86a4b27 100644 --- a/app/Http/Controllers/Reports/AnalisaController.php +++ b/app/Http/Controllers/Reports/AnalisaController.php @@ -11,6 +11,11 @@ use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; use App\Services\Reports\GadaianService as ReportGadaianService; use App\Helper; +use Carbon\Carbon; +use App\Pekerjaan; +use App\Poskod; +use App\TransactionOnline; +use Log; use App\Services\Reports\RingkasanHarianService as ReportRingkasanHarianService; @@ -162,11 +167,484 @@ public function getSummaryLaporanPelangganAktif(Request $request) return response()->json($response); } + public function getActiveCawanganConnections() + { + $cawangan_details = Cawangan::select(['details_caw', 'mysql'])->get(); + + $cawangan_details = $cawangan_details->filter(fn($x) => !in_array(strtolower($x->details_caw), config('report.excluded_cawangan'))); + + $connection_active_cawangan = Helper::getActiveCawanganDbConnection(); + + return collect($cawangan_details->filter(fn($x) => in_array($x->mysql, $connection_active_cawangan))); + + } + + public function getSummaryLaporanDataPelanggan(Request $request) + { + $year = $request->year; + if (!$year) { + return response()->json(['error' => 'Sila pilih tahun'], 400); + } + + $startOfYear = Carbon::create($year, 1, 1)->startOfDay(); + $endOfYear = Carbon::create($year, 12, 31)->endOfDay(); + + Carbon::setLocale('ms'); + + // 1️⃣ Ambil semua pelanggan tahun ini + $pelanggan = Customer::whereYear('tarikhdaftar', $year) + ->select('id','nama','kpbaru','kplama','t_lahir','jantina', + 'kodkerja','poskod','kodcaw','tarikhdaftar','tujuangadai','nopelanggan') + ->get(); + + $connections = $this->getActiveCawanganConnections(); + + // Ambil semua pekerjaan & poskod sekali untuk map cepat + $pekerjaanAll = Pekerjaan::pluck('keterangan','kodkerja'); + $poskodAll = Poskod::with('daerah')->get()->keyBy('poskod'); + + // 2️⃣ Ambil semua nokp pelanggan + $nokps = $pelanggan->map(fn($p) => $p->kpbaru ?? $p->kplama)->filter()->values(); + + // 3️⃣ Ambil semua transaksi gadai + tebus untuk nokp tu dari semua cawangan + $allTransaksi = collect(); + foreach ($connections as $conn) { + $data = DB::connection($conn->mysql) + ->table('gadai as g') + ->leftJoin('tebus as t', 'g.norujukan', '=', 't.norujukan') + ->leftJoin('lelong as l', 'g.norujukan', '=', 'l.norujukan') + ->whereIn('g.nokp', $nokps) + ->whereBetween('g.t_gadai', [$startOfYear, $endOfYear]) // ⬅️ dalam tahun sahaja + ->select( + 'g.nokp', + 'g.norujukan', + 'g.t_gadai', + 't.t_tebus', + 'g.pinjaman', + 'g.upah12', + 'g.tempoh', + 'l.t_lelong', + 'g.sttebus', + ) + ->get(); + $allTransaksi = $allTransaksi->concat($data); + } + + // 4️⃣ Group by nokp + $transGrouped = $allTransaksi->groupBy('nokp'); + + // 5️⃣ Ambil semua norujukan transaksi online + $onlineNorujukan = TransactionOnline::pluck('norujukan')->unique()->values(); + + + // 6️⃣ Map pelanggan + $result = $pelanggan->map(function($row) use ($transGrouped, $onlineNorujukan, $pekerjaanAll, $poskodAll, $year) { + + $nokp = $row->kpbaru ?? $row->kplama ?? null; + + $tempohData = $transGrouped->get($nokp, collect()); + + // Norujukan pelanggan spesifik + $norujukanPelanggan = $tempohData->pluck('norujukan')->unique()->values(); + + // Cara Bayaran + // $caraBayaran = $norujukanPelanggan->intersect($onlineNorujukan)->isNotEmpty() ? 'Online' : 'Kaunter'; + $adaOnline = $norujukanPelanggan->contains(fn($nr) => isset($onlineNorujukan[$nr])); + $caraBayaran = $adaOnline ? 'Online' : 'Kaunter'; + if ($adaOnline) { + \Log::info("Pelanggan {$row->nama} ({$nokp}): Bayaran Online - YA"); + } + // Bilangan transaksi + $bilTransaksi = $tempohData->count(); + + // Bilangan Belum tebus + $endOfYear = Carbon::create($year, 12, 31)->endOfDay(); + $bilOutstanding = $tempohData + ->filter(function ($row) use ($endOfYear) { + + // masih belum tebus langsung + if (empty($row->sttebus)) { + return true; + } + + // dah tebus, tapi tebus selepas hujung tahun + return Carbon::parse($row->t_tebus)->gt($endOfYear); + }) + ->count(); + + // Bilangan tebus + $bilTebus = $tempohData->whereNotNull('t_tebus')->count(); + + // Jumlah pinjaman + $jumlahPinjaman = $tempohData->sum('pinjaman'); + + // Jumlah ujrah ikut tempoh surat + $jumlahUjrah = $tempohData->reduce(function ($carry, $trx) { + if (!$trx->upah12 || !$trx->tempoh) return $carry; + return $carry + ($trx->upah12 / 12 * $trx->tempoh); + }, 0); + + // Tarikh mula & tamat + $tarikhMula = $tempohData->min('t_gadai'); + $tarikhTamat = $tempohData->max('t_tebus'); + $tarikhLelong = $tempohData->max('t_lelong'); + + // Tempoh Pajakan + if (!$tarikhMula) { + $tempohPajakan = '-'; + } elseif (!$tarikhTamat || $tarikhMula == $tarikhTamat) { + $tempohPajakan = Carbon::parse($tarikhMula)->translatedFormat('M Y'); + } else { + $tempohPajakan = Carbon::parse($tarikhMula)->translatedFormat('M Y') . + ' - ' . + Carbon::parse($tarikhTamat)->translatedFormat('M Y'); + } + + // Hari sejak transaksi terakhir + $hariTempohPajakan = $tarikhMula + ? Carbon::parse($tarikhMula)->diffInDays($tarikhTamat ? Carbon::parse($tarikhTamat) : Carbon::now()) + : null; + + // Tujuan gadai + $tujuangadai = $row->tujuangadai ?: '-'; + + // Status aktif: ada transaksi dalam tahun tu + $now = Carbon::now(); + + $endOfYear = Carbon::create($year, 12, 31)->endOfDay(); + $startOfYear = Carbon::create($year, 1, 1)->startOfDay(); + + $statusAktif = $tempohData->contains(function ($trx) use ($startOfYear, $endOfYear) { + + if (!$trx->t_gadai) return false; + + $tGadai = Carbon::parse($trx->t_gadai); + $tTebus = $trx->t_tebus ? Carbon::parse($trx->t_tebus) : null; + + // SAG wujud dalam tahun laporan + return + $tGadai->lte($endOfYear) && + ( + is_null($tTebus) || // belum ditebus + $tTebus->gte($startOfYear) // ditebus dalam / selepas tahun + ); + }); + + // Umur + $umur = $row->t_lahir ? Carbon::parse($row->t_lahir)->age : null; + + // Pekerjaan + $pekerjaan = $row->kodkerja + ? ($pekerjaanAll[ltrim($row->kodkerja,'0')] ?? 'Lain-lain') + : '-'; + + // Daerah / lokasi + $lokasi = $row->poskod && isset($poskodAll[$row->poskod]) + ? $poskodAll[$row->poskod]->daerah->namadaerah ?? 'Lain-lain' + : 'Lain-lain'; + + return [ + 'cawangan' => $row->kodcaw ?? '-', + 'nama' => $row->nama, + 'nopelanggan' => $row->nopelanggan, + 'nokp' => $nokp ?? '-', + 'tarikhdaftar' => Carbon::parse($row->tarikhdaftar)->format('d-m-Y'), + 'umur' => $umur, + 'jantina' => $row->jantina ?? '-', + 'pekerjaan' => $pekerjaan, + 'daerah' => $lokasi, + 'tempoh_pajakan' => $tempohPajakan, + 'tarikh_mula' => $tarikhMula ? Carbon::parse($tarikhMula)->format('d-m-Y') : null, + 'tarikh_tamat' => $tarikhTamat ? Carbon::parse($tarikhTamat)->format('d-m-Y') : null, + 'hari_sejak_transaksi' => $hariTempohPajakan, + 'bil_transaksi' => $bilTransaksi, + 'bil_outstanding' => $bilOutstanding, + 'bil_tebus' => $bilTebus, + 'jumlah_pinjaman' => $jumlahPinjaman, + 'norujukan' => $norujukanPelanggan, + 'jumlah_ujrah' => $jumlahUjrah, + 'tujuan_gadai' => $tujuangadai, + 'status_aktif' => $statusAktif ? 'AKTIF' : 'TIDAK AKTIF', + 'cara_bayaran' => $caraBayaran, + 'tarikh_lelong' => $tarikhLelong ? Carbon::parse($tarikhLelong)->format('d-m-Y') : null, + ]; + }); + + return response()->json([ + 'year' => $year, + 'summary' => [ + 'total_pelanggan' => $result->count(), + 'jumlah_cawangan' => $result->pluck('cawangan')->unique()->count(), + ], + 'pelanggan' => $result->values(), + ], 200); + } + + private function formatTempohPajakan($start, $end) + { + if (!$start || !$end) { + return '-'; + } + + $mula = Carbon::parse($start); + $tamat = Carbon::parse($end); + + if ($mula->year === $tamat->year) { + return $mula->translatedFormat('M') . ' – ' . + $tamat->translatedFormat('M Y'); + } + + return $mula->translatedFormat('M Y') . ' – ' . + $tamat->translatedFormat('M Y'); + } + public function getSummaryLaporanDataPelangganBycaw(Request $request) + { + $year = $request->year; + if (!$year) { + return response()->json(['error' => 'Sila pilih tahun'], 400); + } + // =============================== + // INPUT CAWANGAN (MULTIPLE) + // =============================== + $cawangan = $request->input('cawangan', []); + if (!is_array($cawangan)) { + $cawangan = [$cawangan]; + } + + + $startOfYear = Carbon::create($year, 1, 1)->startOfDay(); + $endOfYear = Carbon::create($year, 12, 31)->endOfDay(); + + Carbon::setLocale('ms'); + + // =============================== + // 1️⃣ AMBIL PELANGGAN (FILTER CAWANGAN) + // =============================== + $pelangganQuery = Customer::whereYear('tarikhdaftar', $year); + + if (!empty($cawangan)) { + $pelangganQuery->whereIn('kodcaw', $cawangan); + } + + $pelanggan = $pelangganQuery + ->select( + 'id','nama','kpbaru','kplama','t_lahir','jantina', + 'kodkerja','poskod','kodcaw','tarikhdaftar', + 'tujuangadai','nopelanggan' + ) + ->get(); + + if ($pelanggan->isEmpty()) { + return response()->json([ + 'year' => $year, + 'summary' => [ + 'total_pelanggan' => 0, + 'jumlah_cawangan' => 0, + ], + 'pelanggan' => [] + ], 200); + } + + // =============================== + // 2️⃣ CONNECTION CAWANGAN + // =============================== + $connections = $this->getActiveCawanganConnections(); + + // =============================== + // 3️⃣ MASTER DATA + // =============================== + $pekerjaanAll = Pekerjaan::pluck('keterangan', 'kodkerja'); + $poskodAll = Poskod::with('daerah')->get()->keyBy('poskod'); + + // =============================== + // 4️⃣ NOKP PELANGGAN + // =============================== + $nokps = $pelanggan + ->map(fn($p) => $p->kpbaru ?? $p->kplama) + ->filter() + ->values(); + + // =============================== + // 5️⃣ TRANSAKSI GADAI / TEBUS + // =============================== + $allTransaksi = collect(); + + foreach ($connections as $conn) { + $data = DB::connection($conn->mysql) + ->table('gadai as g') + ->leftJoin('tebus as t', 'g.norujukan', '=', 't.norujukan') + ->leftJoin('lelong as l', 'g.norujukan', '=', 'l.norujukan') + ->whereIn('g.nokp', $nokps) + ->whereBetween('g.t_gadai', [$startOfYear, $endOfYear]) + ->select( + 'g.nokp', + 'g.norujukan', + 'g.t_gadai', + 't.t_tebus', + 'g.pinjaman', + 'g.upah12', + 'g.tempoh', + 'l.t_lelong', + 'g.sttebus' + ) + ->get(); + + $allTransaksi = $allTransaksi->concat($data); + } + + $transGrouped = $allTransaksi->groupBy('nokp'); + + // =============================== + // 6️⃣ NORUJUKAN BAYARAN ONLINE + // =============================== + $onlineNorujukan = TransactionOnline::pluck('norujukan')->unique(); + + // =============================== + // 7️⃣ MAP DATA PELANGGAN + // =============================== + $result = $pelanggan->map(function ($row) use ( + $transGrouped, + $onlineNorujukan, + $pekerjaanAll, + $poskodAll, + $year + ) { + + $nokp = $row->kpbaru ?? $row->kplama; + + $tempohData = $transGrouped->get($nokp, collect()); + + $norujukanPelanggan = $tempohData->pluck('norujukan')->unique(); + + // Cara Bayaran + $adaOnline = $norujukanPelanggan + ->intersect($onlineNorujukan) + ->isNotEmpty(); + + $caraBayaran = $adaOnline ? 'Online' : 'Kaunter'; + + // Bilangan + $bilTransaksi = $tempohData->count(); + + $bilOutstanding = $tempohData->filter(function ($row) use ($year) { + $endOfYear = Carbon::create($year, 12, 31)->endOfDay(); + + if (empty($row->sttebus)) return true; + + return Carbon::parse($row->t_tebus)->gt($endOfYear); + })->count(); + + $bilTebus = $tempohData->whereNotNull('t_tebus')->count(); + + // Jumlah + $jumlahPinjaman = $tempohData->sum('pinjaman'); + + $jumlahUjrah = $tempohData->reduce(function ($carry, $trx) { + if (!$trx->upah12 || !$trx->tempoh) return $carry; + return $carry + ($trx->upah12 / 12 * $trx->tempoh); + }, 0); + + // Tarikh + $tarikhMula = $tempohData->min('t_gadai'); + $tarikhTamat = $tempohData->max('t_tebus'); + $tarikhLelong = $tempohData->max('t_lelong'); + + // Tempoh Pajakan + if (!$tarikhMula) { + $tempohPajakan = '-'; + } elseif (!$tarikhTamat || $tarikhMula == $tarikhTamat) { + $tempohPajakan = Carbon::parse($tarikhMula)->translatedFormat('M Y'); + } else { + $tempohPajakan = + Carbon::parse($tarikhMula)->translatedFormat('M Y') . + ' - ' . + Carbon::parse($tarikhTamat)->translatedFormat('M Y'); + } + + // Hari sejak transaksi terakhir + $hariTempohPajakan = $tarikhMula + ? Carbon::parse($tarikhMula)->diffInDays($tarikhTamat ? Carbon::parse($tarikhTamat) : Carbon::now()) + : null; + + // Tujuan gadai + $tujuangadai = $row->tujuangadai ?: '-'; + + // Status aktif: ada transaksi dalam tahun tu + $now = Carbon::now(); + + // Status Aktif + $startOfYear = Carbon::create($year, 1, 1)->startOfDay(); + $endOfYear = Carbon::create($year, 12, 31)->endOfDay(); + + $statusAktif = $tempohData->contains(function ($trx) use ($startOfYear, $endOfYear) { + if (!$trx->t_gadai) return false; + + $tGadai = Carbon::parse($trx->t_gadai); + $tTebus = $trx->t_tebus ? Carbon::parse($trx->t_tebus) : null; + + return $tGadai->lte($endOfYear) && + (is_null($tTebus) || $tTebus->gte($startOfYear)); + }); + + // Umur + $umur = $row->t_lahir ? Carbon::parse($row->t_lahir)->age : null; + + // Pekerjaan + $pekerjaan = $row->kodkerja + ? ($pekerjaanAll[ltrim($row->kodkerja, '0')] ?? 'Lain-lain') + : '-'; + + // Daerah + $lokasi = $row->poskod && isset($poskodAll[$row->poskod]) + ? ($poskodAll[$row->poskod]->daerah->namadaerah ?? 'Lain-lain') + : 'Lain-lain'; + + + return [ + 'cawangan' => $row->kodcaw, + 'nama' => $row->nama, + 'nopelanggan' => $row->nopelanggan, + 'nokp' => $nokp, + 'tarikhdaftar' => Carbon::parse($row->tarikhdaftar)->format('d-m-Y'), + 'umur' => $umur, + 'jantina' => $row->jantina, + 'pekerjaan' => $pekerjaan, + 'daerah' => $lokasi, + 'tempoh_pajakan' => $tempohPajakan, + 'tarikh_mula' => $tarikhMula ? Carbon::parse($tarikhMula)->format('d-m-Y') : null, + 'tarikh_tamat' => $tarikhTamat ? Carbon::parse($tarikhTamat)->format('d-m-Y') : null, + 'hari_sejak_transaksi' => $hariTempohPajakan, + 'bil_transaksi' => $bilTransaksi, + 'bil_outstanding' => $bilOutstanding, + 'bil_tebus' => $bilTebus, + 'jumlah_pinjaman' => $jumlahPinjaman, + 'jumlah_ujrah' => $jumlahUjrah, + 'tujuan_gadai' => $tujuangadai, + 'cara_bayaran' => $caraBayaran, + 'status_aktif' => $statusAktif ? 'AKTIF' : 'TIDAK AKTIF', + 'tarikh_lelong' => $tarikhLelong + ? Carbon::parse($tarikhLelong)->format('d-m-Y') + : null, + ]; + }); + + $result = $result->sortBy('cawangan')->values(); + + return response()->json([ + 'year' => $year, + 'cawangan' => $cawangan, + 'summary' => [ + 'total_pelanggan' => $result->count(), + 'jumlah_cawangan' => $result->pluck('cawangan')->unique()->count(), + ], + 'pelanggan' => $result, + ], 200); + } } diff --git a/app/Http/Controllers/Reports/AuditTrailController.php b/app/Http/Controllers/Reports/AuditTrailController.php new file mode 100644 index 0000000..a24ff1a --- /dev/null +++ b/app/Http/Controllers/Reports/AuditTrailController.php @@ -0,0 +1,78 @@ +get('limit', 100); + + $audit_trails = Audit::query() + ->when($request->filled('norujukan'), fn($q) => $q->where('norujukan', $request->norujukan)) + ->when($request->filled('actions'), fn($q) => $q->where('actions', $request->actions)) + ->orderBy('created_at', 'desc') + ->limit($limit) + ->get(); + + return response()->json($audit_trails); + } + + public function AuditTrailOperasi(Request $request) + { + $date_first = $request->get('date', null); + $date_till = $request->get('date_till', null); + + $audit_trails = Audit::query() + ->where('kodcaw', 'operasi') + ->whereDate('created_at', '>=', $date_first) + ->whereDate('created_at', '<=', $date_till) + ->orderBy('created_at', 'asc') + ->get(); + + $audit_trails->map(function ($audit) { + // Convert from UTC to Malaysia timezone (UTC+8) + $audit->created_at = $audit->created_at->format('Y-m-d H:i:s'); + + // Get differences between old_data and new_data + $old_data = json_decode($audit->old_data, true) ?? []; + $new_data = json_decode($audit->new_data, true) ?? []; + + $differences = []; + + // Find changed fields + foreach ($new_data as $key => $new_value) { + if ($key === 'tarikhupdate') continue; + + $old_value = $old_data[$key] ?? null; + if ($old_value !== $new_value) { + $differences[$key] = [ + 'old' => $old_value, + 'new' => $new_value + ]; + } + } + + // Check for removed fields + foreach ($old_data as $key => $old_value) { + if ($key === 'tarikhupdate') continue; + + if (!array_key_exists($key, $new_data)) { + $differences[$key] = [ + 'old' => $old_value, + 'new' => null + ]; + } + } + + $audit->differences = $differences; + return $audit; + }); + + return response()->json($audit_trails); + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Reports/LelonganController.php b/app/Http/Controllers/Reports/LelonganController.php index 1e2195f..539ae2e 100644 --- a/app/Http/Controllers/Reports/LelonganController.php +++ b/app/Http/Controllers/Reports/LelonganController.php @@ -60,6 +60,7 @@ class LelonganController extends Controller sum(lelong.cajlain) as sum_cajlain, sum(lelong.cajlelong) as sum_cajlelong, sum(lelong.hargajual) as sum_hargajual, + sum(lelong.hargaasas) as sum_hargaasas, sum(lelong.baki) as sum_baki')); diff --git a/app/Http/Controllers/Reports/OutstandingController.php b/app/Http/Controllers/Reports/OutstandingController.php index 7b8c110..7e70c3e 100644 --- a/app/Http/Controllers/Reports/OutstandingController.php +++ b/app/Http/Controllers/Reports/OutstandingController.php @@ -46,10 +46,17 @@ class OutstandingController extends Controller // Query outstanding summary for each branch $summary_Outstanding_data = array_map(function ($db_connection) use ($endDate) { + // SAG KES + $queryKes = Gadai::on($db_connection) + ->selectRaw('COUNT(norujukan) as total_gadaian_kes, SUM(pinjaman) as sum_pinjaman_kes') + ->where('tagbaru', 0) + ->where('tagpalsu', 1) + ->where('sttebus', ''); // SAG LAMA $queryLama = Gadai::on($db_connection) ->selectRaw('COUNT(norujukan) as total_gadaian, SUM(pinjaman) as sum_pinjaman') ->where('tagbaru', 0) + ->where('tagpalsu', 0) ->where('sttebus', ''); // SAG BARU @@ -64,12 +71,14 @@ class OutstandingController extends Controller ->where('sttebus', ''); if (!empty($endDate)) { + $queryKes->where('t_gadai', '<=', $endDate); $queryLama->where('t_gadai', '<=', $endDate); $queryBaru->where('t_gadai', '<=', $endDate); $queryAll->where('t_gadai', '<=', $endDate); } return array_merge( + $queryKes->first()->toArray(), $queryLama->first()->toArray(), $queryBaru->first()->toArray(), $queryAll->first()->toArray() @@ -118,10 +127,12 @@ class OutstandingController extends Controller if (!empty($endDate)) { $queryAll->where('tarikh', '=', $endDate); } - - return array_merge( - $queryAll->first()->toArray() - ); + $record = $queryAll->first(); + + return $record + ? $record->toArray() + : ['bakieod' => 0]; + }, $active_cawangan_db_connection); // Combine data with branch info diff --git a/app/Http/Controllers/Reports/SaringanGadaianController.php b/app/Http/Controllers/Reports/SaringanGadaianController.php new file mode 100644 index 0000000..10fe794 --- /dev/null +++ b/app/Http/Controllers/Reports/SaringanGadaianController.php @@ -0,0 +1,129 @@ +startDate ?? now()->startOfMonth()->toDateString(); + $endDate = $request->endDate ?? now()->endOfMonth()->toDateString(); + + $active_dbs = Helper::getActiveCawanganDbConnection(); + + $cawangan = Cawangan::select('kodcaw', 'details_caw', 'mysql') + ->whereIn('mysql', $active_dbs) + ->get(); + + $responses = []; + + foreach ($cawangan as $caw) { + + $db = $caw->mysql; + + $tgb = Tebus::on($db) + ->join('gadai as g1', 'tebus.norujukan', '=', 'g1.norujukan') + ->join('gadai as g2', function ($join) { + $join->on('g2.nokp', '=', 'g1.nokp') + ->on('g2.t_gadai', '=', 'tebus.t_tebus') + ->whereRaw('ABS(g2.berat - g1.berat) <= 0.02') + ->whereColumn('g2.norujukan', '!=', 'g1.norujukan'); + }) + ->whereBetween('tebus.t_tebus', [$startDate, $endDate]) + ->groupBy('tebus.norujukan') + ->selectRaw(" + tebus.norujukan as norujukan_tebus, + MAX(g2.norujukan) as norujukan_gadai_balik, + MAX(g2.nokp) as nokp, + MAX(g2.berat) as berat, + MAX(g2.nilaimarhun) as nilaimarhun, + MAX(g2.pinjaman) as pinjaman, + MAX(g2.t_gadai) as t_gadai, + MAX(g1.taglel) as taglel_lama + ") + ->get() + ->map(function ($row) { + return [ + 'norujukan_tebus' => $row->norujukan_tebus, + 'norujukan_gadai_balik' => $row->norujukan_gadai_balik, + 'nokp' => $row->nokp, + 'berat' => (float) $row->berat, + 'nilaimarhun' => (float) $row->nilaimarhun, + 'pinjaman' => (float) $row->pinjaman, + 'taglel_lama' => $row->taglel_lama, + 't_gadai' => $row->t_gadai, + 'jenis' => $row->taglel_lama == 1 ? 'TGB_LELONG' : 'TGB_BIASA', + ]; + }) + ->toArray(); + + $tgb_norujukan = array_column($tgb, 'norujukan_gadai_balik'); + + + $gadai_biasa = DB::connection($db) + ->table('gadai') + ->whereBetween('t_gadai', [$startDate, $endDate]) + ->whereNotIn('norujukan', $tgb_norujukan) + ->select([ + DB::raw('NULL as norujukan_tebus'), + 'norujukan as norujukan_gadai_balik', + 'nokp', + 'berat', + 'nilaimarhun', + 'pinjaman', + DB::raw('NULL as taglel_lama'), + 't_gadai', + ]) + ->get() + ->map(function ($row) { + return [ + 'norujukan_tebus' => null, + 'norujukan_gadai_balik' => $row->norujukan_gadai_balik, + 'nokp' => $row->nokp, + 'berat' => (float) $row->berat, + 'nilaimarhun' => (float) $row->nilaimarhun, + 'pinjaman' => (float) $row->pinjaman, + 'taglel_lama' => null, + 't_gadai' => $row->t_gadai, + 'jenis' => 'GADAI_BIASA', + ]; + }) + ->toArray(); + + + $details = collect($tgb) + ->merge($gadai_biasa) + ->unique('norujukan_gadai_balik') + ->sortBy(['jenis', 't_gadai']) + ->values() + ->all(); + + + $responses[] = [ + 'kodcaw' => $caw->kodcaw, + 'details_caw' => $caw->details_caw, + 'jumlah_surat' => count($details), + 'total_tgb_lelong' => collect($details)->where('jenis', 'TGB_LELONG')->count(), + 'total_tgb_biasa' => collect($details)->where('jenis', 'TGB_BIASA')->count(), + 'total_gadai_biasa' => collect($details)->where('jenis', 'GADAI_BIASA')->count(), + 'sum_berat' => collect($details)->sum('berat'), + 'sum_nilai_marhun' => collect($details)->sum('nilaimarhun'), + 'sum_pinjaman' => collect($details)->sum('pinjaman'), + 'details' => $details, + ]; + } + + return response()->json($responses); + } +} diff --git a/app/Http/Controllers/Reports/StokAuditController.php b/app/Http/Controllers/Reports/StokAuditController.php index 16ad7bd..af2ff70 100644 --- a/app/Http/Controllers/Reports/StokAuditController.php +++ b/app/Http/Controllers/Reports/StokAuditController.php @@ -2,9 +2,11 @@ namespace App\Http\Controllers\Reports; use App\Cawangan; +use App\Gadai; use App\Helper; use App\Http\Controllers\Controller; use Illuminate\Http\Request; +use Carbon\Carbon; class StokAuditController extends Controller { @@ -38,6 +40,40 @@ class StokAuditController extends Controller public function getSummaryLaporanStokAudit(Request $request) { + $connections = $this->getActiveCawanganConnections(); + + // MODE 1: TARIKH SEMASA + if ($request->dateOption === 'current') { + + $today = Carbon::today(); + + $total_audit = $connections->map(function ($connection) { + + $data = Gadai::on($connection->mysql) + ->where('tagpalsu', 0) + ->where(function($q) { + $q->where('sttebus', '') + ->orWhereNull('sttebus'); + }) + ->get(); + + return [ + 'cawangan' => $connection->details_caw, + 'bilangan_pembiayaan' => $data->count(), + 'berat' => $data->sum('berat'), + 'nilai_marhun' => $data->sum('nilaimarhun'), + 'baki_pembiayaan' => $data->sum('bakipjm'), + 'pembiayaan' => $data->sum('pinjaman'), + 'upah_belum_bayar' => $data->sum('upahblmbyar'), + 'total_utg_onepercent' => 0, + 'total_ujrah' => $data->sum('ujrah'), + ]; + }); + + } + // MODE 2: BULAN TERTENTU + else { + $month = $request->month; $year = $request->year; @@ -59,34 +95,24 @@ class StokAuditController extends Controller 'total_ujrah' => $data->sum('ujrah'), ]; }); + } - $getTotalAcrossCawangan = function($property) use($total_audit) { - $total = array_reduce($total_audit->toArray(), function($carry, $subarray) use($property) { - return $carry + $subarray[$property]; - }, 0); - - return $total; - }; - - $total_all_cawangan_audit = [ + // TOTAL SEMUA CAWANGAN + $total_all = [ 'cawangan' => 'Total Semua Cawangan', - 'bilangan_pembiayaan' => $getTotalAcrossCawangan('bilangan_pembiayaan'), - 'berat' => $getTotalAcrossCawangan('berat'), - 'nilai_marhun' => $getTotalAcrossCawangan('nilai_marhun'), - 'baki_pembiayaan' => $getTotalAcrossCawangan('baki_pembiayaan'), - 'pembiayaan' => $getTotalAcrossCawangan('pembiayaan'), - 'upah_belum_bayar' => $getTotalAcrossCawangan('upah_belum_bayar'), - 'total_utg_onepercent' => $getTotalAcrossCawangan('total_utg_onepercent'), - 'total_ujrah' => $getTotalAcrossCawangan('total_ujrah'), + 'bilangan_pembiayaan' => $total_audit->sum('bilangan_pembiayaan'), + 'berat' => $total_audit->sum('berat'), + 'nilai_marhun' => $total_audit->sum('nilai_marhun'), + 'baki_pembiayaan' => $total_audit->sum('baki_pembiayaan'), + 'pembiayaan' => $total_audit->sum('pembiayaan'), + 'upah_belum_bayar' => $total_audit->sum('upah_belum_bayar'), + 'total_utg_onepercent' => $total_audit->sum('total_utg_onepercent'), + 'total_ujrah' => $total_audit->sum('total_ujrah'), ]; - $total_audit->push($total_all_cawangan_audit); + $total_audit->push($total_all); - if (sizeof($total_audit) == 0) { - return response()->json('failed', 200); - } else { - return response()->json($total_audit, 200); - } + return response()->json($total_audit, 200); } } diff --git a/app/Http/Controllers/StokAuditController.php b/app/Http/Controllers/StokAuditController.php index cc6129f..eb1ddcf 100644 --- a/app/Http/Controllers/StokAuditController.php +++ b/app/Http/Controllers/StokAuditController.php @@ -475,6 +475,9 @@ class StokAuditController extends Controller // Filter audit $rekodaudit = $audit->filter(function ($item) use ($tarikhTerkiniT, $tarikhTerkiniA) { + if ($item->lelong_tawarruq == 0) { + return true; + } $norujukan = $item->norujukan; $adaTebusTerkini = isset($tarikhTerkiniT[$norujukan]) && diff --git a/app/Http/Controllers/TransactionOnlineController.php b/app/Http/Controllers/TransactionOnlineController.php index 92b6e6a..c51ac2e 100644 --- a/app/Http/Controllers/TransactionOnlineController.php +++ b/app/Http/Controllers/TransactionOnlineController.php @@ -8,6 +8,7 @@ use App\Cawangan; use App\Gadai; use App\GlDetail; use App\Http\Controllers\TebusController as TebusController; +use App\Lelong; use App\Services\Loggers\OnlineTransactionLoggerService; use App\Services\OnePercentServices; use App\Support\v2\Calculation; @@ -767,8 +768,52 @@ class TransactionOnlineController extends Controller return 'rejected'; } } - - - + public function CustomerInfoLelong(Request $request){ + $cawangan_all = Cawangan::on('mysql7')->get(); + $totalBakiLelong = 0; + $totalRugiLelong = 0; + + foreach ($cawangan_all as $index => $cawangan) { + $gadai = Gadai::on($cawangan['mysql']) + ->where('nokp', '=', $request->ic) + ->where('sttebus','=','L') + ->orderBy('t_gadai', 'desc') + ->get()->toArray(); + + if (sizeof($gadai) != 0) { + foreach ($gadai as $gad) { + $bakilelong = Lelong::on($cawangan['mysql']) + ->where(function($query) { + $query->whereNull('trkhtuntut') + ->orWhere('trkhtuntut', '=', ''); + }) + ->where('norujukan', '=' ,$gad['norujukan']) + ->where('baki', '>=', 0) + ->sum('baki'); + + $rugilelong = Lelong::on($cawangan['mysql']) + ->where(function($query) { + $query->whereNull('trkhtuntut') + ->orWhere('trkhtuntut', '=', ''); + }) + ->where('norujukan', '=' ,$gad['norujukan']) + ->where('baki','<',0) + ->sum('baki'); + + $totalBakiLelong += $bakilelong; + $totalRugiLelong += $rugilelong; + } + } + } + + return response()->json([ + 'success' => true, + 'message' => 'Data retrieved successfully', + 'data' => [ + 'bakilelong' => $totalBakiLelong, + 'rugilelong' => $totalRugiLelong, + ] + ], 200); + } } diff --git a/app/Http/Controllers/TunaiController.php b/app/Http/Controllers/TunaiController.php index cd4d83f..12d0fba 100644 --- a/app/Http/Controllers/TunaiController.php +++ b/app/Http/Controllers/TunaiController.php @@ -165,6 +165,21 @@ class TunaiController extends Controller } + public function getTunaiByTarikh(Request $request) + { + $cawangan = Cawangan::on('mysql7')->where('kodcaw','=',$request->kodcaw)->first(); + + $tunai = Tunai::on($cawangan['mysql']) + ->where([['kodcaw','=',$request->kodcaw], + ['tarikh','=',$request->tarikh], + ['kodlaluan','=',$request->kodlaluan] + ]) + ->orderBy('tarikh','desc') + ->first(); + + return response()->json($tunai); + } + public function getTunaiPast($kodcaw,Request $request) { diff --git a/app/Http/Controllers/VaultController.php b/app/Http/Controllers/VaultController.php index 333008d..04f3290 100644 --- a/app/Http/Controllers/VaultController.php +++ b/app/Http/Controllers/VaultController.php @@ -454,18 +454,26 @@ class VaultController extends Controller return response()->json($arraytunaiditangan,200); } - - public function laporanPetiBesi($kodcaw,$tarikh) { - $current = Carbon::now(); - $current = new Carbon(); + $current = Carbon::now(); + $current = new Carbon(); $cawangan = Cawangan::on('mysql7')->where('kodcaw','=',$kodcaw)->first(); - $vault=Vault::on($cawangan['mysql']) - ->where('kodcaw','=',$kodcaw) - ->where('tarikh','=', $tarikh) - ->orderby('tarikh','desc')->first(); + + if (!$cawangan) { + return response()->json(['error' => 'Cawangan tidak dijumpai'], 404); + } + + $vault = Vault::on($cawangan['mysql']) + ->where('kodcaw','=',$kodcaw) + ->where('tarikh','=', $tarikh) + ->orderby('tarikh','desc') + ->first(); + + if (!$vault) { + return response()->json(['error' => 'Tiada data pada tarikh tersebut'], 404); + } return response()->json($vault); } diff --git a/app/Http/Controllers/WTDController.php b/app/Http/Controllers/WTDController.php index fe12c2b..b08bbc6 100644 --- a/app/Http/Controllers/WTDController.php +++ b/app/Http/Controllers/WTDController.php @@ -5,8 +5,12 @@ namespace App\Http\Controllers; use App\WTDDraft; use App\TuntutBaki; use App\Cawangan; +use App\Customer; use Illuminate\Http\Request; use Carbon\Carbon; +use App\Helper; +use App\SerahBaki; +use App\WTD; use Illuminate\Support\Facades\Http; @@ -34,4 +38,154 @@ class WTDController extends Controller return response()->json($tuntutbaki); } + + public function getSummaryWtd(Request $request){ + + $startDate = $request->startDate ?? now()->startOfMonth()->toDateString(); + $endDate = $request->endDate ?? now()->endOfMonth()->toDateString(); + + $active_dbs = Helper::getActiveCawanganDbConnection(); + + $cawangan = Cawangan::select('kodcaw', 'details_caw', 'mysql') + ->whereIn('mysql', $active_dbs) + ->get(); + + $responses = []; + + foreach ($cawangan as $caw) { + + $db = $caw->mysql; + + $tuntutbaki = TuntutBaki::on($db) + ->join('serahbaki', 'serahbaki.t_jual', '=', 'tuntutbaki.tarikh') + ->join('gadai', 'gadai.norujukan', '=', 'tuntutbaki.norujukan') + ->whereBetween('tuntutbaki.tarikh', [$startDate, $endDate]) + ->where('tuntutbaki.teller', 'DM') + ->where('serahbaki.aktif', 1) + ->selectRaw(" + gadai.nokp as nokp, + tuntutbaki.norujukan as norujukan, + tuntutbaki.jumlah as jumlah, + serahbaki.batchno as batchno, + serahbaki.t_jual as t_jual, + serahbaki.t_htr_ag as t_htr_ag + ") + ->orderByRaw('CAST(serahbaki.batchno AS UNSIGNED)') + ->orderBy('tuntutbaki.norujukan') + ->get(); + + $nokps = $tuntutbaki + ->pluck('nokp') + ->filter() // elak null + //->unique() + ->values(); + + $customers = Customer::on('mysql7') + ->whereIn('kplama', $nokps) + ->orWhereIn('kpbaru', $nokps) + ->get() + ->keyBy(function ($item) { + return $item->kpbaru ?: $item->kplama; + }); + + $wtd_det = []; + + foreach ($tuntutbaki as $tuntut) { + + $nokp = $tuntut->nokp; + $cust = $customers->get($nokp); + + $wtd_det[] = [ + "norujukan" => $tuntut->norujukan, + "nokp" => $nokp, + "jumlah" => (float) $tuntut->jumlah, + "batchno" => $tuntut->batchno, + "t_proses" => $tuntut->t_jual, + "t_htr_ag" => $tuntut->t_htr_ag, + "nama_cust" => $cust->nama ?? null, + ]; + } + + $details = collect($wtd_det) + ->values() + ->all(); + + $responses[] = [ + 'kodcaw' => $caw->kodcaw, + 'details_caw' => $caw->details_caw, + // WEB + 'jumlah_surat' => count($details), + 'sum_baki' => collect($details)->sum('jumlah'), + // EXCEL + 'details' => $details, + ]; + } + return response()->json($responses); + + } + + public function getDebugWtd(Request $request){ + + $startDate = $request->startDate ?? now()->startOfMonth()->toDateString(); + $endDate = $request->endDate ?? now()->endOfMonth()->toDateString(); + + $active_dbs = Helper::getActiveCawanganDbConnection(); + + $cawangan = Cawangan::select('kodcaw', 'details_caw', 'mysql') + ->whereIn('mysql', $active_dbs) + ->get(); + + $responses = []; + + foreach ($cawangan as $caw) { + + $db = $caw->mysql; + + $serahbaki = SerahBaki::on($db) + ->whereBetween('t_jual', [$startDate, $endDate]) + ->where('aktif', 1) + //->selectRaw("baki as serahb") + ->sum('baki');; + //->get(); + + $tuntutbaki = TuntutBaki::on($db) + ->whereBetween('tarikh', [$startDate, $endDate]) + ->where('teller', 'DM') + //->selectRaw("jumlah as tuntutb") + ->sum('jumlah'); + //->get(); + + $twtd = WTD::on($db) + ->whereBetween('tarikh', [$startDate, $endDate]) + //->selectRaw("wtd as twtd") + ->sum('wtd'); + //->get(); + + $wtd_det = []; + + $wtd_det[] = [ + "serahb" => $serahbaki, + "tuntutb" => $tuntutbaki, + "twtd" => $twtd, + ]; + + $details = collect($wtd_det) + ->values() + ->all(); + //dd($details); + + $responses[] = [ + 'kodcaw' => $caw->kodcaw, + 'details_caw' => $caw->details_caw, + //collect($details)->sum('jumlah'), + // WEB + 'serahb' => collect($details)->sum('serahb'), + 'tuntutb' => collect($details)->sum('tuntutb'), + 'twtd' => collect($details)->sum('twtd'), + //'debugwtd' => $details, + ]; + } + return response()->json($responses); + + } } diff --git a/app/MaxMutuEmas.php b/app/MaxMutuEmas.php new file mode 100644 index 0000000..4512185 --- /dev/null +++ b/app/MaxMutuEmas.php @@ -0,0 +1,40 @@ + 'decimal:2', + 'pc' => 'decimal:2', + 'operasi' => 'decimal:2', + 'tarikhupdate' => 'datetime', + ]; + + /** + * The attributes excluded from the model's JSON form. + * + * @var array + */ + // protected $hidden = []; +} \ No newline at end of file diff --git a/app/Palsu.php b/app/Palsu.php index 06c5eaa..00ce962 100644 --- a/app/Palsu.php +++ b/app/Palsu.php @@ -4,6 +4,7 @@ namespace App; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; +use Illuminate\Database\Eloquent\Relations\HasOne; use App\Audit; use Illuminate\Support\Carbon; @@ -21,6 +22,7 @@ class Palsu extends Model protected $fillable = [ 'recno', 'kodcaw', + 'tarikh', 'norujukan', 'teller', 'nota', @@ -30,6 +32,7 @@ class Palsu extends Model 'untungonepercent', 'untungcajlain', 'pembiayaan', + 'status', ]; // public static function boot() @@ -87,4 +90,14 @@ class Palsu extends Model // { // return $this->belongsTo(Daerah::class, 'koddaerah', 'koddaerah'); // } + + public function tebus(): HasOne + { + return $this->hasOne(Tebus::class, 'norujukan', 'norujukan'); + } + + public function gadai(): HasOne + { + return $this->hasOne(Gadai::class, 'norujukan', 'norujukan'); + } } diff --git a/app/Pampasan.php b/app/Pampasan.php new file mode 100644 index 0000000..9bc0f0b --- /dev/null +++ b/app/Pampasan.php @@ -0,0 +1,35 @@ +kodcaw = $kodcaw; + $this->mysql = Cawangan::on('mysql7')->where('kodcaw', $kodcaw)->value('mysql'); + $this->mula = $mula; + $this->akhir = $akhir; + } + + public function LaporanStatistik($gadai) : array + { + $reportPembiayaan = $this->countPawnByType($gadai); + $reportLoanAmount = $this->countPawnByLoan($gadai); + $reportMarhunValue = $this->countMarhunByValue($gadai); + $reportMarhunMargin = $this->countMarhunByMargin($gadai); + $reportCustomerJob = $this->countCustomerByJob($gadai); + $reportCustomerRace = $this->countCustomerByRace($gadai); + // dd($reportCustomerRace); + + return [ + 'reportPembiayaan' => $reportPembiayaan, + 'reportLoanAmount' => $reportLoanAmount, + 'reportMarhunValue' => $reportMarhunValue, + 'reportMarhunMargin' => $reportMarhunMargin, + 'reportCustomerJob' => $reportCustomerJob, + 'reportCustomerRace' => $reportCustomerRace, + ]; + } + + private function countPawnByType($gadai) + { + $pembiayaanbaru = Tebus::on($this->mysql) + ->join('gadai as g1', 'tebus.norujukan', '=', 'g1.norujukan') + ->join('gadai as g2', function ($join) { + $join->on('g2.nokp', '=', 'g1.nokp') + ->on('g2.t_gadai', '=', 'tebus.t_tebus') + ->whereRaw('ABS(g2.berat - g1.berat) <= 0.02') + ->whereColumn('g2.norujukan', '!=', 'g1.norujukan'); + }) + ->whereBetween('tebus.t_tebus', [$this->mula, $this->akhir]) + ->groupBy('tebus.norujukan') + ->selectRaw(" + tebus.norujukan as norujukan_tebus, + MAX(g2.norujukan) as norujukanpembiayaansemula, + MAX(g1.taglel) as taglel_lama + ") + ->get() + ->toArray(); + + $pembiayaanbaruNorujukan = array_column($pembiayaanbaru, 'norujukanpembiayaansemula'); + $filteredNorujukanLelongan = array_column( + array_filter($pembiayaanbaru, function ($item) { + return $item['taglel_lama'] == 1; + }), + 'norujukanpembiayaansemula' + ); + $filteredPSNorujukan = array_column( + array_filter($pembiayaanbaru, function ($item) { + return $item['taglel_lama'] == 0; + }), + 'norujukanpembiayaansemula' + ); + + + $pembiayaanbaru = $gadai->whereIn('norujukan', $filteredPSNorujukan)->count(); + $pembiayaansemula = $gadai->whereNotIn('norujukan', $pembiayaanbaruNorujukan)->count(); + $lelongan = $gadai->whereIn('norujukan', $filteredNorujukanLelongan)->count(); + + return [ + 'pembiayaanbaru' => $pembiayaanbaru, + 'pembiayaansemula' => $pembiayaansemula, + 'lelongan' => $lelongan + ]; + } + + private function countPawnByLoan($gadai) + { + return collect($gadai)->countBy(function ($item) { + $loan = $item['pinjaman']; + + if ($loan <= 400.99) return '< 400.99'; + if ($loan >= 401 && $loan <= 2000) return '401 - 2000'; + if ($loan >= 2001 && $loan <= 24999) return '2001 - 2499'; + if ($loan >= 2500) return '>= 2500'; + if ($loan > 101000) return '>101000'; + })->toArray(); + } + + private function countMarhunByValue($gadai) + { + return collect($gadai)->countBy(function ($item) { + $nilaimarhun = $item['nilaimarhun']; + + if ($nilaimarhun <= 400.99) return '< 1-400'; + if ($nilaimarhun >= 401 && $nilaimarhun <= 2000) return '401-2000'; + if ($nilaimarhun > 2001) return '> 2001'; + })->toArray(); + } + + private function countMarhunByMargin($gadai) + { + return collect($gadai)->countBy(function ($item) { + $margin= $item['percentpinj']; + + if ($margin >= 10 && $margin <= 40.99) return '10-40.99'; + if ($margin >= 41 && $margin <= 60.99) return '41-60.99'; + if ($margin >= 61 && $margin <= 80) return '> 61-80'; + })->toArray(); + } + + private function countCustomerByJob($gadai) + { + $jobMap = [ + 1 => 'Peniaga', + 2 => 'Pekerja Swasta', + 3 => 'Pekerja Kerajaan', + 4 => 'Bekerja Sendiri', + 5 => 'Suri Rumah', + 6 => 'Lain-lain', + ]; + + return collect($gadai)->countBy(function ($item) use ($jobMap) { + $kodkerja = floatval($item['kodkerja']); + return $jobMap[$kodkerja] ?? 'Lain-lain'; + })->toArray(); + + } + + private function countCustomerByRace($gadai){ + + $raceMap = [ + 'M' => 'Melayu', + 'C' => 'Cina', + 'I' => 'India', + 'L' => 'Lain-lain', + ]; + + return collect($gadai)->countBy(function ($item) use ($raceMap) { + return $raceMap[$item['bangsa']] ?? 'Lain-lain'; + + })->toArray(); + + } +} diff --git a/app/Services/Reports/ImbangDugaService.php b/app/Services/Reports/ImbangDugaService.php index a349f8b..de5f976 100644 --- a/app/Services/Reports/ImbangDugaService.php +++ b/app/Services/Reports/ImbangDugaService.php @@ -377,7 +377,8 @@ class ImbangDugaService return $transaction->trans_type !== 'A'; })->sum('keuntungan_rebet'); - $total = $total_ansuran + $total_tebus + $get_imbangduga['keun_sebenar']; + $backdate_keun_sebenar = isset($get_imbangduga['keun_sebenar']) ? $get_imbangduga['keun_sebenar'] : 0; + $total = $total_ansuran + $total_tebus + $backdate_keun_sebenar; return $total; } diff --git a/app/Services/Reports/LelonganService.php b/app/Services/Reports/LelonganService.php index af2ed7b..99eec40 100644 --- a/app/Services/Reports/LelonganService.php +++ b/app/Services/Reports/LelonganService.php @@ -58,7 +58,7 @@ class LelonganService $marhun_lelongan = $this->getMarhunLelongan($total_lelongan, $cawangan_connection); $cawangan_detail = $this->getCawanganDetail($cawangan_connection); - $total_lelongan = $total_lelongan->zip($customer_info, $marhun_lelongan)->map(function ($data) { + $total_lelongan = $total_lelongan->zip($customer_info, $marhun_lelongan)->map(function ($data) use ($total_lelongan) { [$lelong, $customer_info, $marhun_lelongan] = $data; @@ -76,31 +76,38 @@ class LelonganService 'bakipjm' => $lelong['bakipjm'], 'keuntungan' => $lelong['bakiupah'], 'cajlelong' => $lelong['cajlelong'], + 'hargaasas' => $lelong['hargaasas'], 'hargajual' => $lelong['hargajual'], 'baki' => $lelong['baki'], 'teller' => $lelong['teller'], ]; - dd($data); }); $total_lelongan = $total_lelongan->groupBy('teller'); - $lelongan_tellers = $total_lelongan->keys(); + $result = []; - $total_lelongan = $total_lelongan - ->zip($total_summary_lelongan_teller) - ->map(function ($data) { + foreach ($total_lelongan as $teller => $lelongan) { + $result[$teller] = [ + 'lelongan' => $lelongan->values(), + 'summary_lelongan_teller' => $total_summary_lelongan_teller[$teller] ?? [ + 'total_lelongan' => 0, + 'total_berat' => 0, + 'total_nilai_marhun' => 0, + 'total_pembiayaan' => 0, + 'total_bakipjm' => 0, + 'total_keuntungan' => 0, + 'total_cajlelong' => 0, + 'total_hargaasas' => 0, + 'total_hargajual' => 0, + 'total_baki' => 0, + ], + ]; + } - [$lelongan, $summary] = $data; + $total_lelongan = collect($result); - return [ - 'lelongan' => $lelongan, - 'summary_lelongan_teller' => $summary, - ]; - }); - - $total_lelongan = $lelongan_tellers->combine($total_lelongan); $data = [ 'query' => [ @@ -143,6 +150,7 @@ class LelonganService sum(gadai.bakipjm) as total_bakipjm, sum(lelong.bakiupah) as total_keuntungan, sum(lelong.cajlelong) as total_cajlelong, + sum(lelong.hargaasas) as total_hargaasas, sum(lelong.hargajual) as total_hargajual, sum(lelong.baki) as total_baki') ->get() @@ -155,32 +163,54 @@ class LelonganService 'total_bakipjm' => $x['total_bakipjm'], 'total_keuntungan' => $x['total_keuntungan'], 'total_cajlelong' => $x['total_cajlelong'], + 'total_hargaasas' => $x['total_hargaasas'], 'total_hargajual' => $x['total_hargajual'], 'total_baki' => $x['total_baki'] ]; }); - // dd($total_summary_lelongan); return $total_summary_lelongan[0]; } + // private function getTotalSummaryLelonganGroupByTeller(Builder $query_total_lelongan) + // { + + // $total_summary_lelongan_groupByTeller = (clone $query_total_lelongan) + // ->selectRaw('count(lelong.norujukan) as total_lelongan, + // sum(lelong.berat) as total_berat, + // sum(lelong.nilaimarhun) as total_nilai_marhun, + // sum(lelong.pinjaman) as total_pembiayaan, + // sum(gadai.bakipjm) as total_bakipjm, + // sum(lelong.bakiupah) as total_keuntungan, + // sum(lelong.cajlelong) as total_cajlelong, + // sum(lelong.hargaasas) as total_hargaasas, + // sum(lelong.hargajual) as total_hargajual, + // sum(lelong.baki) as total_baki') + // ->groupBy('lelong.teller') + // ->get(); + // return $total_summary_lelongan_groupByTeller; + // } private function getTotalSummaryLelonganGroupByTeller(Builder $query_total_lelongan) { - - $total_summary_lelongan_groupByTeller = (clone $query_total_lelongan) - ->selectRaw('count(lelong.norujukan) as total_lelongan, - sum(lelong.berat) as total_berat, - sum(lelong.nilaimarhun) as total_nilai_marhun, - sum(lelong.pinjaman) as total_pembiayaan, - sum(gadai.bakipjm) as total_bakipjm, - sum(lelong.bakiupah) as total_keuntungan, - sum(lelong.cajlelong) as total_cajlelong, - sum(lelong.hargajual) as total_hargajual, - sum(lelong.baki) as total_baki') + return (clone $query_total_lelongan) + ->selectRaw(' + lelong.teller, + count(lelong.norujukan) as total_lelongan, + sum(lelong.berat) as total_berat, + sum(lelong.nilaimarhun) as total_nilai_marhun, + sum(lelong.pinjaman) as total_pembiayaan, + sum(gadai.bakipjm) as total_bakipjm, + sum(lelong.bakiupah) as total_keuntungan, + sum(lelong.cajlelong) as total_cajlelong, + sum(lelong.hargaasas) as total_hargaasas, + sum(lelong.hargajual) as total_hargajual, + sum(lelong.baki) as total_baki + ') ->groupBy('lelong.teller') - ->get(); - return $total_summary_lelongan_groupByTeller; + ->get() + ->keyBy('teller'); // ⭐ PENTING } + private function getTotalLelongan(Builder $query_total_lelongan) { $total_lelongan = (clone $query_total_lelongan) @@ -199,6 +229,7 @@ class LelonganService 'gadai.bakipjm', 'lelong.bakiupah', 'lelong.cajlelong', + 'lelong.hargaasas', 'lelong.hargajual', 'lelong.baki') ->orderBy('lelong.teller') @@ -311,6 +342,7 @@ class LelonganService 'bakipjm' => $lelong['bakipjm'], 'keuntungan' => $lelong['bakiupah'], 'cajlelong' => $lelong['cajlelong'], + 'hargaasas' => $lelong['hargaasas'], 'hargajual' => $lelong['hargajual'], 'baki' => $lelong['baki'], 'teller' => $lelong['teller'], diff --git a/app/Services/Reports/RingkasanHarianService.php b/app/Services/Reports/RingkasanHarianService.php index 4167b47..ccb76c5 100644 --- a/app/Services/Reports/RingkasanHarianService.php +++ b/app/Services/Reports/RingkasanHarianService.php @@ -1322,7 +1322,7 @@ class RingkasanHarianService return floatval($totalSerahan); } - return floatval(0); + return floatval($serahanpkbTawarruq); } diff --git a/app/Support/Tawarruq.php b/app/Support/Tawarruq.php index be5506f..785a302 100644 --- a/app/Support/Tawarruq.php +++ b/app/Support/Tawarruq.php @@ -2,11 +2,14 @@ namespace App\Support; +use App\Cawangan; use App\KadarUpah; +use App\Pampasan; use App\Support\v1\GadaiV1 as Version1Gadai; use App\Services\MasterServices; use App\Support\v1\Penebusan; +use Illuminate\Http\JsonResponse; use Illuminate\Http\Request as HttpRequest; use Illuminate\Support\Facades\Log; diff --git a/app/Support/v1/Penebusan.php b/app/Support/v1/Penebusan.php index f85126f..00bde97 100644 --- a/app/Support/v1/Penebusan.php +++ b/app/Support/v1/Penebusan.php @@ -15,6 +15,8 @@ use App\KomuditiPurchase; use App\KomuditiTransaksi; use App\Marhun; use App\Moratorium; +use App\Palsu; +use App\Pampasan; use App\Support\OnePercent; use App\Support\Tawarruq; use App\Support\v1\Calculation as V1Calculation; @@ -479,6 +481,17 @@ class Penebusan $upah_rebet_sebenar = $harga_tebus - $gadai['bakipjm']; } + $isPampasan = Pampasan::on($cawangan['mysql'])->where('norujukan', $request->norujukan)->exists(); + + if($isPampasan){ + $barang_kes = Palsu::on($cawangan['mysql'])->where('norujukan', $norujukan)->first(); + + $harga_tebus = $barang_kes->untung + $barang_kes->pembiayaan; + $upah_tebus = $barang_kes->untung; + $upah_rebet = $this->kiraUpahRebetSebenar($kodcaw,$norujukan); + $upah_rebet_sebenar = $barang_kes->untung; + $rebet = $gadai['hargajualan'] - $harga_tebus; + } $create_tebus = Tebus::on($cawangan['mysql'])->create([ 'kodcaw'=> $kodcaw, diff --git a/app/WTDSimulasi.php b/app/WTDSimulasi.php new file mode 100644 index 0000000..38a963f --- /dev/null +++ b/app/WTDSimulasi.php @@ -0,0 +1,32 @@ +singleton( $app->configure('app'); $app->configure('tinker'); -$app->configure('tennant_master'); +$app->configure('tennant_database'); $app->configure('report'); $app->configure('app_parameter'); - +$app->configure('parameter'); /* |-------------------------------------------------------------------------- | Register Middleware diff --git a/config/app_parameter.php b/config/app_parameter.php index a6cf4d8..c46f175 100644 --- a/config/app_parameter.php +++ b/config/app_parameter.php @@ -2,5 +2,7 @@ return [ 'url' => env('APP_URL', url('/')), - 'api_arrahnbid' => env('API_ARRAHNBID', 'http://lelong.test/api/') + 'api_arrahnbid' => env('API_ARRAHNBID', 'http://lelong.test/api/'), + 'api_v3' => env('API_V3', 'http://apiv3.localhost/api/') ]; + diff --git a/config/parameter.php b/config/parameter.php new file mode 100644 index 0000000..8af8857 --- /dev/null +++ b/config/parameter.php @@ -0,0 +1,5 @@ + env('MAX_MUTUEMAS', true), +]; \ No newline at end of file diff --git a/config/tennant_database.php b/config/tennant_database.php new file mode 100644 index 0000000..09d92cb --- /dev/null +++ b/config/tennant_database.php @@ -0,0 +1,6 @@ + env('TENNANT_MASTER_DB','online_arrahn'), + 'kaunter_db' => env('TENNANT_KAUNTER_DB','kaunterpkb') +]; diff --git a/config/tennant_master.php b/config/tennant_master.php deleted file mode 100644 index e0e2cbe..0000000 --- a/config/tennant_master.php +++ /dev/null @@ -1,5 +0,0 @@ - env('TENNANT_MASTER_DB','master_erahn') -]; diff --git a/database/migrations/2023_11_14_121109_add_columns_to_komuditi_transaksi.php b/database/migrations/2023_11_14_121109_add_columns_to_komuditi_transaksi.php index e564eb6..897302e 100644 --- a/database/migrations/2023_11_14_121109_add_columns_to_komuditi_transaksi.php +++ b/database/migrations/2023_11_14_121109_add_columns_to_komuditi_transaksi.php @@ -42,7 +42,7 @@ class AddColumnsToKomuditiTransaksi extends Migration { $online_arrahn_connection_array = array_filter(config('database.connections'), function($connection) { - if($connection['database'] === 'online_arrahn' || $connection['database'] === 'master_krk' || $connection['database'] === config('tennant_master.database')){ + if($connection['database'] === config('tennant_database.master_db')){ return true; } @@ -53,7 +53,7 @@ class AddColumnsToKomuditiTransaksi extends Migration if(empty($online_arrahn_connection_array)){ - throw new Exception("online_arrahn or master_krk doesn't exist in config.database.connections array"); + throw new Exception("Tennant master database (" . config('tennant_database.master_db') . ") doesn't exist in config.database.connections array"); } return array_keys($online_arrahn_connection_array)[0]; diff --git a/database/migrations/2025_07_03_223000_add_nm_jbg_untung_pembiayaan_columns_to_palsu_table.php b/database/migrations/2025_07_03_223000_add_nm_jbg_untung_pembiayaan_columns_to_palsu_table.php index 9dffcdf..b21d077 100644 --- a/database/migrations/2025_07_03_223000_add_nm_jbg_untung_pembiayaan_columns_to_palsu_table.php +++ b/database/migrations/2025_07_03_223000_add_nm_jbg_untung_pembiayaan_columns_to_palsu_table.php @@ -69,10 +69,10 @@ class AddNmJbgUntungPembiayaanColumnsToPalsuTable extends Migration // Add index and foreign key constraint to existing norujukan column if (Schema::connection($dbase)->hasColumn('palsu', 'norujukan')) { // Add index to norujukan column for better performance - $table->index('norujukan'); + // $table->index('norujukan'); // Add foreign key constraint named 'norujukan' - $table->foreign('norujukan', 'norujukan')->references('norujukan')->on('gadai'); + // $table->foreign('norujukan', 'norujukan')->references('norujukan')->on('gadai'); } }); @@ -87,21 +87,21 @@ class AddNmJbgUntungPembiayaanColumnsToPalsuTable extends Migration Schema::connection($dbase)->table('palsu', function (Blueprint $table) use ($dbase) { // Drop foreign key constraint and index from norujukan column - if (Schema::connection($dbase)->hasColumn('palsu', 'norujukan')) { - try { - $table->dropForeign('norujukan'); - echo "Dropped foreign key 'norujukan' on connection '{$dbase}'\n"; - } catch (\Exception $e) { - echo "Warning: Could not drop foreign key 'norujukan' on connection '{$dbase}': " . $e->getMessage() . "\n"; - } + // if (Schema::connection($dbase)->hasColumn('palsu', 'norujukan')) { + // try { + // $table->dropForeign('norujukan'); + // echo "Dropped foreign key 'norujukan' on connection '{$dbase}'\n"; + // } catch (\Exception $e) { + // echo "Warning: Could not drop foreign key 'norujukan' on connection '{$dbase}': " . $e->getMessage() . "\n"; + // } - try { - $table->dropIndex(['norujukan']); - echo "Dropped index on 'norujukan' column on connection '{$dbase}'\n"; - } catch (\Exception $e) { - echo "Warning: Could not drop index on 'norujukan' on connection '{$dbase}': " . $e->getMessage() . "\n"; - } - } + // try { + // $table->dropIndex(['norujukan']); + // echo "Dropped index on 'norujukan' column on connection '{$dbase}'\n"; + // } catch (\Exception $e) { + // echo "Warning: Could not drop index on 'norujukan' on connection '{$dbase}': " . $e->getMessage() . "\n"; + // } + // } // Drop other columns if they exist $columnsToCheck = ['nilaimarhun', 'jbg', 'untung','untungonepercent','untungcajlain', 'pembiayaan']; diff --git a/database/migrations/2025_08_28_150140_create_pampasan_table.php b/database/migrations/2025_08_28_150140_create_pampasan_table.php new file mode 100644 index 0000000..3c867a7 --- /dev/null +++ b/database/migrations/2025_08_28_150140_create_pampasan_table.php @@ -0,0 +1,57 @@ +select('SELECT 1'); + return true; + } catch (\Exception $e) { + return false; + } + }); + return $db_connection ? array_values($db_connection) : []; + } + + public function up() + { + foreach ($this->getActiveDB() as $dbase) { + if (!Schema::connection($dbase)->hasTable('pampasan')) { + Schema::connection($dbase)->create('pampasan', function (Blueprint $table) { + $table->bigIncrements('id'); + $table->string('norujukan', 50)->unique()->index(); + $table->string('baucerno', 30)->index(); + $table->string('kodcaw', 20)->index(); + $table->decimal('jumlah_pampasan', 11, 2); + + if (Schema::getConnection()->getPdo()->getAttribute(PDO::ATTR_SERVER_VERSION) >= '5.7') { + $table->json('denominasi')->nullable(); + } else { + $table->longText('denominasi')->nullable(); + } + $table->string('teller', 100); + $table->tinyInteger('status') + ->default(0) + ->comment('0 = belum dituntut, 1 = dituntut'); + $table->timestamps(); + }); + } + } + } + + public function down() + { + foreach ($this->getActiveDB() as $dbase) { + Schema::connection($dbase)->dropIfExists('pampasan'); + } + } +} diff --git a/database/migrations/2025_09_17_092001_add_jenis_column_to_palsu_table.php b/database/migrations/2025_09_17_092001_add_jenis_column_to_palsu_table.php new file mode 100644 index 0000000..a9de2a2 --- /dev/null +++ b/database/migrations/2025_09_17_092001_add_jenis_column_to_palsu_table.php @@ -0,0 +1,68 @@ +select('SELECT 1'); + return true; + } catch (\Exception $e) { + return false; + } + }); + + return $db_connection ? array_values($db_connection) : []; + } + + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + $db_connection = $this->getActiveDB(); + + foreach ($db_connection as $dbase) { + Schema::connection($dbase)->table('palsu', function (Blueprint $table) use ($dbase) { + if (!Schema::connection($dbase)->hasColumn('palsu', 'jenis')) { + $table->string('jenis', 50)->nullable()->comment('Jenis/Type classification'); + } + }); + } + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + $db_connection = $this->getActiveDB(); + + foreach ($db_connection as $dbase) { + Schema::connection($dbase)->table('palsu', function (Blueprint $table) use ($dbase) { + if (Schema::connection($dbase)->hasColumn('palsu', 'jenis')) { + $table->dropColumn('jenis'); + } + }); + } + } +} diff --git a/database/migrations/2025_09_17_093116_update_jenis_to_pampasan_for_semporna_records.php b/database/migrations/2025_09_17_093116_update_jenis_to_pampasan_for_semporna_records.php new file mode 100644 index 0000000..424a87b --- /dev/null +++ b/database/migrations/2025_09_17_093116_update_jenis_to_pampasan_for_semporna_records.php @@ -0,0 +1,78 @@ +getSempornaRecords(); + + // Update jenis to 'pampasan' for Semporna records in mysql34 (Semporna branch) + try { + $updated = DB::connection('mysql34')->table('palsu') + ->whereIn('norujukan', $semporna_records) + ->update(['jenis' => 'pampasan']); + + echo "Updated {$updated} Semporna records with jenis = 'pampasan'\n"; + } catch (\Exception $e) { + echo "Error updating Semporna records: " . $e->getMessage() . "\n"; + } + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + $semporna_records = $this->getSempornaRecords(); + + // Revert jenis to null for Semporna records + try { + $reverted = DB::connection('mysql34')->table('palsu') + ->whereIn('norujukan', $semporna_records) + ->update(['jenis' => null]); + + echo "Reverted {$reverted} Semporna records jenis to null\n"; + } catch (\Exception $e) { + echo "Error reverting Semporna records: " . $e->getMessage() . "\n"; + } + } +} diff --git a/database/migrations/2025_09_17_093117_update_non_semporna_records_jenis_to_hapuskira.php b/database/migrations/2025_09_17_093117_update_non_semporna_records_jenis_to_hapuskira.php new file mode 100644 index 0000000..44594a3 --- /dev/null +++ b/database/migrations/2025_09_17_093117_update_non_semporna_records_jenis_to_hapuskira.php @@ -0,0 +1,130 @@ +select('SELECT 1'); + return true; + } catch (\Exception $e) { + return false; + } + }); + + return $db_connection ? array_values($db_connection) : []; + } + + /** + * Semporna norujukan records to exclude + */ + private function getSempornaRecords(): array + { + return [ + '011237240808-0003', + '011237240719-0015', + '011237240806-0011', + '011237240828-0001', + '011237240904-0007', + '011237240904-0008', + '011237240904-0009', + '011237240719-0023', + '011237240719-0024', + '011237240719-0025', + '011237240618-0026', + '011237240719-0027', + '011237240719-0028', + '011237240618-0020', + '011237240719-0030', + '011237240618-0029', + '011237240731-0026', + '011237240912-0009' + ]; + } + + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + $db_connection = $this->getActiveDB(); + $semporna_records = $this->getSempornaRecords(); + + foreach ($db_connection as $dbase) { + try { + if ($dbase == 'mysql34') { + // For Semporna (mysql34), update only non-Semporna records to 'hapuskira' + $updated = DB::connection($dbase)->table('palsu') + ->whereNotIn('norujukan', $semporna_records) + ->update(['jenis' => 'hapuskira']); + + if ($updated > 0) { + echo "Updated {$updated} non-Semporna records in {$dbase} to jenis = 'hapuskira'\n"; + } + } else { + // For all other databases, update all records to 'hapuskira' + $updated = DB::connection($dbase)->table('palsu') + ->update(['jenis' => 'hapuskira']); + + if ($updated > 0) { + echo "Updated {$updated} records in {$dbase} to jenis = 'hapuskira'\n"; + } + } + } catch (\Exception $e) { + echo "Error updating {$dbase}: " . $e->getMessage() . "\n"; + } + } + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + $db_connection = $this->getActiveDB(); + + foreach ($db_connection as $dbase) { + try { + // Revert all jenis values to null except Semporna records which should remain 'pampasan' + if ($dbase == 'mysql34') { + $semporna_records = $this->getSempornaRecords(); + $reverted = DB::connection($dbase)->table('palsu') + ->whereNotIn('norujukan', $semporna_records) + ->update(['jenis' => null]); + + if ($reverted > 0) { + echo "Reverted {$reverted} non-Semporna records in {$dbase} jenis to null\n"; + } + } else { + $reverted = DB::connection($dbase)->table('palsu') + ->update(['jenis' => null]); + + if ($reverted > 0) { + echo "Reverted {$reverted} records in {$dbase} jenis to null\n"; + } + } + } catch (\Exception $e) { + echo "Error reverting {$dbase}: " . $e->getMessage() . "\n"; + } + } + } +} diff --git a/database/migrations/2025_09_17_093118_add_status_column_to_palsu_table.php b/database/migrations/2025_09_17_093118_add_status_column_to_palsu_table.php new file mode 100644 index 0000000..6c71628 --- /dev/null +++ b/database/migrations/2025_09_17_093118_add_status_column_to_palsu_table.php @@ -0,0 +1,73 @@ +select('SELECT 1'); + return true; + } catch (\Exception $e) { + return false; + } + }); + + return $db_connection ? array_values($db_connection) : []; + } + + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + $db_connection = $this->getActiveDB(); + + foreach ($db_connection as $dbase) { + Schema::connection($dbase)->table('palsu', function (Blueprint $table) use ($dbase) { + if (!Schema::connection($dbase)->hasColumn('palsu', 'status')) { + $table->unsignedSmallInteger('status')->default(0)->comment('Status value'); + } + }); + + // Update existing rows to have status = 0 + DB::connection($dbase)->table('palsu') + ->whereNull('status') + ->update(['status' => 0]); + } + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + $db_connection = $this->getActiveDB(); + + foreach ($db_connection as $dbase) { + Schema::connection($dbase)->table('palsu', function (Blueprint $table) use ($dbase) { + if (Schema::connection($dbase)->hasColumn('palsu', 'status')) { + $table->dropColumn('status'); + } + }); + } + } +} diff --git a/database/migrations/2025_09_17_093624_update_all_palsu_status_to_one.php b/database/migrations/2025_09_17_093624_update_all_palsu_status_to_one.php new file mode 100644 index 0000000..3cba378 --- /dev/null +++ b/database/migrations/2025_09_17_093624_update_all_palsu_status_to_one.php @@ -0,0 +1,80 @@ +select('SELECT 1'); + return true; + } catch (\Exception $e) { + return false; + } + }); + + return $db_connection ? array_values($db_connection) : []; + } + + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + $db_connection = $this->getActiveDB(); + + foreach ($db_connection as $dbase) { + try { + // Update all status values to 1 in palsu table + $updated = DB::connection($dbase)->table('palsu') + ->update(['status' => 1]); + + if ($updated > 0) { + echo "Updated {$updated} records in {$dbase} palsu table to status = 1\n"; + } + } catch (\Exception $e) { + echo "Error updating {$dbase}: " . $e->getMessage() . "\n"; + } + } + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + $db_connection = $this->getActiveDB(); + + foreach ($db_connection as $dbase) { + try { + // Revert all status values back to 0 in palsu table + $reverted = DB::connection($dbase)->table('palsu') + ->update(['status' => 0]); + + if ($reverted > 0) { + echo "Reverted {$reverted} records in {$dbase} palsu table to status = 0\n"; + } + } catch (\Exception $e) { + echo "Error reverting {$dbase}: " . $e->getMessage() . "\n"; + } + } + } +} diff --git a/database/migrations/2025_09_17_093756_update_semporna_records_status_to_zero.php b/database/migrations/2025_09_17_093756_update_semporna_records_status_to_zero.php new file mode 100644 index 0000000..7731a9d --- /dev/null +++ b/database/migrations/2025_09_17_093756_update_semporna_records_status_to_zero.php @@ -0,0 +1,78 @@ +getSempornaRecords(); + + // Update status to 0 for Semporna records in mysql34 (Semporna branch) + try { + $updated = DB::connection('mysql34')->table('palsu') + ->whereIn('norujukan', $semporna_records) + ->update(['status' => 0]); + + echo "Updated {$updated} Semporna records with status = 0\n"; + } catch (\Exception $e) { + echo "Error updating Semporna records status: " . $e->getMessage() . "\n"; + } + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + $semporna_records = $this->getSempornaRecords(); + + // Revert status to 1 for Semporna records + try { + $reverted = DB::connection('mysql34')->table('palsu') + ->whereIn('norujukan', $semporna_records) + ->update(['status' => 1]); + + echo "Reverted {$reverted} Semporna records status to 1\n"; + } catch (\Exception $e) { + echo "Error reverting Semporna records status: " . $e->getMessage() . "\n"; + } + } +} diff --git a/database/migrations/2025_09_18_141626_add_agreement_printed_at_to_pampasan_table.php b/database/migrations/2025_09_18_141626_add_agreement_printed_at_to_pampasan_table.php new file mode 100644 index 0000000..01e2154 --- /dev/null +++ b/database/migrations/2025_09_18_141626_add_agreement_printed_at_to_pampasan_table.php @@ -0,0 +1,60 @@ +select('SELECT 1'); + return true; + } catch (\Exception $e) { + return false; + } + }); + return $db_connection ? array_values($db_connection) : []; + } + + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + foreach ($this->getActiveDB() as $dbase) { + Schema::connection($dbase)->table('pampasan', function (Blueprint $table) use ($dbase) { + if (!Schema::connection($dbase)->hasColumn('pampasan', 'agreement_printed_at')) { + $table->timestamp('agreement_printed_at')->nullable()->comment('Timestamp when agreement was printed'); + } + }); + } + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + foreach ($this->getActiveDB() as $dbase) { + Schema::connection($dbase)->table('pampasan', function (Blueprint $table) use ($dbase) { + if (Schema::connection($dbase)->hasColumn('pampasan', 'agreement_printed_at')) { + $table->dropColumn('agreement_printed_at'); + } + }); + } + } +} diff --git a/database/migrations/2025_12_18_160820_add_t_htr_ag_to_serahbaki_table.php b/database/migrations/2025_12_18_160820_add_t_htr_ag_to_serahbaki_table.php new file mode 100644 index 0000000..4354561 --- /dev/null +++ b/database/migrations/2025_12_18_160820_add_t_htr_ag_to_serahbaki_table.php @@ -0,0 +1,83 @@ +getPdo(); + return true; + } catch (\Exception $e) { + return false; + } + }); + } + + + public function up() + { + $db_connection = $this->getActiveDB(); + + $key = array_search('mysql7', $db_connection); + + if ($key !== false) { + unset($db_connection[$key]); + } + + foreach ($db_connection as $dbase) { + Schema::connection($dbase)->table('serahbaki', function (Blueprint $table) use ($dbase) { + + if (!Schema::connection($dbase)->hasColumn('serahbaki', 't_htr_ag')) { + $table->date('t_htr_ag')->nullable()->after('aktif'); + } + }); + } + } + + + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + $db_connection = $this->getActiveDB(); + + $key = array_search('mysql7', $db_connection); + + if ($key !== false) { + unset($db_connection[$key]); + } + + foreach ($db_connection as $dbase) { + if (Schema::connection($dbase)->hasColumn('serahbaki', 't_htr_ag')) { + Schema::connection($dbase)->table('serahbaki', function (Blueprint $table) { + $table->dropColumn('t_htr_ag'); + }); + } + } + } +} + diff --git a/database/migrations/2025_12_18_163018_create_wtd_simulasi_table.php b/database/migrations/2025_12_18_163018_create_wtd_simulasi_table.php new file mode 100644 index 0000000..214b2d7 --- /dev/null +++ b/database/migrations/2025_12_18_163018_create_wtd_simulasi_table.php @@ -0,0 +1,40 @@ +id(); + + $table->string('bulan'); + $table->string('tahun'); + $table->string('kodcaw'); + $table->integer('jumlah_sag'); + $table->decimal('pembiayaan', 15, 2); + $table->decimal('baki', 15, 2); + $table->integer('simulasi'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('wtd_simulasi'); + } +} \ No newline at end of file diff --git a/database/migrations/2026_02_12_144445_create_max_mutuemas_table.php b/database/migrations/2026_02_12_144445_create_max_mutuemas_table.php new file mode 100644 index 0000000..718a8fb --- /dev/null +++ b/database/migrations/2026_02_12_144445_create_max_mutuemas_table.php @@ -0,0 +1,140 @@ +id('recno'); + $table->string('karat'); + $table->string('keterangan'); + $table->decimal('teller', 8, 2); + $table->decimal('pc', 8, 2); + $table->decimal('operasi', 8, 2); + $table->timestamp('tarikhupdate'); + }); + + // Insert data + DB::table('max_mutuemas')->insert([ + [ + 'recno' => 1, + 'karat' => '24.0Kgb', + 'keterangan' => '999 gb', + 'teller' => 75.00000, + 'pc' => 80.00000, + 'operasi' => 80.00000, + 'tarikhupdate' => '2025-01-12 00:00:00', + ], + [ + 'recno' => 2, + 'karat' => '24.0K', + 'keterangan' => '999', + 'teller' => 75.00000, + 'pc' => 80.00000, + 'operasi' => 80.00000, + 'tarikhupdate' => '2025-01-12 00:00:00', + ], + [ + 'recno' => 3, + 'karat' => '23.0K', + 'keterangan' => '950', + 'teller' => 74.00000, + 'pc' => 80.00000, + 'operasi' => 80.00000, + 'tarikhupdate' => '2025-01-12 00:00:00', + ], + [ + 'recno' => 4, + 'karat' => '22.0K', + 'keterangan' => '916', + 'teller' => 73.66667, + 'pc' => 80.00000, + 'operasi' => 80.00000, + 'tarikhupdate' => '2025-01-12 00:00:00', + ], + [ + 'recno' => 5, + 'karat' => '21.0K', + 'keterangan' => '900', + 'teller' => 73.16667, + 'pc' => 80.00000, + 'operasi' => 80.00000, + 'tarikhupdate' => '2025-01-12 00:00:00', + ], + [ + 'recno' => 6, + 'karat' => '20.0K', + 'keterangan' => '835', + 'teller' => 72.66667, + 'pc' => 80.00000, + 'operasi' => 80.00000, + 'tarikhupdate' => '2025-01-12 00:00:00', + ], + [ + 'recno' => 7, + 'karat' => '18.0Kp', + 'keterangan' => '750', + 'teller' => 72.16667, + 'pc' => 80.00000, + 'operasi' => 80.00000, + 'tarikhupdate' => '2025-01-12 00:00:00', + ], + [ + 'recno' => 8, + 'karat' => '18.0K', + 'keterangan' => '750', + 'teller' => 71.66667, + 'pc' => 80.00000, + 'operasi' => 80.00000, + 'tarikhupdate' => '2025-01-12 00:00:00', + ], + [ + 'recno' => 21, + 'karat' => '14.0K', + 'keterangan' => '585', + 'teller' => 71.16667, + 'pc' => 80.00000, + 'operasi' => 80.00000, + 'tarikhupdate' => '2025-01-12 00:00:00', + ], + [ + 'recno' => 22, + 'karat' => '14.0Kp', + 'keterangan' => '585', + 'teller' => 70.66667, + 'pc' => 80.00000, + 'operasi' => 80.00000, + 'tarikhupdate' => '2025-01-12 00:00:00', + ], + [ + 'recno' => 23, + 'karat' => '9.0K', + 'keterangan' => '375', + 'teller' => 70.16667, + 'pc' => 80.00000, + 'operasi' => 80.00000, + 'tarikhupdate' => '2025-01-12 00:00:00', + ], + ]); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('max_mutuemas'); + } +} \ No newline at end of file diff --git a/docker-compose.staging.yml b/docker-compose.staging.yml new file mode 100644 index 0000000..13b6aac --- /dev/null +++ b/docker-compose.staging.yml @@ -0,0 +1,77 @@ +# Staging stack — isolated from local docker-compose.yml (8080 / 3306) +# and from other apps on the server (unique project name + host ports). +# +# Local: +# docker compose --env-file .env.staging -f docker-compose.staging.yml up -d --build +# +# CI (image already in registry): +# APP_IMAGE=git.koppkb.com/KoPKB/api_arrahn IMAGE_TAG= \ +# docker compose --env-file .env.staging -f docker-compose.staging.yml up -d --no-build +# +# Host nginx reverse-proxies the public domain to 127.0.0.1:${HTTP_PORT}. +# See docker/nginx/host-proxy.example.conf +# +# If 8090 or 3308 is already taken, set HTTP_PORT / MYSQL_PUBLISH_PORT in .env.staging. + +name: api_arrahn_staging + +services: + app: + image: ${APP_IMAGE:-api_arrahn}:${IMAGE_TAG:-staging} + build: + context: . + dockerfile: docker/php/Dockerfile + target: staging + container_name: api_arrahn_staging_app + working_dir: /var/www/html + volumes: + - storage_staging:/var/www/html/storage + - ./.env.staging:/var/www/html/.env.staging:ro + env_file: + - .env.staging + environment: + APP_ENV: staging + USE_STAGING_ENV: "true" + extra_hosts: + - "host.docker.internal:host-gateway" + depends_on: + mysql: + condition: service_healthy + restart: unless-stopped + + web: + image: nginx:1.25-alpine + container_name: api_arrahn_staging_web + ports: + - "${HTTP_PORT:-8090}:80" + volumes: + - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro + depends_on: + - app + restart: unless-stopped + + mysql: + image: mysql:8.0 + container_name: api_arrahn_staging_mysql + command: --default-authentication-plugin=mysql_native_password + ports: + - "127.0.0.1:${MYSQL_PUBLISH_PORT:-3308}:3306" + environment: + MYSQL_DATABASE: erahn_xtra + MYSQL_USER: xtrauser + MYSQL_PASSWORD: password + MYSQL_ROOT_PASSWORD: root + volumes: + - mysql_staging_data:/var/lib/mysql + - ./docker/mysql/init:/docker-entrypoint-initdb.d:ro + healthcheck: + test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "-uroot", "-proot"] + interval: 5s + timeout: 5s + retries: 30 + start_period: 20s + restart: unless-stopped + +volumes: + mysql_staging_data: + storage_staging: diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..2cab859 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,40 @@ +services: + app: + build: + context: . + dockerfile: docker/php/Dockerfile + target: development + working_dir: /var/www/html + volumes: + - ./:/var/www/html:cached + environment: + APP_ENV: local + APP_DEBUG: "true" + depends_on: + - mysql + + web: + image: nginx:1.25-alpine + ports: + - "8080:80" + volumes: + - ./:/var/www/html:cached + - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro + depends_on: + - app + + mysql: + image: mysql:8.0 + command: --default-authentication-plugin=mysql_native_password + ports: + - "3306:3306" + environment: + MYSQL_DATABASE: erahn_xtra + MYSQL_USER: xtrauser + MYSQL_PASSWORD: password + MYSQL_ROOT_PASSWORD: root + volumes: + - mysql_data:/var/lib/mysql + +volumes: + mysql_data: diff --git a/docker/mysql/init/01-create-databases.sql b/docker/mysql/init/01-create-databases.sql new file mode 100644 index 0000000..9b47955 --- /dev/null +++ b/docker/mysql/init/01-create-databases.sql @@ -0,0 +1,7 @@ +CREATE DATABASE IF NOT EXISTS master_erahn; +CREATE DATABASE IF NOT EXISTS kaunter_erahn; + +GRANT ALL PRIVILEGES ON master_erahn.* TO 'xtrauser'@'%'; +GRANT ALL PRIVILEGES ON kaunter_erahn.* TO 'xtrauser'@'%'; +GRANT ALL PRIVILEGES ON erahn_xtra.* TO 'xtrauser'@'%'; +FLUSH PRIVILEGES; diff --git a/docker/nginx/default.conf b/docker/nginx/default.conf new file mode 100644 index 0000000..223a96c --- /dev/null +++ b/docker/nginx/default.conf @@ -0,0 +1,36 @@ +server { + listen 80; + server_name _; + + root /var/www/html/public; + index index.php index.html; + + charset utf-8; + client_max_body_size 50M; + + location / { + try_files $uri $uri/ @php; + } + + location @php { + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME /var/www/html/public/index.php; + fastcgi_param PATH_INFO $fastcgi_path_info; + fastcgi_pass app:9000; + fastcgi_index index.php; + fastcgi_read_timeout 120s; + } + + location ~ \.php$ { + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param PATH_INFO $fastcgi_path_info; + fastcgi_pass app:9000; + fastcgi_index index.php; + fastcgi_read_timeout 120s; + } + + location ~ /\.(?!well-known).* { + deny all; + } +} diff --git a/docker/php/Dockerfile b/docker/php/Dockerfile new file mode 100644 index 0000000..172df1c --- /dev/null +++ b/docker/php/Dockerfile @@ -0,0 +1,51 @@ +FROM php:7.4-fpm AS base + +WORKDIR /var/www/html + +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + git \ + pkg-config \ + unzip \ + libonig-dev \ + libzip-dev \ + libpng-dev \ + libjpeg62-turbo-dev \ + libfreetype6-dev \ + && docker-php-ext-configure gd --with-freetype --with-jpeg \ + && docker-php-ext-install -j"$(nproc)" \ + pdo_mysql \ + mbstring \ + bcmath \ + zip \ + exif \ + gd \ + && rm -rf /var/lib/apt/lists/* + +COPY --from=composer:2 /usr/bin/composer /usr/local/bin/composer + +COPY docker/php/php.ini /usr/local/etc/php/conf.d/app.ini +COPY docker/php/zz-clear-env.conf /usr/local/etc/php-fpm.d/zz-clear-env.conf +COPY docker/php/entrypoint.sh /usr/local/bin/app-entrypoint.sh + +RUN chmod +x /usr/local/bin/app-entrypoint.sh \ + && usermod -u 1000 www-data && groupmod -g 1000 www-data + +ENTRYPOINT ["app-entrypoint.sh"] +CMD ["php-fpm"] + +FROM base AS staging + +COPY --chown=www-data:www-data . /var/www/html + +RUN composer install --no-interaction --prefer-dist --no-dev --optimize-autoloader \ + && mkdir -p \ + storage/logs \ + storage/framework/cache/data \ + storage/framework/views \ + storage/framework/sessions \ + storage/app/public \ + bootstrap/cache \ + && chown -R www-data:www-data storage bootstrap/cache vendor + +FROM base AS development diff --git a/docker/php/entrypoint.sh b/docker/php/entrypoint.sh new file mode 100644 index 0000000..a9951a7 --- /dev/null +++ b/docker/php/entrypoint.sh @@ -0,0 +1,30 @@ +#!/bin/sh +set -e + +cd /var/www/html + +if [ "${USE_STAGING_ENV:-false}" = "true" ] && [ -f .env.staging ]; then + cp .env.staging .env +fi + +if [ -f composer.json ]; then + if [ -f vendor/autoload.php ] && [ "${USE_STAGING_ENV:-false}" = "true" ]; then + : # vendor is baked into the staging image + elif [ "${USE_STAGING_ENV:-false}" = "true" ]; then + composer install --no-interaction --prefer-dist --no-dev --optimize-autoloader + else + composer install --no-interaction --prefer-dist + fi +fi + +mkdir -p \ + storage/logs \ + storage/framework/cache/data \ + storage/framework/views \ + storage/framework/sessions \ + storage/app/public \ + bootstrap/cache + +chown -R www-data:www-data storage bootstrap/cache + +exec docker-php-entrypoint "$@" diff --git a/docker/php/php.ini b/docker/php/php.ini new file mode 100644 index 0000000..3e9df60 --- /dev/null +++ b/docker/php/php.ini @@ -0,0 +1,4 @@ +memory_limit=512M +upload_max_filesize=50M +post_max_size=50M +max_execution_time=120 diff --git a/docker/php/zz-clear-env.conf b/docker/php/zz-clear-env.conf new file mode 100644 index 0000000..edbfb22 --- /dev/null +++ b/docker/php/zz-clear-env.conf @@ -0,0 +1,3 @@ +[www] +; Pass container env vars (from compose env_file) through to PHP workers. +clear_env = no diff --git a/routes/report.php b/routes/report.php index 6cf98f2..0046b76 100644 --- a/routes/report.php +++ b/routes/report.php @@ -55,7 +55,11 @@ $router->group(['prefix' => 'api/reports'], function () use ($router) { $router->get('gadaitebus', ['uses' => 'GadaianController@getSummaryLaporanGadaiTebus']); $router->get('gadaitebusmasa', ['uses' => 'GadaianController@getSummaryLaporanGadaiTebusMasa']); $router->get('gadaitebusmasa/{kod_cawangan}', ['uses' => 'GadaianController@getLaporanGadaiTebusMasaCawangan']); + $router->get('audit-trail', ['uses' => 'AuditTrailController@getAuditTrail']); + $router->get('audittrail/operasi',['uses'=>'AuditTrailController@AuditTrailOperasi']); + $router->get('saringan/gadaian', ['uses' => 'SaringanGadaianController@getLaporanGadai']); - + $router->get('data-pelanggan', ['uses' => 'AnalisaController@getSummaryLaporanDataPelanggan']); + $router->get('data-pelanggan-bycaw', ['uses' => 'AnalisaController@getSummaryLaporanDataPelangganBycaw']); }); }); diff --git a/routes/web.php b/routes/web.php index 008c397..a239c1d 100644 --- a/routes/web.php +++ b/routes/web.php @@ -21,6 +21,10 @@ use App\Http\Controllers\TransactionOnlineTrailController; use App\Http\Controllers\Reports\RingkasanHarianController; use App\Transaction; +$router->get('/health', function () { + return response()->json(['status' => 'ok']); +}); + $router->group(['namespace' => '\Rap2hpoutre\LaravelLogViewer'], function() use ($router) { $router->get('logs', 'LogViewerController@index'); }); @@ -56,15 +60,17 @@ $router->group(['prefix'=>'api'], function () use ($router){ $router->put('customers/update/khazanah/{nokp}', ['uses' => 'CustomerController@customerUpdateKhazanah']); $router->get('customers/laporan/{kodcaw}/{tarikh}',['uses'=>'CustomerController@getLaporanCustomers']); $router->get('customers/latest/{kodcaw}',['uses'=>'CustomerController@getLatestCustomer']); - $router->put('customers/information/update/admin', ['uses' => 'CustomerController@customerUpdateAdmin']); + $router->put('customers/information/update/admin', ['uses' => 'CustomerController@customerUpdateAdmin']); //blh refer sini izazi $router->get('admin/customers/nokp/search',['uses'=>'CustomerController@showOneCustomerByICAdmin']); $router->get('customer/blacklist',['uses'=>'CustomerController@blacklistCustomer']); $router->get('customer/anggota',['uses'=>'CustomerController@anggotaKoperasi']); $router->get('customer/eachcawangan/{ic}',['uses'=>'CustomerController@showCustomerByEachCawangan']); $router->put('customers/{noic}/assign-anggota', ['uses' => 'CustomerController@assignAnggota']); + $router->post('/customers/update-tag-pdpa', ['uses' => 'CustomerController@updateTagPdpa']); //arcc $router->get('customer/searchbyname',['uses'=>'CustomerController@searchByName']); + $router->get('customer/searchbygadai/{kodcaw}/{norujukan}',['uses'=>'CustomerController@AdminsearchGadai']); // Route::get('/api/customers/searchbyname', [CustomerController::class, 'searchByName']); // $router->put('customers/update/{nokp}', ['uses' => 'CallCenterController@customerUpdate']); //kena tengok api ni // $router->put('customers/update/kaunter/{nokp}/{kodcaw}', ['uses' => 'CallCenterController@customerUpdateKaunter']); @@ -90,7 +96,7 @@ $router->group(['prefix'=>'api'], function () use ($router){ $router->get('gadai/cawangan/{kodcaw}/{tarikh}',['uses'=>'GadaiController@showOneGadaiByCawanganOnly']); $router->get('gadai/norujukan/{norujukan}',['uses'=>'GadaiController@showOneGadaiByNorujukan']); $router->get('gadai/norujukankodcaw/{kodcaw}/{norujukan}',['uses'=>'GadaiController@showOneGadaiByNorujukanKodcaw']); - $router->get('gadai/norujukan/{kodcaw}/{norujukan}',['uses'=>'GadaiController@showOneGadaibyRujukanAndCawangan']); + $router->get('gadai/norujukan/{kodcaw}/{norujukan}',['uses'=>'GadaiController@showOneGadaibyRujukanAndCawangan']); // refer sini utk pass gadai $router->post('gadai/{kodcaw}',['uses'=>'GadaiController@create']); $router->post('gadaiold/{kodcaw}',['uses'=>'GadaiController@createold']); $router->get('gadai/{cawangan_code}/{date}',['uses'=>'GadaiController@gadaiTransactionByCawanganAndDay']); @@ -196,6 +202,8 @@ $router->group(['prefix'=>'api'], function () use ($router){ $router->get('keluar/lelong',['uses'=>'LelongController@keluarLelong']); + $router->get('lelong/bakilelongbyteller/{kodcaw}',['uses' => 'LelongController@getBakiLelongByTeller']); + //Marhun API @@ -262,6 +270,9 @@ $router->group(['prefix'=>'api'], function () use ($router){ $router->get('maxpinjaman',['uses'=>'MaxPinjamanController@getAllMaxPinjaman']); + $router->get('maxmutuemas',['uses'=>'MaxPinjamanController@getAllMaxMutuEmas']); + $router->get('maxmutuemas/specific',['uses'=>'MaxPinjamanController@getSpecificMaxMutuEmas']); + $router->post('maxmutuemas/update',['uses'=>'MaxPinjamanController@updateMaxMutuEmas']); $router->get('transaksi_keuntungan/{norujukan}',['uses'=>'TransaksiKeuntunganController@getTransaksiKeuntunganByRujukan']); $router->get('transaksi_keuntungan_latest/{norujukan}',['uses'=>'TransaksiKeuntunganController@getTransaksiKeuntunganByRujukanLatest']); @@ -376,6 +387,8 @@ $router->group(['prefix'=>'api'], function () use ($router){ $router->get('laporanpetibesirange/{kodcaw}',['uses'=> 'VaultController@laporanPetiBesiRange']); $router->get('laporanAuditTrail',['uses'=> 'LaporanController@LaporanAuditTrail']); + //Get Tunai By tarikh for Laporan Aliran Tunai Teller + $router->get('getTunaiByTarikh', ['uses' => 'TunaiController@getTunaiByTarikh']); //API PANJAR KHAZANAH $router->get('SenaraiPanjar/{kodcaw}',['uses'=>'PanjarController@list']); @@ -386,6 +399,12 @@ $router->group(['prefix'=>'api'], function () use ($router){ $router->post('CreatePanjar/{kodcaw}',['uses'=>'PanjarController@create']); $router->post('DeletePanjar/{kodcaw}',['uses'=>'PanjarController@delete']); + //API PAMPASAN GUNA PANJAR + $router->post('pampasan/initiatePampasan',['uses'=>'PampasanController@initiatePampasan']); + $router->post('pampasan/terimaPampasan',['uses'=>'PampasanController@terimaPampasan']); + $router->put('pampasan/updateStatusPampasan', ['uses' => 'PampasanController@updateStatusPampasan']); + $router->get('pampasan', ['uses' => 'PampasanController@getPampasan']); + //API KELULUSAN $router->get('SenaraiKelulusan/{kodcaw}',['uses'=>'KelulusanController@list']); @@ -468,8 +487,14 @@ $router->group(['prefix'=>'api'], function () use ($router){ //laporanlelong adminportal $router->get('laporan/lelong',['uses' => 'LelongController@LaporanLelong']); $router->get('lookupbatchlel/{kodcaw}',['uses' => 'LelongController@LookupBatchLel']); - + //barangkes $router->get('palsu/laporan', ['uses' => 'BarangkesController@LaporanBarangKes']); + $router->get('barangkes', ['uses' => 'BarangkesController@index']); // + $router->post('barangkes/store', ['uses' => 'BarangkesController@store']); + + // $router->post('/barangkes/{id}', ['uses' => 'BarangkesController@show']); + $router->put('barangkes/update/{recno}', ['uses' => 'BarangkesController@update']); + //update tagterima Tebus @@ -796,6 +821,7 @@ $router->group(['prefix'=>'portal'], function () use ($router){ $router->get('transaksipelanggan/upah',['uses'=>'TransactionController@TransaksiUpah']); $router->get('searchsagonline',['uses'=>'TransactionOnlineController@searchSAGOnline']); $router->get('customer/info',['uses'=>'TransactionOnlineController@CustomerInfo']); + $router->get('customer/info/lelong',['uses'=>'TransactionOnlineController@CustomerInfoLelong']); }); $router->group(['prefix'=>'admin'], function () use ($router){ @@ -809,9 +835,11 @@ $router->group(['prefix'=>'admin'], function () use ($router){ $router->get('TuntutBakiTarikhTeller/{kodcaw}',['uses'=>'AdminPageController@showTuntutBakiTarikhTeller']); $router->get('lelong/tarikh/{kodcaw}',['uses'=>'AdminPageController@LelonganTarikh']); $router->post('updateTunaiGTByTarikh/{kodcaw}',['uses'=>'AdminPageController@UpdateTunaiByTarikh']); - $router->get('searchByName',['uses'=>'CustomerController@AdminsearchCustomerByName']); - $router->get('searchByIC',['uses'=>'CustomerController@AdminsearchCustomerByIC']); + $router->get('searchByIC',['uses'=>'CustomerController@AdminsearchCustomerByIC']); //refer ni jugak + + // sag + $router->get('searchBySag',['uses'=>'CustomerController@AdminsearchCustomerBySAG']); //refer ni jugak $router->get('pembiayaanTahunan',['uses'=>'AdminPageController@TahunanGadai']); $router->get('penebusanTahunan',['uses'=>'AdminPageController@TahunanTebus']); @@ -879,6 +907,20 @@ $router->group(['prefix'=>'admin'], function () use ($router){ $router->post('wtd/delete',['uses'=>'AdminPageController@RemoveDraftWTD']); $router->get('wtd/dalamproses',['uses'=>'AdminPageController@rekodWTDDalamProses']); + //Aiman Ngube WTD + $router->get('wtd/janaSimulasi',['uses'=>'AdminPageController@JanaSimulasiWTD']); + $router->get('wtd/rekodSimulasi',['uses'=>'AdminPageController@RekodSimulasiWTD']); + $router->post('wtd/prosesSimulasi',['uses'=>'AdminPageController@ProsesSimulasiWTD']); + $router->post('wtd/pengesahanSimulasi',['uses'=>'AdminPageController@PengesahanSimulasiWTD']); + $router->post('wtd/simulasiToDraft',['uses'=>'AdminPageController@SimulasiToDraft']); + $router->post('wtd/simulasiBaru',['uses'=>'AdminPageController@SimulasiBaru']); + + //laporan wtd + $router->get('wtd/summaryWtd', ['uses' => 'WTDController@getSummaryWtd']); + + //debugwtd + $router->get('wtd/debugWtd', ['uses' => 'WTDController@getDebugWtd']); + $router->get('audit/keuntungansebenar',['uses'=>'AdminPageController@KeuntunganSebenarExport']); $router->get('laporan/aging',['uses'=>'AdminPageController@LaporanAging']); $router->get('dashboard/aging',['uses'=>'AdminPageController@DashboardAging']); diff --git a/storage/.gitignore b/storage/.gitignore new file mode 100644 index 0000000..ca5c069 --- /dev/null +++ b/storage/.gitignore @@ -0,0 +1,2 @@ +/debugbar +/framework/sessions \ No newline at end of file diff --git a/tinker/getActiveCawanganDbConnection.php b/tinker/getActiveCawanganDbConnection.php index a9fd113..96df402 100644 --- a/tinker/getActiveCawanganDbConnection.php +++ b/tinker/getActiveCawanganDbConnection.php @@ -11,7 +11,7 @@ $all_active_db_keys = array_filter(array_keys(config('database.connections')), f } }); -$non_cawangan_database = ['lelong', 'online_arrahn', 'kaunterpkb']; +$non_cawangan_database = ['lelong', config('tennant_database.master_db'), config('tennant_database.kaunter_db')]; $all_cawangan_db = array_filter($all_active_db_keys, function($db_key) use($non_cawangan_database){ $isNotCawangan = in_array(config('database.connections.' . $db_key . '.database'), $non_cawangan_database);