Commit 638136dd0cd for woocommerce

commit 638136dd0cd4926a1d43d7b9fb6378dda91aa06a
Author: Adam Grzybkowski <agrzybkowski@outlook.com>
Date:   Mon May 18 11:09:04 2026 +0200

    Add high-value order threshold to store_order push notifications (#64509)

    * Add min_amount sub-field to store_order notification preference

    Extend the store_order preference shape from `{ enabled: bool }` to
    `{ enabled: bool, min_amount: float|null }`. `min_amount: null` is
    the default and means "no threshold"; a positive number is the
    order-total floor for the notification.

    The REST schema accepts either null or a positive number; 0 and
    negatives are rejected via `exclusiveMinimum: true` so the value's
    "high-value" semantics line up with the eventual UI (radio button:
    all-orders / high-value-with-amount), and so a stored 0 can never
    masquerade as a meaningful filter.

    No schema-version bump needed: the v1 envelope already uses a
    nested object per pref key, so this is a forward-compatible add.

    Filtering by the threshold lands in a follow-up.

    * Filter store_order notifications by min_amount threshold

    Override `NewOrderNotification::should_send_to_user()` to consult the
    user's stored `min_amount` alongside the parent's enabled check. When
    `min_amount` is null or non-positive, no threshold filter is applied
    (the parent's enabled-check decision stands). When set, the order's
    total must meet or exceed the threshold for the notification to fire.

    `NotificationProcessor::filter_tokens_by_preferences` already memoizes
    the per-user decision, so an order that lands for N tokens still
    results in at most one threshold evaluation per recipient user.

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

    * Document that min_amount is compared in the order's currency

    Address review feedback on PR #64509: spell out in the docblock that
    the threshold is compared against the order's total in the order's
    own currency, with no currency conversion. Mirrors how
    WC_Coupon::minimum_amount behaves; multi-currency merchants should
    set thresholds with that in mind.

    No behaviour change.

    ---------

    Co-authored-by: woocommercebot <woocommercebot@users.noreply.github.com>

diff --git a/plugins/woocommerce/changelog/64509-issue-RSM-1550 b/plugins/woocommerce/changelog/64509-issue-RSM-1550
new file mode 100644
index 00000000000..12b162b4abe
--- /dev/null
+++ b/plugins/woocommerce/changelog/64509-issue-RSM-1550
@@ -0,0 +1,4 @@
+Significance: minor
+Type: add
+
+Add a merchant-configurable minimum-amount threshold to the store_order push notification, so only orders at or above the threshold trigger a notification. Default behaviour (notify on every enabled order) is unchanged.
\ No newline at end of file
diff --git a/plugins/woocommerce/src/Internal/PushNotifications/Controllers/NotificationPreferencesRestController.php b/plugins/woocommerce/src/Internal/PushNotifications/Controllers/NotificationPreferencesRestController.php
index a1a148588c3..71939936756 100644
--- a/plugins/woocommerce/src/Internal/PushNotifications/Controllers/NotificationPreferencesRestController.php
+++ b/plugins/woocommerce/src/Internal/PushNotifications/Controllers/NotificationPreferencesRestController.php
@@ -198,7 +198,23 @@ class NotificationPreferencesRestController extends RestApiControllerBase {
 		$args     = array();
 		$defaults = $this->preferences_service->get_defaults();

-		foreach ( array_keys( $defaults ) as $key ) {
+		foreach ( $defaults as $key => $shape ) {
+			$properties = array(
+				'enabled' => array(
+					'type'        => 'boolean',
+					'description' => __( 'Whether this notification type is enabled.', 'woocommerce' ),
+				),
+			);
+
+			if ( array_key_exists( 'min_amount', $shape ) ) {
+				$properties['min_amount'] = array(
+					'type'             => array( 'number', 'null' ),
+					'minimum'          => 0,
+					'exclusiveMinimum' => true,
+					'description'      => __( 'Minimum order amount required to trigger this notification, or null to disable the threshold.', 'woocommerce' ),
+				);
+			}
+
 			$args[ $key ] = array(
 				'description'       => sprintf(
 					/* translators: %s: notification preference key (e.g. store_order). */
@@ -206,16 +222,11 @@ class NotificationPreferencesRestController extends RestApiControllerBase {
 					$key
 				),
 				'type'              => 'object',
-				'properties'        => array(
-					'enabled' => array(
-						'type'        => 'boolean',
-						'description' => __( 'Whether this notification type is enabled.', 'woocommerce' ),
-					),
-				),
+				'properties'        => $properties,
 				'required'          => false,
 				'validate_callback' => 'rest_validate_request_arg',
 			);
-		}
+		}//end foreach

 		return $args;
 	}
diff --git a/plugins/woocommerce/src/Internal/PushNotifications/Notifications/NewOrderNotification.php b/plugins/woocommerce/src/Internal/PushNotifications/Notifications/NewOrderNotification.php
index fc51c190144..b6756411147 100644
--- a/plugins/woocommerce/src/Internal/PushNotifications/Notifications/NewOrderNotification.php
+++ b/plugins/woocommerce/src/Internal/PushNotifications/Notifications/NewOrderNotification.php
@@ -83,6 +83,45 @@ class NewOrderNotification extends Notification {
 		);
 	}

+	/**
+	 * {@inheritDoc}
+	 *
+	 * Extends the base enabled-toggle check with a minimum-amount threshold.
+	 * When `min_amount` is set in the user's preferences, the order total must
+	 * meet or exceed it for the notification to be sent.
+	 *
+	 * The threshold is interpreted in the order's currency; no currency
+	 * conversion is performed. This mirrors how `WC_Coupon::minimum_amount`
+	 * behaves, so multi-currency merchants should set thresholds with that
+	 * in mind.
+	 *
+	 * @param mixed $pref_value The user's stored preference value, or null.
+	 * @return bool
+	 *
+	 * @since 10.9.0
+	 */
+	public function should_send_to_user( $pref_value ): bool {
+		if ( ! parent::should_send_to_user( $pref_value ) ) {
+			return false;
+		}
+
+		if ( ! is_array( $pref_value ) || ! isset( $pref_value['min_amount'] ) ) {
+			return true;
+		}
+
+		$min_amount = (float) $pref_value['min_amount'];
+		if ( $min_amount <= 0 ) {
+			return true;
+		}
+
+		$order = WC()->call_function( 'wc_get_order', $this->get_resource_id() );
+		if ( ! $order instanceof WC_Order ) {
+			return false;
+		}
+
+		return (float) $order->get_total() >= $min_amount;
+	}
+
 	/**
 	 * {@inheritDoc}
 	 *
diff --git a/plugins/woocommerce/src/Internal/PushNotifications/Services/NotificationPreferencesService.php b/plugins/woocommerce/src/Internal/PushNotifications/Services/NotificationPreferencesService.php
index fc56810d2d7..d117d518e9e 100644
--- a/plugins/woocommerce/src/Internal/PushNotifications/Services/NotificationPreferencesService.php
+++ b/plugins/woocommerce/src/Internal/PushNotifications/Services/NotificationPreferencesService.php
@@ -115,6 +115,9 @@ class NotificationPreferencesService {
 		foreach ( array_keys( Notification::NOTIFICATION_CLASSES ) as $type ) {
 			$defaults[ $type ] = array( 'enabled' => true );
 		}
+
+		$defaults['store_order']['min_amount'] = null;
+
 		return $defaults;
 	}

@@ -153,7 +156,6 @@ class NotificationPreferencesService {
 	 * @return array<string, mixed>
 	 */
 	protected function sanitize_value( string $key, array $value, array $default_shape ): array {
-		// Reserved for per-key dispatch when sub-fields are added.
 		unset( $key );

 		$sanitized = array();
@@ -165,7 +167,16 @@ class NotificationPreferencesService {
 					: (bool) $sub_default;
 				continue;
 			}
-			// Future sub-fields (thresholds, sub-toggles) extend this switch.
+
+			if ( 'min_amount' === $sub_key ) {
+				if ( ! array_key_exists( $sub_key, $value ) || null === $value[ $sub_key ] ) {
+					$sanitized[ $sub_key ] = null;
+					continue;
+				}
+				$amount                = (float) $value[ $sub_key ];
+				$sanitized[ $sub_key ] = $amount > 0 ? $amount : null;
+				continue;
+			}
 		}

 		return $sanitized;
diff --git a/plugins/woocommerce/tests/php/src/Internal/PushNotifications/Controllers/NotificationPreferencesRestControllerTest.php b/plugins/woocommerce/tests/php/src/Internal/PushNotifications/Controllers/NotificationPreferencesRestControllerTest.php
index 735a7dd1f13..3c30c83fd5f 100644
--- a/plugins/woocommerce/tests/php/src/Internal/PushNotifications/Controllers/NotificationPreferencesRestControllerTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/PushNotifications/Controllers/NotificationPreferencesRestControllerTest.php
@@ -278,6 +278,99 @@ class NotificationPreferencesRestControllerTest extends WC_REST_Unit_Test_Case {
 		$this->assertStringNotContainsString( $internal_message, (string) $serialized );
 	}

+	/**
+	 * @testdox POST should reject non-numeric min_amount via the REST validation layer.
+	 */
+	public function test_post_preferences_rejects_non_numeric_min_amount() {
+		wp_set_current_user( $this->user_id );
+		$this->mock_jetpack_connection_manager_is_connected( true );
+		$this->register_routes();
+
+		$request = new WP_REST_Request( 'POST', '/wc-push-notifications/preferences' );
+		$request->set_param( 'store_order', array( 'min_amount' => 'not-a-number' ) );
+
+		$response = $this->server->dispatch( $request );
+
+		$this->assertSame( WP_Http::BAD_REQUEST, $response->get_status() );
+	}
+
+	/**
+	 * @testdox POST should reject non-positive min_amount via the REST validation layer.
+	 *
+	 * @testWith [-10]
+	 *           [0]
+	 *
+	 * @param int|float $value The invalid value.
+	 */
+	public function test_post_preferences_rejects_non_positive_min_amount( $value ) {
+		wp_set_current_user( $this->user_id );
+		$this->mock_jetpack_connection_manager_is_connected( true );
+		$this->register_routes();
+
+		$request = new WP_REST_Request( 'POST', '/wc-push-notifications/preferences' );
+		$request->set_param( 'store_order', array( 'min_amount' => $value ) );
+
+		$response = $this->server->dispatch( $request );
+
+		$this->assertSame( WP_Http::BAD_REQUEST, $response->get_status() );
+	}
+
+	/**
+	 * @testdox POST should accept a positive min_amount and persist it.
+	 */
+	public function test_post_preferences_accepts_valid_min_amount() {
+		wp_set_current_user( $this->user_id );
+		$this->mock_jetpack_connection_manager_is_connected( true );
+		$this->register_routes();
+
+		$request = new WP_REST_Request( 'POST', '/wc-push-notifications/preferences' );
+		$request->set_param( 'store_order', array( 'min_amount' => 100 ) );
+
+		$response = $this->server->dispatch( $request );
+
+		$this->assertSame( WP_Http::OK, $response->get_status() );
+
+		$data = $response->get_data();
+		$this->assertSame( 100.0, $data['store_order']['min_amount'] );
+	}
+
+	/**
+	 * @testdox POST should accept null min_amount and persist it.
+	 */
+	public function test_post_preferences_accepts_null_min_amount() {
+		wp_set_current_user( $this->user_id );
+		$this->mock_jetpack_connection_manager_is_connected( true );
+		$this->register_routes();
+
+		$request = new WP_REST_Request( 'POST', '/wc-push-notifications/preferences' );
+		$request->set_param( 'store_order', array( 'min_amount' => null ) );
+
+		$response = $this->server->dispatch( $request );
+
+		$this->assertSame( WP_Http::OK, $response->get_status() );
+
+		$data = $response->get_data();
+		$this->assertNull( $data['store_order']['min_amount'] );
+	}
+
+	/**
+	 * @testdox GET should include a null min_amount in store_order by default.
+	 */
+	public function test_get_preferences_includes_min_amount_in_store_order() {
+		wp_set_current_user( $this->user_id );
+		$this->mock_jetpack_connection_manager_is_connected( true );
+		$this->register_routes();
+
+		$request  = new WP_REST_Request( 'GET', '/wc-push-notifications/preferences' );
+		$response = $this->server->dispatch( $request );
+
+		$this->assertSame( WP_Http::OK, $response->get_status() );
+
+		$data = $response->get_data();
+		$this->assertArrayHasKey( 'min_amount', $data['store_order'] );
+		$this->assertNull( $data['store_order']['min_amount'] );
+	}
+
 	/**
 	 * @testdox Should not collide with PushTokenRestController on the WC REST namespaces filter.
 	 *
diff --git a/plugins/woocommerce/tests/php/src/Internal/PushNotifications/Notifications/NewOrderNotificationTest.php b/plugins/woocommerce/tests/php/src/Internal/PushNotifications/Notifications/NewOrderNotificationTest.php
index 451997fc4cf..d1b52d32cd5 100644
--- a/plugins/woocommerce/tests/php/src/Internal/PushNotifications/Notifications/NewOrderNotificationTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/PushNotifications/Notifications/NewOrderNotificationTest.php
@@ -90,4 +90,120 @@ class NewOrderNotificationTest extends WC_Unit_Test_Case {

 		$this->assertNull( $notification->to_payload() );
 	}
+
+	/**
+	 * @testdox should_send_to_user should return true when order total exceeds min_amount.
+	 */
+	public function test_should_send_to_user_when_order_total_above_threshold(): void {
+		$order = $this->create_order_with_total( 100 );
+
+		$notification = new NewOrderNotification( $order->get_id() );
+
+		$this->assertTrue(
+			$notification->should_send_to_user(
+				array(
+					'enabled'    => true,
+					'min_amount' => 50,
+				)
+			)
+		);
+	}
+
+	/**
+	 * @testdox should_send_to_user should return true when order total equals min_amount.
+	 */
+	public function test_should_send_to_user_when_order_total_equals_threshold(): void {
+		$order = $this->create_order_with_total( 50 );
+
+		$notification = new NewOrderNotification( $order->get_id() );
+
+		$this->assertTrue(
+			$notification->should_send_to_user(
+				array(
+					'enabled'    => true,
+					'min_amount' => 50,
+				)
+			)
+		);
+	}
+
+	/**
+	 * @testdox should_send_to_user should return false when order total is below min_amount.
+	 */
+	public function test_should_not_send_to_user_when_order_total_below_threshold(): void {
+		$order = $this->create_order_with_total( 30 );
+
+		$notification = new NewOrderNotification( $order->get_id() );
+
+		$this->assertFalse(
+			$notification->should_send_to_user(
+				array(
+					'enabled'    => true,
+					'min_amount' => 50,
+				)
+			)
+		);
+	}
+
+	/**
+	 * @testdox should_send_to_user should return true when min_amount is null (no threshold).
+	 */
+	public function test_should_send_to_user_when_min_amount_is_null(): void {
+		$order = $this->create_order_with_total( 1 );
+
+		$notification = new NewOrderNotification( $order->get_id() );
+
+		$this->assertTrue(
+			$notification->should_send_to_user(
+				array(
+					'enabled'    => true,
+					'min_amount' => null,
+				)
+			)
+		);
+	}
+
+	/**
+	 * @testdox should_send_to_user should return false when notification is disabled, regardless of amount.
+	 */
+	public function test_should_not_send_to_user_when_disabled(): void {
+		$order = $this->create_order_with_total( 1000 );
+
+		$notification = new NewOrderNotification( $order->get_id() );
+
+		$this->assertFalse(
+			$notification->should_send_to_user(
+				array(
+					'enabled'    => false,
+					'min_amount' => null,
+				)
+			)
+		);
+	}
+
+	/**
+	 * @testdox should_send_to_user should return true when min_amount key is missing (backwards compat).
+	 */
+	public function test_should_send_to_user_when_min_amount_missing(): void {
+		$order = $this->create_order_with_total( 1 );
+
+		$notification = new NewOrderNotification( $order->get_id() );
+
+		$this->assertTrue(
+			$notification->should_send_to_user( array( 'enabled' => true ) )
+		);
+	}
+
+	/**
+	 * Creates an order with a specific total.
+	 *
+	 * @param float $total The order total.
+	 * @return \WC_Order
+	 */
+	private function create_order_with_total( float $total ): \WC_Order {
+		$order = wc_create_order( array( 'status' => 'processing' ) );
+		$order->set_total( (string) $total );
+		$order->save();
+		return $order;
+	}
 }
diff --git a/plugins/woocommerce/tests/php/src/Internal/PushNotifications/Services/NotificationPreferencesServiceTest.php b/plugins/woocommerce/tests/php/src/Internal/PushNotifications/Services/NotificationPreferencesServiceTest.php
index 67b5ada0413..f41bc528b53 100644
--- a/plugins/woocommerce/tests/php/src/Internal/PushNotifications/Services/NotificationPreferencesServiceTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/PushNotifications/Services/NotificationPreferencesServiceTest.php
@@ -243,63 +243,8 @@ class NotificationPreferencesServiceTest extends WC_Unit_Test_Case {

 	/**
 	 * @testdox Should perform a deep merge so partial updates preserve unrelated sub-fields.
-	 *
-	 * Locks in the contract for forward-compatible sub-fields. When stored preferences contain
-	 * multiple sub-fields per pref (e.g. RSM-1550's `min_amount` alongside `enabled`), a partial
-	 * update that only sends one sub-field must not clobber the others. With a shallow merge
-	 * (`array_merge`), the entire sub-object is replaced; with a deep merge
-	 * (`array_replace_recursive`), only the specified sub-fields are overridden.
-	 *
-	 * Today's schema only has `enabled` per pref, so the bug is invisible. This test extends
-	 * the schema via an anonymous subclass to exercise the multi-sub-field case the future
-	 * tickets rely on.
 	 */
 	public function test_save_preferences_deep_merges_partial_updates(): void {
-		$service = new class() extends NotificationPreferencesService {
-			/**
-			 * Extended schema for the test: a second sub-field alongside `enabled`.
-			 *
-			 * @return array<string, array<string, mixed>>
-			 */
-			public function get_defaults(): array {
-				return array(
-					'store_order' => array(
-						'enabled'    => true,
-						'min_amount' => 0,
-					),
-				);
-			}
-
-			/**
-			 * Permissive sanitize for the test: preserve every sub-key in the default shape,
-			 * coercing to the type implied by its default value.
-			 *
-			 * @param string               $key           Preference key.
-			 * @param array                $value         Submitted sub-options.
-			 * @param array<string, mixed> $default_shape Default sub-options.
-			 * @return array<string, mixed>
-			 */
-			protected function sanitize_value( string $key, array $value, array $default_shape ): array {
-				$sanitized = array();
-				foreach ( $default_shape as $sub_key => $sub_default ) {
-					if ( ! array_key_exists( $sub_key, $value ) ) {
-						$sanitized[ $sub_key ] = $sub_default;
-						continue;
-					}
-					if ( is_bool( $sub_default ) ) {
-						$sanitized[ $sub_key ] = (bool) $value[ $sub_key ];
-					} elseif ( is_int( $sub_default ) ) {
-						$sanitized[ $sub_key ] = (int) $value[ $sub_key ];
-					} else {
-						$sanitized[ $sub_key ] = $value[ $sub_key ];
-					}
-				}
-				return $sanitized;
-			}
-		};
-		$service->init( $this->data_store );
-
-		// Stored state already has a non-default `min_amount`.
 		$this->data_store->method( 'read' )->willReturn(
 			array(
 				'schema_version' => NotificationPreferencesDataStore::CURRENT_SCHEMA_VERSION,
@@ -312,7 +257,6 @@ class NotificationPreferencesServiceTest extends WC_Unit_Test_Case {
 			)
 		);

-		// Verify that a partial update of just `enabled` preserves `min_amount`.
 		$this->data_store
 			->expects( $this->once() )
 			->method( 'write' )
@@ -321,12 +265,12 @@ class NotificationPreferencesServiceTest extends WC_Unit_Test_Case {
 				$this->callback(
 					function ( $envelope ) {
 						$prefs = $envelope['preferences']['store_order'];
-						return false === $prefs['enabled'] && 500 === $prefs['min_amount'];
+						return false === $prefs['enabled'] && 500.0 === $prefs['min_amount'];
 					}
 				)
 			);

-		$service->save_preferences(
+		$this->sut->save_preferences(
 			$this->user_id,
 			array( 'store_order' => array( 'enabled' => false ) )
 		);
@@ -348,4 +292,63 @@ class NotificationPreferencesServiceTest extends WC_Unit_Test_Case {
 			$this->assertIsBool( $shape['enabled'] );
 		}
 	}
+
+	/**
+	 * @testdox Should default min_amount to null in store_order defaults.
+	 */
+	public function test_get_defaults_includes_min_amount_for_store_order(): void {
+		$defaults = $this->sut->get_defaults();
+
+		$this->assertArrayHasKey( 'min_amount', $defaults['store_order'] );
+		$this->assertNull( $defaults['store_order']['min_amount'] );
+	}
+
+	/**
+	 * @testdox Should preserve explicit null min_amount.
+	 */
+	public function test_sanitize_preserves_null_min_amount(): void {
+		$this->data_store->method( 'read' )->willReturn( null );
+
+		$result = $this->sut->save_preferences(
+			$this->user_id,
+			array( 'store_order' => array( 'min_amount' => null ) )
+		);
+
+		$this->assertNull( $result['store_order']['min_amount'] );
+	}
+
+	/**
+	 * @testdox Should fall back to null when min_amount is non-positive.
+	 */
+	public function test_sanitize_falls_back_to_null_for_non_positive_min_amount(): void {
+		$this->data_store->method( 'read' )->willReturn( null );
+
+		$result = $this->sut->save_preferences(
+			$this->user_id,
+			array( 'store_order' => array( 'min_amount' => -50 ) )
+		);
+
+		$this->assertNull( $result['store_order']['min_amount'] );
+
+		$result = $this->sut->save_preferences(
+			$this->user_id,
+			array( 'store_order' => array( 'min_amount' => 0 ) )
+		);
+
+		$this->assertNull( $result['store_order']['min_amount'] );
+	}
+
+	/**
+	 * @testdox Should coerce string min_amount to float.
+	 */
+	public function test_sanitize_coerces_min_amount_to_float(): void {
+		$this->data_store->method( 'read' )->willReturn( null );
+
+		$result = $this->sut->save_preferences(
+			$this->user_id,
+			array( 'store_order' => array( 'min_amount' => '50' ) )
+		);
+
+		$this->assertSame( 50.0, $result['store_order']['min_amount'] );
+	}
 }
diff --git a/plugins/woocommerce/tests/php/src/Internal/PushNotifications/Services/NotificationProcessorTest.php b/plugins/woocommerce/tests/php/src/Internal/PushNotifications/Services/NotificationProcessorTest.php
index 8b6e66996cb..269e94211f9 100644
--- a/plugins/woocommerce/tests/php/src/Internal/PushNotifications/Services/NotificationProcessorTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/PushNotifications/Services/NotificationProcessorTest.php
@@ -75,7 +75,10 @@ class NotificationProcessorTest extends WC_Unit_Test_Case {
 		// the dedicated preferences tests below.
 		$this->preferences_service->method( 'get_preferences' )->willReturn(
 			array(
-				'store_order'  => array( 'enabled' => true ),
+				'store_order'  => array(
+					'enabled'    => true,
+					'min_amount' => null,
+				),
 				'store_review' => array( 'enabled' => true ),
 			)
 		);
@@ -533,4 +536,37 @@ class NotificationProcessorTest extends WC_Unit_Test_Case {

 		$this->assertNotEmpty( $order->get_meta( NotificationProcessor::SENT_META_KEY ) );
 	}
+
+	/**
+	 * @testdox Should skip dispatch when the order total is below the user's min_amount threshold.
+	 */
+	public function test_process_skips_dispatch_when_order_below_min_amount(): void {
+		$order = wc_create_order( array( 'status' => 'processing' ) );
+		$order->set_total( '100' );
+		$order->save();
+
+		$preferences_service = $this->createMock( NotificationPreferencesService::class );
+		$preferences_service->method( 'get_preferences' )->willReturn(
+			array(
+				'store_order'  => array(
+					'enabled'    => true,
+					'min_amount' => 500,
+				),
+				'store_review' => array( 'enabled' => true ),
+			)
+		);
+
+		$this->dispatcher->expects( $this->never() )->method( 'dispatch' );
+
+		$sut = new NotificationProcessor();
+		$sut->init( $this->dispatcher, $this->data_store, $preferences_service );
+
+		$notification = new NewOrderNotification( $order->get_id() );
+		$result       = $sut->process( $notification );
+
+		$this->assertTrue( $result );
+		$this->assertNotEmpty(
+			wc_get_order( $order->get_id() )->get_meta( NotificationProcessor::SENT_META_KEY )
+		);
+	}
 }