Add remaining project files (exclude ignored folders)

This commit is contained in:
WD - Dev
2025-07-05 15:11:40 +07:00
parent a96eb2b958
commit b440b80882
4697 changed files with 1365702 additions and 0 deletions
+47
View File
@@ -0,0 +1,47 @@
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
header('Content-Type: application/json');
include "/www/wwwroot/bilspro/config/connect.php";
// Validasi metode
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
echo json_encode(['success' => false, 'message' => 'Metode tidak diperbolehkan']);
exit;
}
// Validasi input
$order_id = $_POST['order_id'] ?? '';
if (empty($order_id)) {
echo json_encode(['success' => false, 'message' => 'Order ID tidak ditemukan']);
exit;
}
// Cek status dari database
$stmt = $pdo->prepare("SELECT status FROM apk_payment WHERE order_id = :order_id");
$stmt->bindParam(':order_id', $order_id);
$stmt->execute();
$data = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$data) {
echo json_encode(['success' => false, 'message' => 'Transaksi tidak ditemukan']);
exit;
}
$status = strtoupper($data['status']);
if (in_array($status, ['SUCCESS', 'PENDING', 'CANCELED', 'LUNAS'])) {
echo json_encode([
'success' => true,
'status' => ucfirst(strtolower($status)) // Output: Success, Pending, etc.
]);
} else {
echo json_encode([
'success' => false,
'message' => 'Status tidak dikenali: ' . $status
]);
}
+98
View File
@@ -0,0 +1,98 @@
(function () {
// Ambil router_id dari <script src="?router_id=...">
function getRouterIdFromScriptSrc() {
const script = document.currentScript;
if (script && script.src) {
const url = new URL(script.src);
return url.searchParams.get("router_id");
}
return null;
}
const routerId = getRouterIdFromScriptSrc() || "unknown";
console.log("Halaman login diakses dari MikroTik:", routerId);
document.addEventListener("DOMContentLoaded", function () {
const container = document.getElementById("voucher-container");
if (container) {
const iframe = document.createElement("iframe");
iframe.id = "voucherFrame";
iframe.src = "https://manjapro.net/voucherpay/?id=" + encodeURIComponent(routerId);
iframe.style.width = "100%";
iframe.style.border = "none";
iframe.style.display = "block";
iframe.setAttribute("scrolling", "no");
container.appendChild(iframe);
}
// Cek jika status sudah "Lunas", isi otomatis input login
const status = localStorage.getItem("status");
const voucher = localStorage.getItem("voucher");
if (status === "Lunas" && voucher) {
console.log("Mendeteksi status Lunas, mengisi otomatis input dengan voucher:", voucher);
const inputs = [
document.querySelector('#voucher'),
document.querySelector('input[name="username"]'),
document.querySelector('input[name="password"]')
];
inputs.forEach((input, i) => {
if (input) {
input.value = voucher;
console.log(`Input otomatis (${input.name || input.id}): ${voucher}`);
}
});
// Cegah reload berulang dengan flag khusus
if (!sessionStorage.getItem("voucher_reloaded")) {
sessionStorage.setItem("voucher_reloaded", "1");
console.log("Melakukan reload sekali untuk mengaktifkan form login");
location.reload();
}
}
});
// Terima pesan tinggi dari iframe dan isi otomatis voucher jika lunas
window.addEventListener("message", function (event) {
const data = event.data;
// Atur tinggi iframe jika ada
if (typeof data === "object" && data.frameHeight) {
const iframe = document.getElementById("voucherFrame");
if (iframe) {
iframe.style.height = data.frameHeight + "px";
console.log("Iframe height disesuaikan:", data.frameHeight);
}
}
// Isi voucher otomatis dan reload
if (data.type === "voucher_paid" && data.voucher) {
console.log("Menerima voucher_paid dari iframe:", data.voucher);
// localStorage.setItem("status", "Lunas");
// localStorage.setItem("voucher", data.voucher);
const inputs = [
document.querySelector('#voucher'),
document.querySelector('input[name="username"]'),
document.querySelector('input[name="password"]')
];
inputs.forEach((input, i) => {
if (input) {
input.value = data.voucher;
console.log(`Input dari iframe (${input.name || input.id}): ${data.voucher}`);
}
});
// Reload supaya auto-fill login aktif
if (!sessionStorage.getItem("voucher_reloaded")) {
sessionStorage.setItem("voucher_reloaded", "1");
console.log("Melakukan reload sekali untuk auto login");
location.reload();
}
}
});
})();
+281
View File
@@ -0,0 +1,281 @@
<?php
include "/www/wwwroot/bilspro/config/connect.php";
include "/www/wwwroot/bilspro/payment/paydisini/api_control.php";
if (!isset($_GET['id']) || empty($_GET['id'])) {
die("ID tidak valid");
}
$board_id = $_GET['id'];
$stmt = $pdo->prepare("SELECT * FROM setting_mikrotik WHERE board_id = :board_id");
$stmt->bindParam(':board_id', $board_id, PDO::PARAM_STR);
$stmt->execute();
$servers = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Daftar Voucher</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="voucher-container" id="voucher-container">
<!-- Konten akan diisi melalui JavaScript berdasarkan localStorage -->
</div>
<script>
function tampilkanKonfirmasi(nama, harga, ids, idm, idv) {
const container = document.getElementById('voucher-container');
container.innerHTML = `
<div class="confirm-wrapper">
<div class="confirm-box">
<h3 class="confirm-title">Konfirmasi Pembelian</h3>
<p class="confirm-nama">${nama}</p>
<p class="confirm-harga">Rp ${harga.toLocaleString()}</p>
<div class="confirm">
<input type="text" id="waInput" placeholder="0812xxxxxxx" />
<p class="confirm-info">Masukkan nomor WhatsApp untuk menerima kode voucher</p>
</div>
<div class="button-group">
<button class="btn-submit" onclick="kirimPembayaran(${ids}, ${idm}, ${idv})">Bayar</button>
<button class="btn-cancel" onclick="resetPembayaran()">Kembali</button>
</div>
</div>
</div>
`;
localStorage.setItem("harga", harga);
localStorage.setItem("nama", nama);
kirimHeight();
}
function resetPembayaran() {
localStorage.clear();
window.location.reload();
}
function countDown(expiredTimeString) {
const targetDate = new Date(expiredTimeString.replace(" ", "T"));
const countdownElement = document.getElementById("countdown");
if (!countdownElement) return;
const countdownFunction = setInterval(() => {
const now = new Date().getTime();
const distance = targetDate.getTime() - now;
if (distance <= 0) {
clearInterval(countdownFunction);
countdownElement.textContent = "Waktu habis, memeriksa status pembayaran...";
cekstatusPembayaran();
return;
}
const hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((distance % (1000 * 60)) / 1000);
let countdownText = "";
if (hours > 0) countdownText += hours + " jam ";
if (minutes > 0 || hours > 0) countdownText += minutes + " menit ";
countdownText += seconds + " detik";
countdownElement.textContent = countdownText;
}, 1000);
}
function kirimPembayaran(ids, idm, idv) {
const wa = document.getElementById('waInput').value.trim();
if (!wa.match(/^[0-9]{10,15}$/)) {
alert("Nomor WhatsApp tidak valid");
return;
}
const box = document.querySelector(".confirm-box");
box.innerHTML = `
<p style="margin-bottom:10px;">Memproses pembayaran...</p>
<p>Mohon tunggu sebentar.</p>
`;
fetch("payment.php", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
body: `ids=${encodeURIComponent(ids)}&idm=${encodeURIComponent(idm)}&idv=${encodeURIComponent(idv)}&wa=${encodeURIComponent(wa)}`
})
.then(response => response.text())
.then(text => {
try {
const data = JSON.parse(text);
if (data.success) {
localStorage.setItem("status", "Pending");
localStorage.setItem("voucher", data.voucher);
localStorage.setItem("exppay", data.exppay);
localStorage.setItem("order_id", data.order_id);
localStorage.setItem("qr", data.qr);
tampilkanQR(data.qr, data.exppay);
} else {
box.innerHTML = `<p style="color:red;">${data.message}</p>`;
}
} catch (e) {
box.innerHTML = `<p style="color:red;">Respon tidak valid:<br>${text}</p>`;
}
})
.catch(error => {
box.innerHTML = `<p style="color:red;">Terjadi kesalahan: ${error}</p>`;
});
}
function cekstatusPembayaran() {
const order_id = localStorage.getItem("order_id");
if (!order_id) {
console.log("ID pembayaran tidak ditemukan.");
return;
}
fetch("cek_status.php", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
body: `order_id=${encodeURIComponent(order_id)}`
})
.then(response => response.text()) // Tangkap sebagai teks dulu untuk debug
.then(text => {
try {
const data = JSON.parse(text);
console.log("Response dari cek_status.php:", data);
if (!data.success) {
console.log("Cek status gagal:", data.message || "Tidak diketahui");
if (data.raw_response) console.log("Raw Response:", data.raw_response);
return;
}
const status = data.status;
if (status === "Lunas") {
localStorage.setItem("status", "Lunas");
tampilkanSukses(localStorage.getItem("nama"), "Rp " + localStorage.getItem("harga"), localStorage.getItem("voucher"));
} else if (status === "Pending") {
alert("Pembayaran masih diproses.");
} else if (status === "Canceled" || status === "Failed") {
alert("Pembayaran dibatalkan atau gagal.");
resetPembayaran();
} else {
console.log("Status tidak dikenali:", status);
}
} catch (err) {
console.log("Gagal parse JSON:", err);
console.log("Respon mentah:", text);
}
})
.catch(err => {
console.log("Gagal melakukan request cek status:", err);
});
}
function tampilkanQR(qrUrl, expPay) {
const container = document.getElementById("voucher-container");
container.innerHTML = `
<div class="confirm-wrapper">
<div class="confirm-box">
<p style="font-size: 12px;">Silakan melakukan pembayaran dengan QRIS di bawah ini</p>
<img src="${qrUrl}" alt="QR Code" style="max-width: 180px;">
<p style="font-size: 14px;" id="countdown"></p>
<p style="font-size: 12px;">Kode voucher akan dikirim ke WhatsApp setelah pembayaran berhasil.</p>
<div class="button-group">
<button class="btn-cancel" onclick="resetPembayaran()">Batal</button>
<button class="btn-submit" onclick="cekstatusPembayaran()">Cek Status</button>
</div>
</div>
</div>
`;
countDown(expPay);
kirimHeight();
}
function tampilkanSukses(nama, harga, kodeVoucher) {
const container = document.getElementById("voucher-container");
container.innerHTML = `
<div class="confirm-wrapper">
<div class="confirm-box">
<div class="confirm-title">Pembayaran ${nama} ${harga}</div>
<div class="confirm-harga">BERHASIL</div>
<div class="confirm-info">Kode Voucher</div>
<h3>${kodeVoucher}</h3>
<div class="confirm-info">Silakan masukan kode voucher di atas</div>
<div class="button-group">
<button class="btn-cancel" onclick="resetPembayaran()">Tutup</button>
</div>
</div>
</div>
`;
kirimHeight();
}
function tampilkanListVoucher() {
const data = <?php
$output = [];
if (!empty($servers)) {
$id_data_server = $servers[0]['id_data_server'];
$stmt = $pdo->prepare("SELECT * FROM profile_paket WHERE jenis_profile = 'Hotspot' AND status = '1' AND id_data_server = :id_data_server");
$stmt->bindParam(':id_data_server', $id_data_server, PDO::PARAM_INT);
$stmt->execute();
$paket = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($paket as $p) {
$output[] = [
'nama' => htmlspecialchars($p['nama']),
'harga' => (int)$p['harga_paket'],
'ids' => (int)$p['id_data_server'],
'idm' => (int)$servers[0]['id'],
'idv' => (int)$p['id']
];
}
}
echo json_encode($output);
?>;
const container = document.getElementById("voucher-container");
container.innerHTML = "";
if (data.length === 0) {
container.innerHTML = "<p>Data Mikrotik tidak ditemukan.</p>";
return;
}
data.forEach(p => {
const html = `
<div class="voucher-box">
<div class="voucher-info">
<div class="voucher-desc">${p.nama}</div>
<div class="voucher-title">Rp. ${p.harga.toLocaleString()}</div>
</div>
<button class="btn-bayar" onclick="tampilkanKonfirmasi('${p.nama}', ${p.harga}, ${p.ids}, ${p.idm}, ${p.idv})">Beli</button>
</div>
`;
container.innerHTML += html;
});
kirimHeight();
}
function kirimHeight() {
const tinggi = document.body.scrollHeight;
window.parent.postMessage({ frameHeight: tinggi }, "*");
}
window.addEventListener("load", () => {
const status = localStorage.getItem("status");
const kodeVoucher = localStorage.getItem("voucher");
const expPay = localStorage.getItem("exppay");
const qr = localStorage.getItem("qr");
if (status === "Pending" && qr && expPay) {
tampilkanQR(qr, expPay);
} else if (status === "Lunas") {
tampilkanSukses(localStorage.getItem("nama"), "Rp " + localStorage.getItem("harga"), localStorage.getItem("voucher"));
parent.postMessage({
type: "voucher_paid",
voucher: localStorage.getItem("voucher")
}, "*");
} else {
tampilkanListVoucher();
}
});
window.addEventListener("resize", kirimHeight);
</script>
</body>
</html>
+123
View File
@@ -0,0 +1,123 @@
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
include "/www/wwwroot/bilspro/config/connect.php";
include "/www/wwwroot/bilspro/payment/paydisini/api_control.php";
header('Content-Type: application/json');
function generateOrderId($pdo) {
do {
$order_id = sprintf('%013d', mt_rand(0, 9999999999999));
$stmt = $pdo->prepare("SELECT COUNT(*) FROM apk_payment WHERE order_id = :order_id");
$stmt->bindParam(':order_id', $order_id);
$stmt->execute();
$exists = $stmt->fetchColumn();
} while ($exists > 0);
return $order_id;
}
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
echo json_encode(['success' => false, 'message' => 'Metode tidak diperbolehkan']);
exit;
}
$ids = $_POST['ids'] ?? '';
$idm = $_POST['idm'] ?? '';
$idv = $_POST['idv'] ?? '';
$wa = $_POST['wa'] ?? '';
if (!preg_match('/^[0-9]{10,15}$/', $wa)) {
echo json_encode(['success' => false, 'message' => 'Nomor WhatsApp tidak valid']);
exit;
}
if (empty($ids) || empty($idm) || empty($idv)) {
echo json_encode(['success' => false, 'message' => 'Data tidak lengkap']);
exit;
}
$stmt = $pdo->prepare("SELECT * FROM profile_paket WHERE id = :idv");
$stmt->execute([':idv' => $idv]);
$data1 = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$data1) {
echo json_encode(['success' => false, 'message' => 'Data paket tidak ditemukan']);
exit;
}
$harga = $data1['harga_paket'];
$kodeprofile = $data1['nama_profile'];
$durasi = $data1['durasi'];
$karakter = "QWERTYUIOPASDFGHJKLZXCV12345098760987612345BNMQWERTYUIOPASGHJKLZXCVBNM";
$kodevoucher = $durasi . substr(str_shuffle($karakter), 0, 7) . 'VPG';
$create_time = date('Y-m-d H:i:s');
$stmt = $pdo->prepare("INSERT INTO ganerate_voucher
(id_data_server, id_agen_voucher, id_setting_mikrotik, id_profile_paket, voucher, harga, create_time, jenis, nomor_whatsapp)
VALUES (:ids, NULL, :idm, :idv, :voucher, :harga, :create_time, 'api-pw', :nomor_whatsapp)");
$stmt->execute([
':ids' => $ids,
':idm' => $idm,
':idv' => $idv,
':voucher' => $kodevoucher,
':harga' => $harga,
':create_time' => $create_time,
':nomor_whatsapp' => $wa
]);
$last_id = $pdo->lastInsertId();
$order_id = generateOrderId($pdo);
$keterangan = "Pembelian voucher " . $kodevoucher;
$waktu_transaksi = date("Y-m-d H:i:s");
$stmt = $pdo->prepare("INSERT INTO apk_payment
(id_data_server, order_id, keterangan, waktu_transaksi, nominal, id_generate, status, jenis)
VALUES
(:ids, :order_id, :keterangan, :waktu_transaksi, :nominal, :id_generate, 'BELUM DIBAYAR', 'Hotspot')");
$stmt->execute([
':ids' => $ids,
':order_id' => $order_id,
':keterangan' => $keterangan,
':waktu_transaksi' => $waktu_transaksi,
':nominal' => $harga,
':id_generate' => $last_id
]);
$trxData = [
'unique_code' => $order_id,
'service' => 'qris',
'amount' => $harga,
'note' => $keterangan,
'valid_time' => 300
];
$response = CreateTransaction($trxData);
$trxResult = json_decode($response);
if ($trxResult && $trxResult->success === true && isset($trxResult->data->qrcode_url)) {
$qrImage = $trxResult->data->qrcode_url;
$expired = $trxResult->data->expired;
$stmt = $pdo->prepare("UPDATE apk_payment SET data_get = :data_get, status = 'PENDING' WHERE order_id = :order_id");
$stmt->execute([
':data_get' => $response,
':order_id' => $order_id
]);
echo json_encode([
'success' => true,
'voucher' => $kodevoucher,
'exppay' => $expired,
'order_id' => $order_id,
'qr' => $qrImage
]);
exit;
} else {
echo json_encode(['success' => false, 'message' => 'Gagal membuat transaksi QR']);
exit;
}
+180
View File
@@ -0,0 +1,180 @@
body {
margin: 0;
padding: 20px;
font-family: 'Segoe UI', sans-serif;
background: #ffffff;
}
.voucher-container {
max-width: 800px;
margin: 0 auto;
}
/* Voucher Box */
.voucher-box {
display: flex;
justify-content: space-between;
align-items: center;
background: linear-gradient(135deg, #ffffff, #fef5e6);
border: 1px solid #f2e8d8;
border-radius: 16px;
padding: 18px 20px;
margin-bottom: 16px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.03);
transition: all 0.25s ease-in-out;
}
.voucher-box:hover {
box-shadow: 0 6px 14px rgba(0, 0, 0, 0.08);
transform: translateY(-2px);
}
.voucher-info {
display: flex;
flex-direction: column;
}
.voucher-desc {
font-size: 13px;
color: #888;
margin-bottom: 4px;
}
.voucher-title {
font-size: 18px;
font-weight: bold;
color: #2c2c2c;
}
.btn-bayar {
background: linear-gradient(to right, #ff7e29, #ff5300);
color: white;
border: none;
border-radius: 50px;
padding: 6px 14px;
font-size: 12px;
font-weight: 600;
cursor: pointer;
transition: background 0.3s ease, transform 0.2s ease;
}
.btn-bayar:hover {
background: linear-gradient(to right, #ff5300, #e44d00);
transform: scale(1.05);
box-shadow: 0 2px 8px rgba(255, 83, 0, 0.25);
}
/* Konfirmasi Pembelian */
.confirm-wrapper {
display: flex;
justify-content: center;
padding: 10px 15px;
box-sizing: border-box;
/* Hapus min-height agar tinggi dinamis mengikuti isi */
min-height: 400px;
}
.confirm-box {
background: #fffaf4;
border: 1px solid #ffd9b8;
border-radius: 16px;
padding: 22px 20px;
max-width: 400px;
width: 100%;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);
text-align: center;
box-sizing: border-box;
}
.confirm-title {
font-size: 16px;
color: #333;
margin-bottom: 5px;
}
.confirm-nama {
font-size: 15px;
font-weight: 600;
margin: 4px 0;
}
.confirm-harga {
font-size: 18px;
font-weight: bold;
color: #d35400;
margin: 6px 0 12px;
}
.confirm-info {
font-size: 11px;
color: #666;
margin-top: 5px;
margin-bottom: 20px;
}
.confirm-box input {
width: 100%;
padding: 5px;
border: 1px solid #ccc;
border-radius: 8px;
font-size: 13px;
box-sizing: border-box;
text-align: center;
}
.button-group {
display: flex;
justify-content: center;
gap: 10px;
flex-wrap: wrap;
}
.btn-submit,
.btn-cancel {
padding: 8px 16px;
font-size: 12px;
font-weight: 600;
border-radius: 50px;
border: none;
cursor: pointer;
}
.btn-submit {
background: linear-gradient(to right, #ff7e29, #ff5300);
color: #fff;
}
.btn-submit:hover {
background: linear-gradient(to right, #ff5300, #e44d00);
}
.btn-cancel {
background-color: #ddd;
color: #333;
}
.btn-cancel:hover {
background-color: #bbb;
}
@media (max-width: 500px) {
.voucher-box {
flex-direction: row;
flex-wrap: wrap;
}
.voucher-info {
width: calc(100% - 100px);
}
.btn-bayar {
width: 80px;
margin-top: 4px;
text-align: center;
}
.confirm-box {
padding: 20px 15px;
}
}