UNPKG

@alphabite/medusa-paypal

Version:

Alphabite's Medusa Paypal Plugin

195 lines 16.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.PaypalService = void 0; const paypal_server_sdk_1 = require("@paypal/paypal-server-sdk"); const libphonenumber_js_1 = require("libphonenumber-js"); const utils_1 = require("@medusajs/framework/utils"); class PaypalService { constructor({ clientId, clientSecret, isSandbox, webhookId, includeCustomerData, includeShippingData, }) { this.verifyWebhook = async ({ headers, body, }) => { if (!this.webhookId) { throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Webhook ID is not set"); } const accessToken = await this.getAccessToken(); const verifyWebhookRes = await fetch(`${this.baseUrl}/v1/notifications/verify-webhook-signature`, { method: "POST", headers: { Authorization: `Bearer ${accessToken}`, "Content-Type": "application/json", }, 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.webhookId, webhook_event: body, }), }); if (!verifyWebhookRes.ok) { throw new Error(`Failed to verify webhook signature: ${verifyWebhookRes.statusText}`); } const verifyWebhookData = await verifyWebhookRes.json(); if (verifyWebhookData.verification_status !== "SUCCESS") { throw new Error("Failed to verify webhook signature"); } return { status: verifyWebhookData.verification_status, body }; }; const environment = isSandbox ? paypal_server_sdk_1.Environment.Sandbox : paypal_server_sdk_1.Environment.Production; this.client = new paypal_server_sdk_1.Client({ clientCredentialsAuthCredentials: { oAuthClientId: clientId, oAuthClientSecret: clientSecret, }, timeout: 0, environment, logging: { logLevel: paypal_server_sdk_1.LogLevel.Info, logRequest: { logBody: true, }, logResponse: { logHeaders: true, }, }, }); this.baseUrl = isSandbox ? "https://api-m.sandbox.paypal.com" : "https://api-m.paypal.com"; this.clientId = clientId; this.clientSecret = clientSecret; this.webhookId = webhookId; this.ordersController = new paypal_server_sdk_1.OrdersController(this.client); this.paymentsController = new paypal_server_sdk_1.PaymentsController(this.client); this.authController = new paypal_server_sdk_1.OAuthAuthorizationController(this.client); this.includeCustomerData = !!includeCustomerData; this.includeShippingData = !!includeShippingData; } async getAccessToken() { try { const authorization = Buffer.from(`${this.clientId}:${this.clientSecret}`).toString("base64"); const authRes = await this.authController.requestToken({ authorization: `Basic ${authorization}`, }); const accessToken = authRes.result.accessToken; if (!accessToken) throw new Error("Failed to get access token"); return accessToken; } catch (error) { throw new Error("Failed to get access token: " + error.message); } } async createOrder({ amount, currency, sessionId, shipping_info, items, email, }) { const ordersController = new paypal_server_sdk_1.OrdersController(this.client); const paypalItems = items?.map((item) => ({ name: item.title, quantity: item.quantity.toString(), unitAmount: { currencyCode: currency, value: item.unit_price.toString(), }, })) || []; const hasItems = paypalItems.length > 0; const shippingData = !!shipping_info && { ...(this.includeCustomerData && this.mapCustomerData({ email, shipping_info })), ...(this.includeShippingData && this.mapShippingData(shipping_info)), type: paypal_server_sdk_1.FulfillmentType.Shipping, }; const createdOrder = await ordersController.createOrder({ body: { intent: paypal_server_sdk_1.CheckoutPaymentIntent.Capture, purchaseUnits: [ { amount: { currencyCode: currency, value: amount.toString(), ...(hasItems && { breakdown: { itemTotal: { currencyCode: currency, value: amount.toString(), }, }, }), }, customId: sessionId, ...(hasItems && { items: paypalItems }), ...(shippingData && { shipping: shippingData }), }, ], applicationContext: { ...(this.includeShippingData && shippingData && { shippingPreference: paypal_server_sdk_1.OrderApplicationContextShippingPreference.SetProvidedAddress, }), userAction: paypal_server_sdk_1.OrderApplicationContextUserAction.PayNow, }, }, }); if (!createdOrder?.result?.id) throw new Error("Failed to create order"); return createdOrder.result; } async captureOrder(id) { const capturedOrder = await this.ordersController.captureOrder({ id, }); return capturedOrder.result; } async retrieveOrder(id) { const orderDetails = await this.ordersController.getOrder({ id, }); return orderDetails.result; } async authorizeOrder(id) { const authorizedOrder = await this.ordersController.authorizeOrder({ id, }); return authorizedOrder.result; } async refundPayment(captureIds) { const refunds = []; for (const captureId of captureIds) { const refund = await this.paymentsController.refundCapturedPayment({ captureId, }); refunds.push(refund.result); } return refunds; } mapCustomerData({ email, shipping_info, }) { if (!this.includeCustomerData || !shipping_info) { return undefined; } const parsedPhoneNumber = !!shipping_info?.phone && (0, libphonenumber_js_1.parsePhoneNumberFromString)(shipping_info.phone); return { name: { fullName: `${shipping_info.first_name} ${shipping_info.last_name}`, }, ...(email && { emailAddress: email }), ...(parsedPhoneNumber && { phoneNumber: { countryCode: parsedPhoneNumber.countryCallingCode, nationalNumber: parsedPhoneNumber.nationalNumber, }, }), }; } mapShippingData(shipping_info) { if (!this.includeShippingData || !shipping_info || !shipping_info.country_code) { return undefined; } return { address: { countryCode: shipping_info.country_code, postalCode: shipping_info.postal_code, adminArea1: shipping_info.province, adminArea2: shipping_info.city, addressLine1: shipping_info.address_1, }, }; } } exports.PaypalService = PaypalService; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGF5cGFsLWNvcmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvcHJvdmlkZXJzL3BheXBhbC9wYXlwYWwtY29yZS9wYXlwYWwtY29yZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSxpRUFnQm1DO0FBRW5DLHlEQUErRDtBQUUvRCxxREFBd0Q7QUFXeEQsTUFBYSxhQUFhO0lBWXhCLFlBQVksRUFDVixRQUFRLEVBQ1IsWUFBWSxFQUNaLFNBQVMsRUFDVCxTQUFTLEVBQ1QsbUJBQW1CLEVBQ25CLG1CQUFtQixHQUNVO1FBNEp4QixrQkFBYSxHQUFHLEtBQUssRUFBRSxFQUM1QixPQUFPLEVBQ1AsSUFBSSxHQUlMLEVBQTRELEVBQUU7WUFDN0QsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztnQkFDcEIsTUFBTSxJQUFJLG1CQUFXLENBQUMsbUJBQVcsQ0FBQyxLQUFLLENBQUMsWUFBWSxFQUFFLHVCQUF1QixDQUFDLENBQUM7WUFDakYsQ0FBQztZQUVELE1BQU0sV0FBVyxHQUFHLE1BQU0sSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO1lBRWhELE1BQU0sZ0JBQWdCLEdBQUcsTUFBTSxLQUFLLENBQUMsR0FBRyxJQUFJLENBQUMsT0FBTyw0Q0FBNEMsRUFBRTtnQkFDaEcsTUFBTSxFQUFFLE1BQU07Z0JBQ2QsT0FBTyxFQUFFO29CQUNQLGFBQWEsRUFBRSxVQUFVLFdBQVcsRUFBRTtvQkFDdEMsY0FBYyxFQUFFLGtCQUFrQjtpQkFDbkM7Z0JBQ0QsSUFBSSxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUM7b0JBQ25CLFNBQVMsRUFBRSxPQUFPLENBQUMsa0JBQWtCLENBQUM7b0JBQ3RDLFFBQVEsRUFBRSxPQUFPLENBQUMsaUJBQWlCLENBQUM7b0JBQ3BDLGVBQWUsRUFBRSxPQUFPLENBQUMsd0JBQXdCLENBQUM7b0JBQ2xELGdCQUFnQixFQUFFLE9BQU8sQ0FBQyx5QkFBeUIsQ0FB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