Files
open-isp/services/mayarService.js
T
oxpoe eaf05f2811 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
2026-10-09 05:51:21 +07:00

78 lines
2.8 KiB
JavaScript

const axios = require('axios');
const { getSetting } = require('../config/settingsManager');
/**
* MAYAR.id payment gateway (Mode 1).
* Docs: https://docs.mayar.id — base https://api.mayar.id/hl/v2
* Auth: Authorization: Bearer <API_KEY>
*/
const MAYAR_BASE = 'https://api.mayar.id/hl/v2';
function apiKey() {
return String(getSetting('mayar_api_key', '') || '').trim();
}
function isConfigured() {
return !!apiKey();
}
function headers() {
return { Authorization: 'Bearer ' + apiKey(), 'Content-Type': 'application/json', Accept: 'application/json' };
}
function toWaMobile(phone) {
let d = String(phone || '').replace(/\D/g, '');
if (!d) return '';
if (d.startsWith('0')) d = '62' + d.slice(1);
return d;
}
/**
* Buat invoice/pembayaran di Mayar.
* @returns {{success:boolean, order_id:string, link:string, reference:string, payload:object}}
*/
async function createInvoice(opts) {
const o = opts || {};
if (!isConfigured()) throw new Error('Mayar belum dikonfigurasi (mayar_api_key kosong).');
const amount = Math.round(Number(o.amount) || 0);
if (amount <= 0) throw new Error('Nominal tagihan tidak valid untuk Mayar.');
const desc = String(o.description || 'Tagihan').slice(0, 200);
const body = {
name: String(o.name || 'Pelanggan').slice(0, 100),
email: String(o.email || ('no-reply+' + Date.now() + '@openisp.local')).slice(0, 120),
mobile: toWaMobile(o.mobile),
description: desc,
items: [{ quantity: 1, rate: amount, description: desc }],
extraData: o.extraData || {}
};
if (o.expiredAt) body.expiredAt = o.expiredAt;
const res = await axios.post(MAYAR_BASE + '/invoices/create', body, { headers: headers(), timeout: 25000 });
const d = (res.data && res.data.data) ? res.data.data : (res.data || {});
const link = d.link || d.paymentLink || d.payment_url || d.url || '';
const orderId = d.id || d.transactionId || d.paymentLinkId || '';
if (!link) throw new Error('Mayar tidak mengembalikan link pembayaran.');
return {
success: true,
order_id: String(orderId),
link: String(link),
reference: String(d.transactionId || orderId || ''),
payload: d,
raw: res.data
};
}
async function getInvoice(id) {
const res = await axios.get(MAYAR_BASE + '/invoices/' + encodeURIComponent(id), { headers: headers(), timeout: 20000 });
return res.data;
}
async function testConnection() {
if (!isConfigured()) return { ok: false, error: 'API key kosong' };
try {
const res = await axios.get(MAYAR_BASE + '/invoices?page=1&pageSize=1', { headers: headers(), timeout: 15000 });
return { ok: true, status: res.status };
} catch (e) {
return { ok: false, error: e && e.response ? ('HTTP ' + e.response.status) : (e.message || String(e)) };
}
}
module.exports = { isConfigured, createInvoice, getInvoice, testConnection, apiKey };