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:
@@ -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)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user