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

+81
View File
@@ -0,0 +1,81 @@
const db = require('../config/database');
/**
* Get all areas with customer and collector statistics
*/
function getAllAreas() {
const sql = `
SELECT a.*,
(SELECT COUNT(*) FROM customers c WHERE LOWER(TRIM(c.area)) = LOWER(TRIM(a.name))) as customer_count,
(SELECT COUNT(*) FROM collectors col WHERE LOWER(TRIM(col.area)) = LOWER(TRIM(a.name))) as collector_count,
(SELECT COUNT(*) FROM technicians t WHERE LOWER(TRIM(t.area)) = LOWER(TRIM(a.name))) as technician_count
FROM areas a
ORDER BY a.name ASC
`;
return db.prepare(sql).all();
}
/**
* Get single area by ID
*/
function getAreaById(id) {
return db.prepare('SELECT * FROM areas WHERE id = ?').get(id);
}
/**
* Create new area
*/
function createArea(data) {
const name = String(data.name || '').trim();
if (!name) throw new Error('Nama Area / Wilayah tidak boleh kosong');
const existing = db.prepare('SELECT id FROM areas WHERE LOWER(TRIM(name)) = LOWER(TRIM(?))').get(name);
if (existing) throw new Error(`Area "${name}" sudah ada.`);
const stmt = db.prepare('INSERT INTO areas (name, description) VALUES (?, ?)');
return stmt.run(name, String(data.description || '').trim());
}
/**
* Update existing area
*/
function updateArea(id, data) {
const oldArea = getAreaById(id);
if (!oldArea) throw new Error('Data Area tidak ditemukan');
const newName = String(data.name || '').trim();
if (!newName) throw new Error('Nama Area / Wilayah tidak boleh kosong');
const existing = db.prepare('SELECT id FROM areas WHERE LOWER(TRIM(name)) = LOWER(TRIM(?)) AND id != ?').get(newName, id);
if (existing) throw new Error(`Nama Area "${newName}" sudah digunakan oleh area lain.`);
const description = String(data.description || '').trim();
// If area name changed, update references in customers, collectors, technicians
if (oldArea.name !== newName) {
db.prepare('UPDATE customers SET area = ? WHERE LOWER(TRIM(area)) = LOWER(TRIM(?))').run(newName, oldArea.name);
db.prepare('UPDATE collectors SET area = ? WHERE LOWER(TRIM(area)) = LOWER(TRIM(?))').run(newName, oldArea.name);
db.prepare('UPDATE technicians SET area = ? WHERE LOWER(TRIM(area)) = LOWER(TRIM(?))').run(newName, oldArea.name);
}
const stmt = db.prepare('UPDATE areas SET name = ?, description = ? WHERE id = ?');
return stmt.run(newName, description, id);
}
/**
* Delete area
*/
function deleteArea(id) {
const area = getAreaById(id);
if (!area) throw new Error('Data Area tidak ditemukan');
return db.prepare('DELETE FROM areas WHERE id = ?').run(id);
}
module.exports = {
getAllAreas,
getAreaById,
createArea,
updateArea,
deleteArea
};