${cqEscape(row.category || 'Pembayaran')}
${cqEscape(row.title)}
${amountText}
Nominal dasar ${baseAmountText} + kode unik ${Number(row.unique_code || 0)}
${cqEscape(statusLabels[status] || status)}
${showQr ? `
` : ''}
${row.note ? `
${cqEscape(row.note)}
` : ''}
Bayar dengan nominal persis seperti di atas agar pembayaran otomatis tercocokkan. QR berlaku ${require('./services/customQrService').DURATION_MINUTES} menit.
${cqEscape(company)}
`;
res.set('Cache-Control', 'no-store');
return res.send(html);
});
app.get('/custom-qr/:token/qr.png', async (req, res) => {
let row = null;
try { row = require('./services/customQrService').getByToken(req.params.token); } catch (e) {}
if (!row) return res.status(404).send('QR tidak ditemukan');
const settings = getSettingsWithCache();
const payload = String(settings.qris_static_payload || '').trim();
if (!payload) return res.status(404).send('QRIS statis belum diatur admin.');
try {
const jpg = await qrisUtil.buildDynamicQrisJpgBuffer(payload, Number(row.amount_unique || row.amount || 0));
res.set('Content-Type', 'image/jpeg');
res.set('Cache-Control', 'no-store');
return res.send(jpg);
} catch (e) {
logger.error('[CustomQR] Gagal membuat QR: ' + e.message);
return res.status(500).send('Gagal membuat QR');
}
});
app.get('/custom-qr/:token/status', (req, res) => {
let row = null;
try { row = require('./services/customQrService').getByToken(req.params.token); } catch (e) {}
if (!row) return res.status(404).json({ status: 'not_found' });
return res.json({ status: row.status, paid_at: row.paid_at || null });
});
// Mount built-in ACS server endpoint (TR-069)
const acsServerService = require('./services/acsServerService');
app.post('/acs', express.raw({ type: ['text/xml', 'application/soap+xml', 'application/xml', 'text/plain'], limit: '2mb' }), acsServerService.handleCwmpRequest);
// Landing page untuk scan QR stiker modem ONU pelanggan
app.get('/app/connect', (req, res) => {
const settings = getSettingsWithCache();
const cid = String(req.query.cid || '').trim();
const serverUrl = `${req.protocol}://${req.get('host')}`;
const companyName = settings.company_header || 'ALIJAYA DIGITAL NETWORK';
const companyPhone = settings.company_phone || '';
res.render('app_connect', {
companyName,
companyPhone,
serverUrl,
cid,
settings
});
});
// Mount customer portal
const customerPortal = require('./routes/customerPortal');
app.use('/customer', customerPortal);
// Mount customer REST API for Android Mobile App
const customerAPI = require('./routes/customerAPI');
app.use('/api/customer', customerAPI);
// ── OPEN-ISP admin theme overlay (non-invasive) ──────────────────────────
// Menyisipkan