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
130 lines
6.8 KiB
JavaScript
130 lines
6.8 KiB
JavaScript
#!/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); });
|