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
@@ -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.",
]);
}
}