* Remove savePaymentInfo check when displaying payment methods

This is because the savePaymentInfo is derived from whether the save payment method checkbox shows. This check doesn't make sense to do because it's not a good indicator of whether the payment method is enabled. Subscriptions for example hides the checkbox because it is implied that the method will be saved. We should instead rely on the server-side to only send permitted saved payment methods.

* Add safely_get_request_payment_method

This will allow us to try to get the payment method if it was passed in the request, but will default to an empty string if not. This is different to get_request_payment_method because it doesn't throw any errors. We need it to be different because get_request_payment_method is used when the order definitely needs payment (so a normal checkout scenario, vs. a £0 subscription checkout)

* Add action to update order meta when checking out

This is needed because some extensions rely on this action to add their information to the metadata of order items.

* Remove safely_get_request_payment_method

This is no longer needed.

* Remove @since from experimental hook

* Add PHPDoc for new update_order_meta hook

* Document use of experimental hook

* Reinstate the check for allowing saved cards

* Add method to Stripe integration to determine if saved_cards is enabled

* Add new field to get_payment_method_data

This adds displaySavePaymentMethodCheckbox which will be used to determine if the checkbox to save payment methods should display.

* Add displaySavePaymentMethodCheckbox option to client

This will determine whether the "Save payment information" checkbox will be displayed.

* Add requiresSaving option to Stripe payment method data

This is informed by the saved_cards option and the result of the wc_stripe_display_save_payment_method_checkbox filter.

* Rename displaySavePaymentMethodCheckbox to requiresSaving & fix logic

* Revert negation on display_save_payment method_checkbox filter & rename

We are going to rename the properties we use to determine whether saved cards are shown, or whether the save payment method checkbox is shown, so that their names are more descriptive of what they are for.

* Rename allowSavedCards and requiresSaving in Stripe integration

* Rename savePaymentInfo&requiresSaving to showSavedCards & showSaveOption

This is so we can hide the checkbox independently of hiding the saved payment methods.

* Show deprecated message if payment methods use savePaymentInfo

This is because we are leaving it in to enable backward compatibility but payment methods registering using this should be informed of the change in case it gets removed.

* Update Stripe typedefs and keys of supports object

* Show customer payment methods if showSavedCards is true on the method

* Make PaymentMethodTab accept showSaveOption prop

This will allow us to show the save checkbox only if the payment method says it should be shown.

* Update tests to use new keys in supports when reg'ing payment methods

* Add optional chaining when validating payment method config

This makes the code a little tidier :)

* Update assets/js/blocks-registry/payment-methods/payment-method-config.js

Co-authored-by: Seghir Nadir <nadir.seghir@gmail.com>

* Add more information to deprecated call in payment method config

* Fix lint error

* Fix prop types for PaymentMethodTab

* Add information about supports on payment methods to docs

Co-authored-by: Seghir Nadir <nadir.seghir@gmail.com>
This commit is contained in:
Thomas Roberts 2021-01-24 13:59:13 +00:00 committed by GitHub
parent e5d256254a
commit 96e3ff9662
11 changed files with 83 additions and 21 deletions

View File

