@duvdu-v1/duvdu 1.1.265 → 1.1.267
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.
|
@@ -39,7 +39,7 @@ interface PaymobOrder {
|
|
|
39
39
|
interface PaymobOrderItem {
|
|
40
40
|
name: string;
|
|
41
41
|
description: string;
|
|
42
|
-
|
|
42
|
+
amount: number;
|
|
43
43
|
quantity: number;
|
|
44
44
|
}
|
|
45
45
|
interface PaymobSourceData {
|
|
@@ -83,14 +83,9 @@ interface PaymobBillingData {
|
|
|
83
83
|
floor: string;
|
|
84
84
|
street: string;
|
|
85
85
|
building: string;
|
|
86
|
-
city
|
|
86
|
+
city?: string;
|
|
87
87
|
state: string;
|
|
88
88
|
country: string;
|
|
89
|
-
postal_code: string;
|
|
90
|
-
}
|
|
91
|
-
interface CreateOrderResult {
|
|
92
|
-
orderId: number;
|
|
93
|
-
token: string;
|
|
94
89
|
}
|
|
95
90
|
interface TransactionData {
|
|
96
91
|
orderId: number;
|
|
@@ -138,28 +133,34 @@ interface OrderDetailsResult {
|
|
|
138
133
|
merchant_order_id: string;
|
|
139
134
|
}
|
|
140
135
|
/**
|
|
141
|
-
* Paymob Service Configuration
|
|
136
|
+
* Paymob Service Configuration for Flash Integration
|
|
142
137
|
*
|
|
143
138
|
* Required Keys:
|
|
144
|
-
* -
|
|
145
|
-
* -
|
|
146
|
-
* -
|
|
147
|
-
*
|
|
148
|
-
* Note:
|
|
149
|
-
* - Public Key: Used for client-side encryption (not needed for this service)
|
|
150
|
-
* - Secret Key: Used for webhook signature verification (handled internally)
|
|
139
|
+
* - secretKey: Your Paymob Secret Key (for API authentication)
|
|
140
|
+
* - publicKey: Your Paymob Public Key (for client-side)
|
|
141
|
+
* - integrationId: Your Paymob Integration ID
|
|
142
|
+
* - hmacSecret: Your Paymob HMAC Secret (for webhook verification)
|
|
151
143
|
*/
|
|
152
144
|
export declare class PaymobService {
|
|
153
|
-
private readonly
|
|
145
|
+
private readonly secretKey;
|
|
146
|
+
private readonly publicKey;
|
|
154
147
|
private readonly integrationId;
|
|
155
|
-
private readonly iframeId;
|
|
156
148
|
private readonly baseUrl;
|
|
157
149
|
private readonly hmacSecret;
|
|
158
150
|
constructor();
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
151
|
+
/**
|
|
152
|
+
* Creates a payment intention using the Flash API
|
|
153
|
+
* @param amount The payment amount
|
|
154
|
+
* @param billingData The user data for billing
|
|
155
|
+
* @param items The order items
|
|
156
|
+
* @param currency The currency code (default: EGP)
|
|
157
|
+
* @param extras Custom metadata
|
|
158
|
+
* @returns The payment URL and client secret
|
|
159
|
+
*/
|
|
160
|
+
createPaymentIntention(amount: number, billingData: PaymobBillingData, items: PaymobOrderItem[], currency?: string, extras?: Record<string, any>): Promise<{
|
|
161
|
+
paymentUrl: string;
|
|
162
|
+
clientSecret: string;
|
|
163
|
+
}>;
|
|
163
164
|
/**
|
|
164
165
|
* Creates a payment URL with user data and custom metadata
|
|
165
166
|
* @param amount The payment amount
|
|
@@ -39,104 +39,74 @@ exports.PaymobService = void 0;
|
|
|
39
39
|
const crypto = __importStar(require("crypto"));
|
|
40
40
|
const axios_1 = __importDefault(require("axios"));
|
|
41
41
|
/**
|
|
42
|
-
* Paymob Service Configuration
|
|
42
|
+
* Paymob Service Configuration for Flash Integration
|
|
43
43
|
*
|
|
44
44
|
* Required Keys:
|
|
45
|
-
* -
|
|
46
|
-
* -
|
|
47
|
-
* -
|
|
48
|
-
*
|
|
49
|
-
* Note:
|
|
50
|
-
* - Public Key: Used for client-side encryption (not needed for this service)
|
|
51
|
-
* - Secret Key: Used for webhook signature verification (handled internally)
|
|
45
|
+
* - secretKey: Your Paymob Secret Key (for API authentication)
|
|
46
|
+
* - publicKey: Your Paymob Public Key (for client-side)
|
|
47
|
+
* - integrationId: Your Paymob Integration ID
|
|
48
|
+
* - hmacSecret: Your Paymob HMAC Secret (for webhook verification)
|
|
52
49
|
*/
|
|
53
50
|
class PaymobService {
|
|
54
51
|
constructor() {
|
|
55
|
-
this.
|
|
52
|
+
this.secretKey = process.env.PAYMOB_SECRET_KEY;
|
|
53
|
+
this.publicKey = process.env.PAYMOB_PUBLIC_KEY;
|
|
56
54
|
this.integrationId = parseInt(process.env.PAYMOB_INTEGRATION_ID);
|
|
57
|
-
this.
|
|
58
|
-
this.baseUrl = process.env.PAYMOB_BASE_URL;
|
|
55
|
+
this.baseUrl = process.env.PAYMOB_BASE_URL || 'https://accept.paymob.com';
|
|
59
56
|
this.hmacSecret = process.env.PAYMOB_HMAC_SECRET;
|
|
60
57
|
console.log('PayMob configuration:', {
|
|
61
58
|
integrationId: this.integrationId,
|
|
62
|
-
|
|
59
|
+
publicKey: this.publicKey,
|
|
63
60
|
baseUrl: this.baseUrl,
|
|
64
61
|
});
|
|
65
62
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
throw new Error(`Failed to get Paymob auth token: ${axiosError.message}`);
|
|
77
|
-
}
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
createOrder(amount, currency = 'EGP', items = [], merchant_order_id) {
|
|
63
|
+
/**
|
|
64
|
+
* Creates a payment intention using the Flash API
|
|
65
|
+
* @param amount The payment amount
|
|
66
|
+
* @param billingData The user data for billing
|
|
67
|
+
* @param items The order items
|
|
68
|
+
* @param currency The currency code (default: EGP)
|
|
69
|
+
* @param extras Custom metadata
|
|
70
|
+
* @returns The payment URL and client secret
|
|
71
|
+
*/
|
|
72
|
+
createPaymentIntention(amount, billingData, items, currency = 'EGP', extras) {
|
|
81
73
|
var _a;
|
|
82
74
|
return __awaiter(this, void 0, void 0, function* () {
|
|
83
75
|
try {
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
auth_token: authToken,
|
|
87
|
-
delivery_needed: false,
|
|
88
|
-
amount_cents: amount * 100,
|
|
76
|
+
const intentionData = {
|
|
77
|
+
amount,
|
|
89
78
|
currency,
|
|
79
|
+
payment_methods: [this.integrationId, 'card'],
|
|
90
80
|
items,
|
|
81
|
+
billing_data: billingData,
|
|
82
|
+
customer: {
|
|
83
|
+
first_name: billingData.first_name,
|
|
84
|
+
last_name: billingData.last_name,
|
|
85
|
+
email: billingData.email,
|
|
86
|
+
extras: extras || {},
|
|
87
|
+
},
|
|
88
|
+
extras: extras || {},
|
|
91
89
|
};
|
|
92
|
-
|
|
93
|
-
orderData.merchant_order_id = merchant_order_id;
|
|
94
|
-
}
|
|
95
|
-
const response = yield axios_1.default.post(`${this.baseUrl}/ecommerce/orders`, orderData, {
|
|
90
|
+
const response = yield axios_1.default.post(`${this.baseUrl}/v1/intention/`, intentionData, {
|
|
96
91
|
headers: {
|
|
92
|
+
'Authorization': `Token ${this.secretKey}`,
|
|
97
93
|
'Content-Type': 'application/json',
|
|
98
94
|
},
|
|
99
95
|
});
|
|
96
|
+
// Create the payment URL for Flash Checkout
|
|
97
|
+
const paymentUrl = `${this.baseUrl}/unifiedcheckout/?publicKey=${this.publicKey}&clientSecret=${response.data.client_secret}`;
|
|
100
98
|
return {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
catch (error) {
|
|
106
|
-
const axiosError = error;
|
|
107
|
-
console.log('PayMob order error:', (_a = axiosError.response) === null || _a === void 0 ? void 0 : _a.data);
|
|
108
|
-
throw new Error(`Failed to create Paymob order: ${axiosError.message}`);
|
|
109
|
-
}
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
getPaymentKey(orderId, token, amount, billingData) {
|
|
113
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
114
|
-
try {
|
|
115
|
-
const paymentKeyRequest = {
|
|
116
|
-
auth_token: token,
|
|
117
|
-
amount_cents: amount * 100,
|
|
118
|
-
expiration: 3600,
|
|
119
|
-
order_id: orderId,
|
|
120
|
-
billing_data: billingData,
|
|
121
|
-
currency: 'EGP',
|
|
122
|
-
integration_id: this.integrationId,
|
|
99
|
+
paymentUrl,
|
|
100
|
+
clientSecret: response.data.client_secret,
|
|
123
101
|
};
|
|
124
|
-
const response = yield axios_1.default.post(`${this.baseUrl}/acceptance/payment_keys`, paymentKeyRequest, {
|
|
125
|
-
headers: {
|
|
126
|
-
'Content-Type': 'application/json',
|
|
127
|
-
},
|
|
128
|
-
});
|
|
129
|
-
return response.data.token;
|
|
130
102
|
}
|
|
131
103
|
catch (error) {
|
|
132
104
|
const axiosError = error;
|
|
133
|
-
|
|
105
|
+
console.log('PayMob intention error:', (_a = axiosError.response) === null || _a === void 0 ? void 0 : _a.data);
|
|
106
|
+
throw new Error(`Failed to create Paymob payment intention: ${axiosError.message}`);
|
|
134
107
|
}
|
|
135
108
|
});
|
|
136
109
|
}
|
|
137
|
-
createPaymentUrl(paymentKey) {
|
|
138
|
-
return `https://accept.paymob.com/api/acceptance/iframes/${this.iframeId}?payment_token=${paymentKey}`;
|
|
139
|
-
}
|
|
140
110
|
/**
|
|
141
111
|
* Creates a payment URL with user data and custom metadata
|
|
142
112
|
* @param amount The payment amount
|
|
@@ -147,9 +117,9 @@ class PaymobService {
|
|
|
147
117
|
* @returns The payment URL and related data
|
|
148
118
|
*/
|
|
149
119
|
createPaymentUrlWithUserData(amount, userId, contractId, userData, serviceType) {
|
|
120
|
+
var _a;
|
|
150
121
|
return __awaiter(this, void 0, void 0, function* () {
|
|
151
|
-
|
|
152
|
-
// Store custom data in merchant_order_id as JSON string
|
|
122
|
+
// Create metadata with custom data
|
|
153
123
|
const customData = {
|
|
154
124
|
contractId,
|
|
155
125
|
userId,
|
|
@@ -157,23 +127,60 @@ class PaymobService {
|
|
|
157
127
|
booking_id: 'BOOK_' + Date.now(),
|
|
158
128
|
timestamp: new Date().toISOString(),
|
|
159
129
|
};
|
|
160
|
-
const
|
|
161
|
-
const
|
|
130
|
+
const extras = customData;
|
|
131
|
+
const billingData = {
|
|
162
132
|
first_name: userData.firstName,
|
|
163
133
|
last_name: userData.lastName,
|
|
164
134
|
email: userData.email,
|
|
165
135
|
phone_number: userData.phone,
|
|
166
136
|
apartment: '123',
|
|
167
|
-
floor: '
|
|
168
|
-
street: '123',
|
|
137
|
+
floor: '1',
|
|
138
|
+
street: '123 Main St',
|
|
169
139
|
building: '123',
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
140
|
+
state: 'Cairo',
|
|
141
|
+
country: 'EGY',
|
|
142
|
+
};
|
|
143
|
+
const items = [
|
|
144
|
+
{
|
|
145
|
+
name: `${serviceType} Payment`,
|
|
146
|
+
description: `Payment for contract ${contractId}`,
|
|
147
|
+
amount,
|
|
148
|
+
quantity: 1,
|
|
149
|
+
},
|
|
150
|
+
];
|
|
151
|
+
// For Flash Integration, we need to create a modified intention request
|
|
152
|
+
// that includes merchant_order_id
|
|
153
|
+
const intentionData = {
|
|
154
|
+
amount,
|
|
155
|
+
currency: 'EGP',
|
|
156
|
+
payment_methods: [this.integrationId, 'card'],
|
|
157
|
+
items,
|
|
158
|
+
billing_data: billingData,
|
|
159
|
+
customer: {
|
|
160
|
+
first_name: billingData.first_name,
|
|
161
|
+
last_name: billingData.last_name,
|
|
162
|
+
email: billingData.email,
|
|
163
|
+
extras: extras || {},
|
|
164
|
+
},
|
|
165
|
+
extras: extras || {},
|
|
166
|
+
merchant_order_id: JSON.stringify(customData), // Store custom data here
|
|
167
|
+
};
|
|
168
|
+
try {
|
|
169
|
+
const response = yield axios_1.default.post(`${this.baseUrl}/v1/intention/`, intentionData, {
|
|
170
|
+
headers: {
|
|
171
|
+
'Authorization': `Token ${this.secretKey}`,
|
|
172
|
+
'Content-Type': 'application/json',
|
|
173
|
+
},
|
|
174
|
+
});
|
|
175
|
+
// Create the payment URL for Flash Checkout
|
|
176
|
+
const paymentUrl = `${this.baseUrl}/unifiedcheckout/?publicKey=${this.publicKey}&clientSecret=${response.data.client_secret}`;
|
|
177
|
+
return { paymentUrl };
|
|
178
|
+
}
|
|
179
|
+
catch (error) {
|
|
180
|
+
const axiosError = error;
|
|
181
|
+
console.log('PayMob intention error:', (_a = axiosError.response) === null || _a === void 0 ? void 0 : _a.data);
|
|
182
|
+
throw new Error(`Failed to create Paymob payment intention: ${axiosError.message}`);
|
|
183
|
+
}
|
|
177
184
|
});
|
|
178
185
|
}
|
|
179
186
|
verifyPayment(hmac, data) {
|
|
@@ -183,7 +190,7 @@ class PaymobService {
|
|
|
183
190
|
.map(([key, value]) => `${key}=${value}`)
|
|
184
191
|
.join('');
|
|
185
192
|
const calculatedHmac = crypto
|
|
186
|
-
.createHmac('sha512', this.
|
|
193
|
+
.createHmac('sha512', this.secretKey)
|
|
187
194
|
.update(concatenatedString)
|
|
188
195
|
.digest('hex');
|
|
189
196
|
return calculatedHmac === hmac;
|
|
@@ -299,11 +306,10 @@ class PaymobService {
|
|
|
299
306
|
getTransactionStatus(transactionId) {
|
|
300
307
|
return __awaiter(this, void 0, void 0, function* () {
|
|
301
308
|
try {
|
|
302
|
-
const
|
|
303
|
-
const response = yield axios_1.default.get(`${this.baseUrl}/acceptance/transactions/${transactionId}`, {
|
|
309
|
+
const response = yield axios_1.default.get(`${this.baseUrl}/api/acceptance/transactions/${transactionId}`, {
|
|
304
310
|
headers: {
|
|
305
311
|
'Content-Type': 'application/json',
|
|
306
|
-
Authorization: `
|
|
312
|
+
'Authorization': `Token ${this.secretKey}`,
|
|
307
313
|
},
|
|
308
314
|
});
|
|
309
315
|
return {
|
|
@@ -323,15 +329,29 @@ class PaymobService {
|
|
|
323
329
|
* Get order details including metadata
|
|
324
330
|
*/
|
|
325
331
|
getOrderDetails(orderId) {
|
|
332
|
+
var _a, _b, _c;
|
|
326
333
|
return __awaiter(this, void 0, void 0, function* () {
|
|
327
334
|
try {
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
+
// Try the Flash Integration API endpoint first
|
|
336
|
+
let response;
|
|
337
|
+
try {
|
|
338
|
+
response = yield axios_1.default.get(`${this.baseUrl}/v1/intention/orders/${orderId}`, {
|
|
339
|
+
headers: {
|
|
340
|
+
'Content-Type': 'application/json',
|
|
341
|
+
'Authorization': `Token ${this.secretKey}`,
|
|
342
|
+
},
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
catch (flashError) {
|
|
346
|
+
console.log('Flash API failed, trying legacy API...');
|
|
347
|
+
// Fallback to legacy API endpoint
|
|
348
|
+
response = yield axios_1.default.get(`${this.baseUrl}/api/ecommerce/orders/${orderId}`, {
|
|
349
|
+
headers: {
|
|
350
|
+
'Content-Type': 'application/json',
|
|
351
|
+
'Authorization': `Token ${this.secretKey}`,
|
|
352
|
+
},
|
|
353
|
+
});
|
|
354
|
+
}
|
|
335
355
|
return {
|
|
336
356
|
id: response.data.id,
|
|
337
357
|
amount_cents: response.data.amount_cents,
|
|
@@ -343,6 +363,21 @@ class PaymobService {
|
|
|
343
363
|
}
|
|
344
364
|
catch (error) {
|
|
345
365
|
const axiosError = error;
|
|
366
|
+
console.error('Order details error response:', (_a = axiosError.response) === null || _a === void 0 ? void 0 : _a.data);
|
|
367
|
+
console.error('Order details error status:', (_b = axiosError.response) === null || _b === void 0 ? void 0 : _b.status);
|
|
368
|
+
// If still failing, provide a fallback that returns minimal data
|
|
369
|
+
if (((_c = axiosError.response) === null || _c === void 0 ? void 0 : _c.status) === 401) {
|
|
370
|
+
console.log('Authentication failed, using fallback approach...');
|
|
371
|
+
// Return a minimal response that won't break the webhook
|
|
372
|
+
return {
|
|
373
|
+
id: orderId,
|
|
374
|
+
amount_cents: 0,
|
|
375
|
+
currency: 'EGP',
|
|
376
|
+
items: [],
|
|
377
|
+
created_at: new Date().toISOString(),
|
|
378
|
+
merchant_order_id: '', // Empty merchant_order_id will trigger fallback logic
|
|
379
|
+
};
|
|
380
|
+
}
|
|
346
381
|
throw new Error(`Failed to get order details: ${axiosError.message}`);
|
|
347
382
|
}
|
|
348
383
|
});
|