Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show the payment method terms on the checkout pages #2888

Draft
wants to merge 3 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions client/classic/upe/deferred-intent.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import jQuery from 'jquery';
import WCStripeAPI from '../../api';
import {
generateCheckoutEventNames,
generateCheckoutSavePaymentMethodInputId,
getSelectedUPEGatewayPaymentMethod,
getStripeServerData,
isUsingSavedPaymentMethod,
Expand All @@ -11,6 +12,7 @@ import {
processPayment,
mountStripePaymentElement,
createAndConfirmSetupIntent,
renderTerms,
confirmVoucherPayment,
} from './payment-processing';

Expand Down Expand Up @@ -43,6 +45,16 @@ jQuery( function ( $ ) {
}
}

const savePaymentMethodInputIds = generateCheckoutSavePaymentMethodInputId();
$( document ).on( 'change', function ( event ) {
if (
event.target &&
savePaymentMethodInputIds.includes( event.target.id )
) {
renderTerms( event );
}
} );

// Mount the Stripe Payment Elements onto the Add Payment Method page and Pay for Order page.
if (
$( 'form#add_payment_method' ).length ||
Expand Down
15 changes: 1 addition & 14 deletions client/classic/upe/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import jQuery from 'jquery';
import WCStripeAPI from '../../api';
import { getStripeServerData, getUPETerms } from '../../stripe-utils';
import { getStripeServerData } from '../../stripe-utils';
import { legacyHashchangeHandler } from './legacy-support';
import './style.scss';
import './deferred-intent.js';
Expand Down Expand Up @@ -283,19 +283,6 @@ jQuery( function ( $ ) {
}
} );

// Add terms parameter to UPE if save payment information checkbox is checked.
// This shows required legal mandates when customer elects to save payment method during checkout.
$( document ).on( 'change', '#wc-stripe-new-payment-method', () => {
const value = $( '#wc-stripe-new-payment-method' ).is( ':checked' )
? 'always'
: 'never';
if ( isUPEEnabled && upeElement ) {
upeElement.update( {
terms: getUPETerms( value ),
} );
}
} );

// On every page load, check to see whether we should display the authentication
// modal and display it if it should be displayed.
maybeShowAuthenticationModal();
Expand Down
25 changes: 24 additions & 1 deletion client/classic/upe/payment-processing.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import {
initializeUPEAppearance,
getStripeServerData,
getUpeSettings,
getTerms,
showErrorCheckout,
appendSetupIntentToForm,
getSelectedUPEGatewayPaymentMethod,
} from '../../stripe-utils';
import { getFontRulesFromPage } from '../../styles/upe';

Expand Down Expand Up @@ -77,7 +79,7 @@ function createStripePaymentElement( api, paymentMethodType = null ) {

const elements = api.getStripe().elements( options );
const createdStripePaymentElement = elements.create( 'payment', {
...getUpeSettings(),
...getUpeSettings( paymentMethodType ),
wallets: {
applePay: 'never',
googlePay: 'never',
Expand Down Expand Up @@ -276,6 +278,27 @@ export const createAndConfirmSetupIntent = (
} );
};

/**
* Updates the terms parameter in the Payment Element based on the "save payment information" checkbox.
*
* @param {Event} event The change event that triggers the function.
*/
export function renderTerms( event ) {
const isChecked = event.target.checked;
const value = isChecked ? 'always' : 'never';
const paymentMethodType = getSelectedUPEGatewayPaymentMethod();
if ( ! paymentMethodType ) {
return;
}

const upeElement = gatewayUPEComponents[ paymentMethodType ].upeElement;
if ( upeElement ) {
upeElement.update( {
terms: getTerms( paymentMethodType, value ),
} );
}
}

/**
* Handles displaying the Boleto or Oxxo voucher to the customer and then redirecting
* them to the order received page once they close the voucher window.
Expand Down
82 changes: 51 additions & 31 deletions client/stripe-utils/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,22 +125,49 @@ const getErrorMessageForTypeAndCode = ( type, code = '' ) => {
return null;
};

function shouldIncludeTerms( paymentMethodType ) {
if ( getStripeServerData()?.cartContainsSubscription ) {
return true;
}

const config = getStripeServerData()?.paymentMethodsConfig;
if (
! config[ paymentMethodType ] ||
! config[ paymentMethodType ].isReusable
) {
return false;
}

const paymentMethodId =
paymentMethodType === 'card' ? '' : `_${ paymentMethodType }`;
const checkboxId = `wc-stripe${ paymentMethodId }-new-payment-method`;

const savePaymentMethodCheckbox = document.getElementById( checkboxId );

if (
savePaymentMethodCheckbox !== null &&
savePaymentMethodCheckbox.checked
) {
return true;
}

return false;
}

/**
* Generates terms parameter for UPE, with value set for reusable payment methods
*
* @param {string} value The terms value for each available payment method.
* @param {string} paymentMethodType The payment method type for which we're passing the Terms parameter.
* @param {string} value The terms value for the passed payment method.
* @return {Object} Terms parameter fit for UPE.
*/
export const getUPETerms = ( value = 'always' ) => {
const config = getStripeServerData()?.paymentMethodsConfig;
const reusablePaymentMethods = Object.keys( config ).filter(
( method ) => config[ method ].isReusable
);
export const getTerms = ( paymentMethodType, value = 'always' ) => {
// The key for SEPA debit is different from the slug we use in paymentMethodType.
// Ref: https://stripe.com/docs/js/elements_object/create_payment_element#payment_element_create-options-terms
const termKey =
paymentMethodType !== 'sepa_debit' ? paymentMethodType : 'sepaDebit';

return reusablePaymentMethods.reduce( ( obj, method ) => {
obj[ method ] = value;
return obj;
}, {} );
return { [ termKey ]: value };
};

/**
Expand Down Expand Up @@ -248,24 +275,6 @@ export const getPaymentMethodTypes = ( paymentMethodType = null ) => {
return paymentMethodTypes;
};

function shouldIncludeTerms() {
if ( getStripeServerData()?.cartContainsSubscription ) {
return true;
}

const savePaymentMethodCheckbox = document.getElementById(
'wc-stripe-new-payment-method'
);
if (
savePaymentMethodCheckbox !== null &&
savePaymentMethodCheckbox.checked
) {
return true;
}

return false;
}

/**
* Returns a string of event names to be used for registering checkout submission handlers.
* For example: "checkout_place_order_stripe checkout_place_order_stripe_ideal ...checkout_place_order_{paymentMethod}"
Expand All @@ -278,6 +287,17 @@ export const generateCheckoutEventNames = () => {
.join( ' ' );
};

/**
* Returns an array with the ID of the inputs to save a new Payment Method.
*
* @return {Array} Array of input IDs.
*/
export const generateCheckoutSavePaymentMethodInputId = () => {
return Object.values( getPaymentMethodsConstants() ).map(
( method ) => `wc-${ method }-new-payment-method`
);
};

export const appendPaymentMethodIdToForm = ( form, paymentMethodId ) => {
form.append(
`<input type="hidden" id="wc-stripe-payment-method" name="wc-stripe-payment-method" value="${ paymentMethodId }" />`
Expand Down Expand Up @@ -380,11 +400,11 @@ export const getHiddenBillingFields = ( enabledBillingFields ) => {
};
};

export const getUpeSettings = () => {
export const getUpeSettings = ( paymentMethodType ) => {
const upeSettings = {};
const showTerms = shouldIncludeTerms() ? 'always' : 'never';
const value = shouldIncludeTerms( paymentMethodType ) ? 'always' : 'never';

upeSettings.terms = getUPETerms( showTerms );
upeSettings.terms = getTerms( paymentMethodType, value );

if (
getStripeServerData()?.isCheckout &&
Expand Down
Loading