Update Banyak
@@ -80,8 +80,8 @@ $logo = (baseurl() == "https://agen.manjapro.net/") ? 'images/white_logo_manja.p
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,400i,700&display=fallback">
|
||||
<!-- Font Awesome -->
|
||||
<link rel="stylesheet" href="css/fontawesome-free/css/all.min.css">
|
||||
<link rel="stylesheet" href="https://bilspro.com/plugins/icheck-bootstrap/icheck-bootstrap.min.css">
|
||||
<link rel="stylesheet" href="https://bilspro.com/dist/css/adminlte.min.css">
|
||||
<link rel="stylesheet" href="https://manjapro.net/plugins/icheck-bootstrap/icheck-bootstrap.min.css">
|
||||
<link rel="stylesheet" href="https://manjapro.net/dist/css/adminlte.min.css">
|
||||
<script src='https://cdn.jsdelivr.net/npm/sweetalert2@11'></script>
|
||||
</head>
|
||||
<body style="zoom: 85%;">
|
||||
@@ -210,11 +210,11 @@ $logo = (baseurl() == "https://agen.manjapro.net/") ? 'images/white_logo_manja.p
|
||||
</div>
|
||||
</div>
|
||||
<!-- jQuery -->
|
||||
<script src="https://bilspro.com/plugins/jquery/jquery.min.js"></script>
|
||||
<script src="https://manjapro.net/plugins/jquery/jquery.min.js"></script>
|
||||
<!-- Bootstrap 4 -->
|
||||
<script src="https://bilspro.com/plugins/bootstrap/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="https://manjapro.net/plugins/bootstrap/js/bootstrap.bundle.min.js"></script>
|
||||
<!-- AdminLTE App -->
|
||||
<script src="https://bilspro.com/dist/js/adminlte.min.js"></script>
|
||||
<script src="https://manjapro.net/dist/js/adminlte.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
// Fungsi untuk mengambil informasi perangkat dan mengisi field hidden pada form
|
||||
function fetchDeviceInfo() {
|
||||
|
||||
@@ -25,9 +25,9 @@ $logo = 'images/white_logo.png';
|
||||
<!-- Font Awesome -->
|
||||
<link rel="stylesheet" href="css/fontawesome-free/css/all.min.css">
|
||||
<!-- icheck bootstrap -->
|
||||
<link rel="stylesheet" href="https://bilspro.com/plugins/icheck-bootstrap/icheck-bootstrap.min.css">
|
||||
<link rel="stylesheet" href="https://manjapro.net/plugins/icheck-bootstrap/icheck-bootstrap.min.css">
|
||||
<!-- Theme style -->
|
||||
<link rel="stylesheet" href="https://bilspro.com/dist/css/adminlte.min.css">
|
||||
<link rel="stylesheet" href="https://manjapro.net/dist/css/adminlte.min.css">
|
||||
<script src='https://cdn.jsdelivr.net/npm/sweetalert2@11'></script>
|
||||
<style>
|
||||
.otp-container {
|
||||
@@ -192,11 +192,11 @@ $logo = 'images/white_logo.png';
|
||||
</div>
|
||||
</div></div>
|
||||
<!-- jQuery -->
|
||||
<script src="https://bilspro.com/plugins/jquery/jquery.min.js"></script>
|
||||
<script src="https://manjapro.net/plugins/jquery/jquery.min.js"></script>
|
||||
<!-- Bootstrap 4 -->
|
||||
<script src="https://bilspro.com/plugins/bootstrap/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="https://manjapro.net/plugins/bootstrap/js/bootstrap.bundle.min.js"></script>
|
||||
<!-- AdminLTE App -->
|
||||
<script src="https://bilspro.com/dist/js/adminlte.min.js"></script>
|
||||
<script src="https://manjapro.net/dist/js/adminlte.min.js"></script>
|
||||
|
||||
<script>
|
||||
function moveToNext(currentInput, nextInputId) {
|
||||
|
||||
@@ -31,4 +31,247 @@
|
||||
.animated-link:active {
|
||||
transform: scale(0.96);
|
||||
text-shadow: 0 0 10px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== Header ===== */
|
||||
.header-box {
|
||||
max-width: 550px;
|
||||
margin: 20px auto 0;
|
||||
color: #fff;
|
||||
padding: 0 15px;
|
||||
text-align: center;
|
||||
}
|
||||
.brand-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 12px;
|
||||
margin-bottom: 40px;
|
||||
zoom: 90%;
|
||||
}
|
||||
.brand-row img {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 50%;
|
||||
border: 3px solid #fff;
|
||||
object-fit: cover;
|
||||
}
|
||||
.brand-row h5 {
|
||||
margin: 0;
|
||||
}
|
||||
.amount {
|
||||
font-size: 2rem;
|
||||
font-weight: 700;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
/* ===== Card Utama ===== */
|
||||
.payment-card {
|
||||
max-width: 550px;
|
||||
margin: 0 auto;
|
||||
border-radius: 22px 22px 0 0;
|
||||
padding: 25px;
|
||||
background: #fff;
|
||||
min-height: 70vh;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* ===== Tombol Bayar ===== */
|
||||
.btn-orange {
|
||||
background: #ff7f11;
|
||||
color: #fff;
|
||||
border-radius: 12px;
|
||||
padding: 14px;
|
||||
font-weight: 600;
|
||||
font-size: 1.1rem;
|
||||
margin: 20px auto 0;
|
||||
display: block;
|
||||
max-width: 500px;
|
||||
}
|
||||
.btn-orange:hover {
|
||||
background: #e76e0d;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* ===== Accordion (Bootstrap 4) ===== */
|
||||
.card {
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 12px !important;
|
||||
margin-bottom: 10px;
|
||||
box-shadow: 0 2px 6px rgba(0,0,0,0.05);
|
||||
}
|
||||
.card-header {
|
||||
border-radius: 12px !important;
|
||||
background: #fff !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
.card-header .btn-link {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
width: 100%;
|
||||
padding: 0.5rem 1rem;
|
||||
text-decoration: none !important;
|
||||
color: inherit !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
.card-header .btn-link:focus {
|
||||
outline: none !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
.card-header .fw-semibold {
|
||||
margin-bottom: 0.25rem !important;
|
||||
}
|
||||
|
||||
/* group kiri = title + icons */
|
||||
.card-header .accordion-left {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.card-header .accordion-icons {
|
||||
display: inline-flex;
|
||||
margin-top: 5px;
|
||||
}
|
||||
.collapse.show ~ .accordion-icons {
|
||||
display: none !important;
|
||||
}
|
||||
.card-body {
|
||||
padding: 0.25rem 0 !important;
|
||||
}
|
||||
|
||||
/* ===== List Metode ===== */
|
||||
.list-group-item {
|
||||
border-color: #dee2e6;
|
||||
padding: 0.5rem 1rem;
|
||||
}
|
||||
.list-btn {
|
||||
border: none;
|
||||
background: none;
|
||||
outline: none;
|
||||
padding: 8px 0;
|
||||
font-weight: 500;
|
||||
text-align: left;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.list-btn:hover {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
/* ===== Metode Terpilih ===== */
|
||||
.method-card {
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 12px;
|
||||
padding: 15px;
|
||||
margin-bottom: 15px;
|
||||
background: #fafafa;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
}
|
||||
.method-selected {
|
||||
border: 2px solid #ff7f11;
|
||||
background: #fff9f4;
|
||||
}
|
||||
.ubah-btn {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
/* ===== Detail Tagihan ===== */
|
||||
#instruksiBox {
|
||||
font-size: 0.95rem;
|
||||
border-radius: 12px;
|
||||
margin-top: 15px;
|
||||
}
|
||||
.detail-row {
|
||||
display: flex;
|
||||
margin-bottom: 6px;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
.detail-row .label {
|
||||
font-weight: 600;
|
||||
min-width: 120px;
|
||||
}
|
||||
.detail-row .value {
|
||||
flex: 1;
|
||||
text-align: right;
|
||||
word-break: break-word;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
/* ===== Bank List ===== */
|
||||
.bank-list {
|
||||
text-align: left;
|
||||
}
|
||||
.bank-list .list-group-item {
|
||||
border: none;
|
||||
}
|
||||
.bank-list .pay-method {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
text-decoration: none;
|
||||
color: #333;
|
||||
gap: 15px;
|
||||
}
|
||||
.bank-logo-box {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border: 2px solid #ddd;
|
||||
border-radius: 10px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background: #fff;
|
||||
flex-shrink: 0;
|
||||
margin-top: -20px;
|
||||
}
|
||||
.bank-logo-box img {
|
||||
max-width: 70%;
|
||||
max-height: 70%;
|
||||
object-fit: contain;
|
||||
}
|
||||
.bank-name {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
border-bottom: 2px solid #f0f0f0;
|
||||
padding-bottom: 5px;
|
||||
flex: 1;
|
||||
}
|
||||
.accordion-icons {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
.bank-icon-box {
|
||||
width: 60px;
|
||||
height: 40px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 6px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background: #fff;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.bank-icon-box img {
|
||||
max-width: 70%;
|
||||
max-height: 70%;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
/* ===== Footer Powered ===== */
|
||||
.powered {
|
||||
text-align: center;
|
||||
font-size: 0.9rem;
|
||||
color: #777;
|
||||
margin-top: 40px;
|
||||
}
|
||||
.powered img {
|
||||
height: 20px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
@@ -19,9 +19,9 @@ $logo = 'images/white_logo.png';
|
||||
<!-- Font Awesome -->
|
||||
<link rel="stylesheet" href="css/fontawesome-free/css/all.min.css">
|
||||
<!-- icheck bootstrap -->
|
||||
<link rel="stylesheet" href="https://bilspro.com/plugins/icheck-bootstrap/icheck-bootstrap.min.css">
|
||||
<link rel="stylesheet" href="https://manjapro.net/plugins/icheck-bootstrap/icheck-bootstrap.min.css">
|
||||
<!-- Theme style -->
|
||||
<link rel="stylesheet" href="https://bilspro.com/dist/css/adminlte.min.css">
|
||||
<link rel="stylesheet" href="https://manjapro.net/dist/css/adminlte.min.css">
|
||||
<script src='https://cdn.jsdelivr.net/npm/sweetalert2@11'></script>
|
||||
</head>
|
||||
<body style="zoom: 85%;">
|
||||
@@ -109,11 +109,11 @@ $logo = 'images/white_logo.png';
|
||||
</div>
|
||||
</div></div>
|
||||
<!-- jQuery -->
|
||||
<script src="https://bilspro.com/plugins/jquery/jquery.min.js"></script>
|
||||
<script src="https://manjapro.net/plugins/jquery/jquery.min.js"></script>
|
||||
<!-- Bootstrap 4 -->
|
||||
<script src="https://bilspro.com/plugins/bootstrap/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="https://manjapro.net/plugins/bootstrap/js/bootstrap.bundle.min.js"></script>
|
||||
<!-- AdminLTE App -->
|
||||
<script src="https://bilspro.com/dist/js/adminlte.min.js"></script>
|
||||
<script src="https://manjapro.net/dist/js/adminlte.min.js"></script>
|
||||
|
||||
<script>
|
||||
document.getElementById('toggle-password').addEventListener('click', function() {
|
||||
|
||||
@@ -13,6 +13,10 @@ $pcmem = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
$jenisAgen = $pcmem['jenis_agen'];
|
||||
|
||||
$stmt = $pdo->prepare("SELECT payment_gateway,apikey_payment_gateway,url_payment_gateway,status_payment_gateway FROM data_server WHERE id = :id_data ");
|
||||
$stmt->bindParam(':id_data', $pcmem['id_data_server'], PDO::PARAM_INT);
|
||||
$stmt->execute();
|
||||
$payGateway = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
?>
|
||||
|
||||
|
||||
@@ -26,9 +26,9 @@ $logo = 'images/white_logo.png';
|
||||
<!-- Font Awesome -->
|
||||
<link rel="stylesheet" href="css/fontawesome-free/css/all.min.css">
|
||||
<!-- icheck bootstrap -->
|
||||
<link rel="stylesheet" href="https://bilspro.com/plugins/icheck-bootstrap/icheck-bootstrap.min.css">
|
||||
<link rel="stylesheet" href="https://manjapro.net/plugins/icheck-bootstrap/icheck-bootstrap.min.css">
|
||||
<!-- Theme style -->
|
||||
<link rel="stylesheet" href="https://bilspro.com/dist/css/adminlte.min.css">
|
||||
<link rel="stylesheet" href="https://manjapro.net/dist/css/adminlte.min.css">
|
||||
<script src='https://cdn.jsdelivr.net/npm/sweetalert2@11'></script>
|
||||
<style>
|
||||
.otp-container {
|
||||
@@ -192,11 +192,11 @@ $logo = 'images/white_logo.png';
|
||||
</div>
|
||||
</div></div>
|
||||
<!-- jQuery -->
|
||||
<script src="https://bilspro.com/plugins/jquery/jquery.min.js"></script>
|
||||
<script src="https://manjapro.net/plugins/jquery/jquery.min.js"></script>
|
||||
<!-- Bootstrap 4 -->
|
||||
<script src="https://bilspro.com/plugins/bootstrap/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="https://manjapro.net/plugins/bootstrap/js/bootstrap.bundle.min.js"></script>
|
||||
<!-- AdminLTE App -->
|
||||
<script src="https://bilspro.com/dist/js/adminlte.min.js"></script>
|
||||
<script src="https://manjapro.net/dist/js/adminlte.min.js"></script>
|
||||
|
||||
<script>
|
||||
function moveToNext(currentInput, nextInputId) {
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
if ($_GET['token'] !== 'YOUR_SECRET_TOKEN') {
|
||||
http_response_code(403);
|
||||
exit('Invalid token');
|
||||
}
|
||||
|
||||
$rawData = file_get_contents('php://input');
|
||||
|
||||
if (empty($rawData)) {
|
||||
http_response_code(400);
|
||||
exit('No backup content received');
|
||||
}
|
||||
|
||||
$filename = "backup_" . date("Ymd_His") . ".rsc";
|
||||
file_put_contents(__DIR__ . "/" . $filename, $rawData);
|
||||
|
||||
echo "Backup received: $filename";
|
||||
?>
|
||||
@@ -1 +1,31 @@
|
||||
NO ACTION => 2 <-> cc.net Limit_Tgl_5<br>NO ACTION => 3 <-> nsn utama Limit_Tgl_10<br>NO ACTION => 3 <-> ciangsana Limit_Tgl_15<br>NO ACTION => 4 <-> fast.net Limit_Tgl_12<br>NO ACTION => 5 <-> bima net Limit Tagihan Tgl 15<br>NO ACTION => 6 <-> kingnet Limit Tgl 15<br>NO ACTION => 8 <-> diamond.net Limit_Tgl_15<br>NO ACTION => 9 <-> 22 p.net Limit_Tgl_15<br>NO ACTION => 10 <-> nettizen Tagihan Limit tgl 15<br>NO ACTION => 12 <-> Tagihan_Limit_Tgl5<br>NO ACTION => 15 <-> Tag_NTA2 Limit Tgl 10<br>NO ACTION => 16 <-> Tagihan Limit Tgl 5<br>NO ACTION => 13 <-> Limit Tanggal 26 (Infinnet)<br>NO ACTION => 18 <-> BUM-Limit-Tgl-5<br>BUAT TAGIHAN => 14 <-> Kh_Limit Tanggal 25 Start : 2025-07-13 - Last : 2025-07-18<br>
|
||||
NO ACTION => 2 <-> cc.net Limit_Tgl_5<br>BUAT TAGIHAN => 3 <-> nsn utama Limit_Tgl_10 Start : 2025-09-21 - Last : 2025-10-01<br>BUAT TAGIHAN => 3 <-> ciangsana Limit_Tgl_15 Start : 2025-09-21 - Last : 2025-10-03<br>NO ACTION => 4 <-> fast.net Limit_Tgl_12<br>NO ACTION => 5 <-> bima net Limit Tagihan Tgl 15<br>NO ACTION => 6 <-> kingnet Limit Tgl 15<br>BUAT TAGIHAN => 8 <-> diamond.net Limit_Tgl_15 Start : 2025-09-21 - Last : 2025-10-03<br>BUAT TAGIHAN => 9 <-> 22 p.net Limit_Tgl_15 Start : 2025-09-21 - Last : 2025-10-03<br>NO ACTION => 10 <-> nettizen Tagihan Limit tgl 15<br>NO ACTION => 12 <-> Tagihan_Limit_Tgl5<br>NO ACTION => 15 <-> Tag_NTA2 Limit Tgl 10<br>NO ACTION => 16 <-> Tagihan Limit Tgl 10<br>NO ACTION => 13 <-> Limit Tanggal 26 (Infinnet)<br>NO ACTION => 18 <-> BUM-Limit-Tgl-5<br>NO ACTION => 14 <-> Kh_Limit Tanggal 25<br>NO ACTION => 17 <-> Tagihan Limit Tgl 10<br>NO ACTION => 17 <-> Tagihan Limit Tgl 15<br>NO ACTION => 20 <-> IVVI-10<br>OFF CONNECTION => 20 <-> IVVI-20<br>KIRIM TAGIHAN => 20 <-> IVVI-30<br>REMAND => 21 <-> QONNET<br>REMAND => 21 <-> QONNET2<br>NO ACTION => 25 <-> Tagihan Limit Tgl 5<br>NO ACTION => 23 <-> Limit Tanggal 5<br>NO ACTION => 26 <-> Limit Tanggal 10<br>NO ACTION => 24 <-> Tagihan30<br>NO ACTION => 23 <-> limit tanggal 19<br>NO ACTION => 31 <-> 23-ISOLIR<br>OFF CONNECTION => 33 <-> usolir-10<br>NO ACTION => 37 <-> paket 140 ribu<br>NO ACTION => 28 <-> PAKET-100K<br>NO ACTION => 28 <-> PAKET-150K<br>NO ACTION => 28 <-> PAKET-200K<br>NO ACTION => 28 <-> PAKET-300K<br>OFF CONNECTION => 42 <-> meldina-20<br>NO ACTION => 41 <-> lippy-20<br>NO ACTION => 43 <-> Tagihan_Limit_tgl_13<br>NO ACTION => 46 <-> Limit Tgl 10<br>REMAND => 35 <-> PAKET 1 DEVICE<br>REMAND => 35 <-> PAKET 2 DEVICE<br>REMAND => 35 <-> PAKET 3 DEVICE<br>REMAND => 35 <-> PAKET 4 DEVICE<br>REMAND => 35 <-> PAKET 5 DEVICE [1/80]<br>REMAND => 35 <-> PAKET 5 DEVICE [1/70]<br>REMAND => 35 <-> PAKET 6 DEVICE [1/80]<br>REMAND => 35 <-> PAKET 6 DEVICE [1/70]<br>REMAND => 35 <-> PAKET 7 DEVICE<br>REMAND => 35 <-> PAKET 8 DEVICE<br>NO ACTION => 44 <-> Isolir_20<br>NO ACTION => 53 <-> PAKET BRONZE <br>NO ACTION => 54 <-> Muhamad rouf<br>NO ACTION => 53 <-> PAKET PLATINUM 5MBs<br>NO ACTION => 53 <-> PAKET GLOD 7 MBs<br>NO ACTION => 53 <-> PAKET GLOD+ 10 MBs<br>OFF CONNECTION => 59 <-> Isolir_21<br>wahyu.B59<br>Array
|
||||
(
|
||||
)
|
||||
Server Not ConnectRobi.B59<br>Array
|
||||
(
|
||||
)
|
||||
Server Not ConnectEpul.B59<br>Array
|
||||
(
|
||||
)
|
||||
Server Not ConnectAnwar.B59<br>Array
|
||||
(
|
||||
)
|
||||
Server Not ConnectRirin/jali.B59<br>Array
|
||||
(
|
||||
)
|
||||
Server Not Connectibu erni/onong.B59<br>Array
|
||||
(
|
||||
)
|
||||
Server Not ConnectBu.dewipuspa.B59<br>Array
|
||||
(
|
||||
)
|
||||
Server Not ConnectSiti salmah.B59<br>Array
|
||||
(
|
||||
)
|
||||
Server Not ConnectRahayu.B59<br>Array
|
||||
(
|
||||
)
|
||||
Server Not ConnectDeni.yahya.B59<br>Array
|
||||
(
|
||||
)
|
||||
Server Not ConnectNO ACTION => 46 <-> Limit tgl 30<br>NO ACTION => 61 <-> Isolir_20<br>NO ACTION => 55 <-> Dcn_CO_Isolir<br>NO ACTION => 62 <-> limit tanggal 5<br>BUAT TAGIHAN => 55 <-> Dcn_GB_Isolir Start : 2025-09-21 - Last : 2025-09-26<br>REMAND => 49 <-> TAGIHAN TANGGAL 20<br>NO ACTION => 19 <-> TAGIHAN-TGL1<br>NO ACTION => 49 <-> TAGIHAN TANGGAL 1<br>NO ACTION => 66 <-> Tagihan Isolir Tgl 1<br>BUAT TAGIHAN => 67 <-> Tag Netborhood Limit Tgl 10 Start : 2025-09-20 - Last : 2025-09-30<br>
|
||||
@@ -221,7 +221,7 @@ try {
|
||||
elseif ($skr2 >= $starttime && $skr2 <= $lasttime) {
|
||||
echo "BUAT TAGIHAN => " . $pset['id_data_server'] . " <-> " . $pset['nama'] . " Start : " . $tgl92 . " - Last : " . $sendtag . "<br>";
|
||||
|
||||
$stmt = $pdo->prepare("SELECT * FROM pelanggan WHERE status = 'aktif' AND id_profile_tagihan = :id");
|
||||
$stmt = $pdo->prepare("SELECT * FROM pelanggan WHERE status = 'aktif' AND id_profile_tagihan = :id LIMIT 50");
|
||||
$stmt->bindParam(':id', $pset['id'], PDO::PARAM_INT);
|
||||
$stmt->execute();
|
||||
$pelanggan = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
@@ -237,6 +237,11 @@ try {
|
||||
$stmt->bindParam(':id', $pecah1['id'], PDO::PARAM_INT);
|
||||
$stmt->execute();
|
||||
$adadata = $stmt->rowCount();
|
||||
|
||||
$stmt = $pdo->prepare("SELECT payment_gateway,status_payment_gateway FROM data_server WHERE id = :id_data_server");
|
||||
$stmt->bindParam(':id_data_server', $pset['id_data_server'], PDO::PARAM_INT);
|
||||
$stmt->execute();
|
||||
$paygw = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if ($adadata == 0) {
|
||||
echo $pecah1['nama'] . "<br>";
|
||||
@@ -306,6 +311,21 @@ try {
|
||||
':limit_pembayaran' => $limit_tag,
|
||||
':status' => $status,
|
||||
]);
|
||||
$last_id = $pdo->lastInsertId();
|
||||
|
||||
if (!empty($paygw['payment_gateway']) && $paygw['payment_gateway'] === 'paydisini' && $paygw['status_payment_gateway'] == 'ACTIVE') {
|
||||
require '../controller/payment_paydisini.php';
|
||||
$link_paydisini = createUrlpaydisini($last_id);
|
||||
if (!empty($link_paydisini['status']) && $link_paydisini['status'] === true) {
|
||||
$transaction_link_paydisini = $link_paydisini['url'];
|
||||
$stmt = $pdo->prepare("UPDATE tagihan
|
||||
SET transaction_link = :transaction_link
|
||||
WHERE id = :idtag");
|
||||
$stmt->bindParam(':transaction_link', $transaction_link_paydisini);
|
||||
$stmt->bindParam(':idtag', $last_id);
|
||||
$stmt->execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
// encrypt url
|
||||
define('ENCRYPTION_KEY', hex2bin('9a307dfcf16ac2e4406b1a59a31c1d096eafe37e40c60ddee4bb827b6a947079'));
|
||||
define('ENCRYPTION_METHOD', 'AES-256-CBC');
|
||||
|
||||
function encrypt_url($data) {
|
||||
$iv = random_bytes(16);
|
||||
$encrypted = openssl_encrypt($data, ENCRYPTION_METHOD, ENCRYPTION_KEY, OPENSSL_RAW_DATA, $iv);
|
||||
// Gabungkan IV hex + "::" + encrypted base64, lalu base64 encode seluruh string
|
||||
$result = base64_encode(bin2hex($iv) . "::" . base64_encode($encrypted));
|
||||
return $result;
|
||||
}
|
||||
|
||||
function decrypt_url($data) {
|
||||
$decoded = base64_decode($data);
|
||||
if ($decoded === false) return false;
|
||||
$parts = explode('::', $decoded);
|
||||
if (count($parts) !== 2) return false;
|
||||
|
||||
$iv = hex2bin($parts[0]);
|
||||
$encrypted_data = base64_decode($parts[1]);
|
||||
return openssl_decrypt($encrypted_data, ENCRYPTION_METHOD, ENCRYPTION_KEY, OPENSSL_RAW_DATA, $iv);
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__ . '/whatsapp_api.php'; // untuk dapatkan OPENAI_API_KEY
|
||||
|
||||
class Gpt_Ai_Api {
|
||||
|
||||
/**
|
||||
* Memanggil OpenAI Chat Completions
|
||||
* @param array $payload Array sesuai format OpenAI API
|
||||
* @return string Respon AI atau pesan error
|
||||
*/
|
||||
public function call_openai(array $payload): string {
|
||||
$ch = curl_init("https://api.openai.com/v1/chat/completions");
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||||
"Content-Type: application/json",
|
||||
"Authorization: " . "Bearer " . OPENAI_API_KEY
|
||||
]);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
|
||||
$response = curl_exec($ch);
|
||||
|
||||
if ($response === false) {
|
||||
$error_msg = curl_error($ch);
|
||||
curl_close($ch);
|
||||
return "⚠️ Gagal menghubungi AI: $error_msg";
|
||||
}
|
||||
|
||||
curl_close($ch);
|
||||
|
||||
$data = json_decode($response, true);
|
||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||
return "⚠️ Respon AI tidak valid JSON.";
|
||||
}
|
||||
|
||||
return $data['choices'][0]['message']['content'] ?? "⚠️ Tidak ada respon dari AI.";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
header("Content-Type: application/json; charset=UTF-8");
|
||||
error_reporting(E_ALL & ~E_NOTICE & ~E_WARNING);
|
||||
|
||||
// ====== SECURITY LAYER ======
|
||||
$apiToken = "xyz123"; // samakan dengan di JS
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
echo json_encode(["status" => false, "message" => "Gunakan POST"]);
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($_SERVER['HTTP_X_API_TOKEN'] !== $apiToken) {
|
||||
echo json_encode(["status" => false, "message" => "Unauthorized"]);
|
||||
exit;
|
||||
}
|
||||
// =============================
|
||||
|
||||
function cekRekeningFlip($bank_code, $account_number) {
|
||||
|
||||
$flipKey = "JDJ5JDEzJHlkOFNYckl1a3U3VXJkZERKVnNZL3VTN1BLWmE2U3NMeUJXZC9COFV4LmZlb2VUTmdQaEN5"; // ganti dengan key kamu
|
||||
$url = "https://bigflip.id/api/v2/disbursement/bank-account-inquiry";
|
||||
|
||||
$data = [
|
||||
"bank_code" => strtolower($bank_code),
|
||||
"account_number" => $account_number,
|
||||
"inquiry_key" => uniqid("inq_")
|
||||
];
|
||||
|
||||
$ch = curl_init($url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||||
"Content-Type: application/x-www-form-urlencoded",
|
||||
"Accept: application/json; charset=UTF-8",
|
||||
"Authorization: Basic " . base64_encode($flipKey . ":")
|
||||
]);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
|
||||
|
||||
$response = curl_exec($ch);
|
||||
|
||||
if (curl_errno($ch)) {
|
||||
$error_msg = curl_error($ch);
|
||||
curl_close($ch);
|
||||
return ["status" => false, "message" => $error_msg];
|
||||
}
|
||||
|
||||
curl_close($ch);
|
||||
$result = json_decode($response, true);
|
||||
|
||||
if (!$result) {
|
||||
return ["status" => false, "message" => "Flip API tidak balas JSON", "raw" => $response];
|
||||
}
|
||||
|
||||
if (isset($result['account_number'])) {
|
||||
return [
|
||||
"status" => true,
|
||||
"account_number" => $result['account_number'],
|
||||
"account_holder" => $result['account_holder'],
|
||||
"bank_code" => $result['bank_code']
|
||||
];
|
||||
}
|
||||
|
||||
return ["status" => false, "message" => $result];
|
||||
}
|
||||
|
||||
// ==== Eksekusi request ====
|
||||
$bank_code = $_POST['bank_code'] ?? '';
|
||||
$account_number = $_POST['account_number'] ?? '';
|
||||
|
||||
if (empty($bank_code) || empty($account_number)) {
|
||||
echo json_encode(["status" => false, "message" => "Bank atau nomor rekening kosong"]);
|
||||
exit;
|
||||
}
|
||||
|
||||
echo json_encode(cekRekeningFlip($bank_code, $account_number));
|
||||
@@ -88,7 +88,9 @@ class CreateTunnel
|
||||
// ==============================
|
||||
// Generate user/pass
|
||||
// ==============================
|
||||
$secretUser = strtolower(preg_replace('/[^a-z0-9]/i', '', substr($Secret, 0, 12))) . "@manjapro.net";
|
||||
// $secretUser = strtolower(preg_replace('/[^a-z0-9]/i', '', substr($Secret, 0, 12))) . "@manjapro.net";
|
||||
$prefix = strtolower(preg_replace('/[^a-z0-9]/i', '', substr($Secret, 0, 10)));
|
||||
$secretUser = $prefix . rand(1000, 9999) . "@manjapro.net";
|
||||
$secretPass = strtolower(substr(md5($secretUser), 0, 12));
|
||||
$nasSecret = substr(md5($secretUser), 0, 20);
|
||||
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
include '../config/connect.php';
|
||||
|
||||
// Ambil parameter DataTables
|
||||
$draw = isset($_POST['draw']) ? intval($_POST['draw']) : 0;
|
||||
$start = isset($_POST['start']) ? intval($_POST['start']) : 0;
|
||||
$length = isset($_POST['length']) ? intval($_POST['length']) : 10;
|
||||
$search = isset($_POST['search']['value']) ? $_POST['search']['value'] : '';
|
||||
$orderColumnIndex = $_POST['order'][0]['column'] ?? 1;
|
||||
$orderDir = $_POST['order'][0]['dir'] ?? 'desc';
|
||||
$status = isset($_GET['s']) ? $_GET['s'] : 'SUCCESS';
|
||||
// Mapping kolom sesuai urutan table DataTable
|
||||
$columns = [
|
||||
0 => 'order_id',
|
||||
1 => 'keterangan',
|
||||
2 => 'nama',
|
||||
3 => 'jumlah',
|
||||
4 => 'saldo',
|
||||
5 => 'biaya',
|
||||
6 => 'status',
|
||||
7 => 'jenis',
|
||||
8 => 'input_time',
|
||||
9 => 'update_time',
|
||||
];
|
||||
|
||||
$orderColumn = $columns[$orderColumnIndex] ?? 'update_time';
|
||||
|
||||
// Filter server ID
|
||||
$id_data_server = isset($_GET['i']) ? $_GET['i'] : 0; // bisa single atau multiple (1,2,3)
|
||||
$where = "WHERE 1=1 ";
|
||||
if ($id_data_server > 0) {
|
||||
if ($id_data_server == 1) {
|
||||
$where .= ""; // semua server
|
||||
} else {
|
||||
// pastikan hanya angka dan koma
|
||||
$safe_ids = implode(',', array_map('intval', explode(',', $id_data_server)));
|
||||
$where .= " AND id_data_server IN ($safe_ids) AND status = '$status'";
|
||||
}
|
||||
}
|
||||
|
||||
// Query untuk hitung total
|
||||
try {
|
||||
$stmt = $pdo->query("SELECT COUNT(*) FROM client_payment $where");
|
||||
$recordsTotal = (int) $stmt->fetchColumn();
|
||||
} catch (Exception $e) {
|
||||
$recordsTotal = 0;
|
||||
}
|
||||
|
||||
// Query untuk filter pencarian
|
||||
$searchQuery = '';
|
||||
if (!empty($search)) {
|
||||
$searchQuery = " AND (update_time LIKE :search OR keterangan) ";
|
||||
}
|
||||
|
||||
// Hitung total setelah filter
|
||||
try {
|
||||
$stmt = $pdo->prepare("SELECT COUNT(*) FROM client_payment $where $searchQuery");
|
||||
if (!empty($search)) $stmt->bindValue(':search', "%$search%", PDO::PARAM_STR);
|
||||
$stmt->execute();
|
||||
$recordsFiltered = (int) $stmt->fetchColumn();
|
||||
} catch (Exception $e) {
|
||||
$recordsFiltered = 0;
|
||||
}
|
||||
|
||||
// Ambil data sesuai filter + order + limit
|
||||
$data = [];
|
||||
try {
|
||||
$sql = "SELECT order_id, keterangan, nama, jumlah, saldo, biaya, status, jenis, input_time, update_time
|
||||
FROM client_payment
|
||||
$where $searchQuery
|
||||
ORDER BY $orderColumn $orderDir
|
||||
LIMIT :start, :length";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
if (!empty($search)) $stmt->bindValue(':search', "%$search%", PDO::PARAM_STR);
|
||||
$stmt->bindValue(':start', $start, PDO::PARAM_INT);
|
||||
$stmt->bindValue(':length', $length, PDO::PARAM_INT);
|
||||
$stmt->execute();
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC) ?: [];
|
||||
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$data[] = [
|
||||
"#PGPDN" . $row['order_id'],
|
||||
$row['keterangan'],
|
||||
$row['nama'],
|
||||
number_format((float)$row['jumlah'], 0, ',', '.'),
|
||||
number_format((float)$row['saldo'], 0, ',', '.'),
|
||||
number_format((float)$row['biaya'], 0, ',', '.'),
|
||||
$row['status'],
|
||||
$row['jenis'],
|
||||
$row['input_time'],
|
||||
$row['update_time'],
|
||||
];
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$data = [];
|
||||
}
|
||||
|
||||
// Response ke DataTables
|
||||
echo json_encode([
|
||||
"draw" => $draw,
|
||||
"recordsTotal" => $recordsTotal,
|
||||
"recordsFiltered" => $recordsFiltered,
|
||||
"data" => $data
|
||||
]);
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
include '../config/connect.php';
|
||||
|
||||
$id = isset($_GET['id']) ? intval($_GET['id']) : 0;
|
||||
$s = isset($_GET['s']) ? intval($_GET['s']) : 0;
|
||||
|
||||
if($id > 0){
|
||||
if($s == 1 ){
|
||||
$colum = "v_akumulasi_client_payment";
|
||||
} else {
|
||||
$colum = "v_akumulasi_paygw";
|
||||
}
|
||||
|
||||
$stmt = $pdo->prepare("SELECT tersedia AS saldo FROM $colum WHERE id_data_server = :id LIMIT 1");
|
||||
$stmt->execute([':id' => $id]);
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
echo json_encode($row ?: ["saldo" => 0]);
|
||||
} else {
|
||||
echo json_encode(["saldo" => 0]);
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
<?php
|
||||
ini_set('display_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
|
||||
require __DIR__ . "/../config/connect.php"; // koneksi PDO
|
||||
require __DIR__ . "/../config/gpt_ai.php"; // koneksi PDO
|
||||
|
||||
$action = $_GET['action'] ?? 'list';
|
||||
$id_server = isset($_GET['i']) ? $_GET['i'] : 0;
|
||||
|
||||
if ($action === 'list') {
|
||||
$limit = isset($_POST['length']) ? intval($_POST['length']) : 20;
|
||||
$start = isset($_POST['start']) ? intval($_POST['start']) : 0;
|
||||
|
||||
// pecah id server jadi array aman
|
||||
$ids = array_filter(array_map('intval', explode(',', $id_server)));
|
||||
$placeholders = implode(',', array_fill(0, count($ids), '?'));
|
||||
|
||||
// hitung total data distinct topik
|
||||
$stmt = $pdo->prepare("SELECT COUNT(DISTINCT topik)
|
||||
FROM chat_topik
|
||||
WHERE id_data_server IN ($placeholders)");
|
||||
$stmt->execute($ids);
|
||||
$totalData = $stmt->fetchColumn();
|
||||
|
||||
// ambil data unik berdasarkan topik (ambil id terbesar per topik)
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT ct.id, ct.topik, ct.deskripsi
|
||||
FROM chat_topik ct
|
||||
INNER JOIN (
|
||||
SELECT topik, MAX(id) AS max_id
|
||||
FROM chat_topik
|
||||
WHERE id_data_server IN ($placeholders)
|
||||
GROUP BY topik
|
||||
) tmax ON ct.id = tmax.max_id
|
||||
ORDER BY ct.id DESC
|
||||
LIMIT ?, ?
|
||||
");
|
||||
|
||||
// binding ids dulu
|
||||
$i = 1;
|
||||
foreach ($ids as $id) {
|
||||
$stmt->bindValue($i++, $id, PDO::PARAM_INT);
|
||||
}
|
||||
// binding limit
|
||||
$stmt->bindValue($i++, $start, PDO::PARAM_INT);
|
||||
$stmt->bindValue($i++, $limit, PDO::PARAM_INT);
|
||||
|
||||
$stmt->execute();
|
||||
|
||||
$data = [];
|
||||
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$data[] = [
|
||||
$row['topik'],
|
||||
$row['deskripsi'],
|
||||
["id" => $row['id']]
|
||||
];
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
"draw" => intval($_POST['draw'] ?? 1),
|
||||
"recordsTotal" => intval($totalData),
|
||||
"recordsFiltered" => intval($totalData),
|
||||
"data" => $data
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
if ($action === 'detail') {
|
||||
$id = intval($_POST['id'] ?? 0);
|
||||
$stmt = $pdo->prepare("SELECT id, deskripsi, topik FROM chat_topik WHERE id = ?");
|
||||
$stmt->execute([$id]);
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
echo json_encode($row ?: []);
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($action === 'save') {
|
||||
$id = intval($_POST['id'] ?? 0);
|
||||
$deskripsi = trim($_POST['deskripsi'] ?? '');
|
||||
$ids = array_filter(array_map('intval', explode(',', $_GET['i'] ?? '0')));
|
||||
|
||||
if ($deskripsi === '' || empty($ids)) {
|
||||
echo json_encode(["status" => "error", "msg" => "Data tidak valid"]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// buat metadata dari GPT
|
||||
$payload = [
|
||||
"model" => "gpt-3.5-turbo",
|
||||
"messages" => [
|
||||
["role" => "system", "content" => "Tolong rubah kalimat berikut menjadi metadata berbentuk JSON."],
|
||||
["role" => "user", "content" => $deskripsi]
|
||||
],
|
||||
"temperature" => 0.0
|
||||
];
|
||||
|
||||
$GPT = new Gpt_Ai_Api();
|
||||
$metadata = $GPT->call_openai($payload);
|
||||
|
||||
// pastikan metadata berbentuk string JSON
|
||||
if (is_array($metadata) || is_object($metadata)) {
|
||||
$metadata = json_encode($metadata, JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
||||
// pastikan metadata berbentuk string JSON
|
||||
if (is_array($metadata) || is_object($metadata)) {
|
||||
$metadata = json_encode($metadata, JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
||||
if ($id > 0) {
|
||||
// update data yang sudah ada
|
||||
$stmt = $pdo->prepare("SELECT topik FROM chat_topik WHERE id = ?");
|
||||
$stmt->execute([$id]);
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if ($row) {
|
||||
$topik = $row['topik'];
|
||||
|
||||
if (count($ids) > 1) {
|
||||
// multi server → replace ke semua id_data_server
|
||||
$pdo->beginTransaction();
|
||||
try {
|
||||
$stmt = $pdo->prepare("
|
||||
INSERT INTO chat_topik (id_data_server, topik, deskripsi, metadata)
|
||||
VALUES (?, ?, ?, ?)
|
||||
ON DUPLICATE KEY UPDATE deskripsi = VALUES(deskripsi),
|
||||
metadata = VALUES(metadata)
|
||||
");
|
||||
foreach ($ids as $sid) {
|
||||
$stmt->execute([$sid, $topik, $deskripsi, $metadata]);
|
||||
}
|
||||
$pdo->commit();
|
||||
echo json_encode(["status" => "ok"]);
|
||||
} catch (Exception $e) {
|
||||
$pdo->rollBack();
|
||||
echo json_encode(["status" => "error", "msg" => $e->getMessage()]);
|
||||
}
|
||||
} else {
|
||||
// single server → update biasa
|
||||
$stmt = $pdo->prepare("UPDATE chat_topik SET deskripsi = ?, metadata = ? WHERE id = ?");
|
||||
$ok = $stmt->execute([$deskripsi, $metadata, $id]);
|
||||
echo json_encode(["status" => $ok ? "ok" : "error"]);
|
||||
}
|
||||
} else {
|
||||
echo json_encode(["status" => "error", "msg" => "Topik tidak ditemukan"]);
|
||||
}
|
||||
} else {
|
||||
// jika id = 0 → insert baru
|
||||
try {
|
||||
$pdo->beginTransaction();
|
||||
$stmt = $pdo->prepare("
|
||||
INSERT INTO chat_topik (id_data_server, topik, deskripsi, metadata)
|
||||
VALUES (?, ?, ?, ?)
|
||||
");
|
||||
foreach ($ids as $sid) {
|
||||
// topik bisa digenerate otomatis dari deskripsi (misalnya hash/md5)
|
||||
$topik = substr(md5($deskripsi . $sid), 0, 16);
|
||||
$stmt->execute([$sid, $topik, $deskripsi, $metadata]);
|
||||
}
|
||||
$pdo->commit();
|
||||
echo json_encode(["status" => "ok"]);
|
||||
} catch (Exception $e) {
|
||||
$pdo->rollBack();
|
||||
echo json_encode(["status" => "error", "msg" => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
echo json_encode(["status" => "error", "msg" => "Action tidak valid"]);
|
||||
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
require __DIR__ . "/../config/connect.php";
|
||||
require __DIR__ . "/../config/encrypt.php";
|
||||
|
||||
$datadecrypt = decrypt_url($_GET['data']);
|
||||
$dataurl = json_decode($datadecrypt, true);
|
||||
|
||||
$SqlSvData = $dataurl[0];
|
||||
$SqlDataWHIdM = $dataurl[1];
|
||||
$hotspotAktif = !empty($dataurl[2]) && $dataurl[2] == 1;
|
||||
|
||||
// Definisi kolom sesuai thead (No dihitung otomatis)
|
||||
$columns = ['nama','nik','akun'];
|
||||
if($hotspotAktif) {
|
||||
$columns[] = 'user_hotspot';
|
||||
}
|
||||
$columns = array_merge($columns, [
|
||||
'alamat','latitude','nomor_whatsapp','nama_server','nama_mikrotik','nama_paket','status_koneksi','time_start'
|
||||
]);
|
||||
|
||||
// Paging
|
||||
$limit = intval($_POST['length']);
|
||||
$offset = intval($_POST['start']);
|
||||
|
||||
// Order
|
||||
$orderIndex = intval($_POST['order'][0]['column']) - 1; // kurangi 1 karena No di kolom pertama
|
||||
$orderCol = $columns[$orderIndex] ?? 'nama';
|
||||
$orderDir = $_POST['order'][0]['dir'] ?? 'asc';
|
||||
|
||||
// Search
|
||||
$search = $_POST['search']['value'] ?? '';
|
||||
$where = "WHERE $SqlSvData status = 'aktif'";
|
||||
if(!empty($search)) {
|
||||
$where .= " AND (nama LIKE :search OR nik LIKE :search OR akun LIKE :search OR status_koneksi LIKE :search OR nomor_whatsapp LIKE :search OR nama_paket LIKE :search OR nama_server LIKE :search OR alamat LIKE :search OR time_start LIKE :search)";
|
||||
}
|
||||
|
||||
// Hitung total
|
||||
$totalStmt = $pdo->query("SELECT COUNT(id) FROM v_pelanggan WHERE $SqlSvData status = 'aktif'");
|
||||
$recordsTotal = $totalStmt->fetchColumn();
|
||||
|
||||
// Query data
|
||||
$sql = "SELECT id,akun,user_hotspot,nama,alamat,latitude,longitude,nomor_whatsapp,email,nik,
|
||||
nama_server,nama_paket,time_start,status_koneksi,nama_mikrotik,id_setting_mikrotik,
|
||||
time_update,ip_address
|
||||
FROM v_pelanggan $where
|
||||
ORDER BY $orderCol $orderDir
|
||||
LIMIT :limit OFFSET :offset";
|
||||
|
||||
$stmt = $pdo->prepare($sql);
|
||||
if(!empty($search)) $stmt->bindValue(':search', "%$search%");
|
||||
$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
|
||||
$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
|
||||
$stmt->execute();
|
||||
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// Format data
|
||||
$no = $offset + 1;
|
||||
$dataArray = [];
|
||||
foreach($data as $row) {
|
||||
$latlong = (substr($row['latitude'],0,1) != '-')
|
||||
? "<a href='https://google.com/maps/?q={$row['latitude']}' target='_blank'>{$row['latitude']}</a>"
|
||||
: "<a href='https://google.com/maps/?q={$row['latitude']},{$row['longitude']}' target='_blank'>{$row['latitude']}, {$row['longitude']}</a>";
|
||||
|
||||
$wa = "{$row['nomor_whatsapp']} <a href='https://wa.me/{$row['nomor_whatsapp']}' target='_blank' class='btn btn-sm btn-success' style='border-radius:20px;'><i class='fab fa-whatsapp'></i></a><br>{$row['email']}";
|
||||
|
||||
$status = $row['status_koneksi'];
|
||||
if($status == 'On') {
|
||||
$status .= " <a href='?".encrypt_url("user_remote|{$row['id']}|{$row['id_setting_mikrotik']}")."' class='btn btn-sm btn-success ml-1' style='border-radius: 20px;'>Remote</a><br>{$row['ip_address']}";
|
||||
}
|
||||
$status .= "<br>{$row['time_update']}";
|
||||
|
||||
$aksi = "<a href='?".encrypt_url("user_detail|{$row['id']}")."' class='btn btn-sm btn-info m-1'>Detail</a>";
|
||||
|
||||
// Build row sesuai urutan thead
|
||||
$rowData = [
|
||||
$no++,
|
||||
$row['nama'],
|
||||
$row['nik'],
|
||||
$row['akun']
|
||||
];
|
||||
|
||||
if($hotspotAktif) {
|
||||
$rowData[] = $row['user_hotspot'];
|
||||
}
|
||||
|
||||
$rowData[] = $row['alamat'];
|
||||
$rowData[] = $latlong;
|
||||
$rowData[] = $wa;
|
||||
$rowData[] = $row['nama_server'];
|
||||
$rowData[] = $row['nama_mikrotik'];
|
||||
$rowData[] = $row['nama_paket'];
|
||||
$rowData[] = $status;
|
||||
$rowData[] = $row['time_start'];
|
||||
$rowData[] = $aksi;
|
||||
|
||||
$dataArray[] = $rowData;
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
"draw" => intval($_POST['draw']),
|
||||
"recordsTotal" => $recordsTotal,
|
||||
"recordsFiltered" => $recordsTotal,
|
||||
"data" => $dataArray
|
||||
]);
|
||||
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
include '../config/connect.php';
|
||||
|
||||
// Ambil parameter DataTables
|
||||
$draw = isset($_POST['draw']) ? intval($_POST['draw']) : 0;
|
||||
$start = isset($_POST['start']) ? intval($_POST['start']) : 0;
|
||||
$length = isset($_POST['length']) ? intval($_POST['length']) : 10;
|
||||
$search = isset($_POST['search']['value']) ? $_POST['search']['value'] : '';
|
||||
$orderColumnIndex = $_POST['order'][0]['column'] ?? 1;
|
||||
$orderDir = $_POST['order'][0]['dir'] ?? 'desc';
|
||||
|
||||
// Mapping kolom sesuai urutan table DataTable
|
||||
$columns = [
|
||||
0 => 'nama_server',
|
||||
1 => 'start_time',
|
||||
2 => 'nominal',
|
||||
3 => 'user_create',
|
||||
4 => 'status',
|
||||
5 => 'update_time',
|
||||
6 => 'id'
|
||||
];
|
||||
|
||||
$orderColumn = $columns[$orderColumnIndex] ?? 'start_time';
|
||||
|
||||
// Filter server ID
|
||||
$id_data_server = isset($_GET['i']) ? $_GET['i'] : 0; // bisa single atau multiple (1,2,3)
|
||||
$jenis = isset($_GET['s']) ? $_GET['s'] : 0;
|
||||
|
||||
// echo $jenis;
|
||||
$where = "WHERE 1=1 AND jenis = '$jenis'";
|
||||
if ($id_data_server > 0) {
|
||||
if ($id_data_server == 1) {
|
||||
$where .= ""; // semua server
|
||||
} else {
|
||||
// pastikan hanya angka dan koma
|
||||
$safe_ids = implode(',', array_map('intval', explode(',', $id_data_server)));
|
||||
$where .= " AND id_data_server IN ($safe_ids) ";
|
||||
}
|
||||
}
|
||||
|
||||
// Query untuk hitung total
|
||||
try {
|
||||
$stmt = $pdo->query("SELECT COUNT(*) FROM v_transaksi_withdraw $where");
|
||||
$recordsTotal = (int) $stmt->fetchColumn();
|
||||
} catch (Exception $e) {
|
||||
$recordsTotal = 0;
|
||||
}
|
||||
|
||||
// Query untuk filter pencarian
|
||||
$searchQuery = '';
|
||||
if (!empty($search)) {
|
||||
$searchQuery = " AND (user_create LIKE :search OR status LIKE :search OR nominal LIKE :search) ";
|
||||
}
|
||||
|
||||
// Hitung total setelah filter
|
||||
try {
|
||||
$stmt = $pdo->prepare("SELECT COUNT(*) FROM v_transaksi_withdraw $where $searchQuery");
|
||||
if (!empty($search)) $stmt->bindValue(':search', "%$search%", PDO::PARAM_STR);
|
||||
$stmt->execute();
|
||||
$recordsFiltered = (int) $stmt->fetchColumn();
|
||||
} catch (Exception $e) {
|
||||
$recordsFiltered = 0;
|
||||
}
|
||||
|
||||
// Ambil data sesuai filter + order + limit
|
||||
$data = [];
|
||||
try {
|
||||
$sql = "SELECT nama_server, start_time, nominal, user_create, status, update_time, id_data_server, id, bukti_success
|
||||
FROM v_transaksi_withdraw
|
||||
$where $searchQuery
|
||||
ORDER BY $orderColumn $orderDir
|
||||
LIMIT :start, :length";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
if (!empty($search)) $stmt->bindValue(':search', "%$search%", PDO::PARAM_STR);
|
||||
$stmt->bindValue(':start', $start, PDO::PARAM_INT);
|
||||
$stmt->bindValue(':length', $length, PDO::PARAM_INT);
|
||||
$stmt->execute();
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC) ?: [];
|
||||
|
||||
// foreach ($rows as $row) {
|
||||
// // Format nominal ke number_format
|
||||
// $row['nominal'] = number_format((float)$row['nominal'], 0, ',', '.');
|
||||
// // $row['status'] = ($row['status'] == 'pending') ? '<span class="badge bg-primary p-2">' . strtoupper($row['status']) . '</span>' : '<span class="badge bg-success p-2">' . strtoupper($row['status']) . '</span>';
|
||||
// $row['id'] = ['id' => '']
|
||||
// $data[] = array_values($row); // ubah ke numerik index biar sesuai DataTables
|
||||
// }
|
||||
foreach ($rows as $row) {
|
||||
$data[] = [
|
||||
$row['nama_server'],
|
||||
$row['start_time'],
|
||||
number_format((float)$row['nominal'], 0, ',', '.'),
|
||||
$row['user_create'],
|
||||
$row['status'],
|
||||
$row['update_time'],
|
||||
[ // kolom 6 → objek
|
||||
"id" => $row['id'],
|
||||
"bukti_success" => $row['bukti_success']
|
||||
]
|
||||
];
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$data = [];
|
||||
}
|
||||
|
||||
// Response ke DataTables
|
||||
echo json_encode([
|
||||
"draw" => $draw,
|
||||
"recordsTotal" => $recordsTotal,
|
||||
"recordsFiltered" => $recordsFiltered,
|
||||
"data" => $data
|
||||
]);
|
||||
@@ -0,0 +1,158 @@
|
||||
<?php
|
||||
ini_set('display_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
|
||||
header('Content-Type: text/html; charset=UTF-8');
|
||||
|
||||
/**
|
||||
* Generate form/page HTML berdasarkan data JSON
|
||||
*/
|
||||
function formPage(string $dataform): string {
|
||||
$data = json_decode($dataform, true);
|
||||
|
||||
if (json_last_error() !== JSON_ERROR_NONE || !$data || !isset($data['page'])) {
|
||||
return '<p class="text-danger">Data tidak valid.</p>';
|
||||
}
|
||||
|
||||
$page = $data['page'];
|
||||
$endpoint = $data['endpoint'] ?? '';
|
||||
$apikey = $data['apikey'] ?? '';
|
||||
$tokenkey = $data['tokenkey'] ?? '';
|
||||
|
||||
if ($page === 'flip') {
|
||||
return '
|
||||
<div class="form-group">
|
||||
<label>ENDPOINT URL</label>
|
||||
<input class="form-control" type="text" name="endpoint" value="' . htmlspecialchars($endpoint) . '">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>API SECRET KEY</label>
|
||||
<div class="input-group">
|
||||
<input type="password" class="form-control password-input" id="password1" name="apikey" value="' . htmlspecialchars($apikey) . '">
|
||||
<div class="input-group-append">
|
||||
<div class="input-group-text password-toggle" data-target="password1">
|
||||
<span class="fas fa-eye"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>TOKEN VALIDASI</label>
|
||||
<div class="input-group">
|
||||
<input type="password" class="form-control password-input" id="password2" name="tokenkey" value="' . htmlspecialchars($tokenkey) . '">
|
||||
<div class="input-group-append">
|
||||
<div class="input-group-text password-toggle" data-target="password2">
|
||||
<span class="fas fa-eye"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.querySelectorAll(".password-toggle").forEach(function(toggle) {
|
||||
toggle.addEventListener("click", function() {
|
||||
var targetId = this.getAttribute("data-target");
|
||||
var input = document.getElementById(targetId);
|
||||
var icon = this.querySelector("span");
|
||||
|
||||
if (!input) return;
|
||||
|
||||
if (input.type === "password") {
|
||||
input.type = "text";
|
||||
icon.classList.remove("fa-eye");
|
||||
icon.classList.add("fa-eye-slash");
|
||||
} else {
|
||||
input.type = "password";
|
||||
icon.classList.remove("fa-eye-slash");
|
||||
icon.classList.add("fa-eye");
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
';
|
||||
}
|
||||
|
||||
if ($page === 'paydisini') {
|
||||
return '
|
||||
<div class="form-group d-none">
|
||||
<label>Admin Payment Gateway</label>
|
||||
<select class="form-control" name="adminpg">
|
||||
<option value="2">Beban Owner</option>
|
||||
<option value="1">Beban Customer</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="text-center mb-4">
|
||||
<a data-toggle="collapse" href="#collapseExample" role="button" aria-expanded="false" aria-controls="collapseExample">
|
||||
<h6><b>Aturan dan Kebijakan</b></h6>
|
||||
</a>
|
||||
</div>
|
||||
<div class="collapse" id="collapseExample">
|
||||
<div class="text-center">
|
||||
<h6>Setelah mengaktifkan Paymnent Gateway ini kami anggap sudah menyetujui ketentuan di bawah ini</h6>
|
||||
</div>
|
||||
<div class="card-body text-justify">
|
||||
<h6>Umum</h6>
|
||||
<ul>
|
||||
<li>ManjaPro didukung oleh Paydisini Payment Gateway Indonesia untuk proses pembayaran.</li>
|
||||
<li>Semua transaksi harus dilakukan melalui sistem resmi ManjaPro untuk keamanan dan validasi.</li>
|
||||
<li>Pelanggan bertanggung jawab atas keamanan akun dan informasi pembayaran masing-masing.</li>
|
||||
</ul>
|
||||
|
||||
<h6>Alur Kerja Pembayaran</h6>
|
||||
<ul>
|
||||
<li>Pelanggan akan diberikan <strong>link pembayaran unik</strong> untuk setiap transaksi (ONE LINK – ONE TRANSACTION).</li>
|
||||
<li>Pembayaran dapat dilakukan melalui metode yang tersedia: BRI VA, BNI VA, Mandiri VA, atau QRIS.</li>
|
||||
<li>Setelah pembayaran diterima, dana akan ditahan selama 1x24 jam di rekening ManjaPro untuk proses pengecekan dan penyesuaian (check & balance).</li>
|
||||
<li>Saldo dapat digunakan atau ditarik (withdraw) setelah status pembayaran berhasil diverifikasi.</li>
|
||||
<li>Pelanggan wajib memastikan data pembayaran dan nominal yang dikirim sesuai dengan instruksi.</li>
|
||||
</ul>
|
||||
|
||||
<h6>Biaya Admin</h6>
|
||||
<ul>
|
||||
<li>Untuk biaya admin Payment Gateway bisa di bebankan ke pelanggan atau ke pemilik</li>
|
||||
<li>BRI VA : Rp. 2.950</li>
|
||||
<li>BNI VA : Rp. 4.500</li>
|
||||
<li>Mandiri VA : Rp. 2.950</li>
|
||||
<li>QRIS : 1%</li>
|
||||
</ul>
|
||||
|
||||
<h6>Withdraw / Penarikan Saldo</h6>
|
||||
<ul>
|
||||
<li>Withdraw hanya dapat dilakukan pada hari kerja. Permintaan pada hari libur akan diproses pada hari kerja berikutnya.</li>
|
||||
<li>Withdraw hanya dapat dilakukan ke rekening yang telah diverifikasi oleh sistem ManjaPro.</li>
|
||||
<li>Verifikasi rekening dapat dilakukan melalui menu <strong>Profil</strong> di akun pelanggan.</li>
|
||||
<li>Minimal saldo untuk melakukan withdraw adalah sesuai ketentuan yang berlaku di akun pelanggan.</li>
|
||||
<li>ManjaPro berhak menunda atau menolak transaksi withdraw jika ditemukan indikasi penipuan atau kesalahan data.</li>
|
||||
</ul>
|
||||
|
||||
<h6>Pemecahan Masalah / Komplain</h6>
|
||||
<ul>
|
||||
<li>Jika terjadi kesalahan pada transaksi atau masalah lainnya, pelanggan wajib menghubungi layanan pelanggan ManjaPro untuk perundingan.</li>
|
||||
<li>Setiap komplain akan diproses sesuai dengan data transaksi yang tercatat di sistem.</li>
|
||||
<li>Keputusan akhir akan diambil oleh ManjaPro setelah proses pengecekan dan verifikasi.</li>
|
||||
</ul>
|
||||
|
||||
<h6>Ketentuan Tambahan</h6>
|
||||
<ul>
|
||||
<li>ManjaPro berhak mengubah aturan dan kebijakan ini sewaktu-waktu tanpa pemberitahuan terlebih dahulu.</li>
|
||||
<li>Pelanggan dianggap menyetujui aturan ini saat melakukan transaksi melalui ManjaPro.</li>
|
||||
<li>Segala tindakan yang melanggar ketentuan dapat menyebabkan akun diblokir atau transaksi dibatalkan.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
';
|
||||
}
|
||||
|
||||
return '<p class="text-danger">Page tidak dikenali.</p>';
|
||||
}
|
||||
|
||||
// Terima JSON dari fetch()
|
||||
$inputJSON = file_get_contents('php://input');
|
||||
|
||||
if (!$inputJSON) {
|
||||
echo "<p class='text-danger'>Data tidak diterima.</p>";
|
||||
exit;
|
||||
}
|
||||
|
||||
// Tampilkan hasil formPage
|
||||
echo formPage($inputJSON);
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
include '../config/connect.php';
|
||||
require 'payment/client/jwtoken/url_paymnet_encrypt.php';
|
||||
|
||||
function createUrlpaydisini($id)
|
||||
{
|
||||
if (empty($id) || !is_numeric($id)) {
|
||||
return ["status" => false];
|
||||
}
|
||||
|
||||
global $pdo;
|
||||
|
||||
try {
|
||||
$stmt = $pdo->prepare("SELECT nama_server, nama FROM v_tagihan WHERE id = :id LIMIT 1");
|
||||
if (!$stmt->execute(['id' => $id])) {
|
||||
return ["status" => false];
|
||||
}
|
||||
|
||||
$pelanggan = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
if (!$pelanggan) {
|
||||
return ["status" => false];
|
||||
}
|
||||
|
||||
$namaServer = $pelanggan['nama_server'] ?? '';
|
||||
$namaPelanggan = $pelanggan['nama'] ?? '';
|
||||
|
||||
$server = mb_strtolower(preg_replace('/[^a-zA-Z0-9]+/', '', (string)$namaServer));
|
||||
$nama = mb_strtolower(preg_replace('/[^a-zA-Z0-9]+/', '', (string)$namaPelanggan));
|
||||
|
||||
if ($server === '' || $nama === '') {
|
||||
return ["status" => false];
|
||||
}
|
||||
|
||||
$encId = jwt_encrypt($id);
|
||||
if (empty($encId) || !is_string($encId)) {
|
||||
return ["status" => false];
|
||||
}
|
||||
|
||||
return [
|
||||
"status" => true,
|
||||
"url" => "pay.manjapro.net/{$server}/{$nama}/{$encId}"
|
||||
];
|
||||
} catch (Throwable $e) {
|
||||
// kalau mau log error: error_log($e->getMessage());
|
||||
return ["status" => false];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
<?php
|
||||
|
||||
/** remote_add() // ambil data mikrotik lalu cek address aplikasi, jika address adalah "tunnel.manjapr.net" maka buat port nya di 2 mikrotik dan jika bukan maka buatnya langsung ke mikrotik nya
|
||||
* buat range port untuk remote ONU.
|
||||
* buat schedule untuk ubah port ke kosong
|
||||
*/
|
||||
class RemoteModem
|
||||
{
|
||||
private $pdo;
|
||||
|
||||
public function __construct($pdo)
|
||||
{
|
||||
$this->pdo = $pdo; // Inject PDO
|
||||
}
|
||||
|
||||
public function remote_add($id_mikrotik, $ip_akses, $nama_user)
|
||||
{
|
||||
$mikrotik = new RouterosAPI();
|
||||
$mikrotik->debug = false;
|
||||
|
||||
try {
|
||||
// 🔥 Ambil data Mikrotik
|
||||
$stmt = $this->pdo->prepare("SELECT ip_address, username, password, port_api, radius_nas_data
|
||||
FROM setting_mikrotik
|
||||
WHERE id = :id");
|
||||
$stmt->execute([':id' => $id_mikrotik]);
|
||||
$mikrotikUser = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if (!$mikrotikUser) {
|
||||
return json_encode([
|
||||
"status" => "error",
|
||||
"message" => "Mikrotik dengan ID $id_mikrotik tidak ditemukan."
|
||||
]);
|
||||
}
|
||||
|
||||
// 🔥 Ambil remote-address jika tunnel
|
||||
$dataIP = json_decode($mikrotikUser['radius_nas_data']);
|
||||
$iptunnel = $dataIP->data->{'remote-address'} ?? null;
|
||||
|
||||
do {
|
||||
$freePort = rand(10000, 19999);
|
||||
|
||||
$stmt = $this->pdo->prepare("SELECT COUNT(*) FROM log_remote WHERE remote_port = :port");
|
||||
$stmt->execute([':port' => $freePort]);
|
||||
$count = $stmt->fetchColumn();
|
||||
} while ($count > 0);
|
||||
|
||||
|
||||
$Secret = "Remote-User-" . $nama_user;
|
||||
|
||||
if ($mikrotikUser['ip_address'] === "tunnel.manjapro.net" && !empty($iptunnel)) {
|
||||
// 🔥 Koneksi ke Mikrotik pusat
|
||||
if (!$mikrotik->connect2('manjapro.net', 'apiapkmanjapro', 'apiapkmanjapro123321', 2887)) {
|
||||
return json_encode([
|
||||
"status" => "error",
|
||||
"message" => "Gagal koneksi ke Mikrotik pusat."
|
||||
]);
|
||||
}
|
||||
|
||||
// Tambah NAT di Mikrotik pusat
|
||||
$mikrotik->comm('/ip/firewall/nat/add', [
|
||||
"chain" => "dstnat",
|
||||
"dst-address-list" => "IP-Public",
|
||||
"dst-port" => $freePort,
|
||||
"protocol" => "tcp",
|
||||
"action" => "dst-nat",
|
||||
"to-addresses" => $iptunnel,
|
||||
"to-ports" => $freePort,
|
||||
"comment" => $Secret
|
||||
]);
|
||||
$mikrotik->disconnect();
|
||||
|
||||
// 🔥 Koneksi ke Mikrotik remote
|
||||
if (!$mikrotik->connect2($mikrotikUser['ip_address'], $mikrotikUser['username'], $mikrotikUser['password'], $mikrotikUser['port_api'])) {
|
||||
return json_encode([
|
||||
"status" => "error",
|
||||
"message" => "Gagal koneksi ke Mikrotik remote."
|
||||
]);
|
||||
}
|
||||
|
||||
// Tambah NAT di Mikrotik remote
|
||||
$mikrotik->comm('/ip/firewall/nat/add', [
|
||||
"chain" => "dstnat",
|
||||
"dst-address" => $iptunnel,
|
||||
"dst-port" => $freePort,
|
||||
"protocol" => "tcp",
|
||||
"action" => "dst-nat",
|
||||
"to-addresses" => $ip_akses,
|
||||
"to-ports" => 80,
|
||||
"comment" => $Secret
|
||||
]);
|
||||
$mikrotik->disconnect();
|
||||
|
||||
$jenis = "tunnel";
|
||||
|
||||
} else {
|
||||
// 🔥 Koneksi ke Mikrotik langsung
|
||||
if (!$mikrotik->connect2($mikrotikUser['ip_address'], $mikrotikUser['username'], $mikrotikUser['password'], $mikrotikUser['port_api'])) {
|
||||
return json_encode([
|
||||
"status" => "error",
|
||||
"message" => "Gagal koneksi ke Mikrotik."
|
||||
]);
|
||||
}
|
||||
|
||||
// Tambah NAT di Mikrotik
|
||||
$mikrotik->comm('/ip/firewall/nat/add', [
|
||||
"chain" => "dstnat",
|
||||
"dst-address" => $mikrotikUser['ip_address'],
|
||||
"dst-port" => $freePort,
|
||||
"protocol" => "tcp",
|
||||
"action" => "dst-nat",
|
||||
"to-addresses" => $ip_akses,
|
||||
"to-ports" => 80,
|
||||
"comment" => $Secret
|
||||
]);
|
||||
$mikrotik->disconnect();
|
||||
|
||||
$jenis = "public";
|
||||
}
|
||||
|
||||
// 🔥 Simpan log_remote
|
||||
$stmt = $this->pdo->prepare("INSERT INTO log_remote
|
||||
(id_setting_mikrotik, nama_user, remote_port, aktif_time, jenis)
|
||||
VALUES (:id_setting_mikrotik, :nama_user, :remote_port, :aktif_time, :jenis)");
|
||||
$stmt->execute([
|
||||
':id_setting_mikrotik' => $id_mikrotik,
|
||||
':nama_user' => $nama_user,
|
||||
':remote_port' => $freePort,
|
||||
':aktif_time' => date('Y-m-d H:i:s'),
|
||||
':jenis' => $jenis
|
||||
]);
|
||||
|
||||
return json_encode([
|
||||
"status" => "success",
|
||||
"message" => "Remote berhasil ditambahkan.",
|
||||
"remote_port" => $freePort,
|
||||
"link_remote" => $mikrotikUser['ip_address'] . ":" . $freePort,
|
||||
"jenis" => $jenis
|
||||
]);
|
||||
|
||||
} catch (Exception $e) {
|
||||
return json_encode([
|
||||
"status" => "error",
|
||||
"message" => $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function remote_close($id_mikrotik, $port)
|
||||
{
|
||||
$mikrotik = new RouterosAPI();
|
||||
$mikrotik->debug = false;
|
||||
|
||||
try {
|
||||
// 🔥 Ambil data Mikrotik
|
||||
$stmt = $this->pdo->prepare("SELECT ip_address, username, password, port_api, radius_nas_data
|
||||
FROM setting_mikrotik
|
||||
WHERE id = :id");
|
||||
$stmt->execute([':id' => $id_mikrotik]);
|
||||
$mikrotikUser = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if (!$mikrotikUser) {
|
||||
return json_encode([
|
||||
"status" => "error",
|
||||
"message" => "Mikrotik dengan ID $id_mikrotik tidak ditemukan."
|
||||
]);
|
||||
}
|
||||
|
||||
$dataIP = json_decode($mikrotikUser['radius_nas_data']);
|
||||
$iptunnel = $dataIP->data->{'remote-address'} ?? null;
|
||||
|
||||
if ($mikrotikUser['ip_address'] === "tunnel.manjapro.net" && !empty($iptunnel)) {
|
||||
// 🔥 Hapus di Mikrotik pusat
|
||||
if ($mikrotik->connect2('manjapro.net', 'apiapkmanjapro', 'apiapkmanjapro123321', 2887)) {
|
||||
$this->removeNatRule($mikrotik, $port);
|
||||
$mikrotik->disconnect();
|
||||
}
|
||||
|
||||
// 🔥 Hapus di Mikrotik remote
|
||||
if ($mikrotik->connect2($mikrotikUser['ip_address'], $mikrotikUser['username'], $mikrotikUser['password'], $mikrotikUser['port_api'])) {
|
||||
$this->removeNatRule($mikrotik, $port);
|
||||
$mikrotik->disconnect();
|
||||
}
|
||||
} else {
|
||||
// 🔥 Hapus di Mikrotik langsung
|
||||
if ($mikrotik->connect2($mikrotikUser['ip_address'], $mikrotikUser['username'], $mikrotikUser['password'], $mikrotikUser['port_api'])) {
|
||||
$this->removeNatRule($mikrotik, $port);
|
||||
$mikrotik->disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
// 🔥 Hapus log_remote
|
||||
$stmt = $this->pdo->prepare("DELETE FROM log_remote
|
||||
WHERE id_setting_mikrotik = :id AND remote_port = :port");
|
||||
$stmt->execute([
|
||||
':id' => $id_mikrotik,
|
||||
':port' => $port
|
||||
]);
|
||||
|
||||
return json_encode([
|
||||
"status" => "success",
|
||||
"message" => "Remote pada port $port berhasil ditutup."
|
||||
]);
|
||||
|
||||
} catch (Exception $e) {
|
||||
return json_encode([
|
||||
"status" => "error",
|
||||
"message" => $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
private function removeNatRule($mikrotik, $port)
|
||||
{
|
||||
// 🔥 Cari dan hapus NAT rule berdasarkan dst-port
|
||||
$natRules = $mikrotik->comm('/ip/firewall/nat/print');
|
||||
foreach ($natRules as $rule) {
|
||||
if (isset($rule['dst-port']) && $rule['dst-port'] == $port) {
|
||||
$mikrotik->comm('/ip/firewall/nat/remove', ['.id' => $rule['.id']]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
header("Content-Type: application/json");
|
||||
|
||||
$flipKey = "JDJ5JDEzJHlkOFNYckl1a3U3VXJkZERKVnNZL3VTN1BLWmE2U3NMeUJXZC9COFV4LmZlb2VUTmdQaEN5"; // ganti dengan key kamu
|
||||
$url = "https://bigflip.id/api/v2/disbursement/bank-account-inquiry";
|
||||
|
||||
$bank_code = "bri"; // contoh bank
|
||||
$account_number = "778001005210532"; // contoh no rek
|
||||
$inquiry_key = uniqid("inq_"); // harus unik setiap request
|
||||
|
||||
$data = http_build_query([
|
||||
"bank_code" => strtolower($bank_code),
|
||||
"account_number" => $account_number,
|
||||
"inquiry_key" => $inquiry_key
|
||||
]);
|
||||
|
||||
$ch = curl_init($url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||||
"Content-Type: application/x-www-form-urlencoded",
|
||||
"Accept: application/json; charset=UTF-8",
|
||||
"Authorization: Basic " . base64_encode($flipKey . ":")
|
||||
]);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
|
||||
if (curl_errno($ch)) {
|
||||
echo json_encode([
|
||||
"status" => false,
|
||||
"message" => curl_error($ch)
|
||||
]);
|
||||
curl_close($ch);
|
||||
exit;
|
||||
}
|
||||
curl_close($ch);
|
||||
|
||||
// cek apakah balasan valid JSON
|
||||
$result = json_decode($response, true);
|
||||
|
||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||
echo json_encode([
|
||||
"status" => false,
|
||||
"message" => "Respon bukan JSON",
|
||||
"http" => $httpCode,
|
||||
"raw" => $response
|
||||
]);
|
||||
} else {
|
||||
echo json_encode([
|
||||
"status" => true,
|
||||
"http" => $httpCode,
|
||||
"response" => $result
|
||||
]);
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
include '../config/connect.php';
|
||||
|
||||
$response = ["success" => false, "message" => "Terjadi kesalahan"];
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$id = intval($_POST['id'] ?? 0);
|
||||
|
||||
if ($id <= 0) {
|
||||
echo json_encode(["success" => false, "message" => "ID tidak valid"]);
|
||||
exit;
|
||||
}
|
||||
|
||||
if (!isset($_FILES['bukti_success']) || $_FILES['bukti_success']['error'] !== UPLOAD_ERR_OK) {
|
||||
echo json_encode(["success" => false, "message" => "File gambar tidak ditemukan"]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$uploadDir = __DIR__ . "/../img/bukti_success/";
|
||||
if (!is_dir($uploadDir)) {
|
||||
mkdir($uploadDir, 0777, true);
|
||||
}
|
||||
|
||||
$ext = pathinfo($_FILES['bukti_success']['name'], PATHINFO_EXTENSION);
|
||||
$fileName = "bukti_" . $id . "_" . time() . "." . strtolower($ext);
|
||||
$filePath = $uploadDir . $fileName;
|
||||
|
||||
if (move_uploaded_file($_FILES['bukti_success']['tmp_name'], $filePath)) {
|
||||
// Update status transaksi withdraw
|
||||
$sql = "UPDATE transaksi_withdraw
|
||||
SET status = 'success', bukti_success = :bukti, update_time = :update_time
|
||||
WHERE id = :id";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([
|
||||
":bukti" => "img/bukti_success/" . $fileName,
|
||||
":update_time" => date('Y-m-d H:i:s'),
|
||||
":id" => $id
|
||||
]);
|
||||
|
||||
// Ambil data transaksi_withdraw yang baru saja diupdate
|
||||
$stmt = $pdo->prepare("SELECT * FROM transaksi_withdraw WHERE id = :id");
|
||||
$stmt->bindParam(':id', $id, PDO::PARAM_INT);
|
||||
$stmt->execute();
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC); // hanya satu baris
|
||||
|
||||
if ($row) {
|
||||
// Generate nomor unik 10 digit
|
||||
$numid = date('Y_md').$id;
|
||||
$keterangan = "Withdraw Pendapatan Voucher Auto Pilot reff_" . $numid;
|
||||
|
||||
// Cek apakah transaksi dengan keterangan tsb sudah ada
|
||||
$stmt = $pdo->prepare("SELECT keterangan FROM transaksi WHERE keterangan = :keterangan");
|
||||
$stmt->bindParam(':keterangan', $keterangan, PDO::PARAM_STR);
|
||||
$stmt->execute();
|
||||
$tagid = $stmt->fetchColumn();
|
||||
|
||||
if ($tagid === false) {
|
||||
$sql = "INSERT INTO transaksi
|
||||
(id_data_server, keterangan, pemasukan, start_time, metode_pembayaran, status)
|
||||
VALUES (:idds, :keterangan, :pemasukan, :start_time, :metode, 'Pendapatan Hotspot')";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->bindParam(':idds', $row['id_data_server'], PDO::PARAM_INT);
|
||||
$stmt->bindParam(':keterangan', $keterangan, PDO::PARAM_STR);
|
||||
$stmt->bindParam(':pemasukan', $row['nominal'], PDO::PARAM_STR);
|
||||
$stmt->bindValue(':start_time', date('Y-m-d H:i:s'));
|
||||
$stmt->bindValue(':metode', 'API Payment');
|
||||
$stmt->execute();
|
||||
}
|
||||
}
|
||||
|
||||
$response = ["success" => true, "message" => "Update berhasil"];
|
||||
} else {
|
||||
$response = ["success" => false, "message" => "Gagal upload file"];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
echo json_encode($response);
|
||||
@@ -14,6 +14,7 @@ try {
|
||||
$length = intval($_GET['length'] ?? 10);
|
||||
$searchValue = $_GET['search']['value'] ?? '';
|
||||
$svid = $_GET['i'] ?? '';
|
||||
$statusFilter = $_GET['s'] ?? '';
|
||||
|
||||
// Kolom yang bisa diurutkan
|
||||
$columns = ['nama_server', 'voucher', 'harga', 'status', 'create_time', 'active_time', 'expaired_time'];
|
||||
@@ -22,14 +23,14 @@ try {
|
||||
$orderColumn = $columns[$orderColumnIndex] ?? 'create_time';
|
||||
|
||||
// Kondisi dasar (statis)
|
||||
$baseCondition = "id_data_server IN (".$svid.")";
|
||||
$baseCondition = "id_data_server IN (".$svid.") AND status = '" . $statusFilter . "'";
|
||||
|
||||
// Hitung total data
|
||||
$totalQuery = $pdo->query("SELECT COUNT(*) FROM v_generate_voucher_manual WHERE $baseCondition");
|
||||
$totalRecords = $totalQuery->fetchColumn();
|
||||
|
||||
// Query data + search
|
||||
$sql = "SELECT nama_server, nama_mikrotik, create_time, voucher, harga, jenis, active_time, expaired_time
|
||||
$sql = "SELECT *
|
||||
FROM v_generate_voucher_manual
|
||||
WHERE $baseCondition";
|
||||
$params = [];
|
||||
@@ -49,7 +50,7 @@ try {
|
||||
|
||||
// Hitung total setelah filter
|
||||
$filteredSql = str_replace(
|
||||
"SELECT nama_server, nama_mikrotik, create_time, voucher, harga, jenis, active_time, expaired_time",
|
||||
"SELECT *",
|
||||
"SELECT COUNT(*)",
|
||||
$sql
|
||||
);
|
||||
@@ -75,23 +76,39 @@ try {
|
||||
$data = [];
|
||||
foreach ($rows as $row) {
|
||||
$harga = floatval($row['harga']);
|
||||
if ($row['jenis'] === 'api-pw') {
|
||||
if (($row['jenis'] === 'api-pw' || $row['jenis'] === 'rad-api-pw') && $row['status'] == 'LUNAS') {
|
||||
$biaya = $harga * $potongan;
|
||||
$active = $row['active_time'];
|
||||
$expired = $row['expaired_time'];
|
||||
$saldo = $harga - $biaya;
|
||||
} else {
|
||||
$biaya = 0; // Tidak ada biaya jika bukan sv-radius
|
||||
if (($row['jenis'] != 'api-pw' || $row['jenis'] != 'rad-api-pw') && $row['status'] == NULL) {
|
||||
$biaya = 0; // Tidak ada biaya jika bukan sv-radius
|
||||
$active = $row['active_time'];
|
||||
$expired = $row['expaired_time'];
|
||||
$saldo = 0;
|
||||
} else {
|
||||
$biaya = 0; // Tidak ada biaya jika bukan sv-radius
|
||||
$active = "";
|
||||
$expired = "";
|
||||
$saldo = 0;
|
||||
}
|
||||
}
|
||||
$saldo = $harga - $biaya;
|
||||
|
||||
|
||||
$data[] = [
|
||||
$row['nama_server'] . '<br>' . $row['nama_mikrotik'],
|
||||
$row['voucher'],
|
||||
number_format($harga), // harga
|
||||
number_format($biaya), // biaya
|
||||
number_format($saldo), // saldo
|
||||
$row['jenis'],
|
||||
number_format((float)$harga, 0, ',', '.'),
|
||||
number_format((float)$biaya, 0, ',', '.'),
|
||||
number_format((float)$saldo, 0, ',', '.'),
|
||||
// number_format($harga), // harga
|
||||
// number_format($biaya), // biaya
|
||||
// number_format($saldo), // saldo
|
||||
$row['jenis'] . '<br>' . $row['status'],
|
||||
$row['create_time'],
|
||||
$row['active_time'],
|
||||
$row['expaired_time'],
|
||||
$active,
|
||||
$expired,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
// error_reporting(1);
|
||||
error_reporting(0);
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', 0);
|
||||
|
||||
$ppnnow = 11;
|
||||
|
||||
@@ -284,14 +286,12 @@ $statuspaygw = $datastatus['status_payment_gateway'];
|
||||
<!--jquery http-->
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
<!-- Load Google Maps API library -->
|
||||
<script>
|
||||
(g=>{var h,a,k,p="The Google Maps JavaScript API",c="google",l="importLibrary",q="__ib__",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement("script"));e.set("libraries",[...r]+"");for(k in g)e.set(k.replace(/[A-Z]/g,t=>"_"+t[0].toLowerCase()),g[k]);e.set("callback",c+".maps."+q);a.src=`https://maps.${c}apis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+" could not load."));a.nonce=m.querySelector("script[nonce]")?.nonce||"";m.head.append(a)}));d[l]?console.warn(p+" only loads once. Ignoring:",g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))})({
|
||||
key: "AIzaSyA1MgLuZuyqR_OGY3ob3M52N46TDBRI_9k",
|
||||
v: "weekly",
|
||||
// Use the 'v' parameter to indicate the version to use (weekly, beta, alpha, etc.).
|
||||
// Add other bootstrap parameters as needed, using camel case.
|
||||
});
|
||||
</script>
|
||||
<link rel="stylesheet" href="dist/js/leaflet/leaflet.css" />
|
||||
<script src="dist/js/leaflet/leaflet.js"></script>
|
||||
|
||||
<link rel="stylesheet" href="dist/js/leaflet/leaflet.fullscreen.css" />
|
||||
<script src="dist/js/leaflet/Leaflet.fullscreen.min.js"></script>
|
||||
|
||||
<style type="text/css">
|
||||
/* Styling untuk marquee container */
|
||||
.marquee-container {
|
||||
@@ -402,32 +402,50 @@ $statuspaygw = $datastatus['status_payment_gateway'];
|
||||
</div>
|
||||
</li> -->
|
||||
<!-- Notifications Dropdown Menu -->
|
||||
<!-- <li class="nav-item dropdown">
|
||||
<a class="nav-link" data-toggle="dropdown" href="#">
|
||||
<i class="far fa-bell"></i>
|
||||
<span class="badge badge-warning navbar-badge">15</span>
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-lg dropdown-menu-right">
|
||||
<span class="dropdown-item dropdown-header">15 Notifications</span>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a href="#" class="dropdown-item">
|
||||
<i class="fas fa-envelope mr-2"></i> 4 new messages
|
||||
<span class="float-right text-muted text-sm">3 mins</span>
|
||||
</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a href="#" class="dropdown-item">
|
||||
<i class="fas fa-users mr-2"></i> 8 friend requests
|
||||
<span class="float-right text-muted text-sm">12 hours</span>
|
||||
</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a href="#" class="dropdown-item">
|
||||
<i class="fas fa-file mr-2"></i> 3 new reports
|
||||
<span class="float-right text-muted text-sm">2 days</span>
|
||||
</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a href="#" class="dropdown-item dropdown-footer">See All Notifications</a>
|
||||
</div>
|
||||
</li> -->
|
||||
<?php if($_SESSION['master']) { ?>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link" data-toggle="dropdown" href="#">
|
||||
<i class="far fa-bell"></i>
|
||||
<span class="badge badge-warning navbar-badge">2</span>
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-lg dropdown-menu-right"
|
||||
style="border-radius: 15px; box-shadow: 0 8px 20px rgba(0,0,0,0.15); overflow:hidden;">
|
||||
|
||||
<!-- Header -->
|
||||
<span class="dropdown-item dropdown-header"
|
||||
style="background: linear-gradient(135deg, #3498db, #8e44ad);
|
||||
color:#fff; font-weight:bold; border-bottom:1px solid #eee;">
|
||||
🔔 2 Notifications
|
||||
</span>
|
||||
|
||||
<!-- Notif 1: AI Customer Service -->
|
||||
<a href="?<?= encrypt_url('whatsapp_gateway/customer_ai'); ?>" class="dropdown-item"
|
||||
style="padding:15px; display:flex; align-items:center;">
|
||||
<i class="fas fa-robot text-primary" style="font-size:20px; margin-right:12px;"></i>
|
||||
<div>
|
||||
<div style="font-weight:bold; color:#2c3e50;">Fitur Baru: AI Customer Service</div>
|
||||
<small style="color:#888;">New</small>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<div class="dropdown-divider"></div>
|
||||
|
||||
<!-- Notif 2: Voucher Auto Pilot -->
|
||||
<a href="?<?= encrypt_url('ganerate_voucher'); ?>" class="dropdown-item"
|
||||
style="padding:15px; display:flex; align-items:center;">
|
||||
<i class="fas fa-ticket-alt text-success" style="font-size:20px; margin-right:12px;"></i>
|
||||
<div>
|
||||
<div style="font-weight:bold; color:#2c3e50;">Fitur Baru: Voucher Auto Pilot</div>
|
||||
<small style="color:#888;">17 Agt 2025</small>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<div class="dropdown-divider"></div>
|
||||
|
||||
</div>
|
||||
</li>
|
||||
<?php } ?>
|
||||
|
||||
<?php if (isset($_SESSION['master'])) { ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link">
|
||||
@@ -840,154 +858,8 @@ $statuspaygw = $datastatus['status_payment_gateway'];
|
||||
})
|
||||
|
||||
</script>
|
||||
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyA1MgLuZuyqR_OGY3ob3M52N46TDBRI_9k&callback=initMap" async defer></script>
|
||||
<script>
|
||||
var map;
|
||||
var marker;
|
||||
|
||||
function initMap() {
|
||||
var latitudeInput = document.getElementById('latitude').value;
|
||||
var longitudeInput = document.getElementById('longitude').value;
|
||||
|
||||
// Cek apakah input form memiliki nilai
|
||||
if (latitudeInput && longitudeInput) {
|
||||
var pos = {
|
||||
lat: parseFloat(latitudeInput),
|
||||
lng: parseFloat(longitudeInput)
|
||||
};
|
||||
initMapWithPos(pos);
|
||||
} else {
|
||||
// Jika input form kosong, gunakan geolocation
|
||||
if (navigator.geolocation) {
|
||||
navigator.geolocation.getCurrentPosition(function(position) {
|
||||
var pos = {
|
||||
lat: position.coords.latitude,
|
||||
lng: position.coords.longitude
|
||||
};
|
||||
initMapWithPos(pos);
|
||||
updateFormInputs(pos.lat, pos.lng);
|
||||
}, function() {
|
||||
handleLocationError(true);
|
||||
});
|
||||
} else {
|
||||
handleLocationError(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fungsi untuk menginisialisasi peta dengan posisi yang diberikan
|
||||
function initMapWithPos(pos) {
|
||||
map = new google.maps.Map(document.getElementById('map'), {
|
||||
center: pos,
|
||||
zoom: 17,
|
||||
mapTypeId: 'hybrid',
|
||||
mapTypeControl: false,
|
||||
streetViewControl: false,
|
||||
fullscreenControl: true,
|
||||
});
|
||||
|
||||
updateMarker(pos.lat, pos.lng);
|
||||
|
||||
// Event listener untuk menambahkan marker saat peta diklik
|
||||
map.addListener('click', function(e) {
|
||||
var latitude = e.latLng.lat().toFixed(6);
|
||||
var longitude = e.latLng.lng().toFixed(6);
|
||||
updateMarker(latitude, longitude);
|
||||
updateFormInputs(latitude, longitude);
|
||||
});
|
||||
}
|
||||
|
||||
// Fungsi untuk menampilkan marker pada peta
|
||||
function updateMarker(latitude, longitude) {
|
||||
if (marker) {
|
||||
marker.setPosition({lat: parseFloat(latitude), lng: parseFloat(longitude)});
|
||||
} else {
|
||||
marker = new google.maps.Marker({
|
||||
position: {lat: parseFloat(latitude), lng: parseFloat(longitude)},
|
||||
map: map
|
||||
});
|
||||
}
|
||||
|
||||
map.setCenter(marker.getPosition());
|
||||
}
|
||||
|
||||
// Fungsi untuk memperbarui nilai input form
|
||||
function updateFormInputs(latitude, longitude) {
|
||||
document.getElementById('latitude').value = latitude;
|
||||
document.getElementById('longitude').value = longitude;
|
||||
|
||||
// Perbarui input latlong
|
||||
document.getElementById('latlong').value = `${latitude}, ${longitude}`;
|
||||
}
|
||||
|
||||
// Tangani error jika geolocation tidak berhasil
|
||||
function handleLocationError(browserHasGeolocation) {
|
||||
alert(browserHasGeolocation ?
|
||||
'Error: The Geolocation service failed.' :
|
||||
'Error: Your browser doesn\'t support geolocation.');
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const latlongInput = document.getElementById('latlong');
|
||||
|
||||
// Ambil input tersembunyi berdasarkan atribut data-maps
|
||||
const latitudeInput = document.querySelector('input[data-maps="latitude"]');
|
||||
const longitudeInput = document.querySelector('input[data-maps="longitude"]');
|
||||
|
||||
// Set nilai latlong jika latitude dan longitude sudah ada
|
||||
if (latitudeInput.value && longitudeInput.value) {
|
||||
latlongInput.value = `${latitudeInput.value}, ${longitudeInput.value}`;
|
||||
}
|
||||
|
||||
latlongInput.addEventListener('input', function() {
|
||||
const latlongValue = latlongInput.value.split(',');
|
||||
|
||||
// Validasi format latitude dan longitude
|
||||
const latLongRegex = /^(-?\d+(\.\d+)?),\s*(-?\d+(\.\d+)?)$/; // Format: latitude, longitude
|
||||
if (latLongRegex.test(latlongInput.value.trim())) {
|
||||
// Pastikan kita memiliki dua nilai: latitude dan longitude
|
||||
if (latlongValue.length === 2) {
|
||||
const lat = latlongValue[0].trim();
|
||||
const long = latlongValue[1].trim();
|
||||
|
||||
// Update input tersembunyi
|
||||
latitudeInput.value = lat;
|
||||
longitudeInput.value = long;
|
||||
|
||||
// Update marker dan center peta
|
||||
updateMarker(lat, long);
|
||||
map.setCenter({lat: parseFloat(lat), lng: parseFloat(long)});
|
||||
}
|
||||
} else {
|
||||
// Jika format tidak valid, beri delay sebelum menampilkan pesan
|
||||
setTimeout(function() {
|
||||
latlongInput.value = ''; // Kosongkan nilai
|
||||
latlongInput.placeholder = 'Isi dengan format yang sesuai'; // Tampilkan pesan
|
||||
latitudeInput.value = ''; // Kosongkan input tersembunyi
|
||||
longitudeInput.value = ''; // Kosongkan input tersembunyi
|
||||
}, 500); // Delay 500ms
|
||||
}
|
||||
});
|
||||
|
||||
// Event listener untuk mengupdate latlong input saat latitude atau longitude diubah
|
||||
latitudeInput.addEventListener('input', function() {
|
||||
const lat = latitudeInput.value;
|
||||
const long = longitudeInput.value;
|
||||
|
||||
// Update latlong input
|
||||
latlongInput.value = `${lat}, ${long}`;
|
||||
});
|
||||
|
||||
longitudeInput.addEventListener('input', function() {
|
||||
const lat = latitudeInput.value;
|
||||
const long = longitudeInput.value;
|
||||
|
||||
// Update latlong input
|
||||
latlongInput.value = `${lat}, ${long}`;
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const dropdown0 = document.getElementById('dropdown0');
|
||||
|
||||
|
After Width: | Height: | Size: 62 KiB |
@@ -0,0 +1,168 @@
|
||||
(function (factory) {
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
// AMD
|
||||
define(['leaflet'], factory);
|
||||
} else if (typeof module !== 'undefined') {
|
||||
// Node/CommonJS
|
||||
module.exports = factory(require('leaflet'));
|
||||
} else {
|
||||
// Browser globals
|
||||
if (typeof window.L === 'undefined') {
|
||||
throw new Error('Leaflet must be loaded first');
|
||||
}
|
||||
factory(window.L);
|
||||
}
|
||||
}(function (L) {
|
||||
L.Control.Fullscreen = L.Control.extend({
|
||||
options: {
|
||||
position: 'topleft',
|
||||
title: {
|
||||
'false': 'View Fullscreen',
|
||||
'true': 'Exit Fullscreen'
|
||||
}
|
||||
},
|
||||
|
||||
onAdd: function (map) {
|
||||
var container = L.DomUtil.create('div', 'leaflet-control-fullscreen leaflet-bar leaflet-control');
|
||||
|
||||
this.link = L.DomUtil.create('a', 'leaflet-control-fullscreen-button leaflet-bar-part', container);
|
||||
this.link.href = '#';
|
||||
|
||||
this._map = map;
|
||||
this._map.on('fullscreenchange', this._toggleTitle, this);
|
||||
this._toggleTitle();
|
||||
|
||||
L.DomEvent.on(this.link, 'click', this._click, this);
|
||||
|
||||
return container;
|
||||
},
|
||||
|
||||
_click: function (e) {
|
||||
L.DomEvent.stopPropagation(e);
|
||||
L.DomEvent.preventDefault(e);
|
||||
this._map.toggleFullscreen(this.options);
|
||||
},
|
||||
|
||||
_toggleTitle: function() {
|
||||
this.link.title = this.options.title[this._map.isFullscreen()];
|
||||
}
|
||||
});
|
||||
|
||||
L.Map.include({
|
||||
isFullscreen: function () {
|
||||
return this._isFullscreen || false;
|
||||
},
|
||||
|
||||
toggleFullscreen: function (options) {
|
||||
var container = this.getContainer();
|
||||
if (this.isFullscreen()) {
|
||||
if (options && options.pseudoFullscreen) {
|
||||
this._disablePseudoFullscreen(container);
|
||||
} else if (document.exitFullscreen) {
|
||||
document.exitFullscreen();
|
||||
} else if (document.mozCancelFullScreen) {
|
||||
document.mozCancelFullScreen();
|
||||
} else if (document.webkitCancelFullScreen) {
|
||||
document.webkitCancelFullScreen();
|
||||
} else if (document.msExitFullscreen) {
|
||||
document.msExitFullscreen();
|
||||
} else {
|
||||
this._disablePseudoFullscreen(container);
|
||||
}
|
||||
} else {
|
||||
if (options && options.pseudoFullscreen) {
|
||||
this._enablePseudoFullscreen(container);
|
||||
} else if (container.requestFullscreen) {
|
||||
container.requestFullscreen();
|
||||
} else if (container.mozRequestFullScreen) {
|
||||
container.mozRequestFullScreen();
|
||||
} else if (container.webkitRequestFullscreen) {
|
||||
container.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
|
||||
} else if (container.msRequestFullscreen) {
|
||||
container.msRequestFullscreen();
|
||||
} else {
|
||||
this._enablePseudoFullscreen(container);
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
_enablePseudoFullscreen: function (container) {
|
||||
L.DomUtil.addClass(container, 'leaflet-pseudo-fullscreen');
|
||||
this._setFullscreen(true);
|
||||
this.fire('fullscreenchange');
|
||||
},
|
||||
|
||||
_disablePseudoFullscreen: function (container) {
|
||||
L.DomUtil.removeClass(container, 'leaflet-pseudo-fullscreen');
|
||||
this._setFullscreen(false);
|
||||
this.fire('fullscreenchange');
|
||||
},
|
||||
|
||||
_setFullscreen: function(fullscreen) {
|
||||
this._isFullscreen = fullscreen;
|
||||
var container = this.getContainer();
|
||||
if (fullscreen) {
|
||||
L.DomUtil.addClass(container, 'leaflet-fullscreen-on');
|
||||
} else {
|
||||
L.DomUtil.removeClass(container, 'leaflet-fullscreen-on');
|
||||
}
|
||||
this.invalidateSize();
|
||||
},
|
||||
|
||||
_onFullscreenChange: function (e) {
|
||||
var fullscreenElement =
|
||||
document.fullscreenElement ||
|
||||
document.mozFullScreenElement ||
|
||||
document.webkitFullscreenElement ||
|
||||
document.msFullscreenElement;
|
||||
|
||||
if (fullscreenElement === this.getContainer() && !this._isFullscreen) {
|
||||
this._setFullscreen(true);
|
||||
this.fire('fullscreenchange');
|
||||
} else if (fullscreenElement !== this.getContainer() && this._isFullscreen) {
|
||||
this._setFullscreen(false);
|
||||
this.fire('fullscreenchange');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
L.Map.mergeOptions({
|
||||
fullscreenControl: false
|
||||
});
|
||||
|
||||
L.Map.addInitHook(function () {
|
||||
if (this.options.fullscreenControl) {
|
||||
this.fullscreenControl = new L.Control.Fullscreen(this.options.fullscreenControl);
|
||||
this.addControl(this.fullscreenControl);
|
||||
}
|
||||
|
||||
var fullscreenchange;
|
||||
|
||||
if ('onfullscreenchange' in document) {
|
||||
fullscreenchange = 'fullscreenchange';
|
||||
} else if ('onmozfullscreenchange' in document) {
|
||||
fullscreenchange = 'mozfullscreenchange';
|
||||
} else if ('onwebkitfullscreenchange' in document) {
|
||||
fullscreenchange = 'webkitfullscreenchange';
|
||||
} else if ('onmsfullscreenchange' in document) {
|
||||
fullscreenchange = 'MSFullscreenChange';
|
||||
}
|
||||
|
||||
if (fullscreenchange) {
|
||||
var onFullscreenChange = L.bind(this._onFullscreenChange, this);
|
||||
|
||||
this.whenReady(function () {
|
||||
L.DomEvent.on(document, fullscreenchange, onFullscreenChange);
|
||||
});
|
||||
|
||||
this.on('unload', function () {
|
||||
L.DomEvent.off(document, fullscreenchange, onFullscreenChange);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
L.control.fullscreen = function (options) {
|
||||
return new L.Control.Fullscreen(options);
|
||||
};
|
||||
}));
|
||||
@@ -0,0 +1 @@
|
||||
(function(factory){var L;if(typeof define==="function"&&define.amd){define(["leaflet"],factory)}else if(typeof module!=="undefined"){L=require("leaflet");module.exports=factory(L)}else{if(typeof window.L==="undefined"){throw new Error("Leaflet must be loaded first")}factory(window.L)}})(function(L){L.Control.Fullscreen=L.Control.extend({options:{position:"topleft",title:{"false":"View Fullscreen","true":"Exit Fullscreen"}},onAdd:function(map){var container=L.DomUtil.create("div","leaflet-control-fullscreen leaflet-bar leaflet-control");this.link=L.DomUtil.create("a","leaflet-control-fullscreen-button leaflet-bar-part",container);this.link.href="#";this._map=map;this._map.on("fullscreenchange",this._toggleTitle,this);this._toggleTitle();L.DomEvent.on(this.link,"click",this._click,this);return container},_click:function(e){L.DomEvent.stopPropagation(e);L.DomEvent.preventDefault(e);this._map.toggleFullscreen(this.options)},_toggleTitle:function(){this.link.title=this.options.title[this._map.isFullscreen()]}});L.Map.include({isFullscreen:function(){return this._isFullscreen||false},toggleFullscreen:function(options){var container=this.getContainer();if(this.isFullscreen()){if(options&&options.pseudoFullscreen){this._disablePseudoFullscreen(container)}else if(document.exitFullscreen){document.exitFullscreen()}else if(document.mozCancelFullScreen){document.mozCancelFullScreen()}else if(document.webkitCancelFullScreen){document.webkitCancelFullScreen()}else if(document.msExitFullscreen){document.msExitFullscreen()}else{this._disablePseudoFullscreen(container)}}else{if(options&&options.pseudoFullscreen){this._enablePseudoFullscreen(container)}else if(container.requestFullscreen){container.requestFullscreen()}else if(container.mozRequestFullScreen){container.mozRequestFullScreen()}else if(container.webkitRequestFullscreen){container.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT)}else if(container.msRequestFullscreen){container.msRequestFullscreen()}else{this._enablePseudoFullscreen(container)}}},_enablePseudoFullscreen:function(container){L.DomUtil.addClass(container,"leaflet-pseudo-fullscreen");this._setFullscreen(true);this.fire("fullscreenchange")},_disablePseudoFullscreen:function(container){L.DomUtil.removeClass(container,"leaflet-pseudo-fullscreen");this._setFullscreen(false);this.fire("fullscreenchange")},_setFullscreen:function(fullscreen){this._isFullscreen=fullscreen;var container=this.getContainer();if(fullscreen){L.DomUtil.addClass(container,"leaflet-fullscreen-on")}else{L.DomUtil.removeClass(container,"leaflet-fullscreen-on")}this.invalidateSize()},_onFullscreenChange:function(e){var fullscreenElement=document.fullscreenElement||document.mozFullScreenElement||document.webkitFullscreenElement||document.msFullscreenElement;if(fullscreenElement===this.getContainer()&&!this._isFullscreen){this._setFullscreen(true);this.fire("fullscreenchange")}else if(fullscreenElement!==this.getContainer()&&this._isFullscreen){this._setFullscreen(false);this.fire("fullscreenchange")}}});L.Map.mergeOptions({fullscreenControl:false});L.Map.addInitHook(function(){if(this.options.fullscreenControl){this.fullscreenControl=new L.Control.Fullscreen(this.options.fullscreenControl);this.addControl(this.fullscreenControl)}var fullscreenchange;if("onfullscreenchange"in document){fullscreenchange="fullscreenchange"}else if("onmozfullscreenchange"in document){fullscreenchange="mozfullscreenchange"}else if("onwebkitfullscreenchange"in document){fullscreenchange="webkitfullscreenchange"}else if("onmsfullscreenchange"in document){fullscreenchange="MSFullscreenChange"}if(fullscreenchange){var onFullscreenChange=L.bind(this._onFullscreenChange,this);this.whenReady(function(){L.DomEvent.on(document,fullscreenchange,onFullscreenChange)});this.on("unload",function(){L.DomEvent.off(document,fullscreenchange,onFullscreenChange)})}});L.control.fullscreen=function(options){return new L.Control.Fullscreen(options)}});
|
||||
|
After Width: | Height: | Size: 299 B |
|
After Width: | Height: | Size: 420 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 696 B |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 618 B |
@@ -0,0 +1,661 @@
|
||||
/* required styles */
|
||||
|
||||
.leaflet-pane,
|
||||
.leaflet-tile,
|
||||
.leaflet-marker-icon,
|
||||
.leaflet-marker-shadow,
|
||||
.leaflet-tile-container,
|
||||
.leaflet-pane > svg,
|
||||
.leaflet-pane > canvas,
|
||||
.leaflet-zoom-box,
|
||||
.leaflet-image-layer,
|
||||
.leaflet-layer {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
.leaflet-container {
|
||||
overflow: hidden;
|
||||
}
|
||||
.leaflet-tile,
|
||||
.leaflet-marker-icon,
|
||||
.leaflet-marker-shadow {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
user-select: none;
|
||||
-webkit-user-drag: none;
|
||||
}
|
||||
/* Prevents IE11 from highlighting tiles in blue */
|
||||
.leaflet-tile::selection {
|
||||
background: transparent;
|
||||
}
|
||||
/* Safari renders non-retina tile on retina better with this, but Chrome is worse */
|
||||
.leaflet-safari .leaflet-tile {
|
||||
image-rendering: -webkit-optimize-contrast;
|
||||
}
|
||||
/* hack that prevents hw layers "stretching" when loading new tiles */
|
||||
.leaflet-safari .leaflet-tile-container {
|
||||
width: 1600px;
|
||||
height: 1600px;
|
||||
-webkit-transform-origin: 0 0;
|
||||
}
|
||||
.leaflet-marker-icon,
|
||||
.leaflet-marker-shadow {
|
||||
display: block;
|
||||
}
|
||||
/* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */
|
||||
/* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */
|
||||
.leaflet-container .leaflet-overlay-pane svg {
|
||||
max-width: none !important;
|
||||
max-height: none !important;
|
||||
}
|
||||
.leaflet-container .leaflet-marker-pane img,
|
||||
.leaflet-container .leaflet-shadow-pane img,
|
||||
.leaflet-container .leaflet-tile-pane img,
|
||||
.leaflet-container img.leaflet-image-layer,
|
||||
.leaflet-container .leaflet-tile {
|
||||
max-width: none !important;
|
||||
max-height: none !important;
|
||||
width: auto;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.leaflet-container img.leaflet-tile {
|
||||
/* See: https://bugs.chromium.org/p/chromium/issues/detail?id=600120 */
|
||||
mix-blend-mode: plus-lighter;
|
||||
}
|
||||
|
||||
.leaflet-container.leaflet-touch-zoom {
|
||||
-ms-touch-action: pan-x pan-y;
|
||||
touch-action: pan-x pan-y;
|
||||
}
|
||||
.leaflet-container.leaflet-touch-drag {
|
||||
-ms-touch-action: pinch-zoom;
|
||||
/* Fallback for FF which doesn't support pinch-zoom */
|
||||
touch-action: none;
|
||||
touch-action: pinch-zoom;
|
||||
}
|
||||
.leaflet-container.leaflet-touch-drag.leaflet-touch-zoom {
|
||||
-ms-touch-action: none;
|
||||
touch-action: none;
|
||||
}
|
||||
.leaflet-container {
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
.leaflet-container a {
|
||||
-webkit-tap-highlight-color: rgba(51, 181, 229, 0.4);
|
||||
}
|
||||
.leaflet-tile {
|
||||
filter: inherit;
|
||||
visibility: hidden;
|
||||
}
|
||||
.leaflet-tile-loaded {
|
||||
visibility: inherit;
|
||||
}
|
||||
.leaflet-zoom-box {
|
||||
width: 0;
|
||||
height: 0;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
z-index: 800;
|
||||
}
|
||||
/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */
|
||||
.leaflet-overlay-pane svg {
|
||||
-moz-user-select: none;
|
||||
}
|
||||
|
||||
.leaflet-pane { z-index: 400; }
|
||||
|
||||
.leaflet-tile-pane { z-index: 200; }
|
||||
.leaflet-overlay-pane { z-index: 400; }
|
||||
.leaflet-shadow-pane { z-index: 500; }
|
||||
.leaflet-marker-pane { z-index: 600; }
|
||||
.leaflet-tooltip-pane { z-index: 650; }
|
||||
.leaflet-popup-pane { z-index: 700; }
|
||||
|
||||
.leaflet-map-pane canvas { z-index: 100; }
|
||||
.leaflet-map-pane svg { z-index: 200; }
|
||||
|
||||
.leaflet-vml-shape {
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
}
|
||||
.lvml {
|
||||
behavior: url(#default#VML);
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
|
||||
/* control positioning */
|
||||
|
||||
.leaflet-control {
|
||||
position: relative;
|
||||
z-index: 800;
|
||||
pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
|
||||
pointer-events: auto;
|
||||
}
|
||||
.leaflet-top,
|
||||
.leaflet-bottom {
|
||||
position: absolute;
|
||||
z-index: 1000;
|
||||
pointer-events: none;
|
||||
}
|
||||
.leaflet-top {
|
||||
top: 0;
|
||||
}
|
||||
.leaflet-right {
|
||||
right: 0;
|
||||
}
|
||||
.leaflet-bottom {
|
||||
bottom: 0;
|
||||
}
|
||||
.leaflet-left {
|
||||
left: 0;
|
||||
}
|
||||
.leaflet-control {
|
||||
float: left;
|
||||
clear: both;
|
||||
}
|
||||
.leaflet-right .leaflet-control {
|
||||
float: right;
|
||||
}
|
||||
.leaflet-top .leaflet-control {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.leaflet-bottom .leaflet-control {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.leaflet-left .leaflet-control {
|
||||
margin-left: 10px;
|
||||
}
|
||||
.leaflet-right .leaflet-control {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
|
||||
/* zoom and fade animations */
|
||||
|
||||
.leaflet-fade-anim .leaflet-popup {
|
||||
opacity: 0;
|
||||
-webkit-transition: opacity 0.2s linear;
|
||||
-moz-transition: opacity 0.2s linear;
|
||||
transition: opacity 0.2s linear;
|
||||
}
|
||||
.leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
|
||||
opacity: 1;
|
||||
}
|
||||
.leaflet-zoom-animated {
|
||||
-webkit-transform-origin: 0 0;
|
||||
-ms-transform-origin: 0 0;
|
||||
transform-origin: 0 0;
|
||||
}
|
||||
svg.leaflet-zoom-animated {
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
.leaflet-zoom-anim .leaflet-zoom-animated {
|
||||
-webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1);
|
||||
-moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1);
|
||||
transition: transform 0.25s cubic-bezier(0,0,0.25,1);
|
||||
}
|
||||
.leaflet-zoom-anim .leaflet-tile,
|
||||
.leaflet-pan-anim .leaflet-tile {
|
||||
-webkit-transition: none;
|
||||
-moz-transition: none;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.leaflet-zoom-anim .leaflet-zoom-hide {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
|
||||
/* cursors */
|
||||
|
||||
.leaflet-interactive {
|
||||
cursor: pointer;
|
||||
}
|
||||
.leaflet-grab {
|
||||
cursor: -webkit-grab;
|
||||
cursor: -moz-grab;
|
||||
cursor: grab;
|
||||
}
|
||||
.leaflet-crosshair,
|
||||
.leaflet-crosshair .leaflet-interactive {
|
||||
cursor: crosshair;
|
||||
}
|
||||
.leaflet-popup-pane,
|
||||
.leaflet-control {
|
||||
cursor: auto;
|
||||
}
|
||||
.leaflet-dragging .leaflet-grab,
|
||||
.leaflet-dragging .leaflet-grab .leaflet-interactive,
|
||||
.leaflet-dragging .leaflet-marker-draggable {
|
||||
cursor: move;
|
||||
cursor: -webkit-grabbing;
|
||||
cursor: -moz-grabbing;
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
/* marker & overlays interactivity */
|
||||
.leaflet-marker-icon,
|
||||
.leaflet-marker-shadow,
|
||||
.leaflet-image-layer,
|
||||
.leaflet-pane > svg path,
|
||||
.leaflet-tile-container {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.leaflet-marker-icon.leaflet-interactive,
|
||||
.leaflet-image-layer.leaflet-interactive,
|
||||
.leaflet-pane > svg path.leaflet-interactive,
|
||||
svg.leaflet-image-layer.leaflet-interactive path {
|
||||
pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
/* visual tweaks */
|
||||
|
||||
.leaflet-container {
|
||||
background: #ddd;
|
||||
outline-offset: 1px;
|
||||
}
|
||||
.leaflet-container a {
|
||||
color: #0078A8;
|
||||
}
|
||||
.leaflet-zoom-box {
|
||||
border: 2px dotted #38f;
|
||||
background: rgba(255,255,255,0.5);
|
||||
}
|
||||
|
||||
|
||||
/* general typography */
|
||||
.leaflet-container {
|
||||
font-family: "Helvetica Neue", Arial, Helvetica, sans-serif;
|
||||
font-size: 12px;
|
||||
font-size: 0.75rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
|
||||
/* general toolbar styles */
|
||||
|
||||
.leaflet-bar {
|
||||
box-shadow: 0 1px 5px rgba(0,0,0,0.65);
|
||||
border-radius: 4px;
|
||||
}
|
||||
.leaflet-bar a {
|
||||
background-color: #fff;
|
||||
border-bottom: 1px solid #ccc;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
line-height: 26px;
|
||||
display: block;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
color: black;
|
||||
}
|
||||
.leaflet-bar a,
|
||||
.leaflet-control-layers-toggle {
|
||||
background-position: 50% 50%;
|
||||
background-repeat: no-repeat;
|
||||
display: block;
|
||||
}
|
||||
.leaflet-bar a:hover,
|
||||
.leaflet-bar a:focus {
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
.leaflet-bar a:first-child {
|
||||
border-top-left-radius: 4px;
|
||||
border-top-right-radius: 4px;
|
||||
}
|
||||
.leaflet-bar a:last-child {
|
||||
border-bottom-left-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
border-bottom: none;
|
||||
}
|
||||
.leaflet-bar a.leaflet-disabled {
|
||||
cursor: default;
|
||||
background-color: #f4f4f4;
|
||||
color: #bbb;
|
||||
}
|
||||
|
||||
.leaflet-touch .leaflet-bar a {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
}
|
||||
.leaflet-touch .leaflet-bar a:first-child {
|
||||
border-top-left-radius: 2px;
|
||||
border-top-right-radius: 2px;
|
||||
}
|
||||
.leaflet-touch .leaflet-bar a:last-child {
|
||||
border-bottom-left-radius: 2px;
|
||||
border-bottom-right-radius: 2px;
|
||||
}
|
||||
|
||||
/* zoom control */
|
||||
|
||||
.leaflet-control-zoom-in,
|
||||
.leaflet-control-zoom-out {
|
||||
font: bold 18px 'Lucida Console', Monaco, monospace;
|
||||
text-indent: 1px;
|
||||
}
|
||||
|
||||
.leaflet-touch .leaflet-control-zoom-in, .leaflet-touch .leaflet-control-zoom-out {
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
|
||||
/* layers control */
|
||||
|
||||
.leaflet-control-layers {
|
||||
box-shadow: 0 1px 5px rgba(0,0,0,0.4);
|
||||
background: #fff;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.leaflet-control-layers-toggle {
|
||||
background-image: url(images/layers.png);
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
}
|
||||
.leaflet-retina .leaflet-control-layers-toggle {
|
||||
background-image: url(images/layers-2x.png);
|
||||
background-size: 26px 26px;
|
||||
}
|
||||
.leaflet-touch .leaflet-control-layers-toggle {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
}
|
||||
.leaflet-control-layers .leaflet-control-layers-list,
|
||||
.leaflet-control-layers-expanded .leaflet-control-layers-toggle {
|
||||
display: none;
|
||||
}
|
||||
.leaflet-control-layers-expanded .leaflet-control-layers-list {
|
||||
display: block;
|
||||
position: relative;
|
||||
}
|
||||
.leaflet-control-layers-expanded {
|
||||
padding: 6px 10px 6px 6px;
|
||||
color: #333;
|
||||
background: #fff;
|
||||
}
|
||||
.leaflet-control-layers-scrollbar {
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
padding-right: 5px;
|
||||
}
|
||||
.leaflet-control-layers-selector {
|
||||
margin-top: 2px;
|
||||
position: relative;
|
||||
top: 1px;
|
||||
}
|
||||
.leaflet-control-layers label {
|
||||
display: block;
|
||||
font-size: 13px;
|
||||
font-size: 1.08333em;
|
||||
}
|
||||
.leaflet-control-layers-separator {
|
||||
height: 0;
|
||||
border-top: 1px solid #ddd;
|
||||
margin: 5px -10px 5px -6px;
|
||||
}
|
||||
|
||||
/* Default icon URLs */
|
||||
.leaflet-default-icon-path { /* used only in path-guessing heuristic, see L.Icon.Default */
|
||||
background-image: url(images/marker-icon.png);
|
||||
}
|
||||
|
||||
|
||||
/* attribution and scale controls */
|
||||
|
||||
.leaflet-container .leaflet-control-attribution {
|
||||
background: #fff;
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
margin: 0;
|
||||
}
|
||||
.leaflet-control-attribution,
|
||||
.leaflet-control-scale-line {
|
||||
padding: 0 5px;
|
||||
color: #333;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.leaflet-control-attribution a {
|
||||
text-decoration: none;
|
||||
}
|
||||
.leaflet-control-attribution a:hover,
|
||||
.leaflet-control-attribution a:focus {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.leaflet-attribution-flag {
|
||||
display: inline !important;
|
||||
vertical-align: baseline !important;
|
||||
width: 1em;
|
||||
height: 0.6669em;
|
||||
}
|
||||
.leaflet-left .leaflet-control-scale {
|
||||
margin-left: 5px;
|
||||
}
|
||||
.leaflet-bottom .leaflet-control-scale {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.leaflet-control-scale-line {
|
||||
border: 2px solid #777;
|
||||
border-top: none;
|
||||
line-height: 1.1;
|
||||
padding: 2px 5px 1px;
|
||||
white-space: nowrap;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
text-shadow: 1px 1px #fff;
|
||||
}
|
||||
.leaflet-control-scale-line:not(:first-child) {
|
||||
border-top: 2px solid #777;
|
||||
border-bottom: none;
|
||||
margin-top: -2px;
|
||||
}
|
||||
.leaflet-control-scale-line:not(:first-child):not(:last-child) {
|
||||
border-bottom: 2px solid #777;
|
||||
}
|
||||
|
||||
.leaflet-touch .leaflet-control-attribution,
|
||||
.leaflet-touch .leaflet-control-layers,
|
||||
.leaflet-touch .leaflet-bar {
|
||||
box-shadow: none;
|
||||
}
|
||||
.leaflet-touch .leaflet-control-layers,
|
||||
.leaflet-touch .leaflet-bar {
|
||||
border: 2px solid rgba(0,0,0,0.2);
|
||||
background-clip: padding-box;
|
||||
}
|
||||
|
||||
|
||||
/* popup */
|
||||
|
||||
.leaflet-popup {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.leaflet-popup-content-wrapper {
|
||||
padding: 1px;
|
||||
text-align: left;
|
||||
border-radius: 12px;
|
||||
}
|
||||
.leaflet-popup-content {
|
||||
margin: 13px 24px 13px 20px;
|
||||
line-height: 1.3;
|
||||
font-size: 13px;
|
||||
font-size: 1.08333em;
|
||||
min-height: 1px;
|
||||
}
|
||||
.leaflet-popup-content p {
|
||||
margin: 17px 0;
|
||||
margin: 1.3em 0;
|
||||
}
|
||||
.leaflet-popup-tip-container {
|
||||
width: 40px;
|
||||
height: 20px;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
margin-top: -1px;
|
||||
margin-left: -20px;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
}
|
||||
.leaflet-popup-tip {
|
||||
width: 17px;
|
||||
height: 17px;
|
||||
padding: 1px;
|
||||
|
||||
margin: -10px auto 0;
|
||||
pointer-events: auto;
|
||||
|
||||
-webkit-transform: rotate(45deg);
|
||||
-moz-transform: rotate(45deg);
|
||||
-ms-transform: rotate(45deg);
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
.leaflet-popup-content-wrapper,
|
||||
.leaflet-popup-tip {
|
||||
background: white;
|
||||
color: #333;
|
||||
box-shadow: 0 3px 14px rgba(0,0,0,0.4);
|
||||
}
|
||||
.leaflet-container a.leaflet-popup-close-button {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
border: none;
|
||||
text-align: center;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
font: 16px/24px Tahoma, Verdana, sans-serif;
|
||||
color: #757575;
|
||||
text-decoration: none;
|
||||
background: transparent;
|
||||
}
|
||||
.leaflet-container a.leaflet-popup-close-button:hover,
|
||||
.leaflet-container a.leaflet-popup-close-button:focus {
|
||||
color: #585858;
|
||||
}
|
||||
.leaflet-popup-scrolled {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.leaflet-oldie .leaflet-popup-content-wrapper {
|
||||
-ms-zoom: 1;
|
||||
}
|
||||
.leaflet-oldie .leaflet-popup-tip {
|
||||
width: 24px;
|
||||
margin: 0 auto;
|
||||
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
|
||||
filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);
|
||||
}
|
||||
|
||||
.leaflet-oldie .leaflet-control-zoom,
|
||||
.leaflet-oldie .leaflet-control-layers,
|
||||
.leaflet-oldie .leaflet-popup-content-wrapper,
|
||||
.leaflet-oldie .leaflet-popup-tip {
|
||||
border: 1px solid #999;
|
||||
}
|
||||
|
||||
|
||||
/* div icon */
|
||||
|
||||
.leaflet-div-icon {
|
||||
background: #fff;
|
||||
border: 1px solid #666;
|
||||
}
|
||||
|
||||
|
||||
/* Tooltip */
|
||||
/* Base styles for the element that has a tooltip */
|
||||
.leaflet-tooltip {
|
||||
position: absolute;
|
||||
padding: 6px;
|
||||
background-color: #fff;
|
||||
border: 1px solid #fff;
|
||||
border-radius: 3px;
|
||||
color: #222;
|
||||
white-space: nowrap;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
pointer-events: none;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.4);
|
||||
}
|
||||
.leaflet-tooltip.leaflet-interactive {
|
||||
cursor: pointer;
|
||||
pointer-events: auto;
|
||||
}
|
||||
.leaflet-tooltip-top:before,
|
||||
.leaflet-tooltip-bottom:before,
|
||||
.leaflet-tooltip-left:before,
|
||||
.leaflet-tooltip-right:before {
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
border: 6px solid transparent;
|
||||
background: transparent;
|
||||
content: "";
|
||||
}
|
||||
|
||||
/* Directions */
|
||||
|
||||
.leaflet-tooltip-bottom {
|
||||
margin-top: 6px;
|
||||
}
|
||||
.leaflet-tooltip-top {
|
||||
margin-top: -6px;
|
||||
}
|
||||
.leaflet-tooltip-bottom:before,
|
||||
.leaflet-tooltip-top:before {
|
||||
left: 50%;
|
||||
margin-left: -6px;
|
||||
}
|
||||
.leaflet-tooltip-top:before {
|
||||
bottom: 0;
|
||||
margin-bottom: -12px;
|
||||
border-top-color: #fff;
|
||||
}
|
||||
.leaflet-tooltip-bottom:before {
|
||||
top: 0;
|
||||
margin-top: -12px;
|
||||
margin-left: -6px;
|
||||
border-bottom-color: #fff;
|
||||
}
|
||||
.leaflet-tooltip-left {
|
||||
margin-left: -6px;
|
||||
}
|
||||
.leaflet-tooltip-right {
|
||||
margin-left: 6px;
|
||||
}
|
||||
.leaflet-tooltip-left:before,
|
||||
.leaflet-tooltip-right:before {
|
||||
top: 50%;
|
||||
margin-top: -6px;
|
||||
}
|
||||
.leaflet-tooltip-left:before {
|
||||
right: 0;
|
||||
margin-right: -12px;
|
||||
border-left-color: #fff;
|
||||
}
|
||||
.leaflet-tooltip-right:before {
|
||||
left: 0;
|
||||
margin-left: -12px;
|
||||
border-right-color: #fff;
|
||||
}
|
||||
|
||||
/* Printing */
|
||||
|
||||
@media print {
|
||||
/* Prevent printers from removing background-images of controls. */
|
||||
.leaflet-control {
|
||||
-webkit-print-color-adjust: exact;
|
||||
print-color-adjust: exact;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
.leaflet-control-fullscreen a {
|
||||
background:#fff url(fullscreen.png) no-repeat 0 0;
|
||||
background-size:26px 52px;
|
||||
}
|
||||
.leaflet-touch .leaflet-control-fullscreen a {
|
||||
background-position: 2px 2px;
|
||||
}
|
||||
.leaflet-fullscreen-on .leaflet-control-fullscreen a {
|
||||
background-position:0 -26px;
|
||||
}
|
||||
.leaflet-touch.leaflet-fullscreen-on .leaflet-control-fullscreen a {
|
||||
background-position: 2px -24px;
|
||||
}
|
||||
|
||||
/* Do not combine these two rules; IE will break. */
|
||||
.leaflet-container:-webkit-full-screen {
|
||||
width:100%!important;
|
||||
height:100%!important;
|
||||
}
|
||||
.leaflet-container.leaflet-fullscreen-on {
|
||||
width:100%!important;
|
||||
height:100%!important;
|
||||
}
|
||||
|
||||
.leaflet-pseudo-fullscreen {
|
||||
position:fixed!important;
|
||||
width:100%!important;
|
||||
height:100%!important;
|
||||
top:0!important;
|
||||
left:0!important;
|
||||
z-index:99999;
|
||||
}
|
||||
|
||||
@media
|
||||
(-webkit-min-device-pixel-ratio:2),
|
||||
(min-resolution:192dpi) {
|
||||
.leaflet-control-fullscreen a {
|
||||
background-image:url(fullscreen@2x.png);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
var map, marker, streetLayer, satelliteLayer, labelsLayer, hybridLayer;
|
||||
|
||||
function initMap() {
|
||||
// console.log("🚀 initMap() dipanggil");
|
||||
|
||||
var latitudeInput = document.getElementById('latitude').value;
|
||||
var longitudeInput = document.getElementById('longitude').value;
|
||||
|
||||
// console.log("📍 Input awal:", latitudeInput, longitudeInput);
|
||||
|
||||
// Kalau input sudah ada → pakai itu
|
||||
if (latitudeInput && longitudeInput) {
|
||||
var pos = {
|
||||
lat: parseFloat(latitudeInput),
|
||||
lng: parseFloat(longitudeInput)
|
||||
};
|
||||
// console.log("✅ Pakai input manual:", pos);
|
||||
initMapWithPos(pos);
|
||||
} else {
|
||||
// Kalau kosong → coba geolocation
|
||||
if (navigator.geolocation) {
|
||||
// console.log("📡 Mencoba geolocation...");
|
||||
navigator.geolocation.getCurrentPosition(function(position) {
|
||||
var pos = {
|
||||
lat: position.coords.latitude,
|
||||
lng: position.coords.longitude
|
||||
};
|
||||
// console.log("✅ Geolocation berhasil:", pos);
|
||||
initMapWithPos(pos);
|
||||
updateFormInputs(pos.lat, pos.lng);
|
||||
}, function() {
|
||||
console.warn("⚠️ Geolocation gagal, fallback ke Jakarta");
|
||||
handleLocationError(true);
|
||||
initMapWithPos({ lat: -6.2, lng: 106.816666 });
|
||||
});
|
||||
} else {
|
||||
console.warn("⚠️ Browser tidak support geolocation, fallback ke Jakarta");
|
||||
handleLocationError(false);
|
||||
initMapWithPos({ lat: -6.2, lng: 106.816666 });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function initMapWithPos(pos) {
|
||||
// console.log("🗺️ initMapWithPos() dengan posisi:", pos);
|
||||
|
||||
// Base layers
|
||||
streetLayer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||
{ attribution: '© OpenStreetMap contributors' });
|
||||
|
||||
satelliteLayer = L.tileLayer(
|
||||
'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
|
||||
{ attribution: 'Tiles © Esri' });
|
||||
|
||||
labelsLayer = L.tileLayer(
|
||||
'https://server.arcgisonline.com/ArcGIS/rest/services/Reference/World_Transportation/MapServer/tile/{z}/{y}/{x}',
|
||||
{ attribution: 'Labels © Esri' });
|
||||
|
||||
// Gabungkan satelit + jalan → Hybrid
|
||||
hybridLayer = L.layerGroup([satelliteLayer, labelsLayer]);
|
||||
|
||||
// Init map
|
||||
map = L.map('map', {
|
||||
center: [pos.lat, pos.lng],
|
||||
zoom: 17,
|
||||
layers: [hybridLayer],
|
||||
fullscreenControl: true,
|
||||
fullscreenControlOptions: { position: 'topleft' }
|
||||
});
|
||||
// console.log("✅ Map berhasil dibuat");
|
||||
|
||||
// Layer switcher
|
||||
var baseLayers = {
|
||||
"Jalan (OSM)": streetLayer,
|
||||
"Hybrid (Satelit + Jalan)": hybridLayer
|
||||
};
|
||||
L.control.layers(baseLayers).addTo(map);
|
||||
|
||||
// Marker awal
|
||||
updateMarker(pos.lat, pos.lng);
|
||||
|
||||
// Klik peta → pindah marker
|
||||
map.on('click', function(e) {
|
||||
var latitude = e.latlng.lat.toFixed(6);
|
||||
var longitude = e.latlng.lng.toFixed(6);
|
||||
// console.log("🖱️ Klik map:", latitude, longitude);
|
||||
updateMarker(latitude, longitude);
|
||||
updateFormInputs(latitude, longitude);
|
||||
});
|
||||
|
||||
// Tombol "Lokasi Saya"
|
||||
L.control.locateMe = function(opts) {
|
||||
var control = L.control({position: 'topleft'});
|
||||
control.onAdd = function(map) {
|
||||
var btn = L.DomUtil.create('button', 'leaflet-bar leaflet-control');
|
||||
btn.setAttribute("type", "button");
|
||||
btn.innerHTML = '📍';
|
||||
btn.title = "Lokasi Saya";
|
||||
btn.style.backgroundColor = 'white';
|
||||
btn.style.width = '34px';
|
||||
btn.style.height = '34px';
|
||||
|
||||
btn.onclick = function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
// console.log("📍 Tombol Lokasi Saya diklik");
|
||||
if (navigator.geolocation) {
|
||||
navigator.geolocation.getCurrentPosition(function(position) {
|
||||
var lat = position.coords.latitude;
|
||||
var lng = position.coords.longitude;
|
||||
// console.log("✅ Lokasi saya:", lat, lng);
|
||||
updateMarker(lat, lng);
|
||||
updateFormInputs(lat, lng);
|
||||
map.setView([lat, lng], 17);
|
||||
}, function() {
|
||||
console.error("❌ Tidak bisa ambil lokasi saya");
|
||||
alert("Tidak bisa mengambil lokasi Anda");
|
||||
}, { enableHighAccuracy: true });
|
||||
} else {
|
||||
console.error("❌ Browser tidak support geolocation");
|
||||
alert("Geolocation tidak didukung di browser ini");
|
||||
}
|
||||
};
|
||||
return btn;
|
||||
};
|
||||
return control;
|
||||
};
|
||||
L.control.locateMe().addTo(map);
|
||||
}
|
||||
|
||||
function updateMarker(latitude, longitude) {
|
||||
// console.log("📍 updateMarker ke:", latitude, longitude);
|
||||
if (marker) {
|
||||
marker.setLatLng([latitude, longitude])
|
||||
.bindPopup("Lokasi terpilih")
|
||||
.openPopup();
|
||||
} else {
|
||||
marker = L.marker([latitude, longitude]).addTo(map)
|
||||
.bindPopup("Lokasi terpilih")
|
||||
.openPopup();
|
||||
}
|
||||
map.setView([latitude, longitude]);
|
||||
}
|
||||
|
||||
function updateFormInputs(latitude, longitude) {
|
||||
// console.log("📝 updateFormInputs:", latitude, longitude);
|
||||
document.getElementById('latitude').value = latitude;
|
||||
document.getElementById('longitude').value = longitude;
|
||||
document.getElementById('latlong').value = `${latitude}, ${longitude}`;
|
||||
}
|
||||
|
||||
function handleLocationError(browserHasGeolocation) {
|
||||
console.error(browserHasGeolocation ?
|
||||
'❌ Error: Geolocation service failed.' :
|
||||
'❌ Error: Browser tidak support geolocation.');
|
||||
}
|
||||
|
||||
// Sinkronisasi input form ⇄ peta
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// console.log("📦 DOMContentLoaded");
|
||||
initMap();
|
||||
const latlongInput = document.getElementById('latlong');
|
||||
const latitudeInput = document.querySelector('input[data-maps="latitude"]') || document.getElementById('latitude');
|
||||
const longitudeInput = document.querySelector('input[data-maps="longitude"]') || document.getElementById('longitude');
|
||||
|
||||
// Set nilai latlong awal kalau ada
|
||||
if (latitudeInput.value && longitudeInput.value) {
|
||||
latlongInput.value = `${latitudeInput.value}, ${longitudeInput.value}`;
|
||||
// console.log("🔄 Sinkron awal dari input:", latlongInput.value);
|
||||
}
|
||||
|
||||
// Input manual latlong
|
||||
latlongInput.addEventListener('input', function() {
|
||||
// console.log("⌨️ Input manual latlong:", latlongInput.value);
|
||||
const latlongValue = latlongInput.value.split(',');
|
||||
|
||||
const latLongRegex = /^(-?\d+(\.\d+)?),\s*(-?\d+(\.\d+)?)$/;
|
||||
if (latLongRegex.test(latlongInput.value.trim())) {
|
||||
if (latlongValue.length === 2) {
|
||||
const lat = parseFloat(latlongValue[0].trim());
|
||||
const long = parseFloat(latlongValue[1].trim());
|
||||
// console.log("✅ Format valid → update map:", lat, long);
|
||||
latitudeInput.value = lat;
|
||||
longitudeInput.value = long;
|
||||
updateMarker(lat, long);
|
||||
map.setView([lat, long], 17);
|
||||
}
|
||||
} else {
|
||||
console.warn("⚠️ Format salah, reset input");
|
||||
setTimeout(function() {
|
||||
latlongInput.value = '';
|
||||
latlongInput.placeholder = 'Isi dengan format yang sesuai';
|
||||
latitudeInput.value = '';
|
||||
longitudeInput.value = '';
|
||||
}, 500);
|
||||
}
|
||||
});
|
||||
|
||||
// Sinkronisasi ketika latitude / longitude berubah
|
||||
latitudeInput.addEventListener('input', function() {
|
||||
// console.log("🔄 Latitude diubah:", latitudeInput.value);
|
||||
latlongInput.value = `${latitudeInput.value}, ${longitudeInput.value}`;
|
||||
});
|
||||
longitudeInput.addEventListener('input', function() {
|
||||
// console.log("🔄 Longitude diubah:", longitudeInput.value);
|
||||
latlongInput.value = `${latitudeInput.value}, ${longitudeInput.value}`;
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,99 @@
|
||||
let map;
|
||||
const markers = [];
|
||||
let streetLayer, satelliteLayer, labelsLayer, hybridLayer;
|
||||
|
||||
function initMap(center) {
|
||||
// Base layers
|
||||
streetLayer = L.tileLayer(
|
||||
'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||
{ attribution: '© OpenStreetMap contributors' }
|
||||
);
|
||||
|
||||
satelliteLayer = L.tileLayer(
|
||||
'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
|
||||
{ attribution: 'Tiles © Esri' }
|
||||
);
|
||||
|
||||
labelsLayer = L.tileLayer(
|
||||
'https://server.arcgisonline.com/ArcGIS/rest/services/Reference/World_Transportation/MapServer/tile/{z}/{y}/{x}',
|
||||
{ attribution: 'Labels © Esri' }
|
||||
);
|
||||
|
||||
hybridLayer = L.layerGroup([satelliteLayer, labelsLayer]);
|
||||
|
||||
// Init map dengan posisi dari API
|
||||
map = L.map('map', {
|
||||
center: [center.lat, center.lng],
|
||||
zoom: 12,
|
||||
layers: [hybridLayer],
|
||||
fullscreenControl: true,
|
||||
fullscreenControlOptions: { position: 'topleft' }
|
||||
});
|
||||
|
||||
// Control layer
|
||||
L.control.layers({
|
||||
"Jalan (OSM)": streetLayer,
|
||||
"Hybrid (Satelit + Jalan)": hybridLayer
|
||||
}).addTo(map);
|
||||
|
||||
// Ambil marker pertama kali
|
||||
fetchMarkers();
|
||||
// Refresh marker tiap 30 detik
|
||||
setInterval(fetchMarkers, 30000);
|
||||
}
|
||||
|
||||
function fetchMarkers() {
|
||||
fetch(`load/maps_marker.php?i=${topologiId}`)
|
||||
.then(response => {
|
||||
if (!response.ok) throw new Error('Network response was not ok ' + response.statusText);
|
||||
return response.json();
|
||||
})
|
||||
.then(res => {
|
||||
if (!res.status) {
|
||||
console.warn("⚠️ Tidak ada data marker");
|
||||
return;
|
||||
}
|
||||
|
||||
// Hapus marker lama
|
||||
markers.forEach(marker => map.removeLayer(marker));
|
||||
markers.length = 0;
|
||||
|
||||
// Tambahkan marker baru
|
||||
res.data.forEach(markerData => {
|
||||
const iconCustom = L.icon({
|
||||
iconUrl: markerData.icon,
|
||||
iconSize: [30, 30]
|
||||
});
|
||||
|
||||
const markerInstance = L.marker(
|
||||
[markerData.lat, markerData.lng],
|
||||
{ icon: iconCustom, title: markerData.title }
|
||||
).addTo(map);
|
||||
|
||||
markerInstance.bindPopup(markerData.content);
|
||||
markers.push(markerInstance);
|
||||
});
|
||||
|
||||
console.log(`✅ Marker berhasil ditampilkan: ${markers.length}`);
|
||||
})
|
||||
.catch(error => console.error('❌ Error fetching markers:', error));
|
||||
}
|
||||
|
||||
// Ambil dulu center dari API sebelum init map
|
||||
window.onload = function() {
|
||||
fetch(`load/maps_marker.php?i=${topologiId}`)
|
||||
.then(res => res.json())
|
||||
.then(res => {
|
||||
if (res.status && res.centerlonglat) {
|
||||
console.log("📍 Init map pakai centerlonglat:", res.centerlonglat);
|
||||
initMap(res.centerlonglat);
|
||||
} else {
|
||||
console.warn("⚠️ Centerlonglat tidak ada, pakai fallback Jakarta");
|
||||
initMap({ lat: -6.2, lng: 106.816666 });
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error("❌ Gagal ambil data awal:", err);
|
||||
initMap({ lat: -6.2, lng: 106.816666 }); // fallback
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,133 @@
|
||||
<?php
|
||||
require '../vendor/autoload.php'; // Pastikan path ini sesuai dengan autoload.php Anda
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
|
||||
use PhpOffice\PhpSpreadsheet\Cell\DataType;
|
||||
|
||||
// Koneksi ke database
|
||||
require __DIR__ . '/../config/connect.php';
|
||||
require __DIR__ . '/../config/encrypt.php';
|
||||
|
||||
// Dekripsi parameter data
|
||||
$datadecrypt = decrypt_url($_GET['data'] ?? '');
|
||||
$dataurl = json_decode($datadecrypt, true);
|
||||
|
||||
$SqlSvData = $dataurl[0] ?? '';
|
||||
|
||||
// Kondisi awal
|
||||
$where = "WHERE {$SqlSvData} status = 'aktif'";
|
||||
|
||||
// Query dasar
|
||||
$query = "
|
||||
SELECT nama, nik, akun, user_hotspot, alamat, latitude, longitude, nomor_whatsapp, email,
|
||||
nama_server, nama_mikrotik, nama_paket, status_koneksi, ip_address, time_update, time_start
|
||||
FROM v_pelanggan
|
||||
{$where}
|
||||
";
|
||||
|
||||
|
||||
$dataparam = json_decode($_POST['datatable_params'], true);
|
||||
// Tambahkan kondisi pencarian
|
||||
$search = $dataparam['search']['value'] ?? '';
|
||||
if (!empty($search)) {
|
||||
$where .= " AND (
|
||||
nama LIKE :search OR
|
||||
nik LIKE :search OR
|
||||
akun LIKE :search OR
|
||||
status_koneksi LIKE :search OR
|
||||
nomor_whatsapp LIKE :search OR
|
||||
nama_paket LIKE :search OR
|
||||
nama_server LIKE :search OR
|
||||
alamat LIKE :search OR
|
||||
time_start LIKE :search
|
||||
)";
|
||||
|
||||
$query = "
|
||||
SELECT nama, nik, akun, user_hotspot, alamat, latitude, longitude, nomor_whatsapp, email,
|
||||
nama_server, nama_mikrotik, nama_paket, status_koneksi, ip_address, time_update, time_start
|
||||
FROM v_pelanggan
|
||||
{$where}
|
||||
";
|
||||
}
|
||||
|
||||
// Siapkan statement
|
||||
$stmt = $pdo->prepare($query);
|
||||
|
||||
// Bind parameter pencarian
|
||||
if (!empty($search)) {
|
||||
$stmt->bindValue(':search', "%{$search}%", PDO::PARAM_STR);
|
||||
}
|
||||
|
||||
$stmt->execute();
|
||||
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// Buat Spreadsheet
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
|
||||
// Set header kolom
|
||||
$sheet->setCellValue('A1', 'No')
|
||||
->setCellValue('B1', 'Nama')
|
||||
->setCellValue('C1', 'NIK')
|
||||
->setCellValue('D1', 'ID Pelanggan')
|
||||
->setCellValue('E1', 'Akun Hotspot')
|
||||
->setCellValue('F1', 'Alamat')
|
||||
->setCellValue('G1', 'Latitude')
|
||||
->setCellValue('H1', 'Longitude')
|
||||
->setCellValue('I1', 'Nomor Whatsapp')
|
||||
->setCellValue('J1', 'Email')
|
||||
->setCellValue('K1', 'Mulai Berlangganan')
|
||||
->setCellValue('L1', 'Server')
|
||||
->setCellValue('M1', 'Mikrotik')
|
||||
->setCellValue('N1', 'Paket Berlangganan')
|
||||
->setCellValue('O1', 'Status Koneksi')
|
||||
->setCellValue('P1', 'IP Address')
|
||||
->setCellValue('Q1', 'Last Update')
|
||||
->setCellValue('R1', 'RX Power ONU')
|
||||
->setCellValue('S1', 'TX Power ONU');
|
||||
|
||||
// Isi data
|
||||
$row = 2;
|
||||
$no = 1;
|
||||
foreach ($data as $item) {
|
||||
// Kolom No otomatis
|
||||
$sheet->setCellValue('A' . $row, $no);
|
||||
|
||||
// Kolom text sensitif (pakai Explicit supaya tidak error di Excel)
|
||||
$sheet->setCellValueExplicit('B' . $row, $item['nama'] ?? '', DataType::TYPE_STRING);
|
||||
$sheet->setCellValueExplicit('C' . $row, $item['nik'] ?? '', DataType::TYPE_STRING);
|
||||
$sheet->setCellValueExplicit('D' . $row, $item['akun'] ?? '', DataType::TYPE_STRING);
|
||||
$sheet->setCellValueExplicit('E' . $row, $item['user_hotspot'] ?? '', DataType::TYPE_STRING);
|
||||
$sheet->setCellValueExplicit('F' . $row, $item['alamat'] ?? '', DataType::TYPE_STRING);
|
||||
$sheet->setCellValueExplicit('G' . $row, $item['latitude'] ?? '', DataType::TYPE_STRING);
|
||||
$sheet->setCellValueExplicit('H' . $row, $item['longitude'] ?? '', DataType::TYPE_STRING);
|
||||
$sheet->setCellValueExplicit('I' . $row, $item['nomor_whatsapp'] ?? '', DataType::TYPE_STRING);
|
||||
$sheet->setCellValueExplicit('J' . $row, $item['email'] ?? '', DataType::TYPE_STRING);
|
||||
|
||||
// Kolom tanggal & teks biasa
|
||||
$sheet->setCellValue('K' . $row, $item['time_start'] ?? '');
|
||||
$sheet->setCellValue('L' . $row, $item['nama_server'] ?? '');
|
||||
$sheet->setCellValue('M' . $row, $item['nama_mikrotik'] ?? '');
|
||||
$sheet->setCellValue('N' . $row, $item['nama_paket'] ?? '');
|
||||
$sheet->setCellValue('O' . $row, $item['status_koneksi'] ?? '');
|
||||
$sheet->setCellValue('P' . $row, $item['ip_address'] ?? '');
|
||||
$sheet->setCellValue('Q' . $row, $item['time_update'] ?? '');
|
||||
|
||||
// RX & TX Power dummy
|
||||
$sheet->setCellValue('R' . $row, 'inf');
|
||||
$sheet->setCellValue('S' . $row, 'inf');
|
||||
|
||||
$row++;
|
||||
$no++;
|
||||
}
|
||||
|
||||
// Set header download
|
||||
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
|
||||
header('Content-Disposition: attachment;filename="data_export_pelanggan_aktif.xlsx"');
|
||||
header('Cache-Control: max-age=0');
|
||||
|
||||
// Output file
|
||||
$writer = new Xlsx($spreadsheet);
|
||||
$writer->save('php://output');
|
||||
exit;
|
||||
@@ -115,9 +115,15 @@
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<?php if($jenisAgen == 'Prabayar') { ?>
|
||||
<?php if($jenisAgen == 'Prabayar') {
|
||||
if ($payGateway['payment_gateway'] == 'paydisini' && $payGateway['status_payment_gateway'] == 'ACTIVE') {
|
||||
$pageSaldo = 'isi_saldo_paydisini';
|
||||
} else {
|
||||
$pageSaldo = 'isi_saldo';
|
||||
}
|
||||
?>
|
||||
<div class="col-4 p-2">
|
||||
<a href="?<?php echo base64_encode('isi_saldo'); ?>">
|
||||
<a href="?<?php echo base64_encode($pageSaldo); ?>">
|
||||
<div class="card text-dark animated-link" style="border-radius: 15px;">
|
||||
<center>
|
||||
<img src="images/wallet.png" width="50px" class="mt-3 mb-2">
|
||||
|
||||
@@ -0,0 +1,199 @@
|
||||
<?php
|
||||
// require __DIR__ . "/../payment/paydisini/api_control.php";
|
||||
// require __DIR__ . "/../payment/client/intruksi_pay.php";
|
||||
require __DIR__ . "/payment/paydisini/proses.php";
|
||||
|
||||
$stmt = $pdo->prepare("SELECT * FROM agen_tambah_saldo WHERE id_agen_voucher = :id_agen_voucher AND status_payment != 'SUCCESS' ORDER BY id DESC LIMIT 1");
|
||||
$stmt->bindParam(':id_agen_voucher', $_SESSION['agen'], PDO::PARAM_INT);
|
||||
$stmt->execute();
|
||||
$dataGet = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
?>
|
||||
|
||||
<nav class="navbar fixed-top">
|
||||
<div id="specificCard" class="card col-12" style="border-radius: 20px; background: none; border: none; margin-top: 10px;">
|
||||
<div class="row">
|
||||
<div class="col-6 icon-container">
|
||||
<a href="index.php" class="fa fa-arrow-left text-light"></a>
|
||||
</div>
|
||||
<div class="col-6 text-right">
|
||||
<h6 class="text-light mt-2 mb-2">Isi Saldo</h6>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="card" style="border-radius: 0px; background: none; border: none; margin-top: 70px; margin-bottom: 20px;">
|
||||
<div class="card-body">
|
||||
<?php if($jenisAgen == 'Prabayar') { ?>
|
||||
<div style="text-align: center; color: #fff;">
|
||||
<p>Saldo Anda</p>
|
||||
|
||||
<div style="display: inline-flex; align-items: center; justify-content: center;">
|
||||
<h1 style="font-size: 36px; color: #fff; margin: 0;">
|
||||
<small>Rp. </small>
|
||||
<b id="saldoValue"><?php echo number_format($pcmem['saldo']); ?></b>
|
||||
</h1>
|
||||
<a onclick="toggleSaldo()" style="background: none; border: none; margin-left: 10px; cursor: pointer;">
|
||||
<i id="iconEye" class="fa fa-eye text-light" style="font-size: 24px;"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<?php } else { ?>
|
||||
<center>
|
||||
<p style="color: #fff;">Total Transaksi Belum Di Bayar</p>
|
||||
<h1 style="font-size: 36px; color: #fff;"><small>Rp. </small><b><?php echo substr(number_format($pcmem['saldo']),1); ?></b></h1>
|
||||
</center>
|
||||
<?php } ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card" id="2" style="border-top-right-radius: 40px; border-top-left-radius: 40px; min-height: 850px; border: none; z-index: 1;">
|
||||
<div class="card-body" style="margin: 20px;">
|
||||
<?php if(!empty($dataGet['nominal'])) { ?>
|
||||
<div class="text-center">
|
||||
<h4><?= "Rp. ". number_format($dataGet['nominal']); ?></h4>
|
||||
<hr>
|
||||
</div>
|
||||
<div class="payment-card">
|
||||
<?php
|
||||
|
||||
echo getListPembayaran($pelanggan['id']);
|
||||
// if ($pelanggan['status'] == 'SUCCESS') {
|
||||
// echo getStatus($pelanggan);
|
||||
// }
|
||||
// elseif ($pelanggan['status'] == 'PENDING') {
|
||||
// $data_get = json_decode($pelanggan['data_get'], true);
|
||||
// $expired = $data_get['data']['expired'] ?? null;
|
||||
// // $expired = date('Y-m-d 18:47:10');
|
||||
|
||||
// if (!empty($expired) && $expired <= date('Y-m-d H:i:s')) {
|
||||
// echo getListPembayaran($pelanggan['id']);
|
||||
// } else {
|
||||
// echo getIntruksi($pelanggan['data_get']);
|
||||
// }
|
||||
// }
|
||||
// else {
|
||||
// echo getListPembayaran($pelanggan['id']);
|
||||
// }
|
||||
?>
|
||||
</div>
|
||||
|
||||
<?php } else { ?>
|
||||
<form method="post">
|
||||
<div class="form-group">
|
||||
<label>Masukan Nominal</label>
|
||||
<input type="text" class="form-control rupiah" id="rupiah0" name="nominal" required="required">
|
||||
<i class="text-danger">Untuk isi saldo minimal Rp. 25,000</i>
|
||||
</div><br>
|
||||
<input type="submit" name="tambah_saldo" value="Tambah Saldo" class="btn btn-warning btn-md btn-block" style="border-radius: 30px;" >
|
||||
</form>
|
||||
<?php } ?>
|
||||
<div class="mt-4">
|
||||
<hr>
|
||||
<center>
|
||||
<p>Riwayat isi saldo otomatis</p>
|
||||
</center>
|
||||
<table class="table">
|
||||
<?php
|
||||
$stmt2 = $pdo->prepare("SELECT * FROM agen_tambah_saldo WHERE id_agen_voucher = :id_agen_voucher AND status_payment != 'PENDING' ORDER BY waktu DESC, id DESC");
|
||||
$stmt2->bindParam(':id_agen_voucher', $_SESSION['agen'], PDO::PARAM_INT);
|
||||
$stmt2->execute();
|
||||
while($saldo = $stmt2->fetch(PDO::FETCH_ASSOC)) { ?>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<?php echo $saldo['waktu']; ?>
|
||||
<p><b>Rp. <?php echo number_format($saldo['nominal']); ?></b></p>
|
||||
</td>
|
||||
<td class="text-right">
|
||||
<?php echo $saldo['status_payment']; ?>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<?php } ?>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
if (isset($_POST['tambah_saldo'])) {
|
||||
try {
|
||||
|
||||
$nominal = preg_replace("/[^0-9]/", "", $_POST['nominal']);
|
||||
|
||||
if($nominal >= 25000) {
|
||||
$waktu = date('Y-m-d H:i:s');
|
||||
$keterangan = "Tambah saldo agen voucher";
|
||||
|
||||
// print_r($response);
|
||||
|
||||
$stmt = $pdo->prepare("INSERT INTO agen_tambah_saldo (id_data_server, id_agen_voucher, nominal, waktu, keterangan, status_payment)
|
||||
VALUES (:id_data_server, :id_agen_voucher, :nominal, :waktu, :keterangan, 'PENDING')");
|
||||
$stmt->bindParam(':id_data_server', $pcmem['id_data_server'], PDO::PARAM_INT);
|
||||
$stmt->bindParam(':id_agen_voucher', $_SESSION['agen'], PDO::PARAM_INT);
|
||||
$stmt->bindParam(':nominal', $nominal, PDO::PARAM_INT); // Pastikan nominal di-bind sebagai integer
|
||||
$stmt->bindParam(':waktu', $waktu);
|
||||
$stmt->bindParam(':keterangan', $keterangan);
|
||||
$stmt->execute();
|
||||
|
||||
sweetAlert("Permintaan Tambah Saldo Berhasil", "success");
|
||||
} else {
|
||||
sweetAlert("Nominal yang anda masukan kurang dari Rp. 25,000", "error");
|
||||
}
|
||||
|
||||
} catch (PDOException $e) {
|
||||
// Menangani kesalahan saat eksekusi
|
||||
sweetAlert("Terjadi kesalahan: " . htmlspecialchars($e->getMessage()), "error");
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_POST['ubah_moninal'])) {
|
||||
try {
|
||||
|
||||
$nominal = preg_replace("/[^0-9]/", "", $_POST['nominal']);
|
||||
|
||||
if($nominal >= 25000) {
|
||||
|
||||
$stmt = $pdo->prepare("UPDATE agen_tambah_saldo SET nominal = :nominal, url_payment = :url_payment, status_payment = :status_payment WHERE id_payment = :id_payment");
|
||||
$stmt->bindParam(':id', $ada['id_payment']);
|
||||
// Eksekusi statement
|
||||
$stmt->execute();
|
||||
|
||||
sweetAlert("Nominal Permintaan telah di ubah", "success");
|
||||
} else {
|
||||
sweetAlert("Nominal yang anda masukan kurang dari Rp. 25,000", "error");
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
// Menangani kesalahan saat eksekusi
|
||||
sweetAlert("Terjadi kesalahan: " . htmlspecialchars($e->getMessage()), "error");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
|
||||
|
||||
<script>
|
||||
let isVisible = false; // Default: tersembunyi
|
||||
const originalSaldo = "<?php echo number_format($pcmem['saldo']); ?>";
|
||||
|
||||
function toggleSaldo() {
|
||||
const saldoValue = document.getElementById('saldoValue');
|
||||
const iconEye = document.getElementById('iconEye');
|
||||
|
||||
if (!isVisible) {
|
||||
// Sembunyikan
|
||||
saldoValue.textContent = "••••••••••••";
|
||||
iconEye.classList.remove("fa-eye");
|
||||
iconEye.classList.add("fa-eye-slash");
|
||||
} else {
|
||||
// Tampilkan
|
||||
saldoValue.textContent = originalSaldo;
|
||||
iconEye.classList.remove("fa-eye-slash");
|
||||
iconEye.classList.add("fa-eye");
|
||||
}
|
||||
|
||||
isVisible = !isVisible;
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,160 @@
|
||||
<?php
|
||||
|
||||
function getListPembayaran($idTagihan) {
|
||||
return '
|
||||
<!-- Pilihan Metode -->
|
||||
<div id="pilihanMetode">
|
||||
<h6 class="mb-3">Metode Pembayaran</h6>
|
||||
|
||||
<div id="accordionMetode">
|
||||
<!-- Virtual Account -->
|
||||
<div class="card">
|
||||
<div class="card-header p-0" id="headingVA">
|
||||
<h5 class="mb-0">
|
||||
<button class="btn btn-link w-100 text-left collapsed" type="button"
|
||||
data-toggle="collapse" data-target="#collapseVA"
|
||||
aria-expanded="false" aria-controls="collapseVA">
|
||||
<span class="d-flex justify-content-between align-items-center">
|
||||
<span class="fw-semibold">Virtual Account</span>
|
||||
<span class="accordion-icons">
|
||||
<span class="bank-icon-box"><img src="https://manjapro.net/dist/img/bri.png" alt="BRI"></span>
|
||||
<span class="bank-icon-box"><img src="https://manjapro.net/dist/img/bni.png" alt="BNI"></span>
|
||||
<span class="bank-icon-box"><img src="https://manjapro.net/dist/img/mandiri.png" alt="Mandiri"></span>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</h5>
|
||||
</div>
|
||||
<div id="collapseVA" class="collapse" aria-labelledby="headingVA" data-parent="#accordionMetode">
|
||||
<div class="card-body p-0">
|
||||
<ul class="list-group list-group-flush bank-list">
|
||||
<li class="list-group-item">
|
||||
<a class="list-btn pay-method" onclick="pilihMetode(\'Virtual Account\', \'BRI\', \'https://manjapro.net/dist/img/bri.png\')">
|
||||
<div class="bank-logo-box"><img src="https://manjapro.net/dist/img/bri.png" alt="BRI"></div>
|
||||
<span class="bank-name">BRI VA</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<a class="list-btn pay-method" onclick="pilihMetode(\'Virtual Account\', \'BNI\', \'https://manjapro.net/dist/img/bni.png\')">
|
||||
<div class="bank-logo-box"><img src="https://manjapro.net/dist/img/bni.png" alt="BNI"></div>
|
||||
<span class="bank-name">BNI VA</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<a class="list-btn pay-method" onclick="pilihMetode(\'Virtual Account\', \'Mandiri\', \'https://manjapro.net/dist/img/mandiri.png\')">
|
||||
<div class="bank-logo-box"><img src="https://manjapro.net/dist/img/mandiri.png" alt="Mandiri"></div>
|
||||
<span class="bank-name">Mandiri VA</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- E-Wallet & QRIS -->
|
||||
<div class="card">
|
||||
<div class="card-header p-0" id="headingQRIS">
|
||||
<h5 class="mb-0">
|
||||
<button class="btn btn-link w-100 text-left collapsed" type="button"
|
||||
data-toggle="collapse" data-target="#collapseQRIS"
|
||||
aria-expanded="false" aria-controls="collapseQRIS">
|
||||
<span class="d-flex justify-content-between align-items-center">
|
||||
<span class="fw-semibold">E-Wallet & QRIS</span>
|
||||
<span class="accordion-icons">
|
||||
<span class="bank-icon-box"><img src="https://manjapro.net/dist/img/qris.png" alt="QRIS"></span>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</h5>
|
||||
</div>
|
||||
<div id="collapseQRIS" class="collapse" aria-labelledby="headingQRIS" data-parent="#accordionMetode">
|
||||
<div class="card-body p-0">
|
||||
<ul class="list-group list-group-flush bank-list">
|
||||
<li class="list-group-item">
|
||||
<a class="list-btn pay-method" onclick="pilihMetode(\'E-Wallet & QRIS\', \'QRIS\', \'https://manjapro.net/dist/img/qris.png\')">
|
||||
<div class="bank-logo-box"><img src="https://manjapro.net/dist/img/qris.png" alt="QRIS"></div>
|
||||
<span class="bank-name">QRIS</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="metodeTerpilih" class="d-none">
|
||||
<div class="method-card method-selected">
|
||||
<div class="bank-logo-box" style="margin-top: 0px;">
|
||||
<img src="https://manjapro.net/dist/img/qris.png" id="metodeLogo">
|
||||
</div>
|
||||
<span class="bank-name" id="metodeText"></span>
|
||||
<button type="button" class="btn btn-sm ubah-btn" onclick="ubahMetode()" style="font-size: 105%; color: #ff7f11;"><strong>Ubah</strong></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button id="btnBayar" class="btn btn-orange w-100 d-none" onclick="bayar()">Bayar</button>
|
||||
|
||||
<script>
|
||||
let metodeDipilih = "";
|
||||
let metodeService = "";
|
||||
let imgMetode = "";
|
||||
const idTagihan = '.$idTagihan.';
|
||||
|
||||
function pilihMetode(metode, service, logo){
|
||||
metodeDipilih = metode;
|
||||
metodeService = service;
|
||||
imgMetode = logo;
|
||||
|
||||
document.getElementById("pilihanMetode").classList.add("d-none");
|
||||
document.getElementById("metodeTerpilih").classList.remove("d-none");
|
||||
document.getElementById("metodeText").innerHTML = metode + "<br>" + service;
|
||||
document.getElementById("metodeLogo").src = logo;
|
||||
document.getElementById("btnBayar").classList.remove("d-none");
|
||||
}
|
||||
|
||||
function ubahMetode(){
|
||||
metodeDipilih = "";
|
||||
metodeService = "";
|
||||
document.getElementById("pilihanMetode").classList.remove("d-none");
|
||||
document.getElementById("metodeTerpilih").classList.add("d-none");
|
||||
document.getElementById("btnBayar").classList.add("d-none");
|
||||
}
|
||||
|
||||
function bayar(){
|
||||
if(metodeDipilih !== ""){
|
||||
let btn = document.getElementById("btnBayar");
|
||||
btn.disabled = true;
|
||||
btn.innerText = "Memproses...";
|
||||
|
||||
fetch("/proses.php", {
|
||||
method: "POST",
|
||||
headers: {"Content-Type": "application/x-www-form-urlencoded"},
|
||||
body: "action=bayar"
|
||||
+ "&paymentMethod=" + encodeURIComponent(metodeService)
|
||||
+ "&idTagihan=" + encodeURIComponent(idTagihan)
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
btn.disabled = false;
|
||||
btn.innerText = "Bayar Sekarang";
|
||||
if(data.success){
|
||||
window.location.reload();
|
||||
} else {
|
||||
alert("Gagal: " + (data.message || "Terjadi kesalahan"));
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
btn.disabled = false;
|
||||
btn.innerText = "Bayar Sekarang";
|
||||
console.error(err);
|
||||
alert("Terjadi error saat menghubungi server.");
|
||||
});
|
||||
|
||||
} else {
|
||||
alert("Silakan pilih metode pembayaran terlebih dahulu!");
|
||||
}
|
||||
}
|
||||
</script>
|
||||
';
|
||||
}
|
||||
|
After Width: | Height: | Size: 7.7 KiB |
|
After Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 129 KiB |
|
After Width: | Height: | Size: 91 KiB |
|
After Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 135 KiB |
|
After Width: | Height: | Size: 616 KiB |
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 83 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 58 KiB |
@@ -14,7 +14,7 @@ $isLoggedIn = isset($_SESSION['user']) || isset($_SESSION['master']);
|
||||
|
||||
// Ambil URL path
|
||||
// $path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
|
||||
$BaseUrl = "http://localhost/manjapro-project";
|
||||
$BaseUrl = "https://manjapro.net";
|
||||
|
||||
// Logika Path
|
||||
$basePath = parse_url($BaseUrl, PHP_URL_PATH);
|
||||
|
||||
@@ -1,37 +1,54 @@
|
||||
<?php
|
||||
// Koneksi ke database
|
||||
include '../config/connect.php';
|
||||
include '../config/encrypt.php';
|
||||
|
||||
// Pastikan input yang diterima dari GET aman
|
||||
$id_data_server = isset($_GET['id']) ? intval($_GET['id']) : 0;
|
||||
// $generate_time = isset($_GET['tgl']) ? $_GET['tgl'] : '';
|
||||
$id_data_server = isset($_GET['id']) ? decrypt_url($_GET['id']) : 0;
|
||||
|
||||
// Memastikan nilai yang diterima valid dan menghindari SQL injection
|
||||
// Memastikan nilai yang diterima valid
|
||||
if ($id_data_server > 0) {
|
||||
$data_akumulasi = [];
|
||||
// Query yang lebih aman menggunakan prepared statements
|
||||
$stmt = $pdo->prepare("SELECT id_data_server,
|
||||
SUM(total) as total,
|
||||
SUM(ditahan) as ditahan,
|
||||
SUM(tersedia) as tersedia
|
||||
|
||||
FROM v_akumulasi_paygw
|
||||
WHERE id_data_server = :id_data_server");
|
||||
|
||||
$stmt->bindValue(':id_data_server', $id_data_server, PDO::PARAM_INT);
|
||||
// $stmt->bindValue(':generate_time', $generate_time, PDO::PARAM_STR);
|
||||
|
||||
$stmt->execute();
|
||||
|
||||
// Mengambil hasil query dan menyimpannya dalam array
|
||||
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$data_akumulasi[] = $row;
|
||||
// Query gabungan
|
||||
if ($id_data_server == 1) {
|
||||
$sql = "SELECT
|
||||
p.id_data_server,
|
||||
SUM(p.total) AS total,
|
||||
SUM(p.ditahan) AS ditahan,
|
||||
SUM(p.tersedia) AS tersedia,
|
||||
SUM(v.jum_lunas) AS jum_lunas,
|
||||
SUM(v.jum_pending) AS jum_pending,
|
||||
SUM(v.jum_cancel) AS jum_cancel,
|
||||
SUM(v.jum_aktif) AS jum_aktif,
|
||||
SUM(v.jum_belum_aktif) AS jum_belum_aktif,
|
||||
SUM(v.jum_nonaktif) AS jum_nonaktif
|
||||
FROM v_akumulasi_paygw p
|
||||
LEFT JOIN v_akumulasi_voucher_paygw v
|
||||
ON p.id_data_server = v.id_data_server";
|
||||
} else {
|
||||
$sql = "SELECT
|
||||
p.id_data_server,
|
||||
SUM(p.total) AS total,
|
||||
SUM(p.ditahan) AS ditahan,
|
||||
SUM(p.tersedia) AS tersedia,
|
||||
SUM(v.jum_lunas) AS jum_lunas,
|
||||
SUM(v.jum_pending) AS jum_pending,
|
||||
SUM(v.jum_cancel) AS jum_cancel,
|
||||
SUM(v.jum_aktif) AS jum_aktif,
|
||||
SUM(v.jum_belum_aktif) AS jum_belum_aktif,
|
||||
SUM(v.jum_nonaktif) AS jum_nonaktif
|
||||
FROM v_akumulasi_paygw p
|
||||
LEFT JOIN v_akumulasi_voucher_paygw v
|
||||
ON p.id_data_server = v.id_data_server
|
||||
WHERE p.id_data_server IN ($id_data_server)";
|
||||
}
|
||||
|
||||
// Mengatur header untuk output JSON
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute();
|
||||
$data_akumulasi = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// Output JSON
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($data_akumulasi);
|
||||
} else {
|
||||
echo json_encode(['error' => 'Invalid parameters']);
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -1,33 +1,81 @@
|
||||
// const { exec } = require('child_process');
|
||||
// const path = require('path');
|
||||
|
||||
// // Jalur ke executable PHP
|
||||
// const phpExecutablePath = '/www/server/php/74/bin/php'; // Jalur yang sesuai dengan sistem Anda
|
||||
|
||||
// // Daftar jalur ke file PHP
|
||||
// const phpScriptPaths = [
|
||||
// path.join(__dirname, 'load_pesan.php'),
|
||||
// path.join(__dirname, 'load_tagihan_flip.php'),
|
||||
// path.join(__dirname, 'create_link_flip.php'),
|
||||
// ];
|
||||
|
||||
// // Fungsi untuk menjalankan file PHP
|
||||
// function runPhpScripts() {
|
||||
// phpScriptPaths.forEach((phpScriptPath) => {
|
||||
// console.log(`Running command: ${phpExecutablePath} ${phpScriptPath}`);
|
||||
// exec(`${phpExecutablePath} ${phpScriptPath}`, (error, stdout, stderr) => {
|
||||
// if (error) {
|
||||
// console.error(`Error executing PHP script ${phpScriptPath}: ${error.message}`);
|
||||
// return;
|
||||
// }
|
||||
// if (stderr) {
|
||||
// console.error(`PHP script ${phpScriptPath} stderr: ${stderr}`);
|
||||
// return;
|
||||
// }
|
||||
// console.log(`PHP script ${phpScriptPath} output: ${stdout}`);
|
||||
// });
|
||||
// });
|
||||
// }
|
||||
|
||||
// // Jalankan PHP scripts segera dan kemudian setiap 5 detik
|
||||
// runPhpScripts();
|
||||
// setInterval(runPhpScripts, 5000);
|
||||
|
||||
const { exec } = require('child_process');
|
||||
const path = require('path');
|
||||
|
||||
// Jalur ke executable PHP
|
||||
const phpExecutablePath = '/www/server/php/74/bin/php'; // Jalur yang sesuai dengan sistem Anda
|
||||
const phpExecutablePath = '/www/server/php/74/bin/php';
|
||||
|
||||
// Daftar jalur ke file PHP
|
||||
const phpScriptPaths = [
|
||||
path.join(__dirname, 'load_pesan.php'),
|
||||
path.join(__dirname, 'create_link_flip.php')
|
||||
path.join(__dirname, 'load_tagihan_flip.php'),
|
||||
path.join(__dirname, 'create_link_flip.php'),
|
||||
path.join(__dirname, 'load_tagihan_paydisini.php'),
|
||||
];
|
||||
|
||||
// Fungsi untuk menjalankan file PHP
|
||||
function runPhpScripts() {
|
||||
phpScriptPaths.forEach((phpScriptPath) => {
|
||||
// Fungsi untuk menjalankan 1 file PHP (Promise)
|
||||
function runPhpScript(phpScriptPath) {
|
||||
return new Promise((resolve) => {
|
||||
console.log(`Running command: ${phpExecutablePath} ${phpScriptPath}`);
|
||||
exec(`${phpExecutablePath} ${phpScriptPath}`, (error, stdout, stderr) => {
|
||||
if (error) {
|
||||
console.error(`Error executing PHP script ${phpScriptPath}: ${error.message}`);
|
||||
return;
|
||||
}
|
||||
if (stderr) {
|
||||
} else if (stderr) {
|
||||
console.error(`PHP script ${phpScriptPath} stderr: ${stderr}`);
|
||||
return;
|
||||
} else {
|
||||
console.log(`PHP script ${phpScriptPath} output: ${stdout}`);
|
||||
}
|
||||
console.log(`PHP script ${phpScriptPath} output: ${stdout}`);
|
||||
resolve(); // tetap resolve biar lanjut meskipun error
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Jalankan PHP scripts segera dan kemudian setiap 5 detik
|
||||
// Fungsi utama
|
||||
async function runPhpScripts() {
|
||||
// Jalankan semua script secara paralel
|
||||
await Promise.all(phpScriptPaths.map(runPhpScript));
|
||||
|
||||
// Random delay 5–15 detik
|
||||
const nextDelay = Math.floor(Math.random() * (10000 - 5000 + 1)) + 5000;
|
||||
console.log(`Next run in ${nextDelay / 1000} seconds\n`);
|
||||
|
||||
// Jalankan lagi setelah delay
|
||||
setTimeout(runPhpScripts, nextDelay);
|
||||
}
|
||||
|
||||
// Jalankan pertama kali
|
||||
runPhpScripts();
|
||||
setInterval(runPhpScripts, 5000);
|
||||
@@ -0,0 +1 @@
|
||||
{"status":"error","message":"Tidak dapat terhubung ke RouterOS"}
|
||||
@@ -12,7 +12,7 @@ $API = new RouterosAPI();
|
||||
$API->debug = false;
|
||||
|
||||
// Konfigurasi MikroTik
|
||||
$ip = '103.188.169.125';
|
||||
$ip = '103.155.198.185';
|
||||
$username = 'apirjn';
|
||||
$password = '@APIRJN123';
|
||||
$port = '6644';
|
||||
@@ -83,7 +83,7 @@ if ($API->connect2($ip, $username, $password, $port)) {
|
||||
}
|
||||
|
||||
header('Content-Type: application/json');
|
||||
// echo json_encode($response, JSON_PRETTY_PRINT);
|
||||
echo json_encode($response, JSON_PRETTY_PRINT);
|
||||
|
||||
} else {
|
||||
echo json_encode([
|
||||
|
||||
@@ -1,96 +1,132 @@
|
||||
<?php
|
||||
// Aktifkan pelaporan kesalahan untuk pengembangan
|
||||
// Aktifkan error log (minimalis)
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', 1); // Menampilkan kesalahan untuk pengembangan
|
||||
ini_set('display_errors', 0);
|
||||
ini_set('log_errors', 1);
|
||||
ini_set('error_log', __DIR__ . '/../logs/create_link_flip.log');
|
||||
|
||||
// Fungsi sanitasi string
|
||||
function sanitizeString($input) {
|
||||
$str01 = preg_replace('/[^a-zA-Z0-9\s]/', ' ', $input);
|
||||
$str02 = preg_replace('/\s+/', ' ', $str01);
|
||||
$str03 = trim($str02); // Perbaiki penamaan variabel di sini
|
||||
return $str03;
|
||||
return trim($str02);
|
||||
}
|
||||
|
||||
include "../config/connect.php";
|
||||
|
||||
try {
|
||||
$sqlData = "SELECT id, apikey_payment_gateway,url_payment_gateway FROM data_server WHERE status_payment_gateway = 'ACTIVE' AND apikey_payment_gateway != '' AND tokenkey_payment_gateway != '' AND url_payment_gateway != ''";
|
||||
$linkCreated = false; // Penanda apakah ada link yang berhasil dibuat
|
||||
|
||||
// Ambil semua server dengan payment gateway aktif
|
||||
$sqlData = "SELECT id, apikey_payment_gateway, url_payment_gateway
|
||||
FROM data_server
|
||||
WHERE status_payment_gateway = 'ACTIVE'
|
||||
AND apikey_payment_gateway != ''
|
||||
AND tokenkey_payment_gateway != ''
|
||||
AND url_payment_gateway != ''";
|
||||
$stmtData = $pdo->query($sqlData);
|
||||
|
||||
|
||||
while ($dataambil = $stmtData->fetch(PDO::FETCH_ASSOC)) {
|
||||
$idds = $dataambil['id'];
|
||||
|
||||
$idds = $dataambil['id'];
|
||||
$apiKey = $dataambil['apikey_payment_gateway'];
|
||||
$apiUrl = $dataambil['url_payment_gateway'];
|
||||
|
||||
$sqlProfil = "SELECT id, kirim_tagihan FROM profile_tagihan WHERE id_data_server = :id_data_server";
|
||||
// Ambil hanya 1 profile_tagihan untuk server ini
|
||||
$sqlProfil = "SELECT id, kirim_tagihan
|
||||
FROM profile_tagihan
|
||||
WHERE id_data_server = :id_data_server
|
||||
LIMIT 1";
|
||||
$stmtProfil = $pdo->prepare($sqlProfil);
|
||||
$stmtProfil->bindParam(':id_data_server', $idds, PDO::PARAM_INT);
|
||||
$stmtProfil->execute();
|
||||
|
||||
while ($dataprofil = $stmtProfil->fetch(PDO::FETCH_ASSOC)) {
|
||||
$sql = "SELECT * FROM v_tagihan WHERE id_data_server = :idds AND id_profile_tagihan = :idpt AND status = 'buat' AND transaction_id IS NULL AND transaction_link IS NULL AND transaction_status IS NULL AND verifikasi_tagihan > 1000 AND RIGHT(email, 10) = '@gmail.com'";
|
||||
if ($dataprofil = $stmtProfil->fetch(PDO::FETCH_ASSOC)) {
|
||||
// Ambil hanya 1 tagihan yang valid
|
||||
$sql = "SELECT * FROM v_tagihan
|
||||
WHERE id_data_server = :idds
|
||||
AND id_profile_tagihan = :idpt
|
||||
AND status = 'buat'
|
||||
AND transaction_id IS NULL
|
||||
AND transaction_link IS NULL
|
||||
AND transaction_status IS NULL
|
||||
AND verifikasi_tagihan > 1000
|
||||
AND RIGHT(email, 10) = '@gmail.com'
|
||||
ORDER BY id ASC
|
||||
LIMIT 1";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([':idds' => $idds, ':idpt' => $dataprofil['id']]);
|
||||
$data = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
echo $dataprofil['id'];
|
||||
// Pastikan $data['limit_pembayaran'] ada dan tidak kosong
|
||||
if ($data && isset($data['limit_pembayaran'])) {
|
||||
$day = str_pad($dataprofil['kirim_tagihan'], 2, '0', STR_PAD_LEFT);
|
||||
$cekkirim = substr($data['limit_pembayaran'], 0, 8) . $day;
|
||||
$stmt->execute([
|
||||
':idds' => $idds,
|
||||
':idpt' => $dataprofil['id']
|
||||
]);
|
||||
|
||||
// Pastikan format tanggal valid
|
||||
if ($data = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
try {
|
||||
$date = new DateTime($cekkirim);
|
||||
$date->modify('-1 day');
|
||||
$cektanggal = $date->format('Y-m-d');
|
||||
$sekarang = date('Y-m-d');
|
||||
if (!empty($data['limit_pembayaran'])) {
|
||||
$day = str_pad($dataprofil['kirim_tagihan'], 2, '0', STR_PAD_LEFT);
|
||||
$cekkirim = substr($data['limit_pembayaran'], 0, 8) . $day;
|
||||
|
||||
if ($sekarang == $cektanggal) {
|
||||
// Kode untuk meng-create link payment gateway
|
||||
require '../payment/flip/Flip/Transaction.php';
|
||||
$flip = new FlipPaymentGateway($apiKey, $apiUrl);
|
||||
$date = new DateTime($cekkirim);
|
||||
$date->modify('-1 day');
|
||||
$cektanggal = $date->format('Y-m-d');
|
||||
$sekarang = date('Y-m-d');
|
||||
|
||||
$response = $flip->createBill(
|
||||
sanitizeString($data['keterangan']),
|
||||
sanitizeString($data['verifikasi_tagihan']),
|
||||
$data['email'],
|
||||
sanitizeString($data['nama']),
|
||||
sanitizeString($data['nomor_whatsapp']),
|
||||
sanitizeString($data['alamat'])
|
||||
);
|
||||
if ($sekarang === $cektanggal) {
|
||||
// Buat link payment gateway
|
||||
require '../payment/flip/Flip/Transaction.php';
|
||||
$flip = new FlipPaymentGateway($apiKey, $apiUrl);
|
||||
|
||||
if (!empty($response['link_id']) && !empty($response['link_url']) && !empty($response['status'])) {
|
||||
$transaction_id = $response['link_id'];
|
||||
$transaction_link = $response['link_url'];
|
||||
$transaction_status = $response['status'];
|
||||
$response = $flip->createBill(
|
||||
sanitizeString($data['keterangan']),
|
||||
sanitizeString($data['verifikasi_tagihan']),
|
||||
$data['email'],
|
||||
sanitizeString($data['nama']),
|
||||
sanitizeString($data['nomor_whatsapp']),
|
||||
sanitizeString($data['alamat'])
|
||||
);
|
||||
|
||||
$stmt = $pdo->prepare("UPDATE tagihan SET transaction_id = :transaction_id, transaction_link = :transaction_link, transaction_status = :transaction_status WHERE id = :idtag");
|
||||
$stmt->bindParam(':transaction_id', $transaction_id);
|
||||
$stmt->bindParam(':transaction_link', $transaction_link);
|
||||
$stmt->bindParam(':transaction_status', $transaction_status);
|
||||
$stmt->bindParam(':idtag', $data['id']);
|
||||
$stmt->execute();
|
||||
echo " =>Success ".$data['nama'].", SV :".$data['nama_server'];
|
||||
} else {
|
||||
echo " =>Error ".$data['nama'].", SV :".$data['nama_server'];
|
||||
print_r($response);
|
||||
if (!empty($response['link_id']) && !empty($response['link_url']) && !empty($response['status'])) {
|
||||
$transaction_id = $response['link_id'];
|
||||
$transaction_link = $response['link_url'];
|
||||
$transaction_status = $response['status'];
|
||||
|
||||
$update = $pdo->prepare("UPDATE tagihan
|
||||
SET transaction_id = :transaction_id,
|
||||
transaction_link = :transaction_link,
|
||||
transaction_status = :transaction_status
|
||||
WHERE id = :idtag");
|
||||
$update->execute([
|
||||
':transaction_id' => $transaction_id,
|
||||
':transaction_link' => $transaction_link,
|
||||
':transaction_status' => $transaction_status,
|
||||
':idtag' => $data['id']
|
||||
]);
|
||||
|
||||
echo "[SUCCESS] {$data['nama']} ({$data['id']}) link dibuat.\n";
|
||||
$linkCreated = true; // Set penanda ada link dibuat
|
||||
} else {
|
||||
error_log("[ERROR] Flip API gagal untuk tagihan ID {$data['id']}");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
echo "No Data";
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
echo "Tanggal tidak valid: " . $e->getMessage();
|
||||
error_log("[EXCEPTION] {$e->getMessage()} untuk tagihan ID {$data['id']}");
|
||||
}
|
||||
} else {
|
||||
echo "Data tidak ditemukan";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Jika tidak ada satupun link yang dibuat
|
||||
if (!$linkCreated) {
|
||||
// error_log("[INFO] Tidak ada tagihan yang perlu dibuat link Flip.");
|
||||
echo "[INFO] Tidak ada tagihan yang perlu dibuat link.\n";
|
||||
}
|
||||
|
||||
echo "[DONE] Proses selesai pada " . date('Y-m-d H:i:s') . "\n";
|
||||
} catch (PDOException $e) {
|
||||
error_log('Database Error: ' . $e->getMessage());
|
||||
echo "Database error occurred: " . $e->getMessage();
|
||||
error_log('[DB ERROR] ' . $e->getMessage());
|
||||
echo "[DB ERROR] " . $e->getMessage();
|
||||
} catch (Exception $e) {
|
||||
error_log('General Error: ' . $e->getMessage());
|
||||
echo "An error occurred: " . $e->getMessage();
|
||||
error_log('[GENERAL ERROR] ' . $e->getMessage());
|
||||
echo "[ERROR] " . $e->getMessage();
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
include "/www/wwwroot/bilspro/config/connect.php";
|
||||
|
||||
// Ambil summary
|
||||
$stmt = $pdo->query("SELECT * FROM v_summary_transaksi_agen_bulanan");
|
||||
$summary = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// Ambil detail
|
||||
$stmt = $pdo->query("SELECT * FROM v_detail_agen_pascabayar");
|
||||
$detail = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// Ubah jadi keyed array
|
||||
function toKeyedArray($rows) {
|
||||
$out = [];
|
||||
foreach ($rows as $r) {
|
||||
$key = $r['id_agen_voucher'].'-'.$r['id_data_server'].'-'.$r['generate_time'];
|
||||
$out[$key] = $r;
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
$summaryArr = toKeyedArray($summary);
|
||||
$detailArr = toKeyedArray($detail);
|
||||
|
||||
// Gabungkan semua key
|
||||
$allKeys = array_unique(array_merge(array_keys($summaryArr), array_keys($detailArr)));
|
||||
|
||||
$diffs = [];
|
||||
$same = [];
|
||||
|
||||
foreach ($allKeys as $key) {
|
||||
$rowSummary = $summaryArr[$key] ?? null;
|
||||
$rowDetail = $detailArr[$key] ?? null;
|
||||
|
||||
if (!$rowSummary || !$rowDetail) {
|
||||
$diffs[$key] = [
|
||||
'missing_in' => !$rowSummary ? 'summary' : 'detail'
|
||||
];
|
||||
continue;
|
||||
}
|
||||
|
||||
// Bandingkan kolom satu per satu
|
||||
$rowDiff = [];
|
||||
foreach ($rowSummary as $col => $valSummary) {
|
||||
$valDetail = $rowDetail[$col] ?? null;
|
||||
|
||||
// Normalisasi null jadi 0
|
||||
$valSummaryNorm = ($valSummary === null || $valSummary === '') ? 0 : $valSummary;
|
||||
$valDetailNorm = ($valDetail === null || $valDetail === '') ? 0 : $valDetail;
|
||||
|
||||
if (trim((string)$valSummaryNorm) !== trim((string)$valDetailNorm)) {
|
||||
$rowDiff[$col] = [
|
||||
'summary' => $valSummary,
|
||||
'detail' => $valDetail
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if ($rowDiff) {
|
||||
$diffs[$key] = $rowDiff;
|
||||
} else {
|
||||
$same[$key] = $rowSummary;
|
||||
}
|
||||
}
|
||||
|
||||
// Hasil
|
||||
echo "<h3>✅ Data Sama: ".count($same)."</h3>";
|
||||
// echo "<pre>".json_encode($same, JSON_PRETTY_PRINT)."</pre>";
|
||||
|
||||
echo "<h3>⚠️ Data Berbeda / Hilang: ".count($diffs)."</h3>";
|
||||
echo "<pre>".json_encode($diffs, JSON_PRETTY_PRINT)."</pre>";
|
||||
@@ -0,0 +1,116 @@
|
||||
[21:38:01] [OK] 103.26.176.81
|
||||
[21:38:01] [OK] 103.188.169.123
|
||||
[21:38:01] [OK] 103.26.176.85
|
||||
[21:38:01] [OK] 103.26.176.83
|
||||
[21:38:01] [OK] 103.155.198.185
|
||||
[21:38:01] [OK] 103.188.169.121
|
||||
[21:38:01] [OK] tunnel.manjapro.net
|
||||
[21:38:01] [OK] tunnel.manjapro.net
|
||||
[21:38:01] [OK] tunnel.manjapro.net
|
||||
[21:38:01] [OK] tunnel.manjapro.net
|
||||
[21:38:01] [OK] tunnel.manjapro.net
|
||||
[21:38:02] [OK] 103.188.169.127
|
||||
[21:38:02] [OK] tunnel.manjapro.net
|
||||
[21:38:02] [OK] 103.26.176.87
|
||||
[21:38:02] [OK] tunnel.manjapro.net
|
||||
[21:38:02] [OK] 157.20.128.231
|
||||
[21:38:02] [OK] tunnel.manjapro.net
|
||||
[21:38:02] [OK] 103.26.176.93
|
||||
[21:38:02] [OK] 103.155.196.145
|
||||
[21:38:02] [OK] 103.94.10.112
|
||||
[21:38:02] [OK] tunnel.manjapro.net
|
||||
[21:38:02] [OK] 103.31.233.237
|
||||
[21:38:02] [OK] 103.242.104.69
|
||||
[21:38:03] [OK] 103.18.79.171
|
||||
[21:38:03] [OK] 103.155.199.191
|
||||
[21:38:03] [OK] tunnel.manjapro.net
|
||||
[21:38:03] [OK] tunnel.manjapro.net
|
||||
[21:38:03] [OK] tunnel.manjapro.net
|
||||
[21:38:04] [OK] 103.242.106.56
|
||||
[21:38:04] [OK] tunnel.manjapro.net
|
||||
[21:38:05] [FAIL] 103.67.80.126
|
||||
[21:38:06] [OK] 103.236.190.109
|
||||
[21:38:07] [FAIL] 103.94.10.240
|
||||
[21:38:07] [FAIL] 103.94.10.240
|
||||
[21:38:07] [FAIL] 103.94.10.240
|
||||
[21:38:07] [OK] 114.141.51.12
|
||||
[21:38:08] [FAIL] infinnet.cloud
|
||||
[21:38:08] [OK] 114.141.51.12
|
||||
[21:38:08] [OK] tunnel.manjapro.net
|
||||
[21:38:10] [OK] tunnel.manjapro.net
|
||||
[21:38:10] [OK] tunnel.manjapro.net
|
||||
[21:38:10] [OK] tunnel.manjapro.net
|
||||
[21:38:11] [OK] tunnel.manjapro.net
|
||||
[21:38:11] [OK] tunnel.manjapro.net
|
||||
[21:38:11] [FAIL] infinnet.cloud
|
||||
[21:38:12] [OK] tunnel.manjapro.net
|
||||
[21:38:12] [FAIL] tunnel.bilspro.com
|
||||
[21:38:12] [FAIL] tunnel.bilspro.com
|
||||
[21:38:12] [OK] tunnel.manjapro.net
|
||||
[21:38:13] [OK] tunnel.manjapro.net
|
||||
[21:38:14] [FAIL] tunnel.bilspro.com
|
||||
[21:38:14] [FAIL] 103.10.1.5
|
||||
[21:38:15] [FAIL] 157.20.12
|
||||
[21:38:16] [FAIL] 103.103.147.225
|
||||
[21:38:17] [FAIL] 103.155.198.109
|
||||
[21:38:17] [FAIL] tunnel.bilspro.com
|
||||
[21:38:18] [FAIL] tunnel.manjapro.net
|
||||
[2025-09-21 21:38:18] Semua child selesai. Mulai update DB...
|
||||
[21:38:18] [UPDATE DB] 03FK-Q7XE1
|
||||
[21:38:18] [UPDATE DB] IDLF-SK944
|
||||
[21:38:18] [UPDATE DB] TYF0-3RP75
|
||||
[21:38:18] [UPDATE DB] 0YDS-EI1V6
|
||||
[21:38:18] [UPDATE DB] C7CU-PGT97
|
||||
[21:38:18] [UPDATE STATUS] 7FZH-WIBI8 (Disconnected -> Disconnected)
|
||||
[21:38:18] [UPDATE DB] YHVJ-ZN9V9
|
||||
[21:38:18] [UPDATE DB] C7CU-PGT910
|
||||
[21:38:18] [UPDATE DB] MPK0-Q43P11
|
||||
[21:38:18] [UPDATE DB] S9QL-XRJ512
|
||||
[21:38:18] [UPDATE DB] HHJH-UFWL14
|
||||
[21:38:18] [UPDATE DB] 03FK-Q7XE15
|
||||
[21:38:18] [UPDATE DB] DG7B-JP4218
|
||||
[21:38:18] [UPDATE DB] XXWL-VMH419
|
||||
[21:38:18] [UPDATE DB] 03FK-Q7XE20
|
||||
[21:38:18] [UPDATE DB] C7CU-PGT922
|
||||
[21:38:18] [UPDATE DB] 8FHL-TXVS23
|
||||
[21:38:18] [UPDATE DB] Q23C-IE2524
|
||||
[21:38:18] [UPDATE DB] Q4D5-ATUM25
|
||||
[21:38:18] [UPDATE DB] HHJH-UFWL28
|
||||
[21:38:18] [UPDATE DB] 11P4-SII029
|
||||
[21:38:18] [UPDATE DB] CUAA-CD2K30
|
||||
[21:38:18] [UPDATE DB] S1Z8-TK6932
|
||||
[21:38:18] [UPDATE DB] H67G-R4AK33
|
||||
[21:38:18] [UPDATE STATUS] 9RV7-3W5U34 (Disconnected -> Disconnected)
|
||||
[21:38:18] [UPDATE DB] 32PA-DAZ435
|
||||
[21:38:18] [UPDATE STATUS] LJQ6-KDDJ37 (Disconnected -> Disconnected)
|
||||
[21:38:18] [UPDATE DB] 0TW0-J74U38
|
||||
[21:38:18] [UPDATE DB] L7TJ-IF2G39
|
||||
[21:38:18] [UPDATE DB] RWDJ-NXBZ40
|
||||
[21:38:18] [UPDATE DB] A26W-ART341
|
||||
[21:38:18] [UPDATE STATUS] RE5H-G12Y42 (Disconnected -> Disconnected)
|
||||
[21:38:18] [UPDATE STATUS] 03FK-Q7XE43 (Disconnected -> Disconnected)
|
||||
[21:38:18] [UPDATE STATUS] Q96U-20UZ44 (Disconnected -> Disconnected)
|
||||
[21:38:18] [UPDATE DB] D3TU-JN5745
|
||||
[21:38:18] [UPDATE DB] 7SDF-17X546
|
||||
[21:38:18] [UPDATE DB] HMAZ-3HSX51
|
||||
[21:38:18] [UPDATE STATUS] PQJB-HG8V53 (Disconnected -> Disconnected)
|
||||
[21:38:19] [UPDATE STATUS] PMA9-QC7654 (Disconnected -> Disconnected)
|
||||
[21:38:19] [UPDATE STATUS] 7ZCI-NFCI62 (Disconnected -> Disconnected)
|
||||
[21:38:19] [UPDATE STATUS] 0E73-PABK63 (Disconnected -> Disconnected)
|
||||
[21:38:19] [UPDATE DB] 4MZF-SFTR65
|
||||
[21:38:19] [UPDATE DB] PJC8-K0EG66
|
||||
[21:38:19] [UPDATE STATUS] 351D-5NCH67 (Disconnected -> Disconnected)
|
||||
[21:38:19] [UPDATE STATUS] A0S7-K2IC69 (Disconnected -> Disconnected)
|
||||
[21:38:19] [UPDATE DB] G9Z1-HRLY70
|
||||
[21:38:19] [UPDATE STATUS] C7CU-PGT972 (Disconnected -> Disconnected)
|
||||
[21:38:19] [UPDATE DB] 66AU-Z7I573
|
||||
[21:38:19] [UPDATE DB] ABMS-YBP776
|
||||
[21:38:19] [UPDATE DB] C7CU-PGT977
|
||||
[21:38:19] [UPDATE DB] C7CU-PGT978
|
||||
[21:38:19] [UPDATE DB] HHJH-UFWL81
|
||||
[21:38:19] [UPDATE DB] 83
|
||||
[21:38:19] [UPDATE STATUS] RNS6-DB3N84 (Disconnected -> Disconnected)
|
||||
[21:38:19] [UPDATE DB] C7CU-PGT987
|
||||
[21:38:19] [UPDATE DB] ZMVC-KAFH88
|
||||
[2025-09-21 21:38:19] Update DB selesai. OK: 56, FAIL: 1
|
||||
[2025-09-21 21:38:19] Lama eksekusi: 17.58 detik
|
||||
@@ -0,0 +1,250 @@
|
||||
<?php
|
||||
$start_time = microtime(true);
|
||||
|
||||
if (php_sapi_name() !== 'cli') {
|
||||
die("Script ini hanya bisa dijalankan lewat CLI.\n");
|
||||
}
|
||||
|
||||
ini_set('max_execution_time', 0);
|
||||
date_default_timezone_set('Asia/Jakarta');
|
||||
|
||||
require "/www/wwwroot/bilspro/config/routeros_api.class.php";
|
||||
|
||||
// ---------------- Config ----------------
|
||||
$max_processes = 10;
|
||||
$timeout_api = 3;
|
||||
$tmpDir = sys_get_temp_dir() . '/mt_results';
|
||||
|
||||
if (!is_dir($tmpDir)) {
|
||||
@mkdir($tmpDir, 0770, true);
|
||||
}
|
||||
|
||||
// Ambil daftar perangkat
|
||||
include "/www/wwwroot/bilspro/config/connect.php";
|
||||
$sqlList = "
|
||||
SELECT DISTINCT ip_address, port_api, username, password, board_id
|
||||
FROM setting_mikrotik";
|
||||
$stmt = $pdo->prepare($sqlList);
|
||||
$stmt->execute();
|
||||
$mikrotiks = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
$pdo = null;
|
||||
|
||||
if (empty($mikrotiks)) {
|
||||
echo "[" . date('Y-m-d H:i:s') . "] Tidak ada data MikroTik.\n";
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Fork parallel
|
||||
$child_pids = [];
|
||||
$outfiles = [];
|
||||
|
||||
foreach ($mikrotiks as $data) {
|
||||
while (count($child_pids) >= $max_processes) {
|
||||
foreach ($child_pids as $key => $pid) {
|
||||
if (pcntl_waitpid($pid, $status, WNOHANG) > 0) {
|
||||
unset($child_pids[$key]);
|
||||
}
|
||||
}
|
||||
usleep(100000);
|
||||
}
|
||||
|
||||
$safeId = preg_replace('~[^A-Za-z0-9_\-]~', '_', substr($data['board_id'], 0, 64));
|
||||
$outfile = $tmpDir . "/mt_" . $safeId . "_" . microtime(true) . "_" . mt_rand(1000,9999) . ".json";
|
||||
$outfiles[] = $outfile;
|
||||
|
||||
$pid = pcntl_fork();
|
||||
if ($pid == -1) {
|
||||
echo "[" . date('Y-m-d H:i:s') . "] Gagal fork.\n";
|
||||
continue;
|
||||
} elseif ($pid) {
|
||||
$child_pids[] = $pid;
|
||||
} else {
|
||||
process_mikrotik_child($data, $timeout_api, $outfile);
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($child_pids as $pid) {
|
||||
pcntl_waitpid($pid, $status);
|
||||
}
|
||||
|
||||
echo "[" . date('Y-m-d H:i:s') . "] Semua child selesai. Mulai update DB...\n";
|
||||
|
||||
// Update DB
|
||||
include "/www/wwwroot/bilspro/config/connect.php";
|
||||
|
||||
$updateSql = "
|
||||
UPDATE setting_mikrotik
|
||||
SET pppa = :pppa,
|
||||
hsa = :hsa,
|
||||
uptime = :ut,
|
||||
board_name = :bm,
|
||||
status = :st
|
||||
WHERE board_id = :id
|
||||
";
|
||||
$statusOnlySql = "
|
||||
UPDATE setting_mikrotik
|
||||
SET status = :st
|
||||
WHERE board_id = :id
|
||||
";
|
||||
|
||||
$updateStmt = $pdo->prepare($updateSql);
|
||||
$statusOnlyStmt = $pdo->prepare($statusOnlySql);
|
||||
|
||||
$execWithRetry = function($stmt, $params) use (&$pdo, $updateSql, $statusOnlySql, &$updateStmt, &$statusOnlyStmt) {
|
||||
try {
|
||||
$stmt->execute($params);
|
||||
return true;
|
||||
} catch (PDOException $e) {
|
||||
$msg = $e->getMessage();
|
||||
if (stripos($msg, '2006 MySQL server has gone away') !== false) {
|
||||
$pdo = null;
|
||||
include "/www/wwwroot/bilspro/config/connect.php";
|
||||
$updateStmt = $pdo->prepare($updateSql);
|
||||
$statusOnlyStmt = $pdo->prepare($statusOnlySql);
|
||||
$stmt = (isset($params[':pppa']) ? $updateStmt : $statusOnlyStmt);
|
||||
$stmt->execute($params);
|
||||
return true;
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
};
|
||||
|
||||
$updated = 0;
|
||||
$failed = 0;
|
||||
|
||||
foreach ($outfiles as $file) {
|
||||
if (!is_file($file)) continue;
|
||||
|
||||
$json = file_get_contents($file);
|
||||
@unlink($file);
|
||||
|
||||
$row = json_decode($json, true);
|
||||
if (!$row || !isset($row['board_id'], $row['status'])) {
|
||||
$failed++;
|
||||
continue;
|
||||
}
|
||||
|
||||
$paramsStatus = [
|
||||
':st' => $row['status'],
|
||||
':id' => $row['board_id'],
|
||||
];
|
||||
|
||||
// Cek data lama untuk log perbandingan
|
||||
$cekStmt = $pdo->prepare("SELECT pppa,hsa,uptime,board_name,status FROM setting_mikrotik WHERE board_id = :id");
|
||||
$cekStmt->execute([':id' => $row['board_id']]);
|
||||
$current = $cekStmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if ($row['status'] === 'Connected') {
|
||||
$params = [
|
||||
':pppa' => $row['pppa'] ?? '',
|
||||
':hsa' => $row['hsa'] ?? '',
|
||||
':ut' => $row['uptime'] ?? '',
|
||||
':bm' => $row['board_name'] ?? '',
|
||||
':st' => 'Connected',
|
||||
':id' => $row['board_id'],
|
||||
];
|
||||
try {
|
||||
$execWithRetry($updateStmt, $params);
|
||||
$updated++;
|
||||
|
||||
echo "[" . date('H:i:s') . "] [UPDATE DB] {$row['board_id']} \n ";
|
||||
// echo "OLD: " . json_encode($current, JSON_UNESCAPED_UNICODE) . "\n NEW: " . json_encode($params, JSON_UNESCAPED_UNICODE) . "\n";
|
||||
} catch (PDOException $e) {
|
||||
echo "[" . date('H:i:s') . "] [DB ERROR] {$row['board_id']} - " . $e->getMessage() . "\n";
|
||||
$failed++;
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
$execWithRetry($statusOnlyStmt, $paramsStatus);
|
||||
$updated++;
|
||||
echo "[" . date('H:i:s') . "] [UPDATE STATUS] {$row['board_id']} ({$current['status']} -> {$row['status']})\n";
|
||||
} catch (PDOException $e) {
|
||||
echo "[" . date('H:i:s') . "] [DB ERROR] {$row['board_id']} - " . $e->getMessage() . "\n";
|
||||
$failed++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$pdo = null;
|
||||
echo "[" . date('Y-m-d H:i:s') . "] Update DB selesai. OK: {$updated}, FAIL: {$failed}\n";
|
||||
|
||||
$end_time = microtime(true);
|
||||
$duration = $end_time - $start_time;
|
||||
echo "[" . date('Y-m-d H:i:s') . "] Lama eksekusi: " . number_format($duration, 2) . " detik\n";
|
||||
|
||||
exit(0);
|
||||
|
||||
// ================================
|
||||
// CHILD: konek RouterOS & tulis file hasil
|
||||
// ================================
|
||||
function process_mikrotik_child(array $data, int $timeout_api, string $outfile): void
|
||||
{
|
||||
$ip = $data['ip_address'];
|
||||
$username = $data['username'];
|
||||
$password = $data['password'];
|
||||
$port = $data['port_api'];
|
||||
$board_id = $data['board_id'];
|
||||
|
||||
$API = new RouterosAPI();
|
||||
$API->debug = false;
|
||||
$API->timeout = $timeout_api;
|
||||
|
||||
$result = [
|
||||
'board_id' => $board_id,
|
||||
'status' => 'Disconnected',
|
||||
'pppa' => '',
|
||||
'hsa' => '',
|
||||
'board_name' => '',
|
||||
'uptime' => '',
|
||||
'ip' => $ip,
|
||||
];
|
||||
|
||||
if ($API->connect2($ip, $username, $password, $port)) {
|
||||
$pppoe_active = [];
|
||||
$pppoe_data = $API->comm("/ppp/active/print");
|
||||
if (is_array($pppoe_data)) {
|
||||
foreach ($pppoe_data as $item) {
|
||||
$name = $item['name'] ?? '';
|
||||
$addr = $item['address'] ?? '';
|
||||
if ($name !== '' && $addr !== '') {
|
||||
$pppoe_active[] = "{$name}_{$addr}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$hotspot_active = [];
|
||||
$hotspot_users = $API->comm("/ip/hotspot/user/print");
|
||||
if (is_array($hotspot_users)) {
|
||||
foreach ($hotspot_users as $item) {
|
||||
$user = $item['name'] ?? '';
|
||||
$comment = $item['comment'] ?? '';
|
||||
if ($user !== '' && strpos($comment, 'Login.') === 0) {
|
||||
$hotspot_active[] = "{$user}_" . substr($comment, 6);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$sys = $API->comm("/system/resource/print");
|
||||
$board_name = '';
|
||||
$uptime = '';
|
||||
if (is_array($sys) && !empty($sys[0])) {
|
||||
$board_name = $sys[0]['board-name'] ?? '';
|
||||
$uptime = $sys[0]['uptime'] ?? '';
|
||||
}
|
||||
|
||||
$API->disconnect();
|
||||
|
||||
$result['status'] = 'Connected';
|
||||
$result['pppa'] = implode('|', $pppoe_active);
|
||||
$result['hsa'] = implode('|', $hotspot_active);
|
||||
$result['board_name'] = $board_name;
|
||||
$result['uptime'] = $uptime;
|
||||
|
||||
echo "[" . date('H:i:s') . "] [OK] {$ip}\n";
|
||||
} else {
|
||||
echo "[" . date('H:i:s') . "] [FAIL] {$ip}\n";
|
||||
}
|
||||
|
||||
file_put_contents($outfile, json_encode($result, JSON_UNESCAPED_UNICODE));
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
[2025-09-21 21:36:01] Tidak ada remote expired.
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
include "/www/wwwroot/bilspro/config/connect.php";
|
||||
include "/www/wwwroot/bilspro/config/routeros_api.class.php";
|
||||
include "/www/wwwroot/bilspro/controller/remoteModem.php";
|
||||
|
||||
// Kurangi 30 menit dari waktu sekarang
|
||||
$date = date('Y-m-d H:i:s', strtotime('-20 minutes'));
|
||||
|
||||
$stmt = $pdo->prepare("SELECT id_setting_mikrotik, remote_port
|
||||
FROM log_remote
|
||||
WHERE aktif_time <= :date
|
||||
LIMIT 1");
|
||||
$stmt->execute([':date' => $date]);
|
||||
|
||||
$data = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if ($data) {
|
||||
// Tutup remote yang sudah expired
|
||||
$remote = new RemoteModem($pdo);
|
||||
$result = $remote->remote_close($data['id_setting_mikrotik'], $data['remote_port']);
|
||||
echo "[" . date('Y-m-d H:i:s') . "] Remote port " . $data['remote_port'] . " berhasil ditutup.\n";
|
||||
} else {
|
||||
// Tidak ada yang perlu dihapus
|
||||
echo "[" . date('Y-m-d H:i:s') . "] Tidak ada remote expired.\n";
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
[2025-09-20 23:50:02] 0 data telah dihapus. Data tersisa sejak 2025-08-01 00:00:00 sampai sekarang.
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
include "/www/wwwroot/bilspro/config/connect.php";
|
||||
|
||||
// Ambil tanggal awal bulan -1 (bulan sebelumnya)
|
||||
$date = date('Y-m-01 00:00:00', strtotime('-1 month'));
|
||||
|
||||
// Jalankan query DELETE
|
||||
$stmt = $pdo->prepare("DELETE FROM monitoring_pelanggan
|
||||
WHERE waktu < :date");
|
||||
$stmt->execute([':date' => $date]);
|
||||
|
||||
// Ambil jumlah data yang dihapus
|
||||
$delete = $stmt->rowCount();
|
||||
|
||||
// Tampilkan hasil
|
||||
echo "[" . date('Y-m-d H:i:s') . "] " . $delete . " data telah dihapus. Data tersisa sejak " . $date . " sampai sekarang.\n";
|
||||
@@ -0,0 +1 @@
|
||||
2025-09-21 21:30:06 ✅ Summary updated, rows affected: 1474
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
include "/www/wwwroot/bilspro/config/connect.php";
|
||||
|
||||
try {
|
||||
// Update / replace summary table
|
||||
$sql = "
|
||||
REPLACE INTO summary_transaksi_agen_bulanan
|
||||
|
||||
SELECT
|
||||
a.id_agen_voucher AS id_agen_voucher,
|
||||
a.id_data_server AS id_data_server,
|
||||
SUBSTR(a.generate_time, 1, 7) AS generate_time,
|
||||
SUM(a.debet) AS debet,
|
||||
SUM(a.kredit) AS kredit,
|
||||
(SUM(COALESCE(a.kredit, 0)) - SUM(COALESCE(a.debet, 0))) AS saldo,
|
||||
COUNT(DISTINCT (CASE WHEN (a.kredit IS NOT NULL) THEN a.id END)) AS jumlah_voucher,
|
||||
COUNT(DISTINCT (CASE WHEN (c.active_time IS NULL) THEN c.id END)) AS jumlah_voucher_belum_aktif,
|
||||
COUNT(DISTINCT (CASE WHEN (c.expaired_time > NOW()) THEN c.id END)) AS jumlah_voucher_aktif,
|
||||
COUNT(DISTINCT (CASE WHEN (c.expaired_time < NOW()) THEN c.id END)) AS jumlah_voucher_expaired
|
||||
FROM
|
||||
transaksi_agen_voucher a
|
||||
JOIN agen_voucher b ON (a.id_agen_voucher = b.id)
|
||||
LEFT JOIN ganerate_voucher c ON (a.id_ganerate_voucher = c.id)
|
||||
WHERE
|
||||
b.jenis_agen = 'Pascabayar'
|
||||
AND a.generate_time < DATE_FORMAT(CURDATE(), '%Y-%m-01')
|
||||
GROUP BY
|
||||
SUBSTR(a.generate_time, 1, 7),
|
||||
a.id_agen_voucher
|
||||
";
|
||||
|
||||
$affected = $pdo->exec($sql);
|
||||
echo date('Y-m-d H:i:s') . " ✅ Summary updated, rows affected: {$affected}\n";
|
||||
|
||||
} catch (PDOException $e) {
|
||||
echo date('Y-m-d H:i:s') . " ❌ Error: " . $e->getMessage() . "\n";
|
||||
exit(1);
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
Voucher: CCU7DPArBx5nR<br>Aktif => 2025-09-21 21:38:11<br>Expaired => 2025-09-28 21:38:11<br>
|
||||
@@ -1,23 +1,23 @@
|
||||
SV_Cikembar_Utama Data pelanggan tidak ada
|
||||
2025-07-15 01:58:01SV_BojongKerta Data pelanggan tidak ada
|
||||
2025-07-15 01:58:01SV_Permata_Sampora Data pelanggan tidak ada
|
||||
2025-07-15 01:58:01SV_Kingnet_Cibadak Data pelanggan tidak ada
|
||||
2025-07-15 01:58:01SV_CC-Net_Cipicung Data pelanggan tidak ada
|
||||
2025-07-15 01:58:01SV_Nusaina_Cibadak Data pelanggan tidak ada
|
||||
2025-07-15 01:58:01SV_Diamond Net Status koneksi tidak aktif atau interval tidak tersedia.
|
||||
2025-09-21 21:09:01SV_BojongKerta Data pelanggan tidak ada
|
||||
2025-09-21 21:09:01RO Bima Net Data pelanggan tidak ada
|
||||
2025-09-21 21:09:01SV_Kingnet_Cibadak Data pelanggan tidak ada
|
||||
2025-09-21 21:09:01SV_CC-Net_Cipicung Data pelanggan tidak ada
|
||||
2025-09-21 21:09:01SV_Nusaina_Cibadak Data pelanggan tidak ada
|
||||
2025-09-21 21:09:01SV_Diamond Net Status koneksi tidak aktif atau interval tidak tersedia.
|
||||
SV_22P Net Cibadak Data pelanggan tidak ada
|
||||
2025-07-15 01:58:01SV_Nettizen_Segaranten Data pelanggan tidak ada
|
||||
2025-07-15 01:28:01SV-DNY-Net-1 Data pelanggan tidak ada
|
||||
2025-07-15 02:08:01SV_NTA_2_Pasawahan Status koneksi tidak aktif atau interval tidak tersedia.
|
||||
2025-09-21 21:09:01SV_Nettizen_Segaranten Data pelanggan tidak ada
|
||||
2025-09-21 20:39:01SV-DNY-Net-1 Data pelanggan tidak ada
|
||||
2025-09-21 21:19:01SV_NTA_2_PSW_1 Status koneksi tidak aktif atau interval tidak tersedia.
|
||||
SV_NTA_1 Status koneksi tidak aktif atau interval tidak tersedia.
|
||||
SV-Cicukang Status koneksi tidak aktif atau interval tidak tersedia.
|
||||
RO-Bumdes-Mekarmanah Status koneksi tidak aktif atau interval tidak tersedia.
|
||||
RO-Pak-Kholiq Data pelanggan tidak ada
|
||||
2025-07-15 02:13:01RO-Dendrit-Net Status koneksi tidak aktif atau interval tidak tersedia.
|
||||
2025-09-21 21:24:01RO-Dendrit-Net Status koneksi tidak aktif atau interval tidak tersedia.
|
||||
LJN.NS.CSR.NET Status koneksi tidak aktif atau interval tidak tersedia.
|
||||
IVVINET-CBD Data pelanggan tidak ada
|
||||
2025-07-15 01:58:02QONNET Data pelanggan tidak ada
|
||||
2025-07-15 01:58:02Mikrotik_X86 Status koneksi tidak aktif atau interval tidak tersedia.
|
||||
2025-09-21 21:09:01QONNET Data pelanggan tidak ada
|
||||
2025-09-21 21:09:01Mikrotik_X86 Status koneksi tidak aktif atau interval tidak tersedia.
|
||||
Mikrotik_BSW_1 Status koneksi tidak aktif atau interval tidak tersedia.
|
||||
Mikrotik_Alea Status koneksi tidak aktif atau interval tidak tersedia.
|
||||
STANG Status koneksi tidak aktif atau interval tidak tersedia.
|
||||
@@ -37,14 +37,22 @@ RO_Wargasari Status koneksi tidak aktif atau interval tidak tersedia.
|
||||
LJN_AGUNG Status koneksi tidak aktif atau interval tidak tersedia.
|
||||
RNET-CMS Status koneksi tidak aktif atau interval tidak tersedia.
|
||||
DCN-GB-CCR Data pelanggan tidak ada
|
||||
2025-07-15 01:58:02coba Status koneksi tidak aktif atau interval tidak tersedia.
|
||||
2025-09-21 21:09:01coba Status koneksi tidak aktif atau interval tidak tersedia.
|
||||
412NET Status koneksi tidak aktif atau interval tidak tersedia.
|
||||
brf Status koneksi tidak aktif atau interval tidak tersedia.
|
||||
BMSNET Status koneksi tidak aktif atau interval tidak tersedia.
|
||||
purabaya Status koneksi tidak aktif atau interval tidak tersedia.
|
||||
DCN-CO-GX4 Data pelanggan tidak ada
|
||||
2025-07-15 01:58:02MIKROTIK GX4 Status koneksi tidak aktif atau interval tidak tersedia.
|
||||
2025-09-21 21:09:01MIKROTIK GX4 Status koneksi tidak aktif atau interval tidak tersedia.
|
||||
RO - Netborhood Wifi Status koneksi tidak aktif atau interval tidak tersedia.
|
||||
Neglasari Status koneksi tidak aktif atau interval tidak tersedia.
|
||||
SV-DNY-Net-2 Data pelanggan tidak ada
|
||||
2025-07-15 02:08:02DNY-Neglasari Status koneksi tidak aktif atau interval tidak tersedia.
|
||||
2025-09-21 21:19:01DNY-Neglasari Status koneksi tidak aktif atau interval tidak tersedia.
|
||||
RO_TTO Status koneksi tidak aktif atau interval tidak tersedia.
|
||||
AP - NET Status koneksi tidak aktif atau interval tidak tersedia.
|
||||
GAS NET Status koneksi tidak aktif atau interval tidak tersedia.
|
||||
SV_NTA_2_PSW_2 Status koneksi tidak aktif atau interval tidak tersedia.
|
||||
chr tencent Status koneksi tidak aktif atau interval tidak tersedia.
|
||||
DamarisNet Status koneksi tidak aktif atau interval tidak tersedia.
|
||||
Triunsa Status koneksi tidak aktif atau interval tidak tersedia.
|
||||
Mikrotik GR 3 Status koneksi tidak aktif atau interval tidak tersedia.
|
||||
|
||||
@@ -1 +1,23 @@
|
||||
Successfully started background process for IP: tunnel.manjapro.net SV-DNY-Net-1<br>Successfully started background process for IP: nsn.my.id SV_22P Net Cibadak<br>Successfully started background process for IP: nsn.my.id RO-Bumdes-Mekarmanah<br>Successfully started background process for IP: 103.242.104.69 RO-Dendrit-Net<br>Successfully started background process for IP: 103.26.176.93 LJN.NS.CSR.NET<br>Successfully started background process for IP: 103.155.198.109 RO_Asep<br>Successfully started background process for IP: 103.155.199.191 PERWASIM-NETWORK<br>Successfully started background process for IP: tunnel.manjapro.net SV_NTA_2_Pasawahan<br>Successfully started background process for IP: tunnel.manjapro.net SV-Cicukang<br>Successfully started background process for IP: tunnel.manjapro.net SV_NTA_1<br>Successfully started background process for IP: 103.94.10.112 STANG<br>Successfully started background process for IP: 157.20.128.231 QONNET<br>Successfully started background process for IP: 114.141.51.12 BMSNET<br>Successfully started background process for IP: 114.141.51.12 purabaya<br>Successfully started background process for IP: nsn.my.id SV_Cikembar_Utama<br>Successfully started background process for IP: tunnel.bilspro.com RO_Sukasari<br>Successfully started background process for IP: tunnel.bilspro.com Mikrotik_X86<br>Successfully started background process for IP: 103.155.196.145 UNIX-NET<br>Successfully started background process for IP: nsn.my.id SV_Diamond Net<br>Successfully started background process for IP: 103.26.176.81 SV_CC-Net_Cipicung<br>Successfully started background process for IP: 103.242.105.199 SV-DNY-Net-2<br>Started parallel processes for checking vouchers. => 2025-07-15 02:00:02
|
||||
Successfully started background process for IP: tunnel.manjapro.net SV-DNY-Net-1
|
||||
Successfully started background process for IP: 103.188.169.123 SV_22P Net Cibadak
|
||||
Successfully started background process for IP: tunnel.manjapro.net RO-Bumdes-Mekarmanah
|
||||
Successfully started background process for IP: 103.242.104.69 RO-Dendrit-Net
|
||||
Successfully started background process for IP: 103.26.176.93 LJN.NS.CSR.NET
|
||||
Successfully started background process for IP: tunnel.manjapro.net RO_Asep
|
||||
Successfully started background process for IP: 103.155.199.191 PERWASIM-NETWORK
|
||||
Successfully started background process for IP: tunnel.manjapro.net SV_NTA_2_PSW_1
|
||||
Successfully started background process for IP: tunnel.manjapro.net SV-Cicukang
|
||||
Successfully started background process for IP: tunnel.manjapro.net SV_NTA_1
|
||||
Successfully started background process for IP: 103.94.10.112 STANG
|
||||
Successfully started background process for IP: 157.20.128.231 QONNET
|
||||
Successfully started background process for IP: 114.141.51.12 BMSNET
|
||||
Successfully started background process for IP: 114.141.51.12 purabaya
|
||||
Successfully started background process for IP: 103.155.198.185 SV_Cikembar_Utama
|
||||
Successfully started background process for IP: 103.155.196.145 UNIX-NET
|
||||
Successfully started background process for IP: 103.26.176.81 SV_CC-Net_Cipicung
|
||||
Successfully started background process for IP: tunnel.manjapro.net SV-DNY-Net-2
|
||||
Successfully started background process for IP: tunnel.manjapro.net Mikrotik_X86
|
||||
Successfully started background process for IP: tunnel.manjapro.net SV_NTA_2_PSW_2
|
||||
Successfully started background process for IP: tunnel.manjapro.net Triunsa
|
||||
Successfully started background process for IP: tunnel.manjapro.net SV_Diamond Net
|
||||
Started parallel processes for checking vouchers. => 2025-09-21 21:30:01
|
||||
@@ -34,9 +34,9 @@ if ($set1->rowCount() > 0) {
|
||||
|
||||
// Check if there was an issue with exec
|
||||
if ($return_var !== 0) {
|
||||
echo "Error executing command for IP: {$m_ip}<br>";
|
||||
echo "Error executing command for IP: {$m_ip}\n";
|
||||
} else {
|
||||
echo "Successfully started background process for IP: {$m_ip} {$nama}<br>";
|
||||
echo "Successfully started background process for IP: {$m_ip} {$nama}\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,341 +1,158 @@
|
||||
<?php
|
||||
// Aktifkan pelaporan kesalahan untuk pengembangan
|
||||
// Aktifkan error log
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', 0); // Tampilkan kesalahan saat pengembangan
|
||||
ini_set('display_errors', 0);
|
||||
ini_set('log_errors', 1);
|
||||
ini_set('error_log', __DIR__ . '/../logs/load_pesan.log');
|
||||
|
||||
// Menghubungkan ke database
|
||||
include "../config/connect.php";
|
||||
include "../config/tanggal_indo.php";
|
||||
include "../config/routeros_api.class.php";
|
||||
include "../config/whatsapp_api.php";
|
||||
|
||||
try {
|
||||
// Ambil semua apiKey_whatsapp yang tidak kosong
|
||||
$sqlData = "SELECT api_key FROM v_key_load_pesan";
|
||||
$stmtData = $pdo->query($sqlData);
|
||||
$apiKeys = $stmtData->fetchAll(PDO::FETCH_COLUMN);
|
||||
|
||||
// Loop melalui setiap apiKey_whatsapp
|
||||
while ($dataambil = $stmtData->fetch(PDO::FETCH_ASSOC)) {
|
||||
$keyapi = $dataambil['api_key'];
|
||||
if (!empty($apiKeys)) {
|
||||
foreach ($apiKeys as $keyapi) {
|
||||
$pdo->beginTransaction();
|
||||
|
||||
// Ambil pesan dengan status 'PENDING' dan api_key sesuai
|
||||
$sql = "SELECT * FROM v_master_pesan WHERE api_key = :apiKey AND status ='PENDING' ";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([':apiKey' => $keyapi]);
|
||||
$data = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
// --- CEK LOG APIKEY ---
|
||||
$sql1 = "SELECT chat_count, update_time
|
||||
FROM chat_log_apikey
|
||||
WHERE apikey_whatsapp = :apiKey
|
||||
LIMIT 1";
|
||||
$stmt = $pdo->prepare($sql1);
|
||||
$stmt->execute([':apiKey' => $keyapi]);
|
||||
$log = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if($data) {
|
||||
$jenis = $data['jenis_pesan'];
|
||||
$apiurl = $data['api_url'];
|
||||
$chatCount = $log ? (int)$log['chat_count'] : 0;
|
||||
$updateTime = $log ? strtotime($log['update_time']) : 0;
|
||||
$now = time();
|
||||
|
||||
// Siapkan data untuk dikirim berdasarkan jenis pesan
|
||||
$datapost = '';
|
||||
if ($jenis == "sendMessage") {
|
||||
$datapost = http_build_query([
|
||||
'apiKey' => $data['api_key'],
|
||||
'phone' => $data['nomor'],
|
||||
'message' => $data['pesan']
|
||||
]);
|
||||
} elseif ($jenis == "sendMediaFromUrl") {
|
||||
$datapost = http_build_query([
|
||||
'apiKey' => $data['api_key'],
|
||||
'phone' => $data['nomor'],
|
||||
'url_file' => $data['url_file'],
|
||||
'as_document' => '0',
|
||||
'caption' => $data['pesan']
|
||||
]);
|
||||
} else {
|
||||
continue; // Skip jika jenis tidak dikenali
|
||||
}
|
||||
|
||||
// echo $datapost;
|
||||
// echo $datapost;
|
||||
|
||||
// Inisialisasi cURL
|
||||
$curl = curl_init();
|
||||
curl_setopt_array($curl, array(
|
||||
CURLOPT_URL => $apiurl . $jenis,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_ENCODING => '',
|
||||
CURLOPT_MAXREDIRS => 10,
|
||||
CURLOPT_TIMEOUT => 30,
|
||||
CURLOPT_FOLLOWLOCATION => true,
|
||||
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
|
||||
CURLOPT_CUSTOMREQUEST => 'POST',
|
||||
CURLOPT_POSTFIELDS => $datapost,
|
||||
CURLOPT_HTTPHEADER => array(
|
||||
'Content-Type: application/x-www-form-urlencoded',
|
||||
'Content-Length: ' . strlen($datapost)
|
||||
),
|
||||
));
|
||||
|
||||
// Eksekusi cURL dan tangani kesalahan
|
||||
$response = curl_exec($curl);
|
||||
if (curl_errno($curl)) {
|
||||
error_log('cURL Error: ' . curl_error($curl));
|
||||
curl_close($curl);
|
||||
continue; // Skip ke data berikutnya jika ada error
|
||||
}
|
||||
curl_close($curl);
|
||||
|
||||
// Decode respons JSON
|
||||
$rdata = json_decode($response);
|
||||
// print_r($rdata)."<br>";
|
||||
|
||||
// Periksa apakah respons valid
|
||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||
error_log('JSON Decode Error: ' . json_last_error_msg());
|
||||
$rdata = (object) ['code' => '200', 'results' => (object) []]; // Anda bisa menyesuaikan ini jika perlu
|
||||
}
|
||||
|
||||
// Update status berdasarkan respons
|
||||
// $status = (isset($rdata->code) && $rdata->code === '200') ? 'TERKIRIM' : 'GAGAL';
|
||||
if($rdata->code == 200){
|
||||
$status = 'TERKIRIM';
|
||||
} else {
|
||||
$status = 'GAGAL';
|
||||
}
|
||||
|
||||
echo $rdata->code; // Mengakses 'code' dengan benar
|
||||
echo " ".$status;
|
||||
|
||||
|
||||
// Update status di database
|
||||
$updateStmt = $pdo->prepare("UPDATE master_pesan SET status = :status WHERE id = :id");
|
||||
$updateStmt->execute([
|
||||
':status' => $status,
|
||||
':id' => $data['id']
|
||||
]);
|
||||
}
|
||||
}
|
||||
// Ambil data tagihan yang status transaksinya SUCCESSFUL
|
||||
$datetime = date('Y-m-d H:i:s', time() - 60); // waktu 60 detik yang lalu
|
||||
$stmt = $pdo->prepare("SELECT * FROM v_tagihan_flip_lunas WHERE last_mikrotik_connect > :datetime");
|
||||
$stmt->execute(['datetime' => $datetime]);
|
||||
$tagihan = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
// Pastikan data tagihan ditemukan
|
||||
if ($tagihan) {
|
||||
|
||||
// Ambil detail tagihan
|
||||
$user = $tagihan['akun'];
|
||||
$idtag = $tagihan['id'];
|
||||
$nama = $tagihan['nama']; // Contoh nama
|
||||
$nominal = $tagihan['verifikasi_tagihan']; // Contoh nominal
|
||||
$keterangan = 'Pembayaran ' . $tagihan['keterangan']; // Contoh keterangan
|
||||
$invoice = 'kwitansi_' . date('Ymd') . $idtag . '.png'; // Nama file output
|
||||
$paketint = $tagihan['nama_paket'];
|
||||
$jumtagihan = 'Rp. '.number_format($tagihan['jumlah_tagihan'], 0, ',', '.');
|
||||
$ppn = 'Rp. '.number_format($tagihan['ppn'], 0, ',', '.');
|
||||
$subsidi = 'Rp. '.number_format($tagihan['kode_unik'], 0, ',', '.');
|
||||
$tanggal = $tagihan['tanggal_bayar'];
|
||||
$metode = "API Payment";
|
||||
$kodeunik = $tagihan['kode_unik'];
|
||||
|
||||
// Buat gambar dari file PNG yang ada
|
||||
$stmt = $pdo->prepare("SELECT backround_kwitansi, kabupaten FROM data_server WHERE id = :id");
|
||||
$stmt->bindParam(':id', $tagihan['id_data_server'], PDO::PARAM_INT);
|
||||
$stmt->execute();
|
||||
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$gambarKwitansi = '../img/' . $result['backround_kwitansi']; // Pastikan variabel gambar ada
|
||||
|
||||
// Membuat gambar dari file PNG
|
||||
$img = imagecreatefrompng($gambarKwitansi);
|
||||
// Buat beberapa warna
|
||||
$white = imagecolorallocate($img, 245, 245, 245);
|
||||
$black = imagecolorallocate($img, 0, 0, 0);
|
||||
$orange = imagecolorallocate($img, 0, 0, 128);
|
||||
$fontPath = '../dist/X_10x20_LE.gdf';
|
||||
$font = imageloadfont($fontPath);
|
||||
$line = '_____________________________________________________________________________________';
|
||||
|
||||
// Menambahkan teks ke gambar
|
||||
// imagestring($img, $font, 320, 30, 'KWITANSI PEMBAYARAN', $black);
|
||||
// imagestring($img, 5, 650, 52, 'No. ' . date('Ymd') . $idtag, $black);
|
||||
// imagestring($img, 2, 650, 67, 'Tanggal pembayaran', $black);
|
||||
// imagestring($img, 2, 650, 82, formatIndo(date('Y-m-d'), 'd F Y'), $black);
|
||||
// imagestring($img, 5, 20, 91, $line, $orange);
|
||||
// imagestring($img, 5, 20, 95, $line, $orange);
|
||||
// imagestring($img, 4, 30, 125, 'Telah Diterima Dari', $black);
|
||||
// imagestring($img, 5, 200, 125, ': ' . $nama, $black);
|
||||
// imagestring($img, 4, 30, 150, 'Sejumlah Uang', $black);
|
||||
// imagestring($img, 4, 200, 150, ': ' . terbilang($nominal) . ' rupiah', $black);
|
||||
// imagestring($img, 4, 30, 175, 'Untuk Pembayaran', $black);
|
||||
// imagestring($img, 4, 200, 175, ':', $black);
|
||||
// imagestring($img, 5, 100, 200, $keterangan, $black);
|
||||
// imagestring($img, 5, 20, 245, $line, $orange);
|
||||
// imagestring($img, 5, 50, 280, '___________________________', $orange);
|
||||
// imagestring($img, $font, 70, 300, 'Nominal : Rp. ' . number_format($nominal, 0, ',', '.'), $black);
|
||||
// imagestring($img, 5, 50, 310, '___________________________', $orange);
|
||||
// imagestring($img, 4, 535, 280, $result['kabupaten'] . ', ' . formatIndo(date('Y-m-d'), 'd F Y'), $black);
|
||||
|
||||
$img = imagecreatefrompng($gambarKwitansi);
|
||||
// Buat beberapa warna
|
||||
$white = imagecolorallocate($img, 245, 245, 245);
|
||||
$black = imagecolorallocate($img, 0, 0, 0);
|
||||
$orange = imagecolorallocate($img, 0, 0, 128);
|
||||
$fontPath = '../dist/X_10x20_LE.gdf';
|
||||
$font = imageloadfont($fontPath);
|
||||
$line = '_____________________________________________________________________________________';
|
||||
imagestring($img, $font, 320, 30, 'KWITANSI PEMBAYARAN', $black);
|
||||
imagestring($img, 3, 580, 30, 'No Faktur', $black);
|
||||
imagestring($img, 3, 670, 30, ': '.date('Ymd').$idtag, $black);
|
||||
imagestring($img, 3, 580, 50, 'Tanggal', $black);
|
||||
imagestring($img, 3, 670, 50, ': '.formatIndo(date('Y-m-d'), 'd F Y'), $black);
|
||||
imagestring($img, 3, 580, 70, 'No Pelanggan', $black);
|
||||
imagestring($img, 3, 670, 70, ': '.$user, $black);
|
||||
imagestring($img, 5, 20, 81, $line, $orange);
|
||||
imagestring($img, 5, 20, 85, $line, $orange);
|
||||
imagestring($img, 4, 30, 110, 'Telah Diterima Dari', $black);
|
||||
imagestring($img, 5, 200, 110, ': '.$nama, $black);
|
||||
imagestring($img, 4, 30, 135, 'Sejumlah Uang', $black);
|
||||
imagestring($img, 4, 200, 135, ': '.terbilang($nominal).' rupiah', $black);
|
||||
imagestring($img, 4, 30, 160, 'Untuk Pembayaran', $black);
|
||||
imagestring($img, 4, 200, 160, ': '. $keterangan, $black);
|
||||
imagestring($img, 5, 20, 175, $line, $orange);
|
||||
imagestring($img, 4, 30, 190, 'NO', $black);
|
||||
imagestring($img, 4, 70, 190, 'KETERANGAN', $black);
|
||||
imagestring($img, 4, 620, 190, 'NOMINAL', $black);
|
||||
imagestring($img, 5, 20, 195, $line, $orange);
|
||||
|
||||
imagestring($img, 4, 30, 215, '1', $black);
|
||||
imagestring($img, 4, 70, 215, $paketint, $black);
|
||||
imagestring($img, 4, 620, 215, $jumtagihan, $black);
|
||||
|
||||
if($tagihan['ppn'] != 0 ) {
|
||||
imagestring($img, 4, 30, 235, '2', $black);
|
||||
imagestring($img, 4, 70, 235, 'PPN 11%', $black);
|
||||
imagestring($img, 4, 620, 235, $ppn, $black);
|
||||
}
|
||||
|
||||
if($tagihan['kode_unik'] != 0 ) {
|
||||
imagestring($img, 4, 30, 255, '3', $black);
|
||||
imagestring($img, 4, 70, 255, 'Subsidi', $black);
|
||||
imagestring($img, 4, 620, 255, $subsidi, $black);
|
||||
}
|
||||
|
||||
imagestring($img, 5, 20, 265, $line, $orange);
|
||||
imagestring($img, 4, 550, 290, 'TOTAL', $black);
|
||||
imagestring($img, 4, 620, 290, 'Rp. '.number_format($nominal, 0, ',', '.'), $black);
|
||||
imagestring($img, 5, 550, 300, '__________________________ ', $orange);
|
||||
|
||||
imagestring($img, 5, 50, 320, '______________________________', $orange);
|
||||
imagestring($img, $font, 70, 340, 'Terbilang : Rp. '.number_format($nominal, 0, ',', '.'), $black);
|
||||
imagestring($img, 5, 50, 350, '______________________________', $orange);
|
||||
// Simpan file ke direktori 'invoice'
|
||||
$invoicePath = 'invoice/'.$invoice;
|
||||
|
||||
// echo $invoicePath;
|
||||
// Simpan file ke direktori 'invoice'
|
||||
$invoicePath = '../invoice/' . $invoice;
|
||||
if (!imagepng($img, $invoicePath)) {
|
||||
// echo "<br>" . $invoicePath;
|
||||
die('Gagal menyimpan gambar.');
|
||||
} else {
|
||||
imagedestroy($img); // Hancurkan gambar setelah disimpan
|
||||
|
||||
// Ambil pengaturan Mikrotik
|
||||
$Mikro = $pdo->prepare("SELECT ip_address, port_api, username, password FROM setting_mikrotik WHERE id = :idset");
|
||||
$Mikro->bindParam(':idset', $tagihan['id_setting_mikrotik'], PDO::PARAM_INT);
|
||||
$Mikro->execute();
|
||||
$Mikrot = $Mikro->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// Ambil detail koneksi
|
||||
$m_ip = $Mikrot[0]['ip_address'];
|
||||
$m_user = $Mikrot[0]['username'];
|
||||
$m_pass = $Mikrot[0]['password'];
|
||||
$m_port = $Mikrot[0]['port_api'];
|
||||
|
||||
// Ambil akun pelanggan
|
||||
$hsakun = $tagihan['user_hotspot'];
|
||||
|
||||
// Koneksi ke API Mikrotik
|
||||
$API = new RouterosAPI();
|
||||
$API->debug = false;
|
||||
|
||||
if ($API->connect2($m_ip, $m_user, $m_pass, $m_port)) {
|
||||
// Memproses berdasarkan jenis layanan
|
||||
if ($tagihan['jenis_layanan'] == 'Hotspot') {
|
||||
|
||||
$statuskas = "Pendapatan Hotspot";
|
||||
|
||||
$arrIDh = $API->comm("/ip/hotspot/user/getall", [
|
||||
".proplist" => ".id",
|
||||
"?name" => $hsakun,
|
||||
]);
|
||||
|
||||
if (!empty($arrIDh)) {
|
||||
$API->comm("/ip/hotspot/user/set", [
|
||||
".id" => $arrIDh[0][".id"],
|
||||
"disabled" => "false",
|
||||
]);
|
||||
}
|
||||
// Kalau sudah lebih dari 200, cek jeda 10 menit
|
||||
if ($chatCount >= 200) {
|
||||
if ($now < $updateTime + (10 * 60)) {
|
||||
// Masih dalam masa jeda, skip API key ini
|
||||
$pdo->commit();
|
||||
echo "[PAUSE] API {$keyapi} ditunda sampai " . date('Y-m-d H:i:s', $updateTime + 300) . "\n";
|
||||
continue;
|
||||
} else {
|
||||
|
||||
$statuskas = "Pendapatan PPPOE";
|
||||
|
||||
$arrID = $API->comm("/ppp/secret/getall", [
|
||||
".proplist" => ".id",
|
||||
"?name" => $user,
|
||||
// Reset counter karena sudah lewat 10 menit
|
||||
$chatCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// --- AMBIL PESAN PENDING ---
|
||||
$sql = "
|
||||
SELECT * FROM master_pesan
|
||||
WHERE api_key = :apiKey AND status = 'PENDING'
|
||||
ORDER BY id ASC
|
||||
LIMIT 1
|
||||
FOR UPDATE
|
||||
";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([':apiKey' => $keyapi]);
|
||||
$data = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if ($data) {
|
||||
// Lock pesan jadi PROCESSING
|
||||
$updateProcessing = $pdo->prepare("
|
||||
UPDATE master_pesan
|
||||
SET status = 'PROCESSING'
|
||||
WHERE id = :id AND status = 'PENDING'
|
||||
");
|
||||
$updateProcessing->execute([':id' => $data['id']]);
|
||||
$pdo->commit();
|
||||
|
||||
// --- KIRIM PESAN ---
|
||||
$jenis = $data['jenis_pesan'];
|
||||
$apiurl = $data['api_url'];
|
||||
$datapost = '';
|
||||
|
||||
if ($jenis === "sendMessage") {
|
||||
$datapost = http_build_query([
|
||||
'apiKey' => $data['api_key'],
|
||||
'phone' => $data['nomor'],
|
||||
'message' => $data['pesan']
|
||||
]);
|
||||
|
||||
if (!empty($arrID)) {
|
||||
$API->comm("/ppp/secret/set", [
|
||||
".id" => $arrID[0][".id"],
|
||||
"disabled" => "false",
|
||||
]);
|
||||
}
|
||||
}
|
||||
// Update status pelanggan menjadi aktif
|
||||
$stmt = $pdo->prepare("UPDATE pelanggan SET status = 'aktif' WHERE id = :idpel");
|
||||
$stmt->bindParam(':idpel', $tagihan['id_pelanggan'], PDO::PARAM_INT);
|
||||
$stmt->execute();
|
||||
|
||||
// Update status tagihan dan simpan bukti pembayaran
|
||||
$stmt = $pdo->prepare("UPDATE tagihan SET img_invoice = :inv, status = 'lunas' WHERE id = :idtag");
|
||||
$stmt->bindParam(':inv', $invoice);
|
||||
$stmt->bindParam(':idtag', $idtag, PDO::PARAM_INT);
|
||||
$stmt->execute();
|
||||
|
||||
// Cek transaksi dengan id tagihan
|
||||
$stmt = $pdo->prepare("SELECT id_tagihan FROM transaksi WHERE id_tagihan = :id");
|
||||
$stmt->bindParam(':id', $idtag, PDO::PARAM_INT);
|
||||
$stmt->execute();
|
||||
$tagid = $stmt->fetchColumn();
|
||||
if ($tagid === false) {
|
||||
// Jika tidak ada, insert data transaksi baru
|
||||
$sql = "INSERT INTO transaksi (id_data_server, id_tagihan, id_user_akses, start_time, keterangan, pemasukan, metode_pembayaran, status) VALUES (:idds, :idtag, :idua, :start_time, :keterangan, :pemasukan, :metode, :status)";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->bindParam(':idds', $tagihan['id_data_server'], PDO::PARAM_INT);
|
||||
$stmt->bindParam(':idtag', $idtag, PDO::PARAM_INT);
|
||||
$stmt->bindParam(':idua', $tagihan['id_marketing'], PDO::PARAM_INT);
|
||||
$stmt->bindParam(':start_time', $tanggal);
|
||||
$stmt->bindParam(':keterangan', $tagihan['keterangan']);
|
||||
$stmt->bindParam(':pemasukan', $tagihan['verifikasi_tagihan']);
|
||||
$stmt->bindParam(':metode', $metode);
|
||||
$stmt->bindParam(':status', $statuskas);
|
||||
$stmt->execute();
|
||||
} elseif ($jenis === "sendMediaFromUrl") {
|
||||
$datapost = http_build_query([
|
||||
'apiKey' => $data['api_key'],
|
||||
'phone' => $data['nomor'],
|
||||
'url_file' => $data['url_file'],
|
||||
'as_document' => '0',
|
||||
'caption' => $data['pesan']
|
||||
]);
|
||||
} else {
|
||||
error_log("[INVALID JENIS] Jenis pesan tidak valid: {$jenis} untuk ID {$data['id']}");
|
||||
$pdo->prepare("UPDATE master_pesan SET status = 'GAGAL' WHERE id = :id")
|
||||
->execute([':id' => $data['id']]);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Kirim Pesan WhatsApp
|
||||
$nomor = explode(',', $tagihan['nomor_whatsapp']);
|
||||
$Url = 'https://manjapro.net/invoice/' . $invoice;
|
||||
|
||||
$APIwa = new PesanWA();
|
||||
$APIwa->Create_Pesan($tagihan['id_data_server'], $idtag, 'pesan_melunasi_tagihan', 'tag');
|
||||
$Pesan = $APIwa->Get_Pesan();
|
||||
$APIwa->Send_Pesan($tagihan['id_data_server'], 'sendMediaFromUrl', $nomor, $Pesan, $Url);
|
||||
$curl = curl_init();
|
||||
curl_setopt_array($curl, [
|
||||
CURLOPT_URL => $apiurl . $jenis,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_TIMEOUT => 30,
|
||||
CURLOPT_POST => true,
|
||||
CURLOPT_POSTFIELDS => $datapost,
|
||||
CURLOPT_HTTPHEADER => [
|
||||
'Content-Type: application/x-www-form-urlencoded',
|
||||
'Content-Length: ' . strlen($datapost)
|
||||
],
|
||||
]);
|
||||
|
||||
$response = curl_exec($curl);
|
||||
$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
||||
|
||||
if (curl_errno($curl) || $httpCode >= 400) {
|
||||
error_log("[CURL ERROR] ID {$data['id']}: " . curl_error($curl));
|
||||
$status = 'GAGAL';
|
||||
} else {
|
||||
$rdata = json_decode($response, true);
|
||||
$status = ($rdata && $rdata['code'] == 200) ? 'TERKIRIM' : 'GAGAL';
|
||||
}
|
||||
curl_close($curl);
|
||||
|
||||
// Update status pesan
|
||||
$pdo->prepare("UPDATE master_pesan SET status = :status WHERE id = :id")
|
||||
->execute([':status' => $status, ':id' => $data['id']]);
|
||||
|
||||
// Update log apikey
|
||||
$newCount = ($status === 'TERKIRIM') ? $chatCount + 1 : $chatCount;
|
||||
$sqlLog = "
|
||||
INSERT INTO chat_log_apikey (apikey_whatsapp, chat_count, update_time)
|
||||
VALUES (:apiKey, :chatCount, NOW())
|
||||
ON DUPLICATE KEY UPDATE
|
||||
chat_count = :chatCount,
|
||||
update_time = NOW()
|
||||
";
|
||||
$pdo->prepare($sqlLog)->execute([
|
||||
':apiKey' => $keyapi,
|
||||
':chatCount' => $newCount
|
||||
]);
|
||||
|
||||
echo "[{$status}] ID {$data['id']} untuk API {$keyapi}, count={$newCount}\n";
|
||||
|
||||
} else {
|
||||
$pdo->commit();
|
||||
// tidak ada pesan untuk API key ini
|
||||
}
|
||||
}
|
||||
echo "Flip Lunas" . $tagihan['nama'];
|
||||
} else {
|
||||
echo "Tidak ADA DATA yang lunas";
|
||||
echo "[INFO] Tidak ada API Key aktif untuk Whatsapp Gateway\n";
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
error_log('Database Error: ' . $e->getMessage());
|
||||
echo "Database error occurred."; // Tampilkan pesan kesalahan
|
||||
$pdo->rollBack();
|
||||
error_log("[DB ERROR] " . $e->getMessage());
|
||||
echo "[DB ERROR] " . $e->getMessage() . "\n";
|
||||
} catch (Exception $e) {
|
||||
error_log('General Error: ' . $e->getMessage());
|
||||
echo "An error occurred."; // Tampilkan pesan kesalahan umum
|
||||
$pdo->rollBack();
|
||||
error_log("[GENERAL ERROR] " . $e->getMessage());
|
||||
echo "[ERROR] " . $e->getMessage() . "\n";
|
||||
}
|
||||
?>
|
||||
?>
|
||||
|
||||
@@ -0,0 +1,199 @@
|
||||
<?php
|
||||
// Aktifkan error log
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', 0);
|
||||
ini_set('log_errors', 1);
|
||||
ini_set('error_log', __DIR__ . '/../logs/load_tagihan_flip.log');
|
||||
|
||||
include "../config/connect.php";
|
||||
include "../config/routeros_api.class.php";
|
||||
include "../config/tanggal_indo.php";
|
||||
include "../config/whatsapp_api.php";
|
||||
|
||||
try {
|
||||
// Ambil data tagihan sukses maksimal 5
|
||||
$datetime = date('Y-m-d H:i:s', time() - 60);
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT * FROM v_tagihan_flip_lunas
|
||||
WHERE last_mikrotik_connect > :datetime
|
||||
LIMIT 5
|
||||
");
|
||||
$stmt->execute(['datetime' => $datetime]);
|
||||
$tagihans = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
if ($tagihans) {
|
||||
foreach ($tagihans as $tagihan) {
|
||||
try {
|
||||
$user = $tagihan['akun'];
|
||||
$idtag = $tagihan['id'];
|
||||
$nama = $tagihan['nama'];
|
||||
$nominal = $tagihan['verifikasi_tagihan'];
|
||||
$keterangan = 'Pembayaran ' . $tagihan['keterangan'];
|
||||
$invoice = 'kwitansi_' . date('Ymd') . $idtag . '.png';
|
||||
$paketint = $tagihan['nama_paket'];
|
||||
$jumtagihan = 'Rp. ' . number_format($tagihan['jumlah_tagihan'], 0, ',', '.');
|
||||
$ppn = 'Rp. ' . number_format($tagihan['ppn'], 0, ',', '.');
|
||||
$subsidi = 'Rp. ' . number_format($tagihan['kode_unik'], 0, ',', '.');
|
||||
$tanggal = $tagihan['tanggal_bayar'];
|
||||
$metode = "API Payment";
|
||||
|
||||
// Ambil template kwitansi
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT backround_kwitansi, kabupaten
|
||||
FROM data_server
|
||||
WHERE id = :id
|
||||
");
|
||||
$stmt->bindParam(':id', $tagihan['id_data_server'], PDO::PARAM_INT);
|
||||
$stmt->execute();
|
||||
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if (!$result) {
|
||||
throw new Exception("Template kwitansi tidak ditemukan.");
|
||||
}
|
||||
|
||||
$gambarKwitansi = '../img/' . $result['backround_kwitansi'];
|
||||
if (!file_exists($gambarKwitansi)) {
|
||||
throw new Exception("File kwitansi tidak ditemukan: $gambarKwitansi");
|
||||
}
|
||||
|
||||
// Membuat gambar
|
||||
$img = imagecreatefrompng($gambarKwitansi);
|
||||
$white = imagecolorallocate($img, 245, 245, 245);
|
||||
$black = imagecolorallocate($img, 0, 0, 0);
|
||||
$orange = imagecolorallocate($img, 0, 0, 128);
|
||||
$fontPath = '../dist/X_10x20_LE.gdf';
|
||||
$font = imageloadfont($fontPath);
|
||||
$line = str_repeat('_', 100);
|
||||
|
||||
imagestring($img, $font, 320, 30, 'KWITANSI PEMBAYARAN', $black);
|
||||
imagestring($img, 3, 580, 30, 'No Faktur', $black);
|
||||
imagestring($img, 3, 670, 30, ': ' . date('Ymd') . $idtag, $black);
|
||||
imagestring($img, 3, 580, 50, 'Tanggal', $black);
|
||||
imagestring($img, 3, 670, 50, ': ' . formatIndo(date('Y-m-d')), $black);
|
||||
imagestring($img, 3, 580, 70, 'No Pelanggan', $black);
|
||||
imagestring($img, 3, 670, 70, ': ' . $user, $black);
|
||||
imagestring($img, 5, 20, 81, $line, $orange);
|
||||
imagestring($img, 4, 30, 110, 'Telah Diterima Dari', $black);
|
||||
imagestring($img, 5, 200, 110, ': ' . $nama, $black);
|
||||
imagestring($img, 4, 30, 135, 'Sejumlah Uang', $black);
|
||||
imagestring($img, 4, 200, 135, ': ' . terbilang($nominal) . ' rupiah', $black);
|
||||
imagestring($img, 4, 30, 160, 'Untuk Pembayaran', $black);
|
||||
imagestring($img, 4, 200, 160, ': ' . $keterangan, $black);
|
||||
|
||||
imagestring($img, 4, 30, 215, '1', $black);
|
||||
imagestring($img, 4, 70, 215, $paketint, $black);
|
||||
imagestring($img, 4, 620, 215, $jumtagihan, $black);
|
||||
|
||||
if ($tagihan['ppn'] != 0) {
|
||||
imagestring($img, 4, 30, 235, '2', $black);
|
||||
imagestring($img, 4, 70, 235, 'PPN 11%', $black);
|
||||
imagestring($img, 4, 620, 235, $ppn, $black);
|
||||
}
|
||||
|
||||
if ($tagihan['kode_unik'] != 0) {
|
||||
imagestring($img, 4, 30, 255, '3', $black);
|
||||
imagestring($img, 4, 70, 255, 'Subsidi', $black);
|
||||
imagestring($img, 4, 620, 255, $subsidi, $black);
|
||||
}
|
||||
|
||||
$invoicePath = '../invoice/' . $invoice;
|
||||
if (!imagepng($img, $invoicePath)) {
|
||||
throw new Exception("Gagal menyimpan kwitansi ke $invoicePath");
|
||||
}
|
||||
imagedestroy($img);
|
||||
|
||||
// Aktifkan user Mikrotik
|
||||
$API = new RouterosAPI();
|
||||
$API->debug = false;
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT ip_address, port_api, username, password
|
||||
FROM setting_mikrotik
|
||||
WHERE id = :id
|
||||
");
|
||||
$stmt->execute(['id' => $tagihan['id_setting_mikrotik']]);
|
||||
$mikrotik = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if ($API->connect2($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password'], $mikrotik['port_api'])) {
|
||||
if ($tagihan['jenis_layanan'] == 'Hotspot') {
|
||||
|
||||
$statuskas = "Pendapatan Hotspot";
|
||||
|
||||
$arrIDh = $API->comm("/ip/hotspot/user/getall", [
|
||||
".proplist" => ".id",
|
||||
"?name" => $tagihan['user_hotspot'],
|
||||
]);
|
||||
if (!empty($arrIDh)) {
|
||||
$API->comm("/ip/hotspot/user/set", [
|
||||
".id" => $arrIDh[0][".id"],
|
||||
"disabled" => "false",
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
|
||||
$statuskas = "Pendapatan PPPOE";
|
||||
|
||||
$arrID = $API->comm("/ppp/secret/getall", [
|
||||
".proplist" => ".id",
|
||||
"?name" => $user,
|
||||
]);
|
||||
if (!empty($arrID)) {
|
||||
$API->comm("/ppp/secret/set", [
|
||||
".id" => $arrID[0][".id"],
|
||||
"disabled" => "false",
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update status pelanggan & tagihan
|
||||
$pdo->prepare("UPDATE pelanggan SET status = 'aktif' WHERE id = :id")
|
||||
->execute(['id' => $tagihan['id_pelanggan']]);
|
||||
$pdo->prepare("UPDATE tagihan SET img_invoice = :inv, status = 'lunas' WHERE id = :id")
|
||||
->execute(['inv' => $invoice, 'id' => $idtag]);
|
||||
|
||||
// Kirim WhatsApp dengan kwitansi
|
||||
$nomor = explode(',', $tagihan['nomor_whatsapp']);
|
||||
$urlInvoice = 'https://manjapro.net/invoice/' . $invoice;
|
||||
|
||||
// Cek transaksi dengan id tagihan
|
||||
$stmt = $pdo->prepare("SELECT id_tagihan FROM transaksi WHERE id_tagihan = :id AND metode_pembayaran = :metode");
|
||||
$stmt->bindParam(':id', $idtag, PDO::PARAM_INT);
|
||||
$stmt->bindParam(':metode', $metode);
|
||||
$stmt->execute();
|
||||
$tagid = $stmt->fetchColumn();
|
||||
if ($tagid === false) {
|
||||
// Jika tidak ada, insert data transaksi baru
|
||||
$sql = "INSERT INTO transaksi (id_data_server, id_tagihan, id_user_akses, start_time, keterangan, pemasukan, metode_pembayaran, status) VALUES (:idds, :idtag, :idua, :start_time, :keterangan, :pemasukan, :metode, :status)";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->bindParam(':idds', $tagihan['id_data_server'], PDO::PARAM_INT);
|
||||
$stmt->bindParam(':idtag', $idtag, PDO::PARAM_INT);
|
||||
$stmt->bindParam(':idua', $tagihan['id_marketing'], PDO::PARAM_INT);
|
||||
$stmt->bindParam(':start_time', $tanggal);
|
||||
$stmt->bindParam(':keterangan', $tagihan['keterangan']);
|
||||
$stmt->bindParam(':pemasukan', $tagihan['verifikasi_tagihan']);
|
||||
$stmt->bindParam(':metode', $metode);
|
||||
$stmt->bindParam(':status', $statuskas);
|
||||
$stmt->execute();
|
||||
}
|
||||
|
||||
$APIwa = new PesanWA();
|
||||
$APIwa->Create_Pesan($tagihan['id_data_server'], $idtag, 'pesan_melunasi_tagihan', 'tag');
|
||||
$Pesan = $APIwa->Get_Pesan();
|
||||
$APIwa->Send_Pesan($tagihan['id_data_server'], 'sendMediaFromUrl', $nomor, $Pesan, $urlInvoice);
|
||||
|
||||
echo "[SUCCESS] Tagihan lunas: {$tagihan['nama']} ({$idtag})\n";
|
||||
} catch (Exception $e) {
|
||||
error_log("[ERROR] {$e->getMessage()} untuk tagihan ID {$tagihan['id']}");
|
||||
echo "[ERROR] {$e->getMessage()} untuk tagihan ID {$tagihan['id']}\n";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
echo "[INFO] Tidak ada tagihan flip yang lunas.\n";
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
error_log('[DB ERROR] ' . $e->getMessage());
|
||||
echo "[DB ERROR] " . $e->getMessage() . "\n";
|
||||
} catch (Exception $e) {
|
||||
error_log('[GENERAL ERROR] ' . $e->getMessage());
|
||||
echo "[ERROR] " . $e->getMessage() . "\n";
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
<?php
|
||||
// Aktifkan error log
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', 0);
|
||||
ini_set('log_errors', 1);
|
||||
ini_set('error_log', __DIR__ . '/../logs/load_tagihan_paydisini.log');
|
||||
|
||||
include "../config/connect.php";
|
||||
include "../config/routeros_api.class.php";
|
||||
include "../config/tanggal_indo.php";
|
||||
include "../config/whatsapp_api.php";
|
||||
|
||||
try {
|
||||
// Ambil data tagihan sukses maksimal 5
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT a.id, a.id_tagihan, a.update_time, a.status_check,
|
||||
b.akun, b.nama, b.verifikasi_tagihan, b.keterangan,
|
||||
b.nama_paket, b.jumlah_tagihan, b.ppn, b.kode_unik,
|
||||
b.id_data_server, b.id_setting_mikrotik, b.jenis_layanan,
|
||||
b.user_hotspot, b.id_pelanggan, b.nomor_whatsapp, b.id_marketing
|
||||
FROM client_payment a
|
||||
LEFT JOIN v_tagihan b ON a.id_tagihan = b.id
|
||||
WHERE a.status = 'SUCCESS'
|
||||
AND (a.status_check IS NULL OR a.status_check IN (1,2,3))
|
||||
AND (a.status_check_time IS NULL OR a.status_check_time < NOW())
|
||||
LIMIT 5
|
||||
");
|
||||
$stmt->execute();
|
||||
$tagihans = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
if ($tagihans) {
|
||||
foreach ($tagihans as $tagihan) {
|
||||
try {
|
||||
$user = $tagihan['akun'];
|
||||
$idtag = $tagihan['id_tagihan'];
|
||||
$nama = $tagihan['nama'];
|
||||
$nominal = $tagihan['verifikasi_tagihan'];
|
||||
$keterangan = 'Pembayaran ' . $tagihan['keterangan'];
|
||||
$invoice = 'kwitansi_' . date('Ymd') . $idtag . '.png';
|
||||
$paketint = $tagihan['nama_paket'];
|
||||
$jumtagihan = 'Rp. ' . number_format($tagihan['jumlah_tagihan'], 0, ',', '.');
|
||||
$ppn = 'Rp. ' . number_format($tagihan['ppn'], 0, ',', '.');
|
||||
$subsidi = 'Rp. ' . number_format($tagihan['kode_unik'], 0, ',', '.');
|
||||
$tanggal = $tagihan['update_time'];
|
||||
$metode = "API Payment";
|
||||
|
||||
// Ambil template kwitansi
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT backround_kwitansi, kabupaten
|
||||
FROM data_server
|
||||
WHERE id = :id
|
||||
");
|
||||
$stmt->bindParam(':id', $tagihan['id_data_server'], PDO::PARAM_INT);
|
||||
$stmt->execute();
|
||||
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if (!$result) {
|
||||
throw new Exception("Template kwitansi tidak ditemukan.");
|
||||
}
|
||||
|
||||
$gambarKwitansi = '../img/' . $result['backround_kwitansi'];
|
||||
if (!file_exists($gambarKwitansi)) {
|
||||
throw new Exception("File kwitansi tidak ditemukan: $gambarKwitansi");
|
||||
}
|
||||
|
||||
// Membuat gambar
|
||||
$img = imagecreatefrompng($gambarKwitansi);
|
||||
$white = imagecolorallocate($img, 245, 245, 245);
|
||||
$black = imagecolorallocate($img, 0, 0, 0);
|
||||
$orange = imagecolorallocate($img, 0, 0, 128);
|
||||
$fontPath = '../dist/X_10x20_LE.gdf';
|
||||
$font = imageloadfont($fontPath);
|
||||
$line = str_repeat('_', 100);
|
||||
|
||||
imagestring($img, $font, 320, 30, 'KWITANSI PEMBAYARAN', $black);
|
||||
imagestring($img, 3, 580, 30, 'No Faktur', $black);
|
||||
imagestring($img, 3, 670, 30, ': ' . date('Ymd') . $idtag, $black);
|
||||
imagestring($img, 3, 580, 50, 'Tanggal', $black);
|
||||
imagestring($img, 3, 670, 50, ': ' . formatIndo(date('Y-m-d')), $black);
|
||||
imagestring($img, 3, 580, 70, 'No Pelanggan', $black);
|
||||
imagestring($img, 3, 670, 70, ': ' . $user, $black);
|
||||
imagestring($img, 5, 20, 81, $line, $orange);
|
||||
imagestring($img, 4, 30, 110, 'Telah Diterima Dari', $black);
|
||||
imagestring($img, 5, 200, 110, ': ' . $nama, $black);
|
||||
imagestring($img, 4, 30, 135, 'Sejumlah Uang', $black);
|
||||
imagestring($img, 4, 200, 135, ': ' . terbilang($nominal) . ' rupiah', $black);
|
||||
imagestring($img, 4, 30, 160, 'Untuk Pembayaran', $black);
|
||||
imagestring($img, 4, 200, 160, ': ' . $keterangan, $black);
|
||||
|
||||
imagestring($img, 4, 30, 215, '1', $black);
|
||||
imagestring($img, 4, 70, 215, $paketint, $black);
|
||||
imagestring($img, 4, 620, 215, $jumtagihan, $black);
|
||||
|
||||
if ($tagihan['ppn'] != 0) {
|
||||
imagestring($img, 4, 30, 235, '2', $black);
|
||||
imagestring($img, 4, 70, 235, 'PPN 11%', $black);
|
||||
imagestring($img, 4, 620, 235, $ppn, $black);
|
||||
}
|
||||
|
||||
if ($tagihan['kode_unik'] != 0) {
|
||||
imagestring($img, 4, 30, 255, '3', $black);
|
||||
imagestring($img, 4, 70, 255, 'Subsidi', $black);
|
||||
imagestring($img, 4, 620, 255, $subsidi, $black);
|
||||
}
|
||||
|
||||
$invoicePath = '../invoice/' . $invoice;
|
||||
if (!imagepng($img, $invoicePath)) {
|
||||
throw new Exception("Gagal menyimpan kwitansi ke $invoicePath");
|
||||
}
|
||||
imagedestroy($img);
|
||||
|
||||
// Aktifkan user Mikrotik
|
||||
$API = new RouterosAPI();
|
||||
$API->debug = false;
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT ip_address, port_api, username, password
|
||||
FROM setting_mikrotik
|
||||
WHERE id = :id
|
||||
");
|
||||
$stmt->execute(['id' => $tagihan['id_setting_mikrotik']]);
|
||||
$mikrotik = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if ($API->connect2($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password'], $mikrotik['port_api'])) {
|
||||
if ($tagihan['jenis_layanan'] == 'Hotspot') {
|
||||
|
||||
$statuskas = "Pendapatan Hotspot";
|
||||
|
||||
$arrIDh = $API->comm("/ip/hotspot/user/getall", [
|
||||
".proplist" => ".id",
|
||||
"?name" => $tagihan['user_hotspot'],
|
||||
]);
|
||||
if (!empty($arrIDh)) {
|
||||
$API->comm("/ip/hotspot/user/set", [
|
||||
".id" => $arrIDh[0][".id"],
|
||||
"disabled" => "false",
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
|
||||
$statuskas = "Pendapatan PPPOE";
|
||||
|
||||
$arrID = $API->comm("/ppp/secret/getall", [
|
||||
".proplist" => ".id",
|
||||
"?name" => $user,
|
||||
]);
|
||||
if (!empty($arrID)) {
|
||||
$API->comm("/ppp/secret/set", [
|
||||
".id" => $arrID[0][".id"],
|
||||
"disabled" => "false",
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update status pelanggan & tagihan
|
||||
$pdo->prepare("UPDATE pelanggan SET status = 'aktif' WHERE id = :id")
|
||||
->execute(['id' => $tagihan['id_pelanggan']]);
|
||||
$pdo->prepare("UPDATE tagihan SET img_invoice = :inv, status = 'lunas' WHERE id = :id")
|
||||
->execute(['inv' => $invoice, 'id' => $idtag]);
|
||||
$pdo->prepare("UPDATE client_payment SET status_check_time = NOW(), status_check = 27 WHERE id = :id")
|
||||
->execute(['id' => $tagihan['id']]);
|
||||
|
||||
// Kirim WhatsApp dengan kwitansi
|
||||
$nomor = explode(',', $tagihan['nomor_whatsapp']);
|
||||
$urlInvoice = 'https://manjapro.net/invoice/' . $invoice;
|
||||
|
||||
// Cek transaksi dengan id tagihan
|
||||
$stmt = $pdo->prepare("SELECT id_tagihan FROM transaksi WHERE id_tagihan = :id");
|
||||
$stmt->bindParam(':id', $idtag, PDO::PARAM_INT);
|
||||
$stmt->execute();
|
||||
$tagid = $stmt->fetchColumn();
|
||||
if ($tagid === false) {
|
||||
// Jika tidak ada, insert data transaksi baru
|
||||
$sql = "INSERT INTO transaksi (id_data_server, id_tagihan, id_user_akses, start_time, keterangan, pemasukan, metode_pembayaran, status) VALUES (:idds, :idtag, :idua, :start_time, :keterangan, :pemasukan, :metode, :status)";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->bindParam(':idds', $tagihan['id_data_server'], PDO::PARAM_INT);
|
||||
$stmt->bindParam(':idtag', $idtag, PDO::PARAM_INT);
|
||||
$stmt->bindParam(':idua', $tagihan['id_marketing'], PDO::PARAM_INT);
|
||||
$stmt->bindParam(':start_time', $tanggal);
|
||||
$stmt->bindParam(':keterangan', $tagihan['keterangan']);
|
||||
$stmt->bindParam(':pemasukan', $tagihan['verifikasi_tagihan']);
|
||||
$stmt->bindParam(':metode', $metode);
|
||||
$stmt->bindParam(':status', $statuskas);
|
||||
$stmt->execute();
|
||||
}
|
||||
|
||||
$APIwa = new PesanWA();
|
||||
$APIwa->Create_Pesan($tagihan['id_data_server'], $idtag, 'pesan_melunasi_tagihan', 'tag');
|
||||
$Pesan = $APIwa->Get_Pesan();
|
||||
$APIwa->Send_Pesan($tagihan['id_data_server'], 'sendMediaFromUrl', $nomor, $Pesan, $urlInvoice);
|
||||
|
||||
echo "[SUCCESS] Tagihan lunas: {$tagihan['nama']} ({$idtag})\n";
|
||||
} catch (Exception $e) {
|
||||
error_log("[ERROR] {$e->getMessage()} untuk tagihan ID {$tagihan['id_tagihan']}");
|
||||
echo "[ERROR] {$e->getMessage()} untuk tagihan ID {$tagihan['id_tagihan']}\n";
|
||||
$count_check = $tagihan['status_check'] ?? 0 ;
|
||||
$check = $count_check + 1 ;
|
||||
$datetime = date('Y-m-d H:i:s', time() + 60);
|
||||
$stmt = $pdo->prepare("UPDATE client_payment
|
||||
SET status_check_time = :datetime, status_check = :check
|
||||
WHERE id = :id");
|
||||
$stmt->execute([
|
||||
'datetime' => $datetime,
|
||||
'check' => $check,
|
||||
'id' => $tagihan['id']
|
||||
]);
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
echo "[INFO] Tidak ada tagihan paydisini yang lunas.\n";
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
error_log('[DB ERROR] ' . $e->getMessage());
|
||||
echo "[DB ERROR] " . $e->getMessage() . "\n";
|
||||
} catch (Exception $e) {
|
||||
error_log('[GENERAL ERROR] ' . $e->getMessage());
|
||||
echo "[ERROR] " . $e->getMessage() . "\n";
|
||||
}
|
||||
@@ -1,27 +1,26 @@
|
||||
<?php
|
||||
header('Content-Type: application/json');
|
||||
|
||||
include "../config/connect.php";
|
||||
|
||||
$id = isset($_GET['i']) ? $_GET['i'] : '';
|
||||
$sqlwh = base64_decode($id);
|
||||
// Mengambil data dari database berdasarkan id_data_server
|
||||
|
||||
// Ambil data monitoring
|
||||
$stmt = $pdo->prepare("SELECT * FROM v_data_maps $sqlwh ORDER BY status_koneksi");
|
||||
$stmt->execute();
|
||||
$monitor = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// Ambil data master_topologi
|
||||
$stmtodp = $pdo->prepare("SELECT * FROM master_topologi $sqlwh");
|
||||
$stmtodp->execute();
|
||||
$master = $stmtodp->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// Memeriksa apakah data ditemukan
|
||||
if (!empty($monitor) || !empty($master)) {
|
||||
$data = []; // Array untuk menampung hasil
|
||||
$data = [];
|
||||
|
||||
// Mengisi data dari master_topologi
|
||||
// Isi data dari master_topologi
|
||||
foreach ($master as $odp) {
|
||||
list($lat, $lng) = explode(", ", $odp['titik_koordinat']);
|
||||
|
||||
$data[] = [
|
||||
'nama' => $odp['nama'],
|
||||
'latitude' => floatval($lat),
|
||||
@@ -31,21 +30,24 @@ if (!empty($monitor) || !empty($master)) {
|
||||
];
|
||||
}
|
||||
|
||||
// Mengisi data ke dalam array hasil dari monitor
|
||||
// Isi data dari monitor
|
||||
foreach ($monitor as $row) {
|
||||
$data[] = [
|
||||
'nama' => $row['nama'],
|
||||
'latitude' => floatval($row['latitude']),
|
||||
'longitude' => floatval($row['longitude']),
|
||||
'icon' => ($row['status'] == 'aktif') ?
|
||||
(($row['status_koneksi'] == 'On') ? 'dist/img/ON.png' : 'dist/img/OF.png') :
|
||||
(($row['status_koneksi'] == 'On') ? 'dist/img/ON1.png' : 'dist/img/OF1.png'),
|
||||
'content' => 'User_Id: <b>' . $row['akun'] . '</b><br>User: <b>' . $row['nama'] . '</b><br>login_at: ' . $row['last_on'] . '<br>last_logout: ' . $row['last_off'] . '<br>Status: ' . ($row['status_koneksi'] == 'On' ? 'Connect / '.$row['status'] : 'Disconnect / '.$row['status'])
|
||||
'icon' => ($row['status'] == 'aktif')
|
||||
? (($row['status_koneksi'] == 'On') ? 'dist/img/ON.png' : 'dist/img/OF.png')
|
||||
: (($row['status_koneksi'] == 'On') ? 'dist/img/ON1.png' : 'dist/img/OF1.png'),
|
||||
'content' => 'User_Id: <b>' . $row['akun'] . '</b><br>
|
||||
User: <b>' . $row['nama'] . '</b><br>
|
||||
login_at: ' . $row['last_on'] . '<br>
|
||||
last_logout: ' . $row['last_off'] . '<br>
|
||||
Status: ' . ($row['status_koneksi'] == 'On' ? 'Connect / '.$row['status'] : 'Disconnect / '.$row['status'])
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
// Format data untuk output
|
||||
// Format ulang data
|
||||
$result = array_map(function($item) {
|
||||
return [
|
||||
'lat' => $item['latitude'],
|
||||
@@ -55,11 +57,20 @@ if (!empty($monitor) || !empty($master)) {
|
||||
'content' => $item['content']
|
||||
];
|
||||
}, $data);
|
||||
|
||||
// Mengirimkan data sebagai JSON
|
||||
echo json_encode($result);
|
||||
|
||||
// Tentukan center pakai titik pertama
|
||||
$center = !empty($result) ? ['lat' => $result[0]['lat'], 'lng' => $result[0]['lng']] : null;
|
||||
|
||||
echo json_encode([
|
||||
'status' => true,
|
||||
'centerlonglat' => $center,
|
||||
'data' => $result
|
||||
]);
|
||||
} else {
|
||||
// Jika tidak ada data, kembalikan array kosong
|
||||
echo json_encode([]);
|
||||
echo json_encode([
|
||||
'status' => false,
|
||||
'centerlonglat' => null,
|
||||
'data' => []
|
||||
]);
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>OCR Google Vision</title>
|
||||
<style>
|
||||
body { font-family: sans-serif; padding: 20px; }
|
||||
#preview { max-width: 300px; margin-top: 10px; }
|
||||
textarea { width: 100%; height: 200px; margin-top: 10px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h2>OCR dengan Google Vision API</h2>
|
||||
|
||||
<input type="file" id="imageUpload" accept="image/*"><br>
|
||||
<img id="preview" src=""><br>
|
||||
|
||||
<button onclick="prosesOCR()">Proses OCR</button>
|
||||
|
||||
<h3>Hasil:</h3>
|
||||
<textarea id="hasilText" readonly></textarea>
|
||||
|
||||
<!-- ... sebelumnya sama ... -->
|
||||
|
||||
<script>
|
||||
const API_KEY = 'AIzaSyDb5jNjAc-xZrjdv7oSHmlaESdG8LeDuB0'; // Pastikan valid dan aktif
|
||||
|
||||
let base64Image = '';
|
||||
|
||||
document.getElementById('imageUpload').addEventListener('change', function () {
|
||||
const file = this.files[0];
|
||||
if (!file) return;
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onloadend = function () {
|
||||
base64Image = reader.result.replace(/^data:image\/(png|jpeg|jpg);base64,/, "");
|
||||
document.getElementById('preview').src = reader.result;
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
|
||||
function prosesOCR() {
|
||||
if (!base64Image) {
|
||||
alert("Upload gambar dulu.");
|
||||
return;
|
||||
}
|
||||
|
||||
const requestBody = {
|
||||
requests: [
|
||||
{
|
||||
image: { content: base64Image },
|
||||
features: [{ type: "TEXT_DETECTION" }]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
fetch(`https://vision.googleapis.com/v1/images:annotate?key=${API_KEY}`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(requestBody)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(result => {
|
||||
console.log("Full response:", result); // Debug di sini
|
||||
const res = result.responses[0];
|
||||
const detections = res.fullTextAnnotation?.text || res.textAnnotations?.[0]?.description || 'Tidak ada teks terdeteksi.';
|
||||
document.getElementById('hasilText').value = detections;
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
alert("❌ Gagal proses OCR. Lihat console log.");
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,6 +1,6 @@
|
||||
SV_Cikembar_Utama =><br>
|
||||
SV_BojongKerta =><br>
|
||||
SV_Permata_Sampora =><br>
|
||||
RO Bima Net =><br>
|
||||
SV_Kingnet_Cibadak =><br>
|
||||
SV_CC-Net_Cipicung =><br>
|
||||
SV_Nusaina_Cibadak =><br>
|
||||
@@ -8,7 +8,7 @@ SV_Diamond Net =><br>
|
||||
SV_22P Net Cibadak =><br>
|
||||
SV_Nettizen_Segaranten =><br>
|
||||
SV-DNY-Net-1 =><br>
|
||||
SV_NTA_2_Pasawahan =><br>
|
||||
SV_NTA_2_PSW_1 =><br>
|
||||
SV_NTA_1 =><br>
|
||||
SV-Cicukang =><br>
|
||||
RO-Bumdes-Mekarmanah =><br>
|
||||
@@ -46,3 +46,11 @@ RO - Netborhood Wifi =><br>
|
||||
Neglasari =><br>
|
||||
SV-DNY-Net-2 =><br>
|
||||
DNY-Neglasari =><br>
|
||||
RO_TTO =><br>
|
||||
AP - NET =><br>
|
||||
GAS NET =><br>
|
||||
SV_NTA_2_PSW_2 =><br>
|
||||
chr tencent =><br>
|
||||
DamarisNet =><br>
|
||||
Triunsa =><br>
|
||||
Mikrotik GR 3 =><br>
|
||||
|
||||
@@ -1,17 +1,146 @@
|
||||
<?php
|
||||
<?php
|
||||
// Aktifkan error reporting
|
||||
ini_set('display_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
|
||||
// Koneksi PDO
|
||||
include "../config/connect.php"; // pastikan $pdo sudah ada
|
||||
|
||||
// Daftar id_data_server
|
||||
$idServers = [3, 2, 4, 5, 6, 8, 9, 67, 74, 75, 76];
|
||||
|
||||
// Buat placeholder dinamis
|
||||
$placeholders = implode(',', array_fill(0, count($idServers), '?'));
|
||||
|
||||
// Query select
|
||||
$sql = "SELECT id, nama, email
|
||||
FROM pelanggan
|
||||
WHERE id_data_server IN ($placeholders)";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute($idServers);
|
||||
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
if ($results) {
|
||||
$no = 1;
|
||||
$gmailDomain = '@gmail.com';
|
||||
|
||||
foreach ($results as $row) {
|
||||
$id = $row['id'];
|
||||
$nama = $row['nama'];
|
||||
$email = trim($row['email']);
|
||||
$emailLower = strtolower($email);
|
||||
|
||||
if (!empty($email) && filter_var($email, FILTER_VALIDATE_EMAIL) && substr($emailLower, -strlen($gmailDomain)) === $gmailDomain) {
|
||||
// Email valid dan Gmail
|
||||
if ($email === $emailLower) {
|
||||
// Semua huruf kecil -> hitam (biarkan)
|
||||
$color = "black";
|
||||
echo "$no => $id => $nama => <span style='color:$color;'>" . htmlspecialchars($email) . "</span><br>";
|
||||
} else {
|
||||
// Ada huruf besar -> kuning (UPDATE ke lowercase)
|
||||
$color = "orange";
|
||||
// $update = $pdo->prepare("UPDATE pelanggan SET email = ? WHERE id = ?");
|
||||
// $update->execute([$emailLower, $id]);
|
||||
|
||||
echo "$no => $id => $nama => <span style='color:$color;'>" . htmlspecialchars($email) . "</span> =UPDATED> $emailLower<br>";
|
||||
}
|
||||
} else {
|
||||
// Email tidak valid -> generate baru dan UPDATE
|
||||
$namaClean = strtolower(preg_replace('/[^a-z]/i', '', $nama));
|
||||
$randomNumber = rand(1000, 9999);
|
||||
$newmail = $namaClean . $randomNumber . $gmailDomain;
|
||||
|
||||
// $update = $pdo->prepare("UPDATE pelanggan SET email = ? WHERE id = ?");
|
||||
// $update->execute([$newmail, $id]);
|
||||
|
||||
echo "$no => $id => $nama => <span style='color:red;'>" . htmlspecialchars($email) . "</span> =NEW> $newmail<br>";
|
||||
}
|
||||
|
||||
$no++;
|
||||
}
|
||||
} else {
|
||||
echo "Tidak ada data ditemukan.";
|
||||
}
|
||||
|
||||
|
||||
|
||||
include "../controller/crudRadiusServer.php";
|
||||
|
||||
$radius = new CrudRadiusServer();
|
||||
$radius->request('add_user', 'POST', [
|
||||
'jenis' => 'Hotspot',
|
||||
'username' => 'TESTVCR',
|
||||
'password' => 'TESTVCR',
|
||||
'groupname' => 'paket-6-device-8',
|
||||
'nasgroupname' => 'server8'
|
||||
]);
|
||||
// try {
|
||||
// $bulan = '2025-08';
|
||||
// $tanggal = date('Y-m-d');
|
||||
// $metode = "API Payment";
|
||||
|
||||
// $stmt = $pdo->prepare("
|
||||
// SELECT v_tagihan.*
|
||||
// FROM v_tagihan
|
||||
// LEFT JOIN transaksi ON v_tagihan.id = transaksi.id_tagihan
|
||||
// WHERE transaksi.id_tagihan IS NULL
|
||||
// AND SUBSTRING(v_tagihan.limit_pembayaran, 1, 7) = :bulan
|
||||
// AND v_tagihan.status = 'lunas'
|
||||
// ");
|
||||
// $stmt->bindParam(':bulan', $bulan);
|
||||
// $stmt->execute();
|
||||
|
||||
// $results = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// if (!$results) {
|
||||
// echo "Tidak ada tagihan lunas tanpa transaksi di bulan $bulan.<br>";
|
||||
// exit;
|
||||
// }
|
||||
|
||||
// echo "Memproses " . count($results) . " tagihan lunas tanpa transaksi...<br>";
|
||||
|
||||
// foreach ($results as $index => $tagihan) {
|
||||
// $idtag = $tagihan['id'];
|
||||
// $cek = $pdo->prepare("SELECT id_tagihan FROM transaksi WHERE id_tagihan = :idtag");
|
||||
// $cek->bindParam(':idtag', $idtag, PDO::PARAM_INT);
|
||||
// $cek->execute();
|
||||
|
||||
// if ($cek->fetchColumn() === false) {
|
||||
// $statuskas = $tagihan['jenis_layanan'] === 'Hotspot' ? 'Pendapatan Hotspot' : 'Pendapatan PPPOE';
|
||||
|
||||
// // $insert = $pdo->prepare("
|
||||
// // INSERT INTO transaksi (
|
||||
// // id_data_server, id_tagihan, id_user_akses, start_time,
|
||||
// // keterangan, pemasukan, metode_pembayaran, status
|
||||
// // ) VALUES (
|
||||
// // :idds, :idtag, :idua, :start_time,
|
||||
// // :keterangan, :pemasukan, :metode, :status
|
||||
// // )
|
||||
// // ");
|
||||
// // $insert->bindParam(':idds', $tagihan['id_data_server'], PDO::PARAM_INT);
|
||||
// // $insert->bindParam(':idtag', $tagihan['id'], PDO::PARAM_INT);
|
||||
// // $insert->bindParam(':idua', $tagihan['id_marketing'], PDO::PARAM_INT);
|
||||
// // $insert->bindParam(':start_time', $tanggal);
|
||||
// // $insert->bindParam(':keterangan', $tagihan['keterangan']);
|
||||
// // $insert->bindParam(':pemasukan', $tagihan['verifikasi_tagihan']);
|
||||
// // $insert->bindParam(':metode', $metode);
|
||||
// // $insert->bindParam(':status', $statuskas);
|
||||
// // $insert->execute();
|
||||
|
||||
// echo "[SUKSES] Insert transaksi untuk tagihan ID: {$tagihan['id']} - {$tagihan['nama']} - {$tagihan['nama_server']}<br>";
|
||||
// } else {
|
||||
// echo "[LEWAT] Tagihan ID {$tagihan['id']} sudah ada di transaksi.<br>";
|
||||
// }
|
||||
// }
|
||||
|
||||
// } catch (PDOException $e) {
|
||||
// echo "[PDO ERROR] " . $e->getMessage() . "<br>";
|
||||
// } catch (Exception $e) {
|
||||
// echo "[ERROR] " . $e->getMessage() . "<br>";
|
||||
// }
|
||||
|
||||
|
||||
// include "../controller/crudRadiusServer.php";
|
||||
|
||||
// $radius = new CrudRadiusServer();
|
||||
// $radius->request('add_user', 'POST', [
|
||||
// 'jenis' => 'Hotspot',
|
||||
// 'username' => 'TESTVCR',
|
||||
// 'password' => 'TESTVCR',
|
||||
// 'groupname' => 'paket-6-device-8',
|
||||
// 'nasgroupname' => 'server8'
|
||||
// ]);
|
||||
|
||||
|
||||
// $radius->request('add_user', 'POST', [
|
||||
@@ -133,7 +262,7 @@ $radius->request('add_user', 'POST', [
|
||||
// // $updateStatusOff[] = $idakun;
|
||||
// // }
|
||||
// // }
|
||||
// // echo $row['nama'] . " =><br>\n";
|
||||
// // echo $row['nama'] . " =><br><br>";
|
||||
|
||||
// // // Update status koneksi yang 'On' sekaligus
|
||||
// // if (!empty($updates)) {
|
||||
@@ -157,6 +286,6 @@ $radius->request('add_user', 'POST', [
|
||||
|
||||
// }
|
||||
// } else {
|
||||
// echo "No data found.\n";
|
||||
// echo "No data found.<br>";
|
||||
// }
|
||||
// ?>
|
||||
|
||||
@@ -1 +1 @@
|
||||
Tidak perlu update untuk ID: 2 Rp.200,000<br>Harga khusus untuk ID: 3 Rp.250,000<br>Tidak perlu update untuk ID: 4 Rp.300,000<br>Tidak perlu update untuk ID: 5 Rp.300,000<br>Tidak perlu update untuk ID: 6 Rp.200,000<br>Harga khusus untuk ID: 7 Rp.200,000<br>Tidak perlu update untuk ID: 8 Rp.200,000<br>Tidak perlu update untuk ID: 9 Rp.200,000<br>Tidak perlu update untuk ID: 10 Rp.200,000<br>Tidak perlu update untuk ID: 12 Rp.750,000<br>Tidak perlu update untuk ID: 13 Rp.750,000<br>Tidak perlu update untuk ID: 14 Rp.450,000<br>Tidak perlu update untuk ID: 15 Rp.450,000<br>Tidak perlu update untuk ID: 16 Rp.300,000<br>Harga khusus untuk ID: 17 Rp.300,000<br>Tidak perlu update untuk ID: 18 Rp.300,000<br>Tidak perlu update untuk ID: 19 Rp.450,000<br>Tidak perlu update untuk ID: 20 Rp.200,000<br>Tidak perlu update untuk ID: 21 Rp.300,000<br>Tidak perlu update untuk ID: 22 Rp.300,000<br>Tidak perlu update untuk ID: 23 Rp.450,000<br>Tidak perlu update untuk ID: 24 Rp.200,000<br>Tidak perlu update untuk ID: 25 Rp.250,000<br>Tidak perlu update untuk ID: 26 Rp.200,000<br>Tidak perlu update untuk ID: 28 Rp.200,000<br>Tidak perlu update untuk ID: 29 Rp.300,000<br>Tidak perlu update untuk ID: 30 Rp.200,000<br>Tidak perlu update untuk ID: 31 Rp.200,000<br>Tidak perlu update untuk ID: 32 Rp.200,000<br>Tidak perlu update untuk ID: 33 Rp.200,000<br>Tidak perlu update untuk ID: 34 Rp.200,000<br>Tidak perlu update untuk ID: 35 Rp.200,000<br>Tidak perlu update untuk ID: 36 Rp.200,000<br>Tidak perlu update untuk ID: 37 Rp.300,000<br>Tidak perlu update untuk ID: 38 Rp.200,000<br>Tidak perlu update untuk ID: 39 Rp.200,000<br>Harga khusus untuk ID: 40 Rp.1,000,000<br>Tidak perlu update untuk ID: 41 Rp.200,000<br>Tidak perlu update untuk ID: 42 Rp.200,000<br>Harga khusus untuk ID: 43 Rp.100,000<br>Tidak perlu update untuk ID: 44 Rp.200,000<br>Tidak perlu update untuk ID: 45 Rp.300,000<br>Tidak perlu update untuk ID: 46 Rp.200,000<br>Tidak perlu update untuk ID: 47 Rp.200,000<br>Tidak perlu update untuk ID: 48 Rp.200,000<br>Tidak perlu update untuk ID: 49 Rp.200,000<br>Tidak perlu update untuk ID: 50 Rp.200,000<br>Tidak perlu update untuk ID: 51 Rp.200,000<br>Tidak perlu update untuk ID: 52 Rp.1,000,000<br>Tidak perlu update untuk ID: 53 Rp.200,000<br>Tidak perlu update untuk ID: 54 Rp.200,000<br>Tidak perlu update untuk ID: 55 Rp.200,000<br>Tidak perlu update untuk ID: 56 Rp.200,000<br>Tidak perlu update untuk ID: 57 Rp.200,000<br>Tidak perlu update untuk ID: 58 Rp.200,000<br>Tidak perlu update untuk ID: 59 Rp.200,000<br>Tidak perlu update untuk ID: 60 Rp.200,000<br>Tidak perlu update untuk ID: 61 Rp.300,000<br>Tidak perlu update untuk ID: 62 Rp.200,000<br>Tidak perlu update untuk ID: 63 Rp.200,000<br>Tidak perlu update untuk ID: 64 Rp.200,000<br>Tidak perlu update untuk ID: 65 Rp.200,000<br>Tidak perlu update untuk ID: 66 Rp.200,000<br>Tidak perlu update untuk ID: 67 Rp.200,000<br>Harga khusus untuk ID: 68 Rp.200,000<br>Harga khusus untuk ID: 69 Rp.200,000<br>Tidak perlu update untuk ID: 70 Rp.200,000<br>Tidak perlu update untuk ID: 71 Rp.200,000<br>Tidak perlu update untuk ID: 72 Rp.200,000<br>Tidak perlu update untuk ID: 73 Rp.200,000<br>2399 data pesan sebelum 3 hari terakhir berhasil dihapus.<br>
|
||||
Tidak perlu update untuk ID: 2 Rp.200,000<br>Harga khusus untuk ID: 3 Rp.250,000<br>Tidak perlu update untuk ID: 4 Rp.300,000<br>Tidak perlu update untuk ID: 5 Rp.300,000<br>Tidak perlu update untuk ID: 6 Rp.200,000<br>Harga khusus untuk ID: 7 Rp.200,000<br>Tidak perlu update untuk ID: 8 Rp.200,000<br>Tidak perlu update untuk ID: 9 Rp.200,000<br>Tidak perlu update untuk ID: 10 Rp.200,000<br>Tidak perlu update untuk ID: 12 Rp.750,000<br>Tidak perlu update untuk ID: 13 Rp.750,000<br>Tidak perlu update untuk ID: 14 Rp.450,000<br>Tidak perlu update untuk ID: 15 Rp.450,000<br>Tidak perlu update untuk ID: 16 Rp.300,000<br>Harga khusus untuk ID: 17 Rp.300,000<br>Tidak perlu update untuk ID: 18 Rp.300,000<br>Tidak perlu update untuk ID: 19 Rp.450,000<br>Tidak perlu update untuk ID: 20 Rp.200,000<br>Tidak perlu update untuk ID: 21 Rp.300,000<br>Tidak perlu update untuk ID: 22 Rp.300,000<br>Tidak perlu update untuk ID: 23 Rp.450,000<br>Tidak perlu update untuk ID: 24 Rp.200,000<br>Tidak perlu update untuk ID: 25 Rp.250,000<br>Tidak perlu update untuk ID: 26 Rp.200,000<br>Tidak perlu update untuk ID: 28 Rp.200,000<br>Tidak perlu update untuk ID: 29 Rp.300,000<br>Tidak perlu update untuk ID: 30 Rp.200,000<br>Tidak perlu update untuk ID: 31 Rp.300,000<br>Tidak perlu update untuk ID: 32 Rp.200,000<br>Tidak perlu update untuk ID: 33 Rp.200,000<br>Tidak perlu update untuk ID: 34 Rp.200,000<br>Tidak perlu update untuk ID: 35 Rp.200,000<br>Tidak perlu update untuk ID: 36 Rp.200,000<br>Tidak perlu update untuk ID: 37 Rp.300,000<br>Tidak perlu update untuk ID: 38 Rp.200,000<br>Tidak perlu update untuk ID: 39 Rp.200,000<br>Harga khusus untuk ID: 40 Rp.1,000,000<br>Tidak perlu update untuk ID: 41 Rp.200,000<br>Tidak perlu update untuk ID: 42 Rp.200,000<br>Harga khusus untuk ID: 43 Rp.100,000<br>Tidak perlu update untuk ID: 44 Rp.200,000<br>Tidak perlu update untuk ID: 45 Rp.300,000<br>Tidak perlu update untuk ID: 46 Rp.200,000<br>Tidak perlu update untuk ID: 47 Rp.200,000<br>Tidak perlu update untuk ID: 48 Rp.200,000<br>Tidak perlu update untuk ID: 49 Rp.200,000<br>Tidak perlu update untuk ID: 50 Rp.200,000<br>Tidak perlu update untuk ID: 51 Rp.200,000<br>Tidak perlu update untuk ID: 52 Rp.1,000,000<br>Tidak perlu update untuk ID: 53 Rp.200,000<br>Tidak perlu update untuk ID: 54 Rp.200,000<br>Tidak perlu update untuk ID: 55 Rp.200,000<br>Tidak perlu update untuk ID: 56 Rp.200,000<br>Tidak perlu update untuk ID: 57 Rp.200,000<br>Tidak perlu update untuk ID: 58 Rp.200,000<br>Tidak perlu update untuk ID: 59 Rp.200,000<br>Tidak perlu update untuk ID: 60 Rp.200,000<br>Tidak perlu update untuk ID: 61 Rp.300,000<br>Tidak perlu update untuk ID: 62 Rp.200,000<br>Tidak perlu update untuk ID: 63 Rp.200,000<br>Tidak perlu update untuk ID: 64 Rp.200,000<br>Tidak perlu update untuk ID: 65 Rp.200,000<br>Tidak perlu update untuk ID: 66 Rp.200,000<br>Tidak perlu update untuk ID: 67 Rp.200,000<br>Harga khusus untuk ID: 68 Rp.200,000<br>Harga khusus untuk ID: 69 Rp.200,000<br>Tidak perlu update untuk ID: 70 Rp.200,000<br>Tidak perlu update untuk ID: 71 Rp.200,000<br>Tidak perlu update untuk ID: 72 Rp.200,000<br>Tidak perlu update untuk ID: 73 Rp.200,000<br>Harga khusus untuk ID: 74 Rp.0<br>Harga khusus untuk ID: 75 Rp.0<br>Harga khusus untuk ID: 76 Rp.0<br>Tidak perlu update untuk ID: 77 Rp.200,000<br>Harga khusus untuk ID: 78 Rp.200,000<br>Harga khusus untuk ID: 79 Rp.200,000<br>339 data pesan sebelum 3 hari terakhir berhasil dihapus.<br>
|
||||
@@ -24,15 +24,15 @@ try {
|
||||
}
|
||||
|
||||
// Tentukan harga berdasarkan jumlah_agen
|
||||
if ($data['jumlah_agen'] <= 15) {
|
||||
if ($data['jumlah_agen'] <= 30) {
|
||||
$harga_agen = 200000;
|
||||
} elseif ($data['jumlah_agen'] > 15 && $data['jumlah_agen'] <= 30) {
|
||||
} elseif ($data['jumlah_agen'] > 30 && $data['jumlah_agen'] <= 70) {
|
||||
$harga_agen = 300000;
|
||||
} elseif ($data['jumlah_agen'] > 30 && $data['jumlah_agen'] <= 60) {
|
||||
} elseif ($data['jumlah_agen'] > 70 && $data['jumlah_agen'] <= 120) {
|
||||
$harga_agen = 450000;
|
||||
} elseif ($data['jumlah_agen'] > 60 && $data['jumlah_agen'] <= 90) {
|
||||
} elseif ($data['jumlah_agen'] > 120 && $data['jumlah_agen'] <= 180) {
|
||||
$harga_agen = 750000;
|
||||
} elseif ($data['jumlah_agen'] > 90 && $data['jumlah_agen'] <= 130) {
|
||||
} elseif ($data['jumlah_agen'] > 180 && $data['jumlah_agen'] <= 250) {
|
||||
$harga_agen = 1000000;
|
||||
} else {
|
||||
$harga_agen = 1500000; // Harga default jika jumlah_agen lebih dari 130
|
||||
|
||||
@@ -51,57 +51,7 @@ $stmt = $pdo->prepare("SELECT
|
||||
FROM v_jumlah_transaksi_tahunan WHERE tahun = '$tahun' $SqlDataId");
|
||||
$stmt->execute();
|
||||
$jumtahun = $stmt->fetchAll();
|
||||
// if($SvId == '1') {
|
||||
// $stmt = $pdo->prepare("SELECT SUM(order_aktif) AS order_aktif FROM v_jumlah_order_list ");
|
||||
// $stmt->execute();
|
||||
// $data = $stmt->fetchAll();
|
||||
|
||||
// $stmt = $pdo->prepare("SELECT
|
||||
// SUM(user_regis) AS user_regis,
|
||||
// SUM(user_aktif) AS user_aktif,
|
||||
// SUM(user_tidak_aktif) AS user_tidak_aktif,
|
||||
// SUM(user_konek) AS user_konek,
|
||||
// SUM(user_diskonek) AS user_diskonek
|
||||
// FROM v_jumlah_pelanggan ");
|
||||
// $stmt->execute();
|
||||
// $datauser = $stmt->fetchAll();
|
||||
|
||||
// $stmt = $pdo->prepare("SELECT
|
||||
// SUM(pemasukan) AS pemasukan,
|
||||
// SUM(pengeluaran) AS pengeluaran,
|
||||
// SUM(saldo) AS saldo
|
||||
// FROM v_jumlah_transaksi_bulanan WHERE bulan = '$bulan' ");
|
||||
// $stmt->execute();
|
||||
// $jumbulan = $stmt->fetchAll();
|
||||
|
||||
// $stmt = $pdo->prepare("SELECT
|
||||
// SUM(pemasukan) AS pemasukan,
|
||||
// SUM(pengeluaran) AS pengeluaran,
|
||||
// SUM(saldo) AS saldo
|
||||
// FROM v_jumlah_transaksi_tahunan WHERE tahun = '$tahun' ");
|
||||
// $stmt->execute();
|
||||
// $jumtahun = $stmt->fetchAll();
|
||||
|
||||
// } else {
|
||||
// $stmt = $pdo->prepare("SELECT * FROM v_jumlah_order_list $SqlDataWHId");
|
||||
// $stmt->execute();
|
||||
// $data = $stmt->fetchAll();
|
||||
|
||||
// $stmt = $pdo->prepare("SELECT * FROM v_jumlah_pelanggan $SqlDataWHId");
|
||||
// $stmt->execute();
|
||||
// $datauser = $stmt->fetchAll();
|
||||
|
||||
// $stmt = $pdo->prepare("SELECT * FROM v_jumlah_transaksi_bulanan WHERE bulan = '$bulan' $SqlDataId");
|
||||
// $stmt->execute();
|
||||
// $jumbulan = $stmt->fetchAll();
|
||||
|
||||
// $stmt = $pdo->prepare("SELECT * FROM v_jumlah_transaksi_tahunan WHERE tahun = '$tahun' $SqlDataId");
|
||||
// $stmt->execute();
|
||||
// $jumtahun = $stmt->fetchAll();
|
||||
// }
|
||||
|
||||
// print_r($datauser);
|
||||
// print_r($_SESSION);
|
||||
?>
|
||||
<!-- Main content -->
|
||||
<section class="content">
|
||||
@@ -351,7 +301,7 @@ $stmt = $pdo->prepare("SELECT
|
||||
<div class="card-body">
|
||||
<div class="direct-chat-messages" style="height: 450px">
|
||||
<?php
|
||||
$stmt = $pdo->prepare("SELECT * FROM v_tiket_gangguan WHERE status = '1' $SqlDataId ORDER BY level ASC, start_time DESC");
|
||||
$stmt = $pdo->prepare("SELECT * FROM v_tiket_gangguan WHERE status = '1' $SqlDataId ORDER BY COALESCE(level, 999) ASC, start_time DESC");
|
||||
$stmt->execute();
|
||||
while ($data = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
// Tentukan warna garis berdasarkan level
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
<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>-->
|
||||
<a type="button" class="btn btn-success btn-sm" data-toggle="modal" data-target="#modalpesan">Kirim Pemberitahuan</a>
|
||||
</ol>
|
||||
</div>
|
||||
<!-- Modal Tambah -->
|
||||
@@ -129,6 +130,97 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- END Modal Tambah -->
|
||||
<!-- Modal Pesan Pemberitahuan -->
|
||||
<div class="modal fade" id="modalpesan" data-backdrop="static" data-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-xl">
|
||||
<div class="modal-content">
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="staticBackdropLabel">Tambah Server Aplikasi</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<div class="card-body pb-0">
|
||||
<div class="form-group">
|
||||
<label>Status Server</label>
|
||||
<select class="form-control" name="jenisserver">
|
||||
<option value="0">All Server</option>
|
||||
<option value="1">Aktif</option>
|
||||
<option value="2">Tidak Aktif</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<div class="card-body pb-0">
|
||||
<div class="form-group">
|
||||
<label>Isi Pesan WhatsApp</label>
|
||||
<textarea class="form-control" rows="10" name="isipesan"></textarea>
|
||||
</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="kirimpesan" class="btn btn-primary" value="Tambah">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- END Modal Tambah -->
|
||||
<?php
|
||||
|
||||
if (isset($_POST['kirimpesan'])) {
|
||||
$now = date('Y-m-d'); // Tahun 4 digit
|
||||
|
||||
// Tentukan kondisi WHERE
|
||||
if ($_POST['jenisserver'] == 0) {
|
||||
$wer = "WHERE id != 1";
|
||||
} elseif ($_POST['jenisserver'] == 1) {
|
||||
$wer = "WHERE id != 1 AND expaired_date > :now";
|
||||
} elseif ($_POST['jenisserver'] == 2) {
|
||||
$wer = "WHERE id != 1 AND expaired_date < :now";
|
||||
} else {
|
||||
$wer = "";
|
||||
}
|
||||
|
||||
// Query database (ambil semua nomor)
|
||||
$sql = "SELECT whatsApp FROM data_server $wer";
|
||||
$stm = $pdo->prepare($sql);
|
||||
|
||||
// Bind parameter jika ada kondisi tanggal
|
||||
if ($_POST['jenisserver'] == 1 || $_POST['jenisserver'] == 2) {
|
||||
$stm->bindParam(':now', $now);
|
||||
}
|
||||
|
||||
$stm->execute();
|
||||
$data = $stm->fetchAll(PDO::FETCH_COLUMN); // langsung array nomor
|
||||
|
||||
// Hapus nomor kosong & duplikat
|
||||
$nomorList = array_filter(array_unique($data));
|
||||
|
||||
if (!empty($nomorList)) {
|
||||
$message = $_POST['isipesan'];
|
||||
$APIwa = new PesanWA();
|
||||
|
||||
// Kirim semua nomor sekaligus (array)
|
||||
$APIwa->Send_Pesan(1, 'sendMessage', $nomorList, $message);
|
||||
|
||||
sweetAlert("Pesan akan segera dikirim ke ".count($nomorList)." nomor", "success");
|
||||
} else {
|
||||
sweetAlert("Data nomor WhatsApp tidak ditemukan", "error");
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.card-header -->
|
||||
@@ -138,6 +230,7 @@
|
||||
<tr>
|
||||
<th>No</th>
|
||||
<th>Nama Server</th>
|
||||
<th>Saldo Voucher</th>
|
||||
<th>Alamat</th>
|
||||
<th>Nama Admin</th>
|
||||
<th>Nomor WhatsApp</th>
|
||||
@@ -150,16 +243,17 @@
|
||||
<tbody>
|
||||
<?php
|
||||
$no = 1;
|
||||
$aserver = mysqli_query($con,"SELECT * FROM data_server WHERE id !='1' ORDER BY expaired_date DESC");
|
||||
$aserver = mysqli_query($con,"SELECT * FROM data_server LEFT JOIN v_akumulasi_paygw ON data_server.id=v_akumulasi_paygw.id_data_server WHERE id !='1' ORDER BY expaired_date DESC");
|
||||
while ($server = mysqli_fetch_assoc($aserver))
|
||||
{
|
||||
?>
|
||||
<tr>
|
||||
<td><?php echo $no; ?></td>
|
||||
<td><?php echo $server['nama_server']; ?></td>
|
||||
<td>Rp. <?php echo number_format($server['tersedia']); ?></td>
|
||||
<td style="max-width : 130px;"><?php echo $server['alamat']; ?></td>
|
||||
<td><?php echo $server['nama_pemilik']; ?></td>
|
||||
<td style="max-width : 100px;"><?php echo $server['nomor_whatsapp']; ?></td>
|
||||
<td style="max-width : 100px;"><?php echo $server['whatsapp']; ?></td>
|
||||
<td>Rp. <?php echo number_format($server['harga_sewa']); ?></td>
|
||||
<td><?php
|
||||
if ($server['expaired_date'] >= date('Y-m-d')) { ?>
|
||||
|
||||
@@ -36,6 +36,12 @@ $nomor = $data[0]['nomor_whatsapp'];
|
||||
$username = $data[0]['username'];
|
||||
$email = $data[0]['email'];
|
||||
$profile = $data[0]['profile'];
|
||||
$rek_nomor = $data[0]['rekening_nomor'];
|
||||
$rek_nama = $data[0]['rekening_nama'];
|
||||
$rek_bank = $data[0]['rekening_bank'];
|
||||
$rek_status = $data[0]['rekening_status'];
|
||||
$nama_server = $data[0]['nama_server'];
|
||||
$whatsapp = $data[0]['whatsapp'];
|
||||
// echo "<pre>";
|
||||
// print_r($data);
|
||||
// echo "</pre>";
|
||||
@@ -57,23 +63,30 @@ $profile = $data[0]['profile'];
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.card-header -->
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-5">
|
||||
<div class="card">
|
||||
<div class="card-body" style="margin-bottom: -40px;">
|
||||
<div class="card">
|
||||
<div class="row">
|
||||
<div class="col-md-2">
|
||||
<div class="card-body">
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
<table class="table table-borderless">
|
||||
<center>
|
||||
<label>Foto Profile</label>
|
||||
<div class="uploadImage" data-id="profile" style="width: 25%; zoom: 60%;">
|
||||
<span>Click to upload image</span>
|
||||
<img src="#" alt="Image preview">
|
||||
<div data-id="profile" style="width: 80%; zoom: 60%;">
|
||||
<img src="img/user/<?= $profile; ?>" style="width: 100%; margin-top: 20px;">
|
||||
<div class="progressContainer">
|
||||
<div class="progressBar"></div>
|
||||
</div>
|
||||
</div>
|
||||
</center>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card-body">
|
||||
<table class="table table-borderless">
|
||||
<center>
|
||||
<label>Detail Akun</label>
|
||||
</center>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="p-2">Nama</td>
|
||||
@@ -99,46 +112,10 @@ $profile = $data[0]['profile'];
|
||||
</table>
|
||||
<input type="submit" class="btn btn-sm btn-primary m-1" name="simpan" value="Simpan">
|
||||
</form>
|
||||
|
||||
<?php if (isset($_SESSION['user'])) { ?>
|
||||
|
||||
<button class="btn btn-primary btn-block text-center" id="absenButton" onclick="handleAbsen()">Loading...</button>
|
||||
<script>
|
||||
let absenStatus = 'belum'; // default
|
||||
|
||||
function updateButtonFromStatus() {
|
||||
absenStatus = AndroidInterface.getTrackingStatus();
|
||||
const btn = document.getElementById('absenButton');
|
||||
|
||||
if (absenStatus === 'masuk') {
|
||||
btn.innerText = 'Absen Keluar';
|
||||
} else {
|
||||
btn.innerText = 'Absen Masuk';
|
||||
}
|
||||
}
|
||||
|
||||
function handleAbsen() {
|
||||
const userId = '<?=$id?>';
|
||||
const btn = document.getElementById('absenButton');
|
||||
|
||||
if (absenStatus === 'masuk') {
|
||||
AndroidInterface.stopTracking();
|
||||
absenStatus = 'belum';
|
||||
btn.innerText = 'Absen Masuk';
|
||||
} else {
|
||||
AndroidInterface.startTracking(userId);
|
||||
absenStatus = 'masuk';
|
||||
btn.innerText = 'Absen Keluar';
|
||||
}
|
||||
}
|
||||
|
||||
window.onload = updateButtonFromStatus;
|
||||
</script>
|
||||
|
||||
<?php } ?>
|
||||
|
||||
|
||||
<hr>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card-body">
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
<table class="table table-borderless">
|
||||
<center>
|
||||
@@ -179,8 +156,182 @@ $profile = $data[0]['profile'];
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card-body">
|
||||
|
||||
<?php if($_SESSION['master']) {
|
||||
$readolny = ($rek_status != 'verificated' && $rek_status != 'onverification') ? '' : 'readonly disabled'; ?>
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
<table class="table table-borderless">
|
||||
<center>
|
||||
<label>Rekening Bank
|
||||
<?= ($rek_status == 'onverification')
|
||||
? '<span class="badge badge-warning p-2">On Verification</span>'
|
||||
: (($rek_status == 'verificated')
|
||||
? '<span class="badge badge-success p-2">Verificated</span>'
|
||||
: ''); ?>
|
||||
</label>
|
||||
</center>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="p-2">Bank</td>
|
||||
<td class="p-2">:</td>
|
||||
<td class="p-2">
|
||||
<div class="input-group mb-3">
|
||||
<select class="form-control" id="bank_code" name="bank_code" required <?= $readolny ?>>
|
||||
<option value="">-- PILIH BANK --</option>
|
||||
<option value="bca" <?= ($rek_bank=='bca' ? 'selected' : '') ?>>BCA</option>
|
||||
<option value="bni" <?= ($rek_bank=='bni' ? 'selected' : '') ?>>BNI</option>
|
||||
<option value="bri" <?= ($rek_bank=='bri' ? 'selected' : '') ?>>BRI</option>
|
||||
<option value="mandiri"<?= ($rek_bank=='mandiri' ? 'selected' : '') ?>>Mandiri</option>
|
||||
<option value="bjb" <?= ($rek_bank=='bjb' ? 'selected' : '') ?>>BJB</option>
|
||||
<option value="cimb" <?= ($rek_bank=='cimb' ? 'selected' : '') ?>>CIMB</option>
|
||||
<option value="danamon"<?= ($rek_bank=='danamon' ? 'selected' : '') ?>>Danamon</option>
|
||||
<option value="permata"<?= ($rek_bank=='permata' ? 'selected' : '') ?>>Permata</option>
|
||||
<option value="maybank"<?= ($rek_bank=='maybank' ? 'selected' : '') ?>>Maybank</option>
|
||||
<option value="btn" <?= ($rek_bank=='btn' ? 'selected' : '') ?>>BTN</option>
|
||||
</select>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="p-2">Nomor Rekening</td>
|
||||
<td class="p-2">:</td>
|
||||
<td class="p-2">
|
||||
<div class="input-group mb-3">
|
||||
<input class="form-control" type="text" id="account_number" name="account_number"
|
||||
value="<?= htmlspecialchars($rek_nomor ?? '') ?>" required <?= $readolny ?>>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="p-2">Nama Penerima</td>
|
||||
<td class="p-2">:</td>
|
||||
<td class="p-2">
|
||||
<div class="input-group mb-1">
|
||||
<input class="form-control" type="text" id="account_holder" name="account_holder"
|
||||
value="<?= htmlspecialchars($rek_nama ?? '') ?>" readonly>
|
||||
</div>
|
||||
<span id="testStatusCek"></span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<?= ($rek_status != 'verificated' && $rek_status != 'onverification')
|
||||
? '<input type="submit" class="btn btn-sm btn-primary m-1" name="simpanrekening" value="Simpan">'
|
||||
: ''; ?>
|
||||
<?= ($rek_status == 'onverification')
|
||||
? '<input type="submit" class="btn btn-sm btn-success m-1" name="verifikasirek" value="Verifikasi Rekening">'
|
||||
: ''; ?>
|
||||
|
||||
</form>
|
||||
|
||||
<?php
|
||||
// if (isset($_POST['simpanrekening'])) {
|
||||
// $SQLrek = "UPDATE data_server
|
||||
// SET rekening_bank = :rekening_bank,
|
||||
// rekening_nomor = :rekening_nomor,
|
||||
// rekening_nama = :rekening_nama,
|
||||
// rekening_status = 'onverification'
|
||||
// WHERE id = :iddatas";
|
||||
// $stmt = $pdo->prepare($SQLrek);
|
||||
|
||||
// // pakai bindValue (langsung ambil dari $_POST)
|
||||
// $stmt->bindValue(':rekening_bank', $_POST['bank_code']);
|
||||
// $stmt->bindValue(':rekening_nomor', $_POST['account_number']);
|
||||
// $stmt->bindValue(':rekening_nama', $_POST['account_holder']);
|
||||
// $stmt->bindValue(':iddatas', $id, PDO::PARAM_INT);
|
||||
|
||||
// if ($stmt->execute()) {
|
||||
// $Pesan = "*Permintaan Verifikasi Rekening*
|
||||
|
||||
// Server : " . $nama_server . "
|
||||
// BANK : " . strtoupper($_POST['bank_code']) . "
|
||||
// Rekening : *" . $_POST['account_number'] . "*
|
||||
// Nama Rek : " . strtoupper($_POST['account_holder']) . "
|
||||
|
||||
// status : _*On Verification*_
|
||||
|
||||
|
||||
// _# Manja ~ Notif_
|
||||
// ";
|
||||
// $nomorWA = ['6281298698422', '6285655548738'];
|
||||
// $APIwa = new PesanWA();
|
||||
// $APIwa->Send_Pesan('1','sendMessage',$nomorWA,$Pesan);
|
||||
|
||||
// sweetAlert("BERHASIL.! Rekening telah ditambahkan silahkan tunggu verifikasi", "success");
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
if (isset($_POST['verifikasirek'])) {
|
||||
$SQLrek = "UPDATE data_server
|
||||
SET rekening_status = 'verificated'
|
||||
WHERE id = :iddatas";
|
||||
$stmt = $pdo->prepare($SQLrek);
|
||||
|
||||
$stmt->bindValue(':iddatas', $id, PDO::PARAM_INT);
|
||||
|
||||
$stmt->execute();
|
||||
$Pesanwarek = "*Verifikasi Rekening Berhasil*
|
||||
|
||||
Server : " . $nama_server . "
|
||||
BANK : " . strtoupper($rek_bank) . "
|
||||
Rekening : *" . $rek_nomor . "*
|
||||
Nama Rek : " . $rek_nama . "
|
||||
|
||||
status : _*Verificated*_
|
||||
|
||||
|
||||
_# Manja ~ Notif_
|
||||
";
|
||||
$nomorWArek = ["$whatsapp", "6281298698422", "6285655548738"];
|
||||
$APIwa = new PesanWA();
|
||||
$APIwa->Send_Pesan('1','sendMessage',$nomorWArek,$Pesanwarek);
|
||||
|
||||
sweetAlert("BERHASIL.! Rekening telah di verifikasi", "success");
|
||||
|
||||
}
|
||||
?>
|
||||
|
||||
|
||||
|
||||
<?php } ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="col-md-7">
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<center>
|
||||
<p>Riwayat Pencairan Dana</p>
|
||||
</center>
|
||||
</div>
|
||||
</div>
|
||||
<table id="withdrawTable" class="table table-striped table-bordered" style="zoom: 90%; width: 100%;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Server</th>
|
||||
<th>Dibuat</th>
|
||||
<th>Nominal</th>
|
||||
<th>User</th>
|
||||
<th>Status</th>
|
||||
<th>Diproses</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<?php $data1111 = "123"; if (isset($id) && $data1111 == "123") { ?>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
@@ -335,13 +486,12 @@ $profile = $data[0]['profile'];
|
||||
<th>Priode</th>
|
||||
<th>Nominal</th>
|
||||
<th>Status</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
// Query untuk mengambil data dari tabel apk_payment
|
||||
$stmt = $pdo->prepare("SELECT * FROM apk_payment WHERE id_data_server = :id ORDER BY waktu_transaksi");
|
||||
$stmt = $pdo->prepare("SELECT * FROM apk_payment WHERE id_data_server = :id AND jenis IS NULL ORDER BY waktu_transaksi");
|
||||
$stmt->bindParam(':id', $id);
|
||||
$stmt->execute();
|
||||
|
||||
@@ -355,17 +505,6 @@ $profile = $data[0]['profile'];
|
||||
<td><?php echo htmlspecialchars($row['keterangan']); ?></td>
|
||||
<td><?php echo number_format($row['nominal'], 0, ',', '.'); ?></td>
|
||||
<td><?php echo htmlspecialchars($row['status']); ?></td>
|
||||
<td>
|
||||
<form method="post">
|
||||
<?php if($row['status'] == 'PENDING' || $row['status'] == 'BELUM DIBAYAR') { ?>
|
||||
<a href="payment/paydisini/?order_id=<?php echo htmlspecialchars($row['order_id']); ?>" class="btn btn-sm btn-primary m-1">Bayar</a>
|
||||
<?php if($row['status'] == 'BELUM DIBAYAR') { ?>
|
||||
<input type="submit" name="hapus<?php echo $row['id']; ?>" class="btn btn-sm btn-danger m-1" value="Hapus" >
|
||||
<?php } } else { ?>
|
||||
<a href="payment/paydisini/?order_id=<?php echo htmlspecialchars($row['order_id']); ?>" class="btn btn-sm btn-secondary m-1">Detail</a>
|
||||
<?php } ?>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
if(isset($_POST['hapus'.$row['id']]))
|
||||
@@ -402,6 +541,75 @@ $profile = $data[0]['profile'];
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
<!--START Modal WithDrow-->
|
||||
<div class="modal fade" id="editModal" data-backdrop="static" data-keyboard="false" tabindex="-1" aria-labelledby="editModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<form id="editForm" method="post" enctype="multipart/form-data">
|
||||
<div class="modal-header bg-primary text-white">
|
||||
<h5 class="modal-title" id="staticBackdropLabel">Upload Bukti Success</h5>
|
||||
<button type="button" class="close text-white" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<input type="hidden" name="id" id="editId">
|
||||
<div class="form-group text-center">
|
||||
<label class="form-label d-block">Upload Gambar</label>
|
||||
|
||||
<!-- klik gambar untuk upload -->
|
||||
<img id="previewImg"
|
||||
src="img/imgblank.jpg"
|
||||
class="img-fluid mb-2 rounded border"
|
||||
style="max-height:500px; cursor:pointer;"
|
||||
onclick="document.getElementById('bukti_success').click();">
|
||||
|
||||
<!-- hidden input file -->
|
||||
<input type="file"
|
||||
class="form-control mt-2 d-none"
|
||||
name="bukti_success"
|
||||
id="bukti_success"
|
||||
accept="image/*"
|
||||
required>
|
||||
|
||||
<!-- tampilkan nama file -->
|
||||
<div id="fileName" class="mt-2 text-muted"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||
<button type="submit" class="btn btn-primary">Simpan</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--END Modal WithDrow-->
|
||||
<div class="modal fade" id="viewBuktiModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered" style="max-width: fit-content; margin: auto;">
|
||||
<div class="modal-content border-0 bg-transparent shadow-none" style="width: auto;">
|
||||
<div class="position-relative d-inline-block">
|
||||
|
||||
<!-- Tombol Close -->
|
||||
<button type="button" class="close text-white position-absolute"
|
||||
data-dismiss="modal" aria-label="Close"
|
||||
style="top: 10px; right: 10px; filter: invert(1); z-index: 10;">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
|
||||
<!-- Gambar dari JS -->
|
||||
<img id="viewBuktiImg" src=""
|
||||
class="img-fluid rounded shadow d-block"
|
||||
alt="Bukti Transaksi" style="max-height: 600px;">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<?php
|
||||
// if (isset($_POST['simpanPassword'])) {
|
||||
// if ($_POST['password'] == $_POST['confirm_password']) {
|
||||
@@ -507,4 +715,114 @@ document.querySelectorAll('.toggle-password').forEach(function(toggle) {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$(document).ready(function() {
|
||||
$('#withdrawTable').DataTable({
|
||||
"processing": true,
|
||||
"serverSide": true,
|
||||
"responsive": true,
|
||||
"ajax": {
|
||||
"url": "controller/get_withdrow.php?i=<?= $id; ?>",
|
||||
"type": "POST"
|
||||
},
|
||||
"pageLength": 10,
|
||||
"columns": [
|
||||
{ "data": 0 }, // Server
|
||||
{ "data": 1 }, // Dibuat
|
||||
{ "data": 2 }, // Nominal
|
||||
{ "data": 3 }, // User
|
||||
{
|
||||
"data": 4, // Status
|
||||
"render": function(data, type, row, meta) {
|
||||
if (data === 'pending') {
|
||||
return `<span class="badge bg-primary p-2">${data.toUpperCase()}</span>`;
|
||||
} else {
|
||||
return `<span class="badge bg-success p-2">${data.toUpperCase()}</span>`;
|
||||
}
|
||||
}
|
||||
},
|
||||
{ "data": 5 }, // Diproses
|
||||
{
|
||||
"data": 6, // id unik
|
||||
"render": function(data, type, row, meta) {
|
||||
let btn = "";
|
||||
|
||||
if (row[4] === 'pending') {
|
||||
btn += `<button class="btn btn-sm btn-warning me-1" onclick="editData('${data.id}')">Bayar</button>`;
|
||||
}
|
||||
|
||||
if (row[4] === 'success') {
|
||||
btn += `<button class="btn btn-sm btn-secondary me-1" onclick="viewBukti('${data.bukti_success}')">
|
||||
<i class="fa fa-image"></i>
|
||||
</button>`;
|
||||
}
|
||||
|
||||
return btn;
|
||||
}
|
||||
}
|
||||
],
|
||||
"order": [[1, "desc"]] // urut berdasarkan Dibuat
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Preview gambar saat pilih file
|
||||
document.getElementById("bukti_success").addEventListener("change", function(event){
|
||||
const file = event.target.files[0];
|
||||
if(file){
|
||||
// preview gambar
|
||||
const reader = new FileReader();
|
||||
reader.onload = function(e){
|
||||
document.getElementById("previewImg").src = e.target.result;
|
||||
}
|
||||
reader.readAsDataURL(file);
|
||||
|
||||
// tampilkan nama file
|
||||
document.getElementById("fileName").innerText = file.name;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
function editData(id) {
|
||||
$("#editId").val(id); // set hidden input
|
||||
$("#bukti_success").val(""); // reset file input
|
||||
$("#previewImg").attr("src", "img/imgblank.jpg"); // reset preview
|
||||
$("#editModal").modal("show"); // tampilkan modal
|
||||
}
|
||||
|
||||
function viewBukti(imgPath) {
|
||||
$("#viewBuktiImg").attr("src", imgPath);
|
||||
$("#viewBuktiModal").modal("show");
|
||||
}
|
||||
|
||||
|
||||
// submit form
|
||||
$("#editForm").on("submit", function(e){
|
||||
e.preventDefault();
|
||||
let formData = new FormData(this);
|
||||
|
||||
$.ajax({
|
||||
url: "controller/update_withdraw.php",
|
||||
type: "POST",
|
||||
data: formData,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
success: function(res){
|
||||
try {
|
||||
let json = JSON.parse(res);
|
||||
if(json.success){
|
||||
Swal.fire("Berhasil!", json.message, "success");
|
||||
$("#editModal").modal("hide");
|
||||
$('#withdrawTable').DataTable().ajax.reload(null, false);
|
||||
} else {
|
||||
Swal.fire("Gagal!", json.message, "error");
|
||||
}
|
||||
} catch(e){
|
||||
Swal.fire("Error!", "Response tidak valid: " + res, "error");
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
@@ -1,3 +1,7 @@
|
||||
<?php
|
||||
ini_set('display_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
?>
|
||||
<!-- Main content -->
|
||||
<section class="content">
|
||||
<div class="container-fluid">
|
||||
@@ -11,6 +15,7 @@
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<ol class="float-sm-right mb-0">
|
||||
<a type="button" class="btn btn-secondary btn-sm m-1" data-toggle="modal" data-target="#ModalScript">Ambil Script</a>
|
||||
<a type="button" class="btn btn-danger btn-sm m-1" data-toggle="modal" data-target="#staticBackdrop">Generate</a>
|
||||
</ol>
|
||||
</div>
|
||||
@@ -88,6 +93,7 @@
|
||||
</div>
|
||||
<?php
|
||||
if (isset($_POST['generate'])) {
|
||||
|
||||
try {
|
||||
// Mulai transaksi DB
|
||||
$pdo->beginTransaction();
|
||||
@@ -111,7 +117,7 @@ if (isset($_POST['generate'])) {
|
||||
$data = json_decode($paket['radius_data']);
|
||||
$kode = $data ? 'VR' : 'VM'; // VR = Radius, VM = MikroTik
|
||||
$jenis = $data ? 'sv-radius' : 'sv-mikrotik';
|
||||
$karakter = "QWERTYUIOPASDFGHJKLZXCVBNM1234567890qwertyuiopasdfghjklzxcvbnm";
|
||||
$karakter = "QWERTYUIOPASDFGHJKLZXCVBNM1234567890";
|
||||
$str = $paket['durasi'];
|
||||
$jumlah = intval($_POST['jumlah']);
|
||||
$date = date('Y-m-d H:i:s');
|
||||
@@ -162,7 +168,7 @@ if (isset($_POST['generate'])) {
|
||||
}
|
||||
} else {
|
||||
|
||||
require('router_api/routeros_api.class.php');
|
||||
// require('router_api/routeros_api.class.php');
|
||||
$API = new RouterosAPI();
|
||||
$API->debug = false;
|
||||
|
||||
@@ -221,15 +227,72 @@ if (isset($_POST['generate'])) {
|
||||
sweetAlert("$totalSuccess voucher berhasil dibuat. Gagal: $totalError", "success");
|
||||
} catch (Exception $e) {
|
||||
$pdo->rollBack();
|
||||
// sweetAlert("Gagal membuat voucher: " . $e->getMessage(), "error");
|
||||
sweetAlert("Gagal membuat voucher: " . $e->getMessage(), "error");
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
|
||||
|
||||
<!--START Modal Data Script-->
|
||||
<div class="modal fade" id="ModalScript" data-backdrop="static" data-keyboard="false" tabindex="-1" aria-labelledby="ModalScriptLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered modal-lg">
|
||||
<div class="modal-content">
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
<div class="modal-header bg-secondary">
|
||||
<h5 class="modal-title" id="staticBackdropLabel">Script Tambahan Login Page</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<?php
|
||||
// ambil data server untuk script
|
||||
$ListServer = new Listdata();
|
||||
$ListServer->set_list("setting_mikrotik", $SqlDataWHId);
|
||||
?>
|
||||
<div class="form-group">
|
||||
<label>Nama Server</label>
|
||||
<select class="form-control" name="idmscript" id="idmscript">
|
||||
<?php foreach ($ListServer->get_list() as $value):
|
||||
$radius_data = json_decode($value['radius_nas_data']);
|
||||
$nasgroupname = $radius_data->data->{'nasgroupname'} ?? '';
|
||||
$dataUrl = encrypt_url(json_encode([
|
||||
'board' => $value['board_id'],
|
||||
'nasgroupname' => $nasgroupname
|
||||
]));
|
||||
?>
|
||||
<option value="<?= htmlspecialchars($dataUrl) ?>">
|
||||
<?= htmlspecialchars($value['nama']) ?>
|
||||
</option>
|
||||
<?php endforeach ?>
|
||||
</select>
|
||||
</div>
|
||||
<h6 class="mt-2 mb-2">Login Page Script</h6>
|
||||
<div class="mb-3">
|
||||
<div class="text-right" style="margin-bottom: -33px; margin-right: 2px;">
|
||||
<a onclick="copyToClipboard('script-page')" class="btn btn-sm btn-light btn-icon" title="Copy">
|
||||
<i class="fa fa-copy"></i>
|
||||
</a>
|
||||
</div>
|
||||
<pre class="bg-light border rounded p-3 mb-2" id="script-page">
|
||||
Loading script...
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--END Modal Data Script-->
|
||||
|
||||
|
||||
<!-- /.card-header -->
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-7">
|
||||
<div class="col-md-5">
|
||||
<div class="row">
|
||||
<div class="col-md-3 mb-2">
|
||||
|
||||
@@ -246,7 +309,7 @@ if (isset($_POST['generate'])) {
|
||||
<div class="small-box bg-info" id="penjualanBox">
|
||||
<div class="inner">
|
||||
<h4 id="totalValue">0</h4>
|
||||
<p>Total Penjualan</p>
|
||||
<p><small>Total Penjualan</small></p>
|
||||
</div>
|
||||
<div class="icon">
|
||||
<i class="ion ion-card"></i>
|
||||
@@ -258,19 +321,19 @@ if (isset($_POST['generate'])) {
|
||||
<div class="small-box bg-danger" id="lunasBox">
|
||||
<div class="inner">
|
||||
<h4 id="ditahanValue">0</h4>
|
||||
<p>Saldo Ditahan</p>
|
||||
<p><small>Saldo Ditahan</small></p>
|
||||
</div>
|
||||
<div class="icon">
|
||||
<i class="ion ion-card"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4 col-6">
|
||||
<div class="col-lg-4 col-12">
|
||||
<!-- small box -->
|
||||
<div class="small-box bg-success" id="pendingBox">
|
||||
<div class="inner">
|
||||
<h4 id="tersediaValue">0</h4>
|
||||
<p>Saldo Tersedia</p>
|
||||
<p><small>Saldo Tersedia</small></p>
|
||||
</div>
|
||||
<div class="icon">
|
||||
<i class="ion ion-card"></i>
|
||||
@@ -279,40 +342,302 @@ if (isset($_POST['generate'])) {
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-5">
|
||||
<?php
|
||||
// Ambil semua data Mikrotik langsung
|
||||
$List = new Listdata();
|
||||
$List->set_list("setting_mikrotik", $SqlDataWHId);
|
||||
?>
|
||||
<h6 class="mt-2 mb-2">Mikrotik</h6>
|
||||
<select class="form-control" name="idmscript" id="idmscript">
|
||||
<?php foreach ($List->get_list() as $value):
|
||||
$radius_data = json_decode($value['radius_nas_data']);
|
||||
$nasgroupname = $radius_data->data->{'nasgroupname'} ?? '';
|
||||
$dataUrl = encrypt_url(json_encode([
|
||||
'board' => $value['board_id'],
|
||||
'nasgroupname' => $nasgroupname
|
||||
]));
|
||||
?>
|
||||
<option value="<?= htmlspecialchars($dataUrl) ?>">
|
||||
<?= htmlspecialchars($value['nama']) ?>
|
||||
</option>
|
||||
<?php endforeach ?>
|
||||
</select>
|
||||
<div class="col-md-6">
|
||||
|
||||
<h6 class="mt-2 mb-2">Login Page Script</h6>
|
||||
<div class="mb-3">
|
||||
<div class="text-right" style="margin-bottom: -33px; margin-right: 2px;">
|
||||
<a onclick="copyToClipboard('script-page')" class="btn btn-sm btn-light btn-icon" title="Copy">
|
||||
<i class="fa fa-copy"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-7">
|
||||
<div class="row">
|
||||
<div class="col-md-3 mb-2">
|
||||
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<center>
|
||||
<p>Akumulasi Penjualan Voucher</p>
|
||||
</center>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-2 col-4">
|
||||
<!-- small box -->
|
||||
<div class="small-box bg-success" id="boxgenerateSuccess">
|
||||
<div class="inner">
|
||||
<h4 id="generateSuccess">0</h4>
|
||||
<p><small>Transaksi Success</small></p>
|
||||
</div>
|
||||
<div class="icon">
|
||||
<i class="ion ion-wifi"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-2 col-4">
|
||||
<!-- small box -->
|
||||
<div class="small-box bg-info" id="boxgeneratePending">
|
||||
<div class="inner">
|
||||
<h4 id="generatePending">0</h4>
|
||||
<p><small>Transaksi Pending</small></p>
|
||||
</div>
|
||||
<div class="icon">
|
||||
<i class="ion ion-wifi"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-2 col-4">
|
||||
<!-- small box -->
|
||||
<div class="small-box bg-warning" id="boxgenerateCancel">
|
||||
<div class="inner">
|
||||
<h4 id="generateCancel">0</h4>
|
||||
<p><small>Transaksi Cancel</small></p>
|
||||
</div>
|
||||
<div class="icon">
|
||||
<i class="ion ion-wifi"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-2 col-4">
|
||||
<!-- small box -->
|
||||
<div class="small-box bg-info" id="boxgenerateBelumaktif">
|
||||
<div class="inner">
|
||||
<h4 id="generateBelumaktif">0</h4>
|
||||
<p><small>Voucher Tersedia</small></p>
|
||||
</div>
|
||||
<div class="icon">
|
||||
<i class="ion ion-wifi"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-2 col-4">
|
||||
<!-- small box -->
|
||||
<div class="small-box bg-success" id="boxgenerateAktif">
|
||||
<div class="inner">
|
||||
<h4 id="generateAktif">0</h4>
|
||||
<p><small>Voucher Active</small></p>
|
||||
</div>
|
||||
<div class="icon">
|
||||
<i class="ion ion-wifi"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-2 col-4">
|
||||
<!-- small box -->
|
||||
<div class="small-box bg-danger" id="boxgenerateNonaktif">
|
||||
<div class="inner">
|
||||
<h4 id="generateNonaktif">0</h4>
|
||||
<p><small>Voucher Expired</small></p>
|
||||
</div>
|
||||
<div class="icon">
|
||||
<i class="ion ion-wifi"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-5">
|
||||
<div class="row">
|
||||
<div class="col-md-9">
|
||||
<center>
|
||||
<p>Riwayat Pencairan Dana</p>
|
||||
</center>
|
||||
</div>
|
||||
<div class="col-md-3 mb-2 text-right">
|
||||
<a type="button" class="btn btn-primary btn-sm m-1" data-toggle="modal" data-target="#ModalPencairan">Pencairan Dana</a>
|
||||
</div>
|
||||
</div>
|
||||
<table id="withdrawTable" class="table table-striped table-bordered" style="zoom: 90%; width: 100%;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Server</th>
|
||||
<th>Dibuat</th>
|
||||
<th>Nominal</th>
|
||||
<th>User</th>
|
||||
<th>Status</th>
|
||||
<th>Diproses</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
<div class="col-md-7">
|
||||
<div class="row">
|
||||
<div class="col-md-9">
|
||||
<center>
|
||||
<p>Voucher List</p>
|
||||
</center>
|
||||
</div>
|
||||
<div class="col-md-3 mb-2">
|
||||
<select id="selectStatus" class="form-control form-select form-select-sm">
|
||||
<option value="LUNAS" selected>Lunas</option>
|
||||
<option value="BELUM BAYAR">Pending</option>
|
||||
<option value="CANCELED">Cancel</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<table id="voucherTable" class="table table-striped table-bordered" style="zoom: 90%;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Server</th>
|
||||
<th>Voucher</th>
|
||||
<th>Harga</th>
|
||||
<th>Biaya</th>
|
||||
<th>Saldo</th>
|
||||
<th>Status</th>
|
||||
<th style="max-width: 100px;">Dibuat</th>
|
||||
<th style="max-width: 100px;">Aktif</th>
|
||||
<th style="max-width: 100px;">Expired</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--ISI KONTEN-->
|
||||
|
||||
<!--START Modal WithDrow-->
|
||||
<div class="modal fade" id="ModalPencairan" data-backdrop="static" data-keyboard="false" tabindex="-1" aria-labelledby="ModalPencairanLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
<div class="modal-header bg-primary">
|
||||
<h5 class="modal-title" id="staticBackdropLabel">Pencairan Dana</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="card-body">
|
||||
<?php
|
||||
// ambil data server untuk script
|
||||
$ListServer = new Listdata();
|
||||
$ListServer->set_list("data_server", "WHERE id IN (" . $SvId . ")");
|
||||
?>
|
||||
<div class="form-group">
|
||||
<label>Nama Server</label>
|
||||
<select class="form-control" id="idgetSaldo" name="idgetSaldo">
|
||||
<option value="0">-- PILIH --</option>
|
||||
<?php foreach ($ListServer->get_list() as $value): ?>
|
||||
<option value="<?= htmlspecialchars($value['id']) ?>">
|
||||
<?= htmlspecialchars($value['nama_server']) ?>
|
||||
</option>
|
||||
<?php endforeach ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Saldo</label>
|
||||
<div id="saldoServer" class="mt-2 text-success font-weight-bold" style="font-size: 24px;">Rp. 0</div>
|
||||
</div>
|
||||
<div class="form-group" id="formNominal">
|
||||
<label>Nominal</label>
|
||||
<input type="text" class="form-control rupiah" id="rupiah0" placeholder="Rp. 0" name="nominal" disabled readonly>
|
||||
</div>
|
||||
<i class="text-danger">Dana bisa di cairkan jika Saldo lebih dari Rp 10.000</i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||
<input type="submit" name="cairkan" class="btn btn-primary" value="Cairkan">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--END Modal WithDrow-->
|
||||
|
||||
</div>
|
||||
<!-- /.card-body -->
|
||||
</div>
|
||||
<!-- /.card -->
|
||||
</div>
|
||||
<!-- /.col -->
|
||||
</div>
|
||||
<!-- /.row -->
|
||||
</div>
|
||||
<!-- /.container-fluid -->
|
||||
</section>
|
||||
<!-- /.content -->
|
||||
|
||||
<?php
|
||||
if (isset($_POST['cairkan'])) {
|
||||
|
||||
$SQLCek = "SELECT nama_server, rekening_bank, rekening_nama, rekening_nomor, rekening_status
|
||||
FROM data_server WHERE id = :idsv";
|
||||
$stmt = $pdo->prepare($SQLCek);
|
||||
$stmt->execute([':idsv' => $_POST['idgetSaldo']]);
|
||||
$rek_data = $stmt->fetch(PDO::FETCH_ASSOC); // ✅ fetch single row
|
||||
|
||||
if (!empty($rek_data['rekening_nama'])) {
|
||||
if ($rek_data['rekening_status'] == 'verificated') {
|
||||
|
||||
$nominal = preg_replace("/[^0-9]/", "", $_POST['nominal']);
|
||||
|
||||
$SQLCarikan = "INSERT INTO transaksi_withdraw
|
||||
(id_data_server, start_time, nominal, user_create, status, jenis) VALUES
|
||||
(:id_data_server, :start_time, :nominal, :user_create, 'pending', 'hotspot_auto')";
|
||||
$stmt = $pdo->prepare($SQLCarikan);
|
||||
$stmt->bindValue(':id_data_server', $_POST['idgetSaldo'], PDO::PARAM_INT);
|
||||
$stmt->bindValue(':start_time', date('Y-m-d H:i:s')); // ✅ pakai bindValue
|
||||
$stmt->bindValue(':nominal', $nominal, PDO::PARAM_INT);
|
||||
$stmt->bindValue(':user_create', $SvNama, PDO::PARAM_STR); // pastikan $SvNama ada
|
||||
$stmt->execute();
|
||||
|
||||
$Pesanwarek = "*PERMINTAAN PENCAIRAN DANA*
|
||||
|
||||
Server : " . $rek_data['nama_server'] . "
|
||||
BANK : " . strtoupper($rek_data['rekening_bank']) . "
|
||||
Rekening : *" . $rek_data['rekening_nomor'] . "*
|
||||
Nama Rek : " . $rek_data['rekening_nama'] . "
|
||||
|
||||
Nominal : *" . $_POST['nominal'] . "*
|
||||
|
||||
|
||||
_# Manja ~ Notif_
|
||||
";
|
||||
$nomorWArek = ["6281298698422", "6285655548738"];
|
||||
$APIwa = new PesanWA();
|
||||
$APIwa->Send_Pesan('1','sendMessage',$nomorWArek,$Pesanwarek);
|
||||
|
||||
sweetAlert("BERHASIL.! Pencairan akan segera diproses, mohon tunggu.", "success");
|
||||
} else {
|
||||
sweetAlert("GAGAL.! Rekening anda sedang diverifikasi mohon ditunggu.", "error");
|
||||
}
|
||||
} else {
|
||||
sweetAlert("GAGAL.! Tidak ada rekening yang tersedia, silahkan isi rekening di Profile Master.", "error");
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
|
||||
<!--END Modal WithDrow-->
|
||||
<div class="modal fade" id="viewBuktiModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered" style="max-width: fit-content; margin: auto;">
|
||||
<div class="modal-content border-0 bg-transparent shadow-none" style="width: auto;">
|
||||
<div class="position-relative d-inline-block">
|
||||
|
||||
<!-- Tombol Close -->
|
||||
<button type="button" class="close text-white position-absolute"
|
||||
data-dismiss="modal" aria-label="Close"
|
||||
style="top: 10px; right: 10px; filter: invert(1); z-index: 10;">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
|
||||
<!-- Gambar dari JS -->
|
||||
<img id="viewBuktiImg" src=""
|
||||
class="img-fluid rounded shadow d-block"
|
||||
alt="Bukti Transaksi" style="max-height: 600px;">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<pre class="bg-light border rounded p-3 mb-2" id="script-page">
|
||||
Loading script...
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
|
||||
<script>
|
||||
// Buat script HTML dengan escape karakter agar aman
|
||||
function generateScript(dataUrl) {
|
||||
@@ -344,78 +669,13 @@ function copyToClipboard(preId) {
|
||||
</script>
|
||||
|
||||
|
||||
</div>
|
||||
<div class="col-md-7">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-5">
|
||||
<div class="row">
|
||||
<div class="col-md-3 mb-2">
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<center>
|
||||
<p>Voucher List</p>
|
||||
</center>
|
||||
</div>
|
||||
</div>
|
||||
<table id="voucherTable" class="table table-striped table-bordered" style="zoom: 90%;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Server</th>
|
||||
<th>Voucher</th>
|
||||
<th>Harga</th>
|
||||
<th>Biaya</th>
|
||||
<th>Saldo</th>
|
||||
<th>Status</th>
|
||||
<th>Dibuat</th>
|
||||
<th>Aktif</th>
|
||||
<th>Expired</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--ISI KONTEN-->
|
||||
|
||||
</div>
|
||||
<!-- /.card-body -->
|
||||
</div>
|
||||
<!-- /.card -->
|
||||
</div>
|
||||
<!-- /.col -->
|
||||
</div>
|
||||
<!-- /.row -->
|
||||
</div>
|
||||
<!-- /.container-fluid -->
|
||||
</section>
|
||||
<!-- /.content -->
|
||||
|
||||
<script>
|
||||
// // Fungsi untuk menetapkan bulan saat ini sebagai nilai default di dropdown
|
||||
// function setDefaultMonth() {
|
||||
// // Dapatkan bulan dan tahun saat ini
|
||||
// var now = new Date();
|
||||
// var currentMonth = now.getMonth() + 1; // getMonth() menghasilkan bulan 0-11, jadi kita tambahkan 1
|
||||
// var currentYear = now.getFullYear();
|
||||
|
||||
// // Format bulan dalam format YYYY-MM
|
||||
// var currentMonthString = currentYear + '-' + (currentMonth < 10 ? '0' + currentMonth : currentMonth);
|
||||
|
||||
// // Atur nilai default pada dropdown
|
||||
// document.getElementById('pilihBulan').value = currentMonthString;
|
||||
|
||||
// // Panggil fungsi untuk mengambil data berdasarkan bulan saat ini
|
||||
// fetchDataAgen();
|
||||
// }
|
||||
|
||||
// Fungsi untuk mengambil data agen berdasarkan bulan yang dipilih
|
||||
function fetchDataAgen() {
|
||||
|
||||
// Ambil nilai ID dan generate_time dari server-side (misalnya dari halaman PHP sebelumnya)
|
||||
var idDataServer = <?php echo $SvId; ?>; // Ganti dengan ID yang sesuai atau ambil dari variabel PHP
|
||||
var idDataServer = "<?php echo encrypt_url($SvId); ?>"; // Ganti dengan ID yang sesuai atau ambil dari variabel PHP
|
||||
|
||||
// Buat request dengan menggunakan XMLHttpRequest
|
||||
var xhr = new XMLHttpRequest();
|
||||
@@ -437,10 +697,12 @@ function copyToClipboard(preId) {
|
||||
var total = parseFloat(data.total) || 0;
|
||||
var ditahan = parseFloat(data.ditahan) || 0;
|
||||
var tersedia = parseFloat(data.tersedia) || 0;
|
||||
// var jumlah_voucher = parseInt(data.total_voucher) || 0;
|
||||
// var jumlah_voucher_belum_aktif = parseInt(data.total_voucher_belum_aktif) || 0;
|
||||
// var jumlah_voucher_aktif = parseInt(data.total_voucher_aktif) || 0;
|
||||
// var jumlah_voucher_expaired = parseInt(data.total_voucher_expaired) || 0;
|
||||
var jum_lunas = parseInt(data.jum_lunas) || 0;
|
||||
var jum_pending = parseInt(data.jum_pending) || 0;
|
||||
var jum_cancel = parseInt(data.jum_cancel) || 0;
|
||||
var jum_belum_aktif = parseInt(data.jum_belum_aktif) || 0;
|
||||
var jum_aktif = parseInt(data.jum_aktif) || 0;
|
||||
var jum_nonaktif = parseInt(data.jum_nonaktif) || 0;
|
||||
|
||||
// Format angka dengan pemisah ribuan
|
||||
total = total.toLocaleString();
|
||||
@@ -451,10 +713,12 @@ function copyToClipboard(preId) {
|
||||
document.getElementById('totalValue').innerText = "Rp. "+total;
|
||||
document.getElementById('ditahanValue').innerText = "Rp. "+ditahan;
|
||||
document.getElementById('tersediaValue').innerText = "Rp. "+tersedia;
|
||||
// document.getElementById('jumtotalValue').innerText = jumlah_voucher.toLocaleString();
|
||||
// document.getElementById('jumbelumValue').innerText = jumlah_voucher_belum_aktif.toLocaleString();
|
||||
// document.getElementById('jumsedangValue').innerText = jumlah_voucher_aktif.toLocaleString();
|
||||
// document.getElementById('jumsudahValue').innerText = jumlah_voucher_expaired.toLocaleString();
|
||||
document.getElementById('generateSuccess').innerText = jum_lunas;
|
||||
document.getElementById('generatePending').innerText = jum_pending;
|
||||
document.getElementById('generateCancel').innerText = jum_cancel;
|
||||
document.getElementById('generateBelumaktif').innerText = jum_belum_aktif;
|
||||
document.getElementById('generateAktif').innerText = jum_aktif;
|
||||
document.getElementById('generateNonaktif').innerText = jum_nonaktif;
|
||||
} else {
|
||||
// Jika data tidak ditemukan atau kosong
|
||||
document.getElementById('result').innerHTML = "Tidak ada data untuk bulan yang dipilih.";
|
||||
@@ -476,31 +740,147 @@ function copyToClipboard(preId) {
|
||||
|
||||
|
||||
<script>
|
||||
|
||||
$(document).ready(function() {
|
||||
$('#voucherTable').DataTable({
|
||||
var defaultStatus = $('#selectStatus').val(); // ambil default (LUNAS)
|
||||
|
||||
var table = $('#voucherTable').DataTable({
|
||||
"processing": true,
|
||||
"serverSide": true,
|
||||
"responsive": true,
|
||||
"autoWidth": false,
|
||||
"ajax": {
|
||||
"url": "controller/voucher_auto.php?i=<?= $SvId; ?>",
|
||||
"url": "controller/voucher_auto.php?i=<?= $SvId; ?>&s=" + defaultStatus,
|
||||
"type": "GET"
|
||||
},
|
||||
"pageLength": 25,
|
||||
"pageLength": 10,
|
||||
"columns": [
|
||||
{ "data": 0 }, // create_time
|
||||
{ "data": 0 }, // server
|
||||
{ "data": 1 }, // voucher
|
||||
{ "data": 2 }, // harga
|
||||
{ "data": 3, "orderable": false }, // biaya (tidak bisa diurutkan)
|
||||
{ "data": 4, "orderable": false }, // saldo (tidak bisa diurutkan)
|
||||
{ "data": 5 }, // status_cek
|
||||
{ "data": 6 },
|
||||
{ "data": 7 }, // active_time
|
||||
{ "data": 8 } // expaired_time
|
||||
{ "data": 3, "orderable": false }, // biaya
|
||||
{ "data": 4, "orderable": false }, // saldo
|
||||
{ "data": 5 }, // status
|
||||
{ "data": 6 }, // dibuat
|
||||
{ "data": 7 }, // aktif
|
||||
{ "data": 8 } // expired
|
||||
],
|
||||
"order": [[0, "desc"]]
|
||||
});
|
||||
|
||||
// Reload data saat status berubah
|
||||
$('#selectStatus').on('change', function() {
|
||||
table.ajax.url("controller/voucher_auto.php?i=<?= $SvId; ?>&s=" + $(this).val()).load();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
$(document).ready(function() {
|
||||
$('#withdrawTable').DataTable({
|
||||
"processing": true,
|
||||
"serverSide": true,
|
||||
"responsive": true,
|
||||
"ajax": {
|
||||
"url": "controller/get_withdrow.php?i=<?= $SvId; ?>&s=hotspot_auto",
|
||||
"type": "POST"
|
||||
},
|
||||
"pageLength": 10,
|
||||
"columns": [
|
||||
{ "data": 0 }, // Server
|
||||
{ "data": 1 }, // Dibuat
|
||||
{ "data": 2 }, // Nominal
|
||||
{ "data": 3 }, // User
|
||||
{
|
||||
"data": 4, // Status
|
||||
"render": function(data, type, row, meta) {
|
||||
if (data === 'pending') {
|
||||
return `<span class="badge bg-primary p-2">${data.toUpperCase()}</span>`;
|
||||
} else {
|
||||
return `<span class="badge bg-success p-2">${data.toUpperCase()}</span>`;
|
||||
}
|
||||
}
|
||||
},
|
||||
{ "data": 5 }, // Diproses
|
||||
{
|
||||
"data": 6, // id unik
|
||||
"render": function(data, type, row, meta) {
|
||||
let btn = "";
|
||||
|
||||
if (row[4] === 'success') {
|
||||
btn += `<button class="btn btn-sm btn-secondary me-1" onclick="viewBukti('${data.bukti_success}')">
|
||||
<i class="fa fa-image"></i>
|
||||
</button>`;
|
||||
}
|
||||
|
||||
return btn;
|
||||
}
|
||||
}
|
||||
],
|
||||
"order": [[1, "desc"]] // urut berdasarkan Dibuat
|
||||
});
|
||||
});
|
||||
|
||||
// function viewBukti Transaksi
|
||||
function viewBukti(imgPath) {
|
||||
$("#viewBuktiImg").attr("src", imgPath);
|
||||
$("#viewBuktiModal").modal("show");
|
||||
}
|
||||
|
||||
$(document).ready(function(){
|
||||
var currentSaldo = 0; // simpan saldo terakhir
|
||||
|
||||
$("#idgetSaldo").on("change", function(){
|
||||
var serverId = $(this).val();
|
||||
var $nominalInput = $("#formNominal input");
|
||||
|
||||
if(serverId == 0){
|
||||
$("#saldoServer").html("Rp. 0");
|
||||
$nominalInput.prop("disabled", true).prop("readonly", true).val("");
|
||||
currentSaldo = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: "controller/get_saldo.php",
|
||||
type: "GET",
|
||||
data: { id: serverId },
|
||||
dataType: "json",
|
||||
success: function(res){
|
||||
if(res && res.saldo !== undefined){
|
||||
currentSaldo = parseInt(res.saldo) || 0;
|
||||
$("#saldoServer").html("Rp. " + new Intl.NumberFormat().format(currentSaldo));
|
||||
|
||||
if(currentSaldo < 10000){
|
||||
$nominalInput.prop("disabled", true).prop("readonly", true).val("");
|
||||
} else {
|
||||
$nominalInput.prop("disabled", false).prop("readonly", false);
|
||||
}
|
||||
} else {
|
||||
$("#saldoServer").html("Rp. 0");
|
||||
$nominalInput.prop("disabled", true).prop("readonly", true).val("");
|
||||
currentSaldo = 0;
|
||||
}
|
||||
},
|
||||
error: function(){
|
||||
$("#saldoServer").html("Gagal mengambil saldo");
|
||||
$nominalInput.prop("disabled", true).prop("readonly", true).val("");
|
||||
currentSaldo = 0;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Cek saat user input nominal
|
||||
$("#formNominal input").on("input", function(){
|
||||
var val = parseInt($(this).val().replace(/\D/g, '')) || 0; // ambil angka aja
|
||||
if(val > currentSaldo){
|
||||
val = currentSaldo; // batasin maksimal saldo
|
||||
}
|
||||
$(this).val(val); // set kembali ke input
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<script>
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
$db1 = mysqli_query($con,"SELECT SUBSTRING(nomor_invoice,-4) AS num FROM invoice WHERE id_data_server = '$pc2[id_data_server]' ORDER BY nomor_invoice DESC Limit 1");
|
||||
$pc1 = mysqli_fetch_assoc($db1);
|
||||
$urutan = $pc1['num'] + 1;
|
||||
$num = date('ym').'0000' + $urutan;
|
||||
$num = (date('ym').'0000') + $urutan;
|
||||
$nomorinv = "INV".$num;
|
||||
$input = mysqli_query($con,"INSERT INTO invoice (id_data_server, id_customer, nomor_invoice, tanggal_invoice, limit_invoice)
|
||||
VALUES ('$pc2[id_data_server]', '$_POST[id_customer]', '$nomorinv', '$_POST[tanggal_invoice]', '$_POST[limit_invoice]')");
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
$db1 = mysqli_query($con,"SELECT SUBSTRING(nomor_invoice,-4) AS num FROM invoice WHERE id_data_server = '$pc2[id_data_server]' ORDER BY nomor_invoice DESC Limit 1");
|
||||
$pc1 = mysqli_fetch_assoc($db1);
|
||||
$urutan = $pc1['num'] + 1;
|
||||
$num = date('ym').'0000' + $urutan;
|
||||
$num = (date('ym').'0000') + $urutan;
|
||||
$nomorinv = "INV".$num;
|
||||
$input = mysqli_query($con,"INSERT INTO invoice (id_data_server, id_customer, nomor_invoice, tanggal_invoice, limit_invoice)
|
||||
VALUES ('$pc2[id_data_server]', '$_POST[id_customer]', '$nomorinv', '$_POST[tanggal_invoice]', '$_POST[limit_invoice]')");
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
<div class="row">
|
||||
<div class="col-4">
|
||||
<div class="dropdown dropright">
|
||||
<a href="excel/export.php" id="export-button" class="btn btn-success btn-sm mr-2">
|
||||
<a href="#" id="export-button" class="btn btn-success btn-sm mr-2">
|
||||
<i class="fas fa-file-excel mr-2"></i>Export
|
||||
</a>
|
||||
<!-- <button type="submit" class="btn btn-success btn-sm mr-2"><i class="fas fa-file-excel mr-2"></i>Export</button> -->
|
||||
|
||||
@@ -88,11 +88,11 @@
|
||||
</div>
|
||||
<!-- /.card-header -->
|
||||
<div class="card-body">
|
||||
<table id="example2" class="table table-bordered table-striped">
|
||||
<table id="example22" class="table table-bordered table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Nama Server</th>
|
||||
<th>Waktu</th>
|
||||
<th>Nama Server</th>
|
||||
<th>Nomor</th>
|
||||
<th>Pesan</th>
|
||||
<th>Url Image</th>
|
||||
@@ -102,11 +102,12 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
$apaket = mysqli_query($con, "SELECT * FROM master_pesan $SqlDataWHId ORDER BY waktu DESC, id DESC LIMIT 500");
|
||||
$apaket = mysqli_query($con, "SELECT * FROM master_pesan $SqlDataWHId ORDER BY waktu DESC LIMIT 500");
|
||||
while ($paket = mysqli_fetch_assoc($apaket))
|
||||
{
|
||||
?>
|
||||
<tr>
|
||||
<td style="max-width: 200px;"><?php echo $paket['waktu']; ?></td>
|
||||
<td>
|
||||
<?php
|
||||
$asv = mysqli_query($con,"SELECT nama_server FROM data_server WHERE id = '$paket[id_data_server]'");
|
||||
@@ -114,13 +115,12 @@
|
||||
echo $sv['nama_server'];
|
||||
?>
|
||||
</td>
|
||||
<td style="max-width: 200px;"><?php echo $paket['waktu']; ?></td>
|
||||
<td><?php echo $paket['nomor']; ?></td>
|
||||
<td style="max-width: 300px;"><?php echo $paket['pesan']; ?></td>
|
||||
<td style="max-width: 200px;"><?php echo $paket['url_file']; ?></td>
|
||||
<td><?php echo $paket['status']; ?></td>
|
||||
<td>
|
||||
<?php if($paket['status'] == 'GAGAL') { ?>
|
||||
<?php if($paket['status'] == 'GAGAL' || $paket['status'] == 'TERKIRIM') { ?>
|
||||
<form method="post">
|
||||
<input type="submit" name="ulangi<?php echo $paket['id']; ?>" class="btn btn-primary btn-sm" value="Ulangi">
|
||||
</a>
|
||||
@@ -149,4 +149,14 @@
|
||||
</div>
|
||||
<!-- /.container-fluid -->
|
||||
</section>
|
||||
<!-- /.content -->
|
||||
<!-- /.content -->
|
||||
<script>
|
||||
$(function () {
|
||||
$("#example22").DataTable({
|
||||
"responsive": true,
|
||||
"autoWidth": false,
|
||||
"pageLength": 100,
|
||||
"order": [[0, "desc"]] // Kolom pertama urut DESC
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -27,63 +27,6 @@
|
||||
</section>
|
||||
|
||||
<script>
|
||||
let map; // Variabel untuk menyimpan peta
|
||||
const markers = []; // Array untuk menyimpan marker
|
||||
|
||||
function initMap() {
|
||||
// Inisialisasi peta dengan tipe hybrid
|
||||
map = new google.maps.Map(document.getElementById('map'), {
|
||||
center: { lat: -7.062083, lng: 106.797390 }, // Pusat peta
|
||||
zoom: 11,
|
||||
mapTypeId: 'hybrid' // Menentukan tipe peta menjadi hybrid
|
||||
});
|
||||
|
||||
// Fetch data dari PHP saat pertama kali
|
||||
fetchMarkers();
|
||||
|
||||
// Mengatur interval untuk memperbarui marker setiap 10 detik
|
||||
setInterval(fetchMarkers, 30000);
|
||||
}
|
||||
|
||||
function fetchMarkers() {
|
||||
fetch('load/maps_marker.php?i=<?php echo base64_encode($SqlDataWHIdM); ?>')
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error('Network response was not ok ' + response.statusText);
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(markersData => {
|
||||
// Hapus marker yang ada sebelumnya
|
||||
markers.forEach(marker => marker.setMap(null));
|
||||
markers.length = 0; // Kosongkan array marker
|
||||
|
||||
// Tambahkan marker baru ke peta
|
||||
markersData.forEach(markerData => {
|
||||
const markerInstance = new google.maps.Marker({
|
||||
position: { lat: markerData.lat, lng: markerData.lng },
|
||||
map: map,
|
||||
title: markerData.title,
|
||||
icon: {
|
||||
url: markerData.icon, // Menggunakan ikon dari data
|
||||
scaledSize: new google.maps.Size(30, 30) // Mengatur ukuran ikon
|
||||
}
|
||||
});
|
||||
|
||||
// Simpan marker ke array
|
||||
markers.push(markerInstance);
|
||||
|
||||
// Event listener untuk klik marker
|
||||
markerInstance.addListener('click', () => {
|
||||
const infoWindow = new google.maps.InfoWindow();
|
||||
infoWindow.setContent(markerData.content); // Set konten InfoWindow
|
||||
infoWindow.open(map, markerInstance); // Tampilkan InfoWindow
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(error => console.error('Error fetching markers:', error));
|
||||
}
|
||||
|
||||
// Inisialisasi peta saat halaman selesai dimuat
|
||||
window.onload = initMap;
|
||||
const topologiId = "<?php echo base64_encode($SqlDataWHIdM); ?>";
|
||||
</script>
|
||||
<script type="text/javascript" src="dist/js/mapsTopologi.js"></script>
|
||||
|
||||
@@ -0,0 +1,204 @@
|
||||
<?php
|
||||
// ubah string jadi array
|
||||
$idArray = array_map('trim', explode(',', $SvId));
|
||||
|
||||
// buat placeholders (?, ?, ?)
|
||||
$placeholders = implode(',', array_fill(0, count($idArray), '?'));
|
||||
|
||||
$sql = "SELECT uuid FROM data_server WHERE id IN ($placeholders)";
|
||||
$stm = $pdo->prepare($sql);
|
||||
$stm->execute($idArray);
|
||||
|
||||
$uuids = $stm->fetchAll(PDO::FETCH_COLUMN); // ambil langsung kolom uuid
|
||||
$tenant_id = implode(',', $uuids); // gabungkan jadi string dipisah koma
|
||||
|
||||
// --- Panggil API pakai tenant_id ---
|
||||
$oltData = [];
|
||||
if ($tenant_id) {
|
||||
$apiUrl = "http://manjapro.net:20263/api/v1/olt/?tenant_id=" . $tenant_id;
|
||||
$ch = curl_init();
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_URL => $apiUrl,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_HTTPHEADER => ["accept: application/json"]
|
||||
]);
|
||||
$response = curl_exec($ch);
|
||||
if (curl_errno($ch)) {
|
||||
$apiError = curl_error($ch);
|
||||
}
|
||||
curl_close($ch);
|
||||
$oltData = json_decode($response, true);
|
||||
}
|
||||
|
||||
$oltVendor = [];
|
||||
|
||||
$apiUrl = "http://manjapro.net:20263/api/v1/olt-vendor/";
|
||||
$ch = curl_init();
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_URL => $apiUrl,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_HTTPHEADER => ["accept: application/json"]
|
||||
]);
|
||||
$resvendor = curl_exec($ch);
|
||||
if (curl_errno($ch)) {
|
||||
$apiError = curl_error($ch);
|
||||
}
|
||||
curl_close($ch);
|
||||
$oltVendor = json_decode($resvendor, true);
|
||||
|
||||
foreach ($oltVendor as $vendor) {
|
||||
$vendorMap[$vendor['id']] = $vendor['nama_vendor'] . " (" . $vendor['model'] . ")" ;
|
||||
}
|
||||
// print_r($oltVendor);
|
||||
|
||||
?>
|
||||
|
||||
<section class="content">
|
||||
<div class="container-fluid mt-4">
|
||||
<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">List OLT</h3>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<ol class="float-sm-right mb-0">
|
||||
<button type="button" class="btn btn-danger btn-sm" data-toggle="modal" data-target="#modalTambah">Tambah</button>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<!--<h3 class="card-title">List OLT</h3>-->
|
||||
<!--<button type="button" class="btn btn-danger btn-sm" data-toggle="modal" data-target="#modalTambah">Tambah</button>-->
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<?php if (!empty($apiError)): ?>
|
||||
<div class="alert alert-danger">Gagal ambil data API: <?= htmlspecialchars($apiError) ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<table id="example2" class="table table-bordered table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>No</th>
|
||||
<th>Nama Perangkat</th>
|
||||
<th>IP</th>
|
||||
<th>Lokasi</th>
|
||||
<th>Vendor</th>
|
||||
<th>Port SNMP</th>
|
||||
<th>Port Telnet</th>
|
||||
<th>Status</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (!empty($oltData) && is_array($oltData)): ?>
|
||||
<?php $no=1; foreach($oltData as $olt): ?>
|
||||
<tr>
|
||||
<td><?= $no++; ?></td>
|
||||
<td><?= htmlspecialchars($olt['name'] ?? '-') ?></td>
|
||||
<td><?= htmlspecialchars($olt['ip'] ?? '-') ?></td>
|
||||
<td><?= htmlspecialchars($olt['location'] ?? '-') ?></td>
|
||||
<td><?= htmlspecialchars($vendorMap[$olt['vendor_id']] ?? '-') ?></td>
|
||||
<td><?= htmlspecialchars($olt['snmp_port'] ?? '-') ?></td>
|
||||
<td><?= htmlspecialchars($olt['telnet_port'] ?? '-') ?></td>
|
||||
<td>
|
||||
<?php if (($olt['status'] ?? '') === 'online'): ?>
|
||||
<span class="badge badge-success">Online</span>
|
||||
<?php elseif (($olt['status'] ?? '') === 'offline'): ?>
|
||||
<span class="badge badge-danger">Offline</span>
|
||||
<?php else: ?>
|
||||
<span class="badge badge-secondary"><?= htmlspecialchars($olt['status'] ?? '-') ?></span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<a href="#" class="btn btn-warning btn-sm">Edit</a>
|
||||
<a href="#" class="btn btn-danger btn-sm">Hapus</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php else: ?>
|
||||
<tr><td colspan="6" class="text-center">Data tidak tersedia</td></tr>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Modal Tambah -->
|
||||
<div class="modal fade" id="modalTambah" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<form method="post">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-primary">
|
||||
<h5 class="modal-title">Tambah OLT</h5>
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<input type="hidden" name="tenant_id" value="<?= htmlspecialchars($tenant_id) ?>">
|
||||
<div class="form-group">
|
||||
<label>Nama</label>
|
||||
<input type="text" name="name" class="form-control" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>IP</label>
|
||||
<input type="text" name="ip" class="form-control" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Lokasi</label>
|
||||
<input type="text" name="location" class="form-control">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Nama Vendor</label>
|
||||
<select class="form-control">
|
||||
<option value="">--PILIH--</option>
|
||||
<?php foreach ($oltVendor as $row): ?>
|
||||
<option value="<?= $row['id'] ?>">
|
||||
<?= $row['nama_vendor'] ?> (<?= $row['model'] ?>)
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" name="tambah" class="btn btn-primary">Simpan</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
// === Handle Tambah Data (POST ke API) ===
|
||||
if (isset($_POST['tambah'])) {
|
||||
$postData = [
|
||||
"tenant_id" => $_POST['tenant_id'],
|
||||
"name" => trim($_POST['name']),
|
||||
"ip" => trim($_POST['ip']),
|
||||
"snmp_community" => "public",
|
||||
"telnet_user" => "root",
|
||||
"telnet_pass" => "admin",
|
||||
"vendor_id" => (int)$_POST['vendor_id'],
|
||||
"location" => trim($_POST['location']),
|
||||
"snmp_port" => 161,
|
||||
"telnet_port" => 23
|
||||
];
|
||||
$ch = curl_init("http://manjapro.net:20263/api/v1/olt/");
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_POST => true,
|
||||
CURLOPT_HTTPHEADER => ["Content-Type: application/json"],
|
||||
CURLOPT_POSTFIELDS => json_encode($postData)
|
||||
]);
|
||||
$res = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
|
||||
// setelah simpan redirect supaya tidak POST ulang
|
||||
header("Location: ".$_SERVER['PHP_SELF']."?id=".urlencode($SvId));
|
||||
exit;
|
||||
}
|
||||
?>
|
||||