Commit 953c595eab for woocommerce

commit 953c595eab549f339822c39ffadc089a084c81a2
Author: Wesley Rosa <wesleyjrosa@gmail.com>
Date:   Mon Dec 15 16:09:19 2025 -0300

    Avoid capturing orders requiring payer action in PayPal Standard (#62433)

    * Avoid capturing orders requiring payer action in PayPal Standard

    * Fix lint issues

    * Add changefile(s) from automation for the following project(s): woocommerce

    * Fix tests

    * Using constant

    ---------

    Co-authored-by: github-actions <github-actions@github.com>

diff --git a/plugins/woocommerce/changelog/62433-fix-avoid-capturing-orders-requiring-payer-action b/plugins/woocommerce/changelog/62433-fix-avoid-capturing-orders-requiring-payer-action
new file mode 100644
index 0000000000..426e12b180
--- /dev/null
+++ b/plugins/woocommerce/changelog/62433-fix-avoid-capturing-orders-requiring-payer-action
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Stores the PayPal Standard order status upon creation and skips capture when payer action is required.
\ No newline at end of file
diff --git a/plugins/woocommerce/includes/gateways/paypal/includes/class-wc-gateway-paypal-constants.php b/plugins/woocommerce/includes/gateways/paypal/includes/class-wc-gateway-paypal-constants.php
index 931af7b86a..a607ec3ce8 100644
--- a/plugins/woocommerce/includes/gateways/paypal/includes/class-wc-gateway-paypal-constants.php
+++ b/plugins/woocommerce/includes/gateways/paypal/includes/class-wc-gateway-paypal-constants.php
@@ -26,10 +26,12 @@ class WC_Gateway_Paypal_Constants {
 	/**
 	 * PayPal payment statuses.
 	 */
-	const STATUS_COMPLETED  = 'COMPLETED';
-	const STATUS_APPROVED   = 'APPROVED';
-	const STATUS_CAPTURED   = 'CAPTURED';
-	const STATUS_AUTHORIZED = 'AUTHORIZED';
+	const STATUS_COMPLETED             = 'COMPLETED';
+	const STATUS_APPROVED              = 'APPROVED';
+	const STATUS_CAPTURED              = 'CAPTURED';
+	const STATUS_AUTHORIZED            = 'AUTHORIZED';
+	const STATUS_PAYER_ACTION_REQUIRED = 'PAYER_ACTION_REQUIRED';
+	const VOIDED                       = 'VOIDED';

 	/**
 	 * PayPal payment intents.
diff --git a/plugins/woocommerce/includes/gateways/paypal/includes/class-wc-gateway-paypal-request.php b/plugins/woocommerce/includes/gateways/paypal/includes/class-wc-gateway-paypal-request.php
index a6e2e94dbd..450a2c9ba0 100644
--- a/plugins/woocommerce/includes/gateways/paypal/includes/class-wc-gateway-paypal-request.php
+++ b/plugins/woocommerce/includes/gateways/paypal/includes/class-wc-gateway-paypal-request.php
@@ -196,6 +196,9 @@ class WC_Gateway_Paypal_Request {
 			// Save the PayPal order ID to the order.
 			$order->update_meta_data( '_paypal_order_id', $response_data['id'] );

+			// Save the PayPal order status to the order.
+			$order->update_meta_data( '_paypal_status', $response_data['status'] );
+
 			// Remember the payment source: payment_source is not patchable.
 			// If the payment source is changed, we need to create a new PayPal order.
 			$order->update_meta_data( '_paypal_payment_source', $payment_source );
@@ -363,12 +366,25 @@ class WC_Gateway_Paypal_Request {
 		}

 		$paypal_status = $order->get_meta( '_paypal_status', true );
+
 		// Skip if the payment is already captured.
 		if ( WC_Gateway_Paypal_Constants::STATUS_CAPTURED === $paypal_status || WC_Gateway_Paypal_Constants::STATUS_COMPLETED === $paypal_status ) {
 			WC_Gateway_Paypal::log( 'PayPal payment is already captured. Skipping capture. Order ID: ' . $order->get_id() );
 			return;
 		}

+		// Skip if the payment requires payer action.
+		if ( WC_Gateway_Paypal_Constants::STATUS_PAYER_ACTION_REQUIRED === $paypal_status ) {
+			WC_Gateway_Paypal::log( 'PayPal payment requires payer action. Skipping capture. Order ID: ' . $order->get_id() );
+			return;
+		}
+
+		// Skip if the payment is voided.
+		if ( WC_Gateway_Paypal_Constants::VOIDED === $paypal_status ) {
+			WC_Gateway_Paypal::log( 'PayPal payment voided. Skipping capture. Order ID: ' . $order->get_id() );
+			return;
+		}
+
 		$authorization_id = $this->get_authorization_id_for_capture( $order );
 		if ( ! $authorization_id ) {
 			WC_Gateway_Paypal::log( 'Authorization ID not found to capture authorized payment. Order ID: ' . $order->get_id() );
@@ -557,7 +573,7 @@ class WC_Gateway_Paypal_Request {
 	 */
 	private function get_approve_link( $http_code, $response_data ) {
 		// See https://developer.paypal.com/docs/api/orders/v2/#orders_create.
-		if ( isset( $response_data['status'] ) && 'PAYER_ACTION_REQUIRED' === $response_data['status'] ) {
+		if ( isset( $response_data['status'] ) && WC_Gateway_Paypal_Constants::STATUS_PAYER_ACTION_REQUIRED === $response_data['status'] ) {
 			$rel = 'payer-action';
 		} else {
 			$rel = 'approve';
diff --git a/plugins/woocommerce/includes/gateways/paypal/includes/class-wc-gateway-paypal-webhook-handler.php b/plugins/woocommerce/includes/gateways/paypal/includes/class-wc-gateway-paypal-webhook-handler.php
index 43d2944c90..52996cd977 100644
--- a/plugins/woocommerce/includes/gateways/paypal/includes/class-wc-gateway-paypal-webhook-handler.php
+++ b/plugins/woocommerce/includes/gateways/paypal/includes/class-wc-gateway-paypal-webhook-handler.php
@@ -80,7 +80,7 @@ class WC_Gateway_Paypal_Webhook_Handler {

 		$status          = $event['resource']['status'] ?? null;
 		$paypal_order_id = $event['resource']['id'] ?? null;
-		if ( 'APPROVED' === $status ) {
+		if ( WC_Gateway_Paypal_Constants::STATUS_APPROVED === $status ) {
 			WC_Gateway_Paypal::log( 'PayPal payment approved. Order ID: ' . $order->get_id() );
 			$order->update_meta_data( '_paypal_status', $status );
 			$order->add_order_note(
diff --git a/plugins/woocommerce/tests/php/includes/gateways/paypal/class-wc-gateway-paypal-request-test.php b/plugins/woocommerce/tests/php/includes/gateways/paypal/class-wc-gateway-paypal-request-test.php
index 6f5266b897..fb94fa55c3 100644
--- a/plugins/woocommerce/tests/php/includes/gateways/paypal/class-wc-gateway-paypal-request-test.php
+++ b/plugins/woocommerce/tests/php/includes/gateways/paypal/class-wc-gateway-paypal-request-test.php
@@ -155,8 +155,9 @@ class WC_Gateway_Paypal_Request_Test extends \WC_Unit_Test_Case {
 			),
 			'body'     => wp_json_encode(
 				array(
-					'id'    => '123',
-					'links' => array(
+					'id'     => '123',
+					'status' => 'CREATED',
+					'links'  => array(
 						array(
 							'rel'    => 'approve',
 							'href'   => 'https://www.paypal.com/checkoutnow?token=123',