Skip to content

Commit

Permalink
moving hooks in more appropriate places
Browse files Browse the repository at this point in the history
  • Loading branch information
dpanta94 committed Jan 10, 2025
1 parent dc4c544 commit 6e391a3
Show file tree
Hide file tree
Showing 4 changed files with 280 additions and 272 deletions.
52 changes: 52 additions & 0 deletions src/Tickets/Commerce/Gateways/Stripe/Hooks.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
use Tribe\Tickets\Admin\Settings as Admin_Settings;
use Tribe\Admin\Pages;
use Tribe__Tickets__Main as Tickets_Plugin;
use WP_Post;
use Exception;
use TEC\Tickets\Commerce\Order;
use TEC\Tickets\Commerce\Status\Status_Handler;

/**
* Class Hooks
Expand Down Expand Up @@ -44,6 +48,8 @@ protected function add_actions() {
add_action( 'wp_ajax_tec_tickets_commerce_gateway_stripe_verify_webhooks', [ $this, 'action_handle_verify_webhooks' ] );

add_action( 'wp_ajax_' . Webhooks::NONCE_KEY_SETUP, [ $this, 'action_handle_set_up_webhook' ] );

add_action( 'tec_tickets_commerce_async_webhook_process', [ $this, 'process_async_stripe_webhook' ], 10 );
}

/**
Expand All @@ -61,6 +67,52 @@ protected function add_filters() {
add_filter( 'tec_tickets_commerce_admin_notices', [ $this, 'filter_admin_notices' ] );
}

/**
* Process the async stripe webhook.
*
* @since TBD
*
* @param int $order_id The order ID.
*
* @throws Exception If the action fails after too many retries.
*/
public function process_async_stripe_webhook( int $order_id ): void {
$order = tec_tc_get_order( $order_id );

if ( ! $order || ! $order instanceof WP_Post || ! $order->ID ) {
return;
}

$pending_webhooks = get_post_meta( $order->ID, '_tec_tickets_commerce_stripe_webhook_pending' );

// On multiple checkout completes, make sure we dont process the same webhook twice.
delete_post_meta( $order->ID, '_tec_tickets_commerce_stripe_webhook_pending' );

foreach ( $pending_webhooks as $pending_webhook ) {
if ( ! ( is_array( $pending_webhook ) && isset( $pending_webhook['new_status'], $pending_webhook['metadata'], $pending_webhook['old_status'] ) ) ) {
continue;
}

$new_status_wp_slug = $pending_webhook['new_status'];

// The order is already there!
if ( $order->post_status === $new_status_wp_slug ) {
continue;
}

// The order is no longer where it was... that could be dangerous, lets bail?
if ( $order->post_status !== $pending_webhook['old_status'] ) {
continue;
}

tribe( Order::class )->modify_status(
$order->ID,
tribe( Status_Handler::class )->get_by_wp_slug( $new_status_wp_slug )->get_slug(),
$pending_webhook['metadata']
);
}
}

/**
* Set up Stripe Webhook based on transient value.
*
Expand Down
51 changes: 0 additions & 51 deletions src/Tickets/Commerce/Provider.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@
use TEC\Common\Contracts\Service_Provider;
use TEC\Tickets\Commerce\Gateways;
use Tribe__Tickets__Main as Tickets_Plugin;
use WP_Post;
use Exception;
use TEC\Tickets\Commerce\Status\Status_Handler;

/**
* Service provider for the Tickets Commerce.
Expand Down Expand Up @@ -102,54 +99,6 @@ public function register() {

// Cache invalidation.
add_filter( 'tec_cache_listener_save_post_types', [ $this, 'filter_cache_listener_save_post_types' ] );

add_action( 'tec_tickets_commerce_async_webhook_process', [ $this, 'process_async_stripe_webhook' ], 10 );
}

/**
* Process the async stripe webhook.
*
* @since TBD
*
* @param int $order_id The order ID.
*
* @throws Exception If the action fails after too many retries.
*/
public function process_async_stripe_webhook( int $order_id ): void {
$order = tec_tc_get_order( $order_id );

if ( ! $order || ! $order instanceof WP_Post || ! $order->ID ) {
return;
}

$pending_webhooks = get_post_meta( $order->ID, '_tec_tickets_commerce_stripe_webhook_pending' );

// On multiple checkout completes, make sure we dont process the same webhook twice.
delete_post_meta( $order->ID, '_tec_tickets_commerce_stripe_webhook_pending' );

foreach ( $pending_webhooks as $pending_webhook ) {
if ( ! ( is_array( $pending_webhook ) && isset( $pending_webhook['new_status'], $pending_webhook['metadata'], $pending_webhook['old_status'] ) ) ) {
continue;
}

$new_status_wp_slug = $pending_webhook['new_status'];

// The order is already there!
if ( $order->post_status === $new_status_wp_slug ) {
continue;
}

// The order is no longer where it was... that could be dangerous, lets bail?
if ( $order->post_status !== $pending_webhook['old_status'] ) {
continue;
}

tribe( Order::class )->modify_status(
$order->ID,
tribe( Status_Handler::class )->get_by_wp_slug( $new_status_wp_slug )->get_slug(),
$pending_webhook['metadata']
);
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
<?php

namespace TEC\Tickets\Commerce\Gateways\Stripe;

use Tribe\Tickets\Test\Commerce\TicketsCommerce\Ticket_Maker;
use Codeception\TestCase\WPTestCase;
use Tribe\Tests\Traits\With_Uopz;
use Tribe\Tickets\Test\Commerce\TicketsCommerce\Order_Maker;
use TEC\Tickets\Commerce\Status\Pending;
use TEC\Tickets\Commerce\Status\Created;
use TEC\Tickets\Commerce\Status\Completed;
use TEC\Tickets\Commerce\Status\Status_Handler;
use TEC\Tickets\Commerce\Order;

class Hooks_Test extends WPTestCase {
use Ticket_Maker;
use With_Uopz;
use Order_Maker;
use With_Uopz;

public function test_it_processes_async_stripe_webhooks() {
$post = self::factory()->post->create(
[
'post_type' => 'page',
]
);
$ticket_id_1 = $this->create_tc_ticket( $post, 10 );
$ticket_id_2 = $this->create_tc_ticket( $post, 20 );

$wp_status_slug_from_slug = fn( $slug ) => tribe( Status_Handler::class )->get_by_slug( $slug )->get_wp_slug();

$order = $this->create_order( [ $ticket_id_1 => 1, $ticket_id_2 => 2 ], [ 'order_status' => Created::SLUG ] );

$this->assertFalse( as_has_scheduled_action( 'tec_tickets_commerce_async_webhook_process', null, 'tec-tickets-commerce-stripe-webhooks' ) );

tribe( Order::class )->checkout_completed( $order->ID );

$this->assertTrue( as_has_scheduled_action( 'tec_tickets_commerce_async_webhook_process', null, 'tec-tickets-commerce-stripe-webhooks' ) );

add_post_meta(
$order->ID,
'_tec_tickets_commerce_stripe_webhook_pending',
[
'new_status' => $wp_status_slug_from_slug( Completed::SLUG ),
'metadata' => [],
'old_status' => $wp_status_slug_from_slug( Created::SLUG ),
]
);

$this->assertSame( $wp_status_slug_from_slug( Created::SLUG ), $order->post_status );
do_action( 'tec_tickets_commerce_async_webhook_process', $order->ID );

$refreshed_order = tec_tc_get_order( $order->ID );

$this->assertSame( $wp_status_slug_from_slug( Completed::SLUG ), $refreshed_order->post_status );

$this->assertEmpty( get_post_meta( $order->ID, '_tec_tickets_commerce_stripe_webhook_pending' ) );

add_post_meta(
$order->ID,
'_tec_tickets_commerce_stripe_webhook_pending',
[
'new_status' => $wp_status_slug_from_slug( Completed::SLUG ),
'metadata' => [],
'old_status' => $wp_status_slug_from_slug( Created::SLUG ),
]
);

add_post_meta(
$order->ID,
'_tec_tickets_commerce_stripe_webhook_pending',
[
'new_status' => $wp_status_slug_from_slug( Pending::SLUG ),
'metadata' => [],
'old_status' => $wp_status_slug_from_slug( Completed::SLUG ),
]
);

do_action( 'tec_tickets_commerce_async_webhook_process', $order->ID );

$refreshed_order = tec_tc_get_order( $order->ID );

$this->assertEmpty( get_post_meta( $order->ID, '_tec_tickets_commerce_stripe_webhook_pending' ) );

$this->assertSame( $wp_status_slug_from_slug( Pending::SLUG ), $refreshed_order->post_status );
}

public function test_it_reschedules_async_stripe_webhooks_when_encounter_issues() {
$post = self::factory()->post->create(
[
'post_type' => 'page',
]
);
$ticket_id_1 = $this->create_tc_ticket( $post, 10 );
$ticket_id_2 = $this->create_tc_ticket( $post, 20 );

$wp_status_slug_from_slug = fn( $slug ) => tribe( Status_Handler::class )->get_by_slug( $slug )->get_wp_slug();

$order = $this->create_order( [ $ticket_id_1 => 1, $ticket_id_2 => 2 ], [ 'order_status' => Created::SLUG ] );

$this->assertFalse( as_has_scheduled_action( 'tec_tickets_commerce_async_webhook_process', null, 'tec-tickets-commerce-stripe-webhooks' ) );
tribe( Order::class )->checkout_completed( $order->ID );
$this->assertTrue( as_has_scheduled_action( 'tec_tickets_commerce_async_webhook_process', null, 'tec-tickets-commerce-stripe-webhooks' ) );

$refreshed_order = tec_tc_get_order( $order->ID );

$this->assertSame( $wp_status_slug_from_slug( Created::SLUG ), $refreshed_order->post_status );

add_post_meta(
$order->ID,
'_tec_tickets_commerce_stripe_webhook_pending',
[
'new_status' => $wp_status_slug_from_slug( Completed::SLUG ),
'metadata' => [],
'old_status' => $wp_status_slug_from_slug( Pending::SLUG ),
]
);

// Issue is encountered here - Different old status
do_action( 'tec_tickets_commerce_async_webhook_process', $order->ID );
$this->assertEmpty( get_post_meta( $order->ID, '_tec_tickets_commerce_stripe_webhook_pending' ) );

$refreshed_order = tec_tc_get_order( $order->ID );

$this->assertSame( $wp_status_slug_from_slug( Created::SLUG ), $refreshed_order->post_status );

tribe( Order::class )->lock_order( $order->ID );

add_post_meta(
$order->ID,
'_tec_tickets_commerce_stripe_webhook_pending',
[
'new_status' => $wp_status_slug_from_slug( Completed::SLUG ),
'metadata' => [],
'old_status' => $wp_status_slug_from_slug( Pending::SLUG ),
]
);

// Issue is encountered here - Order is locked.
do_action( 'tec_tickets_commerce_async_webhook_process', $order->ID );
$this->assertEmpty( get_post_meta( $order->ID, '_tec_tickets_commerce_stripe_webhook_pending' ) );

$refreshed_order = tec_tc_get_order( $order->ID );

$this->assertSame( $wp_status_slug_from_slug( Created::SLUG ), $refreshed_order->post_status );

tribe( Order::class )->unlock_order( $order->ID );

$this->set_class_fn_return( Order::class, 'modify_status', false );

add_post_meta(
$order->ID,
'_tec_tickets_commerce_stripe_webhook_pending',
[
'new_status' => $wp_status_slug_from_slug( Completed::SLUG ),
'metadata' => [],
'old_status' => $wp_status_slug_from_slug( Pending::SLUG ),
]
);
// Issue is encountered here - Modify status will fail.
do_action( 'tec_tickets_commerce_async_webhook_process', $order->ID );
$this->assertEmpty( get_post_meta( $order->ID, '_tec_tickets_commerce_stripe_webhook_pending' ) );

$refreshed_order = tec_tc_get_order( $order->ID );

$this->assertSame( $wp_status_slug_from_slug( Created::SLUG ), $refreshed_order->post_status );

uopz_unset_return( Order::class, 'modify_status' );

add_post_meta(
$order->ID,
'_tec_tickets_commerce_stripe_webhook_pending',
[
'new_status' => $wp_status_slug_from_slug( Completed::SLUG ),
'metadata' => [],
'old_status' => $wp_status_slug_from_slug( Created::SLUG ),
]
);
// Issue is encountered here - Success
do_action( 'tec_tickets_commerce_async_webhook_process', $order->ID );

$refreshed_order = tec_tc_get_order( $order->ID );
$this->assertEmpty( get_post_meta( $order->ID, '_tec_tickets_commerce_stripe_webhook_pending' ) );

$this->assertSame( $wp_status_slug_from_slug( Completed::SLUG ), $refreshed_order->post_status );
}

public function test_it_should_bail_async_stripe_webhooks_when_end_result_is_done_already() {
$post = self::factory()->post->create(
[
'post_type' => 'page',
]
);
$ticket_id_1 = $this->create_tc_ticket( $post, 10 );
$ticket_id_2 = $this->create_tc_ticket( $post, 20 );

$wp_status_slug_from_slug = fn( $slug ) => tribe( Status_Handler::class )->get_by_slug( $slug )->get_wp_slug();

$order = $this->create_order( [ $ticket_id_1 => 1, $ticket_id_2 => 2 ] );

$this->assertFalse( as_has_scheduled_action( 'tec_tickets_commerce_async_webhook_process', null, 'tec-tickets-commerce-stripe-webhooks' ) );

tribe( Order::class )->checkout_completed( $order->ID );

$this->assertTrue( as_has_scheduled_action( 'tec_tickets_commerce_async_webhook_process', null, 'tec-tickets-commerce-stripe-webhooks' ) );

add_post_meta(
$order->ID,
'_tec_tickets_commerce_stripe_webhook_pending',
[
'new_status' => $wp_status_slug_from_slug( Completed::SLUG ),
'metadata' => [],
'old_status' => $wp_status_slug_from_slug( Pending::SLUG ),
]
);

$refreshed_order = tec_tc_get_order( $order->ID );

$this->assertSame( $wp_status_slug_from_slug( Completed::SLUG ), $refreshed_order->post_status );
do_action( 'tec_tickets_commerce_async_webhook_process', $order->ID );

$refreshed_order = tec_tc_get_order( $order->ID );

$this->assertSame( $wp_status_slug_from_slug( Completed::SLUG ), $refreshed_order->post_status );

$this->assertEmpty( get_post_meta( $order->ID, '_tec_tickets_commerce_stripe_webhook_pending' ) );
}
}
Loading

0 comments on commit 6e391a3

Please sign in to comment.