Skip to content

Commit

Permalink
checkout.submitDetails fix
Browse files Browse the repository at this point in the history
  • Loading branch information
ribeiroguilherme committed Dec 21, 2023
1 parent 83dd840 commit 689b362
Show file tree
Hide file tree
Showing 9 changed files with 83 additions and 64 deletions.
4 changes: 2 additions & 2 deletions packages/lib/src/components/ApplePay/ApplePay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import AdyenCheckoutError from '../../core/Errors/AdyenCheckoutError';
import { TxVariants } from '../tx-variants';
import { onSubmitReject } from '../../core/types';
import { PaymentResponseData } from '../../types/global-types';
import { sanitizeResponse } from '../internal/UIElement/utils';
import { sanitizeResponse, verifyPaymentDidNotFail } from '../internal/UIElement/utils';

const latestSupportedVersion = 14;

Expand Down Expand Up @@ -115,7 +115,7 @@ class ApplePayElement extends UIElement<ApplePayConfiguration> {
this.handleAuthorization()
.then(this.makePaymentsCall)
.then(sanitizeResponse)
.then(this.verifyPaymentDidNotFail)
.then(verifyPaymentDidNotFail)
.then(this.collectOrderTrackingDetailsIfNeeded)
.then(({ paymentResponse, orderDetails }) => {
resolve({
Expand Down
4 changes: 2 additions & 2 deletions packages/lib/src/components/GooglePay/GooglePay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import AdyenCheckoutError from '../../core/Errors/AdyenCheckoutError';
import { TxVariants } from '../tx-variants';
import { onSubmitReject } from '../../core/types';
import { AddressData, PaymentResponseData } from '../../types/global-types';
import { sanitizeResponse } from '../internal/UIElement/utils';
import { sanitizeResponse, verifyPaymentDidNotFail } from '../internal/UIElement/utils';

class GooglePay extends UIElement<GooglePayConfiguration> {
public static type = TxVariants.googlepay;
Expand Down Expand Up @@ -110,7 +110,7 @@ class GooglePay extends UIElement<GooglePayConfiguration> {
this.handleAuthorization()
.then(this.makePaymentsCall)
.then(sanitizeResponse)
.then(this.verifyPaymentDidNotFail)
.then(verifyPaymentDidNotFail)
.then((paymentResponse: PaymentResponseData) => {
resolve({ transactionState: 'SUCCESS' });
return paymentResponse;
Expand Down
26 changes: 6 additions & 20 deletions packages/lib/src/components/internal/UIElement/UIElement.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { h } from 'preact';
import BaseElement from '../BaseElement/BaseElement';
import PayButton from '../PayButton';
import { sanitizeResponse } from './utils';
import { cleanupFinalResult, sanitizeResponse, verifyPaymentDidNotFail } from './utils';
import AdyenCheckoutError from '../../../core/Errors/AdyenCheckoutError';
import { hasOwnProperty } from '../../../utils/hasOwnProperty';
import { CoreConfiguration, ICore } from '../../../core/types';
Expand Down Expand Up @@ -134,7 +134,7 @@ export abstract class UIElement<P extends UIElementProps = UIElementProps>

this.makePaymentsCall()
.then(sanitizeResponse)
.then(this.verifyPaymentDidNotFail)
.then(verifyPaymentDidNotFail)
.then(this.handleResponse)
.catch(this.handleFailedResult);
}
Expand Down Expand Up @@ -164,7 +164,7 @@ export abstract class UIElement<P extends UIElementProps = UIElementProps>
this.handleError(
new AdyenCheckoutError(
'IMPLEMENTATION_ERROR',
'Could not perform /payments call. Callback "onSubmit" is missing or Checkout session is not available'
'It can not perform /payments call. Callback "onSubmit" is missing or Checkout session is not available'
)
);
}
Expand Down Expand Up @@ -200,14 +200,6 @@ export abstract class UIElement<P extends UIElementProps = UIElementProps>
// };
}

protected verifyPaymentDidNotFail(response: PaymentResponseData): Promise<PaymentResponseData> {
if (['Cancelled', 'Error', 'Refused'].includes(response.resultCode)) {
return Promise.reject(response);
}

return Promise.resolve(response);
}

private onValid() {
const state = { data: this.data };
if (this.props.onValid) this.props.onValid(state, this.elementRef);
Expand All @@ -234,7 +226,7 @@ export abstract class UIElement<P extends UIElementProps = UIElementProps>
protected handleAdditionalDetails(state: any): void {
this.makeAdditionalDetailsCall(state)
.then(sanitizeResponse)
.then(this.verifyPaymentDidNotFail)
.then(verifyPaymentDidNotFail)
.then(this.handleResponse)
.catch(this.handleFailedResult);
}
Expand All @@ -259,7 +251,7 @@ export abstract class UIElement<P extends UIElementProps = UIElementProps>
this.handleError(
new AdyenCheckoutError(
'IMPLEMENTATION_ERROR',
'Could not perform /payments/details call. Callback "onAdditionalDetails" is missing or Checkout session is not available'
'It can not perform /payments/details call. Callback "onAdditionalDetails" is missing or Checkout session is not available'
)
);
}
Expand Down Expand Up @@ -328,17 +320,11 @@ export abstract class UIElement<P extends UIElementProps = UIElementProps>
};

protected handleSuccessResult = (result: PaymentResponseData): void => {
const sanitizeResult = (result: PaymentResponseData) => {
delete result.order;
delete result.action;
if (!result.donationToken || result.donationToken.length === 0) delete result.donationToken;
};

if (this.props.setStatusAutomatically) {
this.setElementStatus('success');
}

sanitizeResult(result);
cleanupFinalResult(result);

this.props.onPaymentCompleted?.(result, this.elementRef);
};
Expand Down
21 changes: 21 additions & 0 deletions packages/lib/src/components/internal/UIElement/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,19 @@ export function sanitizeResponse(response: RawPaymentResponse): PaymentResponseD
return sanitizedObject as PaymentResponseData;
}

/**
* Remove not relevant properties in the final payment result object
*
* @param paymentResponse
*/
export function cleanupFinalResult(paymentResponse: PaymentResponseData): void {
delete paymentResponse.order;
delete paymentResponse.action;
if (!paymentResponse.donationToken || paymentResponse.donationToken.length === 0) {
delete paymentResponse.donationToken;
}
}

export function resolveFinalResult(result: PaymentResponseData): [status: UIElementStatus, statusProps?: any] {
switch (result.resultCode) {
case 'Authorised':
Expand All @@ -35,3 +48,11 @@ export function resolveFinalResult(result: PaymentResponseData): [status: UIElem
default:
}
}

export function verifyPaymentDidNotFail(response: PaymentResponseData): Promise<PaymentResponseData> {
if (['Cancelled', 'Error', 'Refused'].includes(response.resultCode)) {
return Promise.reject(response);
}

return Promise.resolve(response);
}
57 changes: 41 additions & 16 deletions packages/lib/src/core/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import PaymentMethods from './ProcessResponse/PaymentMethods';
import getComponentForAction from './ProcessResponse/PaymentAction';
import { resolveEnvironment, resolveCDNEnvironment } from './Environment';
import Analytics from './Analytics';
import { PaymentAction } from '../types/global-types';
import { OnPaymentFailedData, PaymentAction, PaymentResponseData } from '../types/global-types';
import { CoreConfiguration, ICore } from './types';
import { processGlobalOptions } from './utils';
import Session from './CheckoutSession';
Expand All @@ -14,6 +14,8 @@ import { Resources } from './Context/Resources';
import { SRPanel } from './Errors/SRPanel';
import registry, { NewableComponent } from './core.registry';
import { DEFAULT_LOCALE } from '../language/config';
import { cleanupFinalResult, sanitizeResponse, verifyPaymentDidNotFail } from '../components/internal/UIElement/utils';
import AdyenCheckoutError from './Errors/AdyenCheckoutError';

class Core implements ICore {
public session?: Session;
Expand Down Expand Up @@ -106,25 +108,48 @@ class Core implements ICore {
}

/**
* Submits details using onAdditionalDetails or the session flow if available
* @param details -
* Method used when handling redirects. It submits details using 'onAdditionalDetails' or the Sessions flow if available.
*
* @public
* @see {https://docs.adyen.com/online-payments/build-your-integration/?platform=Web&integration=Components&version=5.55.1#handle-the-redirect}
* @param details - Details object containing the redirectResult
*/
public submitDetails(details): void {
// TODO: Check this
// if (this.options.onAdditionalDetails) {
// return this.options.onAdditionalDetails(details);
// }
public submitDetails(details: { details: { redirectResult: string } }): void {
let promise = null;

if (this.options.onAdditionalDetails) {
promise = new Promise((resolve, reject) => {
this.options.onAdditionalDetails({ data: details }, undefined, { resolve, reject });
});
}

if (this.session) {
this.session
.submitDetails(details)
.then(response => {
this.options.onPaymentCompleted?.(response);
})
.catch(error => {
this.options.onError?.(error);
});
promise = this.session.submitDetails(details).catch(error => {
this.options.onError?.(error);
return Promise.reject(error);
});
}

if (!promise) {
this.options.onError?.(
new AdyenCheckoutError(
'IMPLEMENTATION_ERROR',
'It can not submit the details. The callback "onAdditionalDetails" or the Session is not setup correctly.'
)
);
return;
}

promise
.then(sanitizeResponse)
.then(verifyPaymentDidNotFail)
.then((response: PaymentResponseData) => {
cleanupFinalResult(response);
this.options.onPaymentCompleted?.(response);
})
.catch((result: OnPaymentFailedData) => {
this.options.onPaymentFailed?.(result);
});
}

/**
Expand Down
2 changes: 1 addition & 1 deletion packages/lib/src/core/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ export interface CoreConfiguration {
* Callback used in the Advanced flow to perform the /payments/details API call.
*
* @param state
* @param element
* @param element - Component submitting details. It is undefined when using checkout.submitDetails()
* @param actions
*/
onAdditionalDetails?(
Expand Down
25 changes: 4 additions & 21 deletions packages/playground/src/pages/Dropin/manual.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
AdyenCheckout,
Dropin,
Ideal,
Card,
GooglePay,
PayPal,
Expand Down Expand Up @@ -137,8 +138,6 @@ export async function initManual() {
});

function handleFinalState(resultCode, dropin) {
localStorage.removeItem('storedPaymentData');

if (resultCode === 'Authorised' || resultCode === 'Received') {
dropin.setStatus('success');
} else {
Expand All @@ -147,26 +146,10 @@ export async function initManual() {
}

function handleRedirectResult() {
const storedPaymentData = localStorage.getItem('storedPaymentData');
const { amazonCheckoutSessionId, redirectResult, payload } = getSearchParameters(window.location.search);

if (redirectResult || payload) {
dropin.setStatus('loading');
return makeDetailsCall({
...(storedPaymentData && { paymentData: storedPaymentData }),
details: {
...(redirectResult && { redirectResult }),
...(payload && { payload })
}
}).then(result => {
if (result.action) {
dropin.handleAction(result.action);
} else {
handleFinalState(result.resultCode, dropin);
}

return true;
});
if (redirectResult) {
window.checkout.submitDetails({ details: { redirectResult } });
}

// Handle Amazon Pay redirect result
Expand Down Expand Up @@ -204,7 +187,7 @@ export async function initManual() {

const dropin = new Dropin({
core: checkout,
paymentMethodComponents: [Card, GooglePay, PayPal, Ach, Affirm, WeChat, Giftcard, AmazonPay],
paymentMethodComponents: [Card, Ideal, GooglePay, PayPal, Ach, Affirm, WeChat, Giftcard, AmazonPay],
instantPaymentTypes: ['googlepay'],
paymentMethodsConfiguration: {
card: {
Expand Down
4 changes: 2 additions & 2 deletions packages/playground/src/pages/Dropin/session.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AdyenCheckout, Dropin, Card, WeChat, Giftcard, PayPal, Ach, GooglePay } from '@adyen/adyen-web';
import { AdyenCheckout, Dropin, Card, WeChat, Giftcard, PayPal, Ach, GooglePay, Ideal } from '@adyen/adyen-web';
import '@adyen/adyen-web/styles/adyen.css';
import { createSession } from '../../services';
import { amount, shopperLocale, shopperReference, countryCode, returnUrl } from '../../config/commonConfig';
Expand Down Expand Up @@ -44,7 +44,7 @@ export async function initSession() {
const dropin = new Dropin({
core: checkout,
instantPaymentTypes: ['googlepay'],
paymentMethodComponents: [Card, WeChat, Giftcard, PayPal, Ach, GooglePay],
paymentMethodComponents: [Card, WeChat, Giftcard, PayPal, Ach, GooglePay, Ideal],
paymentMethodsConfiguration: {
googlepay: {
buttonType: 'plain',
Expand Down
4 changes: 4 additions & 0 deletions packages/playground/src/pages/Result/Result.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ async function handleRedirectResult(redirectResult, sessionId) {
console.log('onPaymentCompleted', result);
document.querySelector('#result-container > pre').innerHTML = JSON.stringify(result, null, '\t');
},
onPaymentFailed: result => {
console.log('onPaymentFailed', result);
document.querySelector('#result-container > pre').innerHTML = JSON.stringify(result, null, '\t');
},
onError: obj => {
console.log('checkout level merchant defined onError handler obj=', obj);
}
Expand Down

0 comments on commit 689b362

Please sign in to comment.