Skip to content

Commit 96084e2

Browse files
authored
Merge pull request #4493 from woocommerce/dev/PCP-6143-PCP-6220-express-checkout-pay-now-continuation-fix
Allow Apple Pay / Google Pay to complete when Pay Now is disabled (6143 / 6220)
2 parents f347225 + 591802d commit 96084e2

2 files changed

Lines changed: 131 additions & 1 deletion

File tree

modules/ppcp-button/src/Endpoint/ApproveOrderEndpoint.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,8 @@ public function handle_request(): void {
269269
}
270270

271271
$should_create_wc_order = $data['should_create_wc_order'] ?? false;
272-
if ( ! $this->final_review_enabled && ! $this->context->is_checkout() && $should_create_wc_order ) {
272+
$is_express_checkout = in_array( $funding_source, array( 'apple_pay', 'googlepay' ), true );
273+
if ( ( ! $this->final_review_enabled || $is_express_checkout ) && ! $this->context->is_checkout() && $should_create_wc_order ) {
273274
$wc_order = $this->wc_order_creator->create_from_paypal_order( $order, WC()->cart, $data );
274275
$this->gateway->process_payment( $wc_order->get_id() );
275276
$order_received_url = $wc_order->get_checkout_order_received_url();

tests/PHPUnit/Button/Endpoint/ApproveOrderEndpointTest.php

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,4 +240,133 @@ public function test_valid_order_session_proceeds_to_replace_order(): void
240240

241241
// Then — replace_order called with the correct order and success response sent
242242
}
243+
244+
/**
245+
* Creates a SUT instance with final_review_enabled set to true (Pay Now disabled).
246+
*/
247+
private function create_sut_with_final_review( bool $final_review_enabled ): ApproveOrderEndpoint
248+
{
249+
return new ApproveOrderEndpoint(
250+
$this->request_data,
251+
$this->api_endpoint,
252+
$this->session_handler,
253+
$this->threed_secure,
254+
$this->settings_provider,
255+
$this->settings_model,
256+
$this->dcc_applies,
257+
$this->order_helper,
258+
$final_review_enabled,
259+
$this->gateway,
260+
$this->wc_order_creator,
261+
$this->logger,
262+
$this->context
263+
);
264+
}
265+
266+
/**
267+
* Sets up common mocks for the WC order creation flow tests.
268+
*
269+
* @return Order&\Mockery\MockInterface
270+
*/
271+
private function arrange_order_creation_flow( string $order_id, string $funding_source, bool $should_create_wc_order ): Order
272+
{
273+
$session_id = 'test-session';
274+
$purchase_unit = Mockery::mock( PurchaseUnit::class );
275+
$purchase_unit->shouldReceive( 'custom_id' )->andReturn( 'pcp_customer_' . $session_id );
276+
277+
$order_status = Mockery::mock( OrderStatus::class );
278+
$order_status->shouldReceive( 'is' )->andReturn( true );
279+
280+
$order = Mockery::mock( Order::class );
281+
$order->shouldReceive( 'purchase_units' )->andReturn( array( $purchase_unit ) );
282+
$order->shouldReceive( 'payment_source' )->andReturn( null );
283+
$order->shouldReceive( 'status' )->andReturn( $order_status );
284+
285+
$this->request_data->shouldReceive( 'read_request' )
286+
->with( ApproveOrderEndpoint::nonce() )
287+
->andReturn( array(
288+
'order_id' => $order_id,
289+
'funding_source' => $funding_source,
290+
'should_create_wc_order' => $should_create_wc_order,
291+
) );
292+
$this->api_endpoint->shouldReceive( 'order' )->with( $order_id )->andReturn( $order );
293+
$this->session_handler->shouldReceive( 'replace_funding_source' )->once();
294+
$this->session_handler->shouldReceive( 'replace_order' )->once();
295+
$this->context->shouldReceive( 'is_checkout' )->andReturn( false );
296+
297+
$wc_session = Mockery::mock( \WC_Session_Handler::class );
298+
$wc_session->shouldReceive( 'get_customer_unique_id' )->andReturn( $session_id );
299+
$wc_session->shouldReceive( 'set' );
300+
$wc_cart = Mockery::mock( \WC_Cart::class );
301+
$wc = Mockery::mock();
302+
$wc->session = $wc_session;
303+
$wc->cart = $wc_cart;
304+
when( 'WC' )->justReturn( $wc );
305+
306+
return $order;
307+
}
308+
309+
/**
310+
* @scenario When final_review_enabled=true (Pay Now disabled) and funding_source is express checkout,
311+
* the express checkout bypass should create a WC order and process payment.
312+
*
313+
* @dataProvider express_checkout_funding_sources
314+
*/
315+
public function test_express_checkout_creates_wc_order_even_with_final_review_enabled( string $funding_source ): void
316+
{
317+
// Arrange
318+
$sut = $this->create_sut_with_final_review( true );
319+
$order = $this->arrange_order_creation_flow( 'EXPRESS-ORDER', $funding_source, true );
320+
321+
$wc_order = Mockery::mock( \WC_Order::class );
322+
$wc_order->shouldReceive( 'get_id' )->andReturn( 42 );
323+
$wc_order->shouldReceive( 'get_checkout_order_received_url' )->andReturn( 'https://example.com/order-received/42' );
324+
325+
$this->wc_order_creator->shouldReceive( 'create_from_paypal_order' )->once()->andReturn( $wc_order );
326+
$this->gateway->shouldReceive( 'process_payment' )->once()->with( 42 );
327+
328+
expect( 'wp_send_json_success' )->once()->with(
329+
Mockery::on( static function ( $data ) {
330+
return isset( $data['order_received_url'] );
331+
} )
332+
);
333+
334+
// When
335+
$sut->handle_request();
336+
337+
// Then — WC order created and payment processed despite final_review_enabled=true
338+
}
339+
340+
/**
341+
* Data provider for express checkout funding sources.
342+
*/
343+
public static function express_checkout_funding_sources(): array
344+
{
345+
return array(
346+
'Apple Pay' => array( 'apple_pay' ),
347+
'Google Pay' => array( 'googlepay' ),
348+
);
349+
}
350+
351+
/**
352+
* @scenario When final_review_enabled=true and funding_source is 'paypal' (standard flow),
353+
* no WC order should be created — the user must complete checkout manually.
354+
*/
355+
public function test_standard_paypal_does_not_create_wc_order_when_final_review_enabled(): void
356+
{
357+
// Arrange
358+
$sut = $this->create_sut_with_final_review( true );
359+
$this->arrange_order_creation_flow( 'PAYPAL-ORDER', 'paypal', true );
360+
361+
$this->wc_order_creator->shouldReceive( 'create_from_paypal_order' )->never();
362+
$this->gateway->shouldReceive( 'process_payment' )->never();
363+
364+
expect( 'wp_send_json_success' )->once();
365+
366+
// When
367+
$sut->handle_request();
368+
369+
// Then — no WC order creation, standard continuation flow
370+
}
371+
243372
}

0 commit comments

Comments
 (0)