From 510a6c6913c8b13a0672a02a3e276e5e6f83bc2d Mon Sep 17 00:00:00 2001 From: Pedro Silva Date: Wed, 27 Mar 2024 11:50:40 +0000 Subject: [PATCH 1/4] Improve fraud prevention capabilities --- .../ppcp-button/src/Assets/SmartButton.php | 14 ++++++-- .../src/Endpoint/CreateOrderEndpoint.php | 9 ++++++ .../src/Helper/EarlyOrderHandler.php | 9 ++++++ .../ppcp-button/src/Helper/ThreeDSecure.php | 32 ++++++++++++++----- .../ppcp-card-fields/src/CardFieldsModule.php | 14 ++++---- .../src/SavePaymentMethodsModule.php | 6 +++- .../src/Gateway/PayPalGateway.php | 1 + .../CreditCardOrderInfoHandlingTrait.php | 7 ++-- .../src/Processor/OrderMetaTrait.php | 8 +++++ .../ppcp-wc-gateway/src/WCGatewayModule.php | 14 ++++++++ .../Vaulting/VaultedCreditCardHandlerTest.php | 3 ++ .../Gateway/OXXO/OXXOGatewayTest.php | 1 + .../Processor/OrderProcessorTest.php | 3 ++ 13 files changed, 102 insertions(+), 19 deletions(-) diff --git a/modules/ppcp-button/src/Assets/SmartButton.php b/modules/ppcp-button/src/Assets/SmartButton.php index 12e7abfbd..17e9810ab 100644 --- a/modules/ppcp-button/src/Assets/SmartButton.php +++ b/modules/ppcp-button/src/Assets/SmartButton.php @@ -990,11 +990,21 @@ document.querySelector("#payment").before(document.querySelector("#ppcp-messages if ( $this->settings->has( '3d_secure_contingency' ) ) { $value = $this->settings->get( '3d_secure_contingency' ); if ( $value ) { - return $value; + return $this->return_3ds_contingency( $value ); } } - return 'SCA_WHEN_REQUIRED'; + return $this->return_3ds_contingency( 'SCA_WHEN_REQUIRED' ); + } + + /** + * Processes and returns the 3D Secure contingency. + * + * @param string $contingency The ThreeD secure contingency. + * @return string + */ + private function return_3ds_contingency( string $contingency ): string { + return apply_filters( 'woocommerce_paypal_payments_three_d_secure_contingency', $contingency ); } /** diff --git a/modules/ppcp-button/src/Endpoint/CreateOrderEndpoint.php b/modules/ppcp-button/src/Endpoint/CreateOrderEndpoint.php index c286b9f20..980e03770 100644 --- a/modules/ppcp-button/src/Endpoint/CreateOrderEndpoint.php +++ b/modules/ppcp-button/src/Endpoint/CreateOrderEndpoint.php @@ -329,6 +329,15 @@ class CreateOrderEndpoint implements EndpointInterface { if ( 'pay-now' === $data['context'] && is_a( $wc_order, \WC_Order::class ) ) { $wc_order->update_meta_data( PayPalGateway::ORDER_ID_META_KEY, $order->id() ); $wc_order->update_meta_data( PayPalGateway::INTENT_META_KEY, $order->intent() ); + + $payer = $order->payer(); + if ( $payer ) { + $payer_email = $payer->email_address(); + if ( $payer_email ) { + $wc_order->update_meta_data( PayPalGateway::ORDER_PAYER_EMAIL_META_KEY, $payer_email ); + } + } + $wc_order->save_meta_data(); do_action( 'woocommerce_paypal_payments_woocommerce_order_created', $wc_order, $order ); diff --git a/modules/ppcp-button/src/Helper/EarlyOrderHandler.php b/modules/ppcp-button/src/Helper/EarlyOrderHandler.php index 03d8fbeed..adff6f56c 100644 --- a/modules/ppcp-button/src/Helper/EarlyOrderHandler.php +++ b/modules/ppcp-button/src/Helper/EarlyOrderHandler.php @@ -159,6 +159,15 @@ class EarlyOrderHandler { $wc_order = wc_get_order( $order_id ); $wc_order->update_meta_data( PayPalGateway::ORDER_ID_META_KEY, $order->id() ); $wc_order->update_meta_data( PayPalGateway::INTENT_META_KEY, $order->intent() ); + + $payer = $order->payer(); + if ( $payer && $wc_order instanceof \WC_Order ) { + $payer_email = $payer->email_address(); + if ( $payer_email ) { + $wc_order->update_meta_data( PayPalGateway::ORDER_PAYER_EMAIL_META_KEY, $payer_email ); + } + } + $wc_order->save_meta_data(); /** diff --git a/modules/ppcp-button/src/Helper/ThreeDSecure.php b/modules/ppcp-button/src/Helper/ThreeDSecure.php index 66c89e4be..1991112b5 100644 --- a/modules/ppcp-button/src/Helper/ThreeDSecure.php +++ b/modules/ppcp-button/src/Helper/ThreeDSecure.php @@ -57,21 +57,24 @@ class ThreeDSecure { * * @link https://developer.paypal.com/docs/business/checkout/add-capabilities/3d-secure/#authenticationresult * - * @param Order $order The order for which the decission is needed. + * @param Order $order The order for which the decision is needed. * * @return int */ public function proceed_with_order( Order $order ): int { + + do_action( 'woocommerce_paypal_payments_three_d_secure_before_check', $order ); + $payment_source = $order->payment_source(); if ( ! $payment_source ) { - return self::NO_DECISION; + return $this->return_decision( self::NO_DECISION, $order ); } if ( ! ( $payment_source->properties()->brand ?? '' ) ) { - return self::NO_DECISION; + return $this->return_decision( self::NO_DECISION, $order ); } if ( ! ( $payment_source->properties()->authentication_result ?? '' ) ) { - return self::NO_DECISION; + return $this->return_decision( self::NO_DECISION, $order ); } $authentication_result = $payment_source->properties()->authentication_result ?? null; @@ -81,18 +84,31 @@ class ThreeDSecure { $this->logger->info( '3DS Authentication Result: ' . wc_print_r( $result->to_array(), true ) ); if ( $result->liability_shift() === AuthResult::LIABILITY_SHIFT_POSSIBLE ) { - return self::PROCCEED; + return $this->return_decision( self::PROCCEED, $order ); } if ( $result->liability_shift() === AuthResult::LIABILITY_SHIFT_UNKNOWN ) { - return self::RETRY; + return $this->return_decision( self::RETRY, $order ); } if ( $result->liability_shift() === AuthResult::LIABILITY_SHIFT_NO ) { - return $this->no_liability_shift( $result ); + return $this->return_decision( $this->no_liability_shift( $result ), $order ); } } - return self::NO_DECISION; + return $this->return_decision( self::NO_DECISION, $order ); + } + + /** + * Processes and returns a ThreeD secure decision. + * + * @param int $decision The ThreeD secure decision. + * @param Order $order The PayPal Order object. + * @return int + */ + public function return_decision( int $decision, Order $order ) { + $decision = apply_filters( 'woocommerce_paypal_payments_three_d_secure_decision', $decision, $order ); + do_action( 'woocommerce_paypal_payments_three_d_secure_after_check', $order, $decision ); + return $decision; } /** diff --git a/modules/ppcp-card-fields/src/CardFieldsModule.php b/modules/ppcp-card-fields/src/CardFieldsModule.php index 213134857..6835108c3 100644 --- a/modules/ppcp-card-fields/src/CardFieldsModule.php +++ b/modules/ppcp-card-fields/src/CardFieldsModule.php @@ -115,17 +115,19 @@ class CardFieldsModule implements ModuleInterface { $settings = $c->get( 'wcgateway.settings' ); assert( $settings instanceof Settings ); + $three_d_secure_contingency = + $settings->has( '3d_secure_contingency' ) + ? apply_filters( 'woocommerce_paypal_payments_three_d_secure_contingency', $settings->get( '3d_secure_contingency' ) ) + : ''; + if ( - $settings->has( '3d_secure_contingency' ) - && ( - $settings->get( '3d_secure_contingency' ) === 'SCA_ALWAYS' - || $settings->get( '3d_secure_contingency' ) === 'SCA_WHEN_REQUIRED' - ) + $three_d_secure_contingency === 'SCA_ALWAYS' + || $three_d_secure_contingency === 'SCA_WHEN_REQUIRED' ) { $data['payment_source']['card'] = array( 'attributes' => array( 'verification' => array( - 'method' => $settings->get( '3d_secure_contingency' ), + 'method' => $three_d_secure_contingency, ), ), ); diff --git a/modules/ppcp-save-payment-methods/src/SavePaymentMethodsModule.php b/modules/ppcp-save-payment-methods/src/SavePaymentMethodsModule.php index 59010f6ca..667175aaf 100644 --- a/modules/ppcp-save-payment-methods/src/SavePaymentMethodsModule.php +++ b/modules/ppcp-save-payment-methods/src/SavePaymentMethodsModule.php @@ -281,7 +281,11 @@ class SavePaymentMethodsModule implements ModuleInterface { $settings = $c->get( 'wcgateway.settings' ); assert( $settings instanceof Settings ); - $verification_method = $settings->has( '3d_secure_contingency' ) ? $settings->get( '3d_secure_contingency' ) : ''; + + $verification_method = + $settings->has( '3d_secure_contingency' ) + ? apply_filters( 'woocommerce_paypal_payments_three_d_secure_contingency', $settings->get( '3d_secure_contingency' ) ) + : ''; $change_payment_method = wc_clean( wp_unslash( $_GET['change_payment_method'] ?? '' ) ); // phpcs:ignore WordPress.Security.NonceVerification diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php b/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php index 73afb085b..2a04aa478 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php @@ -48,6 +48,7 @@ class PayPalGateway extends \WC_Payment_Gateway { const ORDER_ID_META_KEY = '_ppcp_paypal_order_id'; const ORDER_PAYMENT_MODE_META_KEY = '_ppcp_paypal_payment_mode'; const ORDER_PAYMENT_SOURCE_META_KEY = '_ppcp_paypal_payment_source'; + const ORDER_PAYER_EMAIL_META_KEY = '_ppcp_paypal_payer_email'; const FEES_META_KEY = '_ppcp_paypal_fees'; const REFUND_FEES_META_KEY = '_ppcp_paypal_refund_fees'; const REFUNDS_META_KEY = '_ppcp_refunds'; diff --git a/modules/ppcp-wc-gateway/src/Processor/CreditCardOrderInfoHandlingTrait.php b/modules/ppcp-wc-gateway/src/Processor/CreditCardOrderInfoHandlingTrait.php index 32569c60b..281045099 100644 --- a/modules/ppcp-wc-gateway/src/Processor/CreditCardOrderInfoHandlingTrait.php +++ b/modules/ppcp-wc-gateway/src/Processor/CreditCardOrderInfoHandlingTrait.php @@ -52,6 +52,7 @@ trait CreditCardOrderInfoHandlingTrait {
  • %1$s
  • %2$s
  • %3$s
  • +
  • %4$s
  • '; $three_d_response_order_note_result = sprintf( $three_d_response_order_note_result_format, @@ -60,7 +61,9 @@ trait CreditCardOrderInfoHandlingTrait { /* translators: %s is enrollment status */ sprintf( __( 'Enrollment Status: %s', 'woocommerce-paypal-payments' ), esc_html( $result->enrollment_status() ) ), /* translators: %s is authentication status */ - sprintf( __( 'Authentication Status: %s', 'woocommerce-paypal-payments' ), esc_html( $result->authentication_result() ) ) + sprintf( __( 'Authentication Status: %s', 'woocommerce-paypal-payments' ), esc_html( $result->authentication_result() ) ), + /* translators: %s card last digits */ + sprintf( __( 'Card Last Digits: %s', 'woocommerce-paypal-payments' ), esc_html( $payment_source->properties()->last_digits ?? '' ) ) ); $three_d_response_order_note = sprintf( $three_d_response_order_note_format, @@ -76,7 +79,7 @@ trait CreditCardOrderInfoHandlingTrait { /** * Fired when the 3DS information is added to WC order. */ - do_action( 'woocommerce_paypal_payments_thee_d_secure_added', $wc_order, $order ); + do_action( 'woocommerce_paypal_payments_three_d_secure_added', $wc_order, $order ); } } diff --git a/modules/ppcp-wc-gateway/src/Processor/OrderMetaTrait.php b/modules/ppcp-wc-gateway/src/Processor/OrderMetaTrait.php index b18468d7b..1d9b87a2f 100644 --- a/modules/ppcp-wc-gateway/src/Processor/OrderMetaTrait.php +++ b/modules/ppcp-wc-gateway/src/Processor/OrderMetaTrait.php @@ -45,6 +45,14 @@ trait OrderMetaTrait { $wc_order->update_meta_data( PayPalGateway::ORDER_PAYMENT_SOURCE_META_KEY, $payment_source ); } + $payer = $order->payer(); + if ( $payer ) { + $payer_email = $payer->email_address(); + if ( $payer_email ) { + $wc_order->update_meta_data( PayPalGateway::ORDER_PAYER_EMAIL_META_KEY, $payer_email ); + } + } + $wc_order->save(); do_action( 'woocommerce_paypal_payments_woocommerce_order_created', $wc_order, $order ); diff --git a/modules/ppcp-wc-gateway/src/WCGatewayModule.php b/modules/ppcp-wc-gateway/src/WCGatewayModule.php index e82f65e9e..03241f555 100644 --- a/modules/ppcp-wc-gateway/src/WCGatewayModule.php +++ b/modules/ppcp-wc-gateway/src/WCGatewayModule.php @@ -448,6 +448,20 @@ class WCGatewayModule implements ModuleInterface { delete_transient( 'ppcp_reference_transaction_enabled' ); } ); + + add_action( + 'woocommerce_admin_order_data_after_billing_address', + function ( \WC_Order $wc_order ) { + if ( ! apply_filters( 'woocommerce_paypal_payments_order_details_show_paypal_email', true ) ) { + return; + } + + $email = $wc_order->get_meta( PayPalGateway::ORDER_PAYER_EMAIL_META_KEY ) ?: ''; + if ( $email ) { + echo '

    ' . esc_html__( 'PayPal buyer account', 'woocommerce-paypal-payments' ) . ':
    ' . esc_attr( $email ) . '

    '; + } + } + ); } /** diff --git a/tests/PHPUnit/Vaulting/VaultedCreditCardHandlerTest.php b/tests/PHPUnit/Vaulting/VaultedCreditCardHandlerTest.php index fb728709a..c7d176c8e 100644 --- a/tests/PHPUnit/Vaulting/VaultedCreditCardHandlerTest.php +++ b/tests/PHPUnit/Vaulting/VaultedCreditCardHandlerTest.php @@ -92,6 +92,8 @@ class VaultedCreditCardHandlerTest extends TestCase $customer = Mockery::mock(WC_Customer::class); $payer = Mockery::mock(Payer::class); + $payer->shouldReceive('email_address'); + $this->payerFactory->shouldReceive('from_wc_order') ->andReturn($payer); $this->shippingPreferenceFactory->shouldReceive('from_state') @@ -100,6 +102,7 @@ class VaultedCreditCardHandlerTest extends TestCase $order = Mockery::mock(Order::class); $order->shouldReceive('id')->andReturn('1'); $order->shouldReceive('intent')->andReturn('CAPTURE'); + $order->shouldReceive('payer')->andReturn($payer); $paymentSource = Mockery::mock(PaymentSource::class); $paymentSource->shouldReceive('name')->andReturn('card'); diff --git a/tests/PHPUnit/WcGateway/Gateway/OXXO/OXXOGatewayTest.php b/tests/PHPUnit/WcGateway/Gateway/OXXO/OXXOGatewayTest.php index abff51a10..0f70f801c 100644 --- a/tests/PHPUnit/WcGateway/Gateway/OXXO/OXXOGatewayTest.php +++ b/tests/PHPUnit/WcGateway/Gateway/OXXO/OXXOGatewayTest.php @@ -89,6 +89,7 @@ private $testee; $order->shouldReceive('id')->andReturn('1'); $order->shouldReceive('intent'); $order->shouldReceive('payment_source'); + $order->shouldReceive('payer'); $this->orderEndpoint ->shouldReceive('create') diff --git a/tests/PHPUnit/WcGateway/Processor/OrderProcessorTest.php b/tests/PHPUnit/WcGateway/Processor/OrderProcessorTest.php index d27ec6ff7..95f1b7b48 100644 --- a/tests/PHPUnit/WcGateway/Processor/OrderProcessorTest.php +++ b/tests/PHPUnit/WcGateway/Processor/OrderProcessorTest.php @@ -93,6 +93,7 @@ class OrderProcessorTest extends TestCase $currentOrder ->shouldReceive('payment_source') ->andReturn(null); + $currentOrder->shouldReceive('payer'); $wcOrder ->shouldReceive('get_meta') @@ -230,6 +231,7 @@ class OrderProcessorTest extends TestCase $currentOrder ->shouldReceive('payment_source') ->andReturn(null); + $currentOrder->shouldReceive('payer'); $wcOrder ->shouldReceive('get_meta') @@ -357,6 +359,7 @@ class OrderProcessorTest extends TestCase $currentOrder ->shouldReceive('purchase_units') ->andReturn([$purchaseUnit]); + $currentOrder->shouldReceive('payer'); $wcOrder ->shouldReceive('get_meta') From 54ebb93383fe578bab1bd331b2f376efa958f2e5 Mon Sep 17 00:00:00 2001 From: Pedro Silva Date: Thu, 28 Mar 2024 15:02:22 +0000 Subject: [PATCH 2/4] Fix fraud prevention data presentation. --- .../src/Endpoint/CreateOrderEndpoint.php | 10 ++++++++-- .../ppcp-button/src/Helper/EarlyOrderHandler.php | 11 +++++++++-- .../ppcp-wc-gateway/src/Gateway/PayPalGateway.php | 5 +++++ .../CreditCardOrderInfoHandlingTrait.php | 15 ++++++++------- .../src/Processor/OrderMetaTrait.php | 6 +++++- modules/ppcp-wc-gateway/src/WCGatewayModule.php | 2 +- 6 files changed, 36 insertions(+), 13 deletions(-) diff --git a/modules/ppcp-button/src/Endpoint/CreateOrderEndpoint.php b/modules/ppcp-button/src/Endpoint/CreateOrderEndpoint.php index 980e03770..1ef06c3be 100644 --- a/modules/ppcp-button/src/Endpoint/CreateOrderEndpoint.php +++ b/modules/ppcp-button/src/Endpoint/CreateOrderEndpoint.php @@ -330,8 +330,14 @@ class CreateOrderEndpoint implements EndpointInterface { $wc_order->update_meta_data( PayPalGateway::ORDER_ID_META_KEY, $order->id() ); $wc_order->update_meta_data( PayPalGateway::INTENT_META_KEY, $order->intent() ); - $payer = $order->payer(); - if ( $payer ) { + $payment_source = $order->payment_source(); + $payment_source_name = $payment_source ? $payment_source->name() : null; + $payer = $order->payer(); + if ( + $payer + && $payment_source_name + && in_array( $payment_source_name, PayPalGateway::PAYMENT_SOURCES_WITH_PAYER_EMAIL, true ) + ) { $payer_email = $payer->email_address(); if ( $payer_email ) { $wc_order->update_meta_data( PayPalGateway::ORDER_PAYER_EMAIL_META_KEY, $payer_email ); diff --git a/modules/ppcp-button/src/Helper/EarlyOrderHandler.php b/modules/ppcp-button/src/Helper/EarlyOrderHandler.php index adff6f56c..46b4ddf41 100644 --- a/modules/ppcp-button/src/Helper/EarlyOrderHandler.php +++ b/modules/ppcp-button/src/Helper/EarlyOrderHandler.php @@ -160,8 +160,15 @@ class EarlyOrderHandler { $wc_order->update_meta_data( PayPalGateway::ORDER_ID_META_KEY, $order->id() ); $wc_order->update_meta_data( PayPalGateway::INTENT_META_KEY, $order->intent() ); - $payer = $order->payer(); - if ( $payer && $wc_order instanceof \WC_Order ) { + $payment_source = $order->payment_source(); + $payment_source_name = $payment_source ? $payment_source->name() : null; + $payer = $order->payer(); + if ( + $payer + && $payment_source_name + && in_array( $payment_source_name, PayPalGateway::PAYMENT_SOURCES_WITH_PAYER_EMAIL, true ) + && $wc_order instanceof \WC_Order + ) { $payer_email = $payer->email_address(); if ( $payer_email ) { $wc_order->update_meta_data( PayPalGateway::ORDER_PAYER_EMAIL_META_KEY, $payer_email ); diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php b/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php index 2a04aa478..19ebe9d08 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php @@ -55,6 +55,11 @@ class PayPalGateway extends \WC_Payment_Gateway { const THREE_D_AUTH_RESULT_META_KEY = '_ppcp_paypal_3DS_auth_result'; const FRAUD_RESULT_META_KEY = '_ppcp_paypal_fraud_result'; + /** + * List of payment sources wich we are expected to store the payer email in the WC Order metadata. + */ + const PAYMENT_SOURCES_WITH_PAYER_EMAIL = array( 'paypal', 'paylater', 'venmo' ); + /** * The Settings Renderer. * diff --git a/modules/ppcp-wc-gateway/src/Processor/CreditCardOrderInfoHandlingTrait.php b/modules/ppcp-wc-gateway/src/Processor/CreditCardOrderInfoHandlingTrait.php index 281045099..4cd9e07ed 100644 --- a/modules/ppcp-wc-gateway/src/Processor/CreditCardOrderInfoHandlingTrait.php +++ b/modules/ppcp-wc-gateway/src/Processor/CreditCardOrderInfoHandlingTrait.php @@ -52,7 +52,6 @@ trait CreditCardOrderInfoHandlingTrait {
  • %1$s
  • %2$s
  • %3$s
  • -
  • %4$s
  • '; $three_d_response_order_note_result = sprintf( $three_d_response_order_note_result_format, @@ -61,9 +60,7 @@ trait CreditCardOrderInfoHandlingTrait { /* translators: %s is enrollment status */ sprintf( __( 'Enrollment Status: %s', 'woocommerce-paypal-payments' ), esc_html( $result->enrollment_status() ) ), /* translators: %s is authentication status */ - sprintf( __( 'Authentication Status: %s', 'woocommerce-paypal-payments' ), esc_html( $result->authentication_result() ) ), - /* translators: %s card last digits */ - sprintf( __( 'Card Last Digits: %s', 'woocommerce-paypal-payments' ), esc_html( $payment_source->properties()->last_digits ?? '' ) ) + sprintf( __( 'Authentication Status: %s', 'woocommerce-paypal-payments' ), esc_html( $result->authentication_result() ) ) ); $three_d_response_order_note = sprintf( $three_d_response_order_note_format, @@ -99,8 +96,9 @@ trait CreditCardOrderInfoHandlingTrait { return; } - $fraud_responses = $fraud->to_array(); - $card_brand = $payment_source->properties()->brand ?? __( 'N/A', 'woocommerce-paypal-payments' ); + $fraud_responses = $fraud->to_array(); + $card_brand = $payment_source->properties()->brand ?? __( 'N/A', 'woocommerce-paypal-payments' ); + $card_last_digits = $payment_source->properties()->last_digits ?? __( 'N/A', 'woocommerce-paypal-payments' ); $avs_response_order_note_title = __( 'Address Verification Result', 'woocommerce-paypal-payments' ); /* translators: %1$s is AVS order note title, %2$s is AVS order note result markup */ @@ -112,6 +110,7 @@ trait CreditCardOrderInfoHandlingTrait {
  • %3$s
  • %4$s
  • +
  • %5$s
  • '; $avs_response_order_note_result = sprintf( $avs_response_order_note_result_format, @@ -122,7 +121,9 @@ trait CreditCardOrderInfoHandlingTrait { /* translators: %s is fraud AVS postal match */ sprintf( __( 'Postal Match: %s', 'woocommerce-paypal-payments' ), esc_html( $fraud_responses['postal_match'] ) ), /* translators: %s is card brand */ - sprintf( __( 'Card Brand: %s', 'woocommerce-paypal-payments' ), esc_html( $card_brand ) ) + sprintf( __( 'Card Brand: %s', 'woocommerce-paypal-payments' ), esc_html( $card_brand ) ), + /* translators: %s card last digits */ + sprintf( __( 'Card Last Digits: %s', 'woocommerce-paypal-payments' ), esc_html( $card_last_digits ) ) ); $avs_response_order_note = sprintf( $avs_response_order_note_format, diff --git a/modules/ppcp-wc-gateway/src/Processor/OrderMetaTrait.php b/modules/ppcp-wc-gateway/src/Processor/OrderMetaTrait.php index 1d9b87a2f..62a80456a 100644 --- a/modules/ppcp-wc-gateway/src/Processor/OrderMetaTrait.php +++ b/modules/ppcp-wc-gateway/src/Processor/OrderMetaTrait.php @@ -46,7 +46,11 @@ trait OrderMetaTrait { } $payer = $order->payer(); - if ( $payer ) { + if ( + $payer + && $payment_source + && in_array( $payment_source, PayPalGateway::PAYMENT_SOURCES_WITH_PAYER_EMAIL, true ) + ) { $payer_email = $payer->email_address(); if ( $payer_email ) { $wc_order->update_meta_data( PayPalGateway::ORDER_PAYER_EMAIL_META_KEY, $payer_email ); diff --git a/modules/ppcp-wc-gateway/src/WCGatewayModule.php b/modules/ppcp-wc-gateway/src/WCGatewayModule.php index 03241f555..7a8ef6d48 100644 --- a/modules/ppcp-wc-gateway/src/WCGatewayModule.php +++ b/modules/ppcp-wc-gateway/src/WCGatewayModule.php @@ -458,7 +458,7 @@ class WCGatewayModule implements ModuleInterface { $email = $wc_order->get_meta( PayPalGateway::ORDER_PAYER_EMAIL_META_KEY ) ?: ''; if ( $email ) { - echo '

    ' . esc_html__( 'PayPal buyer account', 'woocommerce-paypal-payments' ) . ':
    ' . esc_attr( $email ) . '

    '; + echo '

    ' . esc_html__( 'PayPal email address', 'woocommerce-paypal-payments' ) . ':
    ' . esc_attr( $email ) . '

    '; } } ); From 585c4e76cf59e6dd7032ddc1b4c5d40d97db11fb Mon Sep 17 00:00:00 2001 From: Pedro Silva Date: Mon, 1 Apr 2024 16:32:07 +0100 Subject: [PATCH 3/4] Refactor paypal email display in order detail. --- .../ppcp-wc-gateway/src/WCGatewayModule.php | 37 +++++++++++++++---- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/modules/ppcp-wc-gateway/src/WCGatewayModule.php b/modules/ppcp-wc-gateway/src/WCGatewayModule.php index 7a8ef6d48..d0e57e5de 100644 --- a/modules/ppcp-wc-gateway/src/WCGatewayModule.php +++ b/modules/ppcp-wc-gateway/src/WCGatewayModule.php @@ -449,17 +449,38 @@ class WCGatewayModule implements ModuleInterface { } ); - add_action( - 'woocommerce_admin_order_data_after_billing_address', - function ( \WC_Order $wc_order ) { - if ( ! apply_filters( 'woocommerce_paypal_payments_order_details_show_paypal_email', true ) ) { - return; + /** + * Param types removed to avoid third-party issues. + * + * @psalm-suppress MissingClosureParamType + */ + add_filter( + 'woocommerce_admin_billing_fields', + function ( $fields ) { + global $theorder; + + if ( ! is_array( $fields ) ) { + return $fields; } - $email = $wc_order->get_meta( PayPalGateway::ORDER_PAYER_EMAIL_META_KEY ) ?: ''; - if ( $email ) { - echo '

    ' . esc_html__( 'PayPal email address', 'woocommerce-paypal-payments' ) . ':
    ' . esc_attr( $email ) . '

    '; + if ( ! $theorder instanceof WC_Order ) { + return $fields; } + + $email = $theorder->get_meta( PayPalGateway::ORDER_PAYER_EMAIL_META_KEY ) ?: ''; + + if ( ! $email ) { + return $fields; + } + + $fields['paypal_email'] = array( + 'label' => __( 'PayPal email address', 'woocommerce-paypal-payments' ), + 'value' => $email, + 'wrapper_class' => 'form-field-wide', + 'custom_attributes' => array( 'disabled' => 'disabled' ), + ); + + return $fields; } ); } From 48f9efbfd4bfcc22488fef7e191102773cda0b43 Mon Sep 17 00:00:00 2001 From: Pedro Silva Date: Tue, 2 Apr 2024 11:19:00 +0100 Subject: [PATCH 4/4] Fix display of paypal email when funding source is not paypal. --- modules/ppcp-wc-gateway/src/WCGatewayModule.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/modules/ppcp-wc-gateway/src/WCGatewayModule.php b/modules/ppcp-wc-gateway/src/WCGatewayModule.php index d0e57e5de..4295b1b17 100644 --- a/modules/ppcp-wc-gateway/src/WCGatewayModule.php +++ b/modules/ppcp-wc-gateway/src/WCGatewayModule.php @@ -473,6 +473,14 @@ class WCGatewayModule implements ModuleInterface { return $fields; } + // Is payment source is paypal exclude all non paypal funding sources. + $payment_source = $theorder->get_meta( PayPalGateway::ORDER_PAYMENT_SOURCE_META_KEY ) ?: ''; + $is_paypal_funding_source = ( strpos( $theorder->get_payment_method_title(), '(via PayPal)' ) === false ); + + if ( $payment_source === 'paypal' && ! $is_paypal_funding_source ) { + return $fields; + } + $fields['paypal_email'] = array( 'label' => __( 'PayPal email address', 'woocommerce-paypal-payments' ), 'value' => $email,