Files
YanDrs 0f32cf00ad Update Voucher , Tiket , Dashboard
membuat perubahan dan update
2025-07-15 00:30:19 +07:00

534 lines
24 KiB
PHP

<!-- Main content -->
<section class="content">
<div class="container-fluid">
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-header">
<div class="row">
<div class="col-sm-6">
<h3 class="card-title">Profile Paket</h3>
</div>
<div class="col-sm-6">
<ol class="float-sm-right mb-0">
<a type="button" class="btn btn-danger btn-sm" data-toggle="modal" data-target="#staticBackdrop">Tambah</a>
</ol>
</div>
<!-- Modal Tambah -->
<div class="modal fade" id="staticBackdrop" data-backdrop="static" data-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<form method="post" enctype="multipart/form-data">
<div class="modal-header bg-primary">
<h5 class="modal-title" id="staticBackdropLabel">Tambah Profile Paket</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="row">
<div class="col-md-6">
<div class="card-body">
<div class="form-group">
<label>Nama Server</label>
<select class="form-control" name="ids" required>
<option value="">Pilih</option>
<?php
$List = new Listdata();
$List->set_list("data_server", $SqlDataWH);
foreach ($List->get_list() as $key => $value): ?>
<option value="<?php echo $value['id']; ?>"><?php echo $value['nama_server']; ?></option>
<?php endforeach ?>
</select>
</div>
<div class="form-group">
<label>Radius Server</label>
<div class="form-check">
<input class="form-check-input" type="checkbox" name="radiuscek" value="1" id="checkbox1-0">
<label class="form-check-label" for="checkbox1">
Menggunakan Radius
</label>
</div>
<i class="text-danger"><small>Saat ini radius hanya digunakan untuk Autentikasi saja, untuk limit masih di sisi mikrotik</small></i>
</div>
<div class="form-group">
<label>Jenis Profile</label>
<select class="form-control" name="jenis" data-select="jenis-select1" required>
<option value="">Pilih</option>
<option value="PPPOE">PPPOE</option>
<option value="Hotspot">Hotspot</option>
<option value="DHCP" id="group-dhcp">DHCP IP Address</option>
</select>
</div>
<div class="form-group" id="group-jenis0">
<label>Nama Profile Di Mikrotik</label>
<input type="text" class="form-control" name="profile">
<i class="text-danger"><small>Nama Profile Harus sama dengan yang ada di Mikrotik</small></i>
</div>
<div class="form-group" id="group-jenis1">
<label>Jenis Hotspot</label>
<select class="form-control" name="jenishs" id="jenis-select2" data-select="jenis-select2">
<option value="">Pilih</option>
<option value="1">Sekali Pakai</option>
<option value="0">Berulangkali</option>
</select>
<i class="text-danger"><small>Pilih <b>Berulangkali</b> jika user hotspot di tagihan setiap bulan</small></i>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card-body">
<div class="form-group">
<label>Nama Paket</label>
<input type="text" class="form-control" name="nama" required>
</div>
<div class="form-group">
<label>Harga Paket</label>
<input type="text" class="form-control rupiah" name="harga" required>
</div>
<div class="form-group" id="group-jenis3">
<label>Fee Agen Voucher</label>
<input type="text" class="form-control rupiah" name="fee" id="fee">
<i class="text-danger">Isi jika menggunakan Aplikasi Agen Voucher</i>
</div>
<div class="form-group" id="group-jenis2">
<label>Durasi</label>
<input type="text" class="form-control" name="durasi" placeholder="6H" id="durasi">
<i class="text-danger">Contoh : 3H => 3 Jam , 1D => 1 Hari </i>
</div>
<div class="form-group" id="group-use">
<label>Limit Pengguna / Device</label>
<input type="text" class="form-control" name="use_limit">
</div>
<div class="form-group" id="group-pool">
<label>IP Pool</label>
<input type="text" class="form-control" name="ip_pool">
</div>
<div class="form-group" id="group-rate">
<label>Rate Limit</label>
<input type="text" class="form-control" name="rate_limit" placeholder="( Opsional )">
</div>
<div class="form-group" id="group-session">
<label>Session Timeout</label>
<input type="text" class="form-control" name="session_time" placeholder="( Opsional )">
</div>
<div class="form-group" id="group-idle">
<label>Idle Timeout</label>
<input type="text" class="form-control" name="idle_time" placeholder="( Opsional )">
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<input type="submit" name="tambah" class="btn btn-primary" value="Tambah">
</div>
</form>
<?php
if (isset($_POST['tambah'])) {
try {
// === VALIDASI INPUT USER ===
$requiredFields = ['ids', 'jenis', 'nama', 'harga'];
foreach ($requiredFields as $field) {
if (empty($_POST[$field])) {
sweetAlert("Field " . $field. " tidak boleh kosong!", "error");
return;
}
}
// === SANITASI DAN INISIALISASI ===
$status = ($_POST['jenishs'] == 1) ? 1 : NULL;
$nominal = preg_replace("/[^0-9]/", "", $_POST['harga']);
$cekfee = preg_replace("/[^0-9]/", "", $_POST['fee']);
$fee = (!empty($cekfee)) ? $cekfee : NULL;
$groupname = preg_replace(
'/\s+/',
'-',
strtolower(trim(preg_replace('/[^a-z0-9 ]/i', '', $_POST['jenis'] . ' ' .$_POST['nama'])))
) . '-' . $SvId;
$profile = $_POST['profile'] ?? '';
$use_limit = $_POST['use_limit'] ?? '';
$rate_limit = $_POST['rate_limit'] ?? '';
$session_time = $_POST['session_time'] ?? '';
$ip_pool = $_POST['ip_pool'] ?? '';
$idle_time = $_POST['idle_time'] ?? '';
// === TRANSAKSI DATABASE UNTUK ROLLBACK JIKA GAGAL ===
$pdo->beginTransaction();
// Ambil semua server
$stmt = $pdo->prepare("SELECT * FROM setting_mikrotik WHERE id_data_server = :id_data_server");
$stmt->execute([':id_data_server' => $_POST['ids']]);
$servers = $stmt->fetchAll(PDO::FETCH_ASSOC);
$rollbackServers = [];
$messages = []; // pesan error
// === RADIUS PROCESS ===
if (!empty($_POST['radiuscek']) && $_POST['radiuscek'] == 1) {
$radius = new CrudRadiusServer();
$radiusPayload = [
'jenis' => $_POST['jenis'],
'groupname' => $groupname,
'profile' => $profile,
'use_limit' => $use_limit,
'rate_limit' => $rate_limit,
'session_time' => $session_time,
'ip_pool' => $ip_pool,
'idle_time' => $idle_time
];
$radius->request('add_paket', 'POST', $radiusPayload);
$radius_data = json_encode($radiusPayload);
} else {
$radius_data = '';
}
// === LOOPING SERVER MIKROTIK ===
foreach ($servers as $server) {
$mikrotikName = $server['nama'];
$API = new RouterosAPI();
$API->debug = false;
if ($API->connect2(
$server['ip_address'],
$server['username'],
$server['password'],
$server['port_api']
)) {
$profileName = $_POST['profile'] ?? '';
$ipPool = $_POST['ip_pool'] ?? '';
$profileFound = false;
$poolFound = false;
// === CEK PROFILE ===
if ($_POST['jenis'] == 'PPPOE') {
$profiles = $API->comm('/ppp/profile/print');
} elseif ($_POST['jenis'] == 'Hotspot') {
$profiles = $API->comm('/ip/hotspot/user/profile/print');
}
if (!empty($profiles)) {
foreach ($profiles as $p) {
if ($p['name'] === $profileName) {
$profileFound = true;
break;
}
}
} else {
$profileFound = true;
}
// === CEK IP POOL (HANYA UNTUK DHCP & HOTSPOT) ===
if (!empty($ipPool) && ($_POST['jenis'] == 'DHCP')) {
$poolcek = $API->comm('/ip/pool/print');
if (!empty($poolcek)) {
foreach ($poolcek as $pool) {
if ($pool['name'] === $ipPool) {
$poolFound = true;
break;
}
}
}
} else {
// Jika tidak perlu IP Pool, dianggap ditemukan
$poolFound = true;
}
// === VALIDASI PROFILE & IP POOL ===
if (!$profileFound) {
$messages[] = "Profil <b>$profileName</b> di <b>$mikrotikName</b> tidak ditemukan.";
break; // gagal -> keluar loop
}
if (!$poolFound) {
$messages[] = "IP Pool <b>$ipPool</b> di <b>$mikrotikName</b> tidak ditemukan.";
break; // gagal -> keluar loop
}
// === JIKA HOTSPOT & STATUS AKTIF -> SET ON-LOGIN SCRIPT ===
if ($_POST['jenis'] == 'Hotspot' && $status == 1 && empty($_POST['radiuscek'])) {
$interval = intervalFormat($_POST['durasi']);
$onLoginScript = ':local nama $user; :local tanggal [/system clock get date]; :local waktu [/system clock get time]; :if ([/ip hotspot user get [find name=$nama] comment] = "") do={/ip hotspot user set [find name=$nama] comment="Login.$tanggal $waktu"; :log warning ("User " . $nama . " berhasil login.")} else={:log warning ("User " . $nama . " berhasil melakukan login ulang.")}; :if ([/system schedule find name=$nama] = "") do={/system schedule add name=$nama interval='.$interval.' on-event="/ip hotspot active remove [find user=$nama]; /ip hotspot user remove [find name=$nama]; /system schedule remove [find name=$nama]" start-date=$tanggal start-time=$waktu;}';
$API->comm('/ip/hotspot/user/profile/set', [
'.id' => $p['.id'],
'on-login' => $onLoginScript,
]);
}
// Catat server yang berhasil untuk rollback jika ada error nanti
$rollbackServers[] = $server;
} else {
$messages[] = "Gagal terhubung ke MikroTik <b>$mikrotikName</b>.";
break; // gagal -> langsung keluar loop
}
}
// === CEK ERROR DAN ROLLBACK JIKA PERLU ===
if (!empty($messages)) {
// Rollback ke DB
$pdo->rollBack();
// Rollback radius jika ada
if (!empty($_POST['radiuscek']) && $_POST['radiuscek'] == 1) {
$radius->request('delete_paket', 'DELETE', [
'groupname' => $groupname
]);
}
// Rollback ke server yang sudah diproses
foreach ($rollbackServers as $srv) {
$API = new RouterosAPI();
if ($API->connect2($srv['ip_address'], $srv['username'], $srv['password'], $srv['port_api'])) {
if ($_POST['jenis'] == 'PPPOE') {
$API->comm('/ppp/profile/remove', [
'numbers' => $profileName
]);
} else {
$API->comm('/ip/hotspot/user/profile/remove', [
'numbers' => $profileName
]);
}
}
}
$message = implode("<br>", $messages);
detailAlert("Rollback! $message", true);
return;
}
// === SIMPAN KE DATABASE ===
$stmt = $pdo->prepare("INSERT INTO profile_paket
(id_data_server, jenis_profile, nama_profile, durasi, nama, harga_paket, vi_agen, status, radius_data)
VALUES (:id_data_server, :jenis_profile, :nama_profile, :durasi, :nama, :harga_paket, :vi_agen, :status, :radius_data)");
$stmt->bindParam(':id_data_server', $_POST['ids']);
$stmt->bindParam(':jenis_profile', $_POST['jenis']);
$stmt->bindParam(':nama_profile', $_POST['profile']);
$stmt->bindParam(':durasi', $_POST['durasi']);
$stmt->bindParam(':nama', $_POST['nama']);
$stmt->bindParam(':harga_paket', $nominal);
$stmt->bindParam(':vi_agen', $fee);
$stmt->bindParam(':status', $status);
$stmt->bindParam(':radius_data', $radius_data);
$stmt->execute();
$pdo->commit(); // commit transaksi
sweetAlert("Profile Paket Telah ditambahkan", "success");
} catch (PDOException $e) {
$pdo->rollBack();
sweetAlert("Terjadi kesalahan DB: " . $e->getMessage(), "error");
} catch (Exception $e) {
$pdo->rollBack();
sweetAlert("Terjadi kesalahan: " . $e->getMessage(), "error");
}
}
?>
</div>
</div>
</div>
</div>
</div>
<!-- /.card-header -->
<div class="card-body">
<table id="example2" class="table table-bordered table-striped">
<thead>
<tr>
<th>Nama Server</th>
<th>Jenis Profile</th>
<th>Nama Profile Mikrotik</th>
<th>Nama Paket</th>
<th>Harga Paket</th>
<th>Status</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<?php
$apaket = mysqli_query($con,"SELECT * FROM profile_paket $SqlDataWHId ORDER BY nama ASC");
while ($paket = mysqli_fetch_assoc($apaket))
{
$data_radius = json_decode($paket['radius_data']);
?>
<tr>
<td>
<?php
$asv = mysqli_query($con,"SELECT nama_server FROM data_server WHERE id = '$paket[id_data_server]'");
$sv = mysqli_fetch_assoc($asv);
echo $sv['nama_server'];
?>
</td>
<td><?php echo $paket['jenis_profile']; ?></td>
<td><?php echo $paket['nama_profile']; ?></td>
<td><?php echo $paket['nama']; ?></td>
<td><?php echo "Rp. ".number_format($paket['harga_paket']);
if ($paket['vi_agen'] != NULL ) {
echo '<br><i class="text-danger">Fee Agen Rp. '.number_format($paket['vi_agen']).'</i>';
} ?>
</td>
<td><?php if($paket['status'] == 1 ){ echo "Sekali Pakai";} ?></td>
<td>
<form method="post" enctype="multipart/form-data">
<a href="?<?php echo encrypt_url('profile_paket_edit|'.$paket['id']);?>" class="btn btn-secondary btn-sm">Edit
</a>
<input type="submit" name="hapus<?php echo $paket['id'];?>" class="btn btn-danger btn-sm m-1" value="Hapus">
</form>
</td>
</tr>
<?php
if (isset($_POST['hapus'.$paket['id']]))
{
$groupname = $data_radius->{'groupname'};
$radius = new CrudRadiusServer();
$radius->request('delete_paket', 'DELETE', [
'groupname' => $groupname
]);
$iddata = $paket['id'];
deleteAlert("profile_paket", $iddata);
}
}
?>
</tbody>
</table>
</div>
<!-- /.card-body -->
</div>
<!-- /.card -->
</div>
<!-- /.col -->
</div>
<!-- /.row -->
</div>
<!-- /.container-fluid -->
</section>
<!-- /.content -->
<script>
// Ambil semua elemen dropdown & checkbox dalam modal
const jenisSelects = document.querySelectorAll('[data-select]');
const radiusCheckbox = document.querySelector('input[name="radiuscek"]');
// Sembunyikan semua grup pada awalnya
document.querySelectorAll('[id^="group-"]').forEach(group => {
group.style.display = 'none';
});
// Fungsi untuk mengupdate tampilan grup
function updateGroupVisibility() {
const jenisSelect = document.querySelector('select[name="jenis"]');
const jenishsSelect = document.querySelector('select[name="jenishs"]');
const group0 = document.getElementById('group-jenis0');
const group1 = document.getElementById('group-jenis1');
const group2 = document.getElementById('group-jenis2');
const group3 = document.getElementById('group-jenis3');
const groupdhcp = document.getElementById('group-dhcp');
const radiusUse = document.getElementById('group-use');
const radiusRate = document.getElementById('group-rate');
const radiusSession = document.getElementById('group-session');
const radiusIdle = document.getElementById('group-idle');
const groupPool = document.getElementById('group-pool');
const fee = document.getElementById('fee');
const durasi = document.getElementById('durasi');
// Helper untuk reset grup
function resetGroup(group, resetValue = true) {
if (resetValue) {
const inputs = group.querySelectorAll('select, input');
inputs.forEach(input => {
if (input.type === 'checkbox' || input.type === 'radio') {
input.checked = false;
} else {
input.value = '';
}
});
}
group.style.display = 'none';
}
// Reset semua grup dulu untuk menghindari tumpang tindih
const allGroups = [
group0, group1, group2, group3,
groupdhcp, groupPool,
radiusUse, radiusRate, radiusSession, radiusIdle
];
allGroups.forEach(g => resetGroup(g, false));
// Logic untuk dropdown jenis
if (jenisSelect.value === "Hotspot") {
group0.style.display = 'block';
group1.style.display = 'block';
group1.querySelector('select').required = true;
} else if (jenisSelect.value === "PPPOE") {
group0.style.display = 'block';
} else if (jenisSelect.value === "DHCP") {
groupPool.style.display = 'block';
}
// Logic untuk jenishs select
if (jenisSelect.value === "Hotspot" && jenishsSelect.value === "1") {
group2.style.display = 'block';
group3.style.display = 'block';
fee.required = true;
durasi.required = true;
} else {
fee.required = false;
durasi.required = false;
if (jenishsSelect.value === "1") {
jenishsSelect.selectedIndex = 0;
}
}
// Logic untuk checkbox radius
if (radiusCheckbox.checked) {
groupdhcp.style.display = 'block';
if (jenisSelect.value === "PPPOE") {
radiusUse.style.display = 'block';
radiusRate.style.display = 'block';
} else if (jenisSelect.value === "Hotspot") {
radiusUse.style.display = 'block';
radiusSession.style.display = 'block';
radiusRate.style.display = 'block';
radiusIdle.style.display = 'block';
} else if (jenisSelect.value === "DHCP") {
radiusRate.style.display = 'block';
groupPool.style.display = 'block';
}
} else {
// Hanya reset grup radius & dhcp
[radiusUse, radiusRate, radiusSession, radiusIdle, groupdhcp, groupPool].forEach(g => resetGroup(g));
// Jika jenisSelect saat ini DHCP, reset ke kosong supaya tidak memicu tampil lagi
if (jenisSelect.value === "DHCP") {
jenisSelect.selectedIndex = 0;
}
}
}
// Inisialisasi tampilan saat halaman diload
function initializeGroupVisibility() {
updateGroupVisibility();
}
// Tambahkan event listener untuk setiap dropdown
jenisSelects.forEach(select => {
select.addEventListener('change', updateGroupVisibility);
});
// Tambahkan event listener untuk checkbox radius
radiusCheckbox.addEventListener('change', updateGroupVisibility);
// Jalankan inisialisasi
initializeGroupVisibility();
</script>