add: gui sep requests

This commit is contained in:
2026-02-01 09:43:51 +03:30
parent 1406e4bd24
commit 18d3f17ce3

133
index.js
View File

@@ -855,7 +855,7 @@ app.post("/sep-pay-request", async (req, res) => {
action: "token", action: "token",
TerminalId: SEP_TERMINAL_ID, TerminalId: SEP_TERMINAL_ID,
Amount: parsedAmount, Amount: parsedAmount,
ResNum, ResNum: resNum,
RedirectUrl: redirectUrl, RedirectUrl: redirectUrl,
CellNumber: phone, CellNumber: phone,
SettlementIBANInfo: wages, SettlementIBANInfo: wages,
@@ -961,16 +961,8 @@ app.post("/sepverify", async (req, res) => {
} }
}); });
app.get("/sep-pay-requests/gui", async (req, res) => { // all-payments: list of saved SEP pay requests (from MongoDB)
const basePath = app.get("/all-payments", async (req, res) => {
(req.baseUrl || "").replace(/\/sep-pay-requests\/gui$/, "") || "";
const listPath = basePath
? basePath + "/sep-pay-requests"
: "/sep-pay-requests";
const submitPathPrefix = basePath
? basePath + "/sep-pay-request/"
: "/sep-pay-request/";
let list = []; let list = [];
try { try {
const coll = await getSepPayCollection(); const coll = await getSepPayCollection();
@@ -984,7 +976,7 @@ app.get("/sep-pay-requests/gui", async (req, res) => {
_id: doc._id ? doc._id.toString() : doc._id, _id: doc._id ? doc._id.toString() : doc._id,
})); }));
} catch (err) { } catch (err) {
console.error("sep-pay-requests gui list error", err); console.error("all-payments list error", err);
} }
const listJson = JSON.stringify(list) const listJson = JSON.stringify(list)
@@ -1000,75 +992,33 @@ app.get("/sep-pay-requests/gui", async (req, res) => {
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title>SEP Pay Requests</title> <title>همه پرداخت‌ها</title>
<style> <style>
* { box-sizing: border-box; } * { box-sizing: border-box; }
body { font-family: Tahoma, Arial, sans-serif; margin: 0; padding: 16px; background: #f5f5f5; } body { font-family: Tahoma, Arial, sans-serif; margin: 0; padding: 16px; background: #f5f5f5; }
h1 { color: #333; margin-bottom: 16px; } h1 { color: #333; margin-bottom: 16px; }
.card { background: #fff; border-radius: 8px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); padding: 16px; margin-bottom: 12px; } table { width: 100%; border-collapse: collapse; background: #fff; box-shadow: 0 1px 3px rgba(0,0,0,0.1); border-radius: 8px; overflow: hidden; }
.row { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 8px; align-items: center; } th, td { padding: 10px 12px; text-align: right; border-bottom: 1px solid #eee; }
.label { font-weight: bold; color: #555; min-width: 90px; } th { background: #fafafa; font-weight: bold; color: #555; }
.value { color: #333; } tr:hover { background: #f9f9f9; }
button { background: #1976d2; color: #fff; border: none; padding: 8px 16px; border-radius: 6px; cursor: pointer; font-size: 14px; margin-top: 8px; }
button:hover { background: #1565c0; }
.msg { margin-top: 8px; padding: 8px; border-radius: 6px; font-size: 14px; }
.msg.success { background: #e8f5e9; color: #2e7d32; }
.msg.error { background: #ffebee; color: #c62828; }
input { padding: 6px 8px; border: 1px solid #ccc; border-radius: 4px; width: 180px; }
#list { margin-top: 16px; }
</style> </style>
</head> </head>
<body> <body>
<h1>درخواست‌های پرداخت SEP</h1> <h1>همه پرداختها</h1>
<p><a href="${listPath}">API لیست (JSON)</a></p>
<div id="list"></div> <div id="list"></div>
<script> <script>
(function() { (function() {
const list = JSON.parse("${listJson}"); var list = JSON.parse("${listJson}");
const submitPathPrefix = ${JSON.stringify(submitPathPrefix)}; var listEl = document.getElementById('list');
const submitPath = function(id) { return submitPathPrefix + id + '/submit'; };
const listEl = document.getElementById('list');
if (!list || list.length === 0) { if (!list || list.length === 0) {
listEl.innerHTML = '<p>موردی یافت نشد.</p>'; listEl.innerHTML = '<p>موردی یافت نشد.</p>';
return; return;
} }
var rows = list.map(function(item) {
listEl.innerHTML = list.map(function(item) { var createdAt = item.createdAt ? new Date(item.createdAt).toLocaleString('fa-IR') : '-';
const id = item._id; return '<tr><td>' + (item.amountRaw || item.amount) + '</td><td>' + (item.provincecode || '-') + '</td><td>' + (item.isLink ? 'بله' : 'خیر') + '</td><td>' + (item.phone || '-') + '</td><td>' + createdAt + '</td></tr>';
const token = (item.token || '').toString();
const traceNo = (item.traceNo || '').toString();
const securePan = (item.securePan || '').toString();
const createdAt = item.createdAt ? new Date(item.createdAt).toLocaleString('fa-IR') : '-';
return '<div class="card" data-id="' + id + '">' +
'<div class="row"><span class="label">مبلغ:</span><span class="value">' + (item.amountRaw || item.amount) + '</span></div>' +
'<div class="row"><span class="label">استان:</span><span class="value">' + (item.provincecode || '-') + '</span></div>' +
'<div class="row"><span class="label">لینک:</span><span class="value">' + (item.isLink ? 'بله' : 'خیر') + '</span></div>' +
'<div class="row"><span class="label">Token:</span><span class="value">' + (token ? token.substring(0, 20) + '...' : '-') + '</span></div>' +
'<div class="row"><span class="label">RefId (TraceNo):</span><input type="text" id="ref-' + id + '" value="' + traceNo.replace(/"/g, '&quot;') + '" placeholder="اختیاری" /></div>' +
'<div class="row"><span class="label">CardPan:</span><input type="text" id="pan-' + id + '" value="' + securePan.replace(/"/g, '&quot;') + '" placeholder="اختیاری" /></div>' +
'<div class="row"><span class="label">تاریخ:</span><span class="value">' + createdAt + '</span></div>' +
'<button type="button" onclick="window.submitToTaavon(\\'' + id + '\\', this)">ارسال به تعاون (تراکنش موفق)</button>' +
'<div class="msg" id="msg-' + id + '"></div>' +
'</div>';
}).join(''); }).join('');
listEl.innerHTML = '<table><thead><tr><th>مبلغ</th><th>استان</th><th>لینک</th><th>موبایل</th><th>تاریخ</th></tr></thead><tbody>' + rows + '</tbody></table>';
window.submitToTaavon = async function(id, btn) {
const msgEl = document.getElementById('msg-' + id);
if (msgEl) { msgEl.textContent = ''; msgEl.className = 'msg'; }
btn.disabled = true;
var refId = (document.getElementById('ref-' + id) || {}).value || '';
var cardPan = (document.getElementById('pan-' + id) || {}).value || '';
var body = JSON.stringify({ refId: refId || undefined, cardHolderPan: cardPan || undefined });
try {
var r = await fetch(submitPath(id), { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: body });
var j = await r.json();
if (msgEl) { msgEl.textContent = j.error || (j.message || 'ارسال شد'); msgEl.className = 'msg ' + (j.error ? 'error' : 'success'); }
} catch (e) {
if (msgEl) { msgEl.textContent = e.message; msgEl.className = 'msg error'; }
}
btn.disabled = false;
};
})(); })();
</script> </script>
</body> </body>
@@ -1077,57 +1027,6 @@ app.get("/sep-pay-requests/gui", async (req, res) => {
res.send(html); res.send(html);
}); });
// List all SEP pay requests (API)
app.get("/sep-pay-requests", async (req, res) => {
try {
const coll = await getSepPayCollection();
const list = await coll
.find({})
.sort({ createdAt: -1 })
.limit(500)
.toArray();
// Ensure _id is string for GUI
const listWithIds = list.map((doc) => ({
...doc,
_id: doc._id ? doc._id.toString() : doc._id,
}));
return res.json(listWithIds);
} catch (err) {
console.error("sep-pay-requests list error", err);
return res.status(500).json({ error: err.message });
}
});
// Manual submit to Taavon (like sepverify does) - use stored or body: authority, refId, cardHolderPan
app.post("/sep-pay-request/:id/submit", async (req, res) => {
const id = req.params.id;
const { authority, refId, cardHolderPan } = req.body;
try {
const coll = await getSepPayCollection();
const doc = await coll.findOne({ _id: new ObjectId(id) });
if (!doc) {
return res.status(404).json({ error: "Record not found" });
}
const province = (doc.provincecode || "").toString().substring(0, 2);
const isLink =
doc.isLink === true || doc.isLink === "true" || doc.isLink === "1";
const data = {
authority: authority ?? doc.token,
refId: refId ?? doc.traceNo,
cardHolderPan: cardHolderPan ?? doc.securePan,
};
if (isLink) {
await taavonSendDataZarinPalLink(province, data);
} else {
await taavonSendDataZarinPal(province, data);
}
return res.json({ ok: true, message: "Submitted to Taavon" });
} catch (err) {
console.error("sep-pay-request submit error", err);
return res.status(500).json({ error: err.message });
}
});
//end sep --------------------------------------------------------------------------------------------- //end sep ---------------------------------------------------------------------------------------------
// samasat crack // samasat crack