diff --git a/includes/Modules/Reader_Revenue_Manager.php b/includes/Modules/Reader_Revenue_Manager.php index e2b8036ad1f..846849cc826 100644 --- a/includes/Modules/Reader_Revenue_Manager.php +++ b/includes/Modules/Reader_Revenue_Manager.php @@ -40,7 +40,7 @@ use Google\Site_Kit\Modules\Reader_Revenue_Manager\Post_Product_ID; use Google\Site_Kit\Modules\Reader_Revenue_Manager\Term_Product_ID; use Google\Site_Kit\Modules\Reader_Revenue_Manager\Settings; -use Google\Site_Kit\Modules\Reader_Revenue_Manager\Synchronize_OnboardingState; +use Google\Site_Kit\Modules\Reader_Revenue_Manager\Synchronize_Publication; use Google\Site_Kit\Modules\Reader_Revenue_Manager\Tag_Guard; use Google\Site_Kit\Modules\Reader_Revenue_Manager\Tag_Matchers; use Google\Site_Kit\Modules\Reader_Revenue_Manager\Web_Tag; @@ -75,11 +75,11 @@ final class Reader_Revenue_Manager extends Module implements Module_With_Scopes, public function register() { $this->register_scopes_hook(); - $synchronize_onboarding_state = new Synchronize_OnboardingState( + $synchronize_publication = new Synchronize_Publication( $this, $this->user_options ); - $synchronize_onboarding_state->register(); + $synchronize_publication->register(); if ( Feature_Flags::enabled( 'rrmModuleV2' ) && $this->is_connected() ) { $post_meta = new Post_Meta(); @@ -92,8 +92,8 @@ public function register() { $term_product_id->register(); } - add_action( 'load-toplevel_page_googlesitekit-dashboard', array( $synchronize_onboarding_state, 'maybe_schedule_synchronize_onboarding_state' ) ); - add_action( 'load-toplevel_page_googlesitekit-settings', array( $synchronize_onboarding_state, 'maybe_schedule_synchronize_onboarding_state' ) ); + add_action( 'load-toplevel_page_googlesitekit-dashboard', array( $synchronize_publication, 'maybe_schedule_synchronize_publication' ) ); + add_action( 'load-toplevel_page_googlesitekit-settings', array( $synchronize_publication, 'maybe_schedule_synchronize_publication' ) ); // Reader Revenue Manager tag placement logic. add_action( 'template_redirect', array( $this, 'register_tag' ) ); diff --git a/includes/Modules/Reader_Revenue_Manager/Synchronize_OnboardingState.php b/includes/Modules/Reader_Revenue_Manager/Synchronize_Publication.php similarity index 50% rename from includes/Modules/Reader_Revenue_Manager/Synchronize_OnboardingState.php rename to includes/Modules/Reader_Revenue_Manager/Synchronize_Publication.php index f295d867a54..8515a7c1716 100644 --- a/includes/Modules/Reader_Revenue_Manager/Synchronize_OnboardingState.php +++ b/includes/Modules/Reader_Revenue_Manager/Synchronize_Publication.php @@ -1,9 +1,9 @@ synchronize_publication_data(); } @@ -73,7 +76,7 @@ function () { /** * Cron callback for synchronizing the publication. * - * @since 1.141.0 + * @since n.e.x.t * * @return void */ @@ -82,32 +85,13 @@ protected function synchronize_publication_data() { $restore_user = $this->user_options->switch_user( $owner_id ); if ( user_can( $owner_id, Permissions::VIEW_AUTHENTICATED_DASHBOARD ) ) { - $this->synchronize_onboarding_state(); - } - - $restore_user(); - } - - /** - * Synchronizes the onboarding state. - * - * @since 1.141.0 - * - * @return void - */ - protected function synchronize_onboarding_state() { - $connected = $this->reader_revenue_manager->is_connected(); - - // If not connected, return early. - if ( ! $connected ) { - return; - } + $connected = $this->reader_revenue_manager->is_connected(); - $settings = $this->reader_revenue_manager->get_settings()->get(); - $publication_id = $settings['publicationID']; - $onboarding_state = $settings['publicationOnboardingState']; + // If not connected, return early. + if ( ! $connected ) { + return; + } - if ( 'ONBOARDING_COMPLETE' !== $onboarding_state ) { $publications = $this->reader_revenue_manager->get_data( 'publications' ); // If publications is empty, return early. @@ -115,6 +99,9 @@ protected function synchronize_onboarding_state() { return; } + $settings = $this->reader_revenue_manager->get_settings()->get(); + $publication_id = $settings['publicationID']; + $filtered_publications = array_filter( $publications, function ( $pub ) use ( $publication_id ) { @@ -131,32 +118,95 @@ function ( $pub ) use ( $publication_id ) { $filtered_publications = array_values( $filtered_publications ); $publication = $filtered_publications[0]; - if ( $publication->getOnboardingState() !== $onboarding_state ) { - $this->reader_revenue_manager->get_settings()->merge( - array( - 'publicationOnboardingState' => $publication->getOnboardingState(), - 'publicationOnboardingStateChanged' => true, - ) - ); + $onboarding_state = $settings['publicationOnboardingState']; + $new_onboarding_state = $publication->getOnboardingState(); + + $new_settings = array( + 'publicationOnboardingState' => $new_onboarding_state, + ); + + // Let the client know if the onboarding state has changed. + if ( $new_onboarding_state !== $onboarding_state ) { + $new_settings['publicationOnboardingStateChanged'] = true; + } + + if ( Feature_Flags::enabled( 'rrmModuleV2' ) ) { + $new_settings['productIDs'] = $this->get_product_ids( $publication ); + $new_settings['paymentOption'] = $this->get_payment_option( $publication ); } + + $this->reader_revenue_manager->get_settings()->merge( $new_settings ); } + + $restore_user(); + } + + /** + * Returns the products IDs for the given publication. + * + * @since n.e.x.t + * + * @param Publication $publication Publication object. + * @return array Product IDs. + */ + protected function get_product_ids( Publication $publication ) { + $products = $publication->getProducts(); + $product_ids = array(); + + if ( ! empty( $products ) ) { + foreach ( $products as $product ) { + $name = $product->getName(); + + // Extract the product ID from the name, which is in + // the format of `publicationID:productID`. + if ( strpos( $name, ':' ) !== false ) { + $product_ids[] = substr( $name, strpos( $name, ':' ) + 1 ); + } + } + } + + return $product_ids; + } + + /** + * Returns the payment option for the given publication. + * + * @since n.e.x.t + * + * @param Publication $publication Publication object. + * @return string Payment option. + */ + protected function get_payment_option( Publication $publication ) { + $payment_options = $publication->getPaymentOptions(); + $payment_option = ''; + + if ( $payment_options instanceof PaymentOptions ) { + foreach ( $payment_options as $option => $value ) { + if ( true === $value ) { + $payment_option = $option; + break; + } + } + } + + return $payment_option; } /** * Maybe schedule the synchronize onboarding state cron event. * - * @since 1.141.0 + * @since n.e.x.t * * @return void */ - public function maybe_schedule_synchronize_onboarding_state() { + public function maybe_schedule_synchronize_publication() { $connected = $this->reader_revenue_manager->is_connected(); - $cron_already_scheduled = wp_next_scheduled( self::CRON_SYNCHRONIZE_ONBOARDING_STATE ); + $cron_already_scheduled = wp_next_scheduled( self::CRON_SYNCHRONIZE_PUBLICATION ); if ( $connected && ! $cron_already_scheduled ) { wp_schedule_single_event( time() + HOUR_IN_SECONDS, - self::CRON_SYNCHRONIZE_ONBOARDING_STATE + self::CRON_SYNCHRONIZE_PUBLICATION ); } } diff --git a/tests/phpunit/integration/Modules/Reader_Revenue_Manager/Synchronize_OnboardingStateTest.php b/tests/phpunit/integration/Modules/Reader_Revenue_Manager/Synchronize_OnboardingStateTest.php deleted file mode 100644 index 59e01324e49..00000000000 --- a/tests/phpunit/integration/Modules/Reader_Revenue_Manager/Synchronize_OnboardingStateTest.php +++ /dev/null @@ -1,155 +0,0 @@ -user->create( array( 'role' => 'administrator' ) ); - - $context = new Context( GOOGLESITEKIT_PLUGIN_MAIN_FILE ); - $this->options = new Options( $context ); - $this->user_options = new User_Options( $context, $user_id ); - $this->authentication = new Authentication( $context, $this->options, $this->user_options ); - - // Fake a valid authentication token on the client. - $this->authentication->get_oauth_client()->set_token( array( 'access_token' => 'valid-auth-token' ) ); - $this->authentication->verification()->set( true ); - - $this->fake_site_connection(); - add_filter( 'googlesitekit_setup_complete', '__return_true', 100 ); - - $this->reader_revenue_manager = new Reader_Revenue_Manager( $context, $this->options, $this->user_options, $this->authentication ); - $this->authentication->get_oauth_client()->set_granted_scopes( - $this->reader_revenue_manager->get_scopes() - ); - $this->user_options->switch_user( 0 ); - $this->reader_revenue_manager->get_settings()->register(); - - $this->reader_revenue_manager->get_settings()->merge( - array( - 'publicationID' => '123456789', - 'publicationOnboardingState' => 'ONBOARDING_ACTION_REQUIRED', - 'publicationOnboardingStateChanged' => false, - 'ownerID' => $user_id, - ), - ); - - $this->synchronize_onboarding_state = new Synchronize_OnboardingState( $this->reader_revenue_manager, $this->user_options ); - } - - public function fake_sync_onboarding_state() { - $publication_id = $this->reader_revenue_manager->get_settings()->get()['publicationID']; - - FakeHttp::fake_google_http_handler( - $this->reader_revenue_manager->get_client(), - function ( Request $request ) use ( $publication_id ) { - $url = parse_url( $request->getUri() ); - - if ( '/v1/publications' === $url['path'] ) { - $response = new ListPublicationsResponse(); - $publication = new Publication(); - $publication->setPublicationId( $publication_id ); - $publication->setOnboardingState( 'ONBOARDING_COMPLETE' ); - $response->setPublications( array( $publication ) ); - - return new Response( - 200, - array( 'content-type' => 'application/json' ), - json_encode( $response ) - ); - } - - return new Response( 200 ); - } - ); - } - - public function test_register() { - remove_all_actions( Synchronize_OnboardingState::CRON_SYNCHRONIZE_ONBOARDING_STATE ); - $this->synchronize_onboarding_state->register(); - - $this->assertEquals( 10, has_action( Synchronize_OnboardingState::CRON_SYNCHRONIZE_ONBOARDING_STATE ) ); - } - - public function test_cron_synchronize_publication_data() { - $this->fake_sync_onboarding_state(); - - $this->assertTrue( $this->reader_revenue_manager->is_connected() ); - - $settings = $this->reader_revenue_manager->get_settings()->get(); - $this->synchronize_onboarding_state->register(); - - $this->assertFalse( $settings['publicationOnboardingStateChanged'] ); - - do_action( Synchronize_OnboardingState::CRON_SYNCHRONIZE_ONBOARDING_STATE ); - - $settings = $this->reader_revenue_manager->get_settings()->get(); - $this->assertTrue( $settings['publicationOnboardingStateChanged'] ); - } - - public function test_maybe_schedule_synchronize_onboarding_state() { - $this->assertFalse( wp_next_scheduled( Synchronize_OnboardingState::CRON_SYNCHRONIZE_ONBOARDING_STATE ) ); - $this->synchronize_onboarding_state->maybe_schedule_synchronize_onboarding_state(); - - $this->assertTrue( - (bool) wp_next_scheduled( Synchronize_OnboardingState::CRON_SYNCHRONIZE_ONBOARDING_STATE ) - ); - } -} diff --git a/tests/phpunit/integration/Modules/Reader_Revenue_Manager/Synchronize_PublicationTest.php b/tests/phpunit/integration/Modules/Reader_Revenue_Manager/Synchronize_PublicationTest.php new file mode 100644 index 00000000000..676cde34e6a --- /dev/null +++ b/tests/phpunit/integration/Modules/Reader_Revenue_Manager/Synchronize_PublicationTest.php @@ -0,0 +1,297 @@ +user->create( array( 'role' => 'administrator' ) ); + + $context = new Context( GOOGLESITEKIT_PLUGIN_MAIN_FILE ); + $this->options = new Options( $context ); + $this->user_options = new User_Options( $context, $user_id ); + $this->authentication = new Authentication( $context, $this->options, $this->user_options ); + + // Fake a valid authentication token on the client. + $this->authentication->get_oauth_client()->set_token( array( 'access_token' => 'valid-auth-token' ) ); + $this->authentication->verification()->set( true ); + + $this->fake_site_connection(); + add_filter( 'googlesitekit_setup_complete', '__return_true', 100 ); + + $this->reader_revenue_manager = new Reader_Revenue_Manager( $context, $this->options, $this->user_options, $this->authentication ); + $this->authentication->get_oauth_client()->set_granted_scopes( + $this->reader_revenue_manager->get_scopes() + ); + $this->user_options->switch_user( 0 ); + $this->reader_revenue_manager->get_settings()->register(); + + $this->reader_revenue_manager->get_settings()->merge( + array( + 'publicationID' => '123456789', + 'publicationOnboardingState' => 'ONBOARDING_ACTION_REQUIRED', + 'publicationOnboardingStateChanged' => false, + 'productID' => 'openaccess', + 'productIDs' => array(), + 'paymentOption' => '', + 'ownerID' => $user_id, + ), + ); + + $this->synchronize_publication = new Synchronize_Publication( $this->reader_revenue_manager, $this->user_options ); + } + + public function fake_sync_publication() { + $publication_id = $this->reader_revenue_manager->get_settings()->get()['publicationID']; + + FakeHttp::fake_google_http_handler( + $this->reader_revenue_manager->get_client(), + function ( Request $request ) use ( $publication_id ) { + $url = parse_url( $request->getUri() ); + + if ( '/v1/publications' === $url['path'] ) { + $basic_product = new Product(); + $basic_product->setName( 'testpubID:basic' ); + + $advanced_product = new Product(); + $advanced_product->setName( 'testpubID:advanced' ); + + $payment_options = new PaymentOptions(); + $payment_options->subscriptions = true; + + $publication = new Publication(); + $publication->setPublicationId( $publication_id ); + $publication->setOnboardingState( 'ONBOARDING_COMPLETE' ); + $publication->setProducts( + array( + $basic_product, + $advanced_product, + ) + ); + $publication->setPaymentOptions( $payment_options ); + + $response = new ListPublicationsResponse(); + $response->setPublications( array( $publication ) ); + + return new Response( + 200, + array( 'content-type' => 'application/json' ), + json_encode( $response ) + ); + } + + return new Response( 200 ); + } + ); + } + + public function test_register() { + remove_all_actions( Synchronize_Publication::CRON_SYNCHRONIZE_PUBLICATION ); + $this->synchronize_publication->register(); + + $this->assertEquals( 10, has_action( Synchronize_Publication::CRON_SYNCHRONIZE_PUBLICATION ) ); + } + + public function test_synchronize_onboarding_state() { + $this->fake_sync_publication(); + + $this->assertTrue( $this->reader_revenue_manager->is_connected() ); + + $settings = $this->reader_revenue_manager->get_settings()->get(); + $this->synchronize_publication->register(); + + $this->assertEquals( + 'ONBOARDING_ACTION_REQUIRED', + $settings['publicationOnboardingState'] + ); + $this->assertFalse( $settings['publicationOnboardingStateChanged'] ); + + do_action( Synchronize_Publication::CRON_SYNCHRONIZE_PUBLICATION ); + + $settings = $this->reader_revenue_manager->get_settings()->get(); + + $this->assertEquals( + 'ONBOARDING_COMPLETE', + $settings['publicationOnboardingState'] + ); + $this->assertTrue( $settings['publicationOnboardingStateChanged'] ); + } + + public function test_synchronize_onboarding_state_with_non_existent_publication() { + $this->fake_sync_publication(); + + $this->assertTrue( $this->reader_revenue_manager->is_connected() ); + + $settings = $this->reader_revenue_manager->get_settings()->get(); + $this->synchronize_publication->register(); + + $this->assertEquals( + 'ONBOARDING_ACTION_REQUIRED', + $settings['publicationOnboardingState'] + ); + $this->assertFalse( $settings['publicationOnboardingStateChanged'] ); + + $this->reader_revenue_manager->get_settings()->merge( + array( + 'publicationID' => '987654321', + ), + ); + + do_action( Synchronize_Publication::CRON_SYNCHRONIZE_PUBLICATION ); + + $settings = $this->reader_revenue_manager->get_settings()->get(); + + $this->assertEquals( + 'ONBOARDING_ACTION_REQUIRED', + $settings['publicationOnboardingState'] + ); + $this->assertFalse( $settings['publicationOnboardingStateChanged'] ); + } + + public function test_synchronize_product_ids() { + $this->enable_feature( 'rrmModuleV2' ); + $this->fake_sync_publication(); + + $this->assertTrue( $this->reader_revenue_manager->is_connected() ); + + $settings = $this->reader_revenue_manager->get_settings()->get(); + $this->synchronize_publication->register(); + + $this->assertEmpty( $settings['productIDs'] ); + + do_action( Synchronize_Publication::CRON_SYNCHRONIZE_PUBLICATION ); + + $settings = $this->reader_revenue_manager->get_settings()->get(); + $this->assertEquals( array( 'basic', 'advanced' ), $settings['productIDs'] ); + } + + public function test_synchronize_product_ids_with_non_existent_publication() { + $this->enable_feature( 'rrmModuleV2' ); + $this->fake_sync_publication(); + + $this->assertTrue( $this->reader_revenue_manager->is_connected() ); + + $settings = $this->reader_revenue_manager->get_settings()->get(); + $this->synchronize_publication->register(); + + $this->reader_revenue_manager->get_settings()->merge( + array( + 'publicationID' => '987654321', + ), + ); + + $this->assertEmpty( $settings['productIDs'] ); + + do_action( Synchronize_Publication::CRON_SYNCHRONIZE_PUBLICATION ); + + $settings = $this->reader_revenue_manager->get_settings()->get(); + $this->assertEmpty( $settings['productIDs'] ); + } + + public function test_synchronize_payment_option() { + $this->enable_feature( 'rrmModuleV2' ); + $this->fake_sync_publication(); + + $this->assertTrue( $this->reader_revenue_manager->is_connected() ); + + $settings = $this->reader_revenue_manager->get_settings()->get(); + $this->synchronize_publication->register(); + + $this->assertEmpty( $settings['paymentOption'] ); + + do_action( Synchronize_Publication::CRON_SYNCHRONIZE_PUBLICATION ); + + $settings = $this->reader_revenue_manager->get_settings()->get(); + $this->assertEquals( 'subscriptions', $settings['paymentOption'] ); + } + + public function test_synchronize_payment_option_with_non_existent_publication() { + $this->enable_feature( 'rrmModuleV2' ); + $this->fake_sync_publication(); + + $this->assertTrue( $this->reader_revenue_manager->is_connected() ); + + $settings = $this->reader_revenue_manager->get_settings()->get(); + $this->synchronize_publication->register(); + + $this->reader_revenue_manager->get_settings()->merge( + array( + 'publicationID' => '987654321', + ), + ); + + $this->assertEmpty( $settings['paymentOption'] ); + + do_action( Synchronize_Publication::CRON_SYNCHRONIZE_PUBLICATION ); + + $settings = $this->reader_revenue_manager->get_settings()->get(); + $this->assertEmpty( $settings['paymentOption'] ); + } + + public function test_maybe_schedule_synchronize_publication() { + $this->assertFalse( wp_next_scheduled( Synchronize_Publication::CRON_SYNCHRONIZE_PUBLICATION ) ); + $this->synchronize_publication->maybe_schedule_synchronize_publication(); + + $this->assertTrue( + (bool) wp_next_scheduled( Synchronize_Publication::CRON_SYNCHRONIZE_PUBLICATION ) + ); + } +}