Update Banyak

This commit is contained in:
WD - Dev
2025-09-21 21:40:17 +07:00
parent c6bee729c5
commit efca8f5f80
145 changed files with 195185 additions and 1378 deletions
+5 -5
View File
@@ -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() {
+5 -5
View File
@@ -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) {
+244 -1
View File
@@ -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;
}
+5 -5
View File
@@ -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() {
+4
View File
@@ -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);
?>
+5 -5
View File
@@ -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) {
+18
View File
@@ -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";
?>
+31 -1
View File
@@ -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>
+21 -1
View File
@@ -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 {
+23
View File
@@ -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);
}
+39
View File
@@ -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.";
}
}
+76
View File
@@ -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));
+3 -1
View File
@@ -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);
+105
View File
@@ -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
]);
+21
View File
@@ -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]);
}
+172
View File
@@ -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"]);
+104
View File
@@ -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
]);
+111
View File
@@ -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
]);
+158
View File
@@ -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);
+48
View File
@@ -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];
}
}
+223
View File
@@ -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']]);
}
}
}
}
+56
View File
@@ -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
]);
}
+78
View File
@@ -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);
+29 -12
View File
@@ -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,
];
}
+53 -181
View File
@@ -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');
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

+168
View File
@@ -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);
};
}));
+1
View File
@@ -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)}});
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 299 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 420 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 696 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 618 B

+14419
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+14512
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+661
View File
@@ -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;
}
}
+40
View File
@@ -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);
}
}
+6
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+208
View File
@@ -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}`;
});
});
+99
View File
@@ -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
});
};
+133
View File
@@ -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;
+8 -2
View File
@@ -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">
+199
View File
@@ -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>
+160
View File
@@ -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>
';
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 616 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

+1 -1
View File
@@ -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);
+40 -23
View File
@@ -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']);
}
?>
+60 -12
View File
@@ -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 515 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);
+1
View File
@@ -0,0 +1 @@
{"status":"error","message":"Tidak dapat terhubung ke RouterOS"}
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -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([
+94 -58
View File
@@ -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();
}
?>
+71
View File
@@ -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>";
+116
View File
@@ -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
+250
View File
@@ -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));
}
+1
View File
@@ -0,0 +1 @@
[2025-09-21 21:36:01] Tidak ada remote expired.
+26
View File
@@ -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";
}
+1
View File
@@ -0,0 +1 @@
[2025-09-20 23:50:02] 0 data telah dihapus. Data tersisa sejak 2025-08-01 00:00:00 sampai sekarang.
+17
View File
@@ -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
+38
View File
@@ -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);
}
+1
View File
@@ -0,0 +1 @@
Voucher: CCU7DPArBx5nR<br>Aktif => 2025-09-21 21:38:11<br>Expaired => 2025-09-28 21:38:11<br>
+23 -15
View File
@@ -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.
+23 -1
View File
@@ -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
+2 -2
View File
@@ -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";
}
}
+132 -315
View File
@@ -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";
}
?>
?>
+199
View File
@@ -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";
}
+219
View File
@@ -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";
}
+29 -18
View File
@@ -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' => []
]);
}
?>
+78
View File
@@ -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>
+10 -2
View File
@@ -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>
+141 -12
View File
@@ -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
View File
@@ -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>
+5 -5
View File
@@ -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
+1 -51
View File
@@ -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
+96 -2
View File
@@ -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">&times;</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')) { ?>
+380 -62
View File
@@ -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">&times;</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">&times;</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>
+503 -123
View File
@@ -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">&times;</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">&times;</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">&times;</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>
+1 -1
View File
@@ -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]')");
+1 -1
View File
@@ -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]')");
+1 -1
View File
@@ -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> -->
+16 -6
View File
@@ -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>
+2 -59
View File
@@ -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>
+204
View File
@@ -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">&times;</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;
}
?>

Some files were not shown because too many files have changed in this diff Show More