medusa-plugin-paypal
Version:
Paypal payment provider for Medusa v2
320 lines • 27 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const paypal_server_sdk_1 = require("@paypal/paypal-server-sdk");
const bignumber_js_1 = require("bignumber.js");
const utils_1 = require("@medusajs/framework/utils");
const utils_2 = require("./utils");
class PaypalProviderService extends utils_1.AbstractPaymentProvider {
static validateOptions(options) {
if (!(0, utils_1.isDefined)(options.clientId)) {
throw new Error("Required option `clientId` is missing in PayPal plugin");
}
if (!(0, utils_1.isDefined)(options.clientSecret)) {
throw new Error("Required option `clientSecret` is missing in PayPal plugin");
}
if (!(0, utils_1.isDefined)(options.intent)) {
throw new Error("Required option `intent` is missing in PayPal plugin");
}
if (!(0, utils_1.isDefined)(options.sandbox)) {
throw new Error("Required option `sandbox` is missing in PayPal plugin");
}
if (!(0, utils_1.isDefined)(options.webhookId)) {
throw new Error("Required option `webhookId` is missing in PayPal plugin");
}
}
constructor(container, options) {
// @ts-ignore
super(...arguments);
this.container_ = container;
this.options_ = options;
this.logger_ = this.container_.logger;
this.isIntentCaptured = this.options_.intent === "CAPTURE";
this.paypal_api_ = this.options_.sandbox
? "https://api-m.sandbox.paypal.com"
: "https://api-m.paypal.com";
this.client_ = new paypal_server_sdk_1.Client({
clientCredentialsAuthCredentials: {
oAuthClientId: this.options_.clientId,
oAuthClientSecret: this.options_.clientSecret,
},
timeout: this.options_.timeout || 0,
environment: this.options_.sandbox
? paypal_server_sdk_1.Environment.Sandbox
: paypal_server_sdk_1.Environment.Production,
logging: {
logLevel: this.options_.sandbox ? paypal_server_sdk_1.LogLevel.Debug : paypal_server_sdk_1.LogLevel.Warn,
logRequest: {
logBody: true,
},
logResponse: {
logHeaders: true,
},
},
});
}
async authorizePayment(input) {
try {
const statusData = await this.getPaymentStatus(input);
return statusData;
}
catch (error) {
throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, `Authorize payment failed: ${error.message}`);
}
}
async cancelPayment(paymentData) {
try {
return await this.retrievePayment(paymentData);
}
catch (error) {
throw new Error("An error occurred in cancelPayment");
}
}
async getPaymentStatus(paymentData) {
const retrievedPayment = await this.retrievePayment(paymentData);
const paypalOrder = retrievedPayment.data;
switch (paypalOrder.status) {
case paypal_server_sdk_1.OrderStatus.Created:
return {
status: utils_1.PaymentSessionStatus.PENDING,
data: retrievedPayment.data,
};
// case PaypalOrderStatus.Saved:
// case PaypalOrderStatus.Approved:
case paypal_server_sdk_1.OrderStatus.PayerActionRequired:
return {
status: utils_1.PaymentSessionStatus.REQUIRES_MORE,
data: retrievedPayment.data,
};
case paypal_server_sdk_1.OrderStatus.Voided:
return {
status: utils_1.PaymentSessionStatus.CANCELED,
data: retrievedPayment.data,
};
case "authorized":
return {
status: utils_1.PaymentSessionStatus.AUTHORIZED,
data: retrievedPayment.data,
};
case paypal_server_sdk_1.OrderStatus.Completed:
return {
status: utils_1.PaymentSessionStatus.CAPTURED,
data: retrievedPayment.data,
};
default:
return {
status: utils_1.PaymentSessionStatus.PENDING,
data: retrievedPayment.data,
};
}
}
async capturePayment(paymentData) {
const paypalOrder = paymentData.data;
if (paypalOrder.purchaseUnits?.length &&
paypalOrder.purchaseUnits[0].payments) {
const paymentsController = new paypal_server_sdk_1.PaymentsController(this.client_);
// Intent Captured
if (this.isIntentCaptured &&
paypalOrder.purchaseUnits[0].payments.captures?.length) {
const id = paypalOrder.purchaseUnits[0].payments.captures[0]
.id;
try {
await paymentsController.getCapturedPayment({
captureId: id,
});
return await this.retrievePayment(paymentData);
}
catch (error) {
this.logger_.error(error);
throw new Error("An error occurred in capturePayment");
}
}
else if (paypalOrder.purchaseUnits[0].payments.authorizations?.length) {
const id = paypalOrder.purchaseUnits[0].payments.authorizations[0]
.id;
try {
await paymentsController.captureAuthorizedPayment({
authorizationId: id,
});
return await this.retrievePayment(paymentData);
}
catch (error) {
this.logger_.error(error);
throw new Error("An error occurred in capturePayment");
}
}
else {
throw new Error("An error occurred in capturePayment");
}
}
throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, `An error occurred in capturePayment`);
}
async initiatePayment({ data, amount, currency_code, }) {
const ordersController = new paypal_server_sdk_1.OrdersController(this.client_);
data ? data.amount = amount : data = { amount, currency_code };
data ? data.currency_code = currency_code : data = { amount, currency_code };
try {
const purchaseUnits = (0, utils_2.getPurchaseUnits)(data);
const { result } = await ordersController.createOrder({
body: {
intent: this.isIntentCaptured
? paypal_server_sdk_1.CheckoutPaymentIntent.Capture
: paypal_server_sdk_1.CheckoutPaymentIntent.Authorize,
...purchaseUnits,
},
});
const isPaymentIntent = "id" in result;
return {
id: isPaymentIntent
? result.id
: data?.session_id,
data: {
...result,
},
};
}
catch (error) {
throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, `Initialize payment failed Error:${error.message}`);
}
}
async deletePayment(input) {
return await this.cancelPayment(input);
}
async refundPayment(paymentData) {
const paypalOrder = paymentData.data;
if (paypalOrder.purchaseUnits?.length && paypalOrder.purchaseUnits[0].payments) {
const purchaseUnit = paypalOrder.purchaseUnits[0];
const isAlreadyCaptured = paypalOrder.purchaseUnits.some((pu) => pu.payments?.captures?.length);
if (!isAlreadyCaptured) {
throw new Error("Cannot refund an uncaptured payment");
}
const paymentId = purchaseUnit.payments?.captures[0].id;
const paymentsController = new paypal_server_sdk_1.PaymentsController(this.client_);
try {
await paymentsController.refundCapturedPayment({
captureId: paymentId,
prefer: 'return=minimal'
});
return await this.retrievePayment(paymentData);
}
catch (error) {
this.logger_.error(error);
throw new Error("An error occurred in refundPayment");
}
}
throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, "An error occurred in refundPayment");
}
async retrievePayment(paymentSessionData) {
try {
const ordersController = new paypal_server_sdk_1.OrdersController(this.client_);
const paypalOrderId = paymentSessionData.data.id;
const { result } = await ordersController.getOrder({
id: paypalOrderId,
});
if (result.id) {
return {
data: {
...result,
},
};
}
}
catch (error) {
throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, `An error occurred in retrievePayment Error:${error.message}`);
}
throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, "An error occurred in retrievePayment");
}
async updatePayment(context) {
const ordersController = new paypal_server_sdk_1.OrdersController(this.client_);
try {
const paypalOrderId = context.data.id.id;
await ordersController.patchOrder({
id: paypalOrderId,
body: [
{
op: paypal_server_sdk_1.PatchOp.Replace,
value: {
amount: {
currencyCode: context.currency_code,
value: context.amount.toString(),
},
},
},
],
});
return await this.retrievePayment(context);
}
catch (error) {
throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, `An error occurred in updatePayment Error:${error.message}`);
}
}
async getWebhookActionAndData(webhookData) {
const resource = webhookData?.data.resource;
const verificationResponse = await this.constructWebhookEvent(webhookData.data, webhookData.headers);
if (verificationResponse.verification_status === "SUCCESS") {
switch (webhookData.data.event_type) {
case "CHECKOUT.ORDER.APPROVED":
return {
action: utils_1.PaymentActions.REQUIRES_MORE,
data: {
session_id: resource.custom_id,
amount: new bignumber_js_1.BigNumber(resource.amount.value),
},
};
case "PAYMENT.CAPTURE.REFUNDED":
return {
action: utils_1.PaymentActions.CANCELED,
data: {
session_id: resource.custom_id,
amount: new bignumber_js_1.BigNumber(resource.amount.value),
},
};
case "PAYMENT.CAPTURE.COMPLETED":
return {
action: utils_1.PaymentActions.SUCCESSFUL,
data: {
session_id: resource.custom_id,
amount: new bignumber_js_1.BigNumber(resource.amount.value),
},
};
default:
return { action: utils_1.PaymentActions.NOT_SUPPORTED };
}
}
else {
this.logger_.warn(`⚠️ Webhook verification failed`);
return { action: utils_1.PaymentActions.NOT_SUPPORTED };
}
}
async constructWebhookEvent(data, headers) {
const credentials = btoa(`${this.options_.clientId}:${this.options_.clientSecret}`);
const res_token = await fetch(`${this.paypal_api_}/v1/oauth2/token`, {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
Authorization: `Basic ${credentials}`,
},
body: "grant_type=client_credentials",
});
const token = await res_token.json();
const res = await fetch(`${this.paypal_api_}/v1/notifications/verify-webhook-signature`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token.access_token}`,
},
body: JSON.stringify({
auth_algo: headers["paypal-auth-algo"],
cert_url: headers["paypal-cert-url"],
transmission_id: headers["paypal-transmission-id"],
transmission_sig: headers["paypal-transmission-sig"],
transmission_time: headers["paypal-transmission-time"],
webhook_id: this.options_.webhookId,
webhook_event: data,
}),
});
return await res.json();
}
}
PaypalProviderService.identifier = "paypal";
exports.default = PaypalProviderService;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9wcm92aWRlcnMvcGF5bWVudC1wYXlwYWwvc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLGlFQVVtQztBQXdCbkMsK0NBQXlDO0FBRXpDLHFEQU9tQztBQUduQyxtQ0FBMkM7QUFNM0MsTUFBTSxxQkFBc0IsU0FBUSwrQkFBc0M7SUFVeEUsTUFBTSxDQUFDLGVBQWUsQ0FBQyxPQUFzQjtRQUMzQyxJQUFJLENBQUMsSUFBQSxpQkFBUyxFQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO1lBQ2pDLE1BQU0sSUFBSSxLQUFLLENBQUMsd0RBQXdELENBQUMsQ0FBQztRQUM1RSxDQUFDO1FBQ0QsSUFBSSxDQUFDLElBQUEsaUJBQVMsRUFBQyxPQUFPLENBQUMsWUFBWSxDQUFDLEVBQUUsQ0FBQztZQUNyQyxNQUFNLElBQUksS0FBSyxDQUNiLDREQUE0RCxDQUM3RCxDQUFDO1FBQ0osQ0FBQztRQUNELElBQUksQ0FBQyxJQUFBLGlCQUFTLEVBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUM7WUFDL0IsTUFBTSxJQUFJLEtBQUssQ0FBQyxzREFBc0QsQ0FBQyxDQUFDO1FBQzFFLENBQUM7UUFDRCxJQUFJLENBQUMsSUFBQSxpQkFBUyxFQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDO1lBQ2hDLE1BQU0sSUFBSSxLQUFLLENBQUMsdURBQXVELENBQUMsQ0FBQztRQUMzRSxDQUFDO1FBQ0QsSUFBSSxDQUFDLElBQUEsaUJBQVMsRUFBQyxPQUFPLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQztZQUNsQyxNQUFNLElBQUksS0FBSyxDQUNiLHlEQUF5RCxDQUMxRCxDQUFDO1FBQ0osQ0FBQztJQUNILENBQUM7SUFFRCxZQUFtQixTQUErQixFQUFFLE9BQXNCO1FBQ3hFLGFBQWE7UUFDYixLQUFLLENBQUMsR0FB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