|
|
const express = require('express'); |
|
|
const bodyParser = require('body-parser'); |
|
|
const { Pool } = require('pg'); |
|
|
const Redis = require('ioredis'); |
|
|
const fetch = require('node-fetch'); |
|
|
|
|
|
const pool = new Pool({ connectionString: process.env.DATABASE_URL || 'postgresql://localhost/integral' }); |
|
|
const redis = new Redis(process.env.REDIS_URL || 'redis://localhost:6379'); |
|
|
|
|
|
const app = express(); |
|
|
app.use(bodyParser.json()); |
|
|
|
|
|
redis.subscribe('payouts:created', () => console.log('listening for payouts')); |
|
|
|
|
|
redis.on('message', async (channel, msg) => { |
|
|
if (channel !== 'payouts:created') return; |
|
|
const { payoutId } = JSON.parse(msg); |
|
|
console.log('handle payout', payoutId); |
|
|
|
|
|
try { |
|
|
await settlePayout(payoutId); |
|
|
} catch (err) { |
|
|
console.error(err); |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
async function settlePayout(payoutId) { |
|
|
|
|
|
const r = await pool.query('SELECT * FROM payouts WHERE id=$1 FOR UPDATE', [payoutId]); |
|
|
if (r.rowCount === 0) throw new Error('payout not found'); |
|
|
const payout = r.rows[0]; |
|
|
if (payout.status !== 'created') return; |
|
|
|
|
|
|
|
|
await pool.query('UPDATE payouts SET status=$1 WHERE id=$2', ['processing', payoutId]); |
|
|
|
|
|
|
|
|
|
|
|
const remote = await fakePaymentGateway(payout); |
|
|
|
|
|
if (remote.success) { |
|
|
const txRef = remote.txRef; |
|
|
await pool.query('UPDATE payouts SET status=$1, tx_ref=$2, settled_at=now() WHERE id=$3', |
|
|
['settled', txRef, payoutId]); |
|
|
await redis.publish('payouts:settled', JSON.stringify({ payoutId, txRef })); |
|
|
} else { |
|
|
await pool.query('UPDATE payouts SET status=$1 WHERE id=$2', ['failed', payoutId]); |
|
|
await redis.publish('payouts:failed', JSON.stringify({ payoutId })); |
|
|
} |
|
|
} |
|
|
|
|
|
async function fakePaymentGateway(payout) { |
|
|
|
|
|
await new Promise(r => setTimeout(r, 600)); |
|
|
return { success: true, txRef: `TX-${Date.now()}-${Math.floor(Math.random()*1000)}` }; |
|
|
} |
|
|
|
|
|
app.post('/settle/:payoutId', async (req, res) => { |
|
|
try { |
|
|
const { payoutId } = req.params; |
|
|
await settlePayout(payoutId); |
|
|
res.json({ success: true }); |
|
|
} catch (err) { |
|
|
console.error(err); |
|
|
res.status(500).json({ success: false, error: err.message }); |
|
|
} |
|
|
}); |
|
|
|
|
|
app.listen(process.env.PORT || 3010, () => console.log('billing-service listening 3010')); |
|
|
|