@ -70,7 +70,7 @@ const PaymentMethodOptions = () => {
ariaLabel,
content: (
<PaymentMethodTab
allowsSaving={ supports.savePaymentInfo }
showSaveOption={ supports.showSaveOption }
>
{ cloneElement( component, {
activePaymentMethod,

View File

@ -18,14 +18,15 @@ import PaymentMethodErrorBoundary from './payment-method-error-boundary';
/**
* Component used to render the contents of a payment method tab.
*
* @param {Object} props Incoming props for the component.
* @param {boolean} props.allowsSaving Whether that payment method allows saving
* the data for future purchases.
* @param {Object} props.children Content of the payment method tab.
* @param {Object} props Incoming props for the component.
* @param {boolean} props.showSaveOption Whether that payment method allows saving
* the data for future purchases and should
* display the checkbox to do so.
* @param {Object} props.children Content of the payment method tab.
*
* @return {*} The rendered component.
*/
const PaymentMethodTab = ( { children, allowsSaving } ) => {
const PaymentMethodTab = ( { children, showSaveOption } ) => {
const { isEditor } = useEditorContext();
const {
shouldSavePayment,
@ -36,7 +37,7 @@ const PaymentMethodTab = ( { children, allowsSaving } ) => {
return (
<PaymentMethodErrorBoundary isEditor={ isEditor }>
{ children }
{ customerId > 0 && allowsSaving && (
{ customerId > 0 && showSaveOption && (
<CheckboxControl
className="wc-block-components-payment-methods__save-card-info"
label={ __(
@ -54,7 +55,7 @@ const PaymentMethodTab = ( { children, allowsSaving } ) => {
};
PaymentMethodTab.propTypes = {
allowsSaving: PropTypes.bool,
showSaveOption: PropTypes.bool,
children: PropTypes.node,
};

View File

@ -95,7 +95,7 @@ const getCustomerPaymentMethods = ( availablePaymentMethods = {} ) => {
const isAvailable = gateway in availablePaymentMethods;
return (
isAvailable &&
availablePaymentMethods[ gateway ].supports?.savePaymentInfo
availablePaymentMethods[ gateway ].supports?.showSavedCards
);
}
);

View File

@ -72,7 +72,8 @@ const registerMockPaymentMethods = () => {
icons: null,
canMakePayment: () => true,
supports: {
savePaymentInfo: true,
showSavedCards: true,
showSaveOption: true,
},
ariaLabel: name,
} );

View File

@ -1,3 +1,8 @@
/**
* External dependencies
*/
import deprecated from '@wordpress/deprecated';
/**
* Internal dependencies
*/
@ -21,7 +26,11 @@ export default class PaymentMethodConfig {
this.canMakePayment = config.canMakePayment;
this.paymentMethodId = config.paymentMethodId || this.name;
this.supports = {
savePaymentInfo: config?.supports?.savePaymentInfo || false,
showSavedCards:
config?.supports?.showSavedCards ||
config?.supports?.savePaymentInfo || // Kept for backward compatibility if methods still pass this when registering.
false,
showSaveOption: config?.supports?.showSaveOption || false,
};
}
@ -78,12 +87,30 @@ export default class PaymentMethodConfig {
);
}
if (
config.supports &&
typeof config.supports.savePaymentInfo !== 'undefined' &&
typeof config.supports.savePaymentInfo !== 'boolean'
typeof config.supports?.showSavedCards !== 'undefined' &&
typeof config.supports?.showSavedCards !== 'boolean'
) {
throw new TypeError(
'If the payment method includes the `supports.savePaymentInfo` property, it must be a boolean'
'If the payment method includes the `supports.showSavedCards` property, it must be a boolean'
);
}
if ( typeof config.supports?.savePaymentInfo !== 'undefined' ) {
deprecated(
'Passing savePaymentInfo when registering a payment method.',
{
alternative: 'Pass showSavedCards and showSaveOption',
plugin: 'woocommerce-gutenberg-products-block',
link:
'https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/3686',
}
);
}
if (
typeof config.supports?.showSaveOption !== 'undefined' &&
typeof config.supports?.showSaveOption !== 'boolean'
) {
throw new TypeError(
'If the payment method includes the `supports.showSaveOption` property, it must be a boolean'
);
}
};

View File

@ -56,7 +56,8 @@ const stripeCcPaymentMethod = {
'woo-gutenberg-products-block'
),
supports: {
savePaymentInfo: getStripeServerData().allowSavedCards,
showSavedCards: getStripeServerData().showSavedCards,
showSaveOption: getStripeServerData().showSaveOption,
},
};

View File

@ -297,8 +297,10 @@
* inline cc
* form or separate inputs.
* @property {{[k:string]:CreditCardIcon}} icons Contains supported cc icons.
* @property {boolean} allowSavedCards Used to indicate whether saved cards
* @property {boolean} showSavedCards Used to indicate whether saved cards
* can be used.
* @property {boolean} showSaveOption Used to indicate whether the option to
* save card can be displayed.
* @property {boolean} allowPaymentRequest True if merchant has enabled payment
* request (Chrome/Apple Pay).
*/

View File

@ -52,6 +52,7 @@ We also have individual features or code blocks behind a feature flag, this is a
## Usages of `__experimental` prefix
- `__experimental_woocommerce_blocks_checkout_update_order_meta` hook when the draft order has been created or updated from the cart and is now ready for extensions to modify the metadata ([experimental hook](https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/3686/files#diff-af2c90fa556cc086b780c8fad99b68373d87fd6007e6e2ff1b4c68ebe9ccb551R377-R393)).
- `__experimental_woocommerce_blocks_checkout_order_processed` hook when order has completed processing and is ready for payment ([experimental hook](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/accd1bbf402e043b9fc322f118ab614ba7437c92/src/StoreApi/Routes/Checkout.php#L237)).
- `__experimentalDeRegisterPaymentMethod` function used to deregister a payment method, only used in tests ([experimental function](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/b07883b8b76feeb439d655b255507b24fc59e091/assets/js/blocks-registry/payment-methods/registry.js#L70)).
- `__experimentalDeRegisterExpressPaymentMethod` function used to deregister an express payment method, only used in tests ([experimental function](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/b07883b8b76feeb439d655b255507b24fc59e091/assets/js/blocks-registry/payment-methods/registry.js#L74)).

View File

@ -93,6 +93,9 @@ The options you feed the configuration instance are the same as those for expres
- `label`: This should be a react node that will be used to output the label for the tab in the payment methods are. For example it might be `<strong>Credit/Debit Cart</strong>` or you might output images.
- `ariaLabel`: This is the label that will be read out via screen-readers when the payment method is selected.
- `placeOrderButtonLabel`: This is an optional label which will change the default "Place Order" button text to something else when the payment method is selected.
- `supports`: This is an object containing information about what features your payment method supports. The following keys are valid here:
- `showSavedCards`: This value will determine whether saved cards associated with your payment method are shown to the customer.
- `showSaveOption`: This value will control whether to show the checkbox which allows customers to save their payment method for future payments.
### Props Fed to Payment Method Nodes

View File

@ -93,8 +93,9 @@ final class Stripe extends AbstractPaymentMethodType {
],
'inline_cc_form' => $this->get_inline_cc_form(),
'icons' => $this->get_icons(),
'allowSavedCards' => $this->get_allow_saved_cards(),
'showSavedCards' => $this->get_show_saved_cards(),
'allowPaymentRequest' => $this->get_allow_payment_request(),
'showSaveOption' => $this->get_show_save_option(),
];
}
@ -103,8 +104,17 @@ final class Stripe extends AbstractPaymentMethodType {
*
* @return bool True if merchant allows shopper to save card (payment method) during checkout).
*/
private function get_allow_saved_cards() {
$saved_cards = isset( $this->settings['saved_cards'] ) ? $this->settings['saved_cards'] : false;
private function get_show_saved_cards() {
return isset( $this->settings['saved_cards'] ) ? 'yes' === $this->settings['saved_cards'] : false;
}
/**
* Determine if the checkbox to enable the user to save their payment method should be shown.
*
* @return bool True if the save payment checkbox should be displayed to the user.
*/
private function get_show_save_option() {
$saved_cards = $this->get_show_saved_cards();
// This assumes that Stripe supports `tokenization` - currently this is true, based on
// https://github.com/woocommerce/woocommerce-gateway-stripe/blob/master/includes/class-wc-gateway-stripe.php#L95 .
// See https://github.com/woocommerce/woocommerce-gateway-stripe/blob/ad19168b63df86176cbe35c3e95203a245687640/includes/class-wc-gateway-stripe.php#L271 and

View File

@ -230,7 +230,6 @@ class Checkout extends AbstractRoute {
*
* @see https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/3238
* @internal This Hook is experimental and may change or be removed.
* @since 3.8.0
*
* @param WC_Order $order Order object.
*/
@ -356,6 +355,23 @@ class Checkout extends AbstractRoute {
$order_controller->update_order_from_cart( $this->order );
}
/**
* WooCommerce Blocks Checkout Update Order Meta (experimental).
*
* This hook gives extensions the chance to add or update meta data on the $order.
*
* This is similar to existing core hook woocommerce_checkout_update_order_meta.
* We're using a new action:
* - To keep the interface focused (only pass $order, not passing request data).
* - This also explicitly indicates these orders are from checkout block/StoreAPI.
*
* @see https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/3686
* @internal This Hook is experimental and may change or be removed.
*
* @param WC_Order $order Order object.
*/
do_action( '__experimental_woocommerce_blocks_checkout_update_order_meta', $this->order );
// Confirm order is valid before proceeding further.
if ( ! $this->order instanceof WC_Order ) {
throw new RouteException(