mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-09-01 07:02:48 +08:00
Merge branch 'trunk' into PCP-4156-implement-3ds-for-google-pay
This commit is contained in:
commit
784af34b1e
38 changed files with 1030 additions and 784 deletions
|
@ -54,7 +54,7 @@ class Renderer {
|
|||
|
||||
const enabledSeparateGateways = Object.fromEntries(
|
||||
Object.entries( settings.separate_buttons ).filter(
|
||||
( [ s, data ] ) => document.querySelector( data.wrapper )
|
||||
( [ , data ] ) => document.querySelector( data.wrapper )
|
||||
)
|
||||
);
|
||||
const hasEnabledSeparateGateways =
|
||||
|
@ -65,15 +65,16 @@ class Renderer {
|
|||
this.renderButtons(
|
||||
settings.button.wrapper,
|
||||
settings.button.style,
|
||||
contextConfig,
|
||||
hasEnabledSeparateGateways
|
||||
contextConfig
|
||||
);
|
||||
}
|
||||
} else {
|
||||
const allFundingSources = paypal.getFundingSources();
|
||||
const separateFunding = allFundingSources.filter(
|
||||
( s ) => ! ( s in enabledSeparateGateways )
|
||||
);
|
||||
// render each button separately
|
||||
for ( const fundingSource of paypal
|
||||
.getFundingSources()
|
||||
.filter( ( s ) => ! ( s in enabledSeparateGateways ) ) ) {
|
||||
for ( const fundingSource of separateFunding ) {
|
||||
const style = normalizeStyleForFundingSource(
|
||||
settings.button.style,
|
||||
fundingSource
|
||||
|
@ -83,7 +84,6 @@ class Renderer {
|
|||
settings.button.wrapper,
|
||||
style,
|
||||
contextConfig,
|
||||
hasEnabledSeparateGateways,
|
||||
fundingSource
|
||||
);
|
||||
}
|
||||
|
@ -103,26 +103,15 @@ class Renderer {
|
|||
data.wrapper,
|
||||
data.style,
|
||||
contextConfig,
|
||||
hasEnabledSeparateGateways,
|
||||
fundingSource
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
renderButtons(
|
||||
wrapper,
|
||||
style,
|
||||
contextConfig,
|
||||
hasEnabledSeparateGateways,
|
||||
fundingSource = null
|
||||
) {
|
||||
renderButtons( wrapper, style, contextConfig, fundingSource = null ) {
|
||||
if (
|
||||
! document.querySelector( wrapper ) ||
|
||||
this.isAlreadyRendered(
|
||||
wrapper,
|
||||
fundingSource,
|
||||
hasEnabledSeparateGateways
|
||||
)
|
||||
this.isAlreadyRendered( wrapper, fundingSource )
|
||||
) {
|
||||
// Try to render registered buttons again in case they were removed from the DOM by an external source.
|
||||
widgetBuilder.renderButtons( [ wrapper, fundingSource ] );
|
||||
|
@ -144,10 +133,7 @@ class Renderer {
|
|||
this.onSmartButtonClick( data, actions );
|
||||
}
|
||||
|
||||
venmoButtonClicked = false;
|
||||
if ( data.fundingSource === 'venmo' ) {
|
||||
venmoButtonClicked = true;
|
||||
}
|
||||
venmoButtonClicked = data.fundingSource === 'venmo';
|
||||
},
|
||||
onInit: ( data, actions ) => {
|
||||
if ( this.onSmartButtonsInit ) {
|
||||
|
@ -161,29 +147,29 @@ class Renderer {
|
|||
if ( this.shouldEnableShippingCallback() ) {
|
||||
options.onShippingOptionsChange = ( data, actions ) => {
|
||||
const shippingOptionsChange =
|
||||
! this.isVenmoButtonClickedWhenVaultingIsEnabled(
|
||||
venmoButtonClicked
|
||||
)
|
||||
? handleShippingOptionsChange(
|
||||
data,
|
||||
actions,
|
||||
this.defaultSettings
|
||||
)
|
||||
: null;
|
||||
! this.isVenmoButtonClickedWhenVaultingIsEnabled(
|
||||
venmoButtonClicked
|
||||
)
|
||||
? handleShippingOptionsChange(
|
||||
data,
|
||||
actions,
|
||||
this.defaultSettings
|
||||
)
|
||||
: null;
|
||||
|
||||
return shippingOptionsChange;
|
||||
};
|
||||
options.onShippingAddressChange = ( data, actions ) => {
|
||||
const shippingAddressChange =
|
||||
! this.isVenmoButtonClickedWhenVaultingIsEnabled(
|
||||
venmoButtonClicked
|
||||
)
|
||||
? handleShippingAddressChange(
|
||||
data,
|
||||
actions,
|
||||
this.defaultSettings
|
||||
)
|
||||
: null;
|
||||
! this.isVenmoButtonClickedWhenVaultingIsEnabled(
|
||||
venmoButtonClicked
|
||||
)
|
||||
? handleShippingAddressChange(
|
||||
data,
|
||||
actions,
|
||||
this.defaultSettings
|
||||
)
|
||||
: null;
|
||||
|
||||
return shippingAddressChange;
|
||||
};
|
||||
|
@ -228,12 +214,11 @@ class Renderer {
|
|||
}
|
||||
);
|
||||
|
||||
this.renderedSources.add( wrapper + ( fundingSource ?? '' ) );
|
||||
this.renderedSources.add(
|
||||
wrapper + ( fundingSource ? fundingSource : '' )
|
||||
);
|
||||
|
||||
if (
|
||||
typeof paypal !== 'undefined' &&
|
||||
typeof paypal.Buttons !== 'undefined'
|
||||
) {
|
||||
if ( window.paypal?.Buttons ) {
|
||||
widgetBuilder.registerButtons(
|
||||
[ wrapper, fundingSource ],
|
||||
buttonsOptions()
|
||||
|
@ -246,15 +231,16 @@ class Renderer {
|
|||
return venmoButtonClicked && this.defaultSettings.vaultingEnabled;
|
||||
};
|
||||
|
||||
shouldEnableShippingCallback = () => {
|
||||
shouldEnableShippingCallback = () => {
|
||||
const needShipping =
|
||||
this.defaultSettings.needShipping ||
|
||||
this.defaultSettings.context === 'product';
|
||||
|
||||
return (
|
||||
this.defaultSettings.should_handle_shipping_in_paypal &&
|
||||
needShipping
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
isAlreadyRendered( wrapper, fundingSource ) {
|
||||
return this.renderedSources.has( wrapper + ( fundingSource ?? '' ) );
|
||||
|
@ -272,6 +258,7 @@ class Renderer {
|
|||
this.onButtonsInitListeners[ wrapper ] = reset
|
||||
? []
|
||||
: this.onButtonsInitListeners[ wrapper ] || [];
|
||||
|
||||
this.onButtonsInitListeners[ wrapper ].push( handler );
|
||||
}
|
||||
|
||||
|
@ -283,12 +270,11 @@ class Renderer {
|
|||
|
||||
if ( this.onButtonsInitListeners[ wrapper ] ) {
|
||||
for ( const handler of this.onButtonsInitListeners[ wrapper ] ) {
|
||||
if ( typeof handler === 'function' ) {
|
||||
handler( {
|
||||
wrapper,
|
||||
...this.buttonsOptions[ wrapper ],
|
||||
} );
|
||||
if ( typeof handler !== 'function' ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
handler( { wrapper, ...this.buttonsOptions[ wrapper ] } );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -297,10 +283,11 @@ class Renderer {
|
|||
if ( ! this.buttonsOptions[ wrapper ] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this.buttonsOptions[ wrapper ].actions.disable();
|
||||
} catch ( err ) {
|
||||
console.log( 'Failed to disable buttons: ' + err );
|
||||
console.warn( 'Failed to disable buttons: ' + err );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -308,10 +295,11 @@ class Renderer {
|
|||
if ( ! this.buttonsOptions[ wrapper ] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this.buttonsOptions[ wrapper ].actions.enable();
|
||||
} catch ( err ) {
|
||||
console.log( 'Failed to enable buttons: ' + err );
|
||||
console.warn( 'Failed to enable buttons: ' + err );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,8 +40,9 @@ class WidgetBuilder {
|
|||
|
||||
renderButtons( wrapper ) {
|
||||
wrapper = this.sanitizeWrapper( wrapper );
|
||||
const entryKey = this.toKey( wrapper );
|
||||
|
||||
if ( ! this.buttons.has( this.toKey( wrapper ) ) ) {
|
||||
if ( ! this.buttons.has( entryKey ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -49,11 +50,11 @@ class WidgetBuilder {
|
|||
return;
|
||||
}
|
||||
|
||||
const entry = this.buttons.get( this.toKey( wrapper ) );
|
||||
const entry = this.buttons.get( entryKey );
|
||||
const btn = this.paypal.Buttons( entry.options );
|
||||
|
||||
if ( ! btn.isEligible() ) {
|
||||
this.buttons.delete( this.toKey( wrapper ) );
|
||||
this.buttons.delete( entryKey );
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -67,7 +68,7 @@ class WidgetBuilder {
|
|||
}
|
||||
|
||||
renderAllButtons() {
|
||||
for ( const [ wrapper, entry ] of this.buttons ) {
|
||||
for ( const [ wrapper ] of this.buttons ) {
|
||||
this.renderButtons( wrapper );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ use WooCommerce\PayPalCommerce\Button\Helper\MessagesApply;
|
|||
use WooCommerce\PayPalCommerce\Button\Helper\ThreeDSecure;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\SettingsStatus;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\DCCGatewayConfiguration;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\CardPaymentsConfiguration;
|
||||
|
||||
return array(
|
||||
'button.client_id' => static function ( ContainerInterface $container ): string {
|
||||
|
@ -115,8 +115,8 @@ return array(
|
|||
}
|
||||
|
||||
$no_smart_buttons = ! $settings_status->is_smart_button_enabled_for_location( $context );
|
||||
$dcc_configuration = $container->get( 'wcgateway.configuration.dcc' );
|
||||
assert( $dcc_configuration instanceof DCCGatewayConfiguration );
|
||||
$dcc_configuration = $container->get( 'wcgateway.configuration.card-configuration' );
|
||||
assert( $dcc_configuration instanceof CardPaymentsConfiguration );
|
||||
|
||||
if ( $no_smart_buttons && ! $dcc_configuration->is_enabled() ) {
|
||||
// Smart buttons disabled, and also not using advanced card payments.
|
||||
|
@ -167,7 +167,8 @@ return array(
|
|||
$container->get( 'api.endpoint.payment-tokens' ),
|
||||
$container->get( 'woocommerce.logger.woocommerce' ),
|
||||
$container->get( 'button.handle-shipping-in-paypal' ),
|
||||
$container->get( 'button.helper.disabled-funding-sources' )
|
||||
$container->get( 'button.helper.disabled-funding-sources' ),
|
||||
$container->get( 'wcgateway.configuration.card-configuration' )
|
||||
);
|
||||
},
|
||||
'button.url' => static function ( ContainerInterface $container ): string {
|
||||
|
@ -343,7 +344,8 @@ return array(
|
|||
'button.helper.disabled-funding-sources' => static function ( ContainerInterface $container ): DisabledFundingSources {
|
||||
return new DisabledFundingSources(
|
||||
$container->get( 'wcgateway.settings' ),
|
||||
$container->get( 'wcgateway.all-funding-sources' )
|
||||
$container->get( 'wcgateway.all-funding-sources' ),
|
||||
$container->get( 'wcgateway.configuration.card-configuration' )
|
||||
);
|
||||
},
|
||||
'button.is-logged-in' => static function ( ContainerInterface $container ): bool {
|
||||
|
|
|
@ -54,6 +54,7 @@ use WooCommerce\PayPalCommerce\WcGateway\Helper\SettingsStatus;
|
|||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
use WC_Shipping_Method;
|
||||
use WC_Cart;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\CardPaymentsConfiguration;
|
||||
|
||||
/**
|
||||
* Class SmartButton
|
||||
|
@ -237,33 +238,41 @@ class SmartButton implements SmartButtonInterface {
|
|||
*/
|
||||
private $disabled_funding_sources;
|
||||
|
||||
/**
|
||||
* Provides details about the DCC configuration.
|
||||
*
|
||||
* @var CardPaymentsConfiguration
|
||||
*/
|
||||
private CardPaymentsConfiguration $dcc_configuration;
|
||||
|
||||
/**
|
||||
* SmartButton constructor.
|
||||
*
|
||||
* @param string $module_url The URL to the module.
|
||||
* @param string $version The assets version.
|
||||
* @param SessionHandler $session_handler The Session handler.
|
||||
* @param Settings $settings The Settings.
|
||||
* @param PayerFactory $payer_factory The Payer factory.
|
||||
* @param string $client_id The client ID.
|
||||
* @param RequestData $request_data The Request Data helper.
|
||||
* @param DccApplies $dcc_applies The DCC applies helper.
|
||||
* @param SubscriptionHelper $subscription_helper The subscription helper.
|
||||
* @param MessagesApply $messages_apply The Messages apply helper.
|
||||
* @param Environment $environment The environment object.
|
||||
* @param PaymentTokenRepository $payment_token_repository The payment token repository.
|
||||
* @param SettingsStatus $settings_status The Settings status helper.
|
||||
* @param CurrencyGetter $currency The getter of the 3-letter currency code of the shop.
|
||||
* @param array $all_funding_sources All existing funding sources.
|
||||
* @param bool $basic_checkout_validation_enabled Whether the basic JS validation of the form iss enabled.
|
||||
* @param bool $early_validation_enabled Whether to execute WC validation of the checkout form.
|
||||
* @param array $pay_now_contexts The contexts that should have the Pay Now button.
|
||||
* @param string[] $funding_sources_without_redirect The sources that do not cause issues about redirecting (on mobile, ...) and sometimes not returning back.
|
||||
* @param bool $vault_v3_enabled Whether Vault v3 module is enabled.
|
||||
* @param PaymentTokensEndpoint $payment_tokens_endpoint Payment tokens endpoint.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
* @param bool $should_handle_shipping_in_paypal Whether the shipping should be handled in PayPal.
|
||||
* @param DisabledFundingSources $disabled_funding_sources List of funding sources to be disabled.
|
||||
* @param string $module_url The URL to the module.
|
||||
* @param string $version The assets version.
|
||||
* @param SessionHandler $session_handler The Session handler.
|
||||
* @param Settings $settings The Settings.
|
||||
* @param PayerFactory $payer_factory The Payer factory.
|
||||
* @param string $client_id The client ID.
|
||||
* @param RequestData $request_data The Request Data helper.
|
||||
* @param DccApplies $dcc_applies The DCC applies helper.
|
||||
* @param SubscriptionHelper $subscription_helper The subscription helper.
|
||||
* @param MessagesApply $messages_apply The Messages apply helper.
|
||||
* @param Environment $environment The environment object.
|
||||
* @param PaymentTokenRepository $payment_token_repository The payment token repository.
|
||||
* @param SettingsStatus $settings_status The Settings status helper.
|
||||
* @param CurrencyGetter $currency The getter of the 3-letter currency code of the shop.
|
||||
* @param array $all_funding_sources All existing funding sources.
|
||||
* @param bool $basic_checkout_validation_enabled Whether the basic JS validation of the form iss enabled.
|
||||
* @param bool $early_validation_enabled Whether to execute WC validation of the checkout form.
|
||||
* @param array $pay_now_contexts The contexts that should have the Pay Now button.
|
||||
* @param string[] $funding_sources_without_redirect The sources that do not cause issues about redirecting (on mobile, ...) and sometimes not returning back.
|
||||
* @param bool $vault_v3_enabled Whether Vault v3 module is enabled.
|
||||
* @param PaymentTokensEndpoint $payment_tokens_endpoint Payment tokens endpoint.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
* @param bool $should_handle_shipping_in_paypal Whether the shipping should be handled in PayPal.
|
||||
* @param DisabledFundingSources $disabled_funding_sources List of funding sources to be disabled.
|
||||
* @param CardPaymentsConfiguration $dcc_configuration The DCC Gateway Configuration.
|
||||
*/
|
||||
public function __construct(
|
||||
string $module_url,
|
||||
|
@ -289,9 +298,9 @@ class SmartButton implements SmartButtonInterface {
|
|||
PaymentTokensEndpoint $payment_tokens_endpoint,
|
||||
LoggerInterface $logger,
|
||||
bool $should_handle_shipping_in_paypal,
|
||||
DisabledFundingSources $disabled_funding_sources
|
||||
DisabledFundingSources $disabled_funding_sources,
|
||||
CardPaymentsConfiguration $dcc_configuration
|
||||
) {
|
||||
|
||||
$this->module_url = $module_url;
|
||||
$this->version = $version;
|
||||
$this->session_handler = $session_handler;
|
||||
|
@ -316,6 +325,7 @@ class SmartButton implements SmartButtonInterface {
|
|||
$this->payment_tokens_endpoint = $payment_tokens_endpoint;
|
||||
$this->should_handle_shipping_in_paypal = $should_handle_shipping_in_paypal;
|
||||
$this->disabled_funding_sources = $disabled_funding_sources;
|
||||
$this->dcc_configuration = $dcc_configuration;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -331,76 +341,8 @@ class SmartButton implements SmartButtonInterface {
|
|||
$this->render_message_wrapper_registrar();
|
||||
}
|
||||
|
||||
if (
|
||||
$this->settings->has( 'dcc_enabled' )
|
||||
&& $this->settings->get( 'dcc_enabled' )
|
||||
) {
|
||||
add_action(
|
||||
$this->checkout_dcc_button_renderer_hook(),
|
||||
array(
|
||||
$this,
|
||||
'dcc_renderer',
|
||||
),
|
||||
11
|
||||
);
|
||||
|
||||
add_action(
|
||||
$this->pay_order_renderer_hook(),
|
||||
array(
|
||||
$this,
|
||||
'dcc_renderer',
|
||||
),
|
||||
11
|
||||
);
|
||||
|
||||
$subscription_helper = $this->subscription_helper;
|
||||
add_filter(
|
||||
'woocommerce_credit_card_form_fields',
|
||||
function ( array $default_fields, $id ) use ( $subscription_helper ) : array {
|
||||
if (
|
||||
is_user_logged_in()
|
||||
&& $this->settings->has( 'vault_enabled_dcc' )
|
||||
&& $this->settings->get( 'vault_enabled_dcc' )
|
||||
&& CreditCardGateway::ID === $id
|
||||
&& apply_filters( 'woocommerce_paypal_payments_should_render_card_custom_fields', true )
|
||||
) {
|
||||
|
||||
$default_fields['card-vault'] = sprintf(
|
||||
'<p class="form-row form-row-wide"><label for="ppcp-credit-card-vault"><input class="ppcp-credit-card-vault" type="checkbox" id="ppcp-credit-card-vault" name="vault">%s</label></p>',
|
||||
esc_html__( 'Save your Credit Card', 'woocommerce-paypal-payments' )
|
||||
);
|
||||
if ( $subscription_helper->cart_contains_subscription() || $subscription_helper->order_pay_contains_subscription() ) {
|
||||
$default_fields['card-vault'] = '';
|
||||
}
|
||||
|
||||
$tokens = $this->payment_token_repository->all_for_user_id( get_current_user_id() );
|
||||
if ( $tokens && $this->payment_token_repository->tokens_contains_card( $tokens ) ) {
|
||||
$output = sprintf(
|
||||
'<p class="form-row form-row-wide"><label>%1$s</label><select id="saved-credit-card" name="saved_credit_card"><option value="">%2$s</option>',
|
||||
esc_html__( 'Or select a saved Credit Card payment', 'woocommerce-paypal-payments' ),
|
||||
esc_html__( 'Choose a saved payment', 'woocommerce-paypal-payments' )
|
||||
);
|
||||
foreach ( $tokens as $token ) {
|
||||
if ( isset( $token->source()->card ) ) {
|
||||
$output .= sprintf(
|
||||
'<option value="%1$s">%2$s ...%3$s</option>',
|
||||
$token->id(),
|
||||
$token->source()->card->brand,
|
||||
$token->source()->card->last_digits
|
||||
);
|
||||
}
|
||||
}
|
||||
$output .= '</select></p>';
|
||||
|
||||
$default_fields['saved-credit-card'] = $output;
|
||||
}
|
||||
}
|
||||
|
||||
return $default_fields;
|
||||
},
|
||||
10,
|
||||
2
|
||||
);
|
||||
if ( $this->dcc_configuration->is_enabled() ) {
|
||||
$this->render_dcc_wrapper();
|
||||
}
|
||||
|
||||
if ( $this->is_free_trial_cart() ) {
|
||||
|
@ -439,6 +381,74 @@ class SmartButton implements SmartButtonInterface {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers hooks and callbacks that are only relevant for DCC (ACDC) payments.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function render_dcc_wrapper(): void {
|
||||
add_action(
|
||||
$this->checkout_dcc_button_renderer_hook(),
|
||||
array( $this, 'dcc_renderer' ),
|
||||
11
|
||||
);
|
||||
|
||||
add_action(
|
||||
$this->pay_order_renderer_hook(),
|
||||
array( $this, 'dcc_renderer' ),
|
||||
11
|
||||
);
|
||||
|
||||
$subscription_helper = $this->subscription_helper;
|
||||
add_filter(
|
||||
'woocommerce_credit_card_form_fields',
|
||||
function ( array $default_fields, $id ) use ( $subscription_helper ) : array {
|
||||
if (
|
||||
CreditCardGateway::ID === $id
|
||||
&& is_user_logged_in()
|
||||
&& $this->settings->has( 'vault_enabled_dcc' )
|
||||
&& $this->settings->get( 'vault_enabled_dcc' )
|
||||
&& apply_filters( 'woocommerce_paypal_payments_should_render_card_custom_fields', true )
|
||||
) {
|
||||
|
||||
$default_fields['card-vault'] = sprintf(
|
||||
'<p class="form-row form-row-wide"><label for="ppcp-credit-card-vault"><input class="ppcp-credit-card-vault" type="checkbox" id="ppcp-credit-card-vault" name="vault">%s</label></p>',
|
||||
esc_html__( 'Save your Credit Card', 'woocommerce-paypal-payments' )
|
||||
);
|
||||
if ( $subscription_helper->cart_contains_subscription() || $subscription_helper->order_pay_contains_subscription() ) {
|
||||
$default_fields['card-vault'] = '';
|
||||
}
|
||||
|
||||
$tokens = $this->payment_token_repository->all_for_user_id( get_current_user_id() );
|
||||
if ( $tokens && $this->payment_token_repository->tokens_contains_card( $tokens ) ) {
|
||||
$output = sprintf(
|
||||
'<p class="form-row form-row-wide"><label>%1$s</label><select id="saved-credit-card" name="saved_credit_card"><option value="">%2$s</option>',
|
||||
esc_html__( 'Or select a saved Credit Card payment', 'woocommerce-paypal-payments' ),
|
||||
esc_html__( 'Choose a saved payment', 'woocommerce-paypal-payments' )
|
||||
);
|
||||
foreach ( $tokens as $token ) {
|
||||
if ( isset( $token->source()->card ) ) {
|
||||
$output .= sprintf(
|
||||
'<option value="%1$s">%2$s ...%3$s</option>',
|
||||
$token->id(),
|
||||
$token->source()->card->brand,
|
||||
$token->source()->card->last_digits
|
||||
);
|
||||
}
|
||||
}
|
||||
$output .= '</select></p>';
|
||||
|
||||
$default_fields['saved-credit-card'] = $output;
|
||||
}
|
||||
}
|
||||
|
||||
return $default_fields;
|
||||
},
|
||||
10,
|
||||
2
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the hooks to render the credit messaging HTML depending on the settings.
|
||||
*
|
||||
|
@ -719,9 +729,7 @@ document.querySelector("#payment").before(document.querySelector(".ppcp-messages
|
|||
* Whether DCC fields can be rendered.
|
||||
*/
|
||||
public function can_render_dcc() : bool {
|
||||
return $this->settings->has( 'dcc_enabled' ) && $this->settings->get( 'dcc_enabled' )
|
||||
&& $this->settings->has( 'client_id' ) && $this->settings->get( 'client_id' )
|
||||
&& $this->dcc_applies->for_country_currency()
|
||||
return $this->dcc_configuration->is_acdc_enabled()
|
||||
&& in_array(
|
||||
$this->context(),
|
||||
apply_filters( 'woocommerce_paypal_payments_can_render_dcc_contexts', array( 'checkout', 'pay-now', 'add-payment-method' ) ),
|
||||
|
@ -1114,6 +1122,7 @@ document.querySelector("#payment").before(document.querySelector(".ppcp-messages
|
|||
*/
|
||||
public function script_data(): array {
|
||||
$is_free_trial_cart = $this->is_free_trial_cart();
|
||||
$is_acdc_enabled = $this->dcc_configuration->is_acdc_enabled();
|
||||
|
||||
$url_params = $this->url_params();
|
||||
|
||||
|
@ -1125,7 +1134,7 @@ document.querySelector("#payment").before(document.querySelector(".ppcp-messages
|
|||
'client_id' => $this->client_id,
|
||||
'currency' => $this->currency->get(),
|
||||
'data_client_id' => array(
|
||||
'set_attribute' => ( is_checkout() && $this->dcc_is_enabled() ) || $this->can_save_vault_token(),
|
||||
'set_attribute' => ( is_checkout() && $is_acdc_enabled ) || $this->can_save_vault_token(),
|
||||
'endpoint' => \WC_AJAX::get_endpoint( DataClientIdEndpoint::ENDPOINT ),
|
||||
'nonce' => wp_create_nonce( DataClientIdEndpoint::nonce() ),
|
||||
'user' => get_current_user_id(),
|
||||
|
@ -1455,20 +1464,6 @@ document.querySelector("#payment").before(document.querySelector(".ppcp-messages
|
|||
$disabled_funding_sources[] = 'paylater';
|
||||
}
|
||||
|
||||
$disabled_funding_sources = array_filter(
|
||||
$disabled_funding_sources,
|
||||
/**
|
||||
* Make sure paypal is not sent in disable funding.
|
||||
*
|
||||
* @param string $funding_source The funding_source.
|
||||
*
|
||||
* @psalm-suppress MissingClosureParamType
|
||||
*/
|
||||
function( $funding_source ) {
|
||||
return $funding_source !== 'paypal';
|
||||
}
|
||||
);
|
||||
|
||||
if ( count( $disabled_funding_sources ) > 0 ) {
|
||||
$params['disable-funding'] = implode( ',', array_unique( $disabled_funding_sources ) );
|
||||
}
|
||||
|
@ -1574,7 +1569,6 @@ document.querySelector("#payment").before(document.querySelector(".ppcp-messages
|
|||
* The JS SKD components we need to load.
|
||||
*
|
||||
* @return array
|
||||
* @throws NotFoundException If a setting was not found.
|
||||
*/
|
||||
private function components(): array {
|
||||
$components = array();
|
||||
|
@ -1586,9 +1580,12 @@ document.querySelector("#payment").before(document.querySelector(".ppcp-messages
|
|||
if ( $this->should_load_messages() ) {
|
||||
$components[] = 'messages';
|
||||
}
|
||||
if ( $this->dcc_is_enabled() ) {
|
||||
|
||||
// Card payments are only available on a checkout page.
|
||||
if ( is_checkout() && $this->dcc_configuration->is_bcdc_enabled() ) {
|
||||
$components[] = 'hosted-fields';
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter to add further components from the extensions.
|
||||
*
|
||||
|
@ -1606,31 +1603,6 @@ document.querySelector("#payment").before(document.querySelector(".ppcp-messages
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether DCC is enabled or not.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function dcc_is_enabled(): bool {
|
||||
if ( ! is_checkout() ) {
|
||||
return false;
|
||||
}
|
||||
if ( ! $this->dcc_applies->for_country_currency() ) {
|
||||
return false;
|
||||
}
|
||||
$keys = array(
|
||||
'client_id',
|
||||
'client_secret',
|
||||
'dcc_enabled',
|
||||
);
|
||||
foreach ( $keys as $key ) {
|
||||
if ( ! $this->settings->has( $key ) || ! $this->settings->get( $key ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the style for a given property in a given context.
|
||||
*
|
||||
|
|
|
@ -5,14 +5,14 @@
|
|||
* @package WooCommerce\PayPalCommerce\Button\Helper
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
declare( strict_types = 1 );
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\Button\Helper;
|
||||
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CardButtonGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
use WooCommerce\PayPalCommerce\WcSubscriptions\FreeTrialHandlerTrait;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\CardPaymentsConfiguration;
|
||||
|
||||
/**
|
||||
* Class DisabledFundingSources
|
||||
|
@ -26,84 +26,187 @@ class DisabledFundingSources {
|
|||
*
|
||||
* @var Settings
|
||||
*/
|
||||
private $settings;
|
||||
private Settings $settings;
|
||||
|
||||
/**
|
||||
* All existing funding sources.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $all_funding_sources;
|
||||
private array $all_funding_sources;
|
||||
|
||||
/**
|
||||
* Provides details about the DCC configuration.
|
||||
*
|
||||
* @var CardPaymentsConfiguration
|
||||
*/
|
||||
private CardPaymentsConfiguration $dcc_configuration;
|
||||
|
||||
/**
|
||||
* DisabledFundingSources constructor.
|
||||
*
|
||||
* @param Settings $settings The settings.
|
||||
* @param array $all_funding_sources All existing funding sources.
|
||||
* @param Settings $settings The settings.
|
||||
* @param array $all_funding_sources All existing funding sources.
|
||||
* @param CardPaymentsConfiguration $dcc_configuration DCC gateway configuration.
|
||||
*/
|
||||
public function __construct( Settings $settings, array $all_funding_sources ) {
|
||||
public function __construct( Settings $settings, array $all_funding_sources, CardPaymentsConfiguration $dcc_configuration ) {
|
||||
$this->settings = $settings;
|
||||
$this->all_funding_sources = $all_funding_sources;
|
||||
$this->dcc_configuration = $dcc_configuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of funding sources to be disabled.
|
||||
*
|
||||
* @param string $context The context.
|
||||
* @return array|int[]|mixed|string[]
|
||||
* @throws NotFoundException When the setting is not found.
|
||||
* @return string[] List of disabled sources
|
||||
*/
|
||||
public function sources( string $context ) {
|
||||
$disable_funding = $this->settings->has( 'disable_funding' )
|
||||
? $this->settings->get( 'disable_funding' )
|
||||
: array();
|
||||
public function sources( string $context ) : array {
|
||||
$block_contexts = array( 'checkout-block', 'cart-block' );
|
||||
$flags = array(
|
||||
'context' => $context,
|
||||
'is_block_context' => in_array( $context, $block_contexts, true ),
|
||||
'is_free_trial' => $this->is_free_trial_cart(),
|
||||
);
|
||||
|
||||
$is_dcc_enabled = $this->settings->has( 'dcc_enabled' ) && $this->settings->get( 'dcc_enabled' );
|
||||
// Free trials have a shorter, special funding-source rule.
|
||||
if ( $flags['is_free_trial'] ) {
|
||||
$disable_funding = $this->get_sources_for_free_trial();
|
||||
|
||||
if (
|
||||
! is_checkout()
|
||||
|| ( $is_dcc_enabled && in_array( $context, array( 'checkout-block', 'cart-block' ), true ) )
|
||||
) {
|
||||
$disable_funding[] = 'card';
|
||||
return $this->sanitize_and_filter_sources( $disable_funding, $flags );
|
||||
}
|
||||
|
||||
$available_gateways = WC()->payment_gateways->get_available_payment_gateways();
|
||||
$is_separate_card_enabled = isset( $available_gateways[ CardButtonGateway::ID ] );
|
||||
$disable_funding = $this->get_sources_from_settings();
|
||||
|
||||
if (
|
||||
(
|
||||
is_checkout()
|
||||
&& ! in_array( $context, array( 'checkout-block', 'cart-block' ), true )
|
||||
)
|
||||
&& (
|
||||
$is_dcc_enabled
|
||||
|| $is_separate_card_enabled
|
||||
)
|
||||
) {
|
||||
$key = array_search( 'card', $disable_funding, true );
|
||||
if ( false !== $key ) {
|
||||
unset( $disable_funding[ $key ] );
|
||||
}
|
||||
// Apply rules based on context and payment methods.
|
||||
$disable_funding = $this->apply_context_rules( $disable_funding );
|
||||
|
||||
// Apply special rules for block checkout.
|
||||
if ( $flags['is_block_context'] ) {
|
||||
$disable_funding = $this->apply_block_checkout_rules( $disable_funding );
|
||||
}
|
||||
|
||||
if ( in_array( $context, array( 'checkout-block', 'cart-block' ), true ) ) {
|
||||
$disable_funding = array_merge(
|
||||
return $this->sanitize_and_filter_sources( $disable_funding, $flags );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets disabled funding sources from settings.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_sources_from_settings() : array {
|
||||
try {
|
||||
// Settings field present in the legacy UI.
|
||||
$disabled_funding = $this->settings->get( 'disable_funding' );
|
||||
} catch ( NotFoundException $exception ) {
|
||||
$disabled_funding = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the list of disabled funding methods. In the legacy UI, this
|
||||
* list was accessible via a settings field.
|
||||
*
|
||||
* This filter allows merchants to programmatically disable funding sources
|
||||
* in the new UI.
|
||||
*/
|
||||
return (array) apply_filters(
|
||||
'woocommerce_paypal_payments_disabled_funding',
|
||||
$disabled_funding
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets disabled funding sources for free trial carts.
|
||||
*
|
||||
* Rule: Carts that include a free trial product can ONLY use the
|
||||
* funding source "card" - all other sources are disabled.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_sources_for_free_trial() : array {
|
||||
// Disable all sources.
|
||||
$disable_funding = array_keys( $this->all_funding_sources );
|
||||
|
||||
if ( is_checkout() && $this->dcc_configuration->is_bcdc_enabled() ) {
|
||||
// If BCDC is used, re-enable card payments.
|
||||
$disable_funding = array_filter(
|
||||
$disable_funding,
|
||||
array_diff(
|
||||
array_keys( $this->all_funding_sources ),
|
||||
array( 'venmo', 'paylater', 'paypal', 'card' )
|
||||
)
|
||||
static fn( string $funding_source ) => $funding_source !== 'card'
|
||||
);
|
||||
}
|
||||
|
||||
if ( $this->is_free_trial_cart() ) {
|
||||
$all_sources = array_keys( $this->all_funding_sources );
|
||||
if ( $is_dcc_enabled || $is_separate_card_enabled ) {
|
||||
$all_sources = array_diff( $all_sources, array( 'card' ) );
|
||||
}
|
||||
$disable_funding = $all_sources;
|
||||
return $disable_funding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies rules based on context and payment methods.
|
||||
*
|
||||
* @param array $disable_funding The current disabled funding sources.
|
||||
* @return array
|
||||
*/
|
||||
private function apply_context_rules( array $disable_funding ) : array {
|
||||
if ( ! is_checkout() || $this->dcc_configuration->use_acdc() ) {
|
||||
// Non-checkout pages, or ACDC capability: Don't load card button.
|
||||
$disable_funding[] = 'card';
|
||||
|
||||
return $disable_funding;
|
||||
}
|
||||
|
||||
return apply_filters( 'woocommerce_paypal_payments_disabled_funding_sources', $disable_funding );
|
||||
return $disable_funding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies special rules for block checkout.
|
||||
*
|
||||
* @param array $disable_funding The current disabled funding sources.
|
||||
* @return array
|
||||
*/
|
||||
private function apply_block_checkout_rules( array $disable_funding ) : array {
|
||||
/**
|
||||
* Block checkout only supports the following funding methods:
|
||||
* - PayPal
|
||||
* - PayLater
|
||||
* - Venmo
|
||||
* - ACDC ("card", conditionally)
|
||||
*/
|
||||
$allowed_in_blocks = array( 'venmo', 'paylater', 'paypal', 'card' );
|
||||
|
||||
return array_merge(
|
||||
$disable_funding,
|
||||
array_diff( array_keys( $this->all_funding_sources ), $allowed_in_blocks )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the disabled "funding-sources" list and returns a sanitized array.
|
||||
*
|
||||
* @param array $disable_funding The disabled funding sources.
|
||||
* @param array $flags Decision flags.
|
||||
* @return string[]
|
||||
*/
|
||||
private function sanitize_and_filter_sources( array $disable_funding, array $flags ) : array {
|
||||
/**
|
||||
* Filters the final list of disabled funding sources.
|
||||
*
|
||||
* @param array $diabled_funding The filter value, funding sources to be disabled.
|
||||
* @param array $flags Decision flags to provide more context to filters.
|
||||
*/
|
||||
$disable_funding = apply_filters(
|
||||
'woocommerce_paypal_payments_sdk_disabled_funding_hook',
|
||||
$disable_funding,
|
||||
array(
|
||||
'context' => (string) ( $flags['context'] ?? '' ),
|
||||
'is_block_context' => (bool) ( $flags['is_block_context'] ?? false ),
|
||||
'is_free_trial' => (bool) ( $flags['is_free_trial'] ?? false ),
|
||||
)
|
||||
);
|
||||
|
||||
// Make sure "paypal" is never disabled in the funding-sources.
|
||||
$disable_funding = array_filter(
|
||||
$disable_funding,
|
||||
static fn( string $funding_source ) => $funding_source !== 'paypal'
|
||||
);
|
||||
|
||||
return array_unique( $disable_funding );
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue