let lastResponse = null; $(document).ready(function () { // $("#modaltanggal").modal("show"); // const hariIni = flatpickr("#tanggalCari", { // dateFormat: "Y-m-d", // ini yang tampil ke user // altInput: true, // altFormat: "Y-m-d", // defaultDate: "today", // onChange: function (selectedDate, dateStr, instance) { // loadData(); // }, // }); // const date = $("#tanggalCari").datepicker({ format: "yyyy-mm-dd", autoclose: true, todayHighlight: true, }); $("#tanggalCari").datepicker("setDate", new Date()); $("#tanggalCari").on("changeDate", function (e) { const tanggalCari = $("#tanggalCari").val(); $("#tanggal-trans").text("Tanggal : " + tanggalCari); loadData(); }); const tanggalCari = $("#tanggalCari").val(); // $("#harianToggle").on("change", loadData); // Set tanggal default ke hari ini // console.log("value asli (ke server):", $("#tanggalCari").val()); // console.log("value tampilan:", $("input[data-input]").val()); // tampilan: 30-07-2026 // realtime trigger // $("#tanggalCari").on("change", $("#tanggalCari").val()); $("#harianToggle").on("change", loadData); // var today = Date.now().format("yyyy-mm-dd"); // $("#tanggalCari").val(); // $("#tanggalCari").val(getToday()); loadData(); // lastResponse = loadData(); // $('.btn-export-excel').on('click', function () { $(document).on("click", ".btn-export-excel", function (e) { // e.preventDefault(); $("#cash td").each(function () { const raw = $(this).data("value"); if (raw !== undefined) { $(this).text(raw); } }); const table = document.getElementById("cetak"); const wb = XLSX.utils.table_to_book(table, { sheet: "Sheet 1" }); XLSX.writeFile(wb, `monthlyReport.xlsx`); console.log(e); }); $(".btn-export-pdf").on("click", async function () { // $('.cetak').css('display','block'); // $('.user').css('display','block'); // const { jsPDF } = window.jspdf; // const doc = new jsPDF("p", "pt", "a4"); // // ambil elemen tabel // const table = document.getElementById("cetak"); // const canvas = await html2canvas(table, { scale: 2 }); // const imgData = canvas.toDataURL("image/png"); // const imgWidth = doc.internal.pageSize.getWidth(); // const imgHeight = (canvas.height * imgWidth) / canvas.width; // doc.addImage(imgData, "PNG", 0, 20, imgWidth, imgHeight); // doc.save(`Rekap Harian.pdf`); // // jsPDF Autotable if (!lastResponse) { alert("Data belum tersedia"); return; } printPDF(lastResponse.vehicle); }); // console.log(document.getElementById("cetak")); // console.log(document.getElementById("date-table")); }); function loadData(tanggalMulai, tanggalAkhir) { let tanggal = $("#tanggalCari").val(); let harian = $("#harianToggle").is(":checked") ? 1 : 0; if (harian == 1) $("#harian").text("By : Harian"); else $("#harian").text("By : Shift"); // console.log(harian); // console.log(tanggal); if (!tanggal) return; // Contoh: Load data dengan AJAX $.ajax({ url: "/report/laporan-semua-transaksi/vehicle", // Ganti dengan route Anda type: "GET", data: { tanggal: tanggal, harian: harian, }, beforeSend: function () { console.log("Loading data..."); }, success: function (response) { lastResponse = response; // ✅ tambah ini tableVehicle(response.vehicle); tableOfficer(response.officer); tablePayment(response.payment); // // Update tabel dengan data yang diterima // let html = ""; // let onData = ""; // let jmlCashCasual = 0; // let incomeCashCasual = 0; // let jmlCashlessCasual = 0; // let incomeCashlessCasual = 0; // let grandTotal = 0; // response.tunai.forEach(function (cash) { // // cari pasangan non tunai // let cashless = response.nontunai.find((nt) => String(nt.id_kendaraan) === String(cash.id_kendaraan)); // // fallback aman // cashless = cashless || { // nontunai: 0, // nonTunaiOut: 0, // keluar: { // casual: { jumlah: 0, income: 0 }, // lost: { jumlah: 0, income: 0 }, // member: { jumlah: 0, income: 0 }, // }, // totalCashless: 0, // }; // let casualIn = cash.total; // let tunaiOut = cash.tunaiOut; // // ===== DATA TUNAI ===== // let tCasual = cash.keluar.casual; // let tLost = cash.keluar.lost; // let tMember = cash.keluar.member; // let tManual = cash.keluar.manual; // // ===== DATA NON TUNAI ===== // let nonTunaiOut = cashless.nonTunaiOut; // let nCasual = cashless.keluar.casual; // let nLost = cashless.keluar.lost; // let nMember = cashless.keluar.member; // let nManual = cashless.keluar.manual; // let totalTunai = cash.totalCash || 0; // let totalNonTunai = cashless.totalCashless || 0; // jmlCashCasual += cash.keluar.casual.jumlah; // incomeCashCasual += cash.keluar.casual.income; // jmlCashlessCasual += cashless.keluar.casual.jumlah; // incomeCashlessCasual += cashless.keluar.casual.income; // grandTotal += totalTunai + totalNonTunai; // // let casualCash = cash.keluar.casual; // // let lostCash = cash.keluar.lost; // // let memberCash = cash.keluar.member; // // let casualIn = cash.total; // // let casualNon = cashless ? cashless.keluar.casual : { jumlah: 0, income: 0 }; // // let lostNon = cashless ? cashless.keluar.lost : { jumlah: 0, income: 0 }; // // let memberNon = cashless ? cashless.keluar.member : { jumlah: 0, income: 0 }; // // let totalIncome = // // (cash.totalCash || 0); // // html += ` // // // // ${cash.jenis_mobil} // // // // ${casualIn} // // ${cash.tunaiOut} // // // // ${casualCash.jumlah} // // ${rupiah(casualCash.income)} // // // // ${lostCash.jumlah} // // ${rupiah(lostCash.income)} // // // // ${memberCash.jumlah} // // ${rupiah(memberCash.income)} // // // // 0 // // 0 // // // // 0 // // 0 // // // // 0 // // 0 // // // // ${rupiah(totalIncome)} // // // // `; // html += ` // // ${cash.jenis_mobil} // Tunai // ${casualIn} // ${tunaiOut} // ${tCasual.jumlah} // ${rupiah(tCasual.income)} // ${tLost.jumlah} // ${rupiah(tLost.income)} // ${tMember.jumlah} // ${rupiah(tMember.income)} // ${tManual.jumlah} // ${rupiah(tManual.income)} // 0 // 0 // 0 // 0 // ${rupiah(totalTunai)} // // // Non Tunai // ${casualIn} // ${nonTunaiOut} // ${nCasual.jumlah} // ${rupiah(nCasual.income)} // ${nLost.jumlah} // ${rupiah(nLost.income)} // ${nMember.jumlah} // ${rupiah(nMember.income)} // ${nManual.jumlah} // ${rupiah(nManual.income)} // 0 // 0 // 0 // 0 // ${rupiah(totalNonTunai)} // // `; // }); // // ===== FOOTER TOTAL ===== // html += ` // // TOTAL // Tunai // 0 // 0 // ${rupiah(jmlCashCasual)} // ${rupiah(incomeCashCasual)} // 0 // // // NON TUNAI // 0 // 0 // ${jmlCashlessCasual} // ${rupiah(incomeCashlessCasual)} // 0 // // // GRAND TOTAL // // ${jmlCashCasual + jmlCashlessCasual} // ${rupiah(incomeCashCasual + incomeCashlessCasual)} // // // // // // // // // // // ${rupiah(grandTotal)} // // `; // // console.log('TUNAI:', cash.id_kendaraan, cash); // // console.log('CASHLESS FOUND:', cashless); // $("#table-data").html(html); // response.overNight.forEach(function (on) { // if (!on.jenis_mobil) return; // let overnight = on.overNight; // let onExpired = on.onExpired; // onData += ` // // ${on.jenis_mobil} // ${overnight} // ${onExpired} // 0 // // `; // }); // $("#table-overnight").html(onData); // console.log(response); }, error: function (xhr) { console.log("Error:", xhr); alert("Terjadi kesalahan saat memuat data"); }, }); } function rupiah(angka) { return new Intl.NumberFormat("id-ID").format(angka || 0); } function getToday() { const d = new Date(); const tgl = String(d.getDate()).padStart(2, "0"); const bulan = String(d.getMonth() + 1).padStart(2, "0"); const tahun = d.getFullYear(); return `${tgl}-${bulan}-${tahun}`; } function tableVehicle(response) { // Update tabel dengan data yang diterima let html = ""; let onData = ""; let jmlCashCasual = 0; let incomeCashCasual = 0; let jmlCashlessCasual = 0; let incomeCashlessCasual = 0; let grandTotal = 0; response.tunai.forEach(function (cash) { // cari pasangan non tunai let cashless = response.nontunai.find((nt) => String(nt.id_kendaraan) === String(cash.id_kendaraan)); // fallback aman cashless = cashless || { nontunai: 0, nonTunaiOut: 0, keluar: { casual: { jumlah: 0, income: 0 }, lost: { jumlah: 0, income: 0 }, member: { jumlah: 0, income: 0 }, }, totalCashless: 0, }; let casualIn = cash.total; let tunaiOut = cash.tunaiOut; // ===== DATA TUNAI ===== let tCasual = cash.keluar.casual; let tLost = cash.keluar.lost; let tMember = cash.keluar.member; let tManual = cash.keluar.manual; // ===== DATA NON TUNAI ===== let nonTunaiOut = cashless.nonTunaiOut; let nCasual = cashless.keluar.casual; let nLost = cashless.keluar.lost; let nMember = cashless.keluar.member; let nManual = cashless.keluar.manual; let totalTunai = cash.totalCash || 0; let totalNonTunai = cashless.totalCashless || 0; jmlCashCasual += cash.keluar.casual.jumlah; incomeCashCasual += cash.keluar.casual.income; jmlCashlessCasual += cashless.keluar.casual.jumlah; incomeCashlessCasual += cashless.keluar.casual.income; grandTotal += totalTunai + totalNonTunai; // let casualCash = cash.keluar.casual; // let lostCash = cash.keluar.lost; // let memberCash = cash.keluar.member; // let casualIn = cash.total; // let casualNon = cashless ? cashless.keluar.casual : { jumlah: 0, income: 0 }; // let lostNon = cashless ? cashless.keluar.lost : { jumlah: 0, income: 0 }; // let memberNon = cashless ? cashless.keluar.member : { jumlah: 0, income: 0 }; // let totalIncome = // (cash.totalCash || 0); // html += ` // // ${cash.jenis_mobil} // // ${casualIn} // ${cash.tunaiOut} // // ${casualCash.jumlah} // ${rupiah(casualCash.income)} // // ${lostCash.jumlah} // ${rupiah(lostCash.income)} // // ${memberCash.jumlah} // ${rupiah(memberCash.income)} // // 0 // 0 // // 0 // 0 // // 0 // 0 // // ${rupiah(totalIncome)} // // `; html += ` ${cash.jenis_mobil} Tunai ${casualIn} ${tunaiOut} ${tCasual.jumlah} ${rupiah(tCasual.income)} ${tLost.jumlah} ${rupiah(tLost.income)} ${tMember.jumlah} ${rupiah(tMember.income)} ${tManual.jumlah} ${rupiah(tManual.income)} 0 0 0 0 ${rupiah(totalTunai)} Non Tunai ${casualIn} ${nonTunaiOut} ${nCasual.jumlah} ${rupiah(nCasual.income)} ${nLost.jumlah} ${rupiah(nLost.income)} ${nMember.jumlah} ${rupiah(nMember.income)} ${nManual.jumlah} ${rupiah(nManual.income)} 0 0 0 0 ${rupiah(totalNonTunai)} `; }); // ===== FOOTER TOTAL ===== html += ` TOTAL Tunai 0 0 ${rupiah(jmlCashCasual)} ${rupiah(incomeCashCasual)} ${rupiah(incomeCashCasual)} NON TUNAI 0 0 ${jmlCashlessCasual} ${rupiah(incomeCashlessCasual)} ${rupiah(incomeCashlessCasual)} GRAND TOTAL ${jmlCashCasual + jmlCashlessCasual} ${rupiah(incomeCashCasual + incomeCashlessCasual)} ${rupiah(grandTotal)} `; // console.log('TUNAI:', cash.id_kendaraan, cash); // console.log('CASHLESS FOUND:', cashless); $("#table-data").html(html); response.overNight.forEach(function (on) { if (!on.jenis_mobil) return; let overnight = on.overNight; let onExpired = on.onExpired; onData += ` ${on.jenis_mobil} ${overnight} ${onExpired} 0 `; }); $("#table-overnight").html(onData); console.log(response); } function tableOfficer(response) { // Update tabel dengan data yang diterima console.log(response); let html = ""; let onData = ""; let jmlCashCasual = 0; let incomeCashCasual = 0; let jmlCashlessCasual = 0; let incomeCashlessCasual = 0; let grandTotal = 0; response.tunai.forEach(function (cash) { // cari pasangan non tunai let cashless = response.nontunai.find((nt) => String(nt.id_petugas) === String(cash.id_petugas)); // fallback aman cashless = cashless || { nontunai: 0, nonTunaiOut: 0, keluar: { casual: { jumlah: 0, income: 0 }, lost: { jumlah: 0, income: 0 }, member: { jumlah: 0, income: 0 }, }, totalCashless: 0, }; let petugas = cash.petugas === null ? "NO-OP" : cash.petugas; let casualIn = cash.total; let tunaiOut = cash.tunaiOut; // ===== DATA TUNAI ===== let tCasual = cash.keluar.casual; let tLost = cash.keluar.lost; let tMember = cash.keluar.member; let tManual = cash.keluar.manual; // ===== DATA NON TUNAI ===== let nonTunaiOut = cashless.nonTunaiOut; let nCasual = cashless.keluar.casual; let nLost = cashless.keluar.lost; let nMember = cashless.keluar.member; let nManual = cashless.keluar.manual ?? 0; let totalTunai = cash.totalCash || 0; let totalNonTunai = cashless.totalCashless || 0; jmlCashCasual += cash.keluar.casual.jumlah; incomeCashCasual += cash.keluar.casual.income; jmlCashlessCasual += cashless.keluar.casual.jumlah; incomeCashlessCasual += cashless.keluar.casual.income; grandTotal += totalTunai + totalNonTunai; // let casualCash = cash.keluar.casual; // let lostCash = cash.keluar.lost; // let memberCash = cash.keluar.member; // let casualIn = cash.total; // let casualNon = cashless ? cashless.keluar.casual : { jumlah: 0, income: 0 }; // let lostNon = cashless ? cashless.keluar.lost : { jumlah: 0, income: 0 }; // let memberNon = cashless ? cashless.keluar.member : { jumlah: 0, income: 0 }; // let totalIncome = // (cash.totalCash || 0); // html += ` // // ${cash.jenis_mobil} // // ${casualIn} // ${cash.tunaiOut} // // ${casualCash.jumlah} // ${rupiah(casualCash.income)} // // ${lostCash.jumlah} // ${rupiah(lostCash.income)} // // ${memberCash.jumlah} // ${rupiah(memberCash.income)} // // 0 // 0 // // 0 // 0 // // 0 // 0 // // ${rupiah(totalIncome)} // // `; html += ` ${petugas} Tunai ${casualIn} ${tunaiOut} ${tCasual.jumlah} ${rupiah(tCasual.income)} ${tLost.jumlah} ${rupiah(tLost.income)} ${tMember.jumlah} ${rupiah(tMember.income)} ${tManual.jumlah} ${rupiah(tManual.income)} 0 0 0 ${rupiah(totalTunai)} Non Tunai ${casualIn} ${nonTunaiOut} ${nCasual.jumlah} ${rupiah(nCasual.income)} ${nLost.jumlah} ${rupiah(nLost.income)} ${nMember.jumlah} ${rupiah(nMember.income)} ${nManual.jumlah} ${rupiah(nManual.income)} 0 0 0 0 ${rupiah(totalNonTunai)} `; }); // ===== FOOTER TOTAL ===== html += ` TOTAL Tunai 0 0 ${rupiah(jmlCashCasual)} ${rupiah(incomeCashCasual)} ${rupiah(incomeCashCasual)} NON TUNAI 0 0 ${jmlCashlessCasual} ${rupiah(incomeCashlessCasual)} ${rupiah(incomeCashlessCasual)} GRAND TOTAL ${jmlCashCasual + jmlCashlessCasual} ${rupiah(incomeCashCasual + incomeCashlessCasual)} ${rupiah(grandTotal)} `; // console.log('TUNAI:', cash.id_kendaraan, cash); // console.log('CASHLESS FOUND:', cashless); $("#officer-data").html(html); // response.overNight.forEach(function (on) { // if (!on.jenis_mobil) return; // let overnight = on.overNight; // let onExpired = on.onExpired; // onData += ` // // ${on.jenis_mobil} // ${overnight} // ${onExpired} // 0 // // `; // }); // $("#table-overnight").html(onData); // console.log(response); } function tablePayment(response) { // Update tabel dengan data yang diterima console.log(response); let html = ""; let onData = ""; let jmlCashCasual = 0; let incomeCashCasual = 0; let jmlCashlessCasual = 0; let incomeCashlessCasual = 0; let grandTotal = 0; response.tunai.forEach(function (cash) { // cari pasangan non tunai let cashless = response.nontunai.find((nt) => String(nt.typePayment) === String(cash.typePayment)); // fallback aman cashless = cashless || { nontunai: 0, nonTunaiOut: 0, keluar: { casual: { jumlah: 0, income: 0 }, lost: { jumlah: 0, income: 0 }, member: { jumlah: 0, income: 0 }, }, totalCashless: 0, }; let payment = paymentType(cash.typePayment); // let payment = cash.typePayment; let casualIn = cash.total; let tunaiOut = cash.tunaiOut; // ===== DATA TUNAI ===== let tCasual = cash.keluar.casual; let tLost = cash.keluar.lost; let tMember = cash.keluar.member; let tManual = cash.keluar.manual; // ===== DATA NON TUNAI ===== let nonTunaiOut = cashless.nonTunaiOut; let nCasual = cashless.keluar.casual; let nLost = cashless.keluar.lost; let nMember = cashless.keluar.member; let nManual = cashless.keluar.manual ?? 0; let totalTunai = cash.totalCash || 0; let totalNonTunai = cashless.totalCashless || 0; jmlCashCasual += cash.keluar.casual.jumlah; incomeCashCasual += cash.keluar.casual.income; jmlCashlessCasual += cashless.keluar.casual.jumlah; incomeCashlessCasual += cashless.keluar.casual.income; grandTotal += totalTunai + totalNonTunai; html += ` ${payment} Tunai ${casualIn} ${tunaiOut} ${tCasual.jumlah} ${rupiah(tCasual.income)} ${tLost.jumlah} ${rupiah(tLost.income)} ${tMember.jumlah} ${rupiah(tMember.income)} ${tManual.jumlah} ${rupiah(tManual.income)} 0 0 0 ${rupiah(totalTunai)} Non Tunai ${casualIn} ${nonTunaiOut} ${nCasual.jumlah} ${rupiah(nCasual.income)} ${nLost.jumlah} ${rupiah(nLost.income)} ${nMember.jumlah} ${rupiah(nMember.income)} ${nManual.jumlah} ${rupiah(nManual.income)} 0 0 0 0 ${rupiah(totalNonTunai)} `; }); // ===== FOOTER TOTAL ===== html += ` TOTAL Tunai 0 0 ${rupiah(jmlCashCasual)} ${rupiah(incomeCashCasual)} ${rupiah(incomeCashCasual)} NON TUNAI 0 0 ${jmlCashlessCasual} ${rupiah(incomeCashlessCasual)} ${rupiah(incomeCashlessCasual)} GRAND TOTAL ${jmlCashCasual + jmlCashlessCasual} ${rupiah(incomeCashCasual + incomeCashlessCasual)} ${rupiah(grandTotal)} `; // console.log('TUNAI:', cash.id_kendaraan, cash); // console.log('CASHLESS FOUND:', cashless); $("#payment-data").html(html); } function paymentType(value) { switch (value) { case 2: value = "Mandiri"; break; case 3: value = "BRIZZI"; break; case 4: value = "TapCash"; break; case 5: value = "Flazz"; break; case 9: value = "QRIS"; break; default: value = "Tunai"; } return value; } function printPDF(vehicle) { const { jsPDF } = window.jspdf; const doc = new jsPDF({ orientation: "portait", // portrait kesempitan buat 16 kolom unit: "mm", format: "a4", }); const pageWidth = doc.internal.pageSize.getWidth(); // ===== HEADER ===== doc.setFont("helvetica", "bold"); doc.setFontSize(12); doc.text("MENTENG SQUARE - RAYA PARKING - RAYA Parking", 14, 12); doc.setFontSize(11); doc.text("Rekap Transaksi Kendaraan", pageWidth / 2, 18, { align: "center" }); doc.setFont("helvetica", "normal"); doc.setFontSize(9); doc.text("Tanggal : " + (vehicle.date ?? "-"), pageWidth / 2, 23, { align: "center" }); doc.text("By : Harian", pageWidth - 14, 12, { align: "right" }); // ===== SUSUN BODY TABEL ===== const body = []; let totalTunaiJml = 0, totalTunaiNilai = 0; let totalNonTunaiJml = 0, totalNonTunaiNilai = 0; let grandTotal = 0; vehicle.tunai.forEach(function (cash) { const cashless = vehicle.nontunai.find((nt) => String(nt.id_kendaraan) === String(cash.id_kendaraan)) || { nonTunaiOut: 0, keluar: { casual: { jumlah: 0, income: 0 }, lost: { jumlah: 0, income: 0 }, member: { jumlah: 0, income: 0 }, manual: { jumlah: 0, income: 0 }, }, totalCashless: 0, }; // debugger; const tCasual = cash.keluar.casual; const tLost = cash.keluar.lost; const tMember = cash.keluar.member; const tManual = cash.keluar.manual; const tMasalah = cash.keluar.masalah ?? { jumlah: 0, income: 0 }; const totalTunai = cash.totalCash || 0; const nCasual = cashless.keluar.casual; const nLost = cashless.keluar.lost; const nMember = cashless.keluar.member; const nManual = cashless.keluar.manual; const nMasalah = cashless.keluar.masalah ?? { jumlah: 0, income: 0 }; const totalNonTunai = cashless.totalCashless || 0; // baris TUNAI body.push([ { content: cash.jenis_mobil, rowSpan: 2, styles: { valign: "middle" } }, { content: "Tunai", styles: { fillColor: [40, 167, 69], textColor: 255, fontStyle: "bold" } }, cash.total, cash.tunaiOut, tCasual.jumlah, rupiah(tCasual.income), tLost.jumlah, rupiah(tLost.income), tMember.jumlah, rupiah(tMember.income), tManual.jumlah, rupiah(tManual.income), 0, 0, tMasalah.jumlah, rupiah(tMasalah.income), { content: rupiah(cash.totalCash), styles: { valign: "middle", fontStyle: "bold" } }, ]); // baris NON TUNAI body.push([ { content: "Non Tunai", styles: { fillColor: [255, 193, 7], textColor: 0, fontStyle: "bold" } }, cash.total, cashless.nonTunaiOut, nCasual.jumlah, rupiah(nCasual.income), nLost.jumlah, // rupiah(nLost.income), cash.totalCashless, nMember.jumlah, rupiah(nMember.income), nManual.jumlah, rupiah(nManual.income), 0, 0, nMasalah.jumlah, rupiah(nMasalah.income), { content: rupiah(cashless.totalCashless), styles: { valign: "middle", fontStyle: "bold" } }, ]); totalTunaiJml += tCasual.jumlah + tLost.jumlah + tMember.jumlah + tManual.jumlah + tMasalah.jumlah; totalTunaiNilai += cash.totalCash || 0; totalNonTunaiJml += nCasual.jumlah + nLost.jumlah + nMember.jumlah + nManual.jumlah + nMasalah.jumlah; totalNonTunaiNilai += cashless.totalCashless || 0; grandTotal += (cash.totalCash || 0) + (cashless.totalCashless || 0); }); // baris TOTAL & GRAND TOTAL body.push([ { content: "TOTAL", rowSpan: 2, styles: { fontStyle: "bold" } }, { content: "Tunai", styles: { fillColor: [40, 167, 69], textColor: 255, fontStyle: "bold" } }, "", "", { content: totalTunaiJml, styles: { fontStyle: "bold" } }, rupiah(totalTunaiNilai), "", "", "", "", "", "", "", "", "", "", rupiah(totalTunaiNilai), ]); body.push([ { content: "NON TUNAI", styles: { fillColor: [255, 193, 7], fontStyle: "bold" } }, "", "", { content: totalNonTunaiJml, styles: { fontStyle: "bold" } }, rupiah(totalNonTunaiNilai), "", "", "", "", "", "", "", "", "", "", rupiah(totalNonTunaiNilai), ]); body.push([ { content: "GRAND TOTAL", colSpan: 4, styles: { fontStyle: "bold", halign: "center" } }, { content: totalTunaiJml + totalNonTunaiJml, styles: { fontStyle: "bold" } }, { content: rupiah(totalTunaiNilai + totalNonTunaiNilai), styles: { fontStyle: "bold" } }, "", "", "", "", "", "", "", "", "", "", "", "", { content: rupiah(grandTotal), styles: { fontStyle: "bold" } }, ]); // ===== HEADER 2 BARIS (grouping) ===== const head = [ [ { content: "Jenis Kend", rowSpan: 2, colSpan: 2 }, { content: "Jenis Transaksi", colSpan: 2 }, { content: "Casual", colSpan: 2 }, { content: "Tiket Hilang", colSpan: 2 }, { content: "Member", colSpan: 2 }, { content: "Manual Input", colSpan: 2 }, { content: "Manual Mix", colSpan: 2 }, { content: "Tiket Masalah", colSpan: 2 }, { content: "Pendapatan", rowSpan: 2 }, ], [ "Masuk", "Keluar", "JML", "Nilai", "JML", "Nilai", "JML", "Nilai", "JML", "Nilai", "JML", "Nilai", "JML", "Nilai", ], ]; doc.autoTable({ head: head, body: body, startY: 28, theme: "grid", styles: { fontSize: 6, halign: "center", valign: "middle", lineColor: [200, 200, 200] }, headStyles: { fillColor: [230, 230, 230], textColor: 0, fontStyle: "bold" }, columnStyles: { 0: { halign: "left" } }, }); // ===== TABEL OVER NIGHT (di bawah tabel utama) ===== const onBody = vehicle.overNight.map((on) => [ on.jenis_mobil ?? "-", on.overNight, on.onExpired, (on.overNight || 0) + (on.onExpired || 0), ]); doc.setFont("helvetica", "bold"); doc.setFontSize(8); doc.text("Kendaraan yang masih menginap (Over Night)", 14, doc.lastAutoTable.finalY + 10); doc.autoTable({ head: [["Jenis Kend", "Menginap", "ON (Expired)", "Total"]], body: onBody, startY: doc.lastAutoTable.finalY + 13, theme: "grid", styles: { fontSize: 7, cellPadding: 1 }, headStyles: { fontSize: 8, fillColor: [230, 230, 230], textColor: 0 }, tableWidth: 100, }); doc.save(`Rekap Harian - ${vehicle.date}.pdf`); }