@alphabite/medusa-paypal
Version:
Alphabite's Medusa Paypal Plugin
483 lines • 36.5 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("@medusajs/framework/utils");
const paypal_server_sdk_1 = require("@paypal/paypal-server-sdk");
const paypal_core_1 = require("./paypal-core");
class PaypalModuleService extends utils_1.AbstractPaymentProvider {
static validateOptions(options) {
if (!options.clientId) {
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "PayPal client ID is required in the provider's options.");
}
if (!options.clientSecret) {
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "PayPal client secret is required in the provider's options.");
}
}
constructor(container, options) {
super(container, options);
this.logger_ = container.logger;
this.options_ = options;
this.baseUrl = this.options_.isSandbox
? "https://api-m.sandbox.paypal.com"
: "https://api-m.paypal.com";
this.paymentModuleService_ = container.paymentModuleService;
this.client = new paypal_core_1.PaypalService({
clientId: this.options_.clientId,
clientSecret: this.options_.clientSecret,
isSandbox: this.options_.isSandbox,
paypalWebhookId: this.options_.webhookId,
});
}
async capturePayment(input) {
// console.log(">>>>> STEP 7 - CAPTURING PAYMENT INIT");
try {
if (!input.data) {
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Payment data is required");
}
if (!input.data.id) {
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "PayPal order ID is required to capture payment");
}
if (input.data.status === utils_1.PaymentSessionStatus.CAPTURED ||
input.data.status === "COMPLETED") {
return {
data: {
...input.data,
status: utils_1.PaymentSessionStatus.CAPTURED,
captured_at: new Date().toISOString(),
},
};
}
// console.log(
// ">>>>>> STEP 8 - CAPTURE ORDER, IS AUTHORIZED, ATTEMPTING TO CAPTURE"
// );
const id = input.data.id;
await this.client.captureOrder(id);
return {
data: {
...input.data,
status: utils_1.PaymentSessionStatus.CAPTURED,
captured_at: new Date().toISOString(),
},
};
}
catch (error) {
this.logger_.error("PayPal capture payment error:", error);
throw error;
}
}
async authorizePayment(input) {
console.log(">>>>>>>Authorize payment<<<<<");
if (!input.data) {
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Payment data is required");
}
let paypalData = input.data;
const amount = input.data.amount;
const currencyCode = input.data.currency_code;
const orderId = paypalData?.id;
if (!orderId) {
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "PayPal order ID is required to capture payment");
}
// console.log(">>>>> STEP 2 - CHECK IF ALREADY AUTHORIZED");
// console.log(">>>>>> STEP 2.1 INPUT DATA", {
// amount,
// currencyCode,
// orderId,
// });
const alreadyAuthorized = paypalData?.purchaseUnits?.[0].payments?.captures?.[0]?.status ===
paypal_server_sdk_1.CaptureStatus.Completed;
if (!alreadyAuthorized) {
// console.log(
// ">>>>> STEP 3 - CAPTURE ORDER, IS AUTHORIZED, ATTEMPTING TO CAPTURE ",
// alreadyAuthorized
// );
let captureResponse;
try {
captureResponse = await this.client.captureOrder(orderId);
}
catch (err) {
// console.log(
// ">>>>>> STEP 3.1 - CAPTURE ORDER FAILED",
// JSON.stringify(err, null, 2)
// );
const body = JSON.parse(err?.body || "{}");
// console.log(
// ">>>>>> STEP 3.2 - CAPTURE ORDER FAILED BODY",
// JSON.stringify(err?.body || {}, null, 2)
// );
const captureData = body?.purchase_units?.[0]?.payments?.captures?.[0];
const newOrder = await this.client.createOrder({
amount: Number(amount),
currency: currencyCode,
sessionId: input.context?.idempotency_key,
});
if (!captureData) {
const error = {
code: "404",
message: "Payment declined. Please try again or use a different card.",
retryable: true,
};
return {
status: utils_1.PaymentSessionStatus.PENDING,
data: {
...input.data,
...newOrder,
error,
},
};
}
const paymentStatus = captureData?.status || paypal_server_sdk_1.CaptureStatus.Declined;
const processorResponse = captureData?.processorResponse;
const { status, error = undefined } = this.checkPaymentStatus(paymentStatus, processorResponse);
return {
status: utils_1.PaymentSessionStatus.PENDING,
data: {
...input.data,
...newOrder,
error,
},
};
}
paypalData = captureResponse;
const captureData = captureResponse.purchaseUnits?.[0].payments?.captures?.[0];
const paymentStatus = captureData?.status || paypal_server_sdk_1.CaptureStatus.Declined;
const processorResponse = captureData?.processorResponse;
const { status, error = undefined } = this.checkPaymentStatus(paymentStatus, processorResponse);
// console.log(">>>>> STEP 4 - CHECK PAYMENT STATUS", status, error);
if (status === paypal_server_sdk_1.CaptureStatus.Declined) {
// console.log(">>>>> STEP 4.1 - PAYMENT DECLINED");
const newOrder = await this.client.createOrder({
amount: Number(captureData?.amount?.value),
currency: captureData?.amount?.currencyCode,
sessionId: input.context?.idempotency_key,
});
// console.log(">>>>> STEP 4.2 - NEW ORDER CREATED", newOrder);
console.log(">>>>> STEP 4.3 - RETURNING DECLINED PAYMENT DATA", JSON.stringify({
status: utils_1.PaymentSessionStatus.PENDING,
data: {
...input.data,
...newOrder,
error,
},
}, null, 2));
return {
status: utils_1.PaymentSessionStatus.PENDING,
data: {
...input.data,
...newOrder,
error,
},
};
}
}
// console.log(">>>>> STEP 5 - RETURN AUTHORIZED PAYMENT DATA");
return {
data: {
...paypalData,
},
status: utils_1.PaymentSessionStatus.AUTHORIZED,
};
}
async cancelPayment(input) {
console.log("??????????>>>>>Cancel payment<<<<<", input);
try {
if (!input.data) {
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Payment data is required");
}
const orderId = input.data["id"];
if (!orderId) {
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Cancel payment failed! PayPal order ID and capture ID is required to cancel payment");
}
return {
data: {
order_id: orderId,
status: utils_1.PaymentSessionStatus.CANCELED,
cancelled_at: new Date().toISOString(),
},
};
}
catch (error) {
this.logger_.error("PayPal cancel payment error:", error);
throw error;
}
}
async initiatePayment(input) {
// console.log(">>>>>>>Initiate payment<<<<<");
try {
const { amount, currency_code, context, data } = input;
const order = await this.client.createOrder({
amount: Number(amount),
currency: currency_code,
sessionId: context?.idempotency_key,
});
return {
data: { ...data, ...order, amount, currency_code },
id: order.id,
};
}
catch (error) {
this.logger_.error("PayPal initiate payment error:", error);
throw error;
}
}
async refundPayment(input) {
// console.log(">>>>>>>Refund payment<<<<<");
try {
if (!input.data) {
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Payment data is required");
}
const orderId = input.data["id"];
//@ts-ignore
const captureIds = input.data.purchaseUnits.flatMap((item) => item.payments.captures.map((capture) => capture.id));
if (!orderId || !captureIds) {
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Refund payment failed! PayPal order ID and capture ID is required to cancel payment");
}
await this.client.cancelPayment(captureIds);
return {
data: {
order_id: orderId,
status: utils_1.PaymentSessionStatus.CANCELED,
cancelled_at: new Date().toISOString(),
},
};
}
catch (error) {
this.logger_.error("PayPal cancel payment error:", error);
throw error;
}
}
async deletePayment(input) {
// console.log(">>>>>>>Delete payment<<<<<");
// console.log("Delete payment input", input);
try {
if (!input.data) {
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Payment data is required");
}
const orderId = input.data["id"];
// //@ts-ignore
// const captureIds = input.data.captureData.purchaseUnits.flatMap((item) =>
// item.payments.captures.map((capture) => capture.id)
// );
// if (!orderId || !captureIds)
if (!orderId) {
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Delete payment failed! PayPal order ID and capture ID is required to cancel payment");
}
// await this.client.cancelPayment(captureIds);
return {
data: {
order_id: orderId,
status: utils_1.PaymentSessionStatus.CANCELED,
cancelled_at: new Date().toISOString(),
},
};
}
catch (error) {
this.logger_.error("PayPal cancel payment error:", error);
throw error;
}
}
async getPaymentStatus(input) {
// console.log(">>>>>>>Get payment status<<<<<");
try {
if (!input.data) {
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Payment data is required");
}
const order_id = input.data["id"];
if (!order_id) {
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "PayPal order ID is required to cancel payment");
}
const order = await this.client.getOrderDetails(order_id);
if (!order || !order.status) {
throw new utils_1.MedusaError(utils_1.MedusaError.Types.NOT_FOUND, `PayPal order with ID ${order_id} not found`);
}
return {
status: order.status === "COMPLETED"
? utils_1.PaymentSessionStatus.CAPTURED
: utils_1.PaymentSessionStatus.AUTHORIZED,
};
}
catch (error) {
this.logger_.error("PayPal get payment status error:", error);
throw error;
}
}
async retrievePayment(input) {
// console.log(">>>>>>>Retrieve payment <<<<<");
try {
const id = input["id"];
const res = await this.client.getOrderDetails(id);
return {
data: { response: res },
};
}
catch (error) {
this.logger_.error("PayPal retrieve payment error:", error);
throw error;
}
}
async updatePayment(input) {
// console.log(">>>>>>>Update payment<<<<<");
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Not implemented");
// try {
// if (!input.data) {
// throw new MedusaError(
// MedusaError.Types.INVALID_DATA,
// "Payment data is required"
// );
// }
// const order_id = input.data["order_id"] as string;
// if (!order_id) {
// throw new MedusaError(
// MedusaError.Types.INVALID_DATA,
// "PayPal order ID is required to cancel payment"
// );
// }
// const accessToken = await this.getAccessToken();
// const response = await fetch(``, {
// method: "PATCH",
// headers: {
// "Content-Type": "application/json",
// Authorization: `Bearer ${accessToken}`,
// },
// body: JSON.stringify([
// {
// op: "replace",
// value: {
// address_line_1: "2211 N First Street",
// address_line_2: "Building 17",
// admin_area_2: "San Jose",
// admin_area_1: "CA",
// postal_code: "95131",
// country_code: "US",
// },
// },
// ]),
// });
// if (!response.ok) {
// const errorData = await response.json();
// throw new MedusaError(
// MedusaError.Types.PAYMENT_AUTHORIZATION_ERROR,
// `PayPal update failed: ${errorData.message}`
// );
// }
// const data = await response.json();
// return {
// data: { success: true, message: "payment updated", ...data },
// };
// } catch (error) {
// this.logger_.error("PayPal update payment error:", error);
// throw error;
// }
}
async getWebhookActionAndData(payload) {
try {
const { data, headers } = payload;
await this.client.verifyWebhook({ headers, body: data });
switch (data.event_type) {
case "PAYMENT.CAPTURE.COMPLETED":
// console.log(">>>>> STEP 6 PAYMENT.CAPTURE.COMPLETED<<<<<");
return {
action: "captured",
data: {
session_id: data.resource.custom_id,
amount: Number(data.resource.amount.value),
},
};
default:
return {
action: "not_supported",
};
}
}
catch (e) {
return {
action: "failed",
data: {
session_id: payload.data.resource.custom_id,
amount: Number(payload.data.resource.amount.value),
},
};
}
}
checkPaymentStatus(status, processorResponse) {
const processorResponseMap = {
"0500": {
code: "0500 - DO_NOT_HONOR",
message: "Card refused by issuer. Please try again or use a different card.",
retryable: false,
},
"9500": {
code: "9500 - SUSPECTED_FRAUD",
message: "Suspected fraudulent card. Please try again and use a different card.",
retryable: false,
},
"5400": {
code: "5400 - EXPIRED_CARD",
message: "Card has expired. Please try again and use a different card.",
retryable: false,
},
"5120": {
code: "5120 - INSUFFICIENT_FUNDS",
message: "Insufficient funds. Please try again or use a different card.",
retryable: true,
},
"00N7": {
code: "00N7 - CVV_FAILURE",
message: "Incorrect security code. Please try again or use a different card.",
retryable: true,
},
"1330": {
code: "1330 - INVALID_ACCOUNT",
message: "Card not valid. Please try again or use a different card.",
retryable: true,
},
"5100": {
code: "5100 - GENERIC_DECLINE",
message: "Card is declined. Please try again or use a different card.",
retryable: true,
},
};
// Check the payment status first
switch (status) {
case "COMPLETED":
return { status };
case "DECLINED":
// If we have processor response details, use them
console.log("Processor response details:", processorResponse);
if (processorResponse?.responseCode) {
const errorDetails = processorResponseMap[processorResponse.responseCode] || {
code: processorResponse.responseCode,
message: "Payment declined. Please try again or use a different card.",
retryable: false,
};
return {
status,
error: {
...errorDetails,
avsCode: processorResponse.avsCode,
cvvCode: processorResponse.cvvCode,
},
};
}
// Generic decline if no processor response
return {
status,
error: {
code: "DECLINED",
message: "Payment declined. Please try again or use a different card.",
retryable: false,
},
};
default:
return {
status,
error: {
code: "UNKNOWN_STATUS",
message: `Unknown payment status: ${status}. Please try again or use a different card.`,
retryable: false,
},
};
}
}
}
PaypalModuleService.identifier = "paypal";
exports.default = PaypalModuleService;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9wcm92aWRlcnMvcGF5cGFsL3NlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSxxREFJbUM7QUFxQm5DLGlFQUFpRTtBQUVqRSwrQ0FBOEM7QUFzQjlDLE1BQXFCLG1CQUFvQixTQUFRLCtCQUFnQztJQVEvRSxNQUFNLENBQUMsZUFBZSxDQUFDLE9BQTRCO1FBQ2pELElBQUksQ0FBQyxPQUFPLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDdEIsTUFBTSxJQUFJLG1CQUFXLENBQ25CLG1CQUFXLENBQUMsS0FBSyxDQUFDLFlBQVksRUFDOUIseURBQXlELENBQzFELENBQUM7UUFDSixDQUFDO1FBRUQsSUFBSSxDQUFDLE9BQU8sQ0FBQyxZQUFZLEVBQUUsQ0FBQztZQUMxQixNQUFNLElBQUksbUJBQVcsQ0FDbkIsbUJBQVcsQ0FBQyxLQUFLLENBQUMsWUFBWSxFQUM5Qiw2REFBNkQsQ0FDOUQsQ0FBQztRQUNKLENBQUM7SUFDSCxDQUFDO0lBRUQsWUFBWSxTQUErQixFQUFFLE9BQWdCO1FBQzNELEtBQUssQ0FBQyxTQUFTLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFFMUIsSUFBSSxDQUFDLE9BQU8sR0FBRyxTQUFTLENBQUMsTUFBTSxDQUFDO1FBQ2hDLElBQUksQ0FBQyxRQUFRLEdBQUcsT0FBTyxDQUFDO1FBQ3hCLElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxTQUFTO1lBQ3BDLENBQUMsQ0FBQyxrQ0FBa0M7WUFDcEMsQ0FBQyxDQUFDLDBCQUEwQixDQUFDO1FBQy9CLElBQUksQ0FBQyxxQkFBcUIsR0FBRyxTQUFTLENBQUMsb0JBQW9CLENBQUM7UUFDNUQsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLDJCQUFhLENBQUM7WUFDOUIsUUFBUSxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsUUFBUTtZQUNoQyxZQUFZ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