UNPKG

@gmisoftware/przelewy24-payments-medusa

Version:

Przelewy24 (P24) payment integration plugin for Medusa e-commerce with BLIK, cards, and general P24 support.

491 lines 44.7 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const crypto_1 = __importDefault(require("crypto")); const utils_1 = require("@medusajs/framework/utils"); const p24_api_1 = require("../services/p24-api"); const p24_transaction_status_1 = require("./p24-transaction-status"); const p24_webhook_1 = require("./p24-webhook"); const get_smallest_unit_1 = require("../../../utils/get-smallest-unit"); const coerce_sandbox_1 = require("../../../utils/coerce-sandbox"); const p24_session_data_1 = require("../../../utils/p24-session-data"); const p24_payment_methods_1 = require("../../../utils/p24-payment-methods"); const p24_logger_1 = require("../../../utils/p24-logger"); const p24_errors_1 = require("../../../utils/p24-errors"); const payment_job_errors_1 = require("../../../utils/payment-job-errors"); class P24Base extends utils_1.AbstractPaymentProvider { options_; p24Api; container_; logger_; static validateOptions(options) { if (!(0, utils_1.isDefined)(options.merchant_id)) { throw new Error("Required option `merchant_id` is missing in P24 plugin"); } if (!(0, utils_1.isDefined)(options.pos_id)) { throw new Error("Required option `pos_id` is missing in P24 plugin"); } if (!(0, utils_1.isDefined)(options.api_key)) { throw new Error("Required option `api_key` is missing in P24 plugin"); } if (!(0, utils_1.isDefined)(options.crc)) { throw new Error("Required option `crc` is missing in P24 plugin"); } if (!(0, utils_1.isDefined)(options.frontend_url)) { throw new Error("Required option `frontend_url` is missing in P24 plugin"); } if (!(0, utils_1.isDefined)(options.backend_url)) { throw new Error("Required option `backend_url` is missing in P24 plugin"); } } constructor(cradle, options) { super(cradle, { ...options, sandbox: (0, coerce_sandbox_1.coerceSandbox)(options.sandbox), }); this.container_ = cradle; this.options_ = { ...options, sandbox: (0, coerce_sandbox_1.coerceSandbox)(options.sandbox), debug: Boolean(options.debug), }; this.p24Api = new p24_api_1.P24ApiService(this.options_); this.logger_ = (0, p24_logger_1.createP24Logger)(cradle.logger, Boolean(this.options_.debug)); } get options() { return this.options_; } normalizePaymentCreateParams() { const options = this.paymentIntentOptions; const params = { description: options.description ?? "Payment via Przelewy24", }; if (options.channel != null && options.channel > 0) { params.channel = options.channel; } if (options.method_id != null) { params.method = options.method_id; } return params; } buildTransactionRequest(input, sessionId) { const { currency_code, amount, data, context } = input; const normalizedParams = this.normalizePaymentCreateParams(); const customerEmail = context?.customer?.email || (typeof data?.email === "string" && data.email.trim().length > 0 ? data.email.trim() : undefined) || data?.customer?.email || "customer@example.com"; const country = data?.country?.toUpperCase() || "PL"; const language = data?.language?.toLowerCase() || "pl"; const urlReturn = typeof data?.return_url === "string" && data.return_url.trim().length ? data.return_url : `${this.options_.frontend_url}/payment/return?cart_id=${data?.cart_id ?? ""}`; const psu = data?.psu; const regulationAccept = data?.regulation_accept === true || data?.regulationAccept === true; const cardRefId = typeof data?.card_ref_id === "string" ? data.card_ref_id : undefined; const transactionRequest = { sessionId, amount: (0, get_smallest_unit_1.getSmallestUnit)(Number(amount), currency_code), country, language, currency: currency_code.toUpperCase(), description: normalizedParams.description || `Payment ${context?.idempotency_key}`, email: customerEmail, channel: normalizedParams.channel, method: normalizedParams.method, urlReturn, urlStatus: `${this.options_.backend_url}/hooks/payment/${this.getProviderKey()}_przelewy24`, ...(regulationAccept ? { regulationAccept: true } : {}), }; if (cardRefId) { transactionRequest.cardData = { means: { referenceNumber: { id: cardRefId }, }, transactionType: "standard", }; } if (psu?.IP && psu?.userAgent) { transactionRequest.additional = { PSU: { IP: psu.IP, userAgent: psu.userAgent, }, }; } return transactionRequest; } resolvePaymentSessionQuery() { const resolve = this.container_.resolve; if (typeof resolve !== "function") { return undefined; } try { const query = resolve.call(this.container_, utils_1.ContainerRegistrationKeys.QUERY); if (query && typeof query.graph === "function") { return query; } } catch { // Payment provider scope does not register QUERY (e.g. webhook handling). } return undefined; } async findMedusaPaymentSessionId(p24SessionId) { const inferred = (0, p24_session_data_1.inferMedusaPaymentSessionIdFromP24SessionId)(p24SessionId); if (inferred) { return inferred; } const query = this.resolvePaymentSessionQuery(); if (!query) { return p24SessionId; } const byId = await query.graph({ entity: "payment_session", fields: ["id", "data"], filters: { id: p24SessionId }, }); if (byId.data?.[0]?.id) { return byId.data[0].id; } const providerPrefix = `pp_${this.getProviderKey()}`; const sessions = await query.graph({ entity: "payment_session", fields: ["id", "data"], filters: { provider_id: { $like: `${providerPrefix}%` }, }, }); const matched = sessions.data?.find((session) => { const sessionData = session.data ?? {}; return (sessionData.session_id === p24SessionId || sessionData.sessionId === p24SessionId); }); return matched?.id ?? p24SessionId; } async enrichPaymentMethodFields(data) { const methodId = (0, p24_payment_methods_1.extractMethodIdFromSessionData)(data); if (!methodId) { return data; } if (data.paymentMethod === methodId && typeof data.paymentMethodName === "string" && data.paymentMethodName.length > 0 && typeof data.paymentMethodGroup === "string" && data.paymentMethodGroup.length > 0) { return data; } const currency = String(data.currency_code ?? data.currency ?? "PLN"); const lang = String(data.language ?? "pl").toLowerCase(); const amountGrosze = typeof data.amount_grosze === "number" && Number.isFinite(data.amount_grosze) ? Math.trunc(data.amount_grosze) : typeof data.amount === "number" && Number.isFinite(data.amount) ? (0, get_smallest_unit_1.getSmallestUnit)(data.amount, currency) : 0; const metadata = await (0, p24_payment_methods_1.resolveP24PaymentMethodMetadata)(this.p24Api, { methodId, lang, amountGrosze, currency, providerKey: this.getProviderKey(), }); return { ...data, ...metadata, method_id: methodId, methodId, }; } async initiatePayment(input) { const { currency_code, amount, context, data } = input; try { const sessionId = context?.idempotency_key; const p24SessionId = data?.p24_session_id || sessionId; if (!sessionId) { throw this.buildError("Missing idempotency key for P24 transaction", new Error("idempotency_key is required")); } this.logger_.debug(`Initiating P24 payment amount=${amount} ${currency_code} session=${sessionId} context=${JSON.stringify((0, p24_logger_1.redactUnknown)(context))}`); const transactionRequest = this.buildTransactionRequest(input, p24SessionId); const sessionData = await this.p24Api.registerTransaction(transactionRequest); if (sessionData.responseCode !== 0) { throw this.buildError((0, p24_errors_1.buildLocalizedP24ErrorMessage)(sessionData, "Failed to register P24 transaction"), new Error(`P24 API error: ${sessionData.responseCode} - ${sessionData.message || "Unknown error"}`)); } const isWhiteLabel = Boolean(this.paymentIntentOptions.white_label); const redirectUrl = `${this.p24Api.getBaseRedirectURL()}/${sessionData.data.token}`; const normalizedData = await this.enrichPaymentMethodFields((0, p24_session_data_1.normalizeP24SessionData)({ session_id: transactionRequest.sessionId, medusa_payment_session_id: sessionId, token: sessionData.data.token, amount: Number(amount), amount_grosze: transactionRequest.amount, currency: currency_code, currency_code, description: transactionRequest.description, email: transactionRequest.email, country: transactionRequest.country, language: transactionRequest.language, channel: transactionRequest.channel, method_id: transactionRequest.method, ...(transactionRequest.method != null ? { paymentMethod: transactionRequest.method } : {}), white_label: isWhiteLabel, ...(isWhiteLabel ? {} : { redirect_url: redirectUrl }), responseCode: sessionData.responseCode, })); this.logger_.info(`P24 payment initiated for session ${sessionId}`); return { id: transactionRequest.sessionId, data: normalizedData, }; } catch (error) { this.logger_.error(`Error initiating P24 payment: ${error.message}`); throw error; } } async authorizePayment(input) { const sessionId = (0, p24_session_data_1.getSessionId)(input.data); if (!sessionId) { throw this.buildError("Session ID is required for payment authorization", new Error("No session ID provided")); } try { const { transactionDetails, p24Status, medusaStatus } = await this.getTransactionDetailsAndStatus(sessionId); if (!["authorized", "captured"].includes(medusaStatus)) { throw this.buildError(`Payment is not in a valid state for authorization: current status is ${medusaStatus}`, new Error(`Invalid payment status: ${medusaStatus}`)); } let data = await this.enrichPaymentMethodFields((0, p24_session_data_1.normalizeP24SessionData)({ ...input.data, ...transactionDetails.data, amount_grosze: transactionDetails.data.amount, p24_status: p24Status, order_id: transactionDetails.data.orderId, })); const currencyCode = data.currency || input.data?.currency_code; if (!currencyCode) { throw this.buildError(`Missing currency code for amount conversion in authorizePayment (session: ${sessionId})`, new Error("currency_code is required to convert P24 amount")); } if (data.amount != null) { data.amount = (0, get_smallest_unit_1.getAmountFromSmallestUnit)(data.amount, currencyCode); } if (data.originAmount != null) { data.originAmount = (0, get_smallest_unit_1.getAmountFromSmallestUnit)(data.originAmount, currencyCode); } return { data, status: medusaStatus, }; } catch (error) { this.logger_.error(`Error authorizing payment ${sessionId}: ${error.message}`); throw error; } } async capturePayment(input) { const sessionId = (0, p24_session_data_1.getSessionId)(input.data); const amount = input.data?.amount; const currency = input.data?.currency || input.data?.currency_code; const orderId = (0, p24_session_data_1.getOrderId)(input.data); if (!sessionId || amount == null || !currency || orderId == null) { throw this.buildError("Missing required data for payment capture", new Error("Session ID, amount, currency, and order ID are required")); } try { const verification = await this.p24Api.verifyTransaction(sessionId, (0, get_smallest_unit_1.getSmallestUnit)(amount, currency), currency, orderId); if (verification.responseCode !== 0 || verification.data.status !== "success") { throw this.buildError("Payment capture failed", new Error(`Verification failed - responseCode: ${verification.responseCode}, status: ${verification.data.status}`)); } return { data: await this.enrichPaymentMethodFields((0, p24_session_data_1.normalizeP24SessionData)({ ...input.data, status: "captured", captured_at: new Date().toISOString(), order_id: orderId, capture_verified: true, })), }; } catch (error) { const message = (0, payment_job_errors_1.getJobErrorMessage)(error); if ((0, payment_job_errors_1.isExpectedStalePaymentJobFailure)(error)) { this.logger_.debug(`Skipping stale payment capture for ${sessionId}: ${message}`); } else { this.logger_.error(`Error capturing payment ${sessionId}: ${message}`); } throw error; } } async deletePayment(input) { return { data: input.data, }; } async cancelPayment(input) { return { data: input.data, }; } async refundPayment(input) { const { data: paymentData, amount: refundAmount, context } = input; const sessionId = (0, p24_session_data_1.getSessionId)(paymentData); const orderId = (0, p24_session_data_1.getOrderId)(paymentData); if (!sessionId || orderId == null) { throw this.buildError("No session ID or order ID provided while refunding payment", new Error("Missing session ID or order ID")); } try { const refundsUuid = crypto_1.default.randomUUID(); const requestId = context?.idempotency_key; if (typeof requestId !== "string" || requestId.length === 0) { throw this.buildError("Missing idempotency key for refund request", new Error("context.idempotency_key is required")); } const currencyCode = paymentData?.currency_code || paymentData?.currency || "pln"; const refundData = { requestId, refunds: [ { orderId, sessionId, amount: (0, get_smallest_unit_1.getSmallestUnit)(Number(refundAmount), currencyCode), description: `Refund for order ${sessionId}`, }, ], refundsUuid, }; const refundResult = await this.p24Api.processRefund(refundData); const refundStatus = refundResult.data[0]?.status; const refundMessage = refundResult.data[0]?.message; if (refundResult.responseCode !== 0 || !refundStatus) { throw this.buildError("Refund request failed", new Error(`P24 API error: ${refundResult.responseCode} - ${refundMessage || "Unknown error"}`)); } const p24RefundsNormal = Array.isArray(refundResult.data) ? refundResult.data.map((item) => { const out = { ...item }; const curr = item.currency || currencyCode; if (out.amount != null) { out.amount = (0, get_smallest_unit_1.getAmountFromSmallestUnit)(out.amount, curr); } if (out.originAmount != null) { out.originAmount = (0, get_smallest_unit_1.getAmountFromSmallestUnit)(out.originAmount, curr); } return out; }) : refundResult.data; return { data: (0, p24_session_data_1.normalizeP24SessionData)({ ...paymentData, refund_amount: refundAmount, refunded_at: new Date().toISOString(), refunds_uuid: refundsUuid, refund_request_id: requestId, refund_status: refundStatus, refund_message: refundMessage, p24_refunds: p24RefundsNormal, p24_response_code: refundResult.responseCode, status: "refund_requested", }), }; } catch (e) { throw this.buildError("An error occurred in refundPayment", e); } } async retrievePayment(input) { try { return { data: (0, p24_session_data_1.normalizeP24SessionData)(input.data), }; } catch (e) { throw this.buildError("An error occurred in retrievePayment", e); } } async updatePayment(input) { const { data, amount, currency_code, context } = input; const amountNumeric = Number(amount); const currentAmount = Number(data?.amount); if (Number.isFinite(currentAmount) && currentAmount === amountNumeric) { return { data: (0, p24_session_data_1.normalizeP24SessionData)(data) }; } const baseSessionId = context?.idempotency_key || (0, p24_session_data_1.getSessionId)(data); if (!baseSessionId) { throw this.buildError("Cannot update P24 payment without session id", new Error("Missing session id")); } const newP24SessionId = `${baseSessionId}-${crypto_1.default.randomUUID()}`; const initiated = await this.initiatePayment({ amount, currency_code, context: { ...context, idempotency_key: baseSessionId, }, data: { ...data, amount: amountNumeric, medusa_payment_session_id: baseSessionId, p24_session_id: newP24SessionId, }, }); return { data: (0, p24_session_data_1.normalizeP24SessionData)({ ...data, ...initiated.data, session_id: initiated.data?.session_id, medusa_payment_session_id: baseSessionId, amount: amountNumeric, }), }; } async getWebhookActionAndData(webhookData) { return (0, p24_webhook_1.processP24Webhook)({ p24Api: this.p24Api, logger: this.logger_, findMedusaPaymentSessionId: (p24SessionId) => this.findMedusaPaymentSessionId(p24SessionId), buildError: (message, error) => this.buildError(message, error), }, webhookData); } async getPaymentStatus(input) { const sessionId = input.context?.idempotency_key; if (!sessionId) { this.logger_.warn("No session ID provided for getPaymentStatus, returning pending"); return { status: "pending" }; } try { const { medusaStatus } = await this.getTransactionDetailsAndStatus(sessionId); return { status: medusaStatus }; } catch (error) { this.logger_.error(`Error getting payment status for session ${sessionId}: ${error.message}`); throw error; } } async queryTransactionStatus(sessionId) { return this.getTransactionDetailsAndStatus(sessionId); } async getTransactionDetailsAndStatus(sessionId) { return (0, p24_transaction_status_1.fetchTransactionDetailsAndStatus)({ p24Api: this.p24Api, logger: this.logger_, buildError: (message, error) => this.buildError(message, error), }, sessionId); } mapP24StatusToMedusaStatus(p24Status) { return (0, p24_transaction_status_1.mapP24StatusToMedusaStatus)(p24Status); } buildError(message, error) { const suffix = error instanceof Error ? error.message : typeof error === "string" ? error : "Unknown error"; return new Error(`${message}: ${suffix}`.trim()); } } exports.default = P24Base; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicDI0LWJhc2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvcHJvdmlkZXJzL3ByemVsZXd5MjQvY29yZS9wMjQtYmFzZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLG9EQUE0QjtBQU81QixxREFJbUM7QUFRbkMsaURBQW9EO0FBQ3BELHFFQUdrQztBQUNsQywrQ0FBa0Q7QUFDbEQsd0VBRzBDO0FBQzFDLGtFQUE4RDtBQUM5RCxzRUFLeUM7QUFDekMsNEVBRzRDO0FBQzVDLDBEQUEyRTtBQUMzRSwwREFBMEU7QUFDMUUsMEVBRzJDO0FBbUMzQyxNQUFlLE9BQVEsU0FBUSwrQkFBbUM7SUFDN0MsUUFBUSxDQUFhO0lBQ3JCLE1BQU0sQ0FBZ0I7SUFDdEIsVUFBVSxDQUFlO0lBQ3pCLE9BQU8sQ0FBcUM7SUFFL0QsTUFBTSxDQUFDLGVBQWUsQ0FBQyxPQUFtQjtRQUN4QyxJQUFJLENBQUMsSUFBQSxpQkFBUyxFQUFDLE9BQU8sQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDO1lBQ3BDLE1BQU0sSUFBSSxLQUFLLENBQUMsd0RBQXdELENBQUMsQ0FBQztRQUM1RSxDQUFDO1FBQ0QsSUFBSSxDQUFDLElBQUEsaUJBQVMsRUFBQyxPQUFPLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQztZQUMvQixNQUFNLElBQUksS0FBSyxDQUFDLG1EQUFtRCxDQUFDLENBQUM7UUFDdkUsQ0FBQztRQUNELElBQUksQ0FBQyxJQUFBLGlCQUFTLEVBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7WUFDaEMsTUFBTSxJQUFJLEtBQUssQ0FBQyxvREFBb0QsQ0FBQyxDQUFDO1FBQ3hFLENBQUM7UUFDRCxJQUFJLENBQUMsSUFBQSxpQkFBUyxFQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQzVCLE1BQU0sSUFBSSxLQUFLLENBQUMsZ0RBQWdELENBQUMsQ0FBQztRQUNwRSxDQUFDO1FBQ0Qs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