-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp.js
More file actions
152 lines (126 loc) · 3.93 KB
/
app.js
File metadata and controls
152 lines (126 loc) · 3.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
const express = require('express');
const cron = require('node-cron');
const db = require('./db');
const TransactionModel = require('./models/transaction');
const { initiateCreditPayment } = require('./services/payment/initiateCredit');
const { createPaymentProvider } = require('./services/payment/factory');
const {
fulfillSuccessfulCredit,
markTransactionFailed,
} = require('./services/payment/creditFulfillment');
const { runReconcileOnce } = require('./jobs/reconcilePending');
const port = process.env.PORT || 3000;
const app = express();
app.use(express.json());
db.connect();
// Production often runs reconciliation in a separate worker; in-process cron is for teaching demos.
cron.schedule('*/5 * * * *', () => {
runReconcileOnce().catch((err) => console.error('reconcile cron', err));
});
app.get('/', (req, res) => {
const name = req.query.name || 'World';
res.send(`Welcome To Paystack Integration, I see you ${name}`);
});
app.post('/initiate_transaction', async (req, res) => {
try {
if (!req.body.amountInNaira || !req.body.email) {
return res.status(400).json({
message: 'Invalid request, add amountInNaira and/or email',
});
}
const amount = Number(req.body.amountInNaira);
if (Number.isNaN(amount) || amount <= 0) {
return res.status(400).json({ message: 'Invalid amountInNaira' });
}
const { paystackResponse } = await initiateCreditPayment({
amount,
email: req.body.email,
});
return res.json(paystackResponse);
} catch (error) {
return res.status(500).json({
message: 'Something went wrong',
});
}
});
app.get('/generate_url', async (req, res) => {
if (!req.query.amount || !req.query.email) {
return res.status(400).json({
message: 'Invalid request, add amount and/or email',
});
}
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(req.query.email)) {
return res.status(400).json({
message: 'Invalid email',
});
}
const amount = Number(req.query.amount);
if (Number.isNaN(amount) || amount <= 0) {
return res.status(400).json({ message: 'Invalid amount' });
}
try {
const { init } = await initiateCreditPayment({
amount,
email: req.query.email,
});
return res.json({
url: init.authorizationUrl,
});
} catch (e) {
console.error(e);
return res.status(500).json({ message: 'Something went wrong' });
}
});
app.get('/paystack/info', async (req, res) => {
return res.json({
message: 'Transaction successful',
});
});
app.post('/stripe/callback', async (req, res) => {
const provider = createPaymentProvider('stripe');
return res.json({
message: 'Stripe callback received',
});
});
app.post('/paystack/success', async (req, res) => {
return res.json({
message: 'Successfully processed payment',
});
});
app.post('/paystack/callback', async (req, res) => {
const body = req.body;
const paystack = createPaymentProvider('paystack');
const normalized = paystack.normalizeWebhookPayload(body);
if (!normalized.reference) {
return res.status(400).json({ message: 'Invalid webhook payload' });
}
// ensure the transaction is pending
const transaction = await TransactionModel.findOne({
_id: normalized.reference,
status: 'pending',
});
if (!transaction) {
console.log('Transaction not found');
return res.status(404).json({
message: 'Transaction not found',
});
}
console.log('Transaction found', normalized.reference);
// routing
if (normalized.succeeded) {
const result = await fulfillSuccessfulCredit(normalized.reference);
if (!result.applied) {
console.log('Duplicate or late success webhook; already finalized');
}
}
if (normalized.failed) {
await markTransactionFailed(normalized.reference);
}
return res.status(200).json({
message: 'Callback received',
});
});
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});