i18n (Phase C batch 6): settings(JS), mikrotik, discounts, collector_payments, attendance ID/EN
This commit is contained in:
1 parent
fd13f3fa1b
commit
6ed6945970
7 files changed
+204
-72
No files matched your search
+67
-1
@@ -1781,7 +1781,73 @@
|
|||||||
"mayar_webhook": "Mayar Webhook (Mode 1 — Gateway)",
|
"mayar_webhook": "Mayar Webhook (Mode 1 — Gateway)",
|
||||||
"save": "Save Settings",
|
"save": "Save Settings",
|
||||||
"pay_mode": "Mode",
|
"pay_mode": "Mode",
|
||||||
"qris_note": "Note"
|
"qris_note": "Note",
|
||||||
|
"no_data": "No data yet.",
|
||||||
|
"ew_not_tx": "Not a transaction",
|
||||||
|
"ew_paid": "Paid",
|
||||||
|
"ew_unmatched": "Not matched"
|
||||||
|
},
|
||||||
|
"mt": {
|
||||||
|
"updating": "Updating...",
|
||||||
|
"online_list": "Online PPPoE Users",
|
||||||
|
"offline_list": "Offline PPPoE Users",
|
||||||
|
"limit_uptime": "Uptime Limit (e.g. 1h)"
|
||||||
|
},
|
||||||
|
"disc": {
|
||||||
|
"title": "Invoice Discount",
|
||||||
|
"settings_title": "Discount Settings",
|
||||||
|
"opt_selected": "Selected customers (batch)",
|
||||||
|
"opt_single": "Single customer (1 by 1)",
|
||||||
|
"opt_all": "All active customers",
|
||||||
|
"pick_customer": "Select Customer",
|
||||||
|
"ph_pick_customer": "-- select customer --",
|
||||||
|
"disc_type": "Discount Type",
|
||||||
|
"opt_percent": "Percent (%)",
|
||||||
|
"opt_amount": "Amount (Rp)",
|
||||||
|
"disc_value": "Discount Value",
|
||||||
|
"ph_value": "e.g. 10 (percent) / 20000 (Rp)",
|
||||||
|
"disc_hint": "The percentage is calculated from the base price (before VAT/USO).",
|
||||||
|
"period_month": "Billing Period — Month",
|
||||||
|
"year": "Year",
|
||||||
|
"note_opt": "Note (optional)",
|
||||||
|
"ph_note": "e.g. independence month promo",
|
||||||
|
"apply_hint": "The discount applies to <b>unpaid</b> invoices in the selected period. Paid/void invoices are unchanged. The QRIS unique code is regenerated from the new amount.",
|
||||||
|
"apply": "Apply Discount",
|
||||||
|
"selected": "selected",
|
||||||
|
"history": "Discount History (last 100)",
|
||||||
|
"th_note": "Note"
|
||||||
|
},
|
||||||
|
"cpay": {
|
||||||
|
"title": "Collector Payment Approval",
|
||||||
|
"list": "Request List",
|
||||||
|
"opt_all": "All Processes",
|
||||||
|
"opt_pending": "Needs Approval",
|
||||||
|
"opt_auto": "Collector Auto",
|
||||||
|
"opt_admin": "Approved by Admin",
|
||||||
|
"opt_cashier": "Approved by Cashier",
|
||||||
|
"opt_rejected": "Manually Rejected",
|
||||||
|
"opt_manual": "Processed Manually",
|
||||||
|
"th_invoice": "Invoice",
|
||||||
|
"th_process": "Process",
|
||||||
|
"approve": "Approve",
|
||||||
|
"reject": "Reject"
|
||||||
|
},
|
||||||
|
"att": {
|
||||||
|
"late_checkin": "Late Check-in",
|
||||||
|
"not_checkout": "Not Checked-out",
|
||||||
|
"all_attendance": "All Attendance",
|
||||||
|
"total_staff": "Total Staff",
|
||||||
|
"today": "Today",
|
||||||
|
"working": "Currently Working",
|
||||||
|
"checked_out": "Checked Out",
|
||||||
|
"late": "Late",
|
||||||
|
"after_0830": "After 08:30",
|
||||||
|
"technician": "Technician",
|
||||||
|
"cashier": "Cashier",
|
||||||
|
"checkin_time": "Check-in Time",
|
||||||
|
"duration": "Duration",
|
||||||
|
"location": "Location",
|
||||||
|
"photo": "Photo"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tech": {
|
"tech": {
|
||||||
|
|||||||
+67
-1
@@ -1782,7 +1782,73 @@
|
|||||||
"mayar_webhook": "Webhook Mayar (Mode 1 — Gateway)",
|
"mayar_webhook": "Webhook Mayar (Mode 1 — Gateway)",
|
||||||
"save": "Simpan Pengaturan",
|
"save": "Simpan Pengaturan",
|
||||||
"pay_mode": "Mode",
|
"pay_mode": "Mode",
|
||||||
"qris_note": "Catatan"
|
"qris_note": "Catatan",
|
||||||
|
"no_data": "Belum ada data.",
|
||||||
|
"ew_not_tx": "Bukan transaksi",
|
||||||
|
"ew_paid": "Lunas",
|
||||||
|
"ew_unmatched": "Belum cocok"
|
||||||
|
},
|
||||||
|
"mt": {
|
||||||
|
"updating": "Memperbarui...",
|
||||||
|
"online_list": "Daftar User PPPoE Online",
|
||||||
|
"offline_list": "Daftar User PPPoE Offline",
|
||||||
|
"limit_uptime": "Limit Uptime (e.g. 1h)"
|
||||||
|
},
|
||||||
|
"disc": {
|
||||||
|
"title": "Diskon Tagihan",
|
||||||
|
"settings_title": "Pengaturan Diskon",
|
||||||
|
"opt_selected": "Pelanggan terpilih (batch)",
|
||||||
|
"opt_single": "Satu pelanggan (1 per 1)",
|
||||||
|
"opt_all": "Semua pelanggan aktif",
|
||||||
|
"pick_customer": "Pilih Pelanggan",
|
||||||
|
"ph_pick_customer": "-- pilih pelanggan --",
|
||||||
|
"disc_type": "Tipe Diskon",
|
||||||
|
"opt_percent": "Persen (%)",
|
||||||
|
"opt_amount": "Nominal (Rp)",
|
||||||
|
"disc_value": "Nilai Diskon",
|
||||||
|
"ph_value": "mis. 10 (persen) / 20000 (Rp)",
|
||||||
|
"disc_hint": "Persen dihitung dari harga dasar (sebelum PPN/USO).",
|
||||||
|
"period_month": "Periode Tagihan — Bulan",
|
||||||
|
"year": "Tahun",
|
||||||
|
"note_opt": "Catatan (opsional)",
|
||||||
|
"ph_note": "mis. promo bulan kemerdekaan",
|
||||||
|
"apply_hint": "Diskon berlaku ke tagihan <b>belum bayar</b> pada periode terpilih. Tagihan lunas/hangus tidak diubah. Kode unik QRIS akan digenerate ulang dari nominal baru.",
|
||||||
|
"apply": "Terapkan Diskon",
|
||||||
|
"selected": "dipilih",
|
||||||
|
"history": "Riwayat Diskon (100 terakhir)",
|
||||||
|
"th_note": "Catatan"
|
||||||
|
},
|
||||||
|
"cpay": {
|
||||||
|
"title": "Approval Pembayaran Kolektor",
|
||||||
|
"list": "Daftar Request",
|
||||||
|
"opt_all": "Semua Proses",
|
||||||
|
"opt_pending": "Butuh Approval",
|
||||||
|
"opt_auto": "Auto Kolektor",
|
||||||
|
"opt_admin": "Disetujui Admin",
|
||||||
|
"opt_cashier": "Disetujui Kasir",
|
||||||
|
"opt_rejected": "Ditolak Manual",
|
||||||
|
"opt_manual": "Diproses Manual",
|
||||||
|
"th_invoice": "Tagihan",
|
||||||
|
"th_process": "Proses",
|
||||||
|
"approve": "Setujui",
|
||||||
|
"reject": "Tolak"
|
||||||
|
},
|
||||||
|
"att": {
|
||||||
|
"late_checkin": "Terlambat Check-in",
|
||||||
|
"not_checkout": "Belum Check-out",
|
||||||
|
"all_attendance": "Semua Absensi",
|
||||||
|
"total_staff": "Total Karyawan",
|
||||||
|
"today": "Hari ini",
|
||||||
|
"working": "Sedang Bekerja",
|
||||||
|
"checked_out": "Sudah Pulang",
|
||||||
|
"late": "Terlambat",
|
||||||
|
"after_0830": "Setelah 08:30",
|
||||||
|
"technician": "Teknisi",
|
||||||
|
"cashier": "Kasir",
|
||||||
|
"checkin_time": "Waktu Check-in",
|
||||||
|
"duration": "Durasi",
|
||||||
|
"location": "Lokasi",
|
||||||
|
"photo": "Foto"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tech": {
|
"tech": {
|
||||||
|
|||||||
+20
-20
@@ -131,34 +131,34 @@
|
|||||||
<div class="stat-grid" style="grid-template-columns:repeat(4,1fr)">
|
<div class="stat-grid" style="grid-template-columns:repeat(4,1fr)">
|
||||||
<div class="sc p">
|
<div class="sc p">
|
||||||
<i class="bi bi-people sc-icon"></i>
|
<i class="bi bi-people sc-icon"></i>
|
||||||
<div class="sc-label">Total Karyawan</div>
|
<div class="sc-label"><%= t('admin.att.total_staff','Total Karyawan') %></div>
|
||||||
<div class="sc-val"><%= totalAll %></div>
|
<div class="sc-val"><%= totalAll %></div>
|
||||||
<div class="sc-sub">Hari ini</div>
|
<div class="sc-sub"><%= t('admin.att.today','Hari ini') %></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="sc s">
|
<div class="sc s">
|
||||||
<i class="bi bi-check-circle sc-icon"></i>
|
<i class="bi bi-check-circle sc-icon"></i>
|
||||||
<div class="sc-label">Sedang Bekerja</div>
|
<div class="sc-label"><%= t('admin.att.working','Sedang Bekerja') %></div>
|
||||||
<div class="sc-val"><%= checkedInAll %></div>
|
<div class="sc-val"><%= checkedInAll %></div>
|
||||||
<div class="sc-sub">Check-in</div>
|
<div class="sc-sub">Check-in</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="sc p">
|
<div class="sc p">
|
||||||
<i class="bi bi-door-open sc-icon"></i>
|
<i class="bi bi-door-open sc-icon"></i>
|
||||||
<div class="sc-label">Sudah Pulang</div>
|
<div class="sc-label"><%= t('admin.att.checked_out','Sudah Pulang') %></div>
|
||||||
<div class="sc-val"><%= checkedOutAll %></div>
|
<div class="sc-val"><%= checkedOutAll %></div>
|
||||||
<div class="sc-sub">Check-out</div>
|
<div class="sc-sub">Check-out</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="sc d">
|
<div class="sc d">
|
||||||
<i class="bi bi-clock-history sc-icon"></i>
|
<i class="bi bi-clock-history sc-icon"></i>
|
||||||
<div class="sc-label">Terlambat</div>
|
<div class="sc-label"><%= t('admin.att.late','Terlambat') %></div>
|
||||||
<div class="sc-val"><%= lateCheckIns.length %></div>
|
<div class="sc-val"><%= lateCheckIns.length %></div>
|
||||||
<div class="sc-sub">Setelah 08:30</div>
|
<div class="sc-sub"><%= t('admin.att.after_0830','Setelah 08:30') %></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Breakdown by Type -->
|
<!-- Breakdown by Type -->
|
||||||
<div class="stat-grid" style="grid-template-columns:repeat(4,1fr);margin-top:16px">
|
<div class="stat-grid" style="grid-template-columns:repeat(4,1fr);margin-top:16px">
|
||||||
<div class="sc" style="border-left:3px solid #3b82f6">
|
<div class="sc" style="border-left:3px solid #3b82f6">
|
||||||
<div class="sc-label"><i class="bi bi-person-workspace"></i> Teknisi</div>
|
<div class="sc-label"><i class="bi bi-person-workspace"></i> <%= t('admin.att.technician','Teknisi') %></div>
|
||||||
<div class="sc-val"><%= techStats.total || 0 %></div>
|
<div class="sc-val"><%= techStats.total || 0 %></div>
|
||||||
<div class="sc-sub">
|
<div class="sc-sub">
|
||||||
<span style="color:#22c55e"><%= techStats.checked_in || 0 %> aktif</span> •
|
<span style="color:#22c55e"><%= techStats.checked_in || 0 %> aktif</span> •
|
||||||
@@ -174,7 +174,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="sc" style="border-left:3px solid #22c55e">
|
<div class="sc" style="border-left:3px solid #22c55e">
|
||||||
<div class="sc-label"><i class="bi bi-cash-coin"></i> Kasir</div>
|
<div class="sc-label"><i class="bi bi-cash-coin"></i> <%= t('admin.att.cashier','Kasir') %></div>
|
||||||
<div class="sc-val"><%= cashierStats.total || 0 %></div>
|
<div class="sc-val"><%= cashierStats.total || 0 %></div>
|
||||||
<div class="sc-sub">
|
<div class="sc-sub">
|
||||||
<span style="color:#22c55e"><%= cashierStats.checked_in || 0 %> aktif</span> •
|
<span style="color:#22c55e"><%= cashierStats.checked_in || 0 %> aktif</span> •
|
||||||
@@ -195,7 +195,7 @@
|
|||||||
<% if (lateCheckIns.length > 0) { %>
|
<% if (lateCheckIns.length > 0) { %>
|
||||||
<div class="card" style="margin-top:20px;border-left:3px solid #ef4444">
|
<div class="card" style="margin-top:20px;border-left:3px solid #ef4444">
|
||||||
<div class="card-hd">
|
<div class="card-hd">
|
||||||
<h6><i class="bi bi-exclamation-triangle"></i> Terlambat Check-in (<%= lateCheckIns.length %>)</h6>
|
<h6><i class="bi bi-exclamation-triangle"></i> <%= t('admin.att.late_checkin','Terlambat Check-in') %> (<%= lateCheckIns.length %>)</h6>
|
||||||
</div>
|
</div>
|
||||||
<div class="tbl-wrap">
|
<div class="tbl-wrap">
|
||||||
<table class="dtbl">
|
<table class="dtbl">
|
||||||
@@ -203,8 +203,8 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th><%= t('pwa.field.name','Nama') %></th>
|
<th><%= t('pwa.field.name','Nama') %></th>
|
||||||
<th><%= t('common.type','Tipe') %></th>
|
<th><%= t('common.type','Tipe') %></th>
|
||||||
<th>Waktu Check-in</th>
|
<th><%= t('admin.att.checkin_time','Waktu Check-in') %></th>
|
||||||
<th>Terlambat</th>
|
<th><%= t('admin.att.late','Terlambat') %></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@@ -231,7 +231,7 @@
|
|||||||
<% if (notCheckedOut.length > 0) { %>
|
<% if (notCheckedOut.length > 0) { %>
|
||||||
<div class="card" style="margin-top:20px;border-left:3px solid #f59e0b">
|
<div class="card" style="margin-top:20px;border-left:3px solid #f59e0b">
|
||||||
<div class="card-hd">
|
<div class="card-hd">
|
||||||
<h6><i class="bi bi-bell"></i> Belum Check-out (<%= notCheckedOut.length %>)</h6>
|
<h6><i class="bi bi-bell"></i> <%= t('admin.att.not_checkout','Belum Check-out') %> (<%= notCheckedOut.length %>)</h6>
|
||||||
</div>
|
</div>
|
||||||
<div class="tbl-wrap">
|
<div class="tbl-wrap">
|
||||||
<table class="dtbl">
|
<table class="dtbl">
|
||||||
@@ -240,7 +240,7 @@
|
|||||||
<th><%= t('pwa.field.name','Nama') %></th>
|
<th><%= t('pwa.field.name','Nama') %></th>
|
||||||
<th><%= t('common.type','Tipe') %></th>
|
<th><%= t('common.type','Tipe') %></th>
|
||||||
<th>Check-in</th>
|
<th>Check-in</th>
|
||||||
<th>Durasi</th>
|
<th><%= t('admin.att.duration','Durasi') %></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@@ -267,7 +267,7 @@
|
|||||||
<!-- All Attendance Records -->
|
<!-- All Attendance Records -->
|
||||||
<div class="card" style="margin-top:20px">
|
<div class="card" style="margin-top:20px">
|
||||||
<div class="card-hd">
|
<div class="card-hd">
|
||||||
<h6><i class="bi bi-calendar-check"></i> Semua Absensi - <%= parseDateInTimezone(selectedDate).toLocaleDateString('id-ID', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }) %></h6>
|
<h6><i class="bi bi-calendar-check"></i> <%= t('admin.att.all_attendance','Semua Absensi') %> - <%= parseDateInTimezone(selectedDate).toLocaleDateString('id-ID', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }) %></h6>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<% if (attendances.length > 0) { %>
|
<% if (attendances.length > 0) { %>
|
||||||
@@ -279,10 +279,10 @@
|
|||||||
<th><%= t('common.type','Tipe') %></th>
|
<th><%= t('common.type','Tipe') %></th>
|
||||||
<th>Check-in</th>
|
<th>Check-in</th>
|
||||||
<th>Check-out</th>
|
<th>Check-out</th>
|
||||||
<th>Durasi</th>
|
<th><%= t('admin.att.duration','Durasi') %></th>
|
||||||
<th><%= t('common.status','Status') %></th>
|
<th><%= t('common.status','Status') %></th>
|
||||||
<th>Lokasi</th>
|
<th><%= t('admin.att.location','Lokasi') %></th>
|
||||||
<th>Foto</th>
|
<th><%= t('admin.att.photo','Foto') %></th>
|
||||||
<th><%= t('common.actions','Aksi') %></th>
|
<th><%= t('common.actions','Aksi') %></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@@ -336,13 +336,13 @@
|
|||||||
<div class="photo-stack">
|
<div class="photo-stack">
|
||||||
<% if (att.check_in_photo) { %>
|
<% if (att.check_in_photo) { %>
|
||||||
<a href="<%= att.check_in_photo %>" target="_blank" class="photo-item">
|
<a href="<%= att.check_in_photo %>" target="_blank" class="photo-item">
|
||||||
<img src="<%= att.check_in_photo %>" alt="Foto check-in" class="photo-thumb">
|
<img src="<%= att.check_in_photo %>" alt="<%= t('admin.att.photo','Foto') %> check-in" class="photo-thumb">
|
||||||
In
|
In
|
||||||
</a>
|
</a>
|
||||||
<% } %>
|
<% } %>
|
||||||
<% if (att.check_out_photo) { %>
|
<% if (att.check_out_photo) { %>
|
||||||
<a href="<%= att.check_out_photo %>" target="_blank" class="photo-item">
|
<a href="<%= att.check_out_photo %>" target="_blank" class="photo-item">
|
||||||
<img src="<%= att.check_out_photo %>" alt="Foto check-out" class="photo-thumb">
|
<img src="<%= att.check_out_photo %>" alt="<%= t('admin.att.photo','Foto') %> check-out" class="photo-thumb">
|
||||||
Out
|
Out
|
||||||
</a>
|
</a>
|
||||||
<% } %>
|
<% } %>
|
||||||
@@ -402,7 +402,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function editAttendance(id) {
|
function editAttendance(id) {
|
||||||
const checkIn = prompt('Waktu Check-in (YYYY-MM-DD HH:MM:SS):');
|
const checkIn = prompt('<%= t('admin.att.checkin_time','Waktu Check-in') %> (YYYY-MM-DD HH:MM:SS):');
|
||||||
if (!checkIn) return;
|
if (!checkIn) return;
|
||||||
|
|
||||||
const checkOut = prompt('Waktu Check-out (YYYY-MM-DD HH:MM:SS) - kosongkan jika belum:');
|
const checkOut = prompt('Waktu Check-out (YYYY-MM-DD HH:MM:SS) - kosongkan jika belum:');
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<html lang="<%= lang || 'id' %>">
|
<html lang="<%= lang || 'id' %>">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
<title>Approval Pembayaran Kolektor | <%= company %></title>
|
<title><%= t('admin.cpay.title','Approval Pembayaran Kolektor') %> | <%= company %></title>
|
||||||
<link rel="stylesheet" href="/vendor/bootstrap-icons/bootstrap-icons.min.css">
|
<link rel="stylesheet" href="/vendor/bootstrap-icons/bootstrap-icons.min.css">
|
||||||
<link rel="stylesheet" href="/css/admin.css">
|
<link rel="stylesheet" href="/css/admin.css">
|
||||||
</head>
|
</head>
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
<div class="tb-title">
|
<div class="tb-title">
|
||||||
<button class="hb-menu" onclick="toggleSidebar()"><i class="bi bi-list"></i></button>
|
<button class="hb-menu" onclick="toggleSidebar()"><i class="bi bi-list"></i></button>
|
||||||
<i class="bi bi-check2-square"></i>
|
<i class="bi bi-check2-square"></i>
|
||||||
<span>Approval Pembayaran Kolektor</span>
|
<span><%= t('admin.cpay.title','Approval Pembayaran Kolektor') %></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="tb-right">
|
<div class="tb-right">
|
||||||
<span class="adm-badge"><i class="bi bi-person-fill"></i> <%= (typeof session !== 'undefined' && session.isCashier) ? t('admin.role.cashier', 'Kasir') : t('admin.role.admin', 'Admin') %></span>
|
<span class="adm-badge"><i class="bi bi-person-fill"></i> <%= (typeof session !== 'undefined' && session.isCashier) ? t('admin.role.cashier', 'Kasir') : t('admin.role.admin', 'Admin') %></span>
|
||||||
@@ -31,20 +31,20 @@
|
|||||||
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-hd">
|
<div class="card-hd">
|
||||||
<h6><i class="bi bi-list-ul"></i> Daftar Request (<%= (rows || []).length %>)</h6>
|
<h6><i class="bi bi-list-ul"></i> <%= t('admin.cpay.list','Daftar Request') %> (<%= (rows || []).length %>)</h6>
|
||||||
</div>
|
</div>
|
||||||
<div class="hint" style="padding:12px 16px 0 16px;font-size:12px;color:var(--muted)">
|
<div class="hint" style="padding:12px 16px 0 16px;font-size:12px;color:var(--muted)">
|
||||||
Label proses membantu membedakan request yang memang menunggu approval, request yang otomatis langsung lunas oleh kolektor, dan request yang sudah diproses admin atau kasir.
|
Label proses membantu membedakan request yang memang menunggu approval, request yang otomatis langsung lunas oleh kolektor, dan request yang sudah diproses admin atau kasir.
|
||||||
</div>
|
</div>
|
||||||
<div style="padding:12px 16px 0 16px;display:flex;gap:10px;flex-wrap:wrap">
|
<div style="padding:12px 16px 0 16px;display:flex;gap:10px;flex-wrap:wrap">
|
||||||
<select id="processFilter" class="fs" style="max-width:220px">
|
<select id="processFilter" class="fs" style="max-width:220px">
|
||||||
<option value="all">Semua Proses</option>
|
<option value="all"><%= t('admin.cpay.opt_all','Semua Proses') %></option>
|
||||||
<option value="pending">Butuh Approval</option>
|
<option value="pending"><%= t('admin.cpay.opt_pending','Butuh Approval') %></option>
|
||||||
<option value="auto">Auto Kolektor</option>
|
<option value="auto"><%= t('admin.cpay.opt_auto','Auto Kolektor') %></option>
|
||||||
<option value="admin">Disetujui Admin</option>
|
<option value="admin"><%= t('admin.cpay.opt_admin','Disetujui Admin') %></option>
|
||||||
<option value="cashier">Disetujui Kasir</option>
|
<option value="cashier"><%= t('admin.cpay.opt_cashier','Disetujui Kasir') %></option>
|
||||||
<option value="rejected">Ditolak Manual</option>
|
<option value="rejected"><%= t('admin.cpay.opt_rejected','Ditolak Manual') %></option>
|
||||||
<option value="manual">Diproses Manual</option>
|
<option value="manual"><%= t('admin.cpay.opt_manual','Diproses Manual') %></option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="tbl-wrap">
|
<div class="tbl-wrap">
|
||||||
@@ -54,9 +54,9 @@
|
|||||||
<th><%= t('collector.col_time','Waktu') %></th>
|
<th><%= t('collector.col_time','Waktu') %></th>
|
||||||
<th><%= t('collector.role','Kolektor') %></th>
|
<th><%= t('collector.role','Kolektor') %></th>
|
||||||
<th><%= t('common.customer','Pelanggan') %></th>
|
<th><%= t('common.customer','Pelanggan') %></th>
|
||||||
<th>Tagihan</th>
|
<th><%= t('admin.cpay.th_invoice','Tagihan') %></th>
|
||||||
<th class="num"><%= t('collector.col_amount','Nominal') %></th>
|
<th class="num"><%= t('collector.col_amount','Nominal') %></th>
|
||||||
<th>Proses</th>
|
<th><%= t('admin.cpay.th_process','Proses') %></th>
|
||||||
<th><%= t('common.status','Status') %></th>
|
<th><%= t('common.status','Status') %></th>
|
||||||
<th><%= t('common.actions','Aksi') %></th>
|
<th><%= t('common.actions','Aksi') %></th>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -119,12 +119,12 @@
|
|||||||
<div class="act-menu" style="min-width:270px">
|
<div class="act-menu" style="min-width:270px">
|
||||||
<form method="POST" action="/admin/collector-payments/<%= r.id %>/approve" style="display:flex;gap:6px;padding:4px 4px 6px">
|
<form method="POST" action="/admin/collector-payments/<%= r.id %>/approve" style="display:flex;gap:6px;padding:4px 4px 6px">
|
||||||
<input class="fc" name="decided_note" placeholder="Catatan (opsional)" style="font-size:12px">
|
<input class="fc" name="decided_note" placeholder="Catatan (opsional)" style="font-size:12px">
|
||||||
<button class="btn btn-s btn-sm" type="submit" title="Approve"><i class="bi bi-check-lg"></i> Setujui</button>
|
<button class="btn btn-s btn-sm" type="submit" title="Approve"><i class="bi bi-check-lg"></i> <%= t('admin.cpay.approve','Setujui') %></button>
|
||||||
</form>
|
</form>
|
||||||
<div class="act-sep"></div>
|
<div class="act-sep"></div>
|
||||||
<form method="POST" action="/admin/collector-payments/<%= r.id %>/reject" style="display:flex;gap:6px;padding:4px">
|
<form method="POST" action="/admin/collector-payments/<%= r.id %>/reject" style="display:flex;gap:6px;padding:4px">
|
||||||
<input class="fc" name="decided_note" placeholder="Alasan (opsional)" style="font-size:12px">
|
<input class="fc" name="decided_note" placeholder="Alasan (opsional)" style="font-size:12px">
|
||||||
<button class="btn btn-d btn-sm" type="submit" title="Reject"><i class="bi bi-x-lg"></i> Tolak</button>
|
<button class="btn btn-d btn-sm" type="submit" title="Reject"><i class="bi bi-x-lg"></i> <%= t('admin.cpay.reject','Tolak') %></button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+27
-27
@@ -2,7 +2,7 @@
|
|||||||
<html lang="<%= lang || 'id' %>">
|
<html lang="<%= lang || 'id' %>">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
<title>Diskon Tagihan | <%= company %></title>
|
<title><%= t('admin.disc.title','Diskon Tagihan') %> | <%= company %></title>
|
||||||
<link rel="stylesheet" href="/vendor/bootstrap-icons/bootstrap-icons.min.css">
|
<link rel="stylesheet" href="/vendor/bootstrap-icons/bootstrap-icons.min.css">
|
||||||
<link rel="stylesheet" href="/css/admin.css">
|
<link rel="stylesheet" href="/css/admin.css">
|
||||||
<style>
|
<style>
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
<%- include('partials/sidebar', { activePage: 'discounts', company }) %>
|
<%- include('partials/sidebar', { activePage: 'discounts', company }) %>
|
||||||
<div class="mw">
|
<div class="mw">
|
||||||
<div class="topbar">
|
<div class="topbar">
|
||||||
<div class="tb-title"><button class="hb-menu" onclick="toggleSidebar()"><i class="bi bi-list"></i></button><i class="bi bi-percent"></i> Diskon Tagihan</div>
|
<div class="tb-title"><button class="hb-menu" onclick="toggleSidebar()"><i class="bi bi-list"></i></button><i class="bi bi-percent"></i> <%= t('admin.disc.title','Diskon Tagihan') %></div>
|
||||||
<div class="tb-right">
|
<div class="tb-right">
|
||||||
<span class="adm-badge"><i class="bi bi-person-fill"></i> <%= (typeof session !== 'undefined' && session.isCashier) ? 'Kasir' : 'Admin' %></span>
|
<span class="adm-badge"><i class="bi bi-person-fill"></i> <%= (typeof session !== 'undefined' && session.isCashier) ? 'Kasir' : 'Admin' %></span>
|
||||||
<a href="/admin/logout" class="btn btn-g btn-sm"><i class="bi bi-box-arrow-left"></i></a>
|
<a href="/admin/logout" class="btn btn-g btn-sm"><i class="bi bi-box-arrow-left"></i></a>
|
||||||
@@ -33,42 +33,42 @@
|
|||||||
<form method="POST" action="/admin/discounts/apply" id="discForm">
|
<form method="POST" action="/admin/discounts/apply" id="discForm">
|
||||||
<!-- Konfigurasi diskon -->
|
<!-- Konfigurasi diskon -->
|
||||||
<div class="card mb16">
|
<div class="card mb16">
|
||||||
<div class="card-hd"><h6><i class="bi bi-sliders"></i> Pengaturan Diskon</h6></div>
|
<div class="card-hd"><h6><i class="bi bi-sliders"></i> <%= t('admin.disc.settings_title','Pengaturan Diskon') %></h6></div>
|
||||||
<div class="card-bd">
|
<div class="card-bd">
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<div class="fg">
|
<div class="fg">
|
||||||
<label class="fl">Target</label>
|
<label class="fl">Target</label>
|
||||||
<select class="fs" name="apply_mode" id="applyMode">
|
<select class="fs" name="apply_mode" id="applyMode">
|
||||||
<option value="selected" selected>Pelanggan terpilih (batch)</option>
|
<option value="selected" selected><%= t('admin.disc.opt_selected','Pelanggan terpilih (batch)') %></option>
|
||||||
<option value="single">Satu pelanggan (1 per 1)</option>
|
<option value="single"><%= t('admin.disc.opt_single','Satu pelanggan (1 per 1)') %></option>
|
||||||
<option value="all">Semua pelanggan aktif</option>
|
<option value="all"><%= t('admin.disc.opt_all','Semua pelanggan aktif') %></option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="fg" id="singleWrap" style="display:none">
|
<div class="fg" id="singleWrap" style="display:none">
|
||||||
<label class="fl">Pilih Pelanggan</label>
|
<label class="fl"><%= t('admin.disc.pick_customer','Pilih Pelanggan') %></label>
|
||||||
<select class="fs" name="customer_id">
|
<select class="fs" name="customer_id">
|
||||||
<option value="">-- pilih pelanggan --</option>
|
<option value=""><%= t('admin.disc.ph_pick_customer','-- pilih pelanggan --') %></option>
|
||||||
<% customers.forEach(function(c){ %>
|
<% customers.forEach(function(c){ %>
|
||||||
<option value="<%= c.id %>"><%= c.customer_code || c.id %> — <%= c.name %><%= c.area ? ' ('+c.area+')' : '' %></option>
|
<option value="<%= c.id %>"><%= c.customer_code || c.id %> — <%= c.name %><%= c.area ? ' ('+c.area+')' : '' %></option>
|
||||||
<% }); %>
|
<% }); %>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="fg">
|
<div class="fg">
|
||||||
<label class="fl">Tipe Diskon</label>
|
<label class="fl"><%= t('admin.disc.disc_type','Tipe Diskon') %></label>
|
||||||
<select class="fs" name="discount_type" id="discType">
|
<select class="fs" name="discount_type" id="discType">
|
||||||
<option value="percent">Persen (%)</option>
|
<option value="percent"><%= t('admin.disc.opt_percent','Persen (%)') %></option>
|
||||||
<option value="amount">Nominal (Rp)</option>
|
<option value="amount"><%= t('admin.disc.opt_amount','Nominal (Rp)') %></option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="fg">
|
<div class="fg">
|
||||||
<label class="fl">Nilai Diskon</label>
|
<label class="fl"><%= t('admin.disc.disc_value','Nilai Diskon') %></label>
|
||||||
<input class="fc" type="number" name="discount_value" id="discValue" min="1" step="1" placeholder="mis. 10 (persen) / 20000 (Rp)" required>
|
<input class="fc" type="number" name="discount_value" id="discValue" min="1" step="1" placeholder="<%= t('admin.disc.ph_value','mis. 10 (persen) / 20000 (Rp)') %>" required>
|
||||||
<div class="hint" id="discHint">Persen dihitung dari harga dasar (sebelum PPN/USO).</div>
|
<div class="hint" id="discHint"><%= t('admin.disc.disc_hint','Persen dihitung dari harga dasar (sebelum PPN/USO).') %></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<div class="fg">
|
<div class="fg">
|
||||||
<label class="fl">Periode Tagihan — Bulan</label>
|
<label class="fl"><%= t('admin.disc.period_month','Periode Tagihan — Bulan') %></label>
|
||||||
<select class="fs" name="period_month">
|
<select class="fs" name="period_month">
|
||||||
<% const mNames=['Januari','Februari','Maret','April','Mei','Juni','Juli','Agustus','September','Oktober','November','Desember'];
|
<% const mNames=['Januari','Februari','Maret','April','Mei','Juni','Juli','Agustus','September','Oktober','November','Desember'];
|
||||||
for(let m=1;m<=12;m++){ %>
|
for(let m=1;m<=12;m++){ %>
|
||||||
@@ -77,7 +77,7 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="fg">
|
<div class="fg">
|
||||||
<label class="fl">Tahun</label>
|
<label class="fl"><%= t('admin.disc.year','Tahun') %></label>
|
||||||
<select class="fs" name="period_year">
|
<select class="fs" name="period_year">
|
||||||
<% for(let y=(timeInfo.year||new Date().getFullYear())+1; y>=2023; y--){ %>
|
<% for(let y=(timeInfo.year||new Date().getFullYear())+1; y>=2023; y--){ %>
|
||||||
<option value="<%= y %>" <%= (timeInfo.year===y)?'selected':'' %>><%= y %></option>
|
<option value="<%= y %>" <%= (timeInfo.year===y)?'selected':'' %>><%= y %></option>
|
||||||
@@ -85,13 +85,13 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="fg" style="flex:2">
|
<div class="fg" style="flex:2">
|
||||||
<label class="fl">Catatan (opsional)</label>
|
<label class="fl"><%= t('admin.disc.note_opt','Catatan (opsional)') %></label>
|
||||||
<input class="fc" name="note" placeholder="mis. promo bulan kemerdekaan">
|
<input class="fc" name="note" placeholder="<%= t('admin.disc.ph_note','mis. promo bulan kemerdekaan') %>">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style="display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap;margin-top:6px">
|
<div style="display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap;margin-top:6px">
|
||||||
<div class="hint"><i class="bi bi-info-circle"></i> Diskon berlaku ke tagihan <b>belum bayar</b> pada periode terpilih. Tagihan lunas/hangus tidak diubah. Kode unik QRIS akan digenerate ulang dari nominal baru.</div>
|
<div class="hint"><i class="bi bi-info-circle"></i> <%- t('admin.disc.apply_hint','Diskon berlaku ke tagihan <b>belum bayar</b> pada periode terpilih. Tagihan lunas/hangus tidak diubah. Kode unik QRIS akan digenerate ulang dari nominal baru.') %></div>
|
||||||
<button type="submit" class="btn btn-p" id="applyBtn"><i class="bi bi-percent"></i> Terapkan Diskon</button>
|
<button type="submit" class="btn btn-p" id="applyBtn"><i class="bi bi-percent"></i> <%= t('admin.disc.apply','Terapkan Diskon') %></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -100,9 +100,9 @@
|
|||||||
<div class="card mb16" id="custCard">
|
<div class="card mb16" id="custCard">
|
||||||
<div class="card-hd">
|
<div class="card-hd">
|
||||||
<div style="display:flex;align-items:center;justify-content:space-between;gap:10px;flex-wrap:wrap;width:100%">
|
<div style="display:flex;align-items:center;justify-content:space-between;gap:10px;flex-wrap:wrap;width:100%">
|
||||||
<h6 style="margin:0"><i class="bi bi-people"></i> Pilih Pelanggan (<%= customers.length %>)</h6>
|
<h6 style="margin:0"><i class="bi bi-people"></i> <%= t('admin.disc.pick_customer','Pilih Pelanggan') %> (<%= customers.length %>)</h6>
|
||||||
<div class="disc-filter">
|
<div class="disc-filter">
|
||||||
<span class="disc-badge" id="selCount" title="Jumlah pelanggan terpilih">0 dipilih</span>
|
<span class="disc-badge" id="selCount" title="Jumlah pelanggan terpilih">0 <%= t('admin.disc.selected','dipilih') %></span>
|
||||||
<label style="display:flex;align-items:center;gap:6px;font-size:12px;cursor:pointer">
|
<label style="display:flex;align-items:center;gap:6px;font-size:12px;cursor:pointer">
|
||||||
<input type="checkbox" id="selectAll" style="width:16px;height:16px"> Pilih semua yang tampil
|
<input type="checkbox" id="selectAll" style="width:16px;height:16px"> Pilih semua yang tampil
|
||||||
</label>
|
</label>
|
||||||
@@ -146,7 +146,7 @@
|
|||||||
|
|
||||||
<!-- Riwayat -->
|
<!-- Riwayat -->
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-hd"><h6><i class="bi bi-clock-history"></i> Riwayat Diskon (100 terakhir)</h6></div>
|
<div class="card-hd"><h6><i class="bi bi-clock-history"></i> <%= t('admin.disc.history','Riwayat Diskon (100 terakhir)') %></h6></div>
|
||||||
<div class="tbl-wrap">
|
<div class="tbl-wrap">
|
||||||
<table class="dtbl">
|
<table class="dtbl">
|
||||||
<thead>
|
<thead>
|
||||||
@@ -158,7 +158,7 @@
|
|||||||
<th class="num" style="width:120px">Potongan</th>
|
<th class="num" style="width:120px">Potongan</th>
|
||||||
<th class="num" style="width:120px">Awal → Akhir</th>
|
<th class="num" style="width:120px">Awal → Akhir</th>
|
||||||
<th style="width:110px">Oleh</th>
|
<th style="width:110px">Oleh</th>
|
||||||
<th>Catatan</th>
|
<th><%= t('admin.disc.th_note','Catatan') %></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@@ -201,7 +201,7 @@
|
|||||||
|
|
||||||
function syncHint(){
|
function syncHint(){
|
||||||
hint.textContent = (type.value === 'percent')
|
hint.textContent = (type.value === 'percent')
|
||||||
? 'Persen dihitung dari harga dasar (sebelum PPN/USO). Contoh: 10 = potong 10%.'
|
? '<%= t('admin.disc.disc_hint','Persen dihitung dari harga dasar (sebelum PPN/USO).') %> Contoh: 10 = potong 10%.'
|
||||||
: 'Nominal potongan langsung dalam Rupiah. Contoh: 20000 = potong Rp 20.000.';
|
: 'Nominal potongan langsung dalam Rupiah. Contoh: 20000 = potong Rp 20.000.';
|
||||||
}
|
}
|
||||||
type.addEventListener('change', syncHint); syncHint();
|
type.addEventListener('change', syncHint); syncHint();
|
||||||
@@ -217,8 +217,8 @@
|
|||||||
var applyBtn = document.getElementById('applyBtn');
|
var applyBtn = document.getElementById('applyBtn');
|
||||||
function updateSelCount(){
|
function updateSelCount(){
|
||||||
var n = document.querySelectorAll('#custTable .cust-sel:checked').length;
|
var n = document.querySelectorAll('#custTable .cust-sel:checked').length;
|
||||||
if (selCount) selCount.textContent = n + ' dipilih';
|
if (selCount) selCount.textContent = n + ' <%= t('admin.disc.selected','dipilih') %>';
|
||||||
if (applyBtn) applyBtn.innerHTML = '<i class="bi bi-percent"></i> Terapkan Diskon' + ((mode.value === 'selected' && n) ? ' (' + n + ')' : '');
|
if (applyBtn) applyBtn.innerHTML = '<i class="bi bi-percent"></i> <%= t('admin.disc.apply','Terapkan Diskon') %>' + ((mode.value === 'selected' && n) ? ' (' + n + ')' : '');
|
||||||
}
|
}
|
||||||
all.addEventListener('change', function(){ visibleBoxes().forEach(function(b){ b.checked = all.checked; }); updateSelCount(); });
|
all.addEventListener('change', function(){ visibleBoxes().forEach(function(b){ b.checked = all.checked; }); updateSelCount(); });
|
||||||
document.getElementById('custTable').addEventListener('change', function(e){ if (e.target && e.target.classList.contains('cust-sel')) updateSelCount(); });
|
document.getElementById('custTable').addEventListener('change', function(e){ if (e.target && e.target.classList.contains('cust-sel')) updateSelCount(); });
|
||||||
|
|||||||
@@ -85,7 +85,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div id="refresh-indicator" style="position:absolute;top:-8px;right:0;font-size:11px;color:var(--muted);display:none;align-items:center;gap:4px">
|
<div id="refresh-indicator" style="position:absolute;top:-8px;right:0;font-size:11px;color:var(--muted);display:none;align-items:center;gap:4px">
|
||||||
<i class="bi bi-arrow-clockwise" style="animation:spin 1s linear infinite"></i>
|
<i class="bi bi-arrow-clockwise" style="animation:spin 1s linear infinite"></i>
|
||||||
<span>Memperbarui...</span>
|
<span><%= t('admin.mt.updating','Memperbarui...') %></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<style>
|
<style>
|
||||||
@@ -250,7 +250,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<div class="fg"><label class="fl">Limit Uptime (e.g. 1h)</label><input class="fc" id="h_uptime"></div>
|
<div class="fg"><label class="fl"><%= t('admin.mt.limit_uptime','Limit Uptime (e.g. 1h)') %></label><input class="fc" id="h_uptime"></div>
|
||||||
<div class="fg"><label class="fl">MAC Address</label><input class="fc" id="h_mac"></div>
|
<div class="fg"><label class="fl">MAC Address</label><input class="fc" id="h_mac"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="fg"><label class="fl">Comment</label><input class="fc" id="h_comment"></div>
|
<div class="fg"><label class="fl">Comment</label><input class="fc" id="h_comment"></div>
|
||||||
@@ -267,7 +267,7 @@
|
|||||||
<div class="mo" id="onlineUsersModal">
|
<div class="mo" id="onlineUsersModal">
|
||||||
<div class="mb" style="max-width:900px">
|
<div class="mb" style="max-width:900px">
|
||||||
<div class="mh">
|
<div class="mh">
|
||||||
<span class="mt"><i class="bi bi-ethernet"></i> Daftar User PPPoE Online</span>
|
<span class="mt"><i class="bi bi-ethernet"></i> <%= t('admin.mt.online_list','Daftar User PPPoE Online') %></span>
|
||||||
<button class="mc" onclick="closeModal('onlineUsersModal')">×</button>
|
<button class="mc" onclick="closeModal('onlineUsersModal')">×</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="mbody" style="max-height:500px;overflow-y:auto">
|
<div class="mbody" style="max-height:500px;overflow-y:auto">
|
||||||
@@ -307,7 +307,7 @@
|
|||||||
<div class="mo" id="offlineUsersModal">
|
<div class="mo" id="offlineUsersModal">
|
||||||
<div class="mb" style="max-width:800px">
|
<div class="mb" style="max-width:800px">
|
||||||
<div class="mh">
|
<div class="mh">
|
||||||
<span class="mt"><i class="bi bi-plug"></i> Daftar User PPPoE Offline</span>
|
<span class="mt"><i class="bi bi-plug"></i> <%= t('admin.mt.offline_list','Daftar User PPPoE Offline') %></span>
|
||||||
<button class="mc" onclick="closeModal('offlineUsersModal')">×</button>
|
<button class="mc" onclick="closeModal('offlineUsersModal')">×</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="mbody" style="max-height:500px;overflow-y:auto">
|
<div class="mbody" style="max-height:500px;overflow-y:auto">
|
||||||
|
|||||||
@@ -315,7 +315,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="hint" style="margin:0 0 10px;padding:12px;border:1px dashed var(--border);border-radius:10px;background:var(--bg2)">
|
<div class="hint" style="margin:0 0 10px;padding:12px;border:1px dashed var(--border);border-radius:10px;background:var(--bg2)">
|
||||||
<i class="bi bi-robot"></i> <strong>Otomatisasi dipindah:</strong> Auto-Nonaktif, Auto-Hapus, Auto-Peringatan & Auto-Lunas kini tertata di menu <a href="/admin/automation" style="color:var(--primary);font-weight:800">Automation →</a>
|
<i class="bi bi-robot"></i> <strong>Otomatisasi dipindah:</strong> Auto-Nonaktif, Auto-Hapus, Auto-Peringatan & Auto-<%= t('admin.set.ew_paid','Lunas') %> kini tertata di menu <a href="/admin/automation" style="color:var(--primary);font-weight:800">Automation →</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="hint" style="margin-top:6px;color:var(--warning)">
|
<div class="hint" style="margin-top:6px;color:var(--warning)">
|
||||||
<i class="bi bi-info-circle"></i> <strong><%= t('admin.set.colpay_label','Pembayaran Kolektor:') %></strong> <%= t('admin.set.colpay_desc','Pengaturan approval pembayaran kolektor sekarang diatur per akun kolektor pada menu Manajemen Kolektor, bukan dari pengaturan global.') %>
|
<i class="bi bi-info-circle"></i> <strong><%= t('admin.set.colpay_label','Pembayaran Kolektor:') %></strong> <%= t('admin.set.colpay_desc','Pengaturan approval pembayaran kolektor sekarang diatur per akun kolektor pada menu Manajemen Kolektor, bukan dari pengaturan global.') %>
|
||||||
@@ -1031,7 +1031,7 @@ async function loadEwalletLogs() {
|
|||||||
if (!res.ok || !data.ok) throw new Error(data.error || 'Gagal memuat log');
|
if (!res.ok || !data.ok) throw new Error(data.error || 'Gagal memuat log');
|
||||||
const rows = Array.isArray(data.rows) ? data.rows : [];
|
const rows = Array.isArray(data.rows) ? data.rows : [];
|
||||||
if (rows.length === 0) {
|
if (rows.length === 0) {
|
||||||
body.innerHTML = '<tr><td colspan="7" class="text-center text-muted">Belum ada data.</td></tr>';
|
body.innerHTML = '<tr><td colspan="7" class="text-center text-muted"><%= t('admin.set.no_data','Belum ada data.') %></td></tr>';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const newest = rows[0];
|
const newest = rows[0];
|
||||||
@@ -1056,9 +1056,9 @@ async function loadEwalletLogs() {
|
|||||||
const md = Number(r.matched_donation_order_id || 0) || 0;
|
const md = Number(r.matched_donation_order_id || 0) || 0;
|
||||||
const isMatched = !!(mi || mv || md);
|
const isMatched = !!(mi || mv || md);
|
||||||
let statusBadge;
|
let statusBadge;
|
||||||
if (!parsed) statusBadge = '<span class="ew-badge ew-gray">Bukan transaksi</span>';
|
if (!parsed) statusBadge = '<span class="ew-badge ew-gray"><%= t('admin.set.ew_not_tx','Bukan transaksi') %></span>';
|
||||||
else if (isMatched) statusBadge = '<span class="ew-badge ew-green">Lunas</span>';
|
else if (isMatched) statusBadge = '<span class="ew-badge ew-green"><%= t('admin.set.ew_paid','Lunas') %></span>';
|
||||||
else statusBadge = '<span class="ew-badge ew-amber">Belum cocok</span>';
|
else statusBadge = '<span class="ew-badge ew-amber"><%= t('admin.set.ew_unmatched','Belum cocok') %></span>';
|
||||||
const amountHtml = (amountNum == null)
|
const amountHtml = (amountNum == null)
|
||||||
? '<span class="muted">—</span>'
|
? '<span class="muted">—</span>'
|
||||||
: ('<span class="mono" style="font-weight:800;' + (parsed ? 'color:var(--primary)' : 'color:var(--muted)') + '">Rp ' + amountNum.toLocaleString('id-ID') + '</span>');
|
: ('<span class="mono" style="font-weight:800;' + (parsed ? 'color:var(--primary)' : 'color:var(--muted)') + '">Rp ' + amountNum.toLocaleString('id-ID') + '</span>');
|
||||||
|
|||||||
Reference in new issue
Block a user