UNPKG

medusa-plugin-paypal

Version:
320 lines 27 kB
"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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