Ubah/extend in-place data lama + search semua-field + statistik hari-minggu-bulan
This commit is contained in:
@@ -46,11 +46,15 @@ public function getMember(Request $request)
|
|||||||
// Log::info(json_encode("mem : " . $request->jenismember));
|
// Log::info(json_encode("mem : " . $request->jenismember));
|
||||||
// Log::info(json_encode("trans : " . $request->notrans));
|
// Log::info(json_encode("trans : " . $request->notrans));
|
||||||
// Log::info(json_encode("isactive : " . gettype($request->isactive)));
|
// Log::info(json_encode("isactive : " . gettype($request->isactive)));
|
||||||
$searchBy = $request->input("search-by");
|
// Nama param tidak konsisten antar JS (search-by vs searchBy, dst) -> terima dua-duanya.
|
||||||
$searchValue = trim($request->input("search_value", ""));
|
$val = fn($a, $b, $c = null) => $request->filled($a) ? $request->input($a)
|
||||||
|
: ($request->filled($b) ? $request->input($b)
|
||||||
|
: ($c && $request->filled($c) ? $request->input($c) : null));
|
||||||
|
$searchBy = $val("search-by", "searchBy");
|
||||||
|
$searchValue = trim($val("search_value", "searchValue") ?? "");
|
||||||
|
|
||||||
$memberType = $request->input("member_type");
|
$memberType = $val("member_type", "memberType", "jenismember");
|
||||||
$unitKerja = $request->input("departement");
|
$unitKerja = $val("departement", "department", "depart");
|
||||||
$vehicle = $request->input("vehicle");
|
$vehicle = $request->input("vehicle");
|
||||||
$isActive = $request->input("isActive");
|
$isActive = $request->input("isActive");
|
||||||
$tglAwal = $request->input("tgl_awal");
|
$tglAwal = $request->input("tgl_awal");
|
||||||
@@ -89,21 +93,30 @@ public function getMember(Request $request)
|
|||||||
$dataStiker->where("ts.nama", "ILIKE", "%{$searchValue}%");
|
$dataStiker->where("ts.nama", "ILIKE", "%{$searchValue}%");
|
||||||
break;
|
break;
|
||||||
case "alamat":
|
case "alamat":
|
||||||
$dataStiker->where("ts.alamat", "like", "%{$searchValue}%");
|
$dataStiker->where("ts.alamat", "ILIKE", "%{$searchValue}%");
|
||||||
break;
|
break;
|
||||||
case "nopol":
|
case "nopol":
|
||||||
$dataStiker->where("dts.nopol", "like", "%{$searchValue}%");
|
$dataStiker->where("dts.nopol", "ILIKE", "%{$searchValue}%");
|
||||||
break;
|
break;
|
||||||
case "nocard":
|
case "nocard":
|
||||||
$dataStiker->where("cm.nocard", "like", "%{$searchValue}%");
|
$dataStiker->where("cm.no_card", "ILIKE", "%{$searchValue}%");
|
||||||
break;
|
break;
|
||||||
case "notrans":
|
case "notrans":
|
||||||
$dataStiker->where("ts.notrans", "like", "%{$searchValue}%");
|
$dataStiker->where("ts.notrans", "ILIKE", "%{$searchValue}%");
|
||||||
break;
|
break;
|
||||||
// case "":
|
// case "":
|
||||||
// $dataStiker->where("ts.nama", "like", "%{$searchValue}%");
|
// $dataStiker->where("ts.nama", "like", "%{$searchValue}%");
|
||||||
// break;
|
// break;
|
||||||
}
|
}
|
||||||
|
} elseif (!$searchBy && $searchValue !== "") {
|
||||||
|
// Dropdown "Semua" + ada kata kunci: cari ke semua field teks.
|
||||||
|
$dataStiker->where(function ($w) use ($searchValue) {
|
||||||
|
$w->where("ts.nama", "ILIKE", "%{$searchValue}%")
|
||||||
|
->orWhere("ts.alamat", "ILIKE", "%{$searchValue}%")
|
||||||
|
->orWhere("dts.nopol", "ILIKE", "%{$searchValue}%")
|
||||||
|
->orWhere("cm.no_card", "ILIKE", "%{$searchValue}%")
|
||||||
|
->orWhere("ts.notrans", "ILIKE", "%{$searchValue}%");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($memberType) {
|
if ($memberType) {
|
||||||
@@ -374,6 +387,7 @@ public function store(Request $request, MakeStikerServices $makeStiker)
|
|||||||
public function show($id)
|
public function show($id)
|
||||||
{
|
{
|
||||||
Log::info("Data yang diterima : " . json_encode($id));
|
Log::info("Data yang diterima : " . json_encode($id));
|
||||||
|
// Exact match (dulu LIKE %..% bisa nyantol baris lain, fatal untuk notrans lama).
|
||||||
$dataStiker = StikerTrans
|
$dataStiker = StikerTrans
|
||||||
// with("stiker_details.vehicle", "memberCard")
|
// with("stiker_details.vehicle", "memberCard")
|
||||||
::select(
|
::select(
|
||||||
@@ -394,9 +408,13 @@ public function show($id)
|
|||||||
)
|
)
|
||||||
->leftJoin("jenis_langganan as jl", "jl.id", "=", "transaksi_stiker.jenis_langganan")
|
->leftJoin("jenis_langganan as jl", "jl.id", "=", "transaksi_stiker.jenis_langganan")
|
||||||
->leftJoin("stasiunkerja as sk", "sk.kode", "=", "transaksi_stiker.unit_kerja")
|
->leftJoin("stasiunkerja as sk", "sk.kode", "=", "transaksi_stiker.unit_kerja")
|
||||||
->where("notrans", "like", "%" . $id . "%")
|
->where("notrans", $id)
|
||||||
->first();
|
->first();
|
||||||
|
|
||||||
|
if (!$dataStiker) {
|
||||||
|
return response()->json(["message" => "Data tidak ditemukan."], 404);
|
||||||
|
}
|
||||||
|
|
||||||
$vehicleDetails = StikerTransDetail::query()
|
$vehicleDetails = StikerTransDetail::query()
|
||||||
->from("detail_transaksi_stiker as dts")
|
->from("detail_transaksi_stiker as dts")
|
||||||
->select("jm.nama as vehicle", "ts.tarif", "dts.*")
|
->select("jm.nama as vehicle", "ts.tarif", "dts.*")
|
||||||
@@ -446,9 +464,189 @@ public function edit($id)
|
|||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\Response
|
||||||
*/
|
*/
|
||||||
|
/**
|
||||||
|
* Update di tempat (nomor tidak berubah). Dipakai modal Ubah untuk
|
||||||
|
* data lama maupun baru. Detail kendaraan & kartu diganti sesuai
|
||||||
|
* list yang dikirim (roundtrip pakai kunci yang sama).
|
||||||
|
*/
|
||||||
public function update(Request $request, $id)
|
public function update(Request $request, $id)
|
||||||
{
|
{
|
||||||
//
|
$trx = DB::table("transaksi_stiker")->where("notrans", $id)->first();
|
||||||
|
if (!$trx) {
|
||||||
|
return response()->json(["status" => false, "message" => "Data tidak ditemukan."], 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $request->validate([
|
||||||
|
"nama" => "sometimes|string|max:255",
|
||||||
|
"address" => "nullable|string",
|
||||||
|
"phone" => "nullable|string|max:64",
|
||||||
|
"member" => "nullable|string",
|
||||||
|
"depart" => "nullable|string",
|
||||||
|
"note" => "nullable|string",
|
||||||
|
"harga" => "nullable|numeric",
|
||||||
|
"periode" => "nullable|string",
|
||||||
|
"daterange" => "nullable|string",
|
||||||
|
"awal" => "nullable|string",
|
||||||
|
"akhir" => "nullable|string",
|
||||||
|
"nopolData" => "nullable|array",
|
||||||
|
"cardNumber" => "nullable|array",
|
||||||
|
]);
|
||||||
|
|
||||||
|
return DB::transaction(function () use ($trx, $data, $id) {
|
||||||
|
$upd = [];
|
||||||
|
if (array_key_exists("nama", $data)) {
|
||||||
|
$upd["nama"] = $data["nama"];
|
||||||
|
}
|
||||||
|
if (array_key_exists("address", $data)) {
|
||||||
|
$upd["alamat"] = $data["address"] ?? "";
|
||||||
|
}
|
||||||
|
if (array_key_exists("phone", $data)) {
|
||||||
|
$upd["telepon"] = $data["phone"] ?? "";
|
||||||
|
}
|
||||||
|
if (array_key_exists("member", $data)) {
|
||||||
|
$upd["jenis_langganan"] = $data["member"];
|
||||||
|
}
|
||||||
|
if (array_key_exists("depart", $data)) {
|
||||||
|
$upd["unit_kerja"] = $data["depart"];
|
||||||
|
}
|
||||||
|
if (array_key_exists("note", $data)) {
|
||||||
|
$upd["keterangan"] = $data["note"] ?? "";
|
||||||
|
}
|
||||||
|
if (array_key_exists("harga", $data)) {
|
||||||
|
$upd["harga"] = $data["harga"] ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$periode = $data["periode"] ?? $data["daterange"] ?? null;
|
||||||
|
if ($periode && str_contains($periode, " - ")) {
|
||||||
|
[$p0, $p1] = explode(" - ", $periode, 2);
|
||||||
|
$upd["awal"] = Carbon::createFromFormat("d-m-Y H:i", trim($p0));
|
||||||
|
$upd["akhir"] = Carbon::createFromFormat("d-m-Y H:i", trim($p1));
|
||||||
|
} else {
|
||||||
|
if (!empty($data["awal"])) {
|
||||||
|
$upd["awal"] = $data["awal"];
|
||||||
|
}
|
||||||
|
if (!empty($data["akhir"])) {
|
||||||
|
$upd["akhir"] = $data["akhir"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$upd["tgl_edited"] = now();
|
||||||
|
|
||||||
|
if (!empty($upd)) {
|
||||||
|
DB::table("transaksi_stiker")->where("notrans", $id)->update($upd);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ganti detail kendaraan (kunci notrans yang sama, nomor dipertahankan).
|
||||||
|
if (array_key_exists("nopolData", $data)) {
|
||||||
|
DB::table("detail_transaksi_stiker")->where("notrans", $id)->delete();
|
||||||
|
foreach ($data["nopolData"] ?? [] as $nopol) {
|
||||||
|
if (empty($nopol["nopol"])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$produk = explode(" - ", $nopol["member"] ?? "");
|
||||||
|
DB::table("detail_transaksi_stiker")->insert([
|
||||||
|
"notrans" => $id,
|
||||||
|
"nopol" => $nopol["nopol"],
|
||||||
|
"jenis_mobil" => $nopol["vehicle"] ?? null,
|
||||||
|
"jenis_member" => $produk[0] ?? null,
|
||||||
|
"merk" => $nopol["merk"] ?? null,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ganti kartu (kunci no_id yang sama). Lewati bila no_id kosong (data lama tertentu).
|
||||||
|
if (array_key_exists("cardNumber", $data) && !empty($trx->no_id)) {
|
||||||
|
DB::table("card_member")->where("notrans", $trx->no_id)->delete();
|
||||||
|
foreach ($data["cardNumber"] ?? [] as $card) {
|
||||||
|
if (empty($card["nocard"])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
DB::table("card_member")->insert([
|
||||||
|
"notrans" => $trx->no_id,
|
||||||
|
"no_card" => $card["nocard"],
|
||||||
|
"no_urut" => $card["nourut"] ?? null,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json(["status" => true, "message" => "Data berhasil diperbarui, nomor tetap " . $id . "."]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perpanjang notrans LAMA di tempat (nomor dipertahankan).
|
||||||
|
* Header periode (+ field lain bila dikirim) diupdate; kendaraan
|
||||||
|
* BARU (flag _baru) ditempel ke notrans yang sama; kartu tidak diutak-atik.
|
||||||
|
*/
|
||||||
|
public function extendOld(Request $request)
|
||||||
|
{
|
||||||
|
$notrans = $request->input("notrans");
|
||||||
|
$trx = DB::table("transaksi_stiker")->where("notrans", $notrans)->first();
|
||||||
|
if (!$trx) {
|
||||||
|
return response()->json(["status" => false, "message" => "Data tidak ditemukan."], 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $request->validate([
|
||||||
|
"notrans" => "required|string",
|
||||||
|
"nama" => "sometimes|string|max:255",
|
||||||
|
"address" => "nullable|string",
|
||||||
|
"phone" => "nullable|string|max:64",
|
||||||
|
"member" => "nullable|string",
|
||||||
|
"depart" => "nullable|string",
|
||||||
|
"note" => "nullable|string",
|
||||||
|
"harga" => "nullable|numeric",
|
||||||
|
"periode" => "nullable|string",
|
||||||
|
"daterange" => "nullable|string",
|
||||||
|
"awal" => "nullable|string",
|
||||||
|
"akhir" => "nullable|string",
|
||||||
|
"nopolData" => "nullable|array",
|
||||||
|
]);
|
||||||
|
|
||||||
|
return DB::transaction(function () use ($trx, $data, $notrans) {
|
||||||
|
$upd = ["jenis_transaksi" => "1", "tgl_edited" => now()];
|
||||||
|
foreach (["nama" => "nama", "address" => "alamat", "phone" => "telepon",
|
||||||
|
"member" => "jenis_langganan", "depart" => "unit_kerja",
|
||||||
|
"note" => "keterangan", "harga" => "harga"] as $in => $col) {
|
||||||
|
if (array_key_exists($in, $data)) {
|
||||||
|
$upd[$col] = $data[$in] ?? "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$periode = $data["periode"] ?? $data["daterange"] ?? null;
|
||||||
|
if ($periode && str_contains($periode, " - ")) {
|
||||||
|
[$p0, $p1] = explode(" - ", $periode, 2);
|
||||||
|
$upd["awal"] = Carbon::createFromFormat("d-m-Y H:i", trim($p0));
|
||||||
|
$upd["akhir"] = Carbon::createFromFormat("d-m-Y H:i", trim($p1));
|
||||||
|
} else {
|
||||||
|
if (!empty($data["awal"])) {
|
||||||
|
$upd["awal"] = $data["awal"];
|
||||||
|
}
|
||||||
|
if (!empty($data["akhir"])) {
|
||||||
|
$upd["akhir"] = $data["akhir"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DB::table("transaksi_stiker")->where("notrans", $notrans)->update($upd);
|
||||||
|
|
||||||
|
// Tempel kendaraan BARU saja (baris display lama dilewati via flag _baru).
|
||||||
|
$tambah = 0;
|
||||||
|
foreach ($data["nopolData"] ?? [] as $nopol) {
|
||||||
|
if (empty($nopol["_baru"]) || empty($nopol["nopol"])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$produk = explode(" - ", $nopol["member"] ?? "");
|
||||||
|
DB::table("detail_transaksi_stiker")->insert([
|
||||||
|
"notrans" => $notrans,
|
||||||
|
"nopol" => $nopol["nopol"],
|
||||||
|
"jenis_mobil" => $nopol["vehicle"] ?? null,
|
||||||
|
"jenis_member" => $produk[0] ?? null,
|
||||||
|
"merk" => $nopol["merk"] ?? null,
|
||||||
|
]);
|
||||||
|
$tambah++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json(["status" => true,
|
||||||
|
"message" => "Perpanjangan tersimpan, nomor tetap " . $notrans . " ({$tambah} kendaraan baru)."]);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -309,4 +309,200 @@ $(document).ready(function () {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ================= UBAH (update di tempat, nomor dipertahankan) =================
|
||||||
|
function updateHargaUbah() {
|
||||||
|
let total = 0;
|
||||||
|
$("#ubah-member #edit-list-nopol tr").each(function () {
|
||||||
|
total += parseFloat($(this).data("tarif")) || 0;
|
||||||
|
});
|
||||||
|
$("#ubah-member input[name='harga']").val(total);
|
||||||
|
}
|
||||||
|
|
||||||
|
function showUrlFor(notrans) {
|
||||||
|
const tpl = $("#btnExtend").data("url") || "/transaksi/stiker/:id";
|
||||||
|
return tpl.replace(":id", encodeURIComponent(notrans));
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).on("click", ".edit-button", function () {
|
||||||
|
const notrans = (typeof selectedRowData !== "undefined" && selectedRowData?.notrans)
|
||||||
|
|| $(this).data("id") || "";
|
||||||
|
if (!notrans) {
|
||||||
|
Swal.fire({icon: "warning", title: "Belum pilih data", text: "Klik salah satu baris transaksi dulu."});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$.ajax({
|
||||||
|
url: showUrlFor(notrans),
|
||||||
|
type: "GET",
|
||||||
|
success: function (r) {
|
||||||
|
const m = $("#ubah-member");
|
||||||
|
m.find("#edit-notrans").val(r.notrans);
|
||||||
|
m.find("[name='nama']").val(r.nama ?? "");
|
||||||
|
m.find("[name='address']").val(r.alamat ?? "");
|
||||||
|
m.find("[name='phone']").val(r.telepon ?? "");
|
||||||
|
m.find("[name='note']").val(r.keterangan ?? "");
|
||||||
|
m.find("[name='harga']").val(r.harga ?? 0);
|
||||||
|
m.find("[name='member']").val(r.jenis_langganan ?? "");
|
||||||
|
m.find("[name='depart']").val(r.unit_kerja ?? "");
|
||||||
|
if (r.awal && r.akhir) {
|
||||||
|
m.find("[name='daterange']").val(
|
||||||
|
`${moment(r.awal).format("DD-MM-YYYY HH:mm")} - ${moment(r.akhir).format("DD-MM-YYYY HH:mm")}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const jl = $("#edit-list-nopol").empty();
|
||||||
|
(r.stiker_details || []).forEach((row) => {
|
||||||
|
jl.append(`
|
||||||
|
<tr data-tarif="${row.tarif ?? 0}">
|
||||||
|
<td class="text-center">${row.nopol ?? ""}</td>
|
||||||
|
<td class="text-center" data-value="${row.jenis_mobil ?? ""}">${row.vehicle ?? ""}</td>
|
||||||
|
<td class="text-center">${row.jenis_member ?? ""}</td>
|
||||||
|
<td class="text-center">${row.merk ?? ""}</td>
|
||||||
|
<td class="text-center p-1"><button class="btn btn-danger btn-xs edit-del-nopol" type="button">Hapus</button></td>
|
||||||
|
</tr>`);
|
||||||
|
});
|
||||||
|
const kl = $("#edit-list-card").empty();
|
||||||
|
(r.memberCard || []).forEach((ro) => {
|
||||||
|
kl.append(`
|
||||||
|
<tr>
|
||||||
|
<td class="text-center">${ro.no_card ?? ""}</td>
|
||||||
|
<td class="text-center">${ro.no_urut ?? ""}</td>
|
||||||
|
<td class="text-center p-2"><button class="btn btn-danger btn-xs edit-del-card" type="button">Hapus</button></td>
|
||||||
|
</tr>`);
|
||||||
|
});
|
||||||
|
updateHargaUbah();
|
||||||
|
},
|
||||||
|
error: function (xhr) {
|
||||||
|
Swal.fire({icon: "error", title: "Gagal memuat data", text: xhr.responseJSON?.message || "Data tidak ditemukan."});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#edit-jenisVehicle").on("change", function () {
|
||||||
|
const vehicleSelected = $(this).val();
|
||||||
|
const box = $("#edit-jenis-member").empty().append('<option selected value="">Pilih Jenis</option>');
|
||||||
|
(member || []).forEach((item) => {
|
||||||
|
if (String(item.id_mobil) === String(vehicleSelected) && item.id_mobil !== 0) {
|
||||||
|
box.append(`<option value="${item.tarif}">${item.jenis_langganan} - ${item.tarif}</option>`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#edit-nopol-add").on("click", function () {
|
||||||
|
const nopol = $(".enopol-add").val().trim();
|
||||||
|
const vehicle = $("#edit-jenisVehicle").val();
|
||||||
|
const vehicleName = $("#edit-jenisVehicle option:selected").text();
|
||||||
|
const memberTxt = $("#edit-jenis-member option:selected").text();
|
||||||
|
const tarif = parseFloat($("#edit-jenis-member").val()) || 0;
|
||||||
|
const merk = $(".emerk").val().trim();
|
||||||
|
$(".enopol-add").removeClass("is-invalid");
|
||||||
|
if (!vehicle) {
|
||||||
|
Swal.fire({icon: "warning", title: "Belum lengkap", text: "Wajib pilih jenis kendaraan"});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$.ajax({
|
||||||
|
url: "/transaksi/stiker/checkField",
|
||||||
|
type: "POST",
|
||||||
|
data: { nopol: nopol },
|
||||||
|
headers: { "X-CSRF-token": $('meta[name="csrf-token"]').attr("content") },
|
||||||
|
success: function (rr) {
|
||||||
|
if (rr.response === true) {
|
||||||
|
$("#edit-list-nopol").append(`
|
||||||
|
<tr data-tarif="${tarif}">
|
||||||
|
<td class="text-center">${nopol}</td>
|
||||||
|
<td class="text-center" data-value="${vehicle}">${vehicleName}</td>
|
||||||
|
<td class="text-center">${memberTxt}</td>
|
||||||
|
<td class="text-center">${merk}</td>
|
||||||
|
<td class="text-center p-1"><button class="btn btn-danger btn-xs edit-del-nopol" type="button">Hapus</button></td>
|
||||||
|
</tr>`);
|
||||||
|
$(".enopol-add, .emerk").val("");
|
||||||
|
$("#edit-jenisVehicle, #edit-jenis-member").val("");
|
||||||
|
updateHargaUbah();
|
||||||
|
} else {
|
||||||
|
$(".enopol-add").addClass("is-invalid").next(".invalid-feedback").text(rr.message).show();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function (xhr) {
|
||||||
|
Swal.fire({icon: "error", title: "Gagal memeriksa", text: xhr.responseJSON?.message || "Terjadi kesalahan saat memeriksa nopol"});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$(".ekartu").on("keydown", function (e) {
|
||||||
|
if (e.key === "Enter") { e.preventDefault(); $(".enourut").focus(); }
|
||||||
|
});
|
||||||
|
$(".enourut").on("keydown", function (e) {
|
||||||
|
if (e.key !== "Enter") return;
|
||||||
|
e.preventDefault();
|
||||||
|
const nocard = $(".ekartu").val().trim();
|
||||||
|
const nourut = $(".enourut").val().trim();
|
||||||
|
if (!nocard) return;
|
||||||
|
$("#edit-list-card").append(`
|
||||||
|
<tr><td class="text-center">${nocard}</td><td class="text-center">${nourut}</td>
|
||||||
|
<td class="text-center p-2"><button class="btn btn-danger btn-xs edit-del-card" type="button">Hapus</button></td></tr>`);
|
||||||
|
$(".ekartu, .enourut").val("");
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#edit-list-nopol").on("click", ".edit-del-nopol", function () {
|
||||||
|
$(this).closest("tr").remove();
|
||||||
|
updateHargaUbah();
|
||||||
|
});
|
||||||
|
$("#edit-list-card").on("click", ".edit-del-card", function () {
|
||||||
|
$(this).closest("tr").remove();
|
||||||
|
});
|
||||||
|
|
||||||
|
$(".simpan-ubah").on("click", function () {
|
||||||
|
const btn = $(this);
|
||||||
|
const notrans = $("#edit-notrans").val();
|
||||||
|
if (!notrans) {
|
||||||
|
Swal.fire({icon: "warning", title: "Belum ada data", text: "Buka ulang modal Ubah dari baris transaksi."});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const nopolData = [];
|
||||||
|
$("#edit-list-nopol tr").each(function () {
|
||||||
|
const row = $(this);
|
||||||
|
nopolData.push({
|
||||||
|
nopol: row.find("td:nth-child(1)").text().trim(),
|
||||||
|
vehicle: row.find("td:nth-child(2)").data("value"),
|
||||||
|
member: row.find("td:nth-child(3)").text().trim(),
|
||||||
|
merk: row.find("td:nth-child(4)").text().trim(),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
const cardNumber = [];
|
||||||
|
$("#edit-list-card tr").each(function () {
|
||||||
|
const row = $(this);
|
||||||
|
const nocard = row.find("td:nth-child(1)").text().trim();
|
||||||
|
if (!nocard) return;
|
||||||
|
cardNumber.push({ nocard: nocard, nourut: row.find("td:nth-child(2)").text().trim() });
|
||||||
|
});
|
||||||
|
const payload = {
|
||||||
|
nama: $("#ubah-member [name='nama']").val(),
|
||||||
|
address: $("#ubah-member [name='address']").val(),
|
||||||
|
phone: $("#ubah-member [name='phone']").val(),
|
||||||
|
member: $("#ubah-member [name='member']").val(),
|
||||||
|
depart: $("#ubah-member [name='depart']").val(),
|
||||||
|
note: $("#ubah-member [name='note']").val(),
|
||||||
|
harga: $("#ubah-member [name='harga']").val(),
|
||||||
|
daterange: $("#ubah-member [name='daterange']").val(),
|
||||||
|
nopolData: nopolData,
|
||||||
|
cardNumber: cardNumber,
|
||||||
|
};
|
||||||
|
const saveHtml = btn.html();
|
||||||
|
btn.prop("disabled", true).html('<span class="spinner-border spinner-border-sm me-1"></span>Menyimpan...');
|
||||||
|
$.ajax({
|
||||||
|
url: `${location.origin}/transaksi/member/${encodeURIComponent(notrans)}`,
|
||||||
|
type: "PUT",
|
||||||
|
data: payload,
|
||||||
|
headers: { "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr("content") },
|
||||||
|
success: function (r) {
|
||||||
|
$("#ubah-member").modal("hide");
|
||||||
|
Swal.fire({icon: "success", title: "Berhasil", text: r.message || "Data diperbarui."}).then(() => location.reload());
|
||||||
|
},
|
||||||
|
error: function (xhr) {
|
||||||
|
Swal.fire({icon: "error", title: "Gagal menyimpan", text: xhr.responseJSON?.message || "Periksa kembali isian."});
|
||||||
|
},
|
||||||
|
complete: function () {
|
||||||
|
btn.prop("disabled", false).html(saveHtml);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -247,7 +247,7 @@ $(document).ready(function () {
|
|||||||
if (r.response === true) {
|
if (r.response === true) {
|
||||||
harga += Number(memberExtValue);
|
harga += Number(memberExtValue);
|
||||||
var rowhtml = `
|
var rowhtml = `
|
||||||
<tr>
|
<tr data-baru="1">
|
||||||
<td class="text-center">${nopolExt}</td>
|
<td class="text-center">${nopolExt}</td>
|
||||||
<td class="text-center" data-value="${vehicleExt}">${vehicleExtName}</td>
|
<td class="text-center" data-value="${vehicleExt}">${vehicleExtName}</td>
|
||||||
<td class="text-center">${memberExt}</td>
|
<td class="text-center">${memberExt}</td>
|
||||||
@@ -295,6 +295,7 @@ $(document).ready(function () {
|
|||||||
vehicle: row.find("td:nth-child(2)").data("value"),
|
vehicle: row.find("td:nth-child(2)").data("value"),
|
||||||
member: row.find("td:nth-child(3)").text().trim(),
|
member: row.find("td:nth-child(3)").text().trim(),
|
||||||
merk: row.find("td:nth-child(4)").text().trim(),
|
merk: row.find("td:nth-child(4)").text().trim(),
|
||||||
|
_baru: row.data("baru") ? 1 : 0,
|
||||||
};
|
};
|
||||||
nopolData.push(rowData);
|
nopolData.push(rowData);
|
||||||
});
|
});
|
||||||
@@ -343,6 +344,15 @@ $(document).ready(function () {
|
|||||||
|
|
||||||
console.log(extData);
|
console.log(extData);
|
||||||
|
|
||||||
|
// Notrans lama (mengandung "/") -> perpanjang di tempat, nomor dipertahankan.
|
||||||
|
// Notrans baru -> alur lama (bikin nomor baru via member.store).
|
||||||
|
if (String(formDataExt.notrans || "").includes("/")) {
|
||||||
|
url = "/transaksi/stiker/extend-old";
|
||||||
|
extData = Object.assign({ notrans: formDataExt.notrans }, formDataExt, {
|
||||||
|
nopolData: nopolData,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: url,
|
url: url,
|
||||||
type: "POST",
|
type: "POST",
|
||||||
|
|||||||
@@ -286,7 +286,202 @@ $(document).ready(function () {
|
|||||||
}).then(function () {
|
}).then(function () {
|
||||||
// Reload halaman setelah SweetAlert ditutup
|
// Reload halaman setelah SweetAlert ditutup
|
||||||
location.reload(); // Ini akan me-reload halaman
|
location.reload(); // Ini akan me-reload halaman
|
||||||
});
|
// ================= UBAH (update di tempat, nomor dipertahankan) =================
|
||||||
|
function updateHargaUbah() {
|
||||||
|
let total = 0;
|
||||||
|
$("#ubah-member #edit-list-nopol tr").each(function () {
|
||||||
|
total += parseFloat($(this).data("tarif")) || 0;
|
||||||
|
});
|
||||||
|
$("#ubah-member input[name='harga']").val(total);
|
||||||
|
}
|
||||||
|
|
||||||
|
function showUrlFor(notrans) {
|
||||||
|
const tpl = $("#btnExtend").data("url") || "/transaksi/stiker/:id";
|
||||||
|
return tpl.replace(":id", encodeURIComponent(notrans));
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).on("click", ".edit-button", function () {
|
||||||
|
const notrans = (typeof selectedRowData !== "undefined" && selectedRowData?.notrans)
|
||||||
|
|| $(this).data("id") || "";
|
||||||
|
if (!notrans) {
|
||||||
|
Swal.fire({icon: "warning", title: "Belum pilih data", text: "Klik salah satu baris transaksi dulu."});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$.ajax({
|
||||||
|
url: showUrlFor(notrans),
|
||||||
|
type: "GET",
|
||||||
|
success: function (r) {
|
||||||
|
const m = $("#ubah-member");
|
||||||
|
m.find("#edit-notrans").val(r.notrans);
|
||||||
|
m.find("[name='nama']").val(r.nama ?? "");
|
||||||
|
m.find("[name='address']").val(r.alamat ?? "");
|
||||||
|
m.find("[name='phone']").val(r.telepon ?? "");
|
||||||
|
m.find("[name='note']").val(r.keterangan ?? "");
|
||||||
|
m.find("[name='harga']").val(r.harga ?? 0);
|
||||||
|
m.find("[name='member']").val(r.jenis_langganan ?? "");
|
||||||
|
m.find("[name='depart']").val(r.unit_kerja ?? "");
|
||||||
|
if (r.awal && r.akhir) {
|
||||||
|
m.find("[name='daterange']").val(
|
||||||
|
`${moment(r.awal).format("DD-MM-YYYY HH:mm")} - ${moment(r.akhir).format("DD-MM-YYYY HH:mm")}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const jl = $("#edit-list-nopol").empty();
|
||||||
|
(r.stiker_details || []).forEach((row) => {
|
||||||
|
jl.append(`
|
||||||
|
<tr data-tarif="${row.tarif ?? 0}">
|
||||||
|
<td class="text-center">${row.nopol ?? ""}</td>
|
||||||
|
<td class="text-center" data-value="${row.jenis_mobil ?? ""}">${row.vehicle ?? ""}</td>
|
||||||
|
<td class="text-center">${row.jenis_member ?? ""}</td>
|
||||||
|
<td class="text-center">${row.merk ?? ""}</td>
|
||||||
|
<td class="text-center p-1"><button class="btn btn-danger btn-xs edit-del-nopol" type="button">Hapus</button></td>
|
||||||
|
</tr>`);
|
||||||
|
});
|
||||||
|
const kl = $("#edit-list-card").empty();
|
||||||
|
(r.memberCard || []).forEach((ro) => {
|
||||||
|
kl.append(`
|
||||||
|
<tr>
|
||||||
|
<td class="text-center">${ro.no_card ?? ""}</td>
|
||||||
|
<td class="text-center">${ro.no_urut ?? ""}</td>
|
||||||
|
<td class="text-center p-2"><button class="btn btn-danger btn-xs edit-del-card" type="button">Hapus</button></td>
|
||||||
|
</tr>`);
|
||||||
|
});
|
||||||
|
updateHargaUbah();
|
||||||
|
},
|
||||||
|
error: function (xhr) {
|
||||||
|
Swal.fire({icon: "error", title: "Gagal memuat data", text: xhr.responseJSON?.message || "Data tidak ditemukan."});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#edit-jenisVehicle").on("change", function () {
|
||||||
|
const vehicleSelected = $(this).val();
|
||||||
|
const box = $("#edit-jenis-member").empty().append('<option selected value="">Pilih Jenis</option>');
|
||||||
|
(member || []).forEach((item) => {
|
||||||
|
if (String(item.id_mobil) === String(vehicleSelected) && item.id_mobil !== 0) {
|
||||||
|
box.append(`<option value="${item.tarif}">${item.jenis_langganan} - ${item.tarif}</option>`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#edit-nopol-add").on("click", function () {
|
||||||
|
const nopol = $(".enopol-add").val().trim();
|
||||||
|
const vehicle = $("#edit-jenisVehicle").val();
|
||||||
|
const vehicleName = $("#edit-jenisVehicle option:selected").text();
|
||||||
|
const memberTxt = $("#edit-jenis-member option:selected").text();
|
||||||
|
const tarif = parseFloat($("#edit-jenis-member").val()) || 0;
|
||||||
|
const merk = $(".emerk").val().trim();
|
||||||
|
$(".enopol-add").removeClass("is-invalid");
|
||||||
|
if (!vehicle) {
|
||||||
|
Swal.fire({icon: "warning", title: "Belum lengkap", text: "Wajib pilih jenis kendaraan"});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$.ajax({
|
||||||
|
url: "/transaksi/stiker/checkField",
|
||||||
|
type: "POST",
|
||||||
|
data: { nopol: nopol },
|
||||||
|
headers: { "X-CSRF-token": $('meta[name="csrf-token"]').attr("content") },
|
||||||
|
success: function (rr) {
|
||||||
|
if (rr.response === true) {
|
||||||
|
$("#edit-list-nopol").append(`
|
||||||
|
<tr data-tarif="${tarif}">
|
||||||
|
<td class="text-center">${nopol}</td>
|
||||||
|
<td class="text-center" data-value="${vehicle}">${vehicleName}</td>
|
||||||
|
<td class="text-center">${memberTxt}</td>
|
||||||
|
<td class="text-center">${merk}</td>
|
||||||
|
<td class="text-center p-1"><button class="btn btn-danger btn-xs edit-del-nopol" type="button">Hapus</button></td>
|
||||||
|
</tr>`);
|
||||||
|
$(".enopol-add, .emerk").val("");
|
||||||
|
$("#edit-jenisVehicle, #edit-jenis-member").val("");
|
||||||
|
updateHargaUbah();
|
||||||
|
} else {
|
||||||
|
$(".enopol-add").addClass("is-invalid").next(".invalid-feedback").text(rr.message).show();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function (xhr) {
|
||||||
|
Swal.fire({icon: "error", title: "Gagal memeriksa", text: xhr.responseJSON?.message || "Terjadi kesalahan saat memeriksa nopol"});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$(".ekartu").on("keydown", function (e) {
|
||||||
|
if (e.key === "Enter") { e.preventDefault(); $(".enourut").focus(); }
|
||||||
|
});
|
||||||
|
$(".enourut").on("keydown", function (e) {
|
||||||
|
if (e.key !== "Enter") return;
|
||||||
|
e.preventDefault();
|
||||||
|
const nocard = $(".ekartu").val().trim();
|
||||||
|
const nourut = $(".enourut").val().trim();
|
||||||
|
if (!nocard) return;
|
||||||
|
$("#edit-list-card").append(`
|
||||||
|
<tr><td class="text-center">${nocard}</td><td class="text-center">${nourut}</td>
|
||||||
|
<td class="text-center p-2"><button class="btn btn-danger btn-xs edit-del-card" type="button">Hapus</button></td></tr>`);
|
||||||
|
$(".ekartu, .enourut").val("");
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#edit-list-nopol").on("click", ".edit-del-nopol", function () {
|
||||||
|
$(this).closest("tr").remove();
|
||||||
|
updateHargaUbah();
|
||||||
|
});
|
||||||
|
$("#edit-list-card").on("click", ".edit-del-card", function () {
|
||||||
|
$(this).closest("tr").remove();
|
||||||
|
});
|
||||||
|
|
||||||
|
$(".simpan-ubah").on("click", function () {
|
||||||
|
const btn = $(this);
|
||||||
|
const notrans = $("#edit-notrans").val();
|
||||||
|
if (!notrans) {
|
||||||
|
Swal.fire({icon: "warning", title: "Belum ada data", text: "Buka ulang modal Ubah dari baris transaksi."});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const nopolData = [];
|
||||||
|
$("#edit-list-nopol tr").each(function () {
|
||||||
|
const row = $(this);
|
||||||
|
nopolData.push({
|
||||||
|
nopol: row.find("td:nth-child(1)").text().trim(),
|
||||||
|
vehicle: row.find("td:nth-child(2)").data("value"),
|
||||||
|
member: row.find("td:nth-child(3)").text().trim(),
|
||||||
|
merk: row.find("td:nth-child(4)").text().trim(),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
const cardNumber = [];
|
||||||
|
$("#edit-list-card tr").each(function () {
|
||||||
|
const row = $(this);
|
||||||
|
const nocard = row.find("td:nth-child(1)").text().trim();
|
||||||
|
if (!nocard) return;
|
||||||
|
cardNumber.push({ nocard: nocard, nourut: row.find("td:nth-child(2)").text().trim() });
|
||||||
|
});
|
||||||
|
const payload = {
|
||||||
|
nama: $("#ubah-member [name='nama']").val(),
|
||||||
|
address: $("#ubah-member [name='address']").val(),
|
||||||
|
phone: $("#ubah-member [name='phone']").val(),
|
||||||
|
member: $("#ubah-member [name='member']").val(),
|
||||||
|
depart: $("#ubah-member [name='depart']").val(),
|
||||||
|
note: $("#ubah-member [name='note']").val(),
|
||||||
|
harga: $("#ubah-member [name='harga']").val(),
|
||||||
|
daterange: $("#ubah-member [name='daterange']").val(),
|
||||||
|
nopolData: nopolData,
|
||||||
|
cardNumber: cardNumber,
|
||||||
|
};
|
||||||
|
const saveHtml = btn.html();
|
||||||
|
btn.prop("disabled", true).html('<span class="spinner-border spinner-border-sm me-1"></span>Menyimpan...');
|
||||||
|
$.ajax({
|
||||||
|
url: `${location.origin}/transaksi/member/${encodeURIComponent(notrans)}`,
|
||||||
|
type: "PUT",
|
||||||
|
data: payload,
|
||||||
|
headers: { "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr("content") },
|
||||||
|
success: function (r) {
|
||||||
|
$("#ubah-member").modal("hide");
|
||||||
|
Swal.fire({icon: "success", title: "Berhasil", text: r.message || "Data diperbarui."}).then(() => location.reload());
|
||||||
|
},
|
||||||
|
error: function (xhr) {
|
||||||
|
Swal.fire({icon: "error", title: "Gagal menyimpan", text: xhr.responseJSON?.message || "Periksa kembali isian."});
|
||||||
|
},
|
||||||
|
complete: function () {
|
||||||
|
btn.prop("disabled", false).html(saveHtml);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
} else if (r.status == false) {
|
} else if (r.status == false) {
|
||||||
Swal.fire({icon: "error", title: "Oops...", text: r.message || "Terjadi kendala, silakan hubungi admin."});
|
Swal.fire({icon: "error", title: "Oops...", text: r.message || "Terjadi kendala, silakan hubungi admin."});
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -64,6 +64,7 @@
|
|||||||
<li class="nav-item"><a class="nav-link" href="/report/laporan-per-pintu">Teransaksi Per Pintu</a></li>
|
<li class="nav-item"><a class="nav-link" href="/report/laporan-per-pintu">Teransaksi Per Pintu</a></li>
|
||||||
<li class="nav-item"><a class="nav-link" href="/report/laporan-semua-transaksi">Transaksi Harian</a></li>
|
<li class="nav-item"><a class="nav-link" href="/report/laporan-semua-transaksi">Transaksi Harian</a></li>
|
||||||
<li class="nav-item"><a class="nav-link" href="/report/stiker/harian">Member Harian</a></li>
|
<li class="nav-item"><a class="nav-link" href="/report/stiker/harian">Member Harian</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="/report/statistik">Statistik Transaksi</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -0,0 +1,200 @@
|
|||||||
|
@extends('layouts.master')
|
||||||
|
|
||||||
|
@section('styles')
|
||||||
|
<style>
|
||||||
|
#tabel-statistik th[data-info] { cursor: default; }
|
||||||
|
.stat-card { border-radius: 10px; }
|
||||||
|
</style>
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<div class="container-fluid page-body-wrapper">
|
||||||
|
<div class="main-panel">
|
||||||
|
<div class="content-wrapper">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12 grid-margin stretch-card">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<h4 class="card-title">Statistik Transaksi</h4>
|
||||||
|
<small class="text-muted d-block mb-3">Periode berdasarkan tanggal masuk. Pecah per hari / minggu / bulan.</small>
|
||||||
|
<form id="filter-statistik" action="javascript:void(0)">
|
||||||
|
<div class="row align-items-end g-2">
|
||||||
|
<div class="col-md-2">
|
||||||
|
<label class="form-label" for="grup">Pecah Per</label>
|
||||||
|
<select class="form-select form-select-sm" id="grup">
|
||||||
|
<option value="hari" selected>Hari</option>
|
||||||
|
<option value="minggu">Minggu</option>
|
||||||
|
<option value="bulan">Bulan</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-2">
|
||||||
|
<label class="form-label" for="tgl-awal">Periode Awal</label>
|
||||||
|
<input type="date" class="form-control form-control-sm" id="tgl-awal">
|
||||||
|
</div>
|
||||||
|
<div class="col-md-2">
|
||||||
|
<label class="form-label" for="tgl-akhir">Periode Akhir</label>
|
||||||
|
<input type="date" class="form-control form-control-sm" id="tgl-akhir">
|
||||||
|
</div>
|
||||||
|
<div class="col-md-2">
|
||||||
|
<label class="form-label" for="status-transaksi">Status Transaksi</label>
|
||||||
|
<select class="form-select form-select-sm" id="status-transaksi">
|
||||||
|
<option value="" selected>Semua</option>
|
||||||
|
<option value="0">Casual</option>
|
||||||
|
<option value="3">Member</option>
|
||||||
|
<option value="32">Denda</option>
|
||||||
|
<option value="-1">Masalah</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-2">
|
||||||
|
<label class="form-label" for="cara">Pembayaran</label>
|
||||||
|
<select class="form-select form-select-sm" id="cara">
|
||||||
|
<option value="" selected>Semua</option>
|
||||||
|
<option value="tunai">Tunai</option>
|
||||||
|
<option value="cashless">Cashless</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-2 d-flex gap-2">
|
||||||
|
<button type="submit" class="btn btn-sm btn-primary" id="btn-proses">Proses</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<hr class="my-3">
|
||||||
|
<div class="row g-2 mb-3" id="ringkasan">
|
||||||
|
<div class="col-md-2"><div class="border rounded p-2 h-100 stat-card"><small class="text-muted">Transaksi</small><div class="fw-bold" id="sum-trx">-</div></div></div>
|
||||||
|
<div class="col-md-2"><div class="border rounded p-2 h-100 stat-card"><small class="text-muted">Keluar</small><div class="fw-bold" id="sum-keluar">-</div></div></div>
|
||||||
|
<div class="col-md-2"><div class="border rounded p-2 h-100 stat-card"><small class="text-muted">Pendapatan</small><div class="fw-bold text-success" id="sum-pendapatan">-</div></div></div>
|
||||||
|
<div class="col-md-3"><div class="border rounded p-2 h-100 stat-card"><small class="text-muted">Tunai</small><div class="fw-bold" id="sum-tunai">-</div></div></div>
|
||||||
|
<div class="col-md-3"><div class="border rounded p-2 h-100 stat-card"><small class="text-muted">Cashless</small><div class="fw-bold text-info" id="sum-cashless">-</div></div></div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3" style="max-height: 320px;"><canvas id="chart-statistik" height="120"></canvas></div>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-bordered table-striped" id="tabel-statistik">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Periode</th>
|
||||||
|
<th class="text-end">Transaksi</th>
|
||||||
|
<th class="text-end">Keluar</th>
|
||||||
|
<th class="text-end">Pendapatan</th>
|
||||||
|
<th class="text-end">Tunai</th>
|
||||||
|
<th class="text-end">Cashless</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="body-statistik">
|
||||||
|
<tr><td colspan="6" class="text-center text-muted">Pilih filter lalu klik Proses.</td></tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('javascript')
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
|
||||||
|
<script src="{{ asset('vendor/sweetalert2/dist/sweetalert2.min.js') }}"></script>
|
||||||
|
<script src="{{ asset('vendors/chart.js/Chart.min.js') }}"></script>
|
||||||
|
<script>
|
||||||
|
$(function () {
|
||||||
|
const dataUrl = '{{ route('statistik.data', [], false) }}';
|
||||||
|
let chart = null;
|
||||||
|
const today = new Date().toISOString().split('T')[0];
|
||||||
|
const awal = new Date(Date.now() - 29 * 864e5).toISOString().split('T')[0];
|
||||||
|
$('#tgl-akhir').val(today);
|
||||||
|
$('#tgl-awal').val(awal);
|
||||||
|
|
||||||
|
function fmtRp(v) {
|
||||||
|
return 'Rp ' + Number(v || 0).toLocaleString('id-ID');
|
||||||
|
}
|
||||||
|
function fmtN(v) {
|
||||||
|
return Number(v || 0).toLocaleString('id-ID');
|
||||||
|
}
|
||||||
|
function labelPeriode(p, grup) {
|
||||||
|
if (grup === 'bulan') {
|
||||||
|
const d = new Date(p + 'T00:00:00');
|
||||||
|
return d.toLocaleDateString('id-ID', { month: 'short', year: 'numeric' });
|
||||||
|
}
|
||||||
|
if (grup === 'minggu') return 'Minggu ' + p;
|
||||||
|
const d = new Date(p + 'T00:00:00');
|
||||||
|
return d.toLocaleDateString('id-ID', { day: '2-digit', month: 'short' });
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawChart(rows, grup) {
|
||||||
|
const ctx = document.getElementById('chart-statistik');
|
||||||
|
if (chart) chart.destroy();
|
||||||
|
chart = new Chart(ctx, {
|
||||||
|
type: 'bar',
|
||||||
|
data: {
|
||||||
|
labels: rows.map(r => labelPeriode(r.periode, grup)),
|
||||||
|
datasets: [
|
||||||
|
{ label: 'Tunai', data: rows.map(r => Number(r.tunai)), backgroundColor: '#198754' },
|
||||||
|
{ label: 'Cashless', data: rows.map(r => Number(r.cashless)), backgroundColor: '#0dcaf0' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
scales: { y: { beginAtZero: true, ticks: { callback: v => (v / 1000) + 'rb' } } },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#filter-statistik').on('submit', function () {
|
||||||
|
const btn = $('#btn-proses'); const btnHtml = btn.html();
|
||||||
|
btn.prop('disabled', true).html('<span class="spinner-border spinner-border-sm me-1"></span>Memproses...');
|
||||||
|
$('#body-statistik').html('<tr><td colspan="6" class="text-center text-muted py-4"><span class="spinner-border spinner-border-sm me-2"></span>Memuat statistik...</td></tr>');
|
||||||
|
const grup = $('#grup').val();
|
||||||
|
$.ajax({
|
||||||
|
url: dataUrl,
|
||||||
|
type: 'GET',
|
||||||
|
data: {
|
||||||
|
grup: grup,
|
||||||
|
tgl_awal: $('#tgl-awal').val(),
|
||||||
|
tgl_akhir: $('#tgl-akhir').val(),
|
||||||
|
status_transaksi: $('#status-transaksi').val(),
|
||||||
|
cara: $('#cara').val(),
|
||||||
|
},
|
||||||
|
success: function (r) {
|
||||||
|
const s = r.ringkasan || {};
|
||||||
|
$('#sum-trx').text(fmtN(s.transaksi) + ' trx');
|
||||||
|
$('#sum-keluar').text(fmtN(s.keluar) + ' trx');
|
||||||
|
$('#sum-pendapatan').text(fmtRp(s.pendapatan));
|
||||||
|
$('#sum-tunai').text(fmtRp(s.tunai));
|
||||||
|
$('#sum-cashless').text(fmtRp(s.cashless));
|
||||||
|
if (!r.data.length) {
|
||||||
|
$('#body-statistik').html('<tr><td colspan="6" class="text-center">Data tidak ditemukan.</td></tr>');
|
||||||
|
if (chart) chart.destroy();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let html = '';
|
||||||
|
r.data.forEach(function (row) {
|
||||||
|
html += '<tr><td>' + labelPeriode(row.periode, grup) + '</td>'
|
||||||
|
+ '<td class="text-end">' + fmtN(row.transaksi) + '</td>'
|
||||||
|
+ '<td class="text-end">' + fmtN(row.keluar) + '</td>'
|
||||||
|
+ '<td class="text-end">' + fmtRp(row.pendapatan) + '</td>'
|
||||||
|
+ '<td class="text-end">' + fmtRp(row.tunai) + '</td>'
|
||||||
|
+ '<td class="text-end">' + fmtRp(row.cashless) + '</td></tr>';
|
||||||
|
});
|
||||||
|
$('#body-statistik').html(html);
|
||||||
|
drawChart(r.data, grup);
|
||||||
|
},
|
||||||
|
error: function (xhr) {
|
||||||
|
let msg = 'Gagal memuat statistik.';
|
||||||
|
if (xhr.responseJSON?.message) msg = xhr.responseJSON.message;
|
||||||
|
else if (xhr.status === 422 && xhr.responseJSON?.errors) msg = Object.values(xhr.responseJSON.errors).flat().join(' ');
|
||||||
|
$('#body-statistik').html('<tr><td colspan="6" class="text-center text-danger">' + msg + '</td></tr>');
|
||||||
|
Swal.fire({icon: 'error', title: 'Gagal memuat', text: msg});
|
||||||
|
},
|
||||||
|
complete: function () {
|
||||||
|
btn.prop('disabled', false).html(btnHtml);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#filter-statistik').submit();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@endsection
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
<form class="ubah-member" id="edit-member" methode="POST">
|
<form class="ubah-member" id="edit-member" methode="POST">
|
||||||
@csrf
|
@csrf
|
||||||
@method('PUT')
|
@method('PUT')
|
||||||
|
<input type="hidden" name="notrans" id="edit-notrans">
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
<div class="tab-pane fade show active" id="edit-data" role="tabpanel">
|
<div class="tab-pane fade show active" id="edit-data" role="tabpanel">
|
||||||
<div class="pt-4">
|
<div class="pt-4">
|
||||||
@@ -63,7 +64,7 @@
|
|||||||
<div class="mb-3 row">
|
<div class="mb-3 row">
|
||||||
<label class="col-lg-3 col-form-label form-label">Jenis</label>
|
<label class="col-lg-3 col-form-label form-label">Jenis</label>
|
||||||
<div class="col-lg-6">
|
<div class="col-lg-6">
|
||||||
<select class="select-data form-control" name="member" id="member">
|
<select class="select-data form-control" name="member" id="edit-member-sel">
|
||||||
<option selected value="">Pilih Jenis</option>
|
<option selected value="">Pilih Jenis</option>
|
||||||
@foreach ($memberSelect as $member)
|
@foreach ($memberSelect as $member)
|
||||||
<option value="{{ $member->id }}">{{ $member->nama }}</option>
|
<option value="{{ $member->id }}">{{ $member->nama }}</option>
|
||||||
@@ -74,7 +75,7 @@
|
|||||||
<div class="mb-3 row">
|
<div class="mb-3 row">
|
||||||
<label class="col-lg-3 col-form-label form-label">Dept</label>
|
<label class="col-lg-3 col-form-label form-label">Dept</label>
|
||||||
<div class="col-lg-6">
|
<div class="col-lg-6">
|
||||||
<select class="select-data form-control" name="depart" id="department">
|
<select class="select-data form-control" name="depart" id="edit-department">
|
||||||
<option selected value="">Pilih Departemen</option>
|
<option selected value="">Pilih Departemen</option>
|
||||||
@foreach ($departmentSelect as $department)
|
@foreach ($departmentSelect as $department)
|
||||||
<option value="{{ $department->kode }}">{{ $department->nama }}</option>
|
<option value="{{ $department->kode }}">{{ $department->nama }}</option>
|
||||||
@@ -104,12 +105,12 @@
|
|||||||
<div class="row form-material">
|
<div class="row form-material">
|
||||||
<div class="col-xl-3 col-md-6 mb-3">
|
<div class="col-xl-3 col-md-6 mb-3">
|
||||||
<label class="form-label">Nomer Polisi</label>
|
<label class="form-label">Nomer Polisi</label>
|
||||||
<input type="text" class="form-control nopol-add" onkeyup="this.value = this.value.toUpperCase();" placeholder="No. Polisi">
|
<input type="text" class="form-control enopol-add" onkeyup="this.value = this.value.toUpperCase();" placeholder="No. Polisi">
|
||||||
<div class="invalid-feedback">Nomer Polisi sudah ada</div>
|
<div class="invalid-feedback">Nomer Polisi sudah ada</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xl-3 col-md-6 mb-3">
|
<div class="col-xl-3 col-md-6 mb-3">
|
||||||
<label class="form-label">Jenis Kendaraan :</label>
|
<label class="form-label">Jenis Kendaraan :</label>
|
||||||
<select class="select form-control" id="jenisVehicle">
|
<select class="select form-control" id="edit-jenisVehicle">
|
||||||
<option selected value="">Jenis Kendaraan</option>
|
<option selected value="">Jenis Kendaraan</option>
|
||||||
@foreach ($vehicleSelect as $kendaraan)
|
@foreach ($vehicleSelect as $kendaraan)
|
||||||
<option value="{{ $kendaraan->id }}">{{ $kendaraan->nama }}</option>
|
<option value="{{ $kendaraan->id }}">{{ $kendaraan->nama }}</option>
|
||||||
@@ -118,16 +119,16 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-xl-3 col-md-6 mb-3">
|
<div class="col-xl-3 col-md-6 mb-3">
|
||||||
<label class="form-label">Jenis Member :</label>
|
<label class="form-label">Jenis Member :</label>
|
||||||
<select class="select-data form-control member" id="jenis-member">
|
<select class="select-data form-control member" id="edit-jenis-member">
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xl-3 col-md-6 mb-3">
|
<div class="col-xl-3 col-md-6 mb-3">
|
||||||
<label class="form-label">Merk : </label>
|
<label class="form-label">Merk : </label>
|
||||||
<input type="text" class="form-control merk" onkeyup="this.value = this.value.toUpperCase();" placeholder="Honda...">
|
<input type="text" class="form-control emerk" onkeyup="this.value = this.value.toUpperCase();" placeholder="Honda...">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xl-3 col-md-6 mb-3">
|
<div class="col-xl-3 col-md-6 mb-3">
|
||||||
<label class="form-label"></label>
|
<label class="form-label"></label>
|
||||||
<button type="button" id="nopol-add" class="btn btn-primary btn-xs">Tambah</button>
|
<button type="button" id="edit-nopol-add" class="btn btn-primary btn-xs">Tambah</button>
|
||||||
</div>
|
</div>
|
||||||
<hr>
|
<hr>
|
||||||
<table class="table-bordered table-striped">
|
<table class="table-bordered table-striped">
|
||||||
@@ -140,7 +141,7 @@
|
|||||||
<th class="col-2 text-center">Aksi</th>
|
<th class="col-2 text-center">Aksi</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody id="list-nopol">
|
<tbody id="edit-list-nopol">
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
@@ -152,11 +153,11 @@
|
|||||||
<div class="row form-material">
|
<div class="row form-material">
|
||||||
<div class="col-xl-6 col-md-6 mb-3">
|
<div class="col-xl-6 col-md-6 mb-3">
|
||||||
<label class="form-label">Nomer Kartu</label>
|
<label class="form-label">Nomer Kartu</label>
|
||||||
<input type="text" class="form-control kartu" placeholder="01234567...">
|
<input type="text" class="form-control ekartu" placeholder="01234567...">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xl-6 col-md-6 mb-3">
|
<div class="col-xl-6 col-md-6 mb-3">
|
||||||
<label class="form-label">Nomer Urut</label>
|
<label class="form-label">Nomer Urut</label>
|
||||||
<input type="text" class="form-control nourut" placeholder="01234567...">
|
<input type="text" class="form-control enourut" placeholder="01234567...">
|
||||||
</div>
|
</div>
|
||||||
<hr>
|
<hr>
|
||||||
{{-- <div class="table-responsive"> --}}
|
{{-- <div class="table-responsive"> --}}
|
||||||
@@ -168,7 +169,7 @@
|
|||||||
<th class="col-2 text-center">Aksi</th>
|
<th class="col-2 text-center">Aksi</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody id="list-card">
|
<tbody id="edit-list-card">
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{{-- </div> --}}
|
{{-- </div> --}}
|
||||||
@@ -181,7 +182,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-danger light" data-bs-dismiss="modal">Close</button>
|
<button type="button" class="btn btn-danger light" data-bs-dismiss="modal">Close</button>
|
||||||
<button type="button" class="btn btn-primary simpan">Simpan Perubahan</button>
|
<button type="button" class="btn btn-primary simpan-ubah">Simpan Perubahan</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -105,6 +105,7 @@
|
|||||||
Route::post("stiker/data", [MemberStikerController::class, "getMember"])->name("getMember");
|
Route::post("stiker/data", [MemberStikerController::class, "getMember"])->name("getMember");
|
||||||
// ->where(["stiker"] => '.*');
|
// ->where(["stiker"] => '.*');
|
||||||
Route::post("stiker/checkField", [MemberStikerController::class, "checkField"]);
|
Route::post("stiker/checkField", [MemberStikerController::class, "checkField"]);
|
||||||
|
Route::post("stiker/extend-old", [MemberStikerController::class, "extendOld"])->name("stiker.extendOld");
|
||||||
Route::resource("member", MemberStikerController::class);
|
Route::resource("member", MemberStikerController::class);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -118,6 +119,8 @@
|
|||||||
);
|
);
|
||||||
Route::get("/laporan-per-pintu", [ReportTransaksiController::class, "byGate"]);
|
Route::get("/laporan-per-pintu", [ReportTransaksiController::class, "byGate"]);
|
||||||
Route::get("/laporan-per-pintu/data", [ReportTransaksiController::class, "gateData"])->name("gateData");
|
Route::get("/laporan-per-pintu/data", [ReportTransaksiController::class, "gateData"])->name("gateData");
|
||||||
|
Route::get("/statistik", [ReportTransaksiController::class, "statistik"])->name("statistik");
|
||||||
|
Route::get("/statistik/data", [ReportTransaksiController::class, "statistikData"])->name("statistik.data");
|
||||||
|
|
||||||
Route::prefix("stiker")->group(function () {
|
Route::prefix("stiker")->group(function () {
|
||||||
Route::get("/harian", [LaporanStiker::class, "laporanStikerHarian"]);
|
Route::get("/harian", [LaporanStiker::class, "laporanStikerHarian"]);
|
||||||
|
|||||||
Reference in New Issue
Block a user