Rapihin setup/member/lot-parking + fitur intercom, exclude WIP controller & file sampah dari git

Kumpulan perubahan yang udah numpuk di working tree: refactor Setup
(Gate/Vehicle/Member), rapihin memberin & stiker, service parking baru
(ParkingUtilsServices, NetworkService), model/migration lot-parking &
DHCP reservation, dan fitur baru Intercom (controller/model/migration/
view).

ReportTransaksiController versi lokal ini WIP (~90%, masih didebug) -
versi yang bener ada di server, jadi dikeluarin dari git (ditambahin
ke .gitignore) biar gak numpuk nindihin punya server pas git pull di
sana. Sekalian keluarin dump mentah tabel softseting (1.8MB, nyasar
ke-commit), file .bak, dan arsip ad-hoc (api.tgz, c.zip) yang emang
bukan source code.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01EAJc2mrpj2cSTe4oowLPzQ
This commit is contained in:
2026-10-04 07:15:54 +07:00
co-authored by Claude Sonnet 5
parent efdea9d739
commit 2a9b28581c
91 changed files with 5716 additions and 2470 deletions
@@ -34,9 +34,8 @@ public function index(Request $request)
if (!array_key_exists('gate', $_GET)) {
return response()->json([
'status' => 'success',
// 'desc' => 'Parameter undefined',
'details' => $location
],400);
]);
}
@@ -0,0 +1,128 @@
<?php
namespace App\Http\Controllers\Api\V1;
use App\Http\Controllers\Controller;
use App\Models\IntercomCall;
use App\Models\IntercomDevice;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
/**
* Modul Intercom: reuse pola ParkingOperationController.
* Laravel HANYA urus signaling + log, BUKAN relay audio.
* Audio diurus Go relay (UDP), Laravel cuma simpan metadata + path rekaman.
*/
class IntercomController extends Controller
{
public function devices()
{
return IntercomDevice::orderBy('device_id')->get();
}
public function queue()
{
return IntercomCall::whereIn('status', ['waiting', 'active'])
->orderBy('requested_at')
->limit(20)->get();
}
public function history(Request $request)
{
return IntercomCall::orderByDesc('id')->limit($request->input('limit', 50))->get();
}
// Dipanggil Go relay saat ESP32 kirim MQTT intercom/request
public function request(Request $request)
{
$data = $request->validate([
'device_id' => 'required|string|max:20',
'arah' => 'sometimes|string|in:in,out',
]);
$deviceId = strtoupper($data['device_id']);
$device = IntercomDevice::firstOrCreate(
['device_id' => $deviceId],
['nama' => $deviceId, 'status' => 'idle']
);
// Kalau device lagi active, tetap masuk antrean (tidak ditolak)
$call = IntercomCall::create([
'device_id' => $deviceId,
'arah' => $data['arah'] ?? 'in',
'status' => 'waiting',
'requested_at' => now(),
]);
$device->update(['status' => 'calling', 'last_seen_at' => now()]);
Log::info("Intercom request {$deviceId} call_id={$call->id}");
return response()->json(['status' => true, 'call_id' => $call->id, 'device_id' => $deviceId]);
}
// Admin klik [Terima] di dashboard
public function accept(Request $request)
{
$data = $request->validate(['call_id' => 'required|integer']);
$call = IntercomCall::findOrFail($data['call_id']);
// Tutup sesi active lain di device yang sama (single private session)
IntercomCall::where('device_id', $call->device_id)
->where('status', 'active')->update(['status' => 'ended', 'ended_at' => now(), 'ended_by' => 'admin-switch']);
$call->update(['status' => 'active', 'started_at' => now()]);
IntercomDevice::where('device_id', $call->device_id)->update(['status' => 'active']);
// Go relay yang bertugas publish MQTT intercom/invite/{DEVICE} + buka UDP port.
// Laravel cuma ubah status, tidak publish MQTT langsung.
return response()->json(['status' => true, 'call' => $call]);
}
public function end(Request $request)
{
$data = $request->validate([
'call_id' => 'required|integer',
'ended_by' => 'sometimes|string|max:20',
'recording_path' => 'sometimes|string|max:255',
]);
$call = IntercomCall::findOrFail($data['call_id']);
$now = now();
$durasi = $call->started_at ? $now->diffInSeconds($call->started_at) : ($call->requested_at ? $now->diffInSeconds($call->requested_at) : 0);
$call->update([
'status' => $call->status === 'waiting' && ($data['ended_by'] ?? '') === 'timeout' ? 'missed' : 'ended',
'ended_at' => $now,
'durasi_detik' => $durasi,
'ended_by' => $data['ended_by'] ?? 'admin',
'recording_path' => $data['recording_path'] ?? $call->recording_path,
]);
// Balikin status device ke idle kalau tidak ada sesi lain
$masihAktif = IntercomCall::where('device_id', $call->device_id)->whereIn('status', ['waiting', 'active'])->exists();
if (!$masihAktif) {
IntercomDevice::where('device_id', $call->device_id)->update(['status' => 'idle']);
}
return response()->json(['status' => true, 'call' => $call]);
}
// Heartbeat / LWT dari Go relay: ESP32 online/offline
public function heartbeat(Request $request)
{
$data = $request->validate([
'device_id' => 'required|string|max:20',
'status' => 'sometimes|string|max:20',
'ip_address' => 'sometimes|string|max:45',
]);
IntercomDevice::updateOrCreate(
['device_id' => strtoupper($data['device_id'])],
['status' => $data['status'] ?? 'idle', 'ip_address' => $data['ip_address'] ?? null, 'last_seen_at' => now()]
);
return response()->json(['status' => true]);
}
}
@@ -0,0 +1,19 @@
<?php
namespace App\Http\Controllers\Api\V1;
use App\Http\Controllers\Controller;
use App\Models\SoftSettings;
use Illuminate\Http\Request;
class LocationSiteInfoController extends Controller
{
public function getLocation()
{
$site = SoftSettings::first();
return response->json([
"status" => true,
"data" => $site,
]);
}
}
@@ -1,125 +0,0 @@
<?php
namespace App\Http\Controllers\Api\V1;
use App\Http\Controllers\Controller;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
class MemberinController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
//
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
//
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show($id)
{
Log::info($id);
$dateNow = Carbon::now();
$data = DB::table('mergetransaksistikerdetail as a')
->select('a.*','jm.nama as vehicle')
->leftjoin('jenis_mobil as jm','jm.id','=','a.jenis_mobil')
->where('nopol', $id)
->orderByDesc('tgl_edited')
->first();
$akhir = Carbon::parse($data->akhir);
if(!$data) {
return response()->json([
'status'=>false,
'message'=>'Member tidak ditemukan'
]);
}
if($dateNow->greaterThan($akhir)){
return response()->json([
'status' => 'expired',
'expired' => true,
'message' => 'Member expired',
'data' => $data
]);
} else {
return response()->json([
'status' => 'active',
'expired' => false,
'message' => 'Member aktif',
'data' => $data
]);
}
Log::info(json_encode($data));
}
/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function edit($id)
{
//
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
//
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy($id)
{
//
}
}
@@ -0,0 +1,230 @@
<?php
namespace App\Http\Controllers\Api\V1\ParkingLot;
use App\Http\Controllers\Controller;
use App\Models\LotParking\SiteParking;
use App\Models\LotParking\LotParkingLog;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
class ParkingLotController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$getArea = SiteParking::all(); // Mengambil semua data dari model SiteParking
$parkingDataByArea = []; // Array untuk menyimpan hasil query berdasarkan area
foreach ($getArea as $lantai) {
$spaceParking = $lantai->space_parking;
// Array untuk menyimpan data parking per lantai
$parkingData = [];
for ($lotNumber = 1; $lotNumber <= $spaceParking; $lotNumber++) {
// Melakukan query pada LotParkingLog berdasarkan area dan lot_number
$log = LotParkingLog::where("area", $lantai->sitearea_id)
->where("lot_number", $lotNumber)
->select("lot_number", "status")
->first();
// Jika data tidak ditemukan, buat object baru dengan lot_number dari pengulangan for
if (!$log) {
$log = (object) [
"lot_number" => $lotNumber,
"status" => 0,
];
}
// Menyimpan hasil query dalam array
$parkingData[] = $log;
}
// Menyimpan data parking per lantai dalam array berdasarkan area
$parkingDataByArea[] = [
"lantai" => $lantai->sitearea_id,
"data" => $parkingData,
];
}
// Melakukan dump and die untuk melihat hasil query sementara
// dd(json_encode($parkingDataByArea));
// dd($getArea->toJson());
return view("headoffice.space", [
"areas" => $getArea,
"parkingDataByArea" => $parkingDataByArea,
]);
return view("headoffice.space");
}
public function getParkingData()
{
Log::info("getParkingData method called");
$getArea = SiteParking::all(); // Mengambil semua data dari model SiteParking
$parkingDataByArea = []; // Array untuk menyimpan hasil query berdasarkan area
foreach ($getArea as $lantai) {
$spaceParking = $lantai->space_parking;
// Array untuk menyimpan data parking per lantai
$parkingData = [];
for ($lotNumber = 1; $lotNumber <= $spaceParking; $lotNumber++) {
// Melakukan query pada LotParkingLog berdasarkan area dan lot_number
$log = LotParkingLog::where("area", $lantai->sitearea_id)
->where("lot_number", $lotNumber)
->select("lot_number", "status")
->first();
// Jika data tidak ditemukan, buat object baru dengan lot_number dari pengulangan for
if (!$log) {
$log = (object) [
"lot_number" => $lotNumber,
"status" => 0,
];
}
// Menyimpan hasil query dalam array
$parkingData[] = $log;
}
// Menyimpan data parking per lantai dalam array berdasarkan area
$parkingDataByArea[] = [
"lantai" => $lantai->sitearea_id,
"data" => $parkingData,
];
Log::info($parkingDataByArea);
}
return response()->json($parkingDataByArea);
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
$area = $request->site_area;
$lotNumber = $request->lot_number;
Log::info($area);
Log::info($lotNumber);
$exisLot = LotParkingLog::where("area", $area)->where("lot_number", $lotNumber)->where("status", 1)->first();
if (!$exisLot) {
$LotParking = LotParkingLog::create([
"area" => $area,
"lot_number" => $lotNumber,
"status" => 1,
"update_at" => null,
]);
Log::info("Lot " . $lotNumber . " di " . $area . " terisi.");
return response()->json([
"status" => "success",
"message" => "Lot No " . $lotNumber . " terisi",
"data" => $LotParking,
]);
} else {
return response()->json([
"status" => "error",
"message" => "Kendaraan belum keluar",
]);
}
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show($id)
{
//
}
/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function edit($id)
{
//
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request)
{
Log::info(json_encode($request->all()));
$area = $request->site_area;
$lotNumber = $request->lot_number;
Log::info($area);
Log::info($lotNumber);
$exisLot = LotParkingLog::where("area", $area)
->where("lot_number", $lotNumber)
->where("status", 1)
->orderBy("updated_at", "desc")
->first();
if (!$exisLot) {
return response()->json([
"status" => "error",
"message" => "Lot masih kosong",
]);
} else {
$exisLot->update([
"status" => 0,
]);
Log::info("Lot " . $lotNumber . " di " . $area . " keluar area.");
return response()->json([
"status" => "success",
"message" => "Kendaraan telah keluar",
"data" => $exisLot,
]);
}
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy($id)
{
//
}
}
@@ -16,19 +16,19 @@ class SelfMemberinController extends Controller
*/
public function index(Request $request)
{
$jenis = $request->query('jenis');
$jenis = $request->query("jenis");
Log::info($jenis);
$tarifStiker = DB::table('tarif_stiker');
$tarifStiker = DB::table("tarif_stiker");
if ($jenis) {
$tarifStiker->where('stasiunkerja_id', $jenis);
$tarifStiker->where("stasiunkerja_id", $jenis);
}
$produk = $tarifStiker->get();
Log::info($produk);
return view('apps.member.index', compact('produk'));
return view("apps.memberin.index", compact("produk"));
}
/**
@@ -61,10 +61,7 @@ public function store(Request $request)
public function show($id)
{
Log::info($id);
$tarifStiker = DB::table('tarif_stiker')
->where('stasiunkerja_id', $id)
->orderby('tarif')
->get();
$tarifStiker = DB::table("tarif_stiker")->where("stasiunkerja_id", $id)->orderby("tarif")->get();
return $tarifStiker;
}
@@ -6,6 +6,7 @@
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;
class LoginController extends Controller
@@ -56,4 +57,11 @@ protected function credentials (Request $request)
'password' => $request->input('password'),
];
}
protected function sendFailedLoginResponse(Request $request)
{
throw ValidationException::withMessages([
'login' => 'Username atau password tidak sesuai.',
]);
}
}
@@ -0,0 +1,54 @@
<?php
namespace App\Http\Controllers\Intercom;
use App\Http\Controllers\Controller;
use App\Models\IntercomCall;
class UIController extends Controller
{
// Dashboard operator pusat. Data real-time diambil via JS polling ke /api/v1/intercom/*.
public function index()
{
return view('Intercom.UI.index');
}
// Streaming/download rekaman per sesi. File ditulis Go relay (STORE_DIR).
public function recording($id)
{
$call = IntercomCall::findOrFail($id);
if (!$call->recording_path) {
abort(404, 'Belum ada rekaman untuk sesi ini');
}
$path = $call->recording_path;
// Amankan: hanya basename, cari di kandidat folder (relatif project + /opt).
$candidates = [
$path,
storage_path('app/intercom/' . basename($path)),
'/opt/intercom-relay/storage/' . basename($path),
];
$real = null;
foreach ($candidates as $c) {
if ($c && is_file($c)) {
$real = $c;
break;
}
}
if (!$real) {
abort(404, 'File rekaman tidak ditemukan di server: ' . basename($path));
}
// File dari Go relay berupa raw PCM 16kHz mono 16-bit.
// Disajikan sebagai octet-stream biar bisa di-download / ffplay.
// Nanti kalau relay sudah tulis header WAV, ganti ke audio/wav.
return response()->file($real, [
'Content-Type' => 'application/octet-stream',
'Content-Disposition' => 'attachment; filename="' . basename($real) . '"',
]);
}
}
@@ -1,84 +0,0 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class LevelMenuController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
//
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
//
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show($id)
{
//
}
/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function edit($id)
{
//
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
//
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy($id)
{
//
}
}
@@ -0,0 +1,67 @@
<?php
namespace App\Http\Controllers\Parking\Audit;
use App\Models\TransaksiParkir;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Yajra\DataTables\Facades\DataTables;
class AuditReportController extends Controller
{
public function index()
{
return view("Parking.Audit.index");
}
public function data(Request $request)
{
$query = TransaksiParkir::query()
->from("transaksi_parkir as tp")
->leftJoin("pegawai as p", "p.nomer", "=", "tp.adm");
// Tanggal wajib
$query->whereBetween("waktu_keluar", [$request->start_date . " 00:00:00", $request->end_date . " 23:59:59"]);
// Status
if ($request->filled("status_transaksi")) {
$query->where("status_transaksi", $request->status_transaksi);
} else {
// Default hanya -1 dan -2
$query->whereIn("status_transaksi", [0, -1, -2]);
}
// Alasan tidak boleh NULL
if ($request->filter_alasan == "1") {
$query->whereNotNull("alasan");
}
$totalTransaksi = (clone $query)->count();
$totalBayar = (clone $query)->sum("bayar_keluar");
$data = $query
->select([
"tp.id",
"no_pol",
"waktu_masuk",
"waktu_keluar",
"status_transaksi",
"bayar_keluar",
"alasan",
"cara_bayar",
"p.nama as operator",
])
->orderByDesc("waktu_keluar")
->get();
return response()->json([
"response" => true,
"data" => $data,
"summary" => [
"total_transaksi" => $totalTransaksi,
"total_bayar" => $totalBayar,
],
]);
}
}
@@ -3,11 +3,14 @@
namespace App\Http\Controllers\Parking;
use App\Http\Controllers\Controller;
use App\Models\MemberCard;
use App\Models\SoftSettings;
use App\Models\StikerTrans;
use App\Models\StikerTransDetail;
use App\Models\MemberCard;
use App\Services\MakeStikerServices;
use Carbon\Carbon;
use Exception;
use Illuminate\Support\Str;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
@@ -35,12 +38,22 @@ public function index(Request $request)
public function getMember(Request $request)
{
// Log::info(json_encode("nopol : " . $request->nopol));
Log::info(json_encode("nama : " . $request->input("search-by")));
Log::info(json_encode("value : " . $request->input("search_value")));
Log::info(json_encode("isActive : " . $request->input("isActive")));
// Log::info(json_encode("veh : " . $request->vehicle));
// Log::info(json_encode("dept : " . $request->depart));
// Log::info(json_encode("mem : " . $request->member));
// Log::info(json_encode("mem : " . $request->jenismember));
// Log::info(json_encode("trans : " . $request->notrans));
// Log::info(json_encode("isactive : " . gettype($request->isactive)));
$searchBy = $request->input("search-by");
$searchValue = trim($request->input("search_value", ""));
$memberType = $request->input("member_type");
$unitKerja = $request->input("departement");
$vehicle = $request->input("vehicle");
$isActive = $request->input("isActive");
if ($request->ajax()) {
$dataStiker = DB::table("transaksi_stiker as ts")
->leftJoin("detail_transaksi_stiker as dts", "dts.notrans", "=", "ts.notrans")
@@ -55,40 +68,47 @@ public function getMember(Request $request)
jm.nama vehicle, dts.jenis_member, cm.no_card as no_card'),
)
->distinct();
// ->select(DB::raw('ts.notrans as notrans , ts.nama , ts.alamat as alamat , ts.telepon as telepon , ts.awal as awal , ts.akhir as akhir, sk.nama as unit_kerja, jl.nama as jenis_member, ts.no_id'))
if ($request->nama) {
$dataStiker = $dataStiker->where("ts.nama", "like", "%" . $request->nama . "%");
if ($searchBy && $searchValue !== "") {
switch ($searchBy) {
case "nama":
$nama = strtolower($searchValue);
$NAMA = strtoupper($searchValue);
$dataStiker->where("ts.nama", "ILIKE", "%{$searchValue}%");
break;
case "alamat":
$dataStiker->where("ts.alamat", "like", "%{$searchValue}%");
break;
case "nopol":
$dataStiker->where("dts.nopol", "like", "%{$searchValue}%");
break;
case "nocard":
$dataStiker->where("cm.nocard", "like", "%{$searchValue}%");
break;
case "notrans":
$dataStiker->where("ts.notrans", "like", "%{$searchValue}%");
break;
// case "":
// $dataStiker->where("ts.nama", "like", "%{$searchValue}%");
// break;
}
}
if ($request->notrans) {
$dataStiker = $dataStiker->where("ts.notrans", "like", "%" . $request->notrans . "%");
if ($memberType) {
$dataStiker->where("ts.jenis_langganan", $memberType);
}
if ($request->nopol) {
$dataStiker = $dataStiker->where("ts.unit_kerja", "like", "%" . $request->depart . "%");
if ($unitKerja) {
$dataStiker->where("ts.unit_kerja", $unitKerja);
}
if ($request->member) {
$dataStiker = $dataStiker->where("ts.jenis_langganan", "like", "%" . $request->member . "%");
if ($vehicle) {
$dataStiker->where("dts.jenis_mobil", $vehicle);
}
if ($request->nopol) {
$dataStiker = $dataStiker->where("dts.nopol", "like", "%" . $request->nopol . "%");
if ($request->input("isActive") == "1") {
$dataStiker->whereRaw("NOW() BETWEEN ts.awal AND ts.akhir");
}
if ($request->vehicle) {
$dataStiker = $dataStiker->where("dts.jenis_mobil", "like", "%" . $request->vehicle . "%");
}
if ($request->nocard) {
$dataStiker = $dataStiker->where("cm.no_card", "like", "%" . $request->nocard . "%");
}
if ($request->isactive === "1") {
$dataStiker = $dataStiker->whereRaw("now() between ts.awal and ts.akhir");
}
// Log::info($dataStiker->toSql());
$dataStiker = $dataStiker->get();
@@ -132,22 +152,47 @@ public function checkField(Request $request)
return response()->json(["response" => true, "message" => "Data sudah ada"]);
}
public function store(Request $request)
public function store(Request $request, MakeStikerServices $makeStiker)
{
Log::info("Data yang diterima : " . json_encode($request->all()));
$mountYearNow = Carbon::now()->format("m/Y");
$dataStiker = $request->input("formData");
$dataVehicle = $request->input("nopolData");
$dataCard = $request->input("cardNumber");
Log::info("Data Stiker : " . json_encode($dataStiker));
Log::info("Data Kendaraan : " . json_encode($dataVehicle));
Log::info("Data kartu : " . json_encode($dataCard));
// $cleanedData = stripslashes(trim($data));
// Log::debug('Modified : ' . json_encode($cleanedData));
// $dataStiker = json_decode($cleanedData, false);
// Log::info('Debuggind data : ' . json_encode($dataStiker));
$getTrans = DB::table("indexnum")
->whereIn("nama", ["TRX", "IDN"])
->pluck("value", "nama");
$noTrans = $getTrans->get("TRX");
$noID = $getTrans->get("IDN");
// Log::info("Get Trans : " . json_encode($getTrans));
// Log::info("No Trans : " . $noTrans);
// Log::info("No ID : " . $noID);
$noTransFormat = str_pad($noTrans, 5, "0", STR_PAD_LEFT);
$noIDFormat = str_pad($noID, 5, "0", STR_PAD_LEFT);
$getLocation = SoftSettings::first();
Log::info("Namalokasi : " . json_encode($getLocation->namalokasi));
$ignore = ["RS", "PT", "CV", "TBK"];
$nama = preg_replace("/[^A-Za-z0-9 ]/", "", $getLocation->namalokasi);
$kata = preg_split("/\s+/", trim($nama));
$identity = "";
foreach ($kata as $k) {
if (in_array(strtoupper($k), $ignore)) {
continue;
}
$identity .= strtoupper($k[0]);
}
$randomNumber = strtoupper(Str::random(6));
$newTrans = "TRX-" . $identity . "-" . Carbon::now()->format("Ymd-His") . "-" . $randomNumber;
$newID = "IDN-" . $identity . "-" . Carbon::now()->format("Ymd-His") . "-" . $randomNumber;
// $noid = $seqId->value . "-IDT-" . $mountYearNow;
// $validate = Validator::make($request->all(),[
// 'nama' => 'required|string|unique',
// // 'nopol' => 'required|string|unique:detail_transaksi_stiker,nopol',
@@ -158,84 +203,131 @@ public function store(Request $request)
// return response()->json(['response' => false, 'message' => 'pastikan nama, Nomor Polisi, dan data kartu sudah terisi']);
// }
$dateNow = Carbon::now()->format("Y-m-d H:m:s");
$seqTrans = DB::table("indexnum")->select("value")->where("nama", "sticker")->first();
$seqId = DB::table("indexnum")->select("value")->where("nama", "identitas")->first();
// $dateNow = Carbon::now()->format("Y-m-d H:m:s");
// $seqTrans = DB::table("indexnum")->select("value")->where("nama", "sticker")->first();
// $seqId = DB::table("indexnum")->select("value")->where("nama", "identitas")->first();
$notrans = $seqTrans->value . "/STK/" . $mountYearNow;
$noid = $seqId->value . "/IDT/" . $mountYearNow;
$user = Auth::user();
// $notrans = $seqTrans->value . "/STK/" . $mountYearNow;
// $noid = $seqId->value . "/IDT/" . $mountYearNow;
// $user = Auth::user();
$periode = explode(" - ", $dataStiker["periode"]);
Log::info("Parcing Periode : " . json_encode($periode));
$awal = Carbon::createFromFormat("d-m-Y H:i", $periode[0]);
$akhir = Carbon::createFromFormat("d-m-Y H:i", $periode[1]);
// // Log::info($user);
$dataStiker = $request->input("formData");
$dataVehicle = $request->input("nopolData");
$dataCard = $request->input("cardNumber");
Log::info("Data Stiker : " . json_encode($dataStiker));
Log::info("Data Kendaraan : " . json_encode($dataVehicle));
Log::info("Data kartu : " . json_encode($dataCard));
if ($dataStiker["periode"]) {
$periode = explode(" - ", $dataStiker["periode"]);
Log::info("Parcing Periode : " . json_encode($periode));
$awal = Carbon::createFromFormat("d-m-Y H:i", $periode[0]);
$akhir = Carbon::createFromFormat("d-m-Y H:i", $periode[1]);
} else {
$awal = Carbon::createFromFormat("d-m-Y H:i", $dataStiker["awal"]);
$akhir = Carbon::createFromFormat("d-m-Y H:i", $dataStiker["akhir"]);
}
Log::info("Awal : " . $awal . " Akhir : " . $akhir);
// Log::info($user);
try {
$dataStiker = [
"jenis_transaksi" => $dataStiker["jenis_transaksi"], // 0 = transaksi baru , 1 = perpanjangan
"notrans" => $notrans,
"no_id" => $noid,
"nama" => $dataStiker["nama"],
"alamat" => $dataStiker["address"] ?? "",
"telepon" => $dataStiker["phone"] ?? "",
"unit_kerja" => $dataStiker["depart"],
"jenis_stiker" => $dataStiker["member"],
"awal" => $awal,
"akhir" => $akhir,
"harga" => $dataStiker["harga"] ?? 0,
"keterangan" => $dataStiker["note"] ?? "",
"tanggal" => $dateNow,
"operator" => $user->nomer,
];
$dataStiker["notrans"] = $newTrans;
$dataStiker["no_id"] = $newID;
$dataStiker["awal"] = $awal;
$dataStiker["akhir"] = $akhir;
DB::table("transaksi_stiker")->insert($dataStiker);
if ($dataVehicle) {
foreach ($dataVehicle as $nopol) {
$dataVehicle = [
"notrans" => $notrans,
"nopol" => $nopol["nopol"],
"jenis_mobil" => $nopol["vehicle"],
"jenis_member" => $nopol["member"],
"merk" => $nopol["merk"],
];
DB::table("detail_transaksi_stiker")->insert($dataVehicle);
}
} else {
return 0;
if (!empty($dataVehicle)) {
foreach ($dataVehicle as &$vehicle) {
$vehicle["notrans"] = $newTrans;
}
if ($dataCard) {
foreach ($dataCard as $cardNumber) {
$dataCard = [
"notrans" => $noid,
"no_card" => $cardNumber["nocard"],
"no_urut" => $cardNumber["nourut"],
];
DB::table("card_member")->insert($dataCard);
}
} else {
return 0;
}
DB::table("indexnum")
->where("nama", "sticker")
->update(["value" => DB::raw("lpad(to_number(value,'9999')+1)::text, 4, '0')")]);
DB::table("indexnum")
->where("nama", "identitas")
->update(["value" => DB::raw("lpad(to_number(value,'9999')+1)::text, 4, '0')")]);
$response = true;
$msg = "Data berhasil di simpan";
} catch (Exception $e) {
$response = false;
$msg = "Gagal menyimpan data " . $e->getMessage() . $e->getLine();
}
return response()->json(["response" => $response, "pesan" => $msg]);
if (!empty($dataCard)) {
foreach ($dataCard as &$cardNumber) {
$cardNumber["notrans"] = $newID;
}
}
$createData = $makeStiker->stikerCreate(
[
"dataSticker" => $dataStiker,
"dataVehicle" => $dataVehicle ?? null,
"dataCard" => $dataCard ?? null,
],
$awal,
$akhir,
);
Log::info("Status penyimpanan : " . $createData);
// try {
// $dataStiker = [
// "jenis_transaksi" => $dataStiker["jenis_transaksi"], // 0 = transaksi baru , 1 = perpanjangan
// "notrans" => $notrans,
// "no_id" => $noid,
// "nama" => $dataStiker["nama"],
// "alamat" => $dataStiker["address"] ?? "",
// "telepon" => $dataStiker["phone"] ?? "",
// "unit_kerja" => $dataStiker["depart"],
// "jenis_stiker" => $dataStiker["member"],
// "awal" => $awal,
// "akhir" => $akhir,
// "harga" => $dataStiker["harga"] ?? 0,
// "keterangan" => $dataStiker["note"] ?? "",
// "tanggal" => $dateNow,
// "operator" => $user->nomer,
// ];
// DB::table("transaksi_stiker")->insert($dataStiker);
// if ($dataVehicle) {
// foreach ($dataVehicle as $nopol) {
// $dataVehicle = [
// "notrans" => $notrans,
// "nopol" => $nopol["nopol"],
// "jenis_mobil" => $nopol["vehicle"],
// "jenis_member" => $nopol["member"],
// "merk" => $nopol["merk"],
// ];
// DB::table("detail_transaksi_stiker")->insert($dataVehicle);
// }
// } else {
// return 0;
// }
// if ($dataCard) {
// foreach ($dataCard as $cardNumber) {
// $dataCard = [
// "notrans" => $noid,
// "no_card" => $cardNumber["nocard"],
// "no_urut" => $cardNumber["nourut"],
// ];
// DB::table("card_member")->insert($dataCard);
// }
// } else {
// return 0;
// }
// DB::table("indexnum")
// ->where("nama", "sticker")
// ->update(["value" => DB::raw("lpad(to_number(value,'9999')+1)::text, 4, '0')")]);
// DB::table("indexnum")
// ->where("nama", "identitas")
// ->update(["value" => DB::raw("lpad(to_number(value,'9999')+1)::text, 4, '0')")]);
// $response = true;
// $msg = "Data berhasil di simpan";
// } catch (Exception $e) {
// $response = false;
// $msg = "Gagal menyimpan data " . $e->getMessage() . $e->getLine();
// }
return $createData;
// return response()->json([
// // "response" => $response,
// "response" => $createData,
// "pesan" => $createData,
// ]);
}
/**
@@ -247,8 +339,9 @@ public function store(Request $request)
public function show($id)
{
Log::info("Data yang diterima : " . json_encode($id));
$dataStiker = StikerTrans::with("stiker_details.vehicle", "memberCard")
->select(
$dataStiker = StikerTrans
// with("stiker_details.vehicle", "memberCard")
::select(
"transaksi_stiker.notrans",
"transaksi_stiker.nama",
"transaksi_stiker.alamat",
@@ -258,13 +351,31 @@ public function show($id)
"transaksi_stiker.jenis_langganan",
"transaksi_stiker.unit_kerja",
"transaksi_stiker.no_id",
"transaksi_stiker.harga",
"jl.nama as jmember",
"sk.nama as dept",
// "detail_transaksi_stiker.nama",
// "detail_transaksi_stiker.tarif",
)
->leftJoin("jenis_langganan as jl", "jl.id", "=", "transaksi_stiker.jenis_langganan")
->leftJoin("stasiunkerja as sk", "sk.kode", "=", "transaksi_stiker.unit_kerja")
->where("notrans", "like", "%" . $id . "%")
->first();
$vehicleDetails = StikerTransDetail::query()
->from("detail_transaksi_stiker as dts")
->select("jm.nama as vehicle", "ts.tarif", "dts.*")
->leftJoin("jenis_mobil as jm", "dts.jenis_mobil", "=", "jm.id")
->leftJoin("tarif_stiker as ts", function ($join) {
$join->on("dts.jenis_member", "=", "ts.jenis_langganan")->on("dts.jenis_mobil", "=", "ts.id_mobil");
})
->where("notrans", $dataStiker->notrans)
->get();
$cardMember = MemberCard::where("notrans", $dataStiker->no_id)->get();
$dataStiker["stiker_details"] = $vehicleDetails;
$dataStiker["memberCard"] = $cardMember;
// $dataStiker = DB::table('transaksi_stiker as ts')
// ->leftjoin('detail_transaksi_stiker as dts','dts.notrans','=','ts.notrans')
// ->leftJoin('jenis_langganan as jl','jl.id','=','ts.jenis_langganan')
@@ -4,6 +4,8 @@
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Symfony\Component\HttpFoundation\StreamedResponse;
class TransaksiParkirController extends Controller
{
@@ -17,6 +19,118 @@ public function index()
return view ('operasional.transaksi-parkir');
}
/**
* Data transaksi parkir dengan filter pencarian.
*
* Filter (semua opsional):
* - field: id | no_pol | no_barcode, + q: kata kunci
* - tgl_awal / tgl_akhir (Y-m-d): periode kolom tanggal
* - status_kendaraan: 1 = masuk, 0 = keluar
* - status_transaksi: 0 = casual, 3 = member, 32 = denda
* - export=csv: unduh hasil filter sebagai CSV
*/
public function data(Request $request)
{
$request->validate([
'field' => 'nullable|in:id,no_pol,no_barcode',
'q' => 'nullable|string|max:100',
'tgl_awal' => 'nullable|date_format:Y-m-d',
'tgl_akhir' => 'nullable|date_format:Y-m-d|after_or_equal:tgl_awal',
'status_kendaraan' => 'nullable|in:0,1',
'status_transaksi' => 'nullable|in:0,3,32',
'per_page' => 'nullable|integer|min:1|max:500',
]);
$query = $this->filteredQuery($request);
if ($request->query('export') === 'csv') {
return $this->exportCsv($query);
}
$perPage = (int) $request->input('per_page', 50);
$rows = $query->paginate($perPage);
return response()->json([
'status' => true,
'data' => $rows->items(),
'meta' => [
'current_page' => $rows->currentPage(),
'per_page' => $rows->perPage(),
'total' => $rows->total(),
'last_page' => $rows->lastPage(),
],
]);
}
protected function filteredQuery(Request $request)
{
$query = DB::table('transaksi_parkir as tp')
->leftJoin('jenis_mobil as jm', 'jm.id', '=', 'tp.id_kendaraan')
->select(
'tp.id',
'tp.no_pol',
'tp.no_barcode',
'tp.id_kendaraan',
'jm.nama as nama_kendaraan',
'tp.status',
'tp.status_transaksi',
'tp.waktu_masuk',
'tp.waktu_keluar',
'tp.tanggal'
);
// 1. Pencarian: id / no_pol / no_barcode
if ($request->filled('q')) {
$field = $request->input('field', 'id');
$query->where("tp.{$field}", 'ILIKE', '%' . $request->input('q') . '%');
}
// 2. Periode awal - akhir (kolom tanggal)
if ($request->filled('tgl_awal')) {
$query->whereDate('tp.tanggal', '>=', $request->input('tgl_awal'));
}
if ($request->filled('tgl_akhir')) {
$query->whereDate('tp.tanggal', '<=', $request->input('tgl_akhir'));
}
// 3. Status kendaraan: 1 = masuk, 0 = keluar
if ($request->filled('status_kendaraan')) {
$query->where('tp.status', (int) $request->input('status_kendaraan'));
}
// 4. Status transaksi: 0 = casual, 3 = member, 32 = denda
if ($request->filled('status_transaksi')) {
$query->where('tp.status_transaksi', (int) $request->input('status_transaksi'));
}
return $query->orderBy('tp.tanggal', 'desc');
}
protected function exportCsv($query): StreamedResponse
{
$filename = 'transaksi-parkir-' . now()->format('Ymd-His') . '.csv';
return response()->streamDownload(function () use ($query) {
$out = fopen('php://output', 'w');
fputcsv($out, ['ID', 'No. Pol', 'Barcode', 'Kendaraan', 'Status Kendaraan', 'Status Transaksi', 'Waktu Masuk', 'Waktu Keluar']);
$query->chunk(1000, function ($rows) use ($out) {
foreach ($rows as $r) {
fputcsv($out, [
$r->id,
$r->no_pol,
$r->no_barcode,
trim(($r->id_kendaraan ?? '') . ' ' . ($r->nama_kendaraan ?? '')),
$r->status,
$r->status_transaksi,
$r->waktu_masuk,
$r->waktu_keluar,
]);
}
});
fclose($out);
}, $filename, ['Content-Type' => 'text/csv']);
}
/**
* Show the form for creating a new resource.
*
@@ -1,999 +0,0 @@
<?php
namespace App\Http\Controllers\Parking;
use App\Http\Controllers\Controller;
use App\Models\TransaksiParkir;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
class ReportTransaksiController extends Controller
{
public function byGate()
{
return view("report.by-gate");
}
// private function transaksiParkir($isMirror)
// {
// $mirror = DB::table('parkir_transaksi')
// $query = DB::table('transaksi_parkir');
// return $table;
// }
public function gateData(Request $request)
{
Log::info($request->all());
$awal = $request->tanggal_mulai;
$akhir = $request->tanggal_selesai;
$isShift = $request->shift === "on";
$dateBy = $isShift ? "pklogin" : "waktu_keluar";
$paymentMethod = $request->payment_method === "null" ? null : $request->payment_method;
// 🔹 Base select
$select = [
"np.nama as gate",
"tp.id_pintu_keluar",
"p.nama as petugas",
"tp.id_op_keluar",
"jm.nama as kendaraan",
"tp.status_transaksi",
DB::raw("count(*) as jumlah_transaksi"),
DB::raw("sum(tp.bayar_keluar) as income_transaksi"),
];
// 🔹 Tambah shift kalau aktif
if ($isShift) {
$select[] = "tp.id_shift_keluar";
}
// 🔹 Base group
$groupBy = ["tp.id_pintu_keluar", "np.nama", "p.nama", "tp.id_op_keluar", "jm.nama", "tp.status_transaksi"];
if ($isShift) {
$groupBy[] = "tp.id_shift_keluar";
}
$query = DB::table("transaksi_parkir as tp")
->leftJoin("pegawai as p", "p.nomer", "=", "tp.id_op_keluar")
->leftJoin("nama_pos as np", "np.id", "=", "tp.id_pintu_keluar")
->leftJoin("jenis_mobil as jm", "jm.id", "=", "tp.id_kendaraan")
->select($select)
// 🔹 Filter tanggal (dynamic field)
->where("tp.status", 0)
->whereBetween($dateBy, [$awal . " 00:00:00", $akhir . " 23:59:59"])
// // 🔹 STATUS
// ->when($request->status_transaksi, fn($q, $v) =>
// $q->where('tp.status_transaksi', $v)
// )
// 🔹 PINTU
->when($request->id_pintu_keluar, fn($q, $v) => $q->whereIn("tp.id_pintu_keluar", (array) $v))
// 🔹 Status Transaksi
// ->when($request->status_transaksi, function ($q) use ($request) {
->when(isset($request->status_transaksi), function ($q) use ($request) {
return match ($request->status_transaksi) {
// '0' => $q->whereNotIn('tp.status_transaksi', ['3','-1'])->whereNotNull('alasan'),
"0" => $q->where("tp.status_transaksi", "0")->whereNull("alasan"),
"3" => $q->where("tp.status_transaksi", "3")->whereNull("alasan"),
"-1" => $q->where("tp.status_transaksi", "-1")->whereNotNull("alasan"),
"null" => $q->whereNull("alasan"),
};
})
// 🔹 CARA BAYAR
->when($request->cara_bayar, function ($q) use ($request) {
return match ($request->cara_bayar) {
"cash" => $q->where("tp.cara_bayar", "!=", 3),
"cashless" => $q->where("tp.cara_bayar", 3),
default => $q,
};
})
->when($paymentMethod, function ($q) use ($paymentMethod) {
return $q->where("tp.rep_bank", $paymentMethod);
// return match ($request->payment_method) {
// 2 => $q->where('tp.rep_bank', 2),
// 3 => $q->where('tp.rep_bank', 3),
// 4 => $q->where('tp.rep_bank', 4),
// 5 => $q->where('tp.rep_bank', 5),
// 9 => $q->where('tp.rep_bank', 9),
// default => $q
// };
})
// // 🔹 PETUGAS
// ->when($request->id_op_keluar, fn($q, $v) =>
// $q->whereIn('tp.id_op_keluar', (array) $v)
// )
// // 🔹 KENDARAAN
// ->when($request->id_kendaraan, fn($q, $v) =>
// $q->whereIn('tp.id_kendaraan', (array) $v)
// )
->groupBy($groupBy)
->orderBy("tp.id_pintu_keluar")
->when($isShift, fn($q) => $q->orderBy("tp.id_shift_keluar"))
->orderBy("tp.id_op_keluar")
->orderBy("jm.nama")
->orderBy("tp.status_transaksi");
return response()->json([
"byGateData" => $query->get(),
]);
}
public function allReport()
{
return view("report.all-report");
}
public function allReportData(Request $request)
{
return response()->json([
"vehicle" => $this->vehicleReport($request),
"officer" => $this->reportOfficer($request),
"payment" => $this->paymentType($request),
]);
}
public function vehicleReport(Request $request)
{
Log::info("== allReportData START ==");
Log::info($request->harian);
Log::info($request->tanggal);
$selectDate = $request->tanggal;
$start = microtime(true);
$harian = $request->harian ?? 1;
$dateNow = "2026-01-25";
$startDate = $selectDate ? $selectDate : $dateNow;
$endDate = $selectDate ? $selectDate : $dateNow;
Log::info("Tanggal laporan", [
"start" => $startDate,
"end" => $endDate,
]);
// =========================
// QUERY UTAMA (LEFT JOIN)
// =========================
Log::info("Query transaksi dimulai");
// $dateColumn = $harian == 1
// ? 'tp.waktu_keluar'
// : 'tp.pklogin';
if ($harian == 1) {
$isReport = "harian";
// $dateColumn = ["tp.waktu_keluar"];
$dateColumn = ["tp.waktu_masuk", "tp.waktu_keluar"];
} else {
$isReport = "shift";
// $dateColumn = ["tp.pklogin"];
$dateColumn = ["tp.pmlogin", "tp.pklogin"];
}
$transactions = DB::table("transaksi_parkir as tp")
->leftJoin("jenis_mobil as jm", "jm.id", "=", "tp.id_kendaraan")
->leftJoin("pegawai as pm", "pm.nomer", "=", "tp.id_op_masuk")
->leftJoin("pegawai as pk", "pk.nomer", "=", "tp.id_op_keluar")
->where(function ($q) use ($dateColumn, $startDate, $endDate, $selectDate) {
$q->whereBetween($dateColumn[0], [$startDate . " 00:00:00", $endDate . " 23:59:59"])->orWhereBetween(
$dateColumn[0],
[$startDate . " 00:00:00", $endDate . " 23:59:59"],
);
// $q->whereRaw('DATE(tp.waktu_masuk) = ?', [$selectDate])
// ->orWhereRaw('DATE(tp.waktu_keluar) = ?', [$selectDate]);
})
// ->whereRaw("DATE($dateColumn) = ?", [$dateNow])
// ->whereBetween($dateColumn, [$startDate, $endDate])
->select(
"tp.id",
"jm.nama as jenis_mobil",
"tp.id_kendaraan",
"pm.nama as kasir_masuk",
"pk.nama as kasir_keluar",
"tp.id_op_masuk",
"tp.waktu_masuk",
"tp.waktu_keluar",
"tp.status",
"tp.bayar_masuk",
"tp.bayar_keluar",
"tp.status_transaksi",
"tp.cara_bayar",
)
->get();
Log::info("Query transaksi selesai", [
"rows" => $transactions->count(),
"query_time_ms" => round((microtime(true) - $start) * 1000, 2),
]);
// =========================
// REKAP PER KENDARAAN
// =========================
Log::info("Rekap kendaraan dimulai");
$tunai = $transactions
->sortBy("id_kendaraan")
->groupBy("id_kendaraan")
->map(function ($items, $idKendaraan) use ($startDate, $endDate) {
$start = $startDate . " 00:00:00";
$end = $endDate . " 00:00:00";
// ======================
// PISAH MASUK & KELUAR
// ======================
// $masuk = $items;
$masuk = $items->filter(fn($row) => in_array(data_get($row, "cara_bayar"), [null, 0, "0"], true));
// $masuk = $items->where("status", 1);
// ->whereBetween("waktu_masuk", [$startDate . " 00:00:00", $endDate . " 23:59:59"]);
// ->filter(function ($item) use ($start, $end) {
// $waktuMasuk = $item->waktu_masuk;
// $pmLogin = $item->pmlogin ?? null;
// $inWaktuMasuk = $waktuMasuk && $waktuMasuk >= $start && $waktuMasuk <= $end;
// $inPmMasuk = $pmLogin && $pmLogin >= $start && $pmLogin <= $end;
// return $inWaktuMasuk || $inPmMasuk;
// });
// $keluar = $items->where('status', 0);
$keluar = $items->filter(fn($r) => (int) $r->status === 0);
// $tunai = $keluar->where('cara_bayar', '!=', 3);
$tunai = $keluar->filter(fn($row) => in_array(data_get($row, "cara_bayar"), [null, 0, "0"], true));
// ======================
// MASUK
// ======================
$masukCasual = $masuk->where("status_transaksi", "0");
$masukMember = $masuk->where("status_transaksi", "3");
// ======================
// KELUAR
// ======================
// $keluarCasual = $tunai->where('status_transaksi', '0');
// $keluarMember = $tunai->where('status_transaksi', '3');
// $keluarLost = $tunai->where('status_transaksi', '32');
$keluarCasual = $tunai->filter(
fn($r) => (string) data_get($r, "status_transaksi") === "0" && data_get($r, "id_op_masuk") !== null,
);
$keluarMember = $tunai->filter(fn($r) => (string) data_get($r, "status_transaksi") === "3");
$keluarLost = $tunai->filter(fn($r) => (string) data_get($r, "status_transaksi") === "32");
$keluarManual = $tunai->filter(fn($r) => data_get($r, "id_op_masuk") === null);
$keluarMasalah = $tunai->filter(fn($r) => (string) data_get($r, "status_transaksi") === "-1");
// ======================
// PEMBAYARAN (KELUAR)
// ======================
// $nonTunai = $keluar->where('cara_bayar', 3);
// $tunai = $keluar->where('cara_bayar', '!=', 3);
$totalCash =
$keluarCasual->sum("bayar_keluar") +
$keluarLost->sum("bayar_keluar") +
$keluarMember->sum("bayar_keluar") +
$keluarManual->sum("bayar_keluar");
return [
"id_kendaraan" => $idKendaraan,
"jenis_mobil" => $items->first()->jenis_mobil,
"total" => $items->count(),
"tunaiOut" => $tunai->count(),
// ========= MASUK =========
"masuk" => [
"casual" => [
"jumlah" => $masuk->count(),
"income" => $masukCasual->sum("bayar_masuk"),
],
"member" => [
"jumlah" => $masukMember->count(),
"income" => $masukMember->sum("bayar_masuk"),
],
],
// ========= KELUAR =========
"keluar" => [
"casual" => [
"jumlah" => $keluarCasual->count(),
"income" => $keluarCasual->sum("bayar_keluar"),
],
"lost" => [
"jumlah" => $keluarLost->count(),
"income" => $keluarLost->sum("bayar_keluar"),
],
"member" => [
"jumlah" => $keluarMember->count(),
"income" => $keluarMember->sum("bayar_keluar"),
],
"manual" => [
"jumlah" => $keluarManual->count(),
"income" => $keluarManual->sum("bayar_keluar"),
],
"masalah" => [
"jumlah" => $keluarMasalah->count(),
"income" => $keluarMasalah->sum("bayar_keluar"),
],
],
"totalCash" => $totalCash,
];
})
->values();
$cashless = $transactions
->sortBy("id_kendaraan")
->groupBy("id_kendaraan")
->map(function ($items, $idKendaraan) {
// ======================
// PISAH MASUK & KELUAR
// ======================
// $masuk = $items->where("status", 1);
$masuk = $items->filter(fn($row) => in_array(data_get($row, "cara_bayar"), [null, 0, "0"], true));
// $keluar = $items->where('status', 0);
// $nonTunai = $keluar->where('cara_bayar', 3);
$keluar = $items->filter(fn($r) => (int) $r->status === 0);
// $tunai = $keluar->where('cara_bayar', '!=', 3);
$nonTunai = $keluar->filter(fn($row) => (string) data_get($row, "cara_bayar") === "3");
// ======================
// MASUK
// ======================
$masukCasual = $masuk;
$masukMember = $masuk->where("status_transaksi", "3");
// ======================
// KELUAR
// ======================
// $keluarCasual = $nonTunai->where('status_transaksi', '0');
// $keluarMember = $nonTunai->where('status_transaksi', '3');
// $keluarLost = $nonTunai->where('status_transaksi', '32');
$keluarCasual = $nonTunai->filter(
fn($r) => (string) data_get($r, "status_transaksi") === "0" && data_get($r, "id_op_masuk") !== null,
);
$keluarMember = $nonTunai->filter(fn($r) => (string) data_get($r, "status_transaksi") === "3");
$keluarLost = $nonTunai->filter(fn($r) => (string) data_get($r, "status_transaksi") === "32");
$keluarManual = $nonTunai->filter(fn($r) => data_get($r, "id_op_masuk") === null);
$totalCashless =
$keluarCasual->sum("bayar_keluar") +
$keluarLost->sum("bayar_keluar") +
$keluarMember->sum("bayar_keluar") +
$keluarManual->sum("bayar_keluar");
// ======================
// PEMBAYARAN (KELUAR)
// ======================
return [
"id_kendaraan" => $idKendaraan,
"jenis_mobil" => $items->first()->jenis_mobil,
"total" => $items->count(),
"nonTunaiOut" => $nonTunai->count(),
// ========= MASUK =========
"masuk" => [
"casual" => [
"jumlah" => $masuk->count(),
"income" => $masukCasual->sum("bayar_masuk"),
],
"member" => [
"jumlah" => $masukMember->count(),
"income" => $masukMember->sum("bayar_masuk"),
],
],
// ========= KELUAR =========
"keluar" => [
"casual" => [
"jumlah" => $keluarCasual->count(),
"income" => $keluarCasual->sum("bayar_keluar"),
],
"lost" => [
"jumlah" => $keluarLost->count(),
"income" => $keluarLost->sum("bayar_keluar"),
],
"member" => [
"jumlah" => $keluarMember->count(),
"income" => $keluarMember->sum("bayar_keluar"),
],
"manual" => [
"jumlah" => $keluarManual->count(),
"income" => $keluarManual->sum("bayar_keluar"),
],
],
"totalCashless" => $totalCashless,
];
})
->values();
$transactions = DB::table("transaksi_parkir as tp")
->leftJoin("jenis_mobil as jm", "jm.id", "=", "tp.id_kendaraan")
->leftJoin("pegawai as pm", "pm.nomer", "=", "tp.id_op_masuk")
->leftJoin("pegawai as pk", "pk.nomer", "=", "tp.id_op_keluar")
->whereDate("waktu_masuk", "<", $dateNow)
->select(
"tp.id_kendaraan",
"jm.nama as jenis_mobil",
DB::raw("SUM(CASE WHEN tp.status = 1 THEN 1 ELSE 0 END) as overnight"),
DB::raw("SUM(CASE WHEN tp.status = 3 THEN 1 ELSE 0 END) as onexpired"),
)
->groupBy("tp.id_kendaraan", "jm.nama")
->orderBy("tp.id_kendaraan")
// dd($transactions->toSql());
->get();
$onCheck = $transactions
// ->sortBy('id_kendaraan')
// ->groupBy('id_kendaraan')
->map(function ($items) {
// $overNight = $items->filter(fn ($r) => (int) $r->status === 1);
// $onExpired = $items->filter(fn ($r) => (int) $r->status === 3);
return [
"id_kendaraan" => $items->id_kendaraan,
"jenis_mobil" => $items->jenis_mobil,
"overNight" => (int) $items->overnight,
"onExpired" => (int) $items->onexpired,
];
})
->values();
Log::info("Rekap kendaraan selesai", [
"total_kendaraan" => $tunai->count(),
]);
Log::info("== allReportData END ==", [
"total_time_ms" => round((microtime(true) - $start) * 1000, 2),
]);
return [
// 'date' => $startDate->format('Y-m-d'),÷
"date" => $startDate,
"reportTime" => $isReport,
"tunai" => $tunai,
"nontunai" => $cashless,
"overNight" => $onCheck,
// 'transactions' => $transactions->groupBy('id_kendaraan')
];
}
// ==========###################### Begin Laporan per petugas #######################===============//
public function reportOfficer(Request $request)
{
Log::info("== Officer Report START ==");
Log::info($request->harian);
Log::info($request->tanggal);
$selectDate = $request->tanggal;
$start = microtime(true);
$harian = $request->harian ?? 1;
// $selectDate = Carbon::createFromFormat("", $tanggalRequest)->format("Y-m-d");
// $dateNow = Carbon::now()->format('Y-m-d');
$dateNow = "2026-01-25";
// $startDate = Carbon::today()->startOfDay();
// $endDate = Carbon::today()->endOfDay();
// $startDate = $selectDate . ' 00:00:00';
// $endDate = $selectDate . ' 23:59:59';
$startDate = $selectDate ? $selectDate : $dateNow;
$endDate = $selectDate ? $selectDate : $dateNow;
Log::info("Tanggal laporan", [
"start" => $startDate,
"end" => $endDate,
]);
// =========================
// QUERY UTAMA (LEFT JOIN)
// =========================
Log::info("Query transaksi dimulai");
// $dateColumn = $harian == 1
// ? 'tp.waktu_keluar'
// : 'tp.pklogin';
if ($harian == 1) {
$dateColumn = ["tp.waktu_masuk", "tp.waktu_keluar"];
$dateColumn = ["tp.waktu_keluar"];
} else {
$dateColumn = ["tp.pmlogin", "tp.pklogin"];
$dateColumn = ["tp.pklogin"];
}
$transactions = DB::table("transaksi_parkir as tp")
->leftJoin("pegawai as p", "p.nomer", "=", "tp.id_op_keluar")
// ->leftJoin("pegawai as pm", "pm.nomer", "=", "tp.id_op_masuk")
// ->leftJoin("pegawai as pk", "pk.nomer", "=", "tp.id_op_keluar")
->where(function ($q) use ($dateColumn, $startDate, $endDate, $selectDate) {
$q->whereBetween($dateColumn[0], [$startDate . " 00:00:00", $endDate . " 23:59:59"])->orWhereBetween(
$dateColumn[0],
[$startDate . " 00:00:00", $endDate . " 23:59:59"],
);
// $q->whereRaw('DATE(tp.waktu_masuk) = ?', [$selectDate])
// ->orWhereRaw('DATE(tp.waktu_keluar) = ?', [$selectDate]);
})
// ->whereNull("id_op_masuk")
// ->where("manual", 1)
// ->whereRaw("DATE($dateColumn) = ?", [$dateNow])
// ->whereBetween($dateColumn, [$startDate, $endDate])
->select(
"p.nomer as id_petugas",
"p.nama as petugas",
// "tp.id_kendaraan",
// "pm.nama as kasir_masuk",
// "pk.nama as kasir_keluar",
"tp.id_op_masuk", // ✅ ADA
"tp.id_op_keluar",
"tp.waktu_masuk",
"tp.waktu_keluar",
"tp.status",
"tp.bayar_masuk",
"tp.bayar_keluar",
"tp.status_transaksi",
"tp.cara_bayar",
)
->get();
// Log::info("Result nya : " . json_encode($transactions));
Log::info("Query transaksi selesai", [
"rows" => $transactions->count(),
"query_time_ms" => round((microtime(true) - $start) * 1000, 2),
]);
// =========================
// REKAP PER KENDARAAN
// =========================
Log::info("Rekap petugas dimulai");
$tunai = $transactions
->sortBy("petugas")
->groupBy("id_op_keluar")
->map(function ($items, $id_op_keluar) {
// ======================
// PISAH MASUK & KELUAR
// ======================
// $masuk = $items->where('status', 1);
$masuk = $items->filter(fn($row) => in_array(data_get($row, "cara_bayar"), [null, 0, "0"], true));
// $keluar = $items->where('status', 0);
$keluar = $items->filter(fn($r) => (int) $r->status === 0);
// $tunai = $keluar->where('cara_bayar', '!=', 3);
// ======================
// MASUK
// ======================
// $masukCasual = $masuk->where('status_transaksi', '0');
// $masukMember = $masuk->where('status_transaksi', '3');
// ======================
// KELUAR
// ======================
// $keluarCasual = $tunai->where('status_transaksi', '0');
// $keluarMember = $tunai->where('status_transaksi', '3');
// $keluarLost = $tunai->where('status_transaksi', '32');
$tunai = $keluar->filter(fn($row) => in_array(data_get($row, "cara_bayar"), [null, 0, "0"], true));
$keluarCasual = $tunai->filter(
fn($r) => (string) data_get($r, "status_transaksi") === "0" && data_get($r, "id_op_masuk") !== null,
);
$keluarMember = $tunai->filter(fn($r) => (string) data_get($r, "status_transaksi") === "3");
$keluarLost = $tunai->filter(fn($r) => (string) data_get($r, "status_transaksi") === "32");
$keluarManual = $tunai->filter(fn($r) => data_get($r, "id_op_masuk") === null);
$keluarMasalah = $tunai->filter(fn($r) => (string) data_get($r, "status_transaksi") === "-1");
// ======================
// PEMBAYARAN (KELUAR)
// ======================
// $nonTunai = $keluar->where('cara_bayar', 3);
// $tunai = $keluar->where('cara_bayar', '!=', 3);
$totalCash =
$keluarCasual->sum("bayar_keluar") +
$keluarLost->sum("bayar_keluar") +
$keluarMember->sum("bayar_keluar") +
$keluarManual->sum("bayar_keluar");
Log::info("Transaksi tunai : ");
return [
"id_petugas" => $id_op_keluar,
"petugas" => $items->first()->petugas,
"total" => 0,
"tunaiOut" => $tunai->count(),
// ========= MASUK =========
"masuk" => [
"casual" => [
"jumlah" => 0,
"income" => $masuk->sum("bayar_masuk"),
],
// 'member' => [
// 'jumlah' => $masukMember->count(),
// 'income' => $masukMember->sum('bayar_masuk'),
// ],
],
// ========= KELUAR =========
"keluar" => [
"casual" => [
"jumlah" => $keluarCasual->count(),
"income" => $keluarCasual->sum("bayar_keluar"),
],
"lost" => [
"jumlah" => $keluarLost->count(),
"income" => $keluarLost->sum("bayar_keluar"),
],
"member" => [
"jumlah" => $keluarMember->count(),
"income" => $keluarMember->sum("bayar_keluar"),
],
"manual" => [
"jumlah" => $keluarManual->count(),
"income" => $keluarManual->sum("bayar_keluar"),
],
"masalah" => [
"jumlah" => $keluarMasalah->count(),
"income" => $keluarMasalah->sum("bayar_keluar"),
],
],
"totalCash" => $totalCash,
];
})
->values();
$cashless = $transactions
->sortBy("id_op_keluar")
->groupBy("id_op_keluar")
->map(function ($items, $id_op_keluar) {
// ======================
// PISAH MASUK & KELUAR
// ======================
// $masuk = $items->where('status', 1);
$masuk = $items->filter(fn($row) => in_array(data_get($row, "cara_bayar"), [null, 0, "0"], true));
// $keluar = $items->where('status', 0);
// $nonTunai = $keluar->where('cara_bayar', 3);
$keluar = $items->filter(fn($r) => (int) $r->status === 0);
// $tunai = $keluar->where('cara_bayar', '!=', 3);
$nonTunai = $keluar->filter(fn($row) => (string) data_get($row, "cara_bayar") === "3");
// ======================
// MASUK
// ======================
// $masukCasual = $masuk->where('status_transaksi', '0');
// $masukMember = $masuk->where('status_transaksi', '3');
// ======================
// KELUAR
// ======================
// $keluarCasual = $nonTunai->where('status_transaksi', '0');
// $keluarMember = $nonTunai->where('status_transaksi', '3');
// $keluarLost = $nonTunai->where('status_transaksi', '32');
$keluarCasual = $nonTunai->filter(
fn($r) => (string) data_get($r, "status_transaksi") === "0" && data_get($r, "id_op_masuk") !== null,
);
$keluarMember = $nonTunai->filter(fn($r) => (string) data_get($r, "status_transaksi") === "3");
$keluarLost = $nonTunai->filter(fn($r) => (string) data_get($r, "status_transaksi") === "32");
$keluarManual = $nonTunai->filter(fn($r) => data_get($r, "id_op_masuk") === null);
$totalCashless =
$keluarCasual->sum("bayar_keluar") +
$keluarLost->sum("bayar_keluar") +
$keluarMember->sum("bayar_keluar") +
$keluarManual->sum("bayar_keluar");
// ======================
// PEMBAYARAN (KELUAR)
// ======================
return [
"id_petugas" => $id_op_keluar,
"petugas" => $items->first()->petugas,
"total" => 0,
"nonTunaiOut" => $nonTunai->count(),
// ========= MASUK =========
"masuk" => [
"casual" => [
"jumlah" => 0,
"income" => $masuk->sum("bayar_masuk"),
],
"member" => [
"jumlah" => $masuk->count(),
"income" => $masuk->sum("bayar_masuk"),
],
],
// ========= KELUAR =========
"keluar" => [
"casual" => [
"jumlah" => $keluarCasual->count(),
"income" => $keluarCasual->sum("bayar_keluar"),
],
"lost" => [
"jumlah" => $keluarLost->count(),
"income" => $keluarLost->sum("bayar_keluar"),
],
"member" => [
"jumlah" => $keluarMember->count(),
"income" => $keluarMember->sum("bayar_keluar"),
],
"manual" => [
"jumlah" => $keluarManual->count(),
"income" => $keluarManual->sum("bayar_keluar"),
],
],
"totalCashless" => $totalCashless,
];
})
->values();
// $transactions = DB::table("transaksi_parkir as tp")
// ->leftJoin("pegawai as p", "p.nomer", "=", "tp.id_op_keluar")
// ->leftJoin("pegawai as pm", "pm.nomer", "=", "tp.id_op_masuk")
// ->leftJoin("pegawai as pk", "pk.nomer", "=", "tp.id_op_keluar")
// ->whereDate("waktu_masuk", "<", $dateNow)
// ->select(
// "tp.id_kendaraan",
// "p.nama as jenis_mobil",
// "tp.id_op_keluar",
// "p.nama as petugas",
// DB::raw("SUM(CASE WHEN tp.status = 1 THEN 1 ELSE 0 END) as overnight"),
// DB::raw("SUM(CASE WHEN tp.status = 3 THEN 1 ELSE 0 END) as onexpired"),
// )
// ->groupBy("tp.id_op_keluar", "petugas")
// ->orderBy("tp.id_op_keluar", "asc")
// ->groupBy("p.nomer", "p.nama")
// ->orderBy("p.nomer")
// dd($transactions->toSql());
// ->get();
// $onCheck = $transactions
// ->sortBy('id_kendaraan')
// ->groupBy('id_kendaraan')
// ->map(function ($items) {
// $overNight = $items->filter(fn ($r) => (int) $r->status === 1);
// $onExpired = $items->filter(fn ($r) => (int) $r->status === 3);
// return [
// "id_petugas" => $items->id_op_keluar,
// "petugas" => $items->petugas,
// "overNight" => (int) $items->overnight,
// "onExpired" => (int) $items->onexpired,
// ];
// })
// ->values();
Log::info("Rekap kendaraan selesai", [
"total_kendaraan" => $tunai->count(),
]);
Log::info("== allReportData END ==", [
"total_time_ms" => round((microtime(true) - $start) * 1000, 2),
]);
return [
"date" => $startDate,
"tunai" => $tunai,
"nontunai" => $cashless,
];
}
// ========== End Laporan per petugas ===============///
// ==========###################### Begin Laporan per petugas #######################===============//
public function paymentType(Request $request)
{
Log::info("== Officer Report START ==");
Log::info($request->harian);
Log::info($request->tanggal);
$selectDate = $request->tanggal;
$start = microtime(true);
$harian = $request->harian ?? 1;
$dateNow = "2026-01-25";
$startDate = $selectDate ? $selectDate : $dateNow;
$endDate = $selectDate ? $selectDate : $dateNow;
Log::info("Tanggal laporan", [
"start" => $startDate,
"end" => $endDate,
]);
// ============= QUERY UTAMA (LEFT JOIN) =========================
Log::info("Query transaksi dimulai");
if ($harian == 1) {
// $dateColumn = ["tp.waktu_keluar"];
$dateColumn = ["tp.waktu_masuk", "tp.waktu_keluar"];
} else {
// $dateColumn = ["tp.pklogin"];
$dateColumn = ["tp.pmlogin", "tp.pklogin"];
}
$transactions = DB::table("transaksi_parkir as tp")
// ->leftJoin("pegawai as p", "p.nomer", "=", "tp.id_op_keluar")
// ->leftJoin("pegawai as pm", "pm.nomer", "=", "tp.id_op_masuk")
// ->leftJoin("pegawai as pk", "pk.nomer", "=", "tp.id_op_keluar")
->where(function ($q) use ($dateColumn, $startDate, $endDate, $selectDate) {
$q->whereBetween($dateColumn[0], [$startDate . " 00:00:00", $endDate . " 23:59:59"])->orWhereBetween(
$dateColumn[0],
[$startDate . " 00:00:00", $endDate . " 23:59:59"],
);
// $q->whereRaw('DATE(tp.waktu_masuk) = ?', [$selectDate])
// ->orWhereRaw('DATE(tp.waktu_keluar) = ?', [$selectDate]);
})
// ->whereRaw("DATE($dateColumn) = ?", [$dateNow])
// ->whereBetween($dateColumn, [$startDate, $endDate])
->select(
"rep_bank as bankType",
// "p.nomer as id_petugas",
// "p.nama as petugas",
// "tp.id_kendaraan",
// "pm.nama as kasir_masuk",
// "pk.nama as kasir_keluar",
"tp.id_op_masuk", // ✅ ADA
"tp.id_op_keluar",
"tp.waktu_masuk",
"tp.waktu_keluar",
"tp.status",
"tp.bayar_masuk",
"tp.bayar_keluar",
"tp.status_transaksi",
"tp.cara_bayar",
)
->get();
Log::info("Query transaksi selesai", [
"rows" => $transactions->count(),
"query_time_ms" => round((microtime(true) - $start) * 1000, 2),
]);
Log::info("Rekap payment dimulai");
$tunai = $transactions
->sortBy("bankType")
->groupBy("bankType")
->map(function ($items, $bankType) {
$keluar = $items->filter(fn($r) => (int) $r->status === 0);
$tunai = $keluar->filter(fn($row) => in_array(data_get($row, "cara_bayar"), [null, 0, "0"], true));
$keluarCasual = $tunai->filter(
fn($r) => (string) data_get($r, "status_transaksi") === "0" && data_get($r, "id_op_masuk") !== null,
);
$keluarMember = $tunai->filter(fn($r) => (string) data_get($r, "status_transaksi") === "3");
$keluarLost = $tunai->filter(fn($r) => (string) data_get($r, "status_transaksi") === "32");
$keluarManual = $tunai->filter(fn($r) => data_get($r, "id_op_masuk") === null);
$keluarMasalah = $tunai->filter(fn($r) => (string) data_get($r, "status_transaksi") === "-1");
$totalCash =
$keluarCasual->sum("bayar_keluar") +
$keluarLost->sum("bayar_keluar") +
$keluarMember->sum("bayar_keluar") +
$keluarManual->sum("bayar_keluar");
Log::info("Transaksi tunai : ");
return [
"typePayment" => $bankType,
"petugas" => $items->first()->bankType,
"total" => $items->count(),
"tunaiOut" => $tunai->count(),
"masuk" => [
"casual" => [
"jumlah" => 0,
"income" => 0,
],
],
"keluar" => [
"casual" => [
"jumlah" => $keluarCasual->count(),
"income" => $keluarCasual->sum("bayar_keluar"),
],
"lost" => [
"jumlah" => $keluarLost->count(),
"income" => $keluarLost->sum("bayar_keluar"),
],
"member" => [
"jumlah" => $keluarMember->count(),
"income" => $keluarMember->sum("bayar_keluar"),
],
"manual" => [
"jumlah" => $keluarManual->count(),
"income" => $keluarManual->sum("bayar_keluar"),
],
"masalah" => [
"jumlah" => $keluarMasalah->count(),
"income" => $keluarMasalah->sum("bayar_keluar"),
],
],
"totalCash" => $totalCash,
];
})
->values();
$cashless = $transactions
->sortBy("bankType")
->groupBy("bankType")
->map(function ($items, $bankType) {
$keluar = $items->filter(fn($r) => (int) $r->status === 0);
$nonTunai = $keluar->filter(fn($row) => (string) data_get($row, "cara_bayar") === "3");
$keluarCasual = $nonTunai->filter(
fn($r) => (string) data_get($r, "status_transaksi") === "0" && data_get($r, "id_op_masuk") !== null,
);
$keluarMember = $nonTunai->filter(fn($r) => (string) data_get($r, "status_transaksi") === "3");
$keluarLost = $nonTunai->filter(fn($r) => (string) data_get($r, "status_transaksi") === "32");
$keluarManual = $nonTunai->filter(fn($r) => data_get($r, "id_op_masuk") === null);
$totalCashless =
$keluarCasual->sum("bayar_keluar") +
$keluarLost->sum("bayar_keluar") +
$keluarMember->sum("bayar_keluar") +
$keluarManual->sum("bayar_keluar");
// ======================
// PEMBAYARAN (KELUAR)
// ======================
return [
"typePayment" => $bankType,
"petugas" => $items->first()->bankType,
"total" => $items->count(),
"nonTunaiOut" => $nonTunai->count(),
"masuk" => [
"casual" => [
"jumlah" => 0,
"income" => 0,
],
],
"keluar" => [
"casual" => [
"jumlah" => $keluarCasual->count(),
"income" => $keluarCasual->sum("bayar_keluar"),
],
"lost" => [
"jumlah" => $keluarLost->count(),
"income" => $keluarLost->sum("bayar_keluar"),
],
"member" => [
"jumlah" => $keluarMember->count(),
"income" => $keluarMember->sum("bayar_keluar"),
],
"manual" => [
"jumlah" => $keluarManual->count(),
"income" => $keluarManual->sum("bayar_keluar"),
],
],
"totalCashless" => $totalCashless,
];
})
->values();
Log::info("Rekap kendaraan selesai", [
"total_kendaraan" => $tunai->count(),
]);
Log::info("== allReportData END ==", [
"total_time_ms" => round((microtime(true) - $start) * 1000, 2),
]);
return [
"date" => $startDate,
"tunai" => $tunai,
"nontunai" => $cashless,
];
}
// ========== End Laporan payment Type ===============///
}
@@ -0,0 +1,185 @@
<?php
namespace App\Http\Controllers\Parking\Setup\Gate;
use App\Http\Controllers\Controller;
use App\Services\Parking\NetworkService;
use App\Models\ConfigPosNetwork;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
class MasterConfigNetworkController extends Controller
{
public function index(NetworkService $dhcp)
{
$reservations = ConfigPosNetwork::orderBy("hostname")->get();
$dhcpStatus = $dhcp->status();
return view("setup.index", compact("reservations", "dhcpStatus"));
}
public function status(NetworkService $dhcp)
{
return response()->json($dhcp->status());
}
public function store(Request $request)
{
$data = $request->validate([
"hostname" => ["required", "string", "max:100", 'regex:/^[a-zA-Z0-9_-]+$/'],
"mac_address" => ["required", "string", 'regex:/^([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}$/'],
"ip_address" => ["required", "ip"],
"enabled" => ["nullable", "boolean"],
]);
$data["mac_address"] = strtoupper($data["mac_address"]);
$data["enabled"] = $request->boolean("enabled");
// Cek duplicate MAC
if (ConfigPosNetwork::where("mac_address", $data["mac_address"])->exists()) {
return response()->json(
[
"success" => false,
"message" => "MAC address already registered.",
],
422,
);
}
// Cek duplicate IP
if (ConfigPosNetwork::where("ip_address", $data["ip_address"])->exists()) {
return response()->json(
[
"success" => false,
"message" => "IP address already registered.",
],
422,
);
}
$reservation = ConfigPosNetwork::create($data);
return response()->json(
[
"success" => true,
"message" => "DHCP reservation created successfully.",
"data" => $reservation,
],
201,
);
}
public function update(Request $request, ConfigPosNetwork $reservation)
{
$data = $request->validate([
"hostname" => ["required", "string", "max:100", 'regex:/^[a-zA-Z0-9_-]+$/'],
"mac_address" => ["required", "string", 'regex:/^([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}$/'],
"ip_address" => ["required", "ip"],
"enabled" => ["nullable", "boolean"],
]);
$data["mac_address"] = strtoupper($data["mac_address"]);
$data["enabled"] = $request->boolean("enabled");
// Cek duplicate MAC,
// kecuali reservation yang sedang diedit
if (
ConfigPosNetwork::where("mac_address", $data["mac_address"])->where("id", "!=", $reservation->id)->exists()
) {
return response()->json(
[
"success" => false,
"message" => "MAC address already registered.",
],
422,
);
}
// Cek duplicate IP
if (ConfigPosNetwork::where("ip_address", $data["ip_address"])->where("id", "!=", $reservation->id)->exists()) {
return response()->json(
[
"success" => false,
"message" => "IP address already registered.",
],
422,
);
}
$reservation->update($data);
return response()->json([
"success" => true,
"message" => "DHCP reservation updated successfully.",
"data" => $reservation->fresh(),
]);
}
public function destroy(ConfigPosNetwork $reservation)
{
$reservation->delete();
return response()->json([
"success" => true,
"message" => "Reservation deleted successfully.",
]);
}
public function test(NetworkService $dhcp)
{
try {
$result = $dhcp->test();
return response()->json([
"success" => true,
"message" => "DHCP configuration is valid.",
"data" => $result,
]);
} catch (\Throwable $e) {
return response()->json(
[
"success" => false,
"message" => $e->getMessage(),
],
422,
);
}
}
public function apply(NetworkService $dhcp)
{
try {
$dhcp->apply();
return response()->json([
"success" => true,
"message" => "DHCP configuration applied successfully.",
]);
} catch (\Throwable $e) {
return response()->json(
[
"success" => false,
"message" => $e->getMessage(),
],
500,
);
}
}
public function logs(NetworkService $dhcp)
{
return response()->json([
"success" => true,
"logs" => $dhcp->logs(30),
]);
}
}
@@ -5,7 +5,6 @@
use App\Http\Controllers\Controller;
use App\Models\ConfigHardware;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
class MasterGateHardwareController extends Controller
{
@@ -48,9 +47,11 @@ public function store(Request $request)
*/
public function show($id)
{
Log::info($id);
// # ambil konfigurasi hardware berdasarkan id_pos (id pintu)
$gateDetails = ConfigHardware::where('id_pos', $id)->first();
return $gateDetails;
// # kalau belum ada datanya, kembalikan objek kosong biar form tetap kebuka
return response()->json($gateDetails ?? (object) []);
}
/**
@@ -73,8 +74,26 @@ public function edit($id)
*/
public function update(Request $request, $id)
{
Log::info($id);
Log::info($request->all());
// # hanya kolom yang terdaftar di fillable yang boleh disimpan
$allowed = (new ConfigHardware())->getFillable();
$data = $request->input('data', []);
$filtered = [];
foreach ((array) $data as $key => $value) {
if (in_array($key, $allowed, true)) {
// # ubah string kosong jadi null biar cocok dengan kolom integer
$filtered[$key] = $value === '' ? null : $value;
}
}
// # simpan (buat baru kalau id_pos belum punya baris hardware)
$hardware = ConfigHardware::updateOrCreate(['id_pos' => $id], $filtered);
return response()->json([
'success' => true,
'message' => 'Konfigurasi hardware berhasil disimpan.',
'data' => $hardware,
]);
}
/**
@@ -0,0 +1,206 @@
<?php
namespace App\Http\Controllers\Parking\Setup\Member;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use App\Models\Origin\MasterTarifStiker;
use App\Models\Origin\MasterStasiunKerja;
use App\Models\Origin\MasterJenisLangganan;
class MasterTarifStikerController extends Controller
{
/**
* Halaman utama. Data dropdown (stasiun kerja & jenis langganan)
* di-load langsung di sini biar gak perlu request tambahan pas modal dibuka.
*/
public function index()
{
$stasiunKerjaList = MasterStasiunKerja::orderBy("kode")->get(["kode", "nama"]);
$jenisLanggananList = MasterJenisLangganan::orderBy("id")->get(["id", "nama"]);
return view("Parking.setup.member.tarifstiker", compact("stasiunKerjaList", "jenisLanggananList"));
}
/**
* Ambil seluruh data tarif stiker, sekalian join nama stasiun kerja
* biar gak perlu N+1 query pas render tabel.
*/
public function data(): JsonResponse
{
$data = MasterTarifStiker::with(["stasiunKerja:kode,nama"])
->orderByDesc("tarif_id")
->get();
return response()->json([
"success" => true,
"data" => $data,
]);
}
/**
* Ambil satu data berdasarkan tarif_id.
*/
public function show(string $tarif_id): JsonResponse
{
$item = MasterTarifStiker::with(["stasiunKerja:kode,nama"])->find($tarif_id);
if (!$item) {
return response()->json(
[
"success" => false,
"message" => "Data tarif stiker tidak ditemukan.",
],
404,
);
}
return response()->json([
"success" => true,
"data" => $item,
]);
}
/**
* Simpan data tarif stiker baru.
* tarif_id tidak wajib diisi dari form — kalau kosong, di-generate
* otomatis (max(tarif_id) + 1) karena tabel ini tidak punya
* auto-increment/serial asli di database.
*/
public function store(Request $request): JsonResponse
{
$validator = Validator::make($request->all(), [
"tarif_id" => ["nullable", "integer", "unique:tarif_stiker,tarif_id"],
"id_mobil" => ["required", "string", "max:10"],
"jenis_langganan" => ["required", "string", "max:50"],
"tarif" => ["required", "numeric"],
"last_member" => ["nullable", "string", "max:5"],
"tgl_akhir" => ["nullable", "string", "max:2"],
"jenis" => ["nullable", "string", "max:30"],
"jenis_member" => ["nullable", "string", "max:50"],
"hitung_awal_bulan" => ["nullable", "integer"],
"available_online" => ["nullable", "boolean"],
"langganan" => ["nullable", "string", "max:32", "exists:stasiunkerja,kode"],
"kode_akses" => ["nullable", "string", "max:5"],
]);
if ($validator->fails()) {
return response()->json(
[
"success" => false,
"message" => "Validasi gagal.",
"errors" => $validator->errors(),
],
422,
);
}
$payload = $validator->validated();
$payload["available_online"] = $request->boolean("available_online");
// Transaksi + lock untuk menghindari race condition kalau
// ada 2 request bersamaan sama-sama generate tarif_id baru.
$item = DB::transaction(function () use ($payload) {
if (empty($payload["tarif_id"])) {
$maxId = MasterTarifStiker::lockForUpdate()->max("tarif_id");
$payload["tarif_id"] = ($maxId ?? 0) + 1;
}
return MasterTarifStiker::create($payload);
});
$item->load("stasiunKerja:kode,nama");
return response()->json(
[
"success" => true,
"message" => "Data tarif stiker berhasil ditambahkan.",
"data" => $item,
],
201,
);
}
/**
* Perbarui data tarif stiker berdasarkan tarif_id.
*/
public function update(Request $request, string $tarif_id): JsonResponse
{
$item = MasterTarifStiker::find($tarif_id);
if (!$item) {
return response()->json(
[
"success" => false,
"message" => "Data tarif stiker tidak ditemukan.",
],
404,
);
}
$validator = Validator::make($request->all(), [
"id_mobil" => ["required", "string", "max:10"],
"jenis_langganan" => ["required", "string", "max:50"],
"tarif" => ["required", "numeric"],
"last_member" => ["nullable", "string", "max:5"],
"tgl_akhir" => ["nullable", "string", "max:2"],
"jenis" => ["nullable", "string", "max:30"],
"jenis_member" => ["nullable", "string", "max:50"],
"hitung_awal_bulan" => ["nullable", "integer"],
"available_online" => ["nullable", "boolean"],
"langganan" => ["nullable", "string", "max:32", "exists:stasiunkerja,kode"],
"kode_akses" => ["nullable", "string", "max:5"],
]);
if ($validator->fails()) {
return response()->json(
[
"success" => false,
"message" => "Validasi gagal.",
"errors" => $validator->errors(),
],
422,
);
}
$payload = $validator->validated();
$payload["available_online"] = $request->boolean("available_online");
$item->update($payload);
$item->load("stasiunKerja:kode,nama");
return response()->json([
"success" => true,
"message" => "Data tarif stiker berhasil diperbarui.",
"data" => $item,
]);
}
/**
* Hapus data tarif stiker berdasarkan tarif_id.
*/
public function destroy(string $tarif_id): JsonResponse
{
$item = MasterTarifStiker::find($tarif_id);
if (!$item) {
return response()->json(
[
"success" => false,
"message" => "Data tarif stiker tidak ditemukan.",
],
404,
);
}
$item->delete();
return response()->json([
"success" => true,
"message" => "Data tarif stiker berhasil dihapus.",
]);
}
}
@@ -0,0 +1,177 @@
<?php
namespace App\Http\Controllers\Parking\Setup\Member;
use App\Http\Controllers\Controller;
use App\Models\Origin\MasterStasiunKerja;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
class StasiunKerjaController extends Controller
{
/**
* Tampilkan halaman utama (view + tabel kosong, data di-load via JS).
*/
public function index()
{
return view("Parking.setup.member.stasiunkerja");
}
/**
* Ambil seluruh data stasiun kerja dalam format JSON.
* Dipanggil via fetch() dari JS untuk mengisi tabel.
*/
public function data(): JsonResponse
{
$data = MasterStasiunKerja::orderBy("kode")->get();
return response()->json([
"success" => true,
"data" => $data,
]);
}
/**
* Ambil satu data berdasarkan kode (dipakai saat buka form edit).
*/
public function show(string $kode): JsonResponse
{
$item = MasterStasiunKerja::find($kode);
if (!$item) {
return response()->json(
[
"success" => false,
"message" => "Data stasiun kerja tidak ditemukan.",
],
404,
);
}
return response()->json([
"success" => true,
"data" => $item,
]);
}
/**
* Simpan data stasiun kerja baru.
*/
public function store(Request $request): JsonResponse
{
$validator = Validator::make($request->all(), [
"kode" => ["required", "string", "max:50", Rule::unique("stasiunkerja", "kode")],
"nama" => ["required", "string", "max:255"],
"margin" => ["nullable", "integer"],
"spv" => ["nullable", "string", "max:20"],
"target" => ["nullable", "integer"],
"id_lokasi" => ["nullable", "string", "max:10"],
"lantai" => ["nullable", "string", "max:4"],
"status" => ["nullable", "integer"],
"alamat" => ["nullable", "string", "max:255"],
"bank" => ["nullable", "string", "max:64"],
"telp" => ["nullable", "string", "max:32"],
"kode_akses" => ["nullable", "string", "max:5"],
]);
if ($validator->fails()) {
return response()->json(
[
"success" => false,
"message" => "Validasi gagal.",
"errors" => $validator->errors(),
],
422,
);
}
$item = MasterStasiunKerja::create($validator->validated());
return response()->json(
[
"success" => true,
"message" => "Data stasiun kerja berhasil ditambahkan.",
"data" => $item,
],
201,
);
}
/**
* Perbarui data stasiun kerja berdasarkan kode.
*/
public function update(Request $request, string $kode): JsonResponse
{
$item = MasterStasiunKerja::find($kode);
if (!$item) {
return response()->json(
[
"success" => false,
"message" => "Data stasiun kerja tidak ditemukan.",
],
404,
);
}
$validator = Validator::make($request->all(), [
"nama" => ["required", "string", "max:255"],
"margin" => ["nullable", "integer"],
"spv" => ["nullable", "string", "max:20"],
"target" => ["nullable", "integer"],
"id_lokasi" => ["nullable", "string", "max:10"],
"lantai" => ["nullable", "string", "max:4"],
"status" => ["nullable", "integer"],
"alamat" => ["nullable", "string", "max:255"],
"bank" => ["nullable", "string", "max:64"],
"telp" => ["nullable", "string", "max:32"],
"kode_akses" => ["nullable", "string", "max:5"],
]);
if ($validator->fails()) {
return response()->json(
[
"success" => false,
"message" => "Validasi gagal.",
"errors" => $validator->errors(),
],
422,
);
}
$item->update($validator->validated());
return response()->json([
"success" => true,
"message" => "Data stasiun kerja berhasil diperbarui.",
"data" => $item,
]);
}
/**
* Hapus data stasiun kerja berdasarkan kode.
*/
public function destroy(string $kode): JsonResponse
{
$item = MasterStasiunKerja::find($kode);
if (!$item) {
return response()->json(
[
"success" => false,
"message" => "Data stasiun kerja tidak ditemukan.",
],
404,
);
}
$item->delete();
return response()->json([
"success" => true,
"message" => "Data stasiun kerja berhasil dihapus.",
]);
}
}
@@ -4,7 +4,9 @@
use App\Http\Controllers\Controller;
use App\Models\VehicleItem;
use App\Models\MasterTarif;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class MasterVehicleController extends Controller
{
@@ -40,7 +42,38 @@ public function create()
*/
public function store(Request $request)
{
//
$request->merge([
'id' => strtoupper((string) $request->input('id')),
'short_cut' => strtoupper((string) $request->input('short_cut')),
]);
$data = $request->validate([
'id' => 'required|string|max:16|alpha_num|unique:jenis_mobil,id',
'nama' => 'required|string|max:100',
'short_cut' => 'required|string|max:16',
'tarif' => 'required|numeric|min:0',
]);
$vehicle = DB::transaction(function () use ($data) {
$vehicle = VehicleItem::create([
'id' => strtoupper($data['id']),
'nama' => $data['nama'],
'short_cut' => strtoupper($data['short_cut']),
'tanggal' => now(),
'orang' => 0,
'validasi' => 0,
]);
MasterTarif::create([
'id_mobil' => $vehicle->id,
'tarif' => $data['tarif'],
'tanggal' => now(),
]);
return $vehicle;
});
return response()->json(['success' => true, 'message' => 'Jenis kendaraan dan tarif awal berhasil ditambahkan.', 'data' => $vehicle], 201);
}
/**
@@ -51,7 +84,10 @@ public function store(Request $request)
*/
public function show($id)
{
//
$vehicle = VehicleItem::findOrFail($id);
$tarif = MasterTarif::find($id);
return response()->json(['success' => true, 'data' => $vehicle, 'tarif' => $tarif]);
}
/**
@@ -62,7 +98,7 @@ public function show($id)
*/
public function edit($id)
{
//
return response()->json(['success' => true, 'data' => VehicleItem::findOrFail($id)]);
}
/**
@@ -74,7 +110,18 @@ public function edit($id)
*/
public function update(Request $request, $id)
{
//
$data = $request->validate([
'nama' => 'required|string|max:100',
'short_cut' => 'required|string|max:16',
]);
$vehicle = VehicleItem::findOrFail($id);
$vehicle->update([
'nama' => $data['nama'],
'short_cut' => strtoupper($data['short_cut']),
]);
return response()->json(['success' => true, 'message' => 'Jenis kendaraan berhasil diperbarui.', 'data' => $vehicle]);
}
/**
@@ -85,6 +132,11 @@ public function update(Request $request, $id)
*/
public function destroy($id)
{
//
DB::transaction(function () use ($id) {
MasterTarif::where('id_mobil', $id)->delete();
VehicleItem::findOrFail($id)->delete();
});
return response()->json(['success' => true, 'message' => 'Jenis kendaraan dan tarif terkait berhasil dihapus.']);
}
}
@@ -49,12 +49,13 @@ public function store(Request $request)
*/
public function show($id)
{
// Log::info($id);
$id = str($id);
$vehicleRates = DB::table("tarif")->where("id_mobil", $id)->first();
$vehicleRates = DB::table("tarif")->where("id_mobil", (string) $id)->first();
Log::info(json_encode($vehicleRates));
return $vehicleRates;
if (!$vehicleRates) {
return response()->json(['status' => false, 'message' => 'Tarif kendaraan tidak ditemukan.'], 404);
}
return response()->json($vehicleRates);
}
/**
@@ -77,14 +78,43 @@ public function edit($id)
*/
public function update(Request $request, $id)
{
Log::info($request->all());
// $id = $request->id_mobil;
$dataQuery = MasterTarif::find($id);
try {
Log::info($request->all());
if (!$dataQuery) {
return response()->json(['status' => false, 'message' => 'Tarif kendaraan tidak ditemukan.'], 404);
}
$dataQuery->fill($request->all());
$validated = $request->validate([
'waktu_gratis' => 'nullable|integer|min:0',
'tarif_period' => 'nullable|numeric|min:0',
'frek_interval' => 'nullable|integer|min:1',
'interval' => 'nullable|integer|min:1',
'tarif_interval' => 'nullable|numeric|min:0',
'bayar_dimuka' => 'nullable|boolean',
'asuransi_incl' => 'nullable|numeric|min:0',
'frek_waktu2' => 'nullable|integer|min:1',
'waktu2' => 'nullable|integer|min:1',
'tarif2' => 'nullable|numeric|min:0',
'tarif' => 'required|numeric|min:0',
'waktu_tarif' => 'nullable|integer|min:1',
'maksimum' => 'nullable|numeric|min:0',
'maksimum_mode' => 'required|in:hour,day',
'maksimum_hour' => 'nullable|integer|min:1',
'maksimum_day_minute' => 'nullable|integer|min:0',
'denda' => 'nullable|numeric|min:0',
'denda_member' => 'nullable|integer|min:0',
'denda_only_casual' => 'nullable|boolean',
'denda_only' => 'nullable|boolean',
]);
try {
$data = collect($validated)->except(['maksimum_mode', 'maksimum_hour', 'maksimum_day_minute'])->all();
$data['time_base'] = $validated['maksimum_mode'] === 'hour' ? 1 : 0;
$data['time_base_maks'] = $validated['maksimum_mode'] === 'hour' ? $validated['maksimum_hour'] : null;
$data['min_per_hari'] = $validated['maksimum_mode'] === 'day' ? $validated['maksimum_day_minute'] : null;
$data['denda_only_casual'] = $request->boolean('denda_only_casual') ? 1 : 0;
$data['denda_only'] = $request->boolean('denda_only') ? 1 : 0;
$dataQuery->fill($data);
if (!$dataQuery->isDirty()) {
return response()->json([
@@ -92,7 +122,6 @@ public function update(Request $request, $id)
"message" => "Tidak ada perubahan data",
]);
}
Log::info("Data yang di simpan" . json_encode($dataQuery->getDirty()));
$dataQuery->save();
return response()->json([
@@ -100,10 +129,7 @@ public function update(Request $request, $id)
"message" => "Data berhasil di ubah",
]);
} catch (\Throwable $th) {
Log::info("Data yang di simpan" . json_encode($dataQuery->getDirty()));
// Log::info($request->all());
Log::error('Gagal memperbarui tarif kendaraan', ['id_mobil' => $id, 'error' => $th->getMessage()]);
return response()->json([
"status" => false,
"message" => "Gagal menyimpan data " . $th->getMessage(),
@@ -11,18 +11,31 @@ class SetupController extends Controller
{
public function index()
{
$status = [
'pgcrypto' => $this->checkPgcrypto(),
'pegawai_columns' => $this->checkPegawaiColumns(),
'users_view' => $this->checkUsersView(),
'veri_time' => Schema::hasColumn('transaksi_parkir', 'veri_time'),
];
$status = $this->status();
return view('welcome', compact('status'));
return view('welcome', ['isReady' => $this->isReady($status)]);
}
public function setup()
{
$status = $this->status();
if ($this->isReady($status)) {
return redirect()->route('login');
}
return view('setup', compact('status'));
}
public function run()
{
if ($this->isReady($this->status())) {
return response()->json([
'success' => false,
'message' => 'Setup database sudah selesai dan tidak perlu dijalankan ulang.',
], 403);
}
DB::beginTransaction();
try {
@@ -66,6 +79,18 @@ public function run()
});
}
// 5. Laravel database sessions for authenticated web requests.
if (!Schema::hasTable('sessions')) {
Schema::create('sessions', function ($table) {
$table->string('id')->primary();
$table->unsignedBigInteger('user_id')->nullable()->index();
$table->string('ip_address', 45)->nullable();
$table->text('user_agent')->nullable();
$table->longText('payload');
$table->integer('last_activity')->index();
});
}
DB::commit();
// return redirect()->back()->with('success', 'Setup berhasil dijalankan ✅');
@@ -84,6 +109,26 @@ public function run()
}
}
private function status(): array
{
return [
'pgcrypto' => $this->checkPgcrypto(),
'pegawai_columns' => $this->checkPegawaiColumns(),
'users_view' => $this->checkUsersView(),
'veri_time' => Schema::hasColumn('transaksi_parkir', 'veri_time'),
'sessions' => Schema::hasTable('sessions'),
];
}
private function isReady(array $status): bool
{
return $status['pgcrypto']
&& $status['users_view']
&& $status['veri_time']
&& $status['sessions']
&& !in_array(false, $status['pegawai_columns'], true);
}
/* =========================
Helper
========================= */
@@ -0,0 +1,165 @@
<?php
namespace App\Http\Controllers\ParkingLot;
use App\Http\Controllers\Controller;
use App\Models\LotParking\SiteParking;
use App\Models\LotParking\LotParkingLog;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\DB;
class ParkingLotComponent extends Controller
{
/**
* Halaman utama parking lot
*/
public function index()
{
$getArea = SiteParking::all(); // Mengambil semua data dari model SiteParking
$parkingDataByArea = []; // Array untuk menyimpan hasil query berdasarkan area
foreach ($getArea as $lantai) {
$spaceParking = $lantai->space_parking;
// Array untuk menyimpan data parking per lantai
$parkingData = [];
for ($lotNumber = 1; $lotNumber <= $spaceParking; $lotNumber++) {
// Melakukan query pada LotParkingLog berdasarkan area dan lot_number
$log = LotParkingLog::where("area", $lantai->sitearea_id)
->where("lot_number", $lotNumber)
->select("lot_number", "status")
->first();
// Jika data tidak ditemukan, buat object baru dengan lot_number dari pengulangan for
if (!$log) {
$log = (object) [
"lot_number" => $lotNumber,
"status" => 0,
];
}
// Menyimpan hasil query dalam array
$parkingData[] = $log;
}
// Menyimpan data parking per lantai dalam array berdasarkan area
$parkingDataByArea[] = [
"lantai" => $lantai->sitearea_id,
"data" => $parkingData,
];
}
// Melakukan dump and die untuk melihat hasil query sementara
// dd(json_encode($parkingDataByArea));
// dd($getArea->toJson());
return view("livewire.space", [
"areas" => $getArea,
"parkingDataByArea" => $parkingDataByArea,
]);
// return view("liveware.space");
}
public function getParkingData()
{
Log::info("getParkingData method called");
$getArea = SiteParking::get();
Log::info("Mendapatkan area: " . json_encode($getArea->toArray()));
$parkingDataByArea = [];
foreach ($getArea as $lantai) {
$areaName = $lantai->name;
$spaceParking = (int) $lantai->space_parking;
Log::info("Mencari lot di lantai: {$areaName}, jumlah lot: {$spaceParking}");
$parkingData = [];
for ($lotNumber = 1; $lotNumber <= $spaceParking; $lotNumber++) {
$log = LotParkingLog::where("area", $areaName)
->where("lot_number", $lotNumber)
->where("status", 1)
->select("lot_number", "status")
->orderByDesc("updated_at")
->first();
Log::info("Lot {$areaName} #{$lotNumber}: " . json_encode($log));
if (!$log) {
$log = (object) [
"lot_number" => $lotNumber,
"status" => 0,
];
}
$parkingData[] = $log;
}
$parkingDataByArea[] = [
"lantai" => $areaName,
"data" => $parkingData,
];
}
return response()->json($parkingDataByArea);
}
// public function index()
// {
// $parkingDataByArea = $this->getParkingData();
// return view("livewire.index", compact("parkingDataByArea"));
// }
/**
* Endpoint AJAX untuk refresh data parking
*/
public function data()
{
$parkingDataByArea = $this->getParkingData();
return view("livewire.partial-lot", compact("parkingDataByArea"));
}
/**
* Ambil data parking
*/
// private function getParkingData()
// {
// $getArea = SiteParking::all();
// $parkingDataByArea = [];
// foreach ($getArea as $lantai) {
// $spaceParking = $lantai->space_parking;
// $parkingData = [];
// for ($lotNumber = 1; $lotNumber <= $spaceParking; $lotNumber++) {
// $log = LotParkingLog::where("area", $lantai->sitearea_id)
// ->where("lot_number", $lotNumber)
// ->select("lot_number", "status")
// ->orderByDesc("created_at")
// ->first();
// if (!$log) {
// $log = (object) [
// "lot_number" => $lotNumber,
// "status" => 0,
// ];
// }
// $parkingData[] = $log;
// }
// $parkingDataByArea[] = [
// "lantai" => $lantai->sitearea_id,
// "data" => $parkingData,
// ];
// }
// return $parkingDataByArea;
// }
}
@@ -1,84 +0,0 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class ParkingSetupUserLevelLevelMenuController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
//
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
//
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show($id)
{
//
}
/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function edit($id)
{
//
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
//
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy($id)
{
//
}
}
+1
View File
@@ -32,6 +32,7 @@ class Kernel extends HttpKernel
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\App\Http\Middleware\UseBootstrapSessionStore::class,
\Illuminate\Session\Middleware\StartSession::class,
// \Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
@@ -0,0 +1,20 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Schema;
class UseBootstrapSessionStore
{
public function handle(Request $request, Closure $next)
{
if (config('session.driver') === 'database' && !Schema::hasTable(config('session.table'))) {
// A legacy database may not have Laravel's session table yet.
config(['session.driver' => 'file']);
}
return $next($request);
}
}