@webbers/pay-payments-medusa 1.0.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.
- package/.medusa/server/package.json +90 -0
- package/.medusa/server/src/admin/index.js +229 -0
- package/.medusa/server/src/admin/index.mjs +228 -0
- package/.medusa/server/src/api/admin/pay/clear-cache/route.js +23 -0
- package/.medusa/server/src/api/admin/pay/payment-methods/route.js +36 -0
- package/.medusa/server/src/api/store/pay/payment-methods/route.js +36 -0
- package/.medusa/server/src/providers/pay/core/constants.js +52 -0
- package/.medusa/server/src/providers/pay/core/http-client.js +107 -0
- package/.medusa/server/src/providers/pay/core/pay-base.js +561 -0
- package/.medusa/server/src/providers/pay/core/pay-client.js +118 -0
- package/.medusa/server/src/providers/pay/index.js +22 -0
- package/.medusa/server/src/providers/pay/services/index.js +17 -0
- package/.medusa/server/src/providers/pay/services/pay-bancontact.js +21 -0
- package/.medusa/server/src/providers/pay/services/pay-creditcard.js +21 -0
- package/.medusa/server/src/providers/pay/services/pay-ideal.js +21 -0
- package/.medusa/server/src/providers/pay/services/pay-provider.js +23 -0
- package/.medusa/server/src/providers/pay/services/pay-softpos.js +20 -0
- package/.medusa/server/src/providers/pay/types/common.js +3 -0
- package/.medusa/server/src/providers/pay/types/index.js +28 -0
- package/.medusa/server/src/providers/pay/types/order.js +3 -0
- package/.medusa/server/src/providers/pay/types/transaction.js +3 -0
- package/.medusa/server/src/providers/pay/utils/getExpirationForPaymentMethod.js +16 -0
- package/.medusa/server/src/providers/pay/utils/getSortedPaymentMethods.js +20 -0
- package/.medusa/server/src/providers/pay/utils/paymentMethodMap.js +133 -0
- package/.medusa/server/src/workflows/hooks/order-created.js +96 -0
- package/README.md +221 -0
- package/package.json +90 -0
|
@@ -0,0 +1,561 @@
|
|
|
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 pay_client_1 = require("./pay-client");
|
|
8
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
9
|
+
const constants_1 = require("./constants");
|
|
10
|
+
const getExpirationForPaymentMethod_1 = __importDefault(require("../utils/getExpirationForPaymentMethod"));
|
|
11
|
+
/**
|
|
12
|
+
* Implementation of Pay. Payment Provider for Medusa
|
|
13
|
+
*/
|
|
14
|
+
class PayBase extends utils_1.AbstractPaymentProvider {
|
|
15
|
+
/**
|
|
16
|
+
* Validates that the required options are provided
|
|
17
|
+
* @param options - The options to validate
|
|
18
|
+
* @throws {MedusaError} If required config is missing
|
|
19
|
+
*/
|
|
20
|
+
static validateOptions(options) {
|
|
21
|
+
if (!options.atCode ||
|
|
22
|
+
!options.apiToken ||
|
|
23
|
+
!options.slCode ||
|
|
24
|
+
!options.slSecret ||
|
|
25
|
+
!options.returnUrl ||
|
|
26
|
+
!options.medusaUrl) {
|
|
27
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "AT Code, API Token, SL Code, SL Secret, Return URL & Medusa URL are required in the provider's options.");
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Creates a new instance of the Pay. payment provider
|
|
32
|
+
* @param container - The dependency container
|
|
33
|
+
* @param options - Configuration options
|
|
34
|
+
*/
|
|
35
|
+
constructor(container, options) {
|
|
36
|
+
super(container, options);
|
|
37
|
+
this.getPaymentDescription = (order) => {
|
|
38
|
+
const language = order.metadata?.locale;
|
|
39
|
+
const paymentDescriptions = this.options_?.paymentDescription;
|
|
40
|
+
const displayId = order.display_id.toString();
|
|
41
|
+
let description = order.sales_channel?.name
|
|
42
|
+
? `${order.sales_channel.name} - #${displayId}`
|
|
43
|
+
: `#${displayId}`;
|
|
44
|
+
if (paymentDescriptions) {
|
|
45
|
+
description =
|
|
46
|
+
language && paymentDescriptions?.[language]
|
|
47
|
+
? paymentDescriptions[language]
|
|
48
|
+
: (paymentDescriptions?.default ?? "[display_id]");
|
|
49
|
+
description = description.replace("[display_id]", displayId);
|
|
50
|
+
}
|
|
51
|
+
return description;
|
|
52
|
+
};
|
|
53
|
+
this.logger_ = container.logger;
|
|
54
|
+
this.options_ = options;
|
|
55
|
+
this.debug_ =
|
|
56
|
+
options.testMode ||
|
|
57
|
+
process.env.NODE_ENV === "development" ||
|
|
58
|
+
process.env.NODE_ENV === "test" ||
|
|
59
|
+
false;
|
|
60
|
+
this.client_ = new pay_client_1.PayClient(options, this.logger_);
|
|
61
|
+
}
|
|
62
|
+
createPayOrderPayload(order, session_id, paymentMethodInput) {
|
|
63
|
+
const currency = order.currency_code.toUpperCase();
|
|
64
|
+
const products = order.items.map((item) => ({
|
|
65
|
+
id: item.variant_sku || item.variant_id || item.id,
|
|
66
|
+
description: `${item.product_title} - ${item.variant_title}`,
|
|
67
|
+
type: "ARTICLE",
|
|
68
|
+
price: {
|
|
69
|
+
value: Math.round((item.original_total.valueOf() / item.quantity) * 100),
|
|
70
|
+
currency,
|
|
71
|
+
},
|
|
72
|
+
quantity: item.quantity,
|
|
73
|
+
vatPercentage: item.tax_lines?.[0]?.rate,
|
|
74
|
+
}));
|
|
75
|
+
const discount = order.discount_total.valueOf() * 100;
|
|
76
|
+
if (discount > 0) {
|
|
77
|
+
products.push({
|
|
78
|
+
type: "DISCOUNT",
|
|
79
|
+
id: "DISCOUNT",
|
|
80
|
+
description: "Discount",
|
|
81
|
+
price: {
|
|
82
|
+
value: discount * -1,
|
|
83
|
+
currency,
|
|
84
|
+
},
|
|
85
|
+
quantity: 1,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
const shippingTotal = order.shipping_total.valueOf() * 100;
|
|
89
|
+
if (shippingTotal > 0) {
|
|
90
|
+
products.push({
|
|
91
|
+
type: "SHIPPING",
|
|
92
|
+
id: "SHIPPING",
|
|
93
|
+
description: "Shipping",
|
|
94
|
+
price: {
|
|
95
|
+
value: shippingTotal,
|
|
96
|
+
currency,
|
|
97
|
+
},
|
|
98
|
+
quantity: 1,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
let paymentMethod;
|
|
102
|
+
if (this.paymentCreateOptions.method_id) {
|
|
103
|
+
paymentMethod = {
|
|
104
|
+
id: this.paymentCreateOptions.method_id,
|
|
105
|
+
input: paymentMethodInput,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
const payload = {
|
|
109
|
+
reference: order.display_id.toString(),
|
|
110
|
+
description: this.getPaymentDescription(order),
|
|
111
|
+
paymentMethod,
|
|
112
|
+
returnUrl: this.options_.returnUrl,
|
|
113
|
+
expire: paymentMethod
|
|
114
|
+
? (0, getExpirationForPaymentMethod_1.default)(paymentMethod)
|
|
115
|
+
: undefined,
|
|
116
|
+
exchangeUrl: this.paymentCreateOptions.webhookUrl,
|
|
117
|
+
transferData: {
|
|
118
|
+
session_id,
|
|
119
|
+
},
|
|
120
|
+
amount: {
|
|
121
|
+
value: Math.round(order.total.valueOf() * 100),
|
|
122
|
+
currency,
|
|
123
|
+
},
|
|
124
|
+
customer: {
|
|
125
|
+
firstname: order.customer?.first_name || order.billing_address?.first_name,
|
|
126
|
+
lastname: order.customer?.last_name || order.billing_address?.last_name,
|
|
127
|
+
ipAddress: order.metadata?.ip,
|
|
128
|
+
phone: order.customer?.phone || order.billing_address?.phone,
|
|
129
|
+
email: order.email,
|
|
130
|
+
locale: order.metadata?.locale?.toString()?.toUpperCase() ?? "EN",
|
|
131
|
+
reference: order.customer?.id,
|
|
132
|
+
},
|
|
133
|
+
order: {
|
|
134
|
+
countryCode: order.billing_address?.country_code?.toUpperCase(),
|
|
135
|
+
invoiceAddress: {
|
|
136
|
+
firstName: order.billing_address?.first_name,
|
|
137
|
+
lastName: order.billing_address?.last_name,
|
|
138
|
+
street: order.billing_address?.address_1,
|
|
139
|
+
streetNumber: order.billing_address?.address_2,
|
|
140
|
+
zipCode: order.billing_address?.postal_code,
|
|
141
|
+
city: order.billing_address?.city,
|
|
142
|
+
country: order.billing_address?.country_code?.toUpperCase(),
|
|
143
|
+
},
|
|
144
|
+
deliveryAddress: {
|
|
145
|
+
firstName: order.shipping_address?.first_name,
|
|
146
|
+
lastName: order.shipping_address?.last_name,
|
|
147
|
+
street: order.shipping_address?.address_1,
|
|
148
|
+
streetNumber: order.shipping_address?.address_2,
|
|
149
|
+
zipCode: order.shipping_address?.postal_code,
|
|
150
|
+
city: order.shipping_address?.city,
|
|
151
|
+
country: order.shipping_address?.country_code?.toUpperCase(),
|
|
152
|
+
},
|
|
153
|
+
products,
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
if (this.options_.testMode) {
|
|
157
|
+
try {
|
|
158
|
+
this.logger_.debug(JSON.stringify(payload));
|
|
159
|
+
}
|
|
160
|
+
catch (e) { }
|
|
161
|
+
}
|
|
162
|
+
return payload;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Initiates a new payment with Pay.
|
|
166
|
+
* @param input - The payment initiation input
|
|
167
|
+
* @returns The initiated payment details
|
|
168
|
+
*/
|
|
169
|
+
async initiatePayment({ context, amount, data, currency_code, }) {
|
|
170
|
+
return {
|
|
171
|
+
data: { session_id: data?.session_id },
|
|
172
|
+
id: crypto_1.default.randomUUID(),
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Authorize the Pay. payment
|
|
177
|
+
* @param input - The payment authorization input
|
|
178
|
+
* @returns The authorization result
|
|
179
|
+
*/
|
|
180
|
+
async authorizePayment(input) {
|
|
181
|
+
console.log("authorizePayment", input);
|
|
182
|
+
if (input.data?.orderId) {
|
|
183
|
+
const { status } = await this.getPaymentStatus(input);
|
|
184
|
+
return { data: input.data, status };
|
|
185
|
+
}
|
|
186
|
+
return { data: input.data, status: utils_1.PaymentSessionStatus.AUTHORIZED };
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Captures an authorized payment if autoCapture is disabled
|
|
190
|
+
* @param input - The payment capture input
|
|
191
|
+
* @returns The capture result
|
|
192
|
+
*/
|
|
193
|
+
async capturePayment(input) {
|
|
194
|
+
console.log("capturePayment", input);
|
|
195
|
+
const id = input.data?.orderId;
|
|
196
|
+
if (!id) {
|
|
197
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Payment ID is required");
|
|
198
|
+
}
|
|
199
|
+
try {
|
|
200
|
+
const { data } = (await this.retrievePayment({
|
|
201
|
+
data: {
|
|
202
|
+
id,
|
|
203
|
+
},
|
|
204
|
+
}));
|
|
205
|
+
// If the Pay order is set to authorize we need to capture the order in Pay.
|
|
206
|
+
if (data?.status?.code === constants_1.PayPaymentStatus.AUTHORIZE) {
|
|
207
|
+
await this.client_.captureOrder(id);
|
|
208
|
+
}
|
|
209
|
+
const status = await this.getPaymentStatus({
|
|
210
|
+
data: {
|
|
211
|
+
id,
|
|
212
|
+
},
|
|
213
|
+
}).then((res) => res.status);
|
|
214
|
+
if (status !== utils_1.PaymentSessionStatus.CAPTURED) {
|
|
215
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, `Payment is not captured: current status is ${status}`);
|
|
216
|
+
}
|
|
217
|
+
this.debug_ &&
|
|
218
|
+
this.logger_.info(`Pay. payment ${id} captured with amount ${(input.data?.amount).currency_code} ${(input.data?.amount).value}`);
|
|
219
|
+
const payment = await this.retrievePayment({
|
|
220
|
+
data: {
|
|
221
|
+
id,
|
|
222
|
+
},
|
|
223
|
+
});
|
|
224
|
+
return {
|
|
225
|
+
data: payment.data,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
catch (error) {
|
|
229
|
+
this.logger_.error(`Error capturing payment ${id}: ${error.message}`);
|
|
230
|
+
throw error;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Refunds a payment
|
|
235
|
+
* @param input - The payment refund input
|
|
236
|
+
* @returns The refund result
|
|
237
|
+
*/
|
|
238
|
+
async refundPayment(input) {
|
|
239
|
+
console.log("refundPayment", input);
|
|
240
|
+
const id = input.data?.orderId;
|
|
241
|
+
if (!id) {
|
|
242
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Payment ID is required");
|
|
243
|
+
}
|
|
244
|
+
try {
|
|
245
|
+
const payment = await this.retrievePayment({
|
|
246
|
+
data: {
|
|
247
|
+
id,
|
|
248
|
+
},
|
|
249
|
+
});
|
|
250
|
+
const value = (input.data?.amount).value;
|
|
251
|
+
const currency = payment.data?.amount
|
|
252
|
+
?.currency;
|
|
253
|
+
if (!currency) {
|
|
254
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Currency information is missing from payment data");
|
|
255
|
+
}
|
|
256
|
+
const refund = await this.client_.refundPayment(id, {
|
|
257
|
+
amount: {
|
|
258
|
+
value: parseInt(value.toString()) * 100,
|
|
259
|
+
currency: currency.toUpperCase(),
|
|
260
|
+
},
|
|
261
|
+
});
|
|
262
|
+
this.debug_ &&
|
|
263
|
+
this.logger_.info(`Refund for Pay. payment ${id} created with amount ${currency.toUpperCase()} ${parseFloat(value.toString()).toFixed(2)}`);
|
|
264
|
+
return {
|
|
265
|
+
data: { ...refund },
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
catch (error) {
|
|
269
|
+
this.logger_.error(`Error refunding payment ${id}: ${error.message}`);
|
|
270
|
+
throw error;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Cancels a payment
|
|
275
|
+
* @param input - The payment cancellation input
|
|
276
|
+
* @returns The cancellation result
|
|
277
|
+
*/
|
|
278
|
+
async cancelPayment(input) {
|
|
279
|
+
console.log("cancelPayment", input);
|
|
280
|
+
const id = input.data?.orderId;
|
|
281
|
+
if (!id) {
|
|
282
|
+
return {};
|
|
283
|
+
}
|
|
284
|
+
try {
|
|
285
|
+
const payment = await this.client_.getOrder(id);
|
|
286
|
+
if (payment.status.code === constants_1.PayPaymentStatus.EXPIRED) {
|
|
287
|
+
this.debug_ &&
|
|
288
|
+
this.logger_.info(`Pay. payment ${id} is already expired, no need to cancel`);
|
|
289
|
+
return {
|
|
290
|
+
data: {
|
|
291
|
+
id,
|
|
292
|
+
},
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
const newPayment = await this.client_.abortOrder(id).catch((error) => {
|
|
296
|
+
this.logger_.warn(`Could not cancel Pay. payment ${id}: ${error.message}`);
|
|
297
|
+
return { data: payment };
|
|
298
|
+
});
|
|
299
|
+
this.debug_ &&
|
|
300
|
+
this.logger_.info(`Pay. payment ${id} cancelled successfully`);
|
|
301
|
+
return {
|
|
302
|
+
data: newPayment,
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
catch (error) {
|
|
306
|
+
this.logger_.error(`Error cancelling payment ${id}: ${error.message}`);
|
|
307
|
+
throw error;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Deletes a payment (equivalent to cancellation as Pay. does not support deletion)
|
|
312
|
+
* @param input - The payment deletion input
|
|
313
|
+
* @returns The deletion result
|
|
314
|
+
*/
|
|
315
|
+
async deletePayment(input) {
|
|
316
|
+
console.log("deletePayment", input);
|
|
317
|
+
return this.cancelPayment(input);
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Gets the status of a payment by mapping Pay. statuses to Medusa statuses
|
|
321
|
+
* @param input - The payment status input
|
|
322
|
+
* @returns The payment status
|
|
323
|
+
*/
|
|
324
|
+
async getPaymentStatus(input) {
|
|
325
|
+
console.log("getPaymentStatus", input);
|
|
326
|
+
const id = input.data?.id;
|
|
327
|
+
try {
|
|
328
|
+
const { status } = await this.client_.getTransaction(id);
|
|
329
|
+
/**
|
|
330
|
+
* Also see Pay. status codes: https://developer.pay.nl/docs/transaction-statuses#after-processing-statuses
|
|
331
|
+
* Pay. payments should always go to authorized, so we can continue creating the order.
|
|
332
|
+
* This is required for Buy-now-pay-later options, where it can take some time before
|
|
333
|
+
* a paid status is reached.
|
|
334
|
+
*/
|
|
335
|
+
const statusMap = {
|
|
336
|
+
[constants_1.PayPaymentStatus.INIT]: utils_1.PaymentSessionStatus.PENDING,
|
|
337
|
+
//[PayPaymentStatus.PENDING_20]: PaymentSessionStatus.REQUIRES_MORE,
|
|
338
|
+
[constants_1.PayPaymentStatus.PENDING_50]: utils_1.PaymentSessionStatus.PENDING,
|
|
339
|
+
[constants_1.PayPaymentStatus.PENDING_90]: utils_1.PaymentSessionStatus.PENDING,
|
|
340
|
+
[constants_1.PayPaymentStatus.PENDING_98]: utils_1.PaymentSessionStatus.PENDING,
|
|
341
|
+
[constants_1.PayPaymentStatus.CANCEL]: utils_1.PaymentSessionStatus.CANCELED,
|
|
342
|
+
[constants_1.PayPaymentStatus.EXPIRED]: utils_1.PaymentSessionStatus.CANCELED,
|
|
343
|
+
[constants_1.PayPaymentStatus.DENIED_64]: utils_1.PaymentSessionStatus.CANCELED,
|
|
344
|
+
[constants_1.PayPaymentStatus.DENIED_63]: utils_1.PaymentSessionStatus.CANCELED,
|
|
345
|
+
[constants_1.PayPaymentStatus.CANCEL_61]: utils_1.PaymentSessionStatus.CANCELED,
|
|
346
|
+
[constants_1.PayPaymentStatus.FAILURE]: utils_1.PaymentSessionStatus.ERROR,
|
|
347
|
+
[constants_1.PayPaymentStatus.PAID_CHECKAMOUNT]: utils_1.PaymentSessionStatus.ERROR,
|
|
348
|
+
[constants_1.PayPaymentStatus.PARTIAL_PAYMENT]: utils_1.PaymentSessionStatus.REQUIRES_MORE,
|
|
349
|
+
[constants_1.PayPaymentStatus.VERIFY]: utils_1.PaymentSessionStatus.PENDING,
|
|
350
|
+
[constants_1.PayPaymentStatus.AUTHORIZE]: utils_1.PaymentSessionStatus.AUTHORIZED,
|
|
351
|
+
[constants_1.PayPaymentStatus.PARTLY_CAPTURED]: utils_1.PaymentSessionStatus.REQUIRES_MORE,
|
|
352
|
+
[constants_1.PayPaymentStatus.PAID]: utils_1.PaymentSessionStatus.CAPTURED,
|
|
353
|
+
[constants_1.PayPaymentStatus.CHARGEBACK]: utils_1.PaymentSessionStatus.CANCELED,
|
|
354
|
+
};
|
|
355
|
+
const mappedStatus = statusMap[status.code];
|
|
356
|
+
this.debug_ &&
|
|
357
|
+
this.logger_.debug(`Pay. payment ${id} status: ${status} (mapped to: ${mappedStatus})`);
|
|
358
|
+
return {
|
|
359
|
+
status: mappedStatus,
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
catch (error) {
|
|
363
|
+
this.logger_.error(`Error retrieving payment status for ${id}: ${error.message}`);
|
|
364
|
+
throw error;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Retrieves payment details
|
|
369
|
+
* @param input - The payment retrieval input
|
|
370
|
+
* @returns The payment details
|
|
371
|
+
*/
|
|
372
|
+
async retrievePayment(input) {
|
|
373
|
+
console.log("retrievePayment", input);
|
|
374
|
+
const id = input.data?.id;
|
|
375
|
+
try {
|
|
376
|
+
let data;
|
|
377
|
+
// Check if the order ID starts with a 2, in that case we will need to use the legacy Pay API.
|
|
378
|
+
if (id.startsWith("2")) {
|
|
379
|
+
data = await this.client_.getTransaction(id);
|
|
380
|
+
}
|
|
381
|
+
else {
|
|
382
|
+
data = await this.client_.getOrder(id);
|
|
383
|
+
}
|
|
384
|
+
return {
|
|
385
|
+
data: data,
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
catch (error) {
|
|
389
|
+
this.logger_.error(`Error retrieving Pay. payment ${id}: ${error.message}`);
|
|
390
|
+
throw error;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* Updates the Pay. order object
|
|
395
|
+
* @param input - The payment update input
|
|
396
|
+
* @returns The updated payment details
|
|
397
|
+
*/
|
|
398
|
+
async updatePayment(input) {
|
|
399
|
+
console.log("updatePayment", input);
|
|
400
|
+
// If the Pay data is passed from the order created hook, only then we update
|
|
401
|
+
// the session data.
|
|
402
|
+
const payload = input.data?.payload;
|
|
403
|
+
if (payload) {
|
|
404
|
+
try {
|
|
405
|
+
const data = await this.client_.createOrder(payload).catch((error) => {
|
|
406
|
+
this.logger_.error(`Pay. payment creation failed: ${error.message}`);
|
|
407
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, error.message);
|
|
408
|
+
});
|
|
409
|
+
this.debug_ &&
|
|
410
|
+
this.logger_.info(`Pay. payment ${data.id} successfully created with amount ${payload.amount.currency} ${payload.amount.value}`);
|
|
411
|
+
return { data: data };
|
|
412
|
+
}
|
|
413
|
+
catch (error) {
|
|
414
|
+
this.logger_.error(`Error initiating Pay. payment: ${error.message}`);
|
|
415
|
+
throw error;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
return { data: {} };
|
|
419
|
+
}
|
|
420
|
+
get keyMap() {
|
|
421
|
+
return {
|
|
422
|
+
[this.options_.atCode]: this.options_.apiToken,
|
|
423
|
+
[this.options_.slCode]: this.options_.slSecret,
|
|
424
|
+
...(this.options_.otherSlCodes ? this.options_.otherSlCodes : {}),
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Processes webhook data from Pay.
|
|
429
|
+
* @param payload - The webhook payload
|
|
430
|
+
* @returns The action and data to be processed
|
|
431
|
+
*/
|
|
432
|
+
async getWebhookActionAndData(payload) {
|
|
433
|
+
const { data, rawData, headers } = payload;
|
|
434
|
+
try {
|
|
435
|
+
let payment = null;
|
|
436
|
+
// For the legacy Pay. webhooks no header signature can be done and only
|
|
437
|
+
// order_id should be used to retrieve the payment.
|
|
438
|
+
if (data.action === "new_ppt") {
|
|
439
|
+
const { data: paymentData } = (await this.retrievePayment({
|
|
440
|
+
data: {
|
|
441
|
+
id: data.order_id,
|
|
442
|
+
},
|
|
443
|
+
}).catch((e) => {
|
|
444
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.NOT_FOUND, e.message);
|
|
445
|
+
}));
|
|
446
|
+
if (!payment) {
|
|
447
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.NOT_FOUND, "Payment not found");
|
|
448
|
+
}
|
|
449
|
+
payment = paymentData;
|
|
450
|
+
}
|
|
451
|
+
else {
|
|
452
|
+
// For new webhooks from Pay., check the signature. If valid, the payload
|
|
453
|
+
// will already contain the payment object, so no additional retrieval
|
|
454
|
+
// of the payment is required.
|
|
455
|
+
const signatureMethod = headers["signature-method"];
|
|
456
|
+
const signatureKeyId = headers["signature-keyid"];
|
|
457
|
+
const signatureAlgorithm = headers["signature-algorithm"] ?? "sha256";
|
|
458
|
+
const signature = headers["signature"];
|
|
459
|
+
const secret = this.keyMap[signatureKeyId];
|
|
460
|
+
if (signatureMethod !== "HMAC") {
|
|
461
|
+
throw new utils_1.MedusaError(utils_1.MedusaErrorTypes.INVALID_DATA, "Invalid signature method");
|
|
462
|
+
}
|
|
463
|
+
if (!secret) {
|
|
464
|
+
throw new utils_1.MedusaError(utils_1.MedusaErrorTypes.INVALID_DATA, `No secret key not found for ${signatureKeyId}`);
|
|
465
|
+
}
|
|
466
|
+
const hmac = crypto_1.default.createHmac(signatureAlgorithm, secret);
|
|
467
|
+
const calculatedSignature = hmac.update(rawData).digest("hex");
|
|
468
|
+
if (calculatedSignature !== signature) {
|
|
469
|
+
throw new utils_1.MedusaError(utils_1.MedusaErrorTypes.INVALID_DATA, "Invalid signature");
|
|
470
|
+
}
|
|
471
|
+
if (this.debug_) {
|
|
472
|
+
try {
|
|
473
|
+
this.logger_.debug(JSON.stringify(data));
|
|
474
|
+
}
|
|
475
|
+
catch (e) { }
|
|
476
|
+
}
|
|
477
|
+
if (data.type === "order") {
|
|
478
|
+
payment = data.object;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
if (!payment) {
|
|
482
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.NOT_FOUND, "Payment not found");
|
|
483
|
+
}
|
|
484
|
+
const baseData = {
|
|
485
|
+
session_id: payment.transferData.session_id,
|
|
486
|
+
amount: payment.amount.value / 100,
|
|
487
|
+
};
|
|
488
|
+
console.log("payment.status.code", payment.status.code);
|
|
489
|
+
console.log("baseData", baseData);
|
|
490
|
+
switch (payment.status.code) {
|
|
491
|
+
case constants_1.PayPaymentStatus.PAID:
|
|
492
|
+
return {
|
|
493
|
+
action: utils_1.PaymentActions.SUCCESSFUL,
|
|
494
|
+
data: baseData,
|
|
495
|
+
};
|
|
496
|
+
case constants_1.PayPaymentStatus.INIT:
|
|
497
|
+
case constants_1.PayPaymentStatus.PENDING_20:
|
|
498
|
+
case constants_1.PayPaymentStatus.PENDING_50:
|
|
499
|
+
case constants_1.PayPaymentStatus.PENDING_90:
|
|
500
|
+
case constants_1.PayPaymentStatus.PENDING_98:
|
|
501
|
+
case constants_1.PayPaymentStatus.VERIFY:
|
|
502
|
+
return {
|
|
503
|
+
action: utils_1.PaymentActions.PENDING,
|
|
504
|
+
data: baseData,
|
|
505
|
+
};
|
|
506
|
+
case constants_1.PayPaymentStatus.CANCEL:
|
|
507
|
+
case constants_1.PayPaymentStatus.EXPIRED:
|
|
508
|
+
case constants_1.PayPaymentStatus.DENIED_64:
|
|
509
|
+
case constants_1.PayPaymentStatus.DENIED_63:
|
|
510
|
+
case constants_1.PayPaymentStatus.CANCEL_61:
|
|
511
|
+
case constants_1.PayPaymentStatus.CHARGEBACK:
|
|
512
|
+
return {
|
|
513
|
+
action: utils_1.PaymentActions.CANCELED,
|
|
514
|
+
data: baseData,
|
|
515
|
+
};
|
|
516
|
+
case constants_1.PayPaymentStatus.FAILURE:
|
|
517
|
+
case constants_1.PayPaymentStatus.PAID_CHECKAMOUNT:
|
|
518
|
+
return {
|
|
519
|
+
action: utils_1.PaymentActions.FAILED,
|
|
520
|
+
data: baseData,
|
|
521
|
+
};
|
|
522
|
+
case constants_1.PayPaymentStatus.PARTIAL_PAYMENT:
|
|
523
|
+
case constants_1.PayPaymentStatus.PARTLY_CAPTURED:
|
|
524
|
+
return {
|
|
525
|
+
action: utils_1.PaymentActions.REQUIRES_MORE,
|
|
526
|
+
data: baseData,
|
|
527
|
+
};
|
|
528
|
+
case constants_1.PayPaymentStatus.AUTHORIZE:
|
|
529
|
+
return {
|
|
530
|
+
action: utils_1.PaymentActions.AUTHORIZED,
|
|
531
|
+
data: baseData,
|
|
532
|
+
};
|
|
533
|
+
default:
|
|
534
|
+
return {
|
|
535
|
+
action: utils_1.PaymentActions.NOT_SUPPORTED,
|
|
536
|
+
data: baseData,
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
catch (error) {
|
|
541
|
+
this.logger_.error(`Error processing webhook for payment ${data.id}: ${error.message}`);
|
|
542
|
+
// Even with errors, try to construct a valid response if we have the payment
|
|
543
|
+
const { data: payment } = await this.retrievePayment({
|
|
544
|
+
data: { id: data.orderId },
|
|
545
|
+
}).catch(() => ({ data: null }));
|
|
546
|
+
if (payment) {
|
|
547
|
+
return {
|
|
548
|
+
action: "failed",
|
|
549
|
+
data: {
|
|
550
|
+
session_id: payment?.metadata?.session_id,
|
|
551
|
+
amount: new BigNumber(payment?.amount),
|
|
552
|
+
...payment,
|
|
553
|
+
},
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
throw error;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
exports.default = PayBase;
|
|
561
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGF5LWJhc2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvcHJvdmlkZXJzL3BheS9jb3JlL3BheS1iYXNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBNkJBLHFEQU1rQztBQVNsQyw2Q0FBc0M7QUFDdEMsb0RBQTJCO0FBQzNCLDJDQUE0QztBQUM1QywyR0FBa0Y7QUFVbEY7O0dBRUc7QUFDSCxNQUFlLE9BQVEsU0FBUSwrQkFBd0M7SUFNckU7Ozs7T0FJRztJQUNILE1BQU0sQ0FBQyxlQUFlLENBQUMsT0FBd0I7UUFDN0MsSUFDRSxDQUFDLE9BQU8sQ0FBQyxNQUFNO1lBQ2YsQ0FBQyxPQUFPLENBQUMsUUFBUTtZQUNqQixDQUFDLE9BQU8sQ0FBQyxNQUFNO1lBQ2YsQ0FBQyxPQUFPLENBQUMsUUFBUTtZQUNqQixDQUFDLE9BQU8sQ0FBQyxTQUFTO1lBQ2xCLENBQUMsT0FBTyxDQUFDLFNBQVMsRUFDbEIsQ0FBQztZQUNELE1BQU0sSUFBSSxtQkFBVyxDQUNuQixtQkFBVyxDQUFDLEtBQUssQ0FBQyxZQUFZLEVBQzlCLHlHQUF5RyxDQUMxRyxDQUFBO1FBQ0gsQ0FBQztJQUNILENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsWUFBWSxTQUFTLEVBQUUsT0FBd0I7UUFDN0MsS0FBSyxDQUFDLFNBQVMsRUFBRSxPQUFPLENBQUMsQ0FBQTtRQWUzQiwwQkFBcUIsR0FBRyxDQUN0QixLQUFrRCxFQUNsRCxFQUFFO1lBQ0YsTUFBTSxRQUFRLEdBQUcsS0FBSyxDQUFDLFFBQVEsRUFBRSxNQUFnQixDQUFBO1lBQ2pELE1BQU0sbUJBQW1CLEdBQUcsSUFBSSxDQUFDLFFBQVEsRUFBRSxrQkFBa0IsQ0FBQTtZQUU3RCxNQUFNLFNBQVMsR0FBRyxLQUFLLENBQUMsVUFBVSxDQUFDLFFBQVEsRUFBRSxDQUFBO1lBQzdDLElBQUksV0FBVyxHQUFHLEtBQUssQ0FBQyxhQUFhLEVBQUUsSUFBSTtnQkFDekMsQ0FB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
|