UNPKG

@alphabite/medusa-paypal

Version:

Alphabite's Medusa Paypal Plugin

390 lines 32.2 kB
"use strict"; 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"); const zod_1 = require("zod"); const optionsSchema = zod_1.z.object({ clientId: zod_1.z.string().min(1, "PayPal client ID is required"), clientSecret: zod_1.z.string().min(1, "PayPal client secret is required"), isSandbox: zod_1.z.boolean().default(false), webhookId: zod_1.z.string().optional(), includeShippingData: zod_1.z.boolean().default(false), includeCustomerData: zod_1.z.boolean().default(false), }); class PaypalModuleService extends utils_1.AbstractPaymentProvider { constructor(container, options) { super(container, options); this.options = options; this.logger = container.logger; this.paymentModuleService = container.paymentModuleService; this.client = new paypal_core_1.PaypalService(this.options); } static validateOptions(options) { const result = optionsSchema.safeParse(options); if (!result.success) { throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, `Invalid PayPal plugin options: ${result.error.message}`); } } async capturePayment(input) { 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(), }, }; } 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 new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Failed to capture PayPal payment"); } } async authorizePayment(input) { if (!input.data) { throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Payment data is required"); } const data = input.data; let paypalData = input.data; const amount = input.data.amount; const currencyCode = input.data.currency_code; const orderId = paypalData?.id; if (!orderId || !amount || !currencyCode) { throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "PayPal order ID, Amount or Currency is missing, can not capture order."); } const isAuthorized = paypalData?.purchaseUnits?.[0].payments?.captures?.[0]?.status === paypal_server_sdk_1.CaptureStatus.Completed; if (!isAuthorized) { try { paypalData = await this.client.captureOrder(orderId); } catch (err) { const body = JSON.parse(err?.body || "{}"); 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, items: data?.items, shipping_info: data?.shipping_info, email: data?.email, }); 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 { error = undefined } = this.checkPaymentStatus(paymentStatus, processorResponse); return { status: utils_1.PaymentSessionStatus.PENDING, data: { ...input.data, ...newOrder, error, }, }; } const captureData = paypalData.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); if (status === paypal_server_sdk_1.CaptureStatus.Declined) { const newOrder = await this.client.createOrder({ amount: Number(captureData?.amount?.value), currency: captureData?.amount?.currencyCode, sessionId: input.context?.idempotency_key, items: data?.items, shipping_info: data?.shipping_info, email: data?.email, }); return { status: utils_1.PaymentSessionStatus.PENDING, data: { ...input.data, ...newOrder, error, }, }; } } return { data: { ...paypalData, }, status: utils_1.PaymentSessionStatus.AUTHORIZED, }; } async cancelPayment(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 new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Failed to cancel PayPal payment"); } } async initiatePayment(input) { try { if (!input.data) { throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Payment data is required"); } const { amount, currency_code, context, data } = input; if (!amount || !currency_code) { throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Amount and currency code are required"); } const order = await this.client.createOrder({ amount: Number(amount), currency: currency_code, sessionId: context?.idempotency_key, items: data?.items, shipping_info: data?.shipping_info, email: data?.email, }); return { data: { ...data, ...order, ...context, amount, currency_code }, id: order.id, }; } catch (error) { this.logger.error("PayPal initiate payment error:", error); throw error; } } async refundPayment(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"]; const purchaseUnits = input?.data?.["purchaseUnits"] || []; const captureIds = purchaseUnits ?.flatMap((item) => item?.payments?.captures?.map((capture) => capture.id)) .filter((id) => id !== undefined); 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.refundPayment(captureIds); return { data: { order_id: orderId, status: utils_1.PaymentSessionStatus.CANCELED, cancelled_at: new Date().toISOString(), }, }; } catch (error) { this.logger.error("PayPal refund payment error:", error); throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Failed to refund PayPal payment"); } } async deletePayment(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, "Delete 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 getPaymentStatus(input) { 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.retrieveOrder(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) { try { const id = input["id"]; const res = await this.client.retrieveOrder(id); return { data: { response: res }, }; } catch (error) { this.logger.error("PayPal retrieve payment error:", error); throw error; } } async updatePayment(input) { throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Not implemented"); } async getWebhookActionAndData(payload) { try { const { data, headers } = payload; await this.client.verifyWebhook({ headers, body: data }); switch (data.event_type) { case "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, }, }; switch (status) { case "COMPLETED": return { status }; case "DECLINED": 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, }, }; } 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9wcm92aWRlcnMvcGF5cGFsL3NlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSxxREFBdUc7QUFxQnZHLGlFQUFpRTtBQUVqRSwrQ0FBc0U7QUFDdEUsNkJBQXdCO0FBVXhCLE1BQU0sYUFBYSxHQUFHLE9BQUMsQ0FBQyxNQUFNLENBQUM7SUFDN0IsUUFBUSxFQUFFLE9BQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLDhCQUE4QixDQUFDO0lBQzNELFlBQVksRUFBRSxPQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxrQ0FBa0MsQ0FBQztJQUNuRSxTQUFTLEVBQUUsT0FBQyxDQUFDLE9BQU8sRUFBRSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUM7SUFDckMsU0FBUyxFQUFFLE9BQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLEVBQUU7SUFDaEMsbUJBQW1CLEVBQUUsT0FBQyxDQUFDLE9BQU8sRUFBRSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUM7SUFDL0MsbUJBQW1CLEVBQUUsT0FBQyxDQUFDLE9BQU8sRUFBRSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUM7Q0FDaEQsQ0FBQyxDQUFDO0FBZUgsTUFBcUIsbUJBQW9CLFNBQVEsK0JBQXFEO0lBT3BHLFlBQVksU0FBK0IsRUFBbUIsT0FBcUM7UUFDakcsS0FBSyxDQUFDLFNBQVMsRUFBRSxPQUFPLENBQUMsQ0FBQztRQURrQyxZQUFPLEdBQVAsT0FBTyxDQUE4QjtRQUdqRyxJQUFJLENBQUMsTUFBTSxHQUFHLFNBQVMsQ0FBQyxNQUFNLENBQUM7UUFDL0IsSUFBSSxDQUFDLG9CQUFvQixHQUFHLFNBQVMsQ0FBQyxvQkFBb0IsQ0FBQztRQUUzRCxJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksMkJBQWEsQ0FBQyxJQUFJLENB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