diff --git a/CHANGELOG.md b/CHANGELOG.md index c24a40c..c307e3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ Format mengikuti [Keep a Changelog](https://keepachangelog.com/) dan [Semantic Versioning](https://semver.org/). +## [0.5.13] — 2026-11-05 — "lunas-notify" + +### Diperbaiki +- Notifikasi WA **LUNAS** memakai gateway aktif (GOWA/Fonnte/Meta/Baileys), bukan hanya Baileys. +- Deteksi koneksi GOWA membaca status device dari `/devices` (array) — sebelumnya dianggap tidak terhubung bila Device ID kosong, sehingga notifikasi lunas dilewati. +- Approve pembayaran kolektor dari APK admin dan pencocokan notifikasi pembayaran manual kini mengirim WA lunas ke pelanggan. + ## [0.5.12] — 2026-11-05 — "gowa-test-unsaved" ### Diperbaiki diff --git a/README.md b/README.md index f4ab3e7..7c82c86 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@
-
+
diff --git a/app-customer.js b/app-customer.js
index 465fe86..e1e2861 100644
--- a/app-customer.js
+++ b/app-customer.js
@@ -628,8 +628,8 @@ async function trySendWaPaymentSuccess(settings, invoiceId, methodLabel) {
if (!inv) return;
const phone = String(inv.customer_phone || '').trim();
if (!phone) return;
- const { sendWA, whatsappStatus } = await import('./services/whatsappBot.mjs');
- if (whatsappStatus.connection !== 'open') throw new Error('Bot WhatsApp belum terhubung');
+ // Pakai gateway aktif (GOWA/Fonnte/Meta/Baileys), bukan hanya Baileys.
+ const waNotify = require('./services/waNotifyService');
const appUrl = (settings.public_base_url || '').replace(/\/$/, '');
const portalUrl = appUrl ? `${appUrl}/customer` : '';
@@ -654,7 +654,7 @@ async function trySendWaPaymentSuccess(settings, invoiceId, methodLabel) {
});
logger.info(`[WEBHOOK][payment-notif] Sending WA success notif to ${phone} inv=${invoiceId} method=${metode}`);
- await sendWA(phone, msg);
+ await waNotify.sendText(phone, msg);
} catch (e) {
logger.error(`[WEBHOOK][payment-notif] WA success notif failed: ${e?.message || e}`);
}
diff --git a/package.json b/package.json
index 1353c1d..aed4612 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "open-isp",
- "version": "0.5.12",
+ "version": "0.5.13",
"description": "OPEN-ISP \u2014 sistem billing & manajemen ISP open-source (PWA pelanggan, multi-OLT, RADIUS, WhatsApp, QRIS)",
"main": "app-customer.js",
"scripts": {
diff --git a/routes/adminPortal.js b/routes/adminPortal.js
index e7fab36..6750f19 100644
--- a/routes/adminPortal.js
+++ b/routes/adminPortal.js
@@ -4925,6 +4925,29 @@ router.post('/payment-unmatched/:id/match', requireAdminSession, express.urlenco
if (!unpaid) await customerSvc.activateCustomer(inv.customer_id);
}
} catch (e) {}
+
+ // Notifikasi WA lunas ke pelanggan
+ try {
+ const cust = customerSvc.getCustomerById(inv.customer_id);
+ if (cust && cust.phone) {
+ const pkg = cust.package_id ? customerSvc.getPackageById(cust.package_id) : null;
+ await sendPaymentSuccessWA(
+ cust.phone,
+ cust.name,
+ `${inv.period_month}/${inv.period_year}`,
+ Number(inv.amount || 0).toLocaleString('id-ID'),
+ 'Manual (Webhook)',
+ {
+ customerId: cust.id,
+ invoiceId: inv.id,
+ username: cust.pppoe_username || cust.id,
+ customerCode: cust.customer_code || '',
+ packageName: pkg?.name || cust.package_name || '-',
+ paidAt: new Date(), method: 'Manual (Webhook)'
+ }
+ );
+ }
+ } catch (e) {}
req.session._msg = { type: 'success', text: 'Invoice #' + invId + ' ditandai LUNAS & notif dicocokkan.' };
} catch (e) {
req.session._msg = { type: 'error', text: 'Gagal cocokkan: ' + e.message };
diff --git a/routes/customerAPI.js b/routes/customerAPI.js
index 1f59f16..ae22df7 100644
--- a/routes/customerAPI.js
+++ b/routes/customerAPI.js
@@ -2359,6 +2359,37 @@ router.post('/app/admin/collector-payments/approve', requireAdminApiAuth, async
if (unpaidCount === 0) {
try { await customerSvc.activateCustomer(pay.customer_id); } catch (_) {}
}
+
+ // Notifikasi WA lunas ke pelanggan (gateway aktif)
+ try {
+ const customer = customerSvc.getCustomerById(pay.customer_id);
+ const inv = billingSvc.getInvoiceById(pay.invoice_id);
+ if (customer && customer.phone && inv) {
+ const settings = getSettingsWithCache();
+ const waNotify = require('../services/waNotifyService');
+ const whatsappService = require('../services/whatsappService');
+ const pkg = customer.package_id ? customerSvc.getPackageById(customer.package_id) : null;
+ const appUrl = String(settings.public_base_url || '').replace(/\/$/, '');
+ const template = db.getAppSetting('whatsapp_payment_success_message', '');
+ const msg = whatsappService.formatPaymentSuccessMessage({
+ customerName: customer.name,
+ invoiceId: inv.id,
+ customerUsername: customer.pppoe_username || customer.id || '-',
+ customerCode: customer.customer_code || '',
+ packageName: pkg?.name || customer.package_name || '-',
+ periodMonth: inv.period_month,
+ periodYear: inv.period_year,
+ amount: inv.amount,
+ paymentMethod: collectorLabel,
+ paidAt: new Date(),
+ companyName: settings.company_header || 'OPEN-ISP',
+ companyPhone: settings.company_phone || '',
+ portalUrl: appUrl ? appUrl + '/customer' : '',
+ customTemplate: template
+ });
+ await waNotify.sendText(customer.phone, msg);
+ }
+ } catch (_) {}
}
res.json({ success: true, message: 'Pembayaran berhasil di-approve dan tagihan ditandai LUNAS' });
} catch (e) { res.status(500).json({ success: false, message: e.message }); }
diff --git a/services/waNotifyService.js b/services/waNotifyService.js
index 805fd9c..41bde2c 100644
--- a/services/waNotifyService.js
+++ b/services/waNotifyService.js
@@ -140,8 +140,12 @@ async function isConnected() {
try {
if (gw === 'gowa') {
const st = await require('./gowaWhatsappService').gowaStatus();
- const d = (st && st.data && st.data.results) || (st && st.data) || {};
- val = !!(d.is_connected || d.is_logged_in || d.connected);
+ const raw = (st && st.data && st.data.results) || (st && st.data) || {};
+ const list = Array.isArray(raw) ? raw : [raw];
+ val = list.some(function (d) {
+ return !!(d && (d.is_connected || d.is_logged_in || d.connected ||
+ d.state === 'connected' || d.state === 'logged_in'));
+ });
} else if (gw === 'baileys') {
const mod = await import('./whatsappBot.mjs');
const s = mod.whatsappStatus;
diff --git a/version.txt b/version.txt
index 12697f7..7988f13 100644
--- a/version.txt
+++ b/version.txt
@@ -1 +1 @@
-0.5.12
\ No newline at end of file
+0.5.13
\ No newline at end of file