medusa-payu-payment-plugin 1.1.0

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,22 @@
1
+ "use strict";
2
+ const widgetModule = { widgets: [] };
3
+ const routeModule = {
4
+ routes: []
5
+ };
6
+ const menuItemModule = {
7
+ menuItems: []
8
+ };
9
+ const formModule = { customFields: {} };
10
+ const displayModule = {
11
+ displays: {}
12
+ };
13
+ const i18nModule = { resources: {} };
14
+ const plugin = {
15
+ widgetModule,
16
+ routeModule,
17
+ menuItemModule,
18
+ formModule,
19
+ displayModule,
20
+ i18nModule
21
+ };
22
+ module.exports = plugin;
@@ -0,0 +1,23 @@
1
+ const widgetModule = { widgets: [] };
2
+ const routeModule = {
3
+ routes: []
4
+ };
5
+ const menuItemModule = {
6
+ menuItems: []
7
+ };
8
+ const formModule = { customFields: {} };
9
+ const displayModule = {
10
+ displays: {}
11
+ };
12
+ const i18nModule = { resources: {} };
13
+ const plugin = {
14
+ widgetModule,
15
+ routeModule,
16
+ menuItemModule,
17
+ formModule,
18
+ displayModule,
19
+ i18nModule
20
+ };
21
+ export {
22
+ plugin as default
23
+ };
@@ -0,0 +1,134 @@
1
+ "use strict";
2
+ /**
3
+ * PayU SDK Client
4
+ * Manual hash implementation based on PayU documentation
5
+ * https://docs.payu.in/docs/generate-hash-merchant-hosted
6
+ */
7
+ var __importDefault = (this && this.__importDefault) || function (mod) {
8
+ return (mod && mod.__esModule) ? mod : { "default": mod };
9
+ };
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.PayuClient = void 0;
12
+ exports.generateTxnId = generateTxnId;
13
+ const crypto_1 = __importDefault(require("crypto"));
14
+ /**
15
+ * PayU Client for payment operations
16
+ */
17
+ class PayuClient {
18
+ constructor(config, logger) {
19
+ this.config = config;
20
+ this.logger = logger;
21
+ }
22
+ /**
23
+ * Get PayU payment URL
24
+ */
25
+ getPaymentUrl() {
26
+ return this.config.environment === "production"
27
+ ? "https://secure.payu.in/_payment"
28
+ : "https://test.payu.in/_payment";
29
+ }
30
+ /**
31
+ * Generate payment hash
32
+ *
33
+ * Formula from PayU docs:
34
+ * sha512(key|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5||||||salt)
35
+ *
36
+ * Note: "||||||" is a literal string (6 pipes) appended after udf5
37
+ */
38
+ generatePaymentHash(params) {
39
+ const key = this.config.merchantKey;
40
+ const salt = this.config.merchantSalt;
41
+ const udf1 = params.udf1 || "";
42
+ const udf2 = params.udf2 || "";
43
+ const udf3 = params.udf3 || "";
44
+ const udf4 = params.udf4 || "";
45
+ const udf5 = params.udf5 || "";
46
+ // Exact formula from PayU docs:
47
+ // sha512(key|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5||||||SALT)
48
+ // The ||||||SALT means 5 empty reserved fields between udf5 and SALT (creating 6 pipes)
49
+ const hashString = `${key}|${params.txnid}|${params.amount}|${params.productinfo}|${params.firstname}|${params.email}|${udf1}|${udf2}|${udf3}|${udf4}|${udf5}||||||${salt}`;
50
+ const generatedHash = crypto_1.default.createHash("sha512").update(hashString).digest("hex").toLowerCase();
51
+ this.logger?.debug?.(`PayU hash generated for txnid: ${params.txnid}`);
52
+ return generatedHash;
53
+ }
54
+ /**
55
+ * Verify response hash from PayU callback/webhook
56
+ *
57
+ * Reverse hash formula:
58
+ * sha512(salt|status||||||udf5|udf4|udf3|udf2|udf1|email|firstname|productinfo|amount|txnid|key)
59
+ */
60
+ verifyResponseHash(params) {
61
+ const salt = this.config.merchantSalt;
62
+ const key = this.config.merchantKey;
63
+ const udf1 = params.udf1 || "";
64
+ const udf2 = params.udf2 || "";
65
+ const udf3 = params.udf3 || "";
66
+ const udf4 = params.udf4 || "";
67
+ const udf5 = params.udf5 || "";
68
+ let hashString;
69
+ if (params.additionalCharges) {
70
+ hashString = `${params.additionalCharges}|${salt}|${params.status}||||||${udf5}|${udf4}|${udf3}|${udf2}|${udf1}|${params.email}|${params.firstname}|${params.productinfo}|${params.amount}|${params.txnid}|${key}`;
71
+ }
72
+ else {
73
+ hashString = `${salt}|${params.status}||||||${udf5}|${udf4}|${udf3}|${udf2}|${udf1}|${params.email}|${params.firstname}|${params.productinfo}|${params.amount}|${params.txnid}|${key}`;
74
+ }
75
+ const calculatedHash = crypto_1.default.createHash("sha512").update(hashString).digest("hex").toLowerCase();
76
+ return calculatedHash === params.hash.toLowerCase();
77
+ }
78
+ /**
79
+ * Verify payment status with PayU API
80
+ */
81
+ async verifyPayment(txnid) {
82
+ const command = "verify_payment";
83
+ const hashString = `${this.config.merchantKey}|${command}|${txnid}|${this.config.merchantSalt}`;
84
+ const hash = crypto_1.default.createHash("sha512").update(hashString).digest("hex");
85
+ const apiUrl = this.config.environment === "production"
86
+ ? "https://info.payu.in/merchant/postservice.php?form=2"
87
+ : "https://test.payu.in/merchant/postservice.php?form=2";
88
+ const response = await fetch(apiUrl, {
89
+ method: "POST",
90
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
91
+ body: new URLSearchParams({
92
+ key: this.config.merchantKey,
93
+ command: command,
94
+ var1: txnid,
95
+ hash: hash,
96
+ }),
97
+ });
98
+ return response.json();
99
+ }
100
+ /**
101
+ * Initiate refund
102
+ */
103
+ async refund(mihpayid, tokenId, amount) {
104
+ const command = "cancel_refund_transaction";
105
+ const hashString = `${this.config.merchantKey}|${command}|${mihpayid}|${this.config.merchantSalt}`;
106
+ const hash = crypto_1.default.createHash("sha512").update(hashString).digest("hex");
107
+ const apiUrl = this.config.environment === "production"
108
+ ? "https://info.payu.in/merchant/postservice.php?form=2"
109
+ : "https://test.payu.in/merchant/postservice.php?form=2";
110
+ const response = await fetch(apiUrl, {
111
+ method: "POST",
112
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
113
+ body: new URLSearchParams({
114
+ key: this.config.merchantKey,
115
+ command: command,
116
+ var1: mihpayid,
117
+ var2: tokenId,
118
+ var3: amount,
119
+ hash: hash,
120
+ }),
121
+ });
122
+ return response.json();
123
+ }
124
+ }
125
+ exports.PayuClient = PayuClient;
126
+ /**
127
+ * Generate unique transaction ID
128
+ */
129
+ function generateTxnId() {
130
+ const timestamp = Date.now();
131
+ const random = crypto_1.default.randomBytes(4).toString("hex");
132
+ return `TXN_${timestamp}_${random}`;
133
+ }
134
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL3Byb3ZpZGVycy9wYXl1L2NsaWVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7R0FJRzs7Ozs7O0FBeUtILHNDQUlDO0FBM0tELG9EQUEyQjtBQUkzQjs7R0FFRztBQUNILE1BQWEsVUFBVTtJQUluQixZQUFZLE1BQTBCLEVBQUUsTUFBZTtRQUNuRCxJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQTtRQUNwQixJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQTtJQUN4QixDQUFDO0lBRUQ7O09BRUc7SUFDSCxhQUFhO1FBQ1QsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLFdBQVcsS0FBSyxZQUFZO1lBQzNDLENBQUMsQ0FBQyxpQ0FBaUM7WUFDbkMsQ0FBQyxDQUFDLCtCQUErQixDQUFBO0lBQ3pDLENBQUM7SUFFRDs7Ozs7OztPQU9HO0lBQ0gsbUJBQW1CLENBQUMsTUFXbkI7UUFDRyxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLFdBQVcsQ0FBQTtRQUNuQyxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLFlBQVksQ0FBQTtRQUNyQyxNQUFNLElBQUksR0FBRyxNQUFNLENBQUMsSUFBSSxJQUFJLEVBQUUsQ0FBQTtRQUM5QixNQUFNLElBQUksR0FBRyxNQUFNLENBQUMsSUFBSSxJQUFJLEVBQUUsQ0FBQTtRQUM5QixNQUFNLElBQUksR0FBRyxNQUFNLENBQUMsSUFBSSxJQUFJLEVBQUUsQ0FBQTtRQUM5QixNQUFNLElBQUksR0FBRyxNQUFNLENBQUMsSUFBSSxJQUFJLEVBQUUsQ0FBQTtRQUM5QixNQUFNLElBQUksR0FBRyxNQUFNLENBQUMsSUFBSSxJQUFJLEVBQUUsQ0FBQTtRQUU5QixnQ0FBZ0M7UUFDaEMsMEZBQTBGO1FBQzFGLHdGQUF3RjtRQUN4RixNQUFNLFVBQVUsR0FBRyxHQUFHLEdB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
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ /**
3
+ * PayU Payment Provider Module
4
+ */
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
18
+ }) : function(o, v) {
19
+ o["default"] = v;
20
+ });
21
+ var __importStar = (this && this.__importStar) || (function () {
22
+ var ownKeys = function(o) {
23
+ ownKeys = Object.getOwnPropertyNames || function (o) {
24
+ var ar = [];
25
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
+ return ar;
27
+ };
28
+ return ownKeys(o);
29
+ };
30
+ return function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ })();
38
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
39
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
40
+ };
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.PAYU_PROVIDER_ID = exports.PayuPaymentProviderService = void 0;
43
+ const service_1 = __importStar(require("./service"));
44
+ exports.PayuPaymentProviderService = service_1.default;
45
+ Object.defineProperty(exports, "PAYU_PROVIDER_ID", { enumerable: true, get: function () { return service_1.PAYU_PROVIDER_ID; } });
46
+ const utils_1 = require("@medusajs/framework/utils");
47
+ exports.default = (0, utils_1.ModuleProvider)(utils_1.Modules.PAYMENT, {
48
+ services: [service_1.default],
49
+ });
50
+ __exportStar(require("./types"), exports);
51
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvcHJvdmlkZXJzL3BheXUvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOztHQUVHOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFFSCxxREFBd0U7QUFPL0QscUNBUEYsaUJBQTBCLENBT0U7QUFBRSxpR0FQQSwwQkFBZ0IsT0FPQTtBQU5yRCxxREFBbUU7QUFFbkUsa0JBQWUsSUFBQSxzQkFBYyxFQUFDLGVBQU8sQ0FBQyxPQUFPLEVBQUU7SUFDM0MsUUFBUSxFQUFFLENBQUMsaUJBQTBCLENBQUM7Q0FDekMsQ0FBQyxDQUFBO0FBR0YsMENBQXVCIn0=
@@ -0,0 +1,323 @@
1
+ "use strict";
2
+ /**
3
+ * PayU Payment Provider Service
4
+ * MedusaJS 2 Payment Provider for PayU India
5
+ *
6
+ * Implements redirect-based payment flow using official payu-websdk
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.PAYU_PROVIDER_ID = void 0;
10
+ const utils_1 = require("@medusajs/framework/utils");
11
+ const client_1 = require("./client");
12
+ exports.PAYU_PROVIDER_ID = "payu";
13
+ /**
14
+ * PayU Payment Provider Service
15
+ *
16
+ * Flow:
17
+ * 1. initiatePayment - Returns session data with payment URL and form data
18
+ * 2. Frontend redirects customer to PayU checkout
19
+ * 3. Customer completes payment on PayU
20
+ * 4. PayU redirects back and sends webhook
21
+ * 5. authorizePayment - Verifies and marks payment as authorized
22
+ */
23
+ class PayuPaymentProviderService extends utils_1.AbstractPaymentProvider {
24
+ constructor(container, config) {
25
+ super(container, config);
26
+ if (!config.merchantKey || !config.merchantSalt) {
27
+ throw new Error("PayU: merchantKey and merchantSalt are required. " +
28
+ "Set PAYU_MERCHANT_KEY and PAYU_MERCHANT_SALT environment variables.");
29
+ }
30
+ this.config_ = {
31
+ merchantKey: config.merchantKey,
32
+ merchantSalt: config.merchantSalt,
33
+ environment: config.environment || "test",
34
+ autoCapture: config.autoCapture ?? true,
35
+ };
36
+ this.logger_ = container.logger;
37
+ this.client_ = new client_1.PayuClient(this.config_, this.logger_);
38
+ this.logger_?.info?.(`PayU initialized in ${this.config_.environment} mode`);
39
+ }
40
+ /**
41
+ * Format amount to string with 2 decimals (PayU requirement)
42
+ */
43
+ formatAmount(amount) {
44
+ const num = typeof amount === "string" ? parseFloat(amount) : Number(amount);
45
+ return num.toFixed(2);
46
+ }
47
+ /**
48
+ * Initiate payment session
49
+ */
50
+ async initiatePayment(input) {
51
+ const { amount, context } = input;
52
+ try {
53
+ const txnid = (0, client_1.generateTxnId)();
54
+ const formattedAmount = this.formatAmount(amount);
55
+ const customer = context?.customer;
56
+ const email = customer?.email || "customer@example.com";
57
+ const firstname = customer?.first_name || "Customer";
58
+ const phone = customer?.phone || "";
59
+ const productinfo = input.data?.productinfo || "Order Payment";
60
+ const storefrontUrl = process.env.STOREFRONT_URL || "http://localhost:8000";
61
+ const countryCode = input.data?.country_code || "in";
62
+ const surl = `${storefrontUrl}/${countryCode}/order/confirmed`;
63
+ const furl = `${storefrontUrl}/${countryCode}/checkout?payment_status=failed`;
64
+ // Generate hash using SDK
65
+ const hash = this.client_.generatePaymentHash({
66
+ txnid,
67
+ amount: formattedAmount,
68
+ productinfo,
69
+ firstname,
70
+ email,
71
+ });
72
+ const sessionData = {
73
+ txnid,
74
+ amount: formattedAmount,
75
+ productinfo,
76
+ firstname,
77
+ email,
78
+ phone,
79
+ hash,
80
+ paymentUrl: this.client_.getPaymentUrl(),
81
+ status: "pending",
82
+ countryCode,
83
+ };
84
+ this.logger_?.debug?.(`PayU payment initiated: ${txnid}`);
85
+ return {
86
+ id: txnid,
87
+ data: {
88
+ ...sessionData,
89
+ form_data: {
90
+ key: this.config_.merchantKey,
91
+ txnid,
92
+ amount: formattedAmount,
93
+ productinfo,
94
+ firstname,
95
+ email,
96
+ phone,
97
+ surl,
98
+ furl,
99
+ hash,
100
+ service_provider: "payu_paisa",
101
+ },
102
+ },
103
+ };
104
+ }
105
+ catch (error) {
106
+ this.logger_?.error?.(`PayU initiatePayment error: ${error}`);
107
+ throw error;
108
+ }
109
+ }
110
+ /**
111
+ * Authorize payment after PayU callback
112
+ */
113
+ async authorizePayment(input) {
114
+ try {
115
+ const sessionData = input.data;
116
+ if (sessionData.status === "authorized" || sessionData.status === "captured") {
117
+ return {
118
+ status: utils_1.PaymentSessionStatus.AUTHORIZED,
119
+ data: input.data,
120
+ };
121
+ }
122
+ const response = await this.client_.verifyPayment(sessionData.txnid);
123
+ if (response.status === 1) {
124
+ const txn = response.transaction_details[sessionData.txnid];
125
+ if (txn?.status === "success") {
126
+ this.logger_?.info?.(`PayU authorized: ${sessionData.txnid}`);
127
+ return {
128
+ status: utils_1.PaymentSessionStatus.AUTHORIZED,
129
+ data: {
130
+ ...sessionData,
131
+ status: "authorized",
132
+ payuTransactionId: txn.mihpayid,
133
+ payuResponse: txn,
134
+ },
135
+ };
136
+ }
137
+ }
138
+ return {
139
+ status: utils_1.PaymentSessionStatus.ERROR,
140
+ data: { ...sessionData, status: "failed" },
141
+ };
142
+ }
143
+ catch (error) {
144
+ this.logger_?.error?.(`PayU authorizePayment error: ${error}`);
145
+ throw error;
146
+ }
147
+ }
148
+ /**
149
+ * Capture payment (PayU auto-captures)
150
+ */
151
+ async capturePayment(input) {
152
+ const sessionData = input.data;
153
+ return {
154
+ data: { ...sessionData, status: "captured" },
155
+ };
156
+ }
157
+ /**
158
+ * Refund payment
159
+ */
160
+ async refundPayment(input) {
161
+ try {
162
+ const sessionData = input.data;
163
+ if (!sessionData.payuTransactionId) {
164
+ throw new Error("No PayU transaction ID found");
165
+ }
166
+ const tokenId = `REF_${sessionData.payuTransactionId}_${Date.now()}`;
167
+ const refundAmount = this.formatAmount(input.amount);
168
+ const response = await this.client_.refund(sessionData.payuTransactionId, tokenId, refundAmount);
169
+ if (response.status === 1) {
170
+ this.logger_?.info?.(`PayU refund successful: ${sessionData.txnid}`);
171
+ return {
172
+ data: {
173
+ ...sessionData,
174
+ status: "refunded",
175
+ refund: { tokenId, amount: refundAmount, response },
176
+ },
177
+ };
178
+ }
179
+ throw new Error(`Refund failed: ${response.msg}`);
180
+ }
181
+ catch (error) {
182
+ this.logger_?.error?.(`PayU refundPayment error: ${error}`);
183
+ throw error;
184
+ }
185
+ }
186
+ /**
187
+ * Cancel payment
188
+ */
189
+ async cancelPayment(input) {
190
+ const sessionData = input.data;
191
+ return {
192
+ data: { ...sessionData, status: "cancelled" },
193
+ };
194
+ }
195
+ /**
196
+ * Delete payment session
197
+ */
198
+ async deletePayment(input) {
199
+ return { data: input.data };
200
+ }
201
+ /**
202
+ * Get payment status
203
+ */
204
+ async getPaymentStatus(input) {
205
+ const sessionData = input.data;
206
+ const statusMap = {
207
+ pending: utils_1.PaymentSessionStatus.PENDING,
208
+ authorized: utils_1.PaymentSessionStatus.AUTHORIZED,
209
+ captured: utils_1.PaymentSessionStatus.AUTHORIZED,
210
+ failed: utils_1.PaymentSessionStatus.ERROR,
211
+ refunded: utils_1.PaymentSessionStatus.AUTHORIZED,
212
+ cancelled: utils_1.PaymentSessionStatus.CANCELED,
213
+ };
214
+ return { status: statusMap[sessionData.status] || utils_1.PaymentSessionStatus.PENDING };
215
+ }
216
+ /**
217
+ * Retrieve payment details
218
+ */
219
+ async retrievePayment(input) {
220
+ return { data: input.data };
221
+ }
222
+ /**
223
+ * Update payment session
224
+ */
225
+ async updatePayment(input) {
226
+ try {
227
+ const { data, amount } = input;
228
+ const sessionData = data;
229
+ if (amount) {
230
+ const formattedAmount = this.formatAmount(amount);
231
+ const storefrontUrl = process.env.STOREFRONT_URL || "http://localhost:8000";
232
+ const hash = this.client_.generatePaymentHash({
233
+ txnid: sessionData.txnid,
234
+ amount: formattedAmount,
235
+ productinfo: sessionData.productinfo,
236
+ firstname: sessionData.firstname,
237
+ email: sessionData.email,
238
+ });
239
+ return {
240
+ data: {
241
+ ...sessionData,
242
+ amount: formattedAmount,
243
+ hash,
244
+ form_data: {
245
+ key: this.config_.merchantKey,
246
+ txnid: sessionData.txnid,
247
+ amount: formattedAmount,
248
+ productinfo: sessionData.productinfo,
249
+ firstname: sessionData.firstname,
250
+ email: sessionData.email,
251
+ phone: sessionData.phone,
252
+ surl: `${storefrontUrl}/${sessionData.countryCode || 'in'}/order/confirmed`,
253
+ furl: `${storefrontUrl}/${sessionData.countryCode || 'in'}/checkout?payment_status=failed`,
254
+ hash,
255
+ service_provider: "payu_paisa",
256
+ },
257
+ },
258
+ };
259
+ }
260
+ return { data: data };
261
+ }
262
+ catch (error) {
263
+ this.logger_?.error?.(`PayU updatePayment error: ${error}`);
264
+ throw error;
265
+ }
266
+ }
267
+ /**
268
+ * Handle webhook from PayU
269
+ */
270
+ async getWebhookActionAndData(data) {
271
+ try {
272
+ const webhook = data.data;
273
+ this.logger_?.info?.(`PayU webhook: txnid=${webhook.txnid}, status=${webhook.status}`);
274
+ // Verify hash
275
+ const isValid = this.client_.verifyResponseHash({
276
+ status: webhook.status,
277
+ email: webhook.email,
278
+ firstname: webhook.firstname,
279
+ productinfo: webhook.productinfo,
280
+ amount: webhook.amount,
281
+ txnid: webhook.txnid,
282
+ hash: webhook.hash,
283
+ udf1: webhook.udf1,
284
+ udf2: webhook.udf2,
285
+ udf3: webhook.udf3,
286
+ udf4: webhook.udf4,
287
+ udf5: webhook.udf5,
288
+ });
289
+ if (!isValid) {
290
+ this.logger_?.warn?.(`PayU webhook: Invalid hash for ${webhook.txnid}`);
291
+ return { action: "not_supported" };
292
+ }
293
+ const sessionId = webhook.udf1 || webhook.txnid;
294
+ const status = webhook.status.toLowerCase();
295
+ if (status === "success") {
296
+ return {
297
+ action: "authorized",
298
+ data: {
299
+ session_id: sessionId,
300
+ amount: new utils_1.BigNumber(parseFloat(webhook.amount)),
301
+ },
302
+ };
303
+ }
304
+ if (status === "failure" || status === "failed") {
305
+ return {
306
+ action: "failed",
307
+ data: {
308
+ session_id: sessionId,
309
+ amount: new utils_1.BigNumber(parseFloat(webhook.amount)),
310
+ },
311
+ };
312
+ }
313
+ return { action: "not_supported" };
314
+ }
315
+ catch (error) {
316
+ this.logger_?.error?.(`PayU webhook error: ${error}`);
317
+ return { action: "not_supported" };
318
+ }
319
+ }
320
+ }
321
+ PayuPaymentProviderService.identifier = exports.PAYU_PROVIDER_ID;
322
+ exports.default = PayuPaymentProviderService;
323
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9wcm92aWRlcnMvcGF5dS9zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7Ozs7R0FLRzs7O0FBRUgscURBSWtDO0FBMEJsQyxxQ0FBb0Q7QUFFdkMsUUFBQSxnQkFBZ0IsR0FBRyxNQUFNLENBQUE7QUFFdEM7Ozs7Ozs7OztHQVNHO0FBQ0gsTUFBTSwwQkFBMkIsU0FBUSwrQkFBMkM7SUFPaEYsWUFBWSxTQUFrQyxFQUFFLE1BQTBCO1FBQ3RFLEtBQUssQ0FBQyxTQUFTLEVBQUUsTUFBTSxDQUFDLENBQUE7UUFFeEIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxXQUFXLElBQUksQ0FBQyxNQUFNLENBQUMsWUFBWSxFQUFFLENBQUM7WUFDOUMsTUFBTSxJQUFJLEtBQUssQ0FDWCxtREFBbUQ7Z0JBQ25ELHFFQUFxRSxDQUN4RSxDQUFBO1FBQ0wsQ0FBQztRQUVELElBQUksQ0FBQyxPQUFPLEdBQUc7WUFDWCxXQUFXLEVBQUUsTUFBTSxDQUFDLFdBQVc7WUFDL0IsWUFBWSxFQUFFLE1BQU0sQ0FBQyxZQUFZO1lBQ2pDLFdBQVcsRUFBRSxNQUFNLENBQUMsV0FBVyxJQUFJLE1BQU07WUFDekMsV0FBVyxFQUFFLE1BQU0sQ0FBQyxXQUFXLElBQUksSUFBSTtTQUMxQyxDQUFBO1FBRUQsSUFBSSxDQUFDLE9BQU8sR0FBRyxTQUFTLENBQUMsTUFBZ0IsQ0FBQTtRQUN6QyxJQUFJLENBQUMsT0FBTyxHQUFHLElBQUksbUJBQVUsQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQTtRQUV6RCxJQUFJLENBQUMsT0FBTyxFQUFFLElBQUksRUFBRSxDQUFDLHVCQUF1QixJQUFJLENBQUMsT0FBTyxDQUFDLFdBQVcsT0FBTyxDQUFDLENBQUE7SUFDaEYsQ0FBQztJQUVEOztPQUVHO0lBQ0ssWUFBWSxDQUFDLE1BQWU7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
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ /**
3
+ * PayU Payment Provider Types
4
+ * Type definitions for PayU India payment gateway integration
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvcHJvdmlkZXJzL3BheXUvdHlwZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7R0FHRyJ9
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ /**
3
+ * PayU Payment Plugin Workflows
4
+ *
5
+ * Export all workflows from this file for plugin consumers
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.verifyPayuPaymentWorkflow = void 0;
9
+ var verify_payu_payment_1 = require("./verify-payu-payment");
10
+ Object.defineProperty(exports, "verifyPayuPaymentWorkflow", { enumerable: true, get: function () { return verify_payu_payment_1.verifyPayuPaymentWorkflow; } });
11
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvd29ya2Zsb3dzL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7OztHQUlHOzs7QUFFSCw2REFJOEI7QUFIMUIsZ0lBQUEseUJBQXlCLE9BQUEifQ==
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ /**
3
+ * Verify PayU Payment Workflow
4
+ *
5
+ * Workflow to verify payment status with PayU API
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.verifyPayuPaymentWorkflow = void 0;
9
+ const workflows_sdk_1 = require("@medusajs/framework/workflows-sdk");
10
+ const client_1 = require("../providers/payu/client");
11
+ /**
12
+ * Step: Verify payment with PayU API
13
+ */
14
+ const verifyPaymentStep = (0, workflows_sdk_1.createStep)("verify-payu-payment-step", async (input) => {
15
+ const { txnid, merchantKey = process.env.PAYU_MERCHANT_KEY || "", merchantSalt = process.env.PAYU_MERCHANT_SALT || "", environment = process.env.PAYU_ENVIRONMENT || "test", } = input;
16
+ if (!merchantKey || !merchantSalt) {
17
+ return new workflows_sdk_1.StepResponse({
18
+ success: false,
19
+ status: "error",
20
+ error: "PayU configuration missing",
21
+ });
22
+ }
23
+ try {
24
+ const config = { merchantKey, merchantSalt, environment };
25
+ const client = new client_1.PayuClient(config);
26
+ const response = await client.verifyPayment(txnid);
27
+ if (response.status === 1) {
28
+ const txn = response.transaction_details[txnid];
29
+ if (txn) {
30
+ return new workflows_sdk_1.StepResponse({
31
+ success: true,
32
+ status: txn.status,
33
+ transaction: txn,
34
+ });
35
+ }
36
+ }
37
+ return new workflows_sdk_1.StepResponse({
38
+ success: false,
39
+ status: "not_found",
40
+ error: response.msg || "Transaction not found",
41
+ });
42
+ }
43
+ catch (error) {
44
+ return new workflows_sdk_1.StepResponse({
45
+ success: false,
46
+ status: "error",
47
+ error: error.message,
48
+ });
49
+ }
50
+ });
51
+ /**
52
+ * Verify PayU Payment Workflow
53
+ */
54
+ exports.verifyPayuPaymentWorkflow = (0, workflows_sdk_1.createWorkflow)("verify-payu-payment", (input) => {
55
+ const result = verifyPaymentStep(input);
56
+ return new workflows_sdk_1.WorkflowResponse(result);
57
+ });
58
+ exports.default = exports.verifyPayuPaymentWorkflow;
59
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmVyaWZ5LXBheXUtcGF5bWVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy93b3JrZmxvd3MvdmVyaWZ5LXBheXUtcGF5bWVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7R0FJRzs7O0FBRUgscUVBSzBDO0FBQzFDLHFEQUFxRDtBQXVCckQ7O0dBRUc7QUFDSCxNQUFNLGlCQUFpQixHQUFHLElBQUEsMEJBQVUsRUFDaEMsMEJBQTBCLEVBQzFCLEtBQUssRUFBRSxLQUE2QixFQUFrRCxFQUFFO0lBQ3BGLE1BQU0sRUFDRixLQUFLLEVBQ0wsV0FBVyxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsaUJBQWlCLElBQUksRUFBRSxFQUNqRCxZQUFZLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxrQkFBa0IsSUFBSSxFQUFFLEVBQ25ELFdBQVcsR0FBSSxPQUFPLENBQUMsR0FBRyxDQUFDLGdCQUEwQyxJQUFJLE1BQU0sR0FDbEYsR0FBRyxLQUFLLENBQUE7SUFFVCxJQUFJLENBQUMsV0FBVyxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7UUFDaEMsT0FBTyxJQUFJLDRCQUFZLENBQUM7WUFDcEIsT0FBTyxFQUFFLEtBQUs7WUFDZCxNQUFNLEVBQUUsT0FBTztZQUNmLEtBQUssRUFBRSw0QkFBNEI7U0FDdEMsQ0FBQyxDQUFBO0lBQ04sQ0FBQztJQUVELElBQUksQ0FBQztRQUNELE1BQU0sTUFBTSxHQUF1QixFQUFFLFdBQVcsRUFBRSxZQUFZLEVBQUUsV0FBVyxFQUFFLENBQUE7UUFDN0UsTUFBTSxNQUFNLEdBQUcsSUFBSSxtQkFBVSxDQUFDLE1BQU0sQ0FBQyxDQUFBO1FBQ3JDLE1BQU0sUUFBUSxHQUFHLE1BQU0sTUFBTSxDQUFDLGFBQWEsQ0FBQyxLQUFLLENBQUMsQ0FBQTtRQUVsRCxJQUFJLFFBQVEsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDeEIsTUFBTSxHQUFHLEdBQUcsUUFBUSxDQUFDLG1CQUFtQixDQUFDLEtBQUssQ0FBQyxDQUFBO1lBQy9DLElBQUksR0FBRyxFQUFFLENBQUM7Z0JBQ04sT0FBTyxJQUFJLDRCQUFZLENBQUM7b0JBQ3BCLE9BQU8sRUFBRSxJQUFJO29CQUNiLE1BQU0sRUFBRSxHQUFHLENBQUMsTUFBTTtvQkFDbEIsV0FBVyxFQUFFLEdBQXlDO2lCQUN6RCxDQUFDLENBQUE7WUFDTixDQUFDO1FBQ0wsQ0FBQztRQUVELE9BQU8sSUFBSSw0QkFBWSxDQUFDO1lBQ3BCLE9BQU8sRUFBRSxLQUFLO1lBQ2QsTUFBTSxFQUFFLFdBQVc7WUFDbkIsS0FBSyxFQUFFLFFBQVEsQ0FBQyxHQUFHLElBQUksdUJBQXVCO1NBQ2pELENBQUMsQ0FBQTtJQUNOLENBQUM7SUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1FBQ2IsT0FBTyxJQUFJLDRCQUFZLENBQUM7WUFDcEIsT0FBTyxFQUFFLEtBQUs7WUFDZCxNQUFNLEVBQUUsT0FBTztZQUNmLEtBQUssRUFBRyxLQUFlLENBQUMsT0FBTztTQUNsQyxDQUFDLENBQUE7SUFDTixDQUFDO0FBQ0wsQ0FBQyxDQUNKLENBQUE7QUFFRDs7R0FFRztBQUNVLFFBQUEseUJBQXlCLEdBQUcsSUFBQSw4QkFBYyxFQUNuRCxxQkFBcUIsRUFDckIsQ0FBQyxLQUE2QixFQUFFLEVBQUU7SUFDOUIsTUFBTSxNQUFNLEdBQUcsaUJBQWlCLENBQUMsS0FBSyxDQUFDLENBQUE7SUFDdkMsT0FBTyxJQUFJLGdDQUFnQixDQUFDLE1BQU0sQ0FBQyxDQUFBO0FBQ3ZDLENBQUMsQ0FDSixDQUFBO0FBRUQsa0JBQWUsaUNBQXlCLENBQUEifQ==
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 SAM-AEL
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,290 @@
1
+ # PayU Payment Plugin for MedusaJS 2
2
+
3
+ PayU India payment gateway plugin for MedusaJS 2.x with redirect-based checkout flow.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/medusa-payu-payment-plugin.svg)](https://www.npmjs.com/package/medusa-payu-payment-plugin)
6
+ [![MedusaJS](https://img.shields.io/badge/MedusaJS-2.x-7C3AED)](https://medusajs.com/)
7
+ [![PayU India](https://img.shields.io/badge/PayU-India-00B9F1)](https://payu.in/)
8
+ [![License](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
9
+ [![Node.js](https://img.shields.io/badge/node-%3E%3D20-brightgreen)](https://nodejs.org/)
10
+
11
+ ## Features
12
+
13
+ - ✅ **Redirect-based checkout** - Seamless PayU hosted checkout integration
14
+ - ✅ **Webhook support** - Automatic payment status updates via PayU webhooks
15
+ - ✅ **Refund support** - Full and partial refunds through PayU API
16
+ - ✅ **Hash verification** - Secure SHA-512 transaction validation
17
+ - ✅ **TypeScript** - Full type safety with comprehensive type definitions
18
+ - ✅ **Payment verification workflow** - Built-in workflow for custom payment verification
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ npm install medusa-payu-payment-plugin
24
+ # or
25
+ yarn add medusa-payu-payment-plugin
26
+ ```
27
+
28
+ ## Configuration
29
+
30
+ ### 1. Environment Variables
31
+
32
+ Add to your `.env` file:
33
+
34
+ ```env
35
+ # PayU Credentials
36
+ PAYU_MERCHANT_KEY=your_merchant_key
37
+ PAYU_MERCHANT_SALT=your_merchant_salt
38
+ PAYU_ENVIRONMENT=test # or "production"
39
+
40
+ # Your storefront URL (for redirect callbacks)
41
+ STOREFRONT_URL=http://localhost:8000
42
+ ```
43
+
44
+ ### 2. MedusaJS Config
45
+
46
+ Add to your `medusa-config.ts`:
47
+
48
+ ```typescript
49
+ import { defineConfig } from "@medusajs/framework/utils"
50
+
51
+ export default defineConfig({
52
+ // ... other config
53
+ modules: [
54
+ {
55
+ resolve: "@medusajs/medusa/payment",
56
+ options: {
57
+ providers: [
58
+ {
59
+ resolve: "medusa-payu-payment-plugin/providers/payu",
60
+ id: "payu",
61
+ options: {
62
+ merchantKey: process.env.PAYU_MERCHANT_KEY,
63
+ merchantSalt: process.env.PAYU_MERCHANT_SALT,
64
+ environment: process.env.PAYU_ENVIRONMENT || "test",
65
+ },
66
+ },
67
+ ],
68
+ },
69
+ },
70
+ ],
71
+ })
72
+ ```
73
+
74
+ ### 3. Enable for Region
75
+
76
+ In Medusa Admin:
77
+ 1. Go to **Settings → Regions**
78
+ 2. Select your region
79
+ 3. Add `payu` as a payment provider
80
+
81
+ ## Frontend Integration
82
+
83
+ ### Payment Flow Overview
84
+
85
+ 1. Customer selects PayU at checkout
86
+ 2. Frontend retrieves payment session from cart
87
+ 3. Frontend creates a form and redirects to PayU
88
+ 4. Customer completes payment on PayU's hosted page
89
+ 5. PayU redirects back to your storefront
90
+ 6. Webhook updates order status automatically
91
+
92
+ ### React/Next.js Example
93
+
94
+ ```tsx
95
+ "use client"
96
+
97
+ function PayUPaymentButton({ cart }) {
98
+ const handlePayment = async () => {
99
+ // Get PayU payment session
100
+ const paymentSession = cart.payment_collection?.payment_sessions?.find(
101
+ (session) => session.provider_id === "pp_payu_payu"
102
+ )
103
+
104
+ if (!paymentSession?.data?.form_data) {
105
+ console.error("PayU session not found")
106
+ return
107
+ }
108
+
109
+ const { form_data, paymentUrl } = paymentSession.data
110
+
111
+ // Create and submit hidden form
112
+ const form = document.createElement("form")
113
+ form.method = "POST"
114
+ form.action = paymentUrl
115
+
116
+ Object.entries(form_data).forEach(([key, value]) => {
117
+ const input = document.createElement("input")
118
+ input.type = "hidden"
119
+ input.name = key
120
+ input.value = String(value)
121
+ form.appendChild(input)
122
+ })
123
+
124
+ document.body.appendChild(form)
125
+ form.submit()
126
+ }
127
+
128
+ return (
129
+ <button
130
+ onClick={handlePayment}
131
+ className="btn-primary"
132
+ >
133
+ Pay with PayU
134
+ </button>
135
+ )
136
+ }
137
+ ```
138
+
139
+ ### Payment Session Structure
140
+
141
+ The payment session data contains:
142
+
143
+ ```typescript
144
+ {
145
+ txnid: string // Unique transaction ID
146
+ amount: string // Amount with 2 decimals (e.g., "999.00")
147
+ productinfo: string // Product/order description
148
+ firstname: string // Customer first name
149
+ email: string // Customer email
150
+ phone: string // Customer phone
151
+ hash: string // Security hash (SHA-512)
152
+ paymentUrl: string // PayU checkout URL
153
+ status: string // Payment status
154
+ form_data: { // Ready-to-submit form data
155
+ key: string // Merchant key
156
+ txnid: string
157
+ amount: string
158
+ productinfo: string
159
+ firstname: string
160
+ email: string
161
+ phone: string
162
+ surl: string // Success redirect URL
163
+ furl: string // Failure redirect URL
164
+ hash: string
165
+ service_provider: string
166
+ }
167
+ }
168
+ ```
169
+
170
+ ## Webhook Setup
171
+
172
+ Configure the webhook URL in your PayU dashboard:
173
+
174
+ ```
175
+ https://your-backend.com/hooks/payment/pp_payu_payu
176
+ ```
177
+
178
+ The webhook handler automatically:
179
+ - Verifies the response hash for security
180
+ - Updates payment status (authorized/failed)
181
+ - Triggers order completion workflow
182
+
183
+ ## API Reference
184
+
185
+ ### Provider ID
186
+
187
+ ```
188
+ pp_payu_payu
189
+ ```
190
+
191
+ ### Supported Methods
192
+
193
+ | Method | Description |
194
+ |--------|-------------|
195
+ | `initiatePayment` | Creates payment session with hash and form data |
196
+ | `authorizePayment` | Verifies payment status with PayU API |
197
+ | `capturePayment` | Marks payment as captured (auto-capture enabled) |
198
+ | `refundPayment` | Initiates full or partial refund |
199
+ | `cancelPayment` | Cancels pending payment |
200
+ | `getWebhookActionAndData` | Handles PayU webhook callbacks |
201
+
202
+ ### Exported Workflow
203
+
204
+ You can use the verify payment workflow in your custom code:
205
+
206
+ ```typescript
207
+ import { verifyPayuPaymentWorkflow } from "medusa-payu-payment-plugin/workflows"
208
+
209
+ // In your API route or subscriber
210
+ const { result } = await verifyPayuPaymentWorkflow(container).run({
211
+ input: {
212
+ txnid: "TXN_1234567890_abcd",
213
+ },
214
+ })
215
+
216
+ if (result.success) {
217
+ console.log("Payment status:", result.status)
218
+ console.log("Transaction details:", result.transaction)
219
+ }
220
+ ```
221
+
222
+ ## Environment Variables
223
+
224
+ | Variable | Description | Required |
225
+ |----------|-------------|----------|
226
+ | `PAYU_MERCHANT_KEY` | PayU Merchant Key | Yes |
227
+ | `PAYU_MERCHANT_SALT` | PayU Merchant Salt (Salt V1) | Yes |
228
+ | `PAYU_ENVIRONMENT` | `test` or `production` | No (default: `test`) |
229
+ | `STOREFRONT_URL` | Your storefront URL for redirects | Yes |
230
+
231
+ ## Testing
232
+
233
+ Use PayU test credentials in your test environment:
234
+
235
+ - **Test URL**: https://test.payu.in
236
+ - **Test Cards**: [PayU Test Cards Documentation](https://devguide.payu.in/docs/test-integration/test-cards/)
237
+
238
+ ### Common Test Card Numbers
239
+
240
+ | Card Type | Number | CVV | Expiry |
241
+ |-----------|--------|-----|--------|
242
+ | Visa | 4012001038443335 | 123 | Any future date |
243
+ | Mastercard | 5123456789012346 | 123 | Any future date |
244
+
245
+ ## Troubleshooting
246
+
247
+ ### Hash Mismatch Error
248
+
249
+ Ensure:
250
+ 1. You're using the correct Salt version (this plugin uses Salt V1)
251
+ 2. Amount has exactly 2 decimal places (e.g., `"999.00"`)
252
+ 3. All mandatory fields match exactly between hash generation and form submission
253
+
254
+ ### Webhook Not Received
255
+
256
+ 1. Verify webhook URL is correct in PayU dashboard
257
+ 2. Ensure your server is publicly accessible
258
+ 3. Check server logs for incoming webhook requests
259
+ 4. Verify SSL certificate is valid (required for production)
260
+
261
+ ### Payment Session Not Found
262
+
263
+ Ensure:
264
+ 1. PayU is enabled as a payment provider for the region
265
+ 2. Payment collection is initialized before accessing session
266
+ 3. Provider ID is `pp_payu_payu` (includes the prefix)
267
+
268
+ ## Contributing
269
+
270
+ Contributions are welcome! Please feel free to submit a Pull Request.
271
+
272
+ 1. Fork the repository
273
+ 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
274
+ 3. Commit your changes (`git commit -m 'Add amazing feature'`)
275
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
276
+ 5. Open a Pull Request
277
+
278
+ ## License
279
+
280
+ MIT © [SAM-AEL](https://github.com/SAM-AEL)
281
+
282
+ See [LICENSE](LICENSE) for more information.
283
+
284
+ ## Links
285
+
286
+ - [GitHub Repository](https://github.com/SAM-AEL/medusa-payu-payment-plugin)
287
+ - [npm Package](https://www.npmjs.com/package/medusa-payu-payment-plugin)
288
+ - [PayU Developer Documentation](https://devguide.payu.in/)
289
+ - [MedusaJS Documentation](https://docs.medusajs.com/)
290
+ - [Changelog](CHANGELOG.md)
package/package.json ADDED
@@ -0,0 +1,84 @@
1
+ {
2
+ "name": "medusa-payu-payment-plugin",
3
+ "version": "1.1.0",
4
+ "description": "PayU India payment gateway plugin for MedusaJS 2.x with redirect-based checkout, webhook support, hash verification, and refunds.",
5
+ "author": "SAM-AEL (https://github.com/SAM-AEL)",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/SAM-AEL/medusa-payu-payment-plugin.git"
10
+ },
11
+ "homepage": "https://github.com/SAM-AEL/medusa-payu-payment-plugin#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/SAM-AEL/medusa-payu-payment-plugin/issues"
14
+ },
15
+ "files": [
16
+ ".medusa/server"
17
+ ],
18
+ "exports": {
19
+ "./package.json": "./package.json",
20
+ "./workflows": "./.medusa/server/src/workflows/index.js",
21
+ "./.medusa/server/src/modules/*": "./.medusa/server/src/modules/*/index.js",
22
+ "./modules/*": "./.medusa/server/src/modules/*/index.js",
23
+ "./providers/*": "./.medusa/server/src/providers/*/index.js",
24
+ "./*": "./.medusa/server/src/*.js",
25
+ "./admin": {
26
+ "import": "./.medusa/server/src/admin/index.mjs",
27
+ "require": "./.medusa/server/src/admin/index.js",
28
+ "default": "./.medusa/server/src/admin/index.js"
29
+ }
30
+ },
31
+ "keywords": [
32
+ "medusa",
33
+ "medusajs",
34
+ "medusa-v2",
35
+ "medusa-plugin",
36
+ "medusa-plugin-payment",
37
+ "medusa-plugin-integration",
38
+ "payment",
39
+ "payment-gateway",
40
+ "payu",
41
+ "payu-india",
42
+ "india",
43
+ "ecommerce",
44
+ "checkout",
45
+ "redirect-payment"
46
+ ],
47
+ "scripts": {
48
+ "build": "medusa plugin:build",
49
+ "dev": "medusa plugin:develop",
50
+ "prepublishOnly": "medusa plugin:build"
51
+ },
52
+ "devDependencies": {
53
+ "@medusajs/admin-sdk": "2.11.2",
54
+ "@medusajs/cli": "2.11.2",
55
+ "@medusajs/framework": "2.11.2",
56
+ "@medusajs/icons": "2.11.2",
57
+ "@medusajs/medusa": "2.11.2",
58
+ "@medusajs/test-utils": "2.11.2",
59
+ "@medusajs/ui": "4.0.25",
60
+ "@swc/core": "1.5.7",
61
+ "@types/node": "^20.0.0",
62
+ "@types/react": "^18.3.2",
63
+ "@types/react-dom": "^18.2.25",
64
+ "prop-types": "^15.8.1",
65
+ "react": "^18.2.0",
66
+ "react-dom": "^18.2.0",
67
+ "ts-node": "^10.9.2",
68
+ "typescript": "^5.6.2",
69
+ "vite": "^5.2.11"
70
+ },
71
+ "dependencies": {},
72
+ "peerDependencies": {
73
+ "@medusajs/admin-sdk": "2.11.2",
74
+ "@medusajs/cli": "2.11.2",
75
+ "@medusajs/framework": "2.11.2",
76
+ "@medusajs/icons": "2.11.2",
77
+ "@medusajs/medusa": "2.11.2",
78
+ "@medusajs/test-utils": "2.11.2",
79
+ "@medusajs/ui": "4.0.25"
80
+ },
81
+ "engines": {
82
+ "node": ">=20"
83
+ }
84
+ }