diff --git a/package.json b/package.json index 7a329f6..71c5e1c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "processout.js", - "version": "1.9.1", + "version": "1.9.2", "description": "ProcessOut.js is a JavaScript library for ProcessOut's payment processing API.", "scripts": { "build:processout": "tsc -p src/processout && uglifyjs --compress --keep-fnames --ie8 dist/processout.js -o dist/processout.js", diff --git a/src/dynamic-checkout/clients/apple-pay.ts b/src/dynamic-checkout/clients/apple-pay.ts index ad58ec3..88bc881 100644 --- a/src/dynamic-checkout/clients/apple-pay.ts +++ b/src/dynamic-checkout/clients/apple-pay.ts @@ -157,7 +157,7 @@ module ProcessOut { invoiceData.id, cardToken, cardPaymentOptions, - invoiceId => { + (invoiceId, data) => { if (this.paymentConfig.showStatusMessage) { getViewContainer().appendChild( new DynamicCheckoutPaymentSuccessView(this.processOutInstance, this.paymentConfig) @@ -178,6 +178,7 @@ module ProcessOut { return_url: this.paymentConfig.invoiceDetails.return_url || null, payment_method_name: "apple_pay", payment_method_display_name: this.getApplePayPaymentMethodName(invoiceData), + ...DynamicCheckoutEventsUtils.getPaymentStatusEventDetail(data), }) }, error => { @@ -209,7 +210,7 @@ module ProcessOut { { clientSecret: this.paymentConfig.clientSecret, }, - invoiceId => { + (invoiceId, _reason, data) => { if (this.paymentConfig.showStatusMessage) { getViewContainer().appendChild( new DynamicCheckoutPaymentPendingView(this.processOutInstance, this.paymentConfig) @@ -222,6 +223,7 @@ module ProcessOut { payment_method_display_name: this.getApplePayPaymentMethodName(invoiceData), invoice_id: invoiceId, return_url: this.paymentConfig.invoiceDetails.return_url || null, + ...DynamicCheckoutEventsUtils.getPaymentStatusEventDetail(data), }) }, ) diff --git a/src/dynamic-checkout/clients/google-pay.ts b/src/dynamic-checkout/clients/google-pay.ts index 06cfef0..e263878 100644 --- a/src/dynamic-checkout/clients/google-pay.ts +++ b/src/dynamic-checkout/clients/google-pay.ts @@ -146,7 +146,7 @@ module ProcessOut { invoiceData.id, token, cardPaymentOptions, - invoiceId => { + (invoiceId, data) => { if (this.paymentConfig.showStatusMessage) { getViewContainer().appendChild( new DynamicCheckoutPaymentSuccessView( @@ -171,6 +171,7 @@ module ProcessOut { return_url: this.paymentConfig.invoiceDetails.return_url || null, payment_method_name: "google_pay", payment_method_display_name: this.getGooglePayPaymentMethodName(invoiceData), + ...DynamicCheckoutEventsUtils.getPaymentStatusEventDetail(data), }) }, error => { @@ -206,7 +207,7 @@ module ProcessOut { { clientSecret: this.paymentConfig.clientSecret, }, - invoiceId => { + (invoiceId, _reason, data) => { if (this.paymentConfig.showStatusMessage) { getViewContainer().appendChild( new DynamicCheckoutPaymentPendingView( @@ -221,6 +222,7 @@ module ProcessOut { payment_method_display_name: this.getGooglePayPaymentMethodName(invoiceData), invoice_id: invoiceId, return_url: this.paymentConfig.invoiceDetails.return_url || null, + ...DynamicCheckoutEventsUtils.getPaymentStatusEventDetail(data), }) }, ) diff --git a/src/dynamic-checkout/payment-methods/apm.ts b/src/dynamic-checkout/payment-methods/apm.ts index 471c7ff..1c8bdaa 100644 --- a/src/dynamic-checkout/payment-methods/apm.ts +++ b/src/dynamic-checkout/payment-methods/apm.ts @@ -118,7 +118,7 @@ module ProcessOut { this.paymentConfig.invoiceId, paymentToken, cardPaymentOptions, - invoiceId => { + (invoiceId, data) => { if (this.paymentConfig.showStatusMessage) { this.resetContainerHtml().appendChild( new DynamicCheckoutPaymentSuccessView(this.processOutInstance, this.paymentConfig) @@ -139,6 +139,7 @@ module ProcessOut { return_url: this.paymentConfig.invoiceDetails.return_url || null, payment_method_name: apm.gateway_name, payment_method_display_name: this.paymentMethodDisplayName, + ...DynamicCheckoutEventsUtils.getPaymentStatusEventDetail(data), }) }, error => { @@ -158,7 +159,7 @@ module ProcessOut { ) }, requestOptions, - invoiceId => { + (invoiceId, _reason, data) => { this.resetContainerHtml().appendChild( new DynamicCheckoutPaymentPendingView(this.processOutInstance, this.paymentConfig) .element, @@ -169,6 +170,7 @@ module ProcessOut { payment_method_display_name: this.paymentMethodDisplayName, invoice_id: invoiceId, return_url: this.paymentConfig.invoiceDetails.return_url || null, + ...DynamicCheckoutEventsUtils.getPaymentStatusEventDetail(data), }) }, ) @@ -265,6 +267,7 @@ module ProcessOut { invoice_id: this.paymentConfig.invoiceId, return_url: this.paymentConfig.invoiceDetails.return_url || null, customer_token_id: data.customer_token_id, + ...DynamicCheckoutEventsUtils.getPaymentStatusEventDetail(data), }) return @@ -281,7 +284,7 @@ module ProcessOut { this.paymentConfig.invoiceId, paymentToken, options, - invoiceId => { + (invoiceId, paymentData) => { if (this.paymentConfig.showStatusMessage) { this.resetContainerHtml().appendChild( new DynamicCheckoutPaymentSuccessView( @@ -307,6 +310,7 @@ module ProcessOut { payment_method_name: apm.gateway_name, payment_method_display_name: this.paymentMethodDisplayName, customer_token_id: data.customer_token_id, + ...DynamicCheckoutEventsUtils.getPaymentStatusEventDetail(paymentData), }) }, error => { @@ -340,7 +344,7 @@ module ProcessOut { ) }, requestOptions, - invoiceId => { + (invoiceId, _reason, paymentData) => { this.resetContainerHtml().appendChild( new DynamicCheckoutPaymentPendingView( this.processOutInstance, @@ -354,6 +358,7 @@ module ProcessOut { invoice_id: invoiceId, return_url: this.paymentConfig.invoiceDetails.return_url || null, customer_token_id: data.customer_token_id, + ...DynamicCheckoutEventsUtils.getPaymentStatusEventDetail(paymentData), }) }, ) diff --git a/src/dynamic-checkout/payment-methods/card.ts b/src/dynamic-checkout/payment-methods/card.ts index aaa5c7e..7befe33 100644 --- a/src/dynamic-checkout/payment-methods/card.ts +++ b/src/dynamic-checkout/payment-methods/card.ts @@ -183,6 +183,7 @@ module ProcessOut { payment_method_display_name: this.paymentMethodDisplayName, ...(this.tokenizedCardId && { card_id: this.tokenizedCardId }), customer_token_id: data?.customer_token_id, + ...DynamicCheckoutEventsUtils.getPaymentStatusEventDetail(data), }) if (this.paymentConfig.showStatusMessage) { @@ -199,7 +200,7 @@ module ProcessOut { } } - private handleCardPaymentPending(invoiceId: string) { + private handleCardPaymentPending(invoiceId: string, _reason: string | null, data?: any) { if (this.paymentConfig.showStatusMessage) { this.resetContainerHtml().appendChild( new DynamicCheckoutPaymentPendingView(this.procesoutInstance, this.paymentConfig).element, @@ -212,6 +213,7 @@ module ProcessOut { invoice_id: invoiceId, return_url: this.paymentConfig.invoiceDetails.return_url || null, ...(this.tokenizedCardId && { card_id: this.tokenizedCardId }), + ...DynamicCheckoutEventsUtils.getPaymentStatusEventDetail(data), }) } diff --git a/src/dynamic-checkout/payment-methods/saved-apm.ts b/src/dynamic-checkout/payment-methods/saved-apm.ts index 431f5a6..efb0998 100644 --- a/src/dynamic-checkout/payment-methods/saved-apm.ts +++ b/src/dynamic-checkout/payment-methods/saved-apm.ts @@ -87,7 +87,7 @@ module ProcessOut { invoiceId, paymentToken, cardPaymentOptions, - invoiceId => { + (invoiceId, data) => { if (this.paymentConfig.showStatusMessage) { this.resetContainerHtml().appendChild( new DynamicCheckoutPaymentSuccessView( @@ -110,6 +110,7 @@ module ProcessOut { return_url: this.paymentConfig.invoiceDetails.return_url || null, payment_method_name: apm_customer_token.gateway_name, payment_method_display_name: this.paymentMethodDisplayName, + ...DynamicCheckoutEventsUtils.getPaymentStatusEventDetail(data), }) }, error => { @@ -139,7 +140,7 @@ module ProcessOut { ) }, requestOptions, - invoiceId => { + (invoiceId, _reason, data) => { if (this.paymentConfig.showStatusMessage) { this.resetContainerHtml().appendChild( new DynamicCheckoutPaymentPendingView( @@ -154,6 +155,7 @@ module ProcessOut { payment_method_display_name: this.paymentMethodDisplayName, invoice_id: invoiceId, return_url: this.paymentConfig.invoiceDetails.return_url || null, + ...DynamicCheckoutEventsUtils.getPaymentStatusEventDetail(data), }) }, ) @@ -229,10 +231,11 @@ module ProcessOut { ? this.paymentMethod.apm_customer_token.gateway_name : "apm", payment_method_display_name: this.paymentMethodDisplayName, + ...DynamicCheckoutEventsUtils.getPaymentStatusEventDetail(data), }) } - private handlePaymentPending(invoiceId: string) { + private handlePaymentPending(invoiceId: string, _reason: string | null, data?: any) { if (this.paymentConfig.showStatusMessage) { this.resetContainerHtml().appendChild( new DynamicCheckoutPaymentPendingView(this.processOutInstance, this.paymentConfig) @@ -247,6 +250,7 @@ module ProcessOut { payment_method_display_name: this.paymentMethodDisplayName, invoice_id: this.paymentConfig.invoiceId, return_url: this.paymentConfig.invoiceDetails.return_url || null, + ...DynamicCheckoutEventsUtils.getPaymentStatusEventDetail(data), }) } diff --git a/src/dynamic-checkout/payment-methods/saved-card.ts b/src/dynamic-checkout/payment-methods/saved-card.ts index 7f430f5..8a9e068 100644 --- a/src/dynamic-checkout/payment-methods/saved-card.ts +++ b/src/dynamic-checkout/payment-methods/saved-card.ts @@ -65,7 +65,7 @@ module ProcessOut { ) } - private handlePaymentSuccess(invoiceId: string) { + private handlePaymentSuccess(invoiceId: string, data?: any) { if (this.paymentConfig.showStatusMessage) { this.resetContainerHtml().appendChild( new DynamicCheckoutPaymentSuccessView(this.processOutInstance, this.paymentConfig) @@ -85,10 +85,11 @@ module ProcessOut { return_url: this.paymentConfig.invoiceDetails.return_url || null, payment_method_name: "card", payment_method_display_name: this.paymentMethodDisplayName, + ...DynamicCheckoutEventsUtils.getPaymentStatusEventDetail(data), }) } - private handlePaymentPending(invoiceId: string) { + private handlePaymentPending(invoiceId: string, _reason: string | null, data?: any) { if (this.paymentConfig.showStatusMessage) { this.resetContainerHtml().appendChild( new DynamicCheckoutPaymentPendingView(this.processOutInstance, this.paymentConfig) @@ -101,6 +102,7 @@ module ProcessOut { payment_method_display_name: this.paymentMethodDisplayName, invoice_id: invoiceId, return_url: this.paymentConfig.invoiceDetails.return_url || null, + ...DynamicCheckoutEventsUtils.getPaymentStatusEventDetail(data), }) } diff --git a/src/dynamic-checkout/utils/events.ts b/src/dynamic-checkout/utils/events.ts index c58d22a..8d70a01 100644 --- a/src/dynamic-checkout/utils/events.ts +++ b/src/dynamic-checkout/utils/events.ts @@ -26,6 +26,8 @@ module ProcessOut { payment_method_display_name: string | null return_url: string | null card_id?: string + authorized?: boolean + captured?: boolean } interface DynamicCheckoutPaymentErrorEventDetail extends DynamicCheckoutEventDetail { @@ -133,6 +135,7 @@ module ProcessOut { payment_method_name: response.payment_method_name || null, payment_method_display_name: response.payment_method_display_name || null, return_url: response.return_url || null, + ...DynamicCheckoutEventsUtils.getPaymentStatusEventDetail(response), }, ) @@ -261,6 +264,8 @@ module ProcessOut { invoice_id: string return_url: string | null customer_token_id?: string + authorized?: boolean + captured?: boolean }) { const event = DynamicCheckoutEventsUtils.createEvent( DYNAMIC_CHECKOUT_EVENTS.PAYMENT_SUBMITTED, @@ -276,6 +281,8 @@ module ProcessOut { invoice_id: string return_url: string | null tab_closed?: boolean + authorized?: boolean + captured?: boolean }) { const event = DynamicCheckoutEventsUtils.createEvent( DYNAMIC_CHECKOUT_EVENTS.PAYMENT_CANCELLED, @@ -290,11 +297,17 @@ module ProcessOut { payment_method_display_name: string invoice_id: string return_url: string | null + card_id?: string customer_token_id?: string + authorized?: boolean + captured?: boolean }) { const event = DynamicCheckoutEventsUtils.createEvent( DYNAMIC_CHECKOUT_EVENTS.PAYMENT_PENDING, - details, + { + ...details, + ...DynamicCheckoutEventsUtils.getPaymentStatusEventDetail(details), + }, ) return window.dispatchEvent(event) @@ -308,6 +321,35 @@ module ProcessOut { return data } + static getPaymentStatusEventDetail(data: any) { + const detail = DynamicCheckoutEventsUtils.getEventDetail(data) + const isObject = typeof detail === "object" && detail !== null + + if (!isObject) { + return {} + } + + const metadata = + typeof detail.metadata === "object" && detail.metadata !== null ? detail.metadata : {} + + return { + ...(Object.prototype.hasOwnProperty.call(detail, "authorized") && { + authorized: detail.authorized, + }), + ...(!Object.prototype.hasOwnProperty.call(detail, "authorized") && + Object.prototype.hasOwnProperty.call(metadata, "authorized") && { + authorized: metadata.authorized, + }), + ...(Object.prototype.hasOwnProperty.call(detail, "captured") && { + captured: detail.captured, + }), + ...(!Object.prototype.hasOwnProperty.call(detail, "captured") && + Object.prototype.hasOwnProperty.call(metadata, "captured") && { + captured: metadata.captured, + }), + } + } + private static normalizePaymentError( invoiceId: string, errorData: any, @@ -333,6 +375,7 @@ module ProcessOut { : normalizedError == null ? null : String(normalizedError), + ...DynamicCheckoutEventsUtils.getPaymentStatusEventDetail(normalizedError), ...(isObject && normalizedError.transaction_status && { transaction_status: normalizedError.transaction_status, @@ -354,9 +397,24 @@ module ProcessOut { }, {}) } + private static withPaymentStatusEventDetail(data?: any) { + const paymentStatusEventDetail = DynamicCheckoutEventsUtils.getPaymentStatusEventDetail(data) + + if (!data || Object.prototype.toString.call(data) !== "[object Object]") { + return Object.keys(paymentStatusEventDetail).length > 0 ? paymentStatusEventDetail : data + } + + return { + ...data, + ...paymentStatusEventDetail, + } + } + // IE 11 polyfill static createEvent(eventName: string, data?: any) { - const sanitizedData = DynamicCheckoutEventsUtils.sanitizeEventDetail(data) + const sanitizedData = DynamicCheckoutEventsUtils.sanitizeEventDetail( + DynamicCheckoutEventsUtils.withPaymentStatusEventDetail(data), + ) if (typeof window.CustomEvent === "function") { return new CustomEvent(eventName, { diff --git a/src/processout/processout.ts b/src/processout/processout.ts index 21a0623..8cafc2d 100644 --- a/src/processout/processout.ts +++ b/src/processout/processout.ts @@ -1580,10 +1580,10 @@ module ProcessOut { invoiceID: string, cardID: string, options: any, - success: (data: any) => void, + success: (resourceId: any, data?: any) => void, error: (err: Exception) => void, apiRequestOptions?: apiRequestOptions, - pending?: (resourceId: string, reason: string | null) => void, + pending?: (resourceId: string, reason: string | null, data?: any) => void, ): void { this.handleCardActions( "POST", @@ -1734,7 +1734,7 @@ module ProcessOut { success: (resourceId: any, data?: any) => void, error: (err: Exception) => void, apiRequestOptions?: apiRequestOptions, - pending?: (resourceId: string, reason: string | null) => void, + pending?: (resourceId: string, reason: string | null, data?: any) => void, ): void { // returns this.hppInitialURL only once during the first call from HPP, then returns the endpoint const getEndpoint = (): string => { @@ -1801,7 +1801,22 @@ module ProcessOut { var outcome = resolveOutcome(data) if (outcome === OUTCOME.Failed) { - error(new Exception(data.error_type, data.message)) + const paymentStatusMetadata = { + ...(Object.prototype.hasOwnProperty.call(data, "authorized") && { + authorized: data.authorized, + }), + ...(Object.prototype.hasOwnProperty.call(data, "captured") && { + captured: data.captured, + }), + } + + error( + new Exception( + data.error_type, + data.message, + Object.keys(paymentStatusMetadata).length > 0 ? paymentStatusMetadata : undefined, + ), + ) return } @@ -1810,7 +1825,7 @@ module ProcessOut { // Otherwise, call the success callback with the resourceID // This is to ensure backward compatibility with old usage of PO.js if (pending) { - pending(resourceID, data?.message || null) + pending(resourceID, data?.message || null, data) } else { success(resourceID, data) }