@enomshop/paystack 1.0.7 → 1.0.9
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.
- package/.medusa/server/src/admin/index.js +344 -0
- package/.medusa/server/src/admin/index.mjs +345 -0
- package/.medusa/server/src/api/admin/orders/[id]/manual-payment/route.js +49 -0
- package/.medusa/server/src/api/admin/paystack/dashboard/route.js +132 -0
- package/.medusa/server/src/api/admin/plugin/route.js +7 -0
- package/.medusa/server/src/api/store/orders/[id]/paystack-payment/route.js +59 -0
- package/.medusa/server/src/api/store/plugin/route.js +7 -0
- package/.medusa/server/src/index.js +3 -0
- package/.medusa/server/src/jobs/sync-paystack-payments.js +70 -0
- package/.medusa/server/src/lib/paystack.js +107 -0
- package/.medusa/server/src/providers/paystack/index.js +11 -0
- package/.medusa/server/src/services/paystack-payment-processor.js +350 -0
- package/.medusa/server/src/subscribers/order-placed.js +103 -0
- package/.medusa/server/src/utils/currencyCode.js +9 -0
- package/package.json +1 -1
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.config = void 0;
|
|
4
|
+
exports.default = orderPlacedHandler;
|
|
5
|
+
const utils_1 = require("@medusajs/framework/utils");
|
|
6
|
+
const core_flows_1 = require("@medusajs/core-flows");
|
|
7
|
+
async function orderPlacedHandler({ event: { data }, container, }) {
|
|
8
|
+
const orderId = data.id;
|
|
9
|
+
const query = container.resolve("query");
|
|
10
|
+
const paymentModuleService = container.resolve(utils_1.Modules.PAYMENT);
|
|
11
|
+
const logger = container.resolve("logger");
|
|
12
|
+
// 1. Fetch Order with connected payments and items using Query
|
|
13
|
+
const { data: orders } = await query.graph({
|
|
14
|
+
entity: "order",
|
|
15
|
+
fields: [
|
|
16
|
+
"id",
|
|
17
|
+
"email",
|
|
18
|
+
"currency_code",
|
|
19
|
+
"total",
|
|
20
|
+
"items.*",
|
|
21
|
+
"payment_collections.payments.*"
|
|
22
|
+
],
|
|
23
|
+
filters: { id: orderId }
|
|
24
|
+
});
|
|
25
|
+
const order = orders[0];
|
|
26
|
+
if (!order)
|
|
27
|
+
return;
|
|
28
|
+
const pc = order.payment_collections?.[0];
|
|
29
|
+
if (!pc)
|
|
30
|
+
return;
|
|
31
|
+
// 2. Process the Payments
|
|
32
|
+
let isPaystackPayment = false;
|
|
33
|
+
let capturedAmount = 0;
|
|
34
|
+
for (const payment of pc.payments || []) {
|
|
35
|
+
if (payment.provider_id === "paystack" || payment.provider_id === "pp_paystack") {
|
|
36
|
+
isPaystackPayment = true;
|
|
37
|
+
capturedAmount = Number(payment.amount);
|
|
38
|
+
// Auto-capture if it hasn't been captured yet
|
|
39
|
+
if (!payment.captured_at) {
|
|
40
|
+
try {
|
|
41
|
+
await paymentModuleService.capturePayment({
|
|
42
|
+
payment_id: payment.id,
|
|
43
|
+
amount: payment.amount,
|
|
44
|
+
});
|
|
45
|
+
logger.info(`[Paystack] Successfully auto-captured payment for Order ${orderId}`);
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
logger.error(`[Paystack] Failed to auto-capture payment ${payment.id}:`, err);
|
|
49
|
+
return; // Stop if capture fails
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// Only proceed with fulfillment and email if this was a Paystack order
|
|
55
|
+
if (!isPaystackPayment)
|
|
56
|
+
return;
|
|
57
|
+
// 3. Verifying Amount
|
|
58
|
+
if (capturedAmount !== Number(order.total)) {
|
|
59
|
+
logger.warn(`[Paystack] Amount mismatch for Order ${orderId}. Total: ${order.total}, Captured: ${capturedAmount}`);
|
|
60
|
+
// You might want to flag the order here for manual review
|
|
61
|
+
}
|
|
62
|
+
// 4. Trigger Automatic Fulfillment
|
|
63
|
+
try {
|
|
64
|
+
await (0, core_flows_1.createOrderFulfillmentWorkflow)(container).run({
|
|
65
|
+
input: {
|
|
66
|
+
order_id: order.id,
|
|
67
|
+
items: order.items.map((i) => ({
|
|
68
|
+
id: i.id,
|
|
69
|
+
quantity: i.quantity,
|
|
70
|
+
})),
|
|
71
|
+
},
|
|
72
|
+
throwOnError: false,
|
|
73
|
+
});
|
|
74
|
+
logger.info(`[Paystack] Auto-fulfilled Order ${orderId}`);
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
logger.error(`[Paystack] Failed to auto-fulfill Order ${orderId}`, err);
|
|
78
|
+
}
|
|
79
|
+
// 5. Send Payment Confirmation Email
|
|
80
|
+
const notificationModule = container.resolve(utils_1.Modules.NOTIFICATION);
|
|
81
|
+
if (notificationModule) {
|
|
82
|
+
try {
|
|
83
|
+
await notificationModule.createNotifications([{
|
|
84
|
+
to: order.email,
|
|
85
|
+
channel: "email",
|
|
86
|
+
template: "paystack-payment-success",
|
|
87
|
+
data: {
|
|
88
|
+
order_id: order.id,
|
|
89
|
+
amount: capturedAmount,
|
|
90
|
+
currency: order.currency_code,
|
|
91
|
+
}
|
|
92
|
+
}]);
|
|
93
|
+
logger.info(`[Paystack] Payment confirmation email sent to ${order.email}`);
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
logger.error(`[Paystack] Failed to send email for Order ${orderId}`, err);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
exports.config = {
|
|
101
|
+
event: "order.placed",
|
|
102
|
+
};
|
|
103
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3JkZXItcGxhY2VkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3N1YnNjcmliZXJzL29yZGVyLXBsYWNlZC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFJQSxxQ0FvR0M7QUF2R0QscURBQW9EO0FBQ3BELHFEQUFzRTtBQUV2RCxLQUFLLFVBQVUsa0JBQWtCLENBQUMsRUFDL0MsS0FBSyxFQUFFLEVBQUUsSUFBSSxFQUFFLEVBQ2YsU0FBUyxHQUNzQjtJQUMvQixNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsRUFBRSxDQUFDO0lBRXhCLE1BQU0sS0FBSyxHQUFHLFNBQVMsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDekMsTUFBTSxvQkFBb0IsR0FBRyxTQUFTLENBQUMsT0FBTyxDQUFDLGVBQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUNoRSxNQUFNLE1BQU0sR0FBRyxTQUFTLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBRTNDLCtEQUErRDtJQUMvRCxNQUFNLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxHQUFHLE1BQU0sS0FBSyxDQUFDLEtBQUssQ0FBQztRQUN6QyxNQUFNLEVBQUUsT0FBTztRQUNmLE1BQU0sRUFBQztZQUNMLElBQUk7WUFDSixPQUFPO1lBQ1AsZUFBZTtZQUNmLE9BQU87WUFDUCxTQUFTO1lBQ1QsZ0NBQWdDO1NBQ2pDO1FBQ0QsT0FBTyxFQUFFLEVBQUUsRUFBRSxFQUFFLE9BQU8sRUFBRTtLQUN6QixDQUFDLENBQUM7SUFFSCxNQUFNLEtBQUssR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDeEIsSUFBSSxDQUFDLEtBQUs7UUFBRSxPQUFPO0lBRW5CLE1BQU0sRUFBRSxHQUFHLEtBQUssQ0FBQyxtQkFBbUIsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzFDLElBQUksQ0FBQyxFQUFFO1FBQUUsT0FBTztJQUVoQiwwQkFBMEI7SUFDMUIs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
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formatCurrencyCode = formatCurrencyCode;
|
|
4
|
+
function formatCurrencyCode(currencyCode) {
|
|
5
|
+
// Uppercase the currency code
|
|
6
|
+
const formattedCurrencyCode = currencyCode.toUpperCase();
|
|
7
|
+
return formattedCurrencyCode;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3VycmVuY3lDb2RlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3V0aWxzL2N1cnJlbmN5Q29kZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLGdEQUtDO0FBTEQsU0FBZ0Isa0JBQWtCLENBQUMsWUFBb0I7SUFDckQsOEJBQThCO0lBQzlCLE1BQU0scUJBQXFCLEdBQUcsWUFBWSxDQUFDLFdBQVcsRUFBRSxDQUFDO0lBRXpELE9BQU8scUJBQXFCLENBQUM7QUFDL0IsQ0FBQyJ9
|