@enomshop/paystack 1.0.12 → 1.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -28,11 +28,9 @@ async function POST(req, res) {
|
|
|
28
28
|
});
|
|
29
29
|
// 2. Authorize the session to create the actual Payment record in the DB
|
|
30
30
|
const authorizedPayment = await paymentModule.authorizePaymentSession(paymentSession.id, {});
|
|
31
|
-
// 3. ✨ Use the core workflow to capture the payment so the Order Module is updated ✨
|
|
32
31
|
await (0, core_flows_1.capturePaymentWorkflow)(req.scope).run({
|
|
33
32
|
input: {
|
|
34
33
|
payment_id: authorizedPayment.id,
|
|
35
|
-
amount: amount,
|
|
36
34
|
}
|
|
37
35
|
});
|
|
38
36
|
res.status(200).json({
|
|
@@ -43,4 +41,4 @@ async function POST(req, res) {
|
|
|
43
41
|
res.status(500).json({ message: error.message });
|
|
44
42
|
}
|
|
45
43
|
}
|
|
46
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
44
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL29yZGVycy9baWRdL21hbnVhbC1wYXltZW50L3JvdXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBSUEsb0JBbURDO0FBdERELHFEQUFvRDtBQUNwRCxxREFBOEQ7QUFFdkQsS0FBSyxVQUFVLElBQUksQ0FBQyxHQUFrQixFQUFFLEdBQW1CO0lBQ2hFLE1BQU0sRUFBRSxFQUFFLEVBQUUsUUFBUSxFQUFFLEdBQUcsR0FBRyxDQUFDLE1BQU0sQ0FBQztJQUNwQyxNQUFNLEVBQUUsTUFBTSxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsR0FBRyxHQUFHLENBQUMsSUFJdkMsQ0FBQztJQUVGLE1BQU0sYUFBYSxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLGVBQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUV6RCxJQUFJLENBQUM7UUFDSCxNQUFNLEtBQUssR0FBRyxHQUFHLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUN6QyxNQUFNLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxHQUFHLE1BQU0sS0FBSyxDQUFDLEtBQUssQ0FBQztZQUN6QyxNQUFNLEVBQUUsT0FBTztZQUNmLE1BQU0sRUFBRSxDQUFDLElBQUksRUFBRSxlQUFlLEVBQUUsdUJBQXVCLENBQUM7WUFDeEQsT0FBTyxFQUFFLEVBQUUsRUFBRSxFQUFFLFFBQVEsRUFBRTtTQUMxQixDQUFDLENBQUM7UUFFSCxNQUFNLEtBQUssR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDeEIsTUFBTSxpQkFBaUIsR0FBRyxLQUFLLENBQUMsbUJBQW1CLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUV6RCxJQUFJLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztZQUN2QixPQUFPLEdBQUcsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUUsT0FBTyxFQUFFLDRDQUE0QyxFQUFFLENBQUMsQ0FBQztRQUN6RixDQUFDO1FBRUQscURBQXFEO1FBQ3JELE1BQU0sY0FBYyxHQUFHLE1BQU0sYUFBYSxDQUFDLG9CQUFvQixDQUFDLGlCQUFpQixDQUFDLEVBQUUsRUFBRTtZQUNwRixXQUFXLEVBQUUsbUJBQW1CO1lBQ2hDLE1BQU0sRUFBRSxNQUFNO1lBQ2QsYUFBYSxFQUFFLEtBQUssQ0FBQyxhQUFhO1lBQ2xDLElBQUksRUFBRSxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRTtTQUN4QyxDQUFDLENBQUM7UUFFSCx5RUFBeUU7UUFDekUsTUFBTSxpQkFBaUIsR0FBRyxNQUFNLGFBQWEsQ0FBQyx1QkFBdUIsQ0FDbkUsY0FBYyxDQUFDLEVBQUUsRUFDakIsRUFBRSxDQUNILENBQUM7UUFFRixNQUFNLElBQUEsbUNBQXNCLEVBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDLEdBQUcsQ0FBQztZQUMxQyxLQUFLLEVBQUU7Z0JBQ0wsVUFBVSxFQUFFLGlCQUFpQixDQUFDLEVBQUU7YUFDakM7U0FDRixDQUFDLENBQUM7UUFFSCxHQUFHLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQztZQUNuQixPQUFPLEVBQUUsbURBQW1EO1NBQzdELENBQUMsQ0FBQztJQUNMLENBQUM7SUFBQyxPQUFPLEtBQVUsRUFBRSxDQUFDO1FBQ3BCLEdBQUcsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUUsT0FBTyxFQUFFLEtBQUssQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDO0lBQ25ELENBQUM7QUFDSCxDQUFDIn0=
|
|
@@ -5,23 +5,40 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.config = void 0;
|
|
7
7
|
exports.default = syncPaystackPayments;
|
|
8
|
-
const utils_1 = require("@medusajs/framework/utils");
|
|
9
8
|
const paystack_1 = __importDefault(require("../lib/paystack"));
|
|
10
9
|
const core_flows_1 = require("@medusajs/core-flows");
|
|
11
10
|
// Helper to prevent hitting Paystack rate limits
|
|
12
11
|
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
13
12
|
async function syncPaystackPayments(container) {
|
|
14
|
-
const paymentModuleService = container.resolve(utils_1.Modules.PAYMENT);
|
|
15
13
|
const logger = container.resolve("logger");
|
|
14
|
+
const query = container.resolve("query");
|
|
16
15
|
logger.info("Starting Paystack payment sync...");
|
|
17
16
|
try {
|
|
18
|
-
// @ts-ignore
|
|
19
|
-
const payments = await paymentModuleService.listPayments({
|
|
20
|
-
id: "pp_paystack",
|
|
21
|
-
});
|
|
22
|
-
// 2. Filter for pending payments that are OLDER than 15 minutes
|
|
23
|
-
// This prevents race conditions with incoming webhooks
|
|
24
17
|
const fifteenMinutesAgo = new Date(Date.now() - 15 * 60 * 1000);
|
|
18
|
+
const { data: payments } = await query.graph({
|
|
19
|
+
entity: "payment",
|
|
20
|
+
fields: [
|
|
21
|
+
"id",
|
|
22
|
+
"amount",
|
|
23
|
+
"currency_code",
|
|
24
|
+
"data",
|
|
25
|
+
"created_at"
|
|
26
|
+
],
|
|
27
|
+
filters: {
|
|
28
|
+
// 1. Only Paystack payments
|
|
29
|
+
payment_session: {
|
|
30
|
+
provider_id: "pp_paystack",
|
|
31
|
+
},
|
|
32
|
+
// 2. Must be uncaptured (null)
|
|
33
|
+
captured_at: null,
|
|
34
|
+
// 3. Must not be canceled (null)
|
|
35
|
+
canceled_at: null,
|
|
36
|
+
// 4. Must be older than 15 minutes ($lt = Less Than)
|
|
37
|
+
created_at: {
|
|
38
|
+
$lt: fifteenMinutesAgo,
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
});
|
|
25
42
|
const pendingPayments = payments.filter((p) => !p.captured_at &&
|
|
26
43
|
!p.canceled_at &&
|
|
27
44
|
p.created_at && new Date(p.created_at) < fifteenMinutesAgo);
|
|
@@ -37,11 +54,9 @@ async function syncPaystackPayments(container) {
|
|
|
37
54
|
const txRef = payment.data?.paystackTxRef;
|
|
38
55
|
if (!txRef)
|
|
39
56
|
continue;
|
|
40
|
-
// 3. Verify transaction status with Paystack
|
|
41
57
|
const { data, status } = await paystack.transaction.verify(txRef);
|
|
42
58
|
if (status && data.status === "success") {
|
|
43
59
|
logger.info(`Capturing payment ${payment.id} from Paystack sync`);
|
|
44
|
-
// 4. Capture the payment in Medusa
|
|
45
60
|
await (0, core_flows_1.capturePaymentWorkflow)(container).run({
|
|
46
61
|
input: {
|
|
47
62
|
payment_id: payment.id,
|
|
@@ -50,10 +65,7 @@ async function syncPaystackPayments(container) {
|
|
|
50
65
|
}
|
|
51
66
|
else if (status && (data.status === "failed" || data.status === "abandoned")) {
|
|
52
67
|
logger.info(`Canceling failed/abandoned payment ${payment.id} from Paystack sync`);
|
|
53
|
-
// Optional: You can cancel the payment in Medusa to clean up the database
|
|
54
|
-
// await paymentModuleService.cancelPayment(payment.id);
|
|
55
68
|
}
|
|
56
|
-
// 5. Sleep for 200ms to respect Paystack API rate limits (approx 5 req/sec)
|
|
57
69
|
await sleep(200);
|
|
58
70
|
}
|
|
59
71
|
catch (error) {
|
|
@@ -67,6 +79,6 @@ async function syncPaystackPayments(container) {
|
|
|
67
79
|
}
|
|
68
80
|
exports.config = {
|
|
69
81
|
name: "sync-paystack-payments",
|
|
70
|
-
schedule: "*/
|
|
82
|
+
schedule: "*/5 * * * *",
|
|
71
83
|
};
|
|
72
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
84
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3luYy1wYXlzdGFjay1wYXltZW50cy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9qb2JzL3N5bmMtcGF5c3RhY2stcGF5bWVudHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBUUEsdUNBK0VDO0FBckZELCtEQUF1QztBQUN2QyxxREFBOEQ7QUFFOUQsaURBQWlEO0FBQ2pELE1BQU0sS0FBSyxHQUFHLENBQUMsRUFBVSxFQUFFLEVBQUUsQ0FBQyxJQUFJLE9BQU8sQ0FBQyxDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUMsVUFBVSxDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDO0FBRWpFLEtBQUssVUFBVSxvQkFBb0IsQ0FBQyxTQUEwQjtJQUMzRSxNQUFNLE1BQU0sR0FBRyxTQUFTLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQzNDLE1BQU0sS0FBSyxHQUFHLFNBQVMsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUM7SUFFekMsTUFBTSxDQUFDLElBQUksQ0FBQyxtQ0FBbUMsQ0FBQyxDQUFDO0lBRWpELElBQUksQ0FBQztRQUNILE1BQU0saUJBQWlCLEdBQUcsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDLENBQUM7UUFFaEUsTUFBTSxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsR0FBRyxNQUFNLEtBQUssQ0FBQyxLQUFLLENBQUM7WUFDM0MsTUFBTSxFQUFFLFNBQVM7WUFDakIsTUFBTSxFQUFFO2dCQUNOLElBQUk7Z0JBQ0osUUFBUTtnQkFDUixlQUFlO2dCQUNmLE1BQU07Z0JBQ04sWUFBWTthQUNiO1lBQ0QsT0FBTyxFQUFFO2dCQUNQLDRCQUE0QjtnQkFDNUIsZUFBZSxFQUFFO29CQUNmLFdBQVcsRUFBRSxhQUFhO2lCQUMzQjtnQkFDRCwrQkFBK0I7Z0JBQy9CLFdBQVcsRUFBRSxJ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
|
|
@@ -7,9 +7,7 @@ const core_flows_1 = require("@medusajs/core-flows");
|
|
|
7
7
|
async function PaystackOrderPlacedHandler({ event: { data }, container, }) {
|
|
8
8
|
const orderId = data.id;
|
|
9
9
|
const query = container.resolve("query");
|
|
10
|
-
const paymentModuleService = container.resolve(utils_1.Modules.PAYMENT);
|
|
11
10
|
const logger = container.resolve("logger");
|
|
12
|
-
// 1. Fetch Order with connected payments and items using Query
|
|
13
11
|
const { data: orders } = await query.graph({
|
|
14
12
|
entity: "order",
|
|
15
13
|
fields: [
|
|
@@ -23,21 +21,18 @@ async function PaystackOrderPlacedHandler({ event: { data }, container, }) {
|
|
|
23
21
|
filters: { id: orderId }
|
|
24
22
|
});
|
|
25
23
|
const order = orders[0];
|
|
26
|
-
if (!order)
|
|
24
|
+
if (!order || !order.payment_collections?.[0])
|
|
27
25
|
return;
|
|
28
|
-
const pc = order.payment_collections?.[0];
|
|
29
|
-
if (!pc)
|
|
30
|
-
return;
|
|
31
|
-
// 2. Process the Payments
|
|
32
26
|
let isPaystackPayment = false;
|
|
33
27
|
let capturedAmount = 0;
|
|
34
|
-
for (const payment of
|
|
28
|
+
for (const payment of order.payment_collections[0].payments || []) {
|
|
35
29
|
if (payment.provider_id === "paystack" || payment.provider_id === "pp_paystack") {
|
|
36
30
|
isPaystackPayment = true;
|
|
37
31
|
capturedAmount = Number(payment.amount);
|
|
38
32
|
if (!payment.captured_at) {
|
|
39
33
|
try {
|
|
40
|
-
// 2.
|
|
34
|
+
// 2. Pass the PAYMENT ID, not the Order ID.
|
|
35
|
+
// This creates the Order Transaction in the isolated Order Module automatically.
|
|
41
36
|
await (0, core_flows_1.capturePaymentWorkflow)(container).run({
|
|
42
37
|
input: {
|
|
43
38
|
payment_id: payment.id,
|
|
@@ -101,4 +96,4 @@ async function PaystackOrderPlacedHandler({ event: { data }, container, }) {
|
|
|
101
96
|
exports.config = {
|
|
102
97
|
event: "order.placed",
|
|
103
98
|
};
|
|
104
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
99
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3JkZXItcGxhY2VkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3N1YnNjcmliZXJzL29yZGVyLXBsYWNlZC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFJQSw2Q0FpR0M7QUFwR0QscURBQW9EO0FBQ3BELHFEQUE4RjtBQUUvRSxLQUFLLFVBQVUsMEJBQTBCLENBQUMsRUFDdkQsS0FBSyxFQUFFLEVBQUUsSUFBSSxFQUFFLEVBQ2YsU0FBUyxHQUNzQjtJQUMvQixNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsRUFBRSxDQUFDO0lBRXhCLE1BQU0sS0FBSyxHQUFHLFNBQVMsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDekMsTUFBTSxNQUFNLEdBQUcsU0FBUyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUUzQyxNQUFNLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxHQUFHLE1BQU0sS0FBSyxDQUFDLEtBQUssQ0FBQztRQUN6QyxNQUFNLEVBQUUsT0FBTztRQUNmLE1BQU0sRUFBQztZQUNMLElBQUk7WUFDSixPQUFPO1lBQ1AsZUFBZTtZQUNmLE9BQU87WUFDUCxTQUFTO1lBQ1QsZ0NBQWdDO1NBQ2pDO1FBQ0QsT0FBTyxFQUFFLEVBQUUsRUFBRSxFQUFFLE9BQU8sRUFBRTtLQUN6QixDQUFDLENBQUM7SUFFSCxNQUFNLEtBQUssR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDeEIsSUFBSSxDQUFDLEtBQUssSUFBSSxDQUFDLEtBQUssQ0FBQyxtQkFBbUIsRUFBRSxDQUFDLENBQUMsQ0FBQztRQUFFLE9BQU87SUFFdEQsSUFBSSxpQkFBaUIsR0FBRyxLQUFLLENBQUM7SUFDOUIsSUFBSSxjQUFjLEdBQUcsQ0FBQyxDQUFDO0lBRXZCLEtBQUssTUFBTSxPQUFPLElBQUksS0FBSyxDQUFDLG1CQUFtQixDQUFDLENBQUMsQ0FBQyxDQUFDLFFBQVEsSUFBRyxFQUFFLEVBQUUs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
|