Compare commits
No commits in common. "f4e0ca47413f3c5de96bc01d19b2cb78e44775d5" and "d430e82d3f909938f3aaebddb50203daf06626de" have entirely different histories.
f4e0ca4741
...
d430e82d3f
|
|
@ -1,15 +0,0 @@
|
||||||
// Utility to compute Midtrans webhook signature: sha512(order_id + status_code + gross_amount + server_key)
|
|
||||||
const crypto = require('crypto')
|
|
||||||
|
|
||||||
function main() {
|
|
||||||
const [orderId, statusCode, grossAmount, serverKey] = process.argv.slice(2)
|
|
||||||
if (!orderId || !statusCode || !grossAmount || !serverKey) {
|
|
||||||
console.error('Usage: node scripts/midtrans-sig.js <order_id> <status_code> <gross_amount> <server_key>')
|
|
||||||
process.exit(1)
|
|
||||||
}
|
|
||||||
const raw = String(orderId) + String(statusCode) + String(grossAmount) + String(serverKey)
|
|
||||||
const sig = crypto.createHash('sha512').update(raw).digest('hex')
|
|
||||||
process.stdout.write(sig)
|
|
||||||
}
|
|
||||||
|
|
||||||
main()
|
|
||||||
|
|
@ -276,14 +276,10 @@ app.get('/api/payments/:orderId/status', async (req, res) => {
|
||||||
if (isSuccessfulMidtransStatus(status)) {
|
if (isSuccessfulMidtransStatus(status)) {
|
||||||
const nominal = String(status?.gross_amount || '')
|
const nominal = String(status?.gross_amount || '')
|
||||||
if (!notifiedOrders.has(orderId)) {
|
if (!notifiedOrders.has(orderId)) {
|
||||||
|
notifiedOrders.add(orderId)
|
||||||
activeOrders.delete(orderId)
|
activeOrders.delete(orderId)
|
||||||
logInfo('status.notify.erp.trigger', { orderId, transaction_status: status?.transaction_status })
|
logInfo('status.notify.erp.trigger', { orderId, transaction_status: status?.transaction_status })
|
||||||
const ok = await notifyERP({ orderId, nominal })
|
await notifyERP({ orderId, nominal })
|
||||||
if (ok) {
|
|
||||||
notifiedOrders.add(orderId)
|
|
||||||
} else {
|
|
||||||
logWarn('erp.notify.defer', { orderId, reason: 'post_failed_or_missing_data' })
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
logInfo('erp.notify.skip', { orderId, reason: 'already_notified' })
|
logInfo('erp.notify.skip', { orderId, reason: 'already_notified' })
|
||||||
}
|
}
|
||||||
|
|
@ -470,18 +466,18 @@ function resolveMercantId(orderId) {
|
||||||
async function notifyERP({ orderId, nominal, mercantId }) {
|
async function notifyERP({ orderId, nominal, mercantId }) {
|
||||||
if (!ERP_ENABLE_NOTIF) {
|
if (!ERP_ENABLE_NOTIF) {
|
||||||
logInfo('erp.notify.skip', { reason: 'disabled' })
|
logInfo('erp.notify.skip', { reason: 'disabled' })
|
||||||
return false
|
return
|
||||||
}
|
}
|
||||||
// Untuk notifikasi dinamis, hanya URL dan client secret yang wajib
|
// Untuk notifikasi dinamis, hanya URL dan client secret yang wajib
|
||||||
if (!ERP_NOTIFICATION_URL || !ERP_CLIENT_ID) {
|
if (!ERP_NOTIFICATION_URL || !ERP_CLIENT_ID) {
|
||||||
logWarn('erp.notify.missing_config', { hasUrl: !!ERP_NOTIFICATION_URL, hasClientId: !!ERP_CLIENT_ID })
|
logWarn('erp.notify.missing_config', { hasUrl: !!ERP_NOTIFICATION_URL, hasClientId: !!ERP_CLIENT_ID })
|
||||||
return false
|
return
|
||||||
}
|
}
|
||||||
const statusCode = '200'
|
const statusCode = '200'
|
||||||
const mId = mercantId || resolveMercantId(orderId)
|
const mId = mercantId || resolveMercantId(orderId)
|
||||||
if (!mId) {
|
if (!mId) {
|
||||||
logWarn('erp.notify.skip', { orderId, reason: 'missing_mercant_id' })
|
logWarn('erp.notify.skip', { orderId, reason: 'missing_mercant_id' })
|
||||||
return false
|
return
|
||||||
}
|
}
|
||||||
const signature = computeErpSignature(mId, statusCode, nominal, ERP_CLIENT_ID)
|
const signature = computeErpSignature(mId, statusCode, nominal, ERP_CLIENT_ID)
|
||||||
// Payload ERP harus flat: { mercant_id, nominal, status_code, signature }
|
// Payload ERP harus flat: { mercant_id, nominal, status_code, signature }
|
||||||
|
|
@ -495,10 +491,8 @@ async function notifyERP({ orderId, nominal, mercantId }) {
|
||||||
try {
|
try {
|
||||||
const res = await postJson(ERP_NOTIFICATION_URL, payload)
|
const res = await postJson(ERP_NOTIFICATION_URL, payload)
|
||||||
logInfo('erp.notify.success', { orderId, status: res.status })
|
logInfo('erp.notify.success', { orderId, status: res.status })
|
||||||
return true
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logError('erp.notify.error', { orderId, message: e?.message })
|
logError('erp.notify.error', { orderId, message: e?.message })
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -524,17 +518,12 @@ app.post('/api/payments/webhook', async (req, res) => {
|
||||||
|
|
||||||
// Process success callbacks asynchronously
|
// Process success callbacks asynchronously
|
||||||
if (isSuccessfulMidtransStatus(body)) {
|
if (isSuccessfulMidtransStatus(body)) {
|
||||||
logInfo('webhook.success_status', { order_id: orderId, transaction_status: body?.transaction_status, fraud_status: body?.fraud_status })
|
|
||||||
const nominal = String(grossAmount)
|
const nominal = String(grossAmount)
|
||||||
if (!notifiedOrders.has(orderId)) {
|
if (!notifiedOrders.has(orderId)) {
|
||||||
|
notifiedOrders.add(orderId)
|
||||||
// Mark order inactive upon completion
|
// Mark order inactive upon completion
|
||||||
activeOrders.delete(orderId)
|
activeOrders.delete(orderId)
|
||||||
const ok = await notifyERP({ orderId, nominal })
|
await notifyERP({ orderId, nominal })
|
||||||
if (ok) {
|
|
||||||
notifiedOrders.add(orderId)
|
|
||||||
} else {
|
|
||||||
logWarn('erp.notify.defer', { orderId, reason: 'post_failed_or_missing_data' })
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
logInfo('erp.notify.skip', { orderId, reason: 'already_notified' })
|
logInfo('erp.notify.skip', { orderId, reason: 'already_notified' })
|
||||||
}
|
}
|
||||||
|
|
@ -550,4 +539,4 @@ app.post('/api/payments/webhook', async (req, res) => {
|
||||||
const port = process.env.PORT || 8000
|
const port = process.env.PORT || 8000
|
||||||
app.listen(port, () => {
|
app.listen(port, () => {
|
||||||
console.log(`[server] listening on http://localhost:${port}/ (production=${isProduction})`)
|
console.log(`[server] listening on http://localhost:${port}/ (production=${isProduction})`)
|
||||||
})
|
})
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
417582e9fb7105b479e3e7aee99a285dbee0f2ec3238869f8f6fc36b6a098dbee411cf0d3e7637b69f41803518e640a6c9ae71a66b414b29e2182f5aed2ea55a
|
|
||||||
BIN
tmp-sig2.txt
BIN
tmp-sig2.txt
Binary file not shown.
|
|
@ -1 +0,0 @@
|
||||||
e781ba511b1675c05974b45db5f9ddc108d6d2d0acd62ba47fa4125094000512baf9b147689254ac88c406aade53921c9e7e3ae35c154809bdd7723014264667
|
|
||||||
Loading…
Reference in New Issue