@enomshop/paystack 1.0.7 → 1.0.10

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.
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.config = void 0;
7
+ exports.default = syncPaystackPayments;
8
+ const utils_1 = require("@medusajs/framework/utils");
9
+ const paystack_1 = __importDefault(require("../lib/paystack"));
10
+ // Helper to prevent hitting Paystack rate limits
11
+ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
12
+ async function syncPaystackPayments(container) {
13
+ const paymentModuleService = container.resolve(utils_1.Modules.PAYMENT);
14
+ const logger = container.resolve("logger");
15
+ logger.info("Starting Paystack payment sync...");
16
+ try {
17
+ // @ts-ignore
18
+ const payments = await paymentModuleService.listPayments({
19
+ id: "pp_paystack",
20
+ });
21
+ // 2. Filter for pending payments that are OLDER than 15 minutes
22
+ // This prevents race conditions with incoming webhooks
23
+ const fifteenMinutesAgo = new Date(Date.now() - 15 * 60 * 1000);
24
+ const pendingPayments = payments.filter((p) => !p.captured_at &&
25
+ !p.canceled_at &&
26
+ p.created_at && new Date(p.created_at) < fifteenMinutesAgo);
27
+ if (pendingPayments.length === 0) {
28
+ logger.info("No stale pending Paystack payments found.");
29
+ return;
30
+ }
31
+ logger.info(`Found ${pendingPayments.length} stale payments to verify.`);
32
+ // Initialize Paystack client
33
+ const paystack = new paystack_1.default(process.env.PAYSTACK_SECRET_KEY);
34
+ for (const payment of pendingPayments) {
35
+ try {
36
+ const txRef = payment.data?.paystackTxRef;
37
+ if (!txRef)
38
+ continue;
39
+ // 3. Verify transaction status with Paystack
40
+ const { data, status } = await paystack.transaction.verify(txRef);
41
+ if (status && data.status === "success") {
42
+ logger.info(`Capturing payment ${payment.id} from Paystack sync`);
43
+ // 4. Capture the payment in Medusa
44
+ await paymentModuleService.capturePayment({
45
+ payment_id: payment.id,
46
+ amount: payment.amount,
47
+ });
48
+ }
49
+ else if (status && (data.status === "failed" || data.status === "abandoned")) {
50
+ logger.info(`Canceling failed/abandoned payment ${payment.id} from Paystack sync`);
51
+ // Optional: You can cancel the payment in Medusa to clean up the database
52
+ // await paymentModuleService.cancelPayment(payment.id);
53
+ }
54
+ // 5. Sleep for 200ms to respect Paystack API rate limits (approx 5 req/sec)
55
+ await sleep(200);
56
+ }
57
+ catch (error) {
58
+ logger.error(`Error syncing Paystack payment ${payment.id}:`, error);
59
+ }
60
+ }
61
+ }
62
+ catch (error) {
63
+ logger.error("Error running Paystack payment sync job:", error);
64
+ }
65
+ }
66
+ exports.config = {
67
+ name: "sync-paystack-payments",
68
+ schedule: "*/15 * * * *", // Runs every 15 minutes
69
+ };
70
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3luYy1wYXlzdGFjay1wYXltZW50cy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9qb2JzL3N5bmMtcGF5c3RhY2stcGF5bWVudHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBT0EsdUNBaUVDO0FBdkVELHFEQUFvRDtBQUNwRCwrREFBdUM7QUFFdkMsaURBQWlEO0FBQ2pELE1BQU0sS0FBSyxHQUFHLENBQUMsRUFBVSxFQUFFLEVBQUUsQ0FBQyxJQUFJLE9BQU8sQ0FBQyxDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUMsVUFBVSxDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDO0FBRWpFLEtBQUssVUFBVSxvQkFBb0IsQ0FBQyxTQUEwQjtJQUMzRSxNQUFNLG9CQUFvQixHQUFHLFNBQVMsQ0FBQyxPQUFPLENBQUMsZUFBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ2hFLE1BQU0sTUFBTSxHQUFHLFNBQVMsQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUM7SUFFM0MsTUFBTSxDQUFDLElBQUksQ0FBQyxtQ0FBbUMsQ0FBQyxDQUFDO0lBRWpELElBQUksQ0FBQztRQUNMLGFBQWE7UUFDYixNQUFNLFFBQVEsR0FBRyxNQUFNLG9CQUFvQixDQUFDLFlBQVksQ0FBQztZQUN2RCxFQUFFLEVBQUUsYUFBYTtTQUNsQixDQUFDLENBQUM7UUFFRCxnRUFBZ0U7UUFDaEUsdURBQXVEO1FBQ3ZELE1BQU0saUJBQWlCLEdBQUcsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDLENBQUM7UUFFaEUsTUFBTSxlQUFlLEdBQUcsUUFBUSxDQUFDLE1BQU0sQ0FDckMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUNKLENBQUMsQ0FBQyxDQUFDLFdBQVc7WUFDZCxDQUFDLENBQUMsQ0FBQyxXQUFXO1lBQ2QsQ0FBQyxDQUFDLFVBQVUsSUFBSSxJQUFJLElBQUksQ0FBQyxDQUFDLENBQUMsVUFBaUIsQ0FBQyxHQUFHLGlCQUFpQixDQUNwRSxDQUFDO1FBRUYsSUFBSSxlQUFlLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQ2pDLE1BQU0sQ0FBQyxJQUFJLENBQUMsMkNBQTJDLENBQUMsQ0FBQztZQUN6RCxPQUFPO1FBQ1QsQ0FBQztRQUVELE1BQU0sQ0FBQyxJQUFJLENBQUMsU0FBUyxlQUFlLENBQUMsTUFBTSw0QkFBNEIsQ0FBQyxDQUFDO1FBRXpFLDZCQUE2QjtRQUM3QixNQUFNLFFBQVEsR0FBRyxJQUFJLGtCQUFRLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxtQkFBNkIsQ0FBQyxDQUFDO1FBRXpFLEtBQUssTUFBTSxPQUFPLElBQUksZUFBZSxFQUFFLENBQUM7WUFDdEMsSUFBSSxDQUFDO2dCQUNILE1BQU0sS0FBSyxHQUFHLE9BQU8sQ0FBQyxJQUFJLEVBQUUsYUFBdUIsQ0FBQztnQkFDcEQsSUFBSSxDQUFDLEtBQUs7b0JBQUUsU0FBUztnQkFFckIsNkNBQTZDO2dCQUM3QyxNQUFNLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxHQUFHLE1BQU0sUUFBUSxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7Z0JBRWxFLElBQUksTUFBTSxJQUFJLElBQUksQ0FBQyxNQUFNLEtBQUssU0FBUyxFQUFFLENBQUM7b0JBQ3hDLE1BQU0sQ0FBQyxJQUFJLENBQUMscUJBQXFCLE9BQU8sQ0FBQyxFQUFFLHFCQUFxQixDQUFDLENBQUM7b0JBRWxFLG1DQUFtQztvQkFDbkMsTUFBTSxvQkFBb0IsQ0FBQyxjQUFjLENBQUM7d0JBQ3hDLFVBQVUsRUFBRSxPQUFPLENBQUMsRUFBRTt3QkFDdEIsTUFBTSxFQUFFLE9BQU8sQ0FBQyxNQUFNO3FCQUN2QixDQUFDLENBQUM7Z0JBQ0wsQ0FBQztxQkFBTSxJQUFJLE1BQU0sSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLEtBQUssUUFBUSxJQUFJLElBQUksQ0FBQyxNQUFNLEtBQUssV0FBVyxDQUFDLEVBQUUsQ0FBQztvQkFDL0UsTUFBTSxDQUFDLElBQUksQ0FBQyxzQ0FBc0MsT0FBTyxDQUFDLEVBQUUscUJBQXFCLENBQUMsQ0FBQztvQkFDbkYsMEVBQTBFO29CQUMxRSx3REFBd0Q7Z0JBQzFELENBQUM7Z0JBRUQsNEVBQTRFO2dCQUM1RSxNQUFNLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUVuQixDQUFDO1lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztnQkFDZixNQUFNLENBQUMsS0FBSyxDQUFDLGtDQUFrQyxPQUFPLENBQUMsRUFBRSxHQUFHLEVBQUUsS0FBSyxDQUFDLENBQUM7WUFDdkUsQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDO0lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztRQUNmLE1BQU0sQ0FBQyxLQUFLLENBQUMsMENBQTBDLEVBQUUsS0FBSyxDQUFDLENBQUM7SUFDbEUsQ0FBQztBQUNILENBQUM7QUFFWSxRQUFBLE1BQU0sR0FBRztJQUNwQixJQUFJLEVBQUUsd0JBQXdCO0lBQzlCLFFBQVEsRUFBRSxjQUFjLEVBQUUsd0JBQXdCO0NBQ25ELENBQUMifQ==
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.PAYSTACK_API_PATH = void 0;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ const axios_retry_1 = __importDefault(require("axios-retry"));
9
+ exports.PAYSTACK_API_PATH = "https://api.paystack.co";
10
+ class Paystack {
11
+ constructor(apiKey, options) {
12
+ this.transaction = {
13
+ get: ({ id }) => this.requestPaystackAPI({
14
+ path: "/transaction/" + id,
15
+ method: "GET",
16
+ }),
17
+ list: (query) => this.requestPaystackAPI({
18
+ path: "/transaction",
19
+ method: "GET",
20
+ query: query,
21
+ }),
22
+ balance: () => this.requestPaystackAPI({
23
+ path: "/balance",
24
+ method: "GET",
25
+ }),
26
+ verify: (reference) => this.requestPaystackAPI({
27
+ path: "/transaction/verify/" + reference,
28
+ method: "GET",
29
+ }),
30
+ totals: () => this.requestPaystackAPI({
31
+ path: "/transaction/totals",
32
+ method: "GET",
33
+ }),
34
+ initialize: ({ amount, email, currency, reference, callback_url, metadata, }) => this.requestPaystackAPI({
35
+ path: "/transaction/initialize",
36
+ method: "POST",
37
+ body: {
38
+ amount,
39
+ email,
40
+ currency,
41
+ reference,
42
+ callback_url,
43
+ metadata: metadata ? JSON.stringify(metadata) : undefined,
44
+ },
45
+ }),
46
+ };
47
+ this.refund = {
48
+ create: ({ transaction, amount, }) => this.requestPaystackAPI({
49
+ path: "/refund",
50
+ method: "POST",
51
+ body: {
52
+ transaction,
53
+ amount,
54
+ },
55
+ }),
56
+ };
57
+ this.customer = {
58
+ create: (data) => this.requestPaystackAPI({
59
+ path: "/customer",
60
+ method: "POST",
61
+ body: data, // Cast to match your Request interface expectations
62
+ }),
63
+ update: (customerCode, data) => this.requestPaystackAPI({
64
+ path: `/customer/${customerCode}`,
65
+ method: "PUT",
66
+ body: data,
67
+ }),
68
+ };
69
+ this.apiKey = apiKey;
70
+ this.axiosInstance = axios_1.default.create({
71
+ baseURL: exports.PAYSTACK_API_PATH,
72
+ headers: {
73
+ Authorization: `Bearer ${this.apiKey}`,
74
+ "Content-Type": "application/json",
75
+ },
76
+ });
77
+ if (options?.disable_retries !== true) {
78
+ (0, axios_retry_1.default)(this.axiosInstance, {
79
+ retries: 3,
80
+ // Enables retries on network errors, idempotent http methods, and 5xx errors
81
+ retryCondition: axios_retry_1.default.isNetworkOrIdempotentRequestError,
82
+ // Exponential backoff with jitter
83
+ retryDelay: axios_retry_1.default.exponentialDelay,
84
+ });
85
+ }
86
+ }
87
+ async requestPaystackAPI(request) {
88
+ const options = {
89
+ method: request.method,
90
+ url: request.path,
91
+ params: request.query,
92
+ data: request.body,
93
+ };
94
+ try {
95
+ const res = await this.axiosInstance(options);
96
+ return res.data;
97
+ }
98
+ catch (error) {
99
+ if (axios_1.default.isAxiosError(error)) {
100
+ throw new Error(`Error from Paystack API with status code ${error.response?.status}: ${error.response?.data?.message}`);
101
+ }
102
+ throw error;
103
+ }
104
+ }
105
+ }
106
+ exports.default = Paystack;
107
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGF5c3RhY2suanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL3BheXN0YWNrLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBLGtEQUFpRTtBQUNqRSw4REFBcUM7QUFFeEIsUUFBQSxpQkFBaUIsR0FBRyx5QkFBeUIsQ0FBQztBQW1DM0QsTUFBcUIsUUFBUTtJQUszQixZQUFZLE1BQWMsRUFBRSxPQUFnQztRQTJDNUQsZ0JBQVcsR0FBRztZQUNaLEdBQUcsRUFBRSxDQUFDLEVBQUUsRUFBRSxFQUFrQixFQUFFLEVBQUUsQ0FDOUIsSUFBSSxDQUFDLGtCQUFrQixDQU1yQjtnQkFDQSxJQUFJLEVBQUUsZUFBZSxHQUFHLEVBQUU7Z0JBQzFCLE1BQU0sRUFBRSxLQUFLO2FBQ2QsQ0FBQztZQUNKLElBQUksRUFBRSxDQUFDLEtBQTRELEVBQUUsRUFBRSxDQUNyRSxJQUFJLENBQUMsa0JBQWtCLENBZXJCO2dCQUNBLElBQUksRUFBRSxjQUFjO2dCQUNwQixNQUFNLEVBQUUsS0FBSztnQkFDYixLQUFLLEVBQUUsS0FBK0I7YUFDdkMsQ0FBQztZQUNKLE9BQU8sRUFBRSxHQUFHLEVBQUUsQ0FDWixJQUFJLENBQUMsa0JBQWtCLENBRXJCO2dCQUNBLElBQUksRUFBRSxVQUFVO2dCQUNoQixNQUFNLEVBQUUsS0FBSzthQUNkLENBQUM7WUFDSixNQUFNLEVBQUUsQ0FBQyxTQUFpQixFQUFFLEVBQUUsQ0FDNUIsSUFBSSxDQUFDLGtCQUFrQixDQWVyQjtnQkFDQSxJQUFJLEVBQUUsc0JBQXNCLEdBQUcsU0FBUztnQkFDeEMsTUFBTSxFQUFFLEtBQUs7YUFDZCxDQUFDO1lBQ0osTUFBTSxFQUFFLEdBQUcsRUFBRSxDQUNYLElBQUksQ0FBQyxrQkFBa0IsQ0FPckI7Z0JBQ0EsSUFBSSxFQUFFLHFCQUFxQjtnQkFDM0IsTUFBTSxFQUFFLEtBQUs7YUFDZCxDQUFDO1lBQ0osVUFBVSxFQUFFLENBQUMsRUFDWCxNQUFNLEVBQ04sS0FBSyxFQUNMLFFBQVEsRUFDUixTQUFTLEVBQ1QsWUFBWSxFQUNaLFFBQVEsR0FRVCxFQUFFLEVBQUUsQ0FDSCxJQUFJLENBQUMsa0JBQWtCLENBTXJCO2dCQUNBLElBQUksRUFBRSx5QkFBeUI7Z0JBQy9CLE1BQU0sRUFBRSxNQUFNO2dCQUNkLElBQUksRUFBRTtvQkFDSixNQUFNO29CQUNOLEtBQUs7b0JBQ0wsUUFBUTtvQkFDUixTQUFTO29CQUNULFlBQVk7b0JBQ1osUUFBUSxFQUFFLFFBQVEsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUztpQkFDMUQ7YUFDRixDQUFDO1NBQ0wsQ0FBQztRQUVGLFdBQU0sR0FBRztZQUNQLE1BQU0sRUFBRSxDQUFDLEVBQ1AsV0FBVyxFQUNYLE1BQU0sR0FJUCxFQUFFLEVBQUUsQ0FDSCxJQUFJLENBQUMsa0JBQWtCLENBT3JCO2dCQUNBLElBQUksRUFBRSxTQUFTO2dCQUNmLE1BQU0sRUFBRSxNQUFNO2dCQUNkLElBQUksRUFBRTtvQkFDSixXQUFXO29CQUNYLE1BQU07aUJBQ1A7YUFDRixDQUFDO1NBQ0wsQ0FBQztRQUVGLGFBQVEsR0FBRztZQUNULE1BQU0sRUFBRSxDQUFDLElBS1IsRUFBRSxFQUFFLENBQ0gsSUFBSSxDQUFDLGtCQUFrQixDQVVyQjtnQkFDQSxJQUFJLEVBQUUsV0FBVztnQkFDakIsTUFBTSxFQUFFLE1BQU07Z0JBQ2QsSUFBSSxFQUFFLElBQStCLEVBQUUsb0RBQW9EO2FBQzVGLENBQUM7WUFFSixNQUFNLEVBQUUsQ0FDTixZQUFvQixFQUNwQixJQUlDLEVBQ0QsRUFBRSxDQUNGLElBQUksQ0FBQyxrQkFBa0IsQ0FVckI7Z0JBQ0EsSUFBSSxFQUFFLGFBQWEsWUFBWSxFQUFFO2dCQUNqQyxNQUFNLEVBQUUsS0FBSztnQkFDYixJQUFJLEVBQUUsSUFBK0I7YUFDdEMsQ0FBQztTQUNMLENBQUM7UUE1TkEsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUM7UUFDckIsSUFBSSxDQUFDLGFBQWEsR0FBRyxlQUFLLENBQUMsTUFBTSxDQUFDO1lBQ2hDLE9BQU8sRUFBRSx5QkFBaUI7WUFDMUIsT0FBTyxFQUFFO2dCQUNQLGFBQWEsRUFBRSxVQUFVLElBQUksQ0FBQyxNQUFNLEVBQUU7Z0JBQ3RDLGNBQWMsRUFBRSxrQkFBa0I7YUFDbkM7U0FDRixDQUFDLENBQUM7UUFFSCxJQUFJLE9BQU8sRUFBRSxlQUFlLEtBQUssSUFBSSxFQUFFLENBQUM7WUFDdEMsSUFBQSxxQkFBVSxFQUFDLElBQUksQ0FBQyxhQUFhLEVBQUU7Z0JBQzdCLE9BQU8sRUFBRSxDQUFDO2dCQUNWLDZFQUE2RTtnQkFDN0UsY0FBYyxFQUFFLHFCQUFVLENBQUMsaUNBQWlDO2dCQUM1RCxrQ0FBa0M7Z0JBQ2xDLFVBQVUsRUFBRSxxQkFBVSxDQUFDLGdCQUFnQjthQUN4QyxDQUFDLENBQUM7UUFDTCxDQUFDO0lBQ0gsQ0FBQztJQUVTLEtBQUssQ0FBQyxrQkFBa0IsQ0FBSSxPQUFnQjtRQUNwRCxNQUFNLE9BQU8sR0FBRztZQUNkLE1BQU0sRUFBRSxPQUFPLENBQUMsTUFBTTtZQUN0QixHQUFHLEVBQUUsT0FBTyxDQUFDLElBQUk7WUFDakIsTUFBTSxFQUFFLE9BQU8sQ0FBQyxLQUFLO1lBQ3JCLElBQUksRUFBRSxPQUFPLENBQUMsSUFBSTtTQUNVLENBQUM7UUFFL0IsSUFBSSxDQUFDO1lBQ0gsTUFBTSxHQUFHLEdBQUcsTUFBTSxJQUFJLENBQUMsYUFBYSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBQzlDLE9BQU8sR0FBRyxDQUFDLElBQUksQ0FBQztRQUNsQixDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLElBQUksZUFBSyxDQUFDLFlBQVksQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO2dCQUM5QixNQUFNLElBQUksS0FBSyxDQUNiLDRDQUE0QyxLQUFLLENBQUMsUUFBUSxFQUFFLE1BQU0sS0FBSyxLQUFLLENBQUMsUUFBUSxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsQ0FDdkcsQ0FBQztZQUNKLENBQUM7WUFFRCxNQUFNLEtBQUssQ0FBQztRQUNkLENBQUM7SUFDSCxDQUFDO0NBcUxGO0FBbk9ELDJCQW1PQyJ9
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const utils_1 = require("@medusajs/framework/utils");
7
+ const paystack_payment_processor_1 = __importDefault(require("../../services/paystack-payment-processor"));
8
+ exports.default = (0, utils_1.ModuleProvider)(utils_1.Modules.PAYMENT, {
9
+ services: [paystack_payment_processor_1.default],
10
+ });
11
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvcHJvdmlkZXJzL3BheXN0YWNrL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEscURBQW9FO0FBQ3BFLDJHQUFpRjtBQUVqRixrQkFBZSxJQUFBLHNCQUFjLEVBQUMsZUFBTyxDQUFDLE9BQU8sRUFBRTtJQUM3QyxRQUFRLEVBQUUsQ0FBQyxvQ0FBd0IsQ0FBQztDQUNyQyxDQUFDLENBQUMifQ==
@@ -0,0 +1,350 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const crypto_1 = __importDefault(require("crypto"));
7
+ const paystack_1 = __importDefault(require("../lib/paystack"));
8
+ const utils_1 = require("@medusajs/framework/utils");
9
+ const currencyCode_1 = require("../utils/currencyCode");
10
+ class PaystackPaymentProcessor extends utils_1.AbstractPaymentProvider {
11
+ constructor(cradle, options) {
12
+ super(cradle, options);
13
+ if (!options.secret_key) {
14
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_ARGUMENT, "The Paystack provider requires the secret_key option");
15
+ }
16
+ this.configuration = options;
17
+ this.paystack = new paystack_1.default(this.configuration.secret_key, {
18
+ disable_retries: options.disable_retries,
19
+ });
20
+ this.debug = Boolean(options.debug);
21
+ this.logger = cradle.logger;
22
+ }
23
+ async initiatePayment(initiatePaymentData) {
24
+ if (this.debug) {
25
+ this.logger.info(`PS_P_Debug: InitiatePayment ${JSON.stringify(initiatePaymentData, null, 2)}`);
26
+ }
27
+ const { data, amount, currency_code } = initiatePaymentData;
28
+ const { email, session_id, order_id, callback_url, ...customMetadata } = (data ?? {});
29
+ const validatedCurrencyCode = (0, currencyCode_1.formatCurrencyCode)(currency_code);
30
+ const SUPPORTED_CURRENCIES = ["NGN", "GHS", "ZAR", "USD", "KES", "EGP", "RWF"];
31
+ if (!SUPPORTED_CURRENCIES.includes(validatedCurrencyCode)) {
32
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, `Currency ${validatedCurrencyCode} is not supported by Paystack. Supported currencies are: ${SUPPORTED_CURRENCIES.join(", ")}`);
33
+ }
34
+ if (!email) {
35
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_ARGUMENT, "Email is required to initiate a Paystack payment. Ensure you are providing the email in the context object when calling `initiatePaymentSession` in your Medusa storefront");
36
+ }
37
+ // FIX: Multiply amount by 100 for subunits
38
+ const paystackAmount = Math.round(Number(amount) * 100);
39
+ // FIX: Generate a custom reference
40
+ const reference = customMetadata?.reference || `TX${Date.now().toString().slice(-8)}${Math.floor(100 + Math.random() * 900)}`;
41
+ try {
42
+ const { data: psData, status, message, } = await this.paystack.transaction.initialize({
43
+ amount: paystackAmount,
44
+ email,
45
+ currency: validatedCurrencyCode,
46
+ reference,
47
+ callback_url,
48
+ metadata: {
49
+ session_id,
50
+ order_id,
51
+ ...customMetadata,
52
+ },
53
+ });
54
+ if (status === false) {
55
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, "Failed to initiate Paystack payment", message);
56
+ }
57
+ return {
58
+ id: psData.reference,
59
+ status: utils_1.PaymentSessionStatus.PENDING,
60
+ data: {
61
+ paystackTxRef: psData.reference,
62
+ paystackTxAccessCode: psData.access_code,
63
+ paystackTxAuthorizationUrl: psData.authorization_url,
64
+ },
65
+ };
66
+ }
67
+ catch (error) {
68
+ if (this.debug) {
69
+ this.logger.error("PS_P_Debug: InitiatePayment: Error", error);
70
+ }
71
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, "Failed to initiate Paystack payment", error?.toString() ?? "Unknown error");
72
+ }
73
+ }
74
+ async createAccountHolder(input) {
75
+ if (this.debug) {
76
+ this.logger.info(`PS_P_Debug: createAccountHolder ${JSON.stringify(input, null, 2)}`);
77
+ }
78
+ const { customer } = input.context || {};
79
+ if (!customer?.email) {
80
+ return { id: `ps_mock_${Date.now()}` };
81
+ }
82
+ try {
83
+ const { data, status, message } = await this.paystack.customer.create({
84
+ email: customer.email,
85
+ first_name: customer.first_name ?? undefined,
86
+ last_name: customer.last_name ?? undefined,
87
+ phone: customer.phone ?? undefined,
88
+ });
89
+ if (status === false) {
90
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, message || "Paystack API Error");
91
+ }
92
+ return { id: data.customer_code };
93
+ }
94
+ catch (error) {
95
+ if (this.debug) {
96
+ this.logger.error("PS_P_Debug: createAccountHolder: Error", error);
97
+ }
98
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, "Failed to create Paystack customer", error?.toString() ?? "Unknown error");
99
+ }
100
+ }
101
+ async updateAccountHolder(input) {
102
+ if (this.debug) {
103
+ this.logger.info(`PS_P_Debug: updateAccountHolder ${JSON.stringify(input, null, 2)}`);
104
+ }
105
+ const { account_holder, customer } = input.context || {};
106
+ const customerCode = account_holder?.data?.id;
107
+ if (!customerCode || !customerCode.startsWith("CUS_") || !customer) {
108
+ return { id: customerCode || `ps_mock_${Date.now()}` };
109
+ }
110
+ try {
111
+ const { status, message } = await this.paystack.customer.update(customerCode, {
112
+ first_name: customer.first_name ?? undefined,
113
+ last_name: customer.last_name ?? undefined,
114
+ phone: customer.phone ?? undefined,
115
+ });
116
+ if (status === false) {
117
+ if (this.debug) {
118
+ this.logger.error(`PS_P_Debug: updateAccountHolder API Error: ${message}`);
119
+ }
120
+ }
121
+ return { id: customerCode };
122
+ }
123
+ catch (error) {
124
+ if (this.debug) {
125
+ this.logger.error("PS_P_Debug: updateAccountHolder: Error", error);
126
+ }
127
+ return { id: customerCode };
128
+ }
129
+ }
130
+ async deleteAccountHolder(input) {
131
+ if (this.debug) {
132
+ this.logger.info(`PS_P_Debug: deleteAccountHolder ${JSON.stringify(input, null, 2)}`);
133
+ }
134
+ return;
135
+ }
136
+ async updatePayment(input) {
137
+ if (this.debug) {
138
+ this.logger.info(`PS_P_Debug: UpdatePayment ${JSON.stringify(input, null, 2)}`);
139
+ }
140
+ const session = await this.initiatePayment(input);
141
+ return {
142
+ data: session.data,
143
+ status: session.status,
144
+ };
145
+ }
146
+ async authorizePayment(input) {
147
+ if (this.debug) {
148
+ this.logger.info(`PS_P_Debug: AuthorizePayment ${JSON.stringify(input, null, 2)}`);
149
+ }
150
+ try {
151
+ const { paystackTxRef } = input.data;
152
+ if (!paystackTxRef) {
153
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Missing paystackTxRef in payment data.");
154
+ }
155
+ const { status: psStatus, data } = await this.paystack.transaction.verify(paystackTxRef);
156
+ if (this.debug) {
157
+ this.logger.info(`PS_P_Debug: AuthorizePayment: Verification ${JSON.stringify({ psStatus, data }, null, 2)}`);
158
+ }
159
+ if (psStatus === false) {
160
+ return {
161
+ status: utils_1.PaymentSessionStatus.ERROR,
162
+ data: {
163
+ ...input.data,
164
+ paystackTxId: data.id,
165
+ paystackTxData: data,
166
+ },
167
+ };
168
+ }
169
+ switch (data.status) {
170
+ case "success":
171
+ return {
172
+ status: utils_1.PaymentSessionStatus.AUTHORIZED,
173
+ data: {
174
+ ...input.data,
175
+ paystackTxId: data.id,
176
+ paystackTxData: data,
177
+ },
178
+ };
179
+ case "failed":
180
+ return {
181
+ status: utils_1.PaymentSessionStatus.ERROR,
182
+ data: {
183
+ ...input.data,
184
+ paystackTxId: data.id,
185
+ paystackTxData: data,
186
+ },
187
+ };
188
+ default:
189
+ return {
190
+ status: utils_1.PaymentSessionStatus.PENDING,
191
+ data: {
192
+ ...input.data,
193
+ paystackTxId: data.id,
194
+ paystackTxData: data,
195
+ },
196
+ };
197
+ }
198
+ }
199
+ catch (error) {
200
+ if (this.debug) {
201
+ this.logger.error("PS_P_Debug: AuthorizePayment: Error", error);
202
+ }
203
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, "Failed to authorize payment", error?.toString() ?? "Unknown error");
204
+ }
205
+ }
206
+ async retrievePayment(input) {
207
+ if (this.debug) {
208
+ this.logger.info(`PS_P_Debug: RetrievePayment ${JSON.stringify(input, null, 2)}`);
209
+ }
210
+ try {
211
+ const { paystackTxId } = input.data;
212
+ if (!paystackTxId) {
213
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Missing paystackTxId in payment data. This payment has not been authorized.");
214
+ }
215
+ const { data, status, message } = await this.paystack.transaction.get({
216
+ id: paystackTxId,
217
+ });
218
+ if (status === false) {
219
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, "Failed to retrieve payment", message);
220
+ }
221
+ return {
222
+ data: {
223
+ ...input.data,
224
+ paystackTxData: data,
225
+ },
226
+ };
227
+ }
228
+ catch (error) {
229
+ if (this.debug) {
230
+ this.logger.error("PS_P_Debug: RetrievePayment: Error", error);
231
+ }
232
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, "Failed to retrieve payment", error?.toString() ?? "Unknown error");
233
+ }
234
+ }
235
+ async refundPayment(input) {
236
+ if (this.debug) {
237
+ this.logger.info(`PS_P_Debug: RefundPayment ${JSON.stringify(input, null, 2)}`);
238
+ }
239
+ try {
240
+ const { paystackTxId } = input.data;
241
+ if (!paystackTxId) {
242
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Missing paystackTxId in payment data.");
243
+ }
244
+ const { data, status, message } = await this.paystack.refund.create({
245
+ transaction: paystackTxId,
246
+ amount: Math.round(Number(input.amount) * 100), // FIX: Subunit conversion
247
+ });
248
+ if (status === false) {
249
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, "Failed to refund payment", message);
250
+ }
251
+ return {
252
+ data: {
253
+ ...input.data,
254
+ paystackTxData: data,
255
+ },
256
+ };
257
+ }
258
+ catch (error) {
259
+ if (this.debug) {
260
+ this.logger.error("PS_P_Debug: RefundPayment: Error", error);
261
+ }
262
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, "Failed to refund payment", error?.toString() ?? "Unknown error");
263
+ }
264
+ }
265
+ async getPaymentStatus(input) {
266
+ if (this.debug) {
267
+ this.logger.info(`PS_P_Debug: GetPaymentStatus ${JSON.stringify(input, null, 2)}`);
268
+ }
269
+ const { paystackTxId } = input.data;
270
+ if (!paystackTxId) {
271
+ return { status: utils_1.PaymentSessionStatus.PENDING };
272
+ }
273
+ try {
274
+ const { data, status } = await this.paystack.transaction.get({
275
+ id: paystackTxId,
276
+ });
277
+ if (this.debug) {
278
+ this.logger.info(`PS_P_Debug: GetPaymentStatus: Verification ${JSON.stringify({ status, data }, null, 2)}`);
279
+ }
280
+ if (status === false) {
281
+ return { status: utils_1.PaymentSessionStatus.ERROR };
282
+ }
283
+ switch (data?.status) {
284
+ case "success":
285
+ return { status: utils_1.PaymentSessionStatus.AUTHORIZED };
286
+ case "failed":
287
+ return { status: utils_1.PaymentSessionStatus.ERROR };
288
+ default:
289
+ return { status: utils_1.PaymentSessionStatus.PENDING };
290
+ }
291
+ }
292
+ catch (error) {
293
+ if (this.debug) {
294
+ this.logger.error("PS_P_Debug: GetPaymentStatus: Error", error);
295
+ }
296
+ return { status: utils_1.PaymentSessionStatus.ERROR };
297
+ }
298
+ }
299
+ async getWebhookActionAndData({ data: { event, data }, rawData, headers, }) {
300
+ if (this.debug) {
301
+ this.logger.info(`PS_P_Debug: Handling webhook event ${JSON.stringify({ data, headers }, null, 2)}`);
302
+ }
303
+ const webhookSecretKey = this.configuration.secret_key;
304
+ const hash = crypto_1.default
305
+ .createHmac("sha512", webhookSecretKey)
306
+ .update(rawData)
307
+ .digest("hex");
308
+ if (hash !== headers["x-paystack-signature"]) {
309
+ return {
310
+ action: utils_1.PaymentActions.NOT_SUPPORTED,
311
+ };
312
+ }
313
+ if (event !== "charge.success") {
314
+ return {
315
+ action: utils_1.PaymentActions.NOT_SUPPORTED,
316
+ };
317
+ }
318
+ const sessionId = data.metadata?.session_id;
319
+ if (!sessionId) {
320
+ if (this.debug) {
321
+ this.logger.error("PS_P_Debug: No sessionId found in webhook transaction metadata");
322
+ }
323
+ return {
324
+ action: utils_1.PaymentActions.NOT_SUPPORTED,
325
+ };
326
+ }
327
+ if (this.debug) {
328
+ this.logger.info(`PS_P_Debug: Webhook event is valid ${JSON.stringify({ sessionId, amount: data.amount }, null, 2)}`);
329
+ }
330
+ return {
331
+ action: utils_1.PaymentActions.SUCCESSFUL, // FIX: Tell Medusa to capture automatically
332
+ data: {
333
+ session_id: sessionId,
334
+ amount: Number(data.amount) / 100, // FIX: Convert from subunit back to main unit
335
+ },
336
+ };
337
+ }
338
+ async capturePayment(input) {
339
+ return { data: input.data };
340
+ }
341
+ async cancelPayment(input) {
342
+ return { data: input.data };
343
+ }
344
+ async deletePayment(input) {
345
+ return { data: input.data };
346
+ }
347
+ }
348
+ PaystackPaymentProcessor.identifier = "paystack";
349
+ exports.default = PaystackPaymentProcessor;
350
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGF5c3RhY2stcGF5bWVudC1wcm9jZXNzb3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvc2VydmljZXMvcGF5c3RhY2stcGF5bWVudC1wcm9jZXNzb3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSxvREFBNEI7QUFDNUIsK0RBQXVDO0FBMEJ2QyxxREFLbUM7QUFDbkMsd0RBQTJEO0FBcUIzRCxNQUFNLHdCQUF5QixTQUFRLCtCQUF1RDtJQU81RixZQUNFLE1BQW9ELEVBQ3BELE9BQXVDO1FBRXZDLEtBQUssQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDdkIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxVQUFVLEVBQUUsQ0FBQztZQUN4QixNQUFNLElBQUksbUJBQVcsQ0FDbkIsbUJBQVcsQ0FBQyxLQUFLLENBQUMsZ0JBQWdCLEVBQ2xDLHNEQUFzRCxDQUN2RCxDQUFDO1FBQ0osQ0FBQztRQUNELElBQUksQ0FBQyxhQUFhLEdBQUcsT0FBTyxDQUFDO1FBQzdCLElBQUksQ0FBQyxRQUFRLEdBQUcsSUFBSSxrQkFBUSxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsVUFBVSxFQUFFO1lBQzFELGVBQWUsRUFBRSxPQUFPLENBQUMsZUFBZTtTQUN6QyxDQUFDLENBQUM7UUFDSCxJQUFJLENBQUMsS0FBSyxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDcEMsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDO0lBQzlCLENBQUM7SUFFRCxLQUFLLENBQUMsZUFBZSxDQUNuQixtQkFBeUM7UUFFekMsSUFBSSxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDZixJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FDZCwrQkFBK0IsSUFBSSxDQUFDLFNBQVMsQ0FBQyxtQkFBbUIsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FDOUUsQ0FBQztR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