OPEN-ISP v0.5 (pickle-lime) — rilis open-source perdana

Aplikasi billing & manajemen ISP (fiber optic) — PWA pelanggan, portal teknisi & kolektor,
admin panel lengkap, multi-vendor OLT, RADIUS, WhatsApp/Telegram, pembayaran QRIS.

Kredit & lisensi (ISC):
- Base kode & repo: alijayanet/billing-rtrw oleh Alijaya Net — terima kasih banyak
  atas base kode dan repo yang bermanfaat.
- Add-on: GoWA, LibreSpeed/OpenSpeedTest, Uptime Kuma, notification-forwarder.
- Dikembangkan menjadi OPEN-ISP oleh oxpoe — https://github.com/oxpoe/open-isp
This commit is contained in:
oxpoe committed 2026-10-09 05:51:21 +07:00
commit eaf05f2811
280 files changed
+123975

No files matched your search

+129
View File
@@ -0,0 +1,129 @@
#!/usr/bin/env node
/**
* OPEN-ISP — Seed Data Demo untuk Tester
* ======================================
* Mengisi database dengan data contoh agar dashboard bisa langsung dilihat:
* paket, area, pelanggan, tagihan (sebagian lunas), tiket, dan voucher.
*
* Jalankan (SEKALI saja, aman — tidak menimpa bila sudah ada data):
* node scripts/seed-demo.js
*
* Untuk Docker:
* docker exec open-isp node scripts/seed-demo.js
*
* Login default hasil seed:
* ADMIN : admin / demo-isp123
* PELANGGAN: lihat "Login Pelanggan" di output (ID Pelanggan / No. WhatsApp)
*/
const db = require('../config/database');
const customerSvc = require('../services/customerService');
const billingSvc = require('../services/billingService');
const log = (...a) => console.log('[seed-demo]', ...a);
function count(tbl) {
try { return db.prepare(`SELECT COUNT(*) c FROM ${tbl}`).get().c; } catch (e) { return 0; }
}
(async () => {
/* ── Guard: jangan timpa data yang sudah ada ─────────────────────────── */
const existing = count('customers') + count('packages');
if (existing > 0) {
log('Database sudah berisi data (customers/packages > 0) — seed DILEWATI.');
log('(Hapus isi database bila ingin seed ulang di instalasi bersih.)');
process.exit(0);
}
/* ── 1. Paket ─────────────────────────────────────────────────────────── */
const pkgs = [
{ name: 'Demo Lite 10 Mbps', speed_down: 10, speed_up: 10, price: 100000, description: 'Paket hemat untuk kebutuhan dasar', billing_type: 'postpaid' },
{ name: 'Demo Home 20 Mbps', speed_down: 20, speed_up: 20, price: 130000, description: 'Paket favorit keluarga', billing_type: 'postpaid' },
{ name: 'Demo Pro 30 Mbps', speed_down: 30, speed_up: 30, price: 175000, description: 'Bekerja & streaming lancar', billing_type: 'postpaid' },
{ name: 'Demo Bisnis 50 Mbps', speed_down: 50, speed_up: 50, price: 275000, description: 'Untuk kantor & usaha', billing_type: 'postpaid' },
];
const pkgIds = [];
for (const p of pkgs) {
try { const r = customerSvc.createPackage(p); pkgIds.push(r.lastInsertRowid); log('Paket:', p.name); }
catch (e) { log('Gagal paket', p.name, e.message); }
}
/* ── 2. Area ──────────────────────────────────────────────────────────── */
const areas = ['Demo Area Pusat', 'Demo Area Timur', 'Demo Area Barat'];
for (const a of areas) {
try { db.prepare('INSERT OR IGNORE INTO areas (name, description) VALUES (?, ?)').run(a, 'Area contoh (data demo)'); log('Area:', a); }
catch (e) { log('Gagal area', a, e.message); }
}
/* ── 3. Pelanggan ─────────────────────────────────────────────────────── */
const custs = [
['Budi Santoso', '081200000001', 'Jl. Merdeka No. 1'],
['Siti Aminah', '081200000002', 'Jl. Sudirman No. 12'],
['Agus Wijaya', '081200000003', 'Jl. Diponegoro No. 3'],
['Dewi Lestari', '081200000004', 'Jl. Gajah Mada No. 44'],
['Rudi Hartono', '081200000005', 'Jl. Hayam Wuruk No. 8'],
['Sri Wahyuni', '081200000006', 'Jl. Pahlawan No. 21'],
['Joko Susilo', '081200000007', 'Jl. Ahmad Yani No. 5'],
['Ratna Sari', '081200000008', 'Jl. Kartini No. 17'],
['Hendra Gunawan', '081200000009', 'Jl. Cendrawasih No. 9'],
['Maya Putri', '081200000010', 'Jl. Melati No. 2'],
['Anton Prasetyo', '081200000011', 'Jl. Kenanga No. 30'],
['Lina Marlina', '081200000012', 'Jl. Anggrek No. 7'],
];
const today = new Date();
const installDate = new Date(today.getTime() - 35 * 86400000).toISOString().slice(0, 10);
const custIds = [];
let i = 0;
for (const [name, phone, address] of custs) {
i++;
const pkgId = pkgIds[(i - 1) % (pkgIds.length || 1)];
try {
const r = customerSvc.createCustomer({
name, phone, address,
area: areas[(i - 1) % areas.length],
package_id: pkgId,
status: (i === 11 || i === 12) ? 'inactive' : 'active', // 2 pelanggan nonaktif utk variasi
install_date: installDate,
connection_type: 'pppoe',
pppoe_username: `demo${String(i).padStart(2, '0')}@demo.id`,
pppoe_password: 'demo-isp123',
auto_isolate: 1,
isolate_day: 10,
notes: 'Data demo — silakan hapus',
});
custIds.push({ id: r.lastInsertRowid, name, phone });
log('Pelanggan:', name);
} catch (e) { log('Gagal pelanggan', name, e.message); }
}
/* ── 4. Tagihan bulan ini + sebagian dibuat LUNAS ─────────────────────── */
const month = today.getMonth() + 1;
const year = today.getFullYear();
let invCount = 0;
try { invCount = billingSvc.generateMonthlyInvoices(month, year); log(`Generate tagihan ${month}/${year}:`, invCount); }
catch (e) { log('Gagal generate tagihan:', e.message); }
// 8 pelanggan pertama -> LUNAS, sisanya dibiarkan belum bayar
let paid = 0;
for (let k = 0; k < Math.min(8, custIds.length); k++) {
try { billingSvc.payInvoiceForCustomerPeriod(custIds[k].id, month, year, 'Admin Demo', 'Pembayaran demo'); paid++; }
catch (e) { log('Gagal pelunasan', custIds[k].name, e.message); }
}
log(`Pelunasan demo: ${paid} pelanggan`);
/* ── 5. Tiket contoh ──────────────────────────────────────────────────── */
try {
const ticketSvc = require('../services/ticketService');
if (custIds[0]) ticketSvc.createTicket(custIds[0].id, 'Koneksi lambat', 'Sejak tadi malam internet terasa lambat, mohon dicek. (data demo)');
if (custIds[1]) ticketSvc.createTicket(custIds[1].id, 'Modem mati', 'Lampu modem tidak menyala sejak pagi. (data demo)');
log('Tiket demo: 2');
} catch (e) { log('Tiket dilewati:', e.message); }
/* ── Ringkasan ────────────────────────────────────────────────────────── */
const demo = db.prepare("SELECT customer_code, name, phone FROM customers WHERE notes LIKE 'Data demo%' LIMIT 2").all();
log('==================== SELESAI ====================');
log('Login ADMIN : admin / demo-isp123');
log('Login PELANGGAN: gunakan ID Pelanggan atau No. WhatsApp di bawah ini');
demo.forEach(d => log(` • ${d.name} — ${d.customer_code} / ${d.phone}`));
log('=================================================');
process.exit(0);
})().catch(e => { console.error('[seed-demo] ERROR:', e.message); process.exit(1); });