i18n (Phase C batch 7): olts + packages ID/EN

This commit is contained in:
oxpoe committed 2026-10-09 07:35:14 +07:00
1 parent 6ed6945970
commit 9760888735
4 files changed
+183 -71

No files matched your search

+56
View File
@@ -1848,6 +1848,62 @@
"duration": "Duration", "duration": "Duration",
"location": "Location", "location": "Location",
"photo": "Photo" "photo": "Photo"
},
"olt": {
"all_summary": "All OLTs (Total Summary)",
"host": "OLT Host:",
"snmp_port": "SNMP Port:",
"th_action": "ACTION",
"th_onu_name": "ONU / Customer Name",
"del_olt": "Delete OLT",
"opt_generic": "Generic / Other (Standard SNMP EPON/GPON)",
"ph_enable_pw": "zxr10 (optional)",
"ph_enable_pw2": "Leave blank to keep unchanged",
"wan_title": "ONU WAN Configuration",
"wan_name": "ONU NAME",
"wan_method": "CONFIGURATION METHOD",
"wan_mode": "WAN MODE",
"wan_cvlan": "CVLAN (optional)",
"ph_cvlan": "Default = VLAN",
"wan_vlan_mode": "VLAN mode",
"wan_bind_lan": "LAN BINDING",
"wan_bind_ssid": "SSID (WIFI) BINDING",
"oid_active": "Active SNMP Profile",
"conn_ok": "Connection Successful!",
"conn_fail": "Connection Failed:"
},
"pkg": {
"isolir_action": "Isolir action",
"isolir_ip_pool": "Isolir IP Pool",
"prof_name": "Profile Name",
"radius_hint": "<b>RADIUS</b> mode — the values above are read from RADIUS settings. To change them, open <b>RADIUS Settings</b> (button above).",
"mt_hint": "<b>MikroTik</b> mode — the values above are read from the PPP profile on the router. To change them, edit in <b>MikroTik &rarr; PPPoE Profiles</b>.",
"all_routers": "All Routers",
"th_promo": "Promo / Prorated",
"del_pkg": "Delete Package",
"mode_radius_hint": "RADIUS mode: rate-limit &amp; IP come from <b>RADIUS attributes</b> — no MikroTik PPP profile is created automatically.",
"billing_type": "Billing Type *",
"opt_postpaid": "Postpaid (Calendar / Fixed Due Date)",
"opt_prepaid": "Prepaid (Rolling Validity)",
"validity_days": "Validity Duration (Days) *",
"ph_down": "Example: 10",
"ph_up": "Example: 5",
"ph_upto_down": "Leave blank if no UpTo (e.g.: 20)",
"ph_upto_up": "Leave blank if no UpTo (e.g.: 10)",
"upto_hint": "If filled, the package is displayed as: <strong>10 Mbps (Up to 20 Mbps)</strong> on invoices & the customer portal.",
"promo_price": "Promo price (Rp / cycle)",
"promo_cycles": "Number of promo months",
"ph_promo_price": "Optional, e.g. 99000",
"ph_promo_cycles": "0 = no promo",
"ppn_pct": "VAT Percentage (%)",
"uso_pct": "ULO/USO Percentage (%)",
"pool_name": "IP Pool Name",
"pool_ranges": "IP Ranges",
"isolir_profile": "Isolir Profile (this package)",
"ph_isolir_profile": "— use global/customer default —",
"night_profile": "Night Profile Name (MikroTik)",
"ph_night_profile": "-- Select Profile --",
"night_down": "Night Download (Mbps)"
} }
}, },
"tech": { "tech": {
+56
View File
@@ -1849,6 +1849,62 @@
"duration": "Durasi", "duration": "Durasi",
"location": "Lokasi", "location": "Lokasi",
"photo": "Foto" "photo": "Foto"
},
"olt": {
"all_summary": "Semua OLT (Ringkasan Total)",
"host": "Host OLT:",
"snmp_port": "Port SNMP:",
"th_action": "AKSI",
"th_onu_name": "Nama ONU / Pelanggan",
"del_olt": "Hapus OLT",
"opt_generic": "Generic / Lainnya (Standard SNMP EPON/GPON)",
"ph_enable_pw": "zxr10 (opsional)",
"ph_enable_pw2": "Kosongkan jika tidak diubah",
"wan_title": "Konfigurasi WAN ONU",
"wan_name": "NAMA ONU",
"wan_method": "METODE KONFIGURASI",
"wan_mode": "MODE WAN",
"wan_cvlan": "CVLAN (opsional)",
"ph_cvlan": "Default = VLAN",
"wan_vlan_mode": "VLAN mode",
"wan_bind_lan": "BINDING LAN",
"wan_bind_ssid": "BINDING SSID (WIFI)",
"oid_active": "Profil SNMP Aktif",
"conn_ok": "Koneksi Sukses!",
"conn_fail": "Koneksi Gagal:"
},
"pkg": {
"isolir_action": "Aksi isolir",
"isolir_ip_pool": "IP Pool isolir",
"prof_name": "Nama Profil",
"radius_hint": "Mode <b>RADIUS</b> — nilai di atas dibaca dari pengaturan RADIUS. Untuk mengubah, buka <b>RADIUS Settings</b> (tombol di atas).",
"mt_hint": "Mode <b>MikroTik</b> — nilai di atas dibaca dari profil PPP di router. Untuk mengubah, edit di <b>MikroTik &rarr; PPPoE Profiles</b>.",
"all_routers": "Semua Router",
"th_promo": "Promo / Prorata",
"del_pkg": "Hapus Paket",
"mode_radius_hint": "Mode RADIUS: rate-limit &amp; IP dari <b>atribut RADIUS</b> — profil PPP MikroTik tidak dibuat otomatis.",
"billing_type": "Tipe Penagihan / Billing *",
"opt_postpaid": "Pascabayar (Kalender / Jatuh Tempo Tetap)",
"opt_prepaid": "Prabayar (Masa Aktif Bergulir)",
"validity_days": "Durasi Masa Aktif (Hari) *",
"ph_down": "Contoh: 10",
"ph_up": "Contoh: 5",
"ph_upto_down": "Kosongkan jika tanpa UpTo (mis: 20)",
"ph_upto_up": "Kosongkan jika tanpa UpTo (mis: 10)",
"upto_hint": "Bila diisi, paket akan tampil sebagai: <strong>10 Mbps (Up to 20 Mbps)</strong> di invoice & portal pelanggan.",
"promo_price": "Harga promo (Rp / siklus)",
"promo_cycles": "Jumlah bulan promo",
"ph_promo_price": "Opsional, mis. 99000",
"ph_promo_cycles": "0 = tanpa promo",
"ppn_pct": "Persentase PPN (%)",
"uso_pct": "Persentase ULO/USO (%)",
"pool_name": "Nama IP Pool",
"pool_ranges": "Rentang IP (ranges)",
"isolir_profile": "Profil Isolir (paket ini)",
"ph_isolir_profile": "— pakai default global/customer —",
"night_profile": "Nama Profile Malam (MikroTik)",
"ph_night_profile": "-- Pilih Profile --",
"night_down": "Download Malam (Mbps)"
} }
}, },
"tech": { "tech": {
+22 -22
View File
@@ -221,9 +221,9 @@
<option value=""><%= t('admin.olts.no_data', 'Tidak ada data OLT') %></option> <option value=""><%= t('admin.olts.no_data', 'Tidak ada data OLT') %></option>
<% } else if (olts.length === 1) { %> <% } else if (olts.length === 1) { %>
<option value="<%= olts[0].id %>" <%= olts[0].is_active ? '' : 'disabled' %> selected><%= olts[0].name %> (<%= olts[0].host %>)</option> <option value="<%= olts[0].id %>" <%= olts[0].is_active ? '' : 'disabled' %> selected><%= olts[0].name %> (<%= olts[0].host %>)</option>
<option value="all"> Semua OLT (Ringkasan Total)</option> <option value="all"> <%= t('admin.olt.all_summary','Semua OLT (Ringkasan Total)') %></option>
<% } else { %> <% } else { %>
<option value="all"> Semua OLT (Ringkasan Total)</option> <option value="all"> <%= t('admin.olt.all_summary','Semua OLT (Ringkasan Total)') %></option>
<% olts.forEach(olt => { %> <% olts.forEach(olt => { %>
<option value="<%= olt.id %>" <%= olt.is_active ? '' : 'disabled' %>><%= olt.name %> (<%= olt.host %>)</option> <option value="<%= olt.id %>" <%= olt.is_active ? '' : 'disabled' %>><%= olt.name %> (<%= olt.host %>)</option>
<% }) %> <% }) %>
@@ -295,8 +295,8 @@
<div style="background:#0f172a; padding:12px; border-radius:8px; border:1px solid #334155;"> <div style="background:#0f172a; padding:12px; border-radius:8px; border:1px solid #334155;">
<div class="text-muted fw-bold mb-2" style="font-size:11px; text-transform:uppercase; color:#94a3b8;"><i class="bi bi-hdd-rack"></i> Profil & Parameter Connection</div> <div class="text-muted fw-bold mb-2" style="font-size:11px; text-transform:uppercase; color:#94a3b8;"><i class="bi bi-hdd-rack"></i> Profil & Parameter Connection</div>
<div class="mb-1">Profil SNMP: <strong id="oid-profile-name" style="color:#38bdf8;">-</strong></div> <div class="mb-1">Profil SNMP: <strong id="oid-profile-name" style="color:#38bdf8;">-</strong></div>
<div class="mb-1">Host OLT: <strong id="oid-host">-</strong></div> <div class="mb-1"><%= t('admin.olt.host','Host OLT:') %> <strong id="oid-host">-</strong></div>
<div class="mb-1">Port SNMP: <strong id="oid-port">161</strong></div> <div class="mb-1"><%= t('admin.olt.snmp_port','Port SNMP:') %> <strong id="oid-port">161</strong></div>
<div>Community: <strong id="oid-community" style="color:#4ade80;">public</strong></div> <div>Community: <strong id="oid-community" style="color:#4ade80;">public</strong></div>
</div> </div>
</div> </div>
@@ -362,7 +362,7 @@
<th>PORT/INDEX</th> <th>PORT/INDEX</th>
<th>SN / SERIAL NUMBER</th> <th>SN / SERIAL NUMBER</th>
<th>TYPE</th> <th>TYPE</th>
<th>AKSI</th> <th><%= t('admin.olt.th_action','AKSI') %></th>
</tr> </tr>
</thead> </thead>
<tbody id="unauth-table-body"> <tbody id="unauth-table-body">
@@ -398,7 +398,7 @@
<tr> <tr>
<th><%= t('admin.olts.table.no', 'No') %></th> <th><%= t('admin.olts.table.no', 'No') %></th>
<th><%= t('admin.olts.table.id', 'Id') %></th> <th><%= t('admin.olts.table.id', 'Id') %></th>
<th>Nama ONU / Pelanggan</th> <th><%= t('admin.olt.th_onu_name','Nama ONU / Pelanggan') %></th>
<th><%= t('admin.olts.table.serial', 'Serial Number') %></th> <th><%= t('admin.olts.table.serial', 'Serial Number') %></th>
<th><%= t('admin.olts.table.status', 'Status') %></th> <th><%= t('admin.olts.table.status', 'Status') %></th>
<th><%= t('admin.olts.table.tx', 'TxPower') %></th> <th><%= t('admin.olts.table.tx', 'TxPower') %></th>
@@ -456,7 +456,7 @@
<div class="act-menu"> <div class="act-menu">
<button type="button" class="act-item primary" onclick="testExistingOlt('<%= olt.id %>')"><i class="bi bi-broadcast"></i> <%= t('admin.dash.test_conn','Test Koneksi') %></button> <button type="button" class="act-item primary" onclick="testExistingOlt('<%= olt.id %>')"><i class="bi bi-broadcast"></i> <%= t('admin.dash.test_conn','Test Koneksi') %></button>
<button type="button" class="act-item" onclick="editOlt('<%= olt.id %>')"><i class="bi bi-pencil"></i> Edit OLT</button> <button type="button" class="act-item" onclick="editOlt('<%= olt.id %>')"><i class="bi bi-pencil"></i> Edit OLT</button>
<button type="submit" form="odl-<%= olt.id %>" class="act-item danger"><i class="bi bi-trash"></i> Hapus OLT</button> <button type="submit" form="odl-<%= olt.id %>" class="act-item danger"><i class="bi bi-trash"></i> <%= t('admin.olt.del_olt','Hapus OLT') %></button>
</div> </div>
</div> </div>
</td> </td>
@@ -492,7 +492,7 @@
<option value="hioso">HIOSO (EPON / GPON)</option> <option value="hioso">HIOSO (EPON / GPON)</option>
<option value="hsgq">HSGQ (EPON / GPON)</option> <option value="hsgq">HSGQ (EPON / GPON)</option>
<option value="bdcom">BDCOM (EPON / GPON)</option> <option value="bdcom">BDCOM (EPON / GPON)</option>
<option value="generic">Generic / Lainnya (Standard SNMP EPON/GPON)</option> <option value="generic"><%= t('admin.olt.opt_generic','Generic / Lainnya (Standard SNMP EPON/GPON)') %></option>
</select> </select>
</div> </div>
</div> </div>
@@ -503,7 +503,7 @@
</div> </div>
<div class="form-row"> <div class="form-row">
<div class="fg"><label class="fl">Telnet port</label><input type="number" name="telnet_port" class="fc" value="23" min="1" max="65535"></div> <div class="fg"><label class="fl">Telnet port</label><input type="number" name="telnet_port" class="fc" value="23" min="1" max="65535"></div>
<div class="fg"><label class="fl">Enable password (ZTE)</label><input type="password" name="enable_password" class="fc" placeholder="zxr10 (opsional)"></div> <div class="fg"><label class="fl">Enable password (ZTE)</label><input type="password" name="enable_password" class="fc" placeholder="<%= t('admin.olt.ph_enable_pw','zxr10 (opsional)') %>"></div>
</div> </div>
<div class="fg"><label class="fl">API Base URL (go-api-c320 ZTE)</label><input type="url" name="api_base_url" class="fc" placeholder="http://127.0.0.1:8081 — kosong jika tidak pakai"></div> <div class="fg"><label class="fl">API Base URL (go-api-c320 ZTE)</label><input type="url" name="api_base_url" class="fc" placeholder="http://127.0.0.1:8081 — kosong jika tidak pakai"></div>
<div class="fg"><label class="fl"><%= t('admin.olts.form.description', 'Deskripsi / Lokasi') %></label><textarea name="description" class="fc" rows="2"></textarea></div> <div class="fg"><label class="fl"><%= t('admin.olts.form.description', 'Deskripsi / Lokasi') %></label><textarea name="description" class="fc" rows="2"></textarea></div>
@@ -540,7 +540,7 @@
<option value="hioso">HIOSO (EPON / GPON)</option> <option value="hioso">HIOSO (EPON / GPON)</option>
<option value="hsgq">HSGQ (EPON / GPON)</option> <option value="hsgq">HSGQ (EPON / GPON)</option>
<option value="bdcom">BDCOM (EPON / GPON)</option> <option value="bdcom">BDCOM (EPON / GPON)</option>
<option value="generic">Generic / Lainnya (Standard SNMP EPON/GPON)</option> <option value="generic"><%= t('admin.olt.opt_generic','Generic / Lainnya (Standard SNMP EPON/GPON)') %></option>
</select> </select>
</div> </div>
</div> </div>
@@ -551,7 +551,7 @@
</div> </div>
<div class="form-row"> <div class="form-row">
<div class="fg"><label class="fl">Telnet port</label><input type="number" name="telnet_port" id="e_telnet_port" class="fc" min="1" max="65535"></div> <div class="fg"><label class="fl">Telnet port</label><input type="number" name="telnet_port" id="e_telnet_port" class="fc" min="1" max="65535"></div>
<div class="fg"><label class="fl">Enable password (ZTE)</label><input type="password" name="enable_password" id="e_enable_password" class="fc" placeholder="Kosongkan jika tidak diubah"></div> <div class="fg"><label class="fl">Enable password (ZTE)</label><input type="password" name="enable_password" id="e_enable_password" class="fc" placeholder="<%= t('admin.olt.ph_enable_pw2','Kosongkan jika tidak diubah') %>"></div>
</div> </div>
<div class="fg"><label class="fl">API Base URL (go-api-c320)</label><input type="url" name="api_base_url" id="e_api_base_url" class="fc" placeholder="http://IP:8081"></div> <div class="fg"><label class="fl">API Base URL (go-api-c320)</label><input type="url" name="api_base_url" id="e_api_base_url" class="fc" placeholder="http://IP:8081"></div>
<div class="fg"><label class="fl"><%= t('admin.olts.form.description', 'Deskripsi / Lokasi') %></label><textarea name="description" id="e_description" class="fc" rows="2"></textarea></div> <div class="fg"><label class="fl"><%= t('admin.olts.form.description', 'Deskripsi / Lokasi') %></label><textarea name="description" id="e_description" class="fc" rows="2"></textarea></div>
@@ -579,7 +579,7 @@
<div class="mo" id="wanConfigModal"> <div class="mo" id="wanConfigModal">
<div class="mb" style="max-width: 500px;"> <div class="mb" style="max-width: 500px;">
<div class="mh"> <div class="mh">
<span class="mt"><i class="bi bi-globe"></i> Konfigurasi WAN ONU</span> <span class="mt"><i class="bi bi-globe"></i> <%= t('admin.olt.wan_title','Konfigurasi WAN ONU') %></span>
<button type="button" class="mc" onclick="closeModal('wanConfigModal')">&times;</button> <button type="button" class="mc" onclick="closeModal('wanConfigModal')">&times;</button>
</div> </div>
<form id="wanConfigForm" onsubmit="submitWanConfig(event)"> <form id="wanConfigForm" onsubmit="submitWanConfig(event)">
@@ -589,12 +589,12 @@
<input type="hidden" id="wan_onu_sn"> <input type="hidden" id="wan_onu_sn">
<div class="fg"> <div class="fg">
<label class="fl">NAMA ONU</label> <label class="fl"><%= t('admin.olt.wan_name','NAMA ONU') %></label>
<input type="text" id="wan_onu_name" class="fc" readonly> <input type="text" id="wan_onu_name" class="fc" readonly>
</div> </div>
<div class="fg"> <div class="fg">
<label class="fl">METODE KONFIGURASI</label> <label class="fl"><%= t('admin.olt.wan_method','METODE KONFIGURASI') %></label>
<select id="wan_method" class="fs" onchange="onWanMethodChange()"> <select id="wan_method" class="fs" onchange="onWanMethodChange()">
<option value="telnet">Telnet CLI (OLT OMCI)</option> <option value="telnet">Telnet CLI (OLT OMCI)</option>
<option value="go-api">REST go-api-c320 (ZTE VLAN / service-port)</option> <option value="go-api">REST go-api-c320 (ZTE VLAN / service-port)</option>
@@ -606,7 +606,7 @@
</div> </div>
<div class="fg"> <div class="fg">
<label class="fl">MODE WAN</label> <label class="fl"><%= t('admin.olt.wan_mode','MODE WAN') %></label>
<select id="wan_mode" class="fs" onchange="toggleWanFields()"> <select id="wan_mode" class="fs" onchange="toggleWanFields()">
<option value="Bridge">Bridge</option> <option value="Bridge">Bridge</option>
<option value="PPPoE">PPPoE</option> <option value="PPPoE">PPPoE</option>
@@ -619,11 +619,11 @@
</div> </div>
<div id="wan_goapi_extra" style="display:none"> <div id="wan_goapi_extra" style="display:none">
<div class="form-row"> <div class="form-row">
<div class="fg"><label class="fl">CVLAN (opsional)</label><input type="number" id="wan_cvlan" class="fc" min="1" max="4094" placeholder="Default = VLAN"></div> <div class="fg"><label class="fl"><%= t('admin.olt.wan_cvlan','CVLAN (opsional)') %></label><input type="number" id="wan_cvlan" class="fc" min="1" max="4094" placeholder="<%= t('admin.olt.ph_cvlan','Default = VLAN') %>"></div>
<div class="fg"><label class="fl">Priority (0–7)</label><input type="number" id="wan_priority" class="fc" min="0" max="7" value="0"></div> <div class="fg"><label class="fl">Priority (0–7)</label><input type="number" id="wan_priority" class="fc" min="0" max="7" value="0"></div>
</div> </div>
<div class="fg"> <div class="fg">
<label class="fl">VLAN mode</label> <label class="fl"><%= t('admin.olt.wan_vlan_mode','VLAN mode') %></label>
<select id="wan_vlan_mode" class="fs"> <select id="wan_vlan_mode" class="fs">
<option value="tag">tag</option> <option value="tag">tag</option>
<option value="translation">translation</option> <option value="translation">translation</option>
@@ -633,7 +633,7 @@
</div> </div>
<div class="fg"> <div class="fg">
<label class="fl">BINDING LAN</label> <label class="fl"><%= t('admin.olt.wan_bind_lan','BINDING LAN') %></label>
<div class="d-flex flex-wrap gap-3 mt-1"> <div class="d-flex flex-wrap gap-3 mt-1">
<label class="d-flex align-items-center gap-1 small cursor-pointer"><input type="checkbox" name="wan_lan" value="1" checked> LAN1</label> <label class="d-flex align-items-center gap-1 small cursor-pointer"><input type="checkbox" name="wan_lan" value="1" checked> LAN1</label>
<label class="d-flex align-items-center gap-1 small cursor-pointer"><input type="checkbox" name="wan_lan" value="2"> LAN2</label> <label class="d-flex align-items-center gap-1 small cursor-pointer"><input type="checkbox" name="wan_lan" value="2"> LAN2</label>
@@ -643,7 +643,7 @@
</div> </div>
<div class="fg"> <div class="fg">
<label class="fl">BINDING SSID (WIFI)</label> <label class="fl"><%= t('admin.olt.wan_bind_ssid','BINDING SSID (WIFI)') %></label>
<div class="d-flex flex-wrap gap-3 mt-1"> <div class="d-flex flex-wrap gap-3 mt-1">
<label class="d-flex align-items-center gap-1 small cursor-pointer"><input type="checkbox" name="wan_ssid" value="1" checked> SSID1</label> <label class="d-flex align-items-center gap-1 small cursor-pointer"><input type="checkbox" name="wan_ssid" value="1" checked> SSID1</label>
<label class="d-flex align-items-center gap-1 small cursor-pointer"><input type="checkbox" name="wan_ssid" value="2"> SSID2</label> <label class="d-flex align-items-center gap-1 small cursor-pointer"><input type="checkbox" name="wan_ssid" value="2"> SSID2</label>
@@ -794,7 +794,7 @@ async function loadOltDashboard(id) {
<tr style="border-top:2px solid #334155; background:rgba(255,255,255,0.03);"> <tr style="border-top:2px solid #334155; background:rgba(255,255,255,0.03);">
<td colspan="2" style="color:#38bdf8; font-weight:bold; padding-top:8px;">OLT #${idx+1}: ${oSummary.name} (${oSummary.host}) - Brand: ${brand} [${oSummary.status}]</td> <td colspan="2" style="color:#38bdf8; font-weight:bold; padding-top:8px;">OLT #${idx+1}: ${oSummary.name} (${oSummary.host}) - Brand: ${brand} [${oSummary.status}]</td>
</tr> </tr>
<tr><td>Profil SNMP Aktif</td><td><code>${prof ? prof.name : (oSummary.error || 'Pending/No Match')}</code></td></tr> <tr><td><%= t('admin.olt.oid_active','Profil SNMP Aktif') %></td><td><code>${prof ? prof.name : (oSummary.error || 'Pending/No Match')}</code></td></tr>
<tr><td>OID Status Table</td><td><code>${prof ? prof.status_table : '-'}</code></td></tr> <tr><td>OID Status Table</td><td><code>${prof ? prof.status_table : '-'}</code></td></tr>
<tr><td>OID Name Table</td><td><code>${prof ? prof.name_table : '-'}</code></td></tr> <tr><td>OID Name Table</td><td><code>${prof ? prof.name_table : '-'}</code></td></tr>
<tr><td>OID Serial Table</td><td><code>${prof ? prof.sn_table : '-'}</code></td></tr> <tr><td>OID Serial Table</td><td><code>${prof ? prof.sn_table : '-'}</code></td></tr>
@@ -1163,10 +1163,10 @@ async function testFormOlt(type) {
const data = await res.json(); const data = await res.json();
if (data.success) { if (data.success) {
resultDiv.className = 'alert alert-s small mt-2'; resultDiv.className = 'alert alert-s small mt-2';
resultDiv.innerHTML = '<i class="bi bi-check-circle-fill"></i> <strong>Koneksi Sukses!</strong><br>' + (data.message || 'OLT merespons.'); resultDiv.innerHTML = '<i class="bi bi-check-circle-fill"></i> <strong><%= t('admin.olt.conn_ok','Koneksi Sukses!') %></strong><br>' + (data.message || 'OLT merespons.');
} else { } else {
resultDiv.className = 'alert alert-d small mt-2'; resultDiv.className = 'alert alert-d small mt-2';
resultDiv.innerHTML = '<i class="bi bi-exclamation-triangle-fill"></i> <strong>Koneksi Gagal:</strong><br>' + (data.message || data.error); resultDiv.innerHTML = '<i class="bi bi-exclamation-triangle-fill"></i> <strong><%= t('admin.olt.conn_fail','Koneksi Gagal:') %></strong><br>' + (data.message || data.error);
} }
} catch (e) { } catch (e) {
resultDiv.className = 'alert alert-d small mt-2'; resultDiv.className = 'alert alert-d small mt-2';
+49 -49
View File
@@ -51,22 +51,22 @@
<div class="card-bd"> <div class="card-bd">
<% if (isolirSource === 'radius') { %> <% if (isolirSource === 'radius') { %>
<div class="form-row"> <div class="form-row">
<div class="fg"><label class="fl">Aksi isolir</label><div class="mono"><%= radiusIsolir.action %></div></div> <div class="fg"><label class="fl"><%= t('admin.pkg.isolir_action','Aksi isolir') %></label><div class="mono"><%= radiusIsolir.action %></div></div>
<div class="fg"><label class="fl">Rate-limit</label><div class="mono"><%= radiusIsolir.rateLimit %></div></div> <div class="fg"><label class="fl">Rate-limit</label><div class="mono"><%= radiusIsolir.rateLimit %></div></div>
<div class="fg"><label class="fl">Pool</label><div class="mono"><%= radiusIsolir.pool %></div></div> <div class="fg"><label class="fl">Pool</label><div class="mono"><%= radiusIsolir.pool %></div></div>
<div class="fg"><label class="fl">IP Pool isolir</label><div class="mono"><%= radiusIsolir.ipPoolEnabled ? (radiusIsolir.ipPoolStart + ' – ' + radiusIsolir.ipPoolEnd) : 'nonaktif' %></div></div> <div class="fg"><label class="fl"><%= t('admin.pkg.isolir_ip_pool','IP Pool isolir') %></label><div class="mono"><%= radiusIsolir.ipPoolEnabled ? (radiusIsolir.ipPoolStart + ' – ' + radiusIsolir.ipPoolEnd) : 'nonaktif' %></div></div>
</div> </div>
<div class="hint"><i class="bi bi-info-circle"></i> Mode <b>RADIUS</b> — nilai di atas dibaca dari pengaturan RADIUS. Untuk mengubah, buka <b>RADIUS Settings</b> (tombol di atas).</div> <div class="hint"><i class="bi bi-info-circle"></i> <%- t('admin.pkg.radius_hint','Mode <b>RADIUS</b> — nilai di atas dibaca dari pengaturan RADIUS. Untuk mengubah, buka <b>RADIUS Settings</b> (tombol di atas).') %></div>
<% } else { %> <% } else { %>
<div class="form-row"> <div class="form-row">
<div class="fg"><label class="fl">Nama Profil</label><div class="mono"><%= isolirProfileName %></div></div> <div class="fg"><label class="fl"><%= t('admin.pkg.prof_name','Nama Profil') %></label><div class="mono"><%= isolirProfileName %></div></div>
<div class="fg"><label class="fl">Rate-limit (live)</label><div class="mono"><%= isolirExists ? (isolirLiveRl || '-') : '—' %></div></div> <div class="fg"><label class="fl">Rate-limit (live)</label><div class="mono"><%= isolirExists ? (isolirLiveRl || '-') : '—' %></div></div>
</div> </div>
<div class="form-row"> <div class="form-row">
<div class="fg"><label class="fl">Local Address (live)</label><div class="mono"><%= isolirExists ? (isolirLiveLocal || '-') : '—' %></div></div> <div class="fg"><label class="fl">Local Address (live)</label><div class="mono"><%= isolirExists ? (isolirLiveLocal || '-') : '—' %></div></div>
<div class="fg"><label class="fl">Remote / Pool (live)</label><div class="mono"><%= isolirExists ? (isolirLiveRemote || '-') : '—' %></div></div> <div class="fg"><label class="fl">Remote / Pool (live)</label><div class="mono"><%= isolirExists ? (isolirLiveRemote || '-') : '—' %></div></div>
</div> </div>
<div class="hint"><i class="bi bi-info-circle"></i> Mode <b>MikroTik</b> — nilai di atas dibaca dari profil PPP di router. Untuk mengubah, edit di <b>MikroTik &rarr; PPPoE Profiles</b>.</div> <div class="hint"><i class="bi bi-info-circle"></i> <%- t('admin.pkg.mt_hint','Mode <b>MikroTik</b> — nilai di atas dibaca dari profil PPP di router. Untuk mengubah, edit di <b>MikroTik &rarr; PPPoE Profiles</b>.') %></div>
<% } %> <% } %>
</div> </div>
</div> </div>
@@ -77,7 +77,7 @@
<div style="display:flex;align-items:center;gap:10px"> <div style="display:flex;align-items:center;gap:10px">
<% if (typeof routers !== 'undefined' && routers && routers.length > 0) { %> <% if (typeof routers !== 'undefined' && routers && routers.length > 0) { %>
<select class="fs" style="width:160px" onchange="window.location.href='/admin/set-active-router?router_id=' + this.value"> <select class="fs" style="width:160px" onchange="window.location.href='/admin/set-active-router?router_id=' + this.value">
<option value="all" <%= (!selectedRouterId) ? 'selected' : '' %>> Semua Router</option> <option value="all" <%= (!selectedRouterId) ? 'selected' : '' %>> <%= t('admin.pkg.all_routers','Semua Router') %></option>
<% routers.forEach(r => { %> <% routers.forEach(r => { %>
<option value="<%= r.id %>" <%= (selectedRouterId === r.id) ? 'selected' : '' %>> <%= r.name %></option> <option value="<%= r.id %>" <%= (selectedRouterId === r.id) ? 'selected' : '' %>> <%= r.name %></option>
<% }) %> <% }) %>
@@ -93,7 +93,7 @@
<th>#</th> <th>#</th>
<th><%= t('admin.packages.table.name', 'Nama Paket') %></th> <th><%= t('admin.packages.table.name', 'Nama Paket') %></th>
<th><%= t('admin.packages.table.price_month', 'Harga / Bulan') %></th> <th><%= t('admin.packages.table.price_month', 'Harga / Bulan') %></th>
<th>Promo / Prorata</th> <th><%= t('admin.pkg.th_promo','Promo / Prorata') %></th>
<th><%= t('admin.packages.table.speed', 'Kecepatan') %></th> <th><%= t('admin.packages.table.speed', 'Kecepatan') %></th>
<th><%= t('admin.packages.table.description', 'Deskripsi') %></th> <th><%= t('admin.packages.table.description', 'Deskripsi') %></th>
<th><%= t('admin.packages.table.isolir', 'Profil Isolir') %></th> <th><%= t('admin.packages.table.isolir', 'Profil Isolir') %></th>
@@ -158,7 +158,7 @@
<div class="act-menu"> <div class="act-menu">
<button type="button" class="act-item" data-idx="<%= i %>" onclick="editPkg(+this.dataset.idx)"><i class="bi bi-pencil"></i> Edit Paket</button> <button type="button" class="act-item" data-idx="<%= i %>" onclick="editPkg(+this.dataset.idx)"><i class="bi bi-pencil"></i> Edit Paket</button>
<div class="act-sep"></div> <div class="act-sep"></div>
<button type="submit" form="pkdel-<%= p.id %>" class="act-item danger"><i class="bi bi-trash"></i> Hapus Paket</button> <button type="submit" form="pkdel-<%= p.id %>" class="act-item danger"><i class="bi bi-trash"></i> <%= t('admin.pkg.del_pkg','Hapus Paket') %></button>
</div> </div>
</div> </div>
</td> </td>
@@ -188,7 +188,7 @@
</div> </div>
<div class="hint" style="margin:-2px 0 10px;font-size:11px"> <div class="hint" style="margin:-2px 0 10px;font-size:11px">
<% if (typeof profileMode !== 'undefined' && profileMode === 'radius-attributes') { %> <% if (typeof profileMode !== 'undefined' && profileMode === 'radius-attributes') { %>
<i class="bi bi-broadcast"></i> Mode RADIUS: rate-limit &amp; IP dari <b>atribut RADIUS</b> — profil PPP MikroTik tidak dibuat otomatis. <i class="bi bi-broadcast"></i> <%- t('admin.pkg.mode_radius_hint','Mode RADIUS: rate-limit &amp; IP dari <b>atribut RADIUS</b> — profil PPP MikroTik tidak dibuat otomatis.') %>
<% } else { %> <% } else { %>
<i class="bi bi-router"></i> Profil PPP MikroTik akan <b>dibuat/diperbarui otomatis</b> dari speed paket<% if (typeof profileMode !== 'undefined' && profileMode === 'radius-profile') { %> (mode RADIUS pakai profil MikroTik)<% } %>. <i class="bi bi-router"></i> Profil PPP MikroTik akan <b>dibuat/diperbarui otomatis</b> dari speed paket<% if (typeof profileMode !== 'undefined' && profileMode === 'radius-profile') { %> (mode RADIUS pakai profil MikroTik)<% } %>.
<% } %> <% } %>
@@ -204,14 +204,14 @@
<!-- Tipe Billing: Pascabayar vs Prabayar --> <!-- Tipe Billing: Pascabayar vs Prabayar -->
<div class="form-row" style="background:rgba(99,102,241,0.05);padding:12px 14px;border-radius:10px;margin-top:10px;border:1px solid rgba(99,102,241,0.15);"> <div class="form-row" style="background:rgba(99,102,241,0.05);padding:12px 14px;border-radius:10px;margin-top:10px;border:1px solid rgba(99,102,241,0.15);">
<div class="fg"> <div class="fg">
<label class="fl"><i class="bi bi-credit-card-2-front text-primary me-1"></i> Tipe Penagihan / Billing *</label> <label class="fl"><i class="bi bi-credit-card-2-front text-primary me-1"></i> <%= t('admin.pkg.billing_type','Tipe Penagihan / Billing *') %></label>
<select class="fs" name="billing_type" id="add_billing_type" onchange="toggleAddBillingType(this.value)"> <select class="fs" name="billing_type" id="add_billing_type" onchange="toggleAddBillingType(this.value)">
<option value="postpaid" selected>Pascabayar (Kalender / Jatuh Tempo Tetap)</option> <option value="postpaid" selected><%= t('admin.pkg.opt_postpaid','Pascabayar (Kalender / Jatuh Tempo Tetap)') %></option>
<option value="prepaid">Prabayar (Masa Aktif Bergulir)</option> <option value="prepaid"><%= t('admin.pkg.opt_prepaid','Prabayar (Masa Aktif Bergulir)') %></option>
</select> </select>
</div> </div>
<div class="fg" id="add_duration_days_fg" style="display:none"> <div class="fg" id="add_duration_days_fg" style="display:none">
<label class="fl"><i class="bi bi-clock-history text-warning me-1"></i> Durasi Masa Aktif (Hari) *</label> <label class="fl"><i class="bi bi-clock-history text-warning me-1"></i> <%= t('admin.pkg.validity_days','Durasi Masa Aktif (Hari) *') %></label>
<input class="fc" name="duration_days" id="add_duration_days" type="number" min="1" value="30" placeholder="30"> <input class="fc" name="duration_days" id="add_duration_days" type="number" min="1" value="30" placeholder="30">
<small class="text-muted" style="font-size:11px;display:block;margin-top:2px;"> <small class="text-muted" style="font-size:11px;display:block;margin-top:2px;">
Pelanggan aktif selama X hari sejak aktivasi / pembayaran. Pelanggan aktif selama X hari sejak aktivasi / pembayaran.
@@ -223,11 +223,11 @@
<div class="form-row" style="background:rgba(59,130,246,0.04);padding:12px 14px;border-radius:10px;margin-top:10px;border:1px solid rgba(59,130,246,0.12);"> <div class="form-row" style="background:rgba(59,130,246,0.04);padding:12px 14px;border-radius:10px;margin-top:10px;border:1px solid rgba(59,130,246,0.12);">
<div class="fg"> <div class="fg">
<label class="fl" style="color:var(--primary);font-weight:700;"><i class="bi bi-download"></i> Kecepatan Download (Mbps) *</label> <label class="fl" style="color:var(--primary);font-weight:700;"><i class="bi bi-download"></i> Kecepatan Download (Mbps) *</label>
<input class="fc" name="speed_down" id="add_down" type="number" step="any" min="0" placeholder="Contoh: 10" required> <input class="fc" name="speed_down" id="add_down" type="number" step="any" min="0" placeholder="<%= t('admin.pkg.ph_down','Contoh: 10') %>" required>
</div> </div>
<div class="fg"> <div class="fg">
<label class="fl" style="color:var(--info);font-weight:700;"><i class="bi bi-upload"></i> Kecepatan Upload (Mbps) *</label> <label class="fl" style="color:var(--info);font-weight:700;"><i class="bi bi-upload"></i> Kecepatan Upload (Mbps) *</label>
<input class="fc" name="speed_up" id="add_up" type="number" step="any" min="0" placeholder="Contoh: 5" required> <input class="fc" name="speed_up" id="add_up" type="number" step="any" min="0" placeholder="<%= t('admin.pkg.ph_up','Contoh: 5') %>" required>
</div> </div>
</div> </div>
<div class="hint" style="margin-top:6px;font-size:11px"> <div class="hint" style="margin-top:6px;font-size:11px">
@@ -241,22 +241,22 @@
<div class="form-row"> <div class="form-row">
<div class="fg"> <div class="fg">
<label class="fl">Download UpTo (Mbps)</label> <label class="fl">Download UpTo (Mbps)</label>
<input class="fc" name="speed_down_upto" id="add_down_upto" type="number" step="any" min="0" placeholder="Kosongkan jika tanpa UpTo (mis: 20)"> <input class="fc" name="speed_down_upto" id="add_down_upto" type="number" step="any" min="0" placeholder="<%= t('admin.pkg.ph_upto_down','Kosongkan jika tanpa UpTo (mis: 20)') %>">
</div> </div>
<div class="fg"> <div class="fg">
<label class="fl">Upload UpTo (Mbps)</label> <label class="fl">Upload UpTo (Mbps)</label>
<input class="fc" name="speed_up_upto" id="add_up_upto" type="number" step="any" min="0" placeholder="Kosongkan jika tanpa UpTo (mis: 10)"> <input class="fc" name="speed_up_upto" id="add_up_upto" type="number" step="any" min="0" placeholder="<%= t('admin.pkg.ph_upto_up','Kosongkan jika tanpa UpTo (mis: 10)') %>">
</div> </div>
</div> </div>
<small class="text-muted" style="font-size:11px;display:block;margin-top:2px;"> <small class="text-muted" style="font-size:11px;display:block;margin-top:2px;">
Bila diisi, paket akan tampil sebagai: <strong>10 Mbps (Up to 20 Mbps)</strong> di invoice & portal pelanggan. <%- t('admin.pkg.upto_hint','Bila diisi, paket akan tampil sebagai: <strong>10 Mbps (Up to 20 Mbps)</strong> di invoice & portal pelanggan.') %>
</small> </small>
</div> </div>
<div style="background: rgba(34,197,94,0.06); padding: 12px 14px; border-radius: 10px; margin-top: 10px;"> <div style="background: rgba(34,197,94,0.06); padding: 12px 14px; border-radius: 10px; margin-top: 10px;">
<div class="fw6" style="font-size:12px;margin-bottom:8px;color:var(--success)"><i class="bi bi-percent"></i> Promo & prorata tagihan</div> <div class="fw6" style="font-size:12px;margin-bottom:8px;color:var(--success)"><i class="bi bi-percent"></i> Promo & prorata tagihan</div>
<div class="form-row"> <div class="form-row">
<div class="fg"><label class="fl">Harga promo (Rp / siklus)</label><input class="fc" name="promo_price" type="number" min="0" placeholder="Opsional, mis. 99000"></div> <div class="fg"><label class="fl"><%= t('admin.pkg.promo_price','Harga promo (Rp / siklus)') %></label><input class="fc" name="promo_price" type="number" min="0" placeholder="<%= t('admin.pkg.ph_promo_price','Opsional, mis. 99000') %>"></div>
<div class="fg"><label class="fl">Jumlah bulan promo</label><input class="fc" name="promo_cycles" type="number" min="0" value="0" placeholder="0 = tanpa promo"></div> <div class="fg"><label class="fl"><%= t('admin.pkg.promo_cycles','Jumlah bulan promo') %></label><input class="fc" name="promo_cycles" type="number" min="0" value="0" placeholder="<%= t('admin.pkg.ph_promo_cycles','0 = tanpa promo') %>"></div>
</div> </div>
<div class="flex ai-c" style="gap:8px;margin-top:4px"> <div class="flex ai-c" style="gap:8px;margin-top:4px">
<input type="checkbox" name="prorate_first_invoice" id="add_prorate" value="1"> <input type="checkbox" name="prorate_first_invoice" id="add_prorate" value="1">
@@ -274,7 +274,7 @@
</label> </label>
</div> </div>
<div class="fg"> <div class="fg">
<label class="fl">Persentase PPN (%)</label> <label class="fl"><%= t('admin.pkg.ppn_pct','Persentase PPN (%)') %></label>
<input class="fc" name="ppn_percentage" type="number" step="any" min="0" value="11.0"> <input class="fc" name="ppn_percentage" type="number" step="any" min="0" value="11.0">
</div> </div>
</div> </div>
@@ -286,7 +286,7 @@
</label> </label>
</div> </div>
<div class="fg"> <div class="fg">
<label class="fl">Persentase ULO/USO (%)</label> <label class="fl"><%= t('admin.pkg.uso_pct','Persentase ULO/USO (%)') %></label>
<input class="fc" name="uso_percentage" type="number" step="any" min="0" value="1.75"> <input class="fc" name="uso_percentage" type="number" step="any" min="0" value="1.75">
</div> </div>
</div> </div>
@@ -298,8 +298,8 @@
<div style="background:rgba(59,130,246,0.05);padding:12px 14px;border-radius:10px;margin-top:10px;border:1px solid rgba(59,130,246,0.15);"> <div style="background:rgba(59,130,246,0.05);padding:12px 14px;border-radius:10px;margin-top:10px;border:1px solid rgba(59,130,246,0.15);">
<div class="fw6" style="font-size:12px;margin-bottom:8px;color:var(--info)"><i class="bi bi-hdd-network"></i> IP Pool &amp; Profil MikroTik <span class="text-muted" style="font-weight:400">(comment: "manage by cloud")</span></div> <div class="fw6" style="font-size:12px;margin-bottom:8px;color:var(--info)"><i class="bi bi-hdd-network"></i> IP Pool &amp; Profil MikroTik <span class="text-muted" style="font-weight:400">(comment: "manage by cloud")</span></div>
<div class="form-row"> <div class="form-row">
<div class="fg"><label class="fl">Nama IP Pool</label><input class="fc" name="pool_name" id="add_pool_name" placeholder="mis. HOME10"></div> <div class="fg"><label class="fl"><%= t('admin.pkg.pool_name','Nama IP Pool') %></label><input class="fc" name="pool_name" id="add_pool_name" placeholder="mis. HOME10"></div>
<div class="fg"><label class="fl">Rentang IP (ranges)</label><input class="fc" name="pool_ranges" id="add_pool_ranges" placeholder="10.20.0.10-10.20.0.254"></div> <div class="fg"><label class="fl"><%= t('admin.pkg.pool_ranges','Rentang IP (ranges)') %></label><input class="fc" name="pool_ranges" id="add_pool_ranges" placeholder="10.20.0.10-10.20.0.254"></div>
</div> </div>
<div class="form-row"> <div class="form-row">
<div class="fg"><label class="fl">Local Address (gateway)</label><input class="fc" name="local_address" id="add_local_address" placeholder="10.20.0.1/24"></div> <div class="fg"><label class="fl">Local Address (gateway)</label><input class="fc" name="local_address" id="add_local_address" placeholder="10.20.0.1/24"></div>
@@ -324,7 +324,7 @@
</div> </div>
</div> </div>
<div class="form-row"> <div class="form-row">
<div class="fg"><label class="fl"><i class="bi bi-shield-slash"></i> Profil Isolir (paket ini)</label><select class="fs" name="isolir_profile" id="add_isolir_profile"><option value="">— pakai default global/customer —</option></select></div> <div class="fg"><label class="fl"><i class="bi bi-shield-slash"></i> <%= t('admin.pkg.isolir_profile','Profil Isolir (paket ini)') %></label><select class="fs" name="isolir_profile" id="add_isolir_profile"><option value=""><%= t('admin.pkg.ph_isolir_profile','— pakai default global/customer —') %></option></select></div>
</div> </div>
<small class="text-muted" style="font-size:11px;display:block;margin-top:2px">Profil PPP + IP pool dibuat/diperbarui otomatis ke MikroTik (mode MikroTik / RADIUS profil). Pada mode RADIUS-atribut, IP &amp; rate-limit dari RADIUS.</small> <small class="text-muted" style="font-size:11px;display:block;margin-top:2px">Profil PPP + IP pool dibuat/diperbarui otomatis ke MikroTik (mode MikroTik / RADIUS profil). Pada mode RADIUS-atribut, IP &amp; rate-limit dari RADIUS.</small>
</div> </div>
@@ -337,16 +337,16 @@
</div> </div>
<div id="add_night_fields" style="display:none"> <div id="add_night_fields" style="display:none">
<div class="fg"> <div class="fg">
<label class="fl">Nama Profile Malam (MikroTik)</label> <label class="fl"><%= t('admin.pkg.prof_name','Nama Profil') %>e Malam (MikroTik)</label>
<div style="display:flex;gap:8px"> <div style="display:flex;gap:8px">
<select class="fs" id="add_night_profile_select" style="max-width:200px" onchange="document.getElementById('add_night_profile_input').value=this.value"> <select class="fs" id="add_night_profile_select" style="max-width:200px" onchange="document.getElementById('add_night_profile_input').value=this.value">
<option value="">-- Pilih Profile --</option> <option value=""><%= t('admin.pkg.ph_night_profile','-- Pilih Profile --') %></option>
</select> </select>
<input class="fc" name="night_profile_name" id="add_night_profile_input" placeholder="<%= t('admin.common.type_manual','Atau ketik manual...') %>"> <input class="fc" name="night_profile_name" id="add_night_profile_input" placeholder="<%= t('admin.common.type_manual','Atau ketik manual...') %>">
</div> </div>
</div> </div>
<div class="form-row"> <div class="form-row">
<div class="fg"><label class="fl">Download Malam (Mbps)</label><input class="fc" name="night_speed_down" type="number" step="any" min="0" placeholder="20"></div> <div class="fg"><label class="fl"><%= t('admin.pkg.night_down','Download Malam (Mbps)') %></label><input class="fc" name="night_speed_down" type="number" step="any" min="0" placeholder="20"></div>
<div class="fg"><label class="fl">Upload Malam (Mbps)</label><input class="fc" name="night_speed_up" type="number" step="any" min="0" placeholder="10"></div> <div class="fg"><label class="fl">Upload Malam (Mbps)</label><input class="fc" name="night_speed_up" type="number" step="any" min="0" placeholder="10"></div>
</div> </div>
<div style="font-size: 10px; color: var(--muted); margin-top: 4px;">Sistem akan ganti profile ppp pelanggan ke profile ini pada jam 00:00 - 06:00.</div> <div style="font-size: 10px; color: var(--muted); margin-top: 4px;">Sistem akan ganti profile ppp pelanggan ke profile ini pada jam 00:00 - 06:00.</div>
@@ -360,10 +360,10 @@
</div> </div>
<div id="add_fup_fields" style="display:none"> <div id="add_fup_fields" style="display:none">
<div class="fg"> <div class="fg">
<label class="fl">Nama Profile FUP (MikroTik)</label> <label class="fl"><%= t('admin.pkg.prof_name','Nama Profil') %>e FUP (MikroTik)</label>
<div style="display:flex;gap:8px"> <div style="display:flex;gap:8px">
<select class="fs" id="add_fup_profile_select" style="max-width:200px" onchange="document.getElementById('add_fup_profile_input').value=this.value"> <select class="fs" id="add_fup_profile_select" style="max-width:200px" onchange="document.getElementById('add_fup_profile_input').value=this.value">
<option value="">-- Pilih Profile --</option> <option value=""><%= t('admin.pkg.ph_night_profile','-- Pilih Profile --') %></option>
</select> </select>
<input class="fc" name="fup_profile_name" id="add_fup_profile_input" placeholder="<%= t('admin.common.type_manual','Atau ketik manual...') %>"> <input class="fc" name="fup_profile_name" id="add_fup_profile_input" placeholder="<%= t('admin.common.type_manual','Atau ketik manual...') %>">
</div> </div>
@@ -408,14 +408,14 @@
<!-- Tipe Billing: Pascabayar vs Prabayar (Edit) --> <!-- Tipe Billing: Pascabayar vs Prabayar (Edit) -->
<div class="form-row" style="background:rgba(99,102,241,0.05);padding:12px 14px;border-radius:10px;margin-top:10px;border:1px solid rgba(99,102,241,0.15);"> <div class="form-row" style="background:rgba(99,102,241,0.05);padding:12px 14px;border-radius:10px;margin-top:10px;border:1px solid rgba(99,102,241,0.15);">
<div class="fg"> <div class="fg">
<label class="fl"><i class="bi bi-credit-card-2-front text-primary me-1"></i> Tipe Penagihan / Billing *</label> <label class="fl"><i class="bi bi-credit-card-2-front text-primary me-1"></i> <%= t('admin.pkg.billing_type','Tipe Penagihan / Billing *') %></label>
<select class="fs" name="billing_type" id="e_billing_type" onchange="toggleEditBillingType(this.value)"> <select class="fs" name="billing_type" id="e_billing_type" onchange="toggleEditBillingType(this.value)">
<option value="postpaid">Pascabayar (Kalender / Jatuh Tempo Tetap)</option> <option value="postpaid"><%= t('admin.pkg.opt_postpaid','Pascabayar (Kalender / Jatuh Tempo Tetap)') %></option>
<option value="prepaid">Prabayar (Masa Aktif Bergulir)</option> <option value="prepaid"><%= t('admin.pkg.opt_prepaid','Prabayar (Masa Aktif Bergulir)') %></option>
</select> </select>
</div> </div>
<div class="fg" id="e_duration_days_fg" style="display:none"> <div class="fg" id="e_duration_days_fg" style="display:none">
<label class="fl"><i class="bi bi-clock-history text-warning me-1"></i> Durasi Masa Aktif (Hari) *</label> <label class="fl"><i class="bi bi-clock-history text-warning me-1"></i> <%= t('admin.pkg.validity_days','Durasi Masa Aktif (Hari) *') %></label>
<input class="fc" name="duration_days" id="e_duration_days" type="number" min="1" value="30" placeholder="30"> <input class="fc" name="duration_days" id="e_duration_days" type="number" min="1" value="30" placeholder="30">
<small class="text-muted" style="font-size:11px;display:block;margin-top:2px;"> <small class="text-muted" style="font-size:11px;display:block;margin-top:2px;">
Pelanggan aktif selama X hari sejak aktivasi / pembayaran. Pelanggan aktif selama X hari sejak aktivasi / pembayaran.
@@ -441,23 +441,23 @@
<div class="form-row"> <div class="form-row">
<div class="fg"> <div class="fg">
<label class="fl">Download UpTo (Mbps)</label> <label class="fl">Download UpTo (Mbps)</label>
<input class="fc" name="speed_down_upto" id="e_down_upto" type="number" step="any" min="0" placeholder="Kosongkan jika tanpa UpTo (mis: 20)"> <input class="fc" name="speed_down_upto" id="e_down_upto" type="number" step="any" min="0" placeholder="<%= t('admin.pkg.ph_upto_down','Kosongkan jika tanpa UpTo (mis: 20)') %>">
</div> </div>
<div class="fg"> <div class="fg">
<label class="fl">Upload UpTo (Mbps)</label> <label class="fl">Upload UpTo (Mbps)</label>
<input class="fc" name="speed_up_upto" id="e_up_upto" type="number" step="any" min="0" placeholder="Kosongkan jika tanpa UpTo (mis: 10)"> <input class="fc" name="speed_up_upto" id="e_up_upto" type="number" step="any" min="0" placeholder="<%= t('admin.pkg.ph_upto_up','Kosongkan jika tanpa UpTo (mis: 10)') %>">
</div> </div>
</div> </div>
<small class="text-muted" style="font-size:11px;display:block;margin-top:2px;"> <small class="text-muted" style="font-size:11px;display:block;margin-top:2px;">
Bila diisi, paket akan tampil sebagai: <strong>10 Mbps (Up to 20 Mbps)</strong> di invoice & portal pelanggan. <%- t('admin.pkg.upto_hint','Bila diisi, paket akan tampil sebagai: <strong>10 Mbps (Up to 20 Mbps)</strong> di invoice & portal pelanggan.') %>
</small> </small>
</div> </div>
<div style="background: rgba(34,197,94,0.06); padding: 12px 14px; border-radius: 10px; margin-top: 10px;"> <div style="background: rgba(34,197,94,0.06); padding: 12px 14px; border-radius: 10px; margin-top: 10px;">
<div class="fw6" style="font-size:12px;margin-bottom:8px;color:var(--success)"><i class="bi bi-percent"></i> Promo & prorata tagihan</div> <div class="fw6" style="font-size:12px;margin-bottom:8px;color:var(--success)"><i class="bi bi-percent"></i> Promo & prorata tagihan</div>
<div class="form-row"> <div class="form-row">
<div class="fg"><label class="fl">Harga promo (Rp / siklus)</label><input class="fc" name="promo_price" id="e_promo_price" type="number" min="0" placeholder="Kosong = tanpa harga promo"></div> <div class="fg"><label class="fl"><%= t('admin.pkg.promo_price','Harga promo (Rp / siklus)') %></label><input class="fc" name="promo_price" id="e_promo_price" type="number" min="0" placeholder="Kosong = tanpa harga promo"></div>
<div class="fg"><label class="fl">Jumlah bulan promo</label><input class="fc" name="promo_cycles" id="e_promo_cycles" type="number" min="0" value="0"></div> <div class="fg"><label class="fl"><%= t('admin.pkg.promo_cycles','Jumlah bulan promo') %></label><input class="fc" name="promo_cycles" id="e_promo_cycles" type="number" min="0" value="0"></div>
</div> </div>
<div class="flex ai-c" style="gap:8px;margin-top:4px"> <div class="flex ai-c" style="gap:8px;margin-top:4px">
<input type="checkbox" name="prorate_first_invoice" id="e_prorate" value="1"> <input type="checkbox" name="prorate_first_invoice" id="e_prorate" value="1">
@@ -475,7 +475,7 @@
</label> </label>
</div> </div>
<div class="fg"> <div class="fg">
<label class="fl">Persentase PPN (%)</label> <label class="fl"><%= t('admin.pkg.ppn_pct','Persentase PPN (%)') %></label>
<input class="fc" name="ppn_percentage" id="e_ppn_percentage" type="number" step="any" min="0"> <input class="fc" name="ppn_percentage" id="e_ppn_percentage" type="number" step="any" min="0">
</div> </div>
</div> </div>
@@ -487,7 +487,7 @@
</label> </label>
</div> </div>
<div class="fg"> <div class="fg">
<label class="fl">Persentase ULO/USO (%)</label> <label class="fl"><%= t('admin.pkg.uso_pct','Persentase ULO/USO (%)') %></label>
<input class="fc" name="uso_percentage" id="e_uso_percentage" type="number" step="any" min="0"> <input class="fc" name="uso_percentage" id="e_uso_percentage" type="number" step="any" min="0">
</div> </div>
</div> </div>
@@ -499,8 +499,8 @@
<div style="background:rgba(59,130,246,0.05);padding:12px 14px;border-radius:10px;margin-top:10px;border:1px solid rgba(59,130,246,0.15);"> <div style="background:rgba(59,130,246,0.05);padding:12px 14px;border-radius:10px;margin-top:10px;border:1px solid rgba(59,130,246,0.15);">
<div class="fw6" style="font-size:12px;margin-bottom:8px;color:var(--info)"><i class="bi bi-hdd-network"></i> IP Pool &amp; Profil MikroTik <span class="text-muted" style="font-weight:400">(comment: "manage by cloud")</span></div> <div class="fw6" style="font-size:12px;margin-bottom:8px;color:var(--info)"><i class="bi bi-hdd-network"></i> IP Pool &amp; Profil MikroTik <span class="text-muted" style="font-weight:400">(comment: "manage by cloud")</span></div>
<div class="form-row"> <div class="form-row">
<div class="fg"><label class="fl">Nama IP Pool</label><input class="fc" name="pool_name" id="e_pool_name" placeholder="mis. HOME10"></div> <div class="fg"><label class="fl"><%= t('admin.pkg.pool_name','Nama IP Pool') %></label><input class="fc" name="pool_name" id="e_pool_name" placeholder="mis. HOME10"></div>
<div class="fg"><label class="fl">Rentang IP (ranges)</label><input class="fc" name="pool_ranges" id="e_pool_ranges" placeholder="10.20.0.10-10.20.0.254"></div> <div class="fg"><label class="fl"><%= t('admin.pkg.pool_ranges','Rentang IP (ranges)') %></label><input class="fc" name="pool_ranges" id="e_pool_ranges" placeholder="10.20.0.10-10.20.0.254"></div>
</div> </div>
<div class="form-row"> <div class="form-row">
<div class="fg"><label class="fl">Local Address (gateway)</label><input class="fc" name="local_address" id="e_local_address" placeholder="10.20.0.1/24"></div> <div class="fg"><label class="fl">Local Address (gateway)</label><input class="fc" name="local_address" id="e_local_address" placeholder="10.20.0.1/24"></div>
@@ -525,7 +525,7 @@
</div> </div>
</div> </div>
<div class="form-row"> <div class="form-row">
<div class="fg"><label class="fl"><i class="bi bi-shield-slash"></i> Profil Isolir (paket ini)</label><select class="fs" name="isolir_profile" id="e_isolir_profile"><option value="">— pakai default global/customer —</option></select></div> <div class="fg"><label class="fl"><i class="bi bi-shield-slash"></i> <%= t('admin.pkg.isolir_profile','Profil Isolir (paket ini)') %></label><select class="fs" name="isolir_profile" id="e_isolir_profile"><option value=""><%= t('admin.pkg.ph_isolir_profile','— pakai default global/customer —') %></option></select></div>
</div> </div>
<small class="text-muted" style="font-size:11px;display:block;margin-top:2px">Profil PPP + IP pool dibuat/diperbarui otomatis ke MikroTik (mode MikroTik / RADIUS profil). Pada mode RADIUS-atribut, IP &amp; rate-limit dari RADIUS.</small> <small class="text-muted" style="font-size:11px;display:block;margin-top:2px">Profil PPP + IP pool dibuat/diperbarui otomatis ke MikroTik (mode MikroTik / RADIUS profil). Pada mode RADIUS-atribut, IP &amp; rate-limit dari RADIUS.</small>
</div> </div>
@@ -539,16 +539,16 @@
<small class="text-muted" style="font-size:11px;display:block;margin:-6px 0 8px 26px">Centang untuk mengatur (kolom terbuka otomatis bila paket ini memakai Jam Kalong).</small> <small class="text-muted" style="font-size:11px;display:block;margin:-6px 0 8px 26px">Centang untuk mengatur (kolom terbuka otomatis bila paket ini memakai Jam Kalong).</small>
<div id="e_night_fields" style="display:none"> <div id="e_night_fields" style="display:none">
<div class="fg"> <div class="fg">
<label class="fl">Nama Profile Malam (MikroTik)</label> <label class="fl"><%= t('admin.pkg.prof_name','Nama Profil') %>e Malam (MikroTik)</label>
<div style="display:flex;gap:8px"> <div style="display:flex;gap:8px">
<select class="fs" id="e_night_profile_select" style="max-width:200px" onchange="document.getElementById('e_night_profile').value=this.value"> <select class="fs" id="e_night_profile_select" style="max-width:200px" onchange="document.getElementById('e_night_profile').value=this.value">
<option value="">-- Pilih Profile --</option> <option value=""><%= t('admin.pkg.ph_night_profile','-- Pilih Profile --') %></option>
</select> </select>
<input class="fc" name="night_profile_name" id="e_night_profile"> <input class="fc" name="night_profile_name" id="e_night_profile">
</div> </div>
</div> </div>
<div class="form-row"> <div class="form-row">
<div class="fg"><label class="fl">Download Malam (Mbps)</label><input class="fc" name="night_speed_down" id="e_night_down" type="number" step="any" min="0"></div> <div class="fg"><label class="fl"><%= t('admin.pkg.night_down','Download Malam (Mbps)') %></label><input class="fc" name="night_speed_down" id="e_night_down" type="number" step="any" min="0"></div>
<div class="fg"><label class="fl">Upload Malam (Mbps)</label><input class="fc" name="night_speed_up" id="e_night_up" type="number" step="any" min="0"></div> <div class="fg"><label class="fl">Upload Malam (Mbps)</label><input class="fc" name="night_speed_up" id="e_night_up" type="number" step="any" min="0"></div>
</div> </div>
</div> </div>
@@ -562,10 +562,10 @@
<small class="text-muted" style="font-size:11px;display:block;margin:-6px 0 8px 26px">Centang untuk mengatur (kolom terbuka otomatis bila paket ini memakai FUP).</small> <small class="text-muted" style="font-size:11px;display:block;margin:-6px 0 8px 26px">Centang untuk mengatur (kolom terbuka otomatis bila paket ini memakai FUP).</small>
<div id="e_fup_fields" style="display:none"> <div id="e_fup_fields" style="display:none">
<div class="fg"> <div class="fg">
<label class="fl">Nama Profile FUP (MikroTik)</label> <label class="fl"><%= t('admin.pkg.prof_name','Nama Profil') %>e FUP (MikroTik)</label>
<div style="display:flex;gap:8px"> <div style="display:flex;gap:8px">
<select class="fs" id="e_fup_profile_select" style="max-width:200px" onchange="document.getElementById('e_fup_profile').value=this.value"> <select class="fs" id="e_fup_profile_select" style="max-width:200px" onchange="document.getElementById('e_fup_profile').value=this.value">
<option value="">-- Pilih Profile --</option> <option value=""><%= t('admin.pkg.ph_night_profile','-- Pilih Profile --') %></option>
</select> </select>
<input class="fc" name="fup_profile_name" id="e_fup_profile"> <input class="fc" name="fup_profile_name" id="e_fup_profile">
</div> </div>