Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Product Statuses - Handle failure of the Update Product Statuses Job #2271

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,13 @@
'context' => [ 'view' ],
'readonly' => true,
],
'error' => [
'type' => 'string',
'description' => __( 'Error message in case of failure', 'google-listings-and-ads' ),
'context' => [ 'view' ],
'readonly' => true,
'default' => null,
],

Check warning on line 185 in src/API/Site/Controllers/MerchantCenter/ProductStatisticsController.php

View check run for this annotation

Codecov / codecov/patch

src/API/Site/Controllers/MerchantCenter/ProductStatisticsController.php#L179-L185

Added lines #L179 - L185 were not covered by tests
];
}

Expand Down
42 changes: 24 additions & 18 deletions src/Jobs/UpdateMerchantProductStatuses.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Automattic\WooCommerce\GoogleListingsAndAds\MerchantCenter\MerchantCenterService;
use Automattic\WooCommerce\GoogleListingsAndAds\API\Google\MerchantReport;
use Automattic\WooCommerce\GoogleListingsAndAds\MerchantCenter\MerchantStatuses;
use Throwable;

defined( 'ABSPATH' ) || exit;

Expand Down Expand Up @@ -79,26 +80,31 @@ public function can_schedule( $args = [] ): bool {
*
* @param int[] $items An array of job arguments.
*
* @throws JobException If the shipping settings cannot be synced.
* @throws JobException If the merchant product statuses cannot be retrieved..
*/
public function process_items( array $items ) {
$next_page_token = $items['next_page_token'] ?? null;

// Clear the cache if we're starting from the beginning.
if ( ! $next_page_token ) {
$this->merchant_statuses->clear_cache();
$this->merchant_statuses->delete_product_statuses_count_intermediate_data();
}

$results = $this->merchant_report->get_product_view_report( $next_page_token );
$next_page_token = $results['next_page_token'];

$this->merchant_statuses->update_product_stats( $results['statuses'] );

if ( $next_page_token ) {
$this->schedule( [ [ 'next_page_token' => $next_page_token ] ] );
} else {
$this->merchant_statuses->handle_complete_mc_statuses_fetching();
try {
$next_page_token = $items['next_page_token'] ?? null;

// Clear the cache if we're starting from the beginning.
if ( ! $next_page_token ) {
$this->merchant_statuses->clear_cache();
$this->merchant_statuses->delete_product_statuses_count_intermediate_data();
}

$results = $this->merchant_report->get_product_view_report( $next_page_token );
$next_page_token = $results['next_page_token'];

$this->merchant_statuses->update_product_stats( $results['statuses'] );

if ( $next_page_token ) {
$this->schedule( [ [ 'next_page_token' => $next_page_token ] ] );
} else {
$this->merchant_statuses->handle_complete_mc_statuses_fetching();
}
} catch ( Throwable $e ) {
$this->merchant_statuses->handle_failed_mc_statuses_fetching( $e->getMessage() );
throw new JobException( 'Error updating merchant product statuses: ' . $e->getMessage() );
}
}

Expand Down
30 changes: 30 additions & 0 deletions src/MerchantCenter/MerchantStatuses.php
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,14 @@ public function get_product_statistics( bool $force_refresh = false ): array {
'timestamp' => $this->cache_created_time->getTimestamp(),
'statistics' => [],
'loading' => true,
'error' => null,
];
}

if ( $this->mc_statuses['error'] ) {
return $this->mc_statuses;
}

$counting_stats = $this->mc_statuses['statistics'];
$counting_stats = array_merge(
[ 'active' => $counting_stats[ MCStatus::PARTIALLY_APPROVED ] + $counting_stats[ MCStatus::APPROVED ] ],
Expand Down Expand Up @@ -812,6 +817,30 @@ protected function calculate_total_synced_product_statistics( array $statistics
return array_sum( $synced_status_values );
}

/**
* Handle the failure of the Merchant Center statuses fetching.
*
* @since x.x.x
*
* @param string $error_message The error message.
*/
public function handle_failed_mc_statuses_fetching( string $error_message = '' ) {
$this->delete_product_statuses_count_intermediate_data();

$mc_statuses = [
'timestamp' => $this->cache_created_time->getTimestamp(),
'statistics' => [],
'loading' => false,
'error' => $error_message,
];

$this->container->get( TransientsInterface::class )->set(
Transients::MC_STATUSES,
$mc_statuses,
$this->get_status_lifetime()
);
}


/**
* Handle the completion of the Merchant Center statuses fetching.
Expand All @@ -837,6 +866,7 @@ public function handle_complete_mc_statuses_fetching() {
'timestamp' => $this->cache_created_time->getTimestamp(),
'statistics' => $intermediate_data,
'loading' => false,
'error' => null,
];

$this->container->get( TransientsInterface::class )->set(
Expand Down
38 changes: 38 additions & 0 deletions tests/Unit/Jobs/UpdateMerchantProductStatusesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@
use Automattic\WooCommerce\GoogleListingsAndAds\MerchantCenter\MerchantStatuses;
use Automattic\WooCommerce\GoogleListingsAndAds\Tests\Framework\UnitTest;
use Automattic\WooCommerce\GoogleListingsAndAds\Value\MCStatus;
use Automattic\WooCommerce\GoogleListingsAndAds\Jobs\JobException;
use PHPUnit\Framework\MockObject\MockObject;
use Exception;
use Error;

/**
* Class UpdateMerchantProductStatusesTest
Expand Down Expand Up @@ -210,4 +212,40 @@ function ( $statuses ) use ( $matcher ) {

$this->job->schedule();
}

public function test_update_merchant_product_statuses_when_view_report_throws_error() {
$this->merchant_center_service->method( 'is_connected' )
->willReturn( true );

$this->merchant_report->expects( $this->exactly( 1 ) )
->method( 'get_product_view_report' )
->willThrowException( new Error( 'error' ) );

$this->merchant_statuses->expects( $this->exactly( 1 ) )
->method( 'handle_failed_mc_statuses_fetching' )
->with( 'error' );

$this->expectException( JobException::class );
$this->expectExceptionMessage( 'Error updating merchant product statuses: error' );

do_action( self::PROCESS_ITEM_HOOK, [] );
}

public function test_update_merchant_product_statuses_when_view_report_throws_exception() {
$this->merchant_center_service->method( 'is_connected' )
->willReturn( true );

$this->merchant_report->expects( $this->exactly( 1 ) )
->method( 'get_product_view_report' )
->willThrowException( new Exception( 'error' ) );

$this->merchant_statuses->expects( $this->exactly( 1 ) )
->method( 'handle_failed_mc_statuses_fetching' )
->with( 'error' );

$this->expectException( JobException::class );
$this->expectExceptionMessage( 'Error updating merchant product statuses: error' );

do_action( self::PROCESS_ITEM_HOOK, [] );
}
}
69 changes: 69 additions & 0 deletions tests/Unit/MerchantCenter/MerchantStatusesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ public function test_get_product_statistics_with_transient() {
MCStatus::NOT_SYNCED => 0,
],
'loading' => false,
'error' => null,
]
);

Expand Down Expand Up @@ -268,6 +269,40 @@ public function test_get_product_statistics_with_transient() {
);
}

public function test_get_product_statistics_with_transient_and_error() {
$this->merchant_center_service->expects( $this->once() )
->method( 'is_connected' )
->willReturn( true );

$this->transients->expects( $this->once() )
->method( 'get' )
->willReturn(
[
'statistics' => [],
'loading' => false,
'error' => 'My error message.',
]
);

$this->update_merchant_product_statuses_job->expects( $this->never() )
->method( 'schedule' );

$this->update_merchant_product_statuses_job->expects( $this->exactly( 2 ) )
->method( 'is_scheduled' );

$product_statistics = $this->merchant_statuses->get_product_statistics();

$this->assertEquals(
'My error message.',
$product_statistics['error']
);

$this->assertEquals(
false,
$product_statistics['loading']
);
}

public function test_get_product_statistics_without_transient() {
$this->merchant_center_service->expects( $this->once() )
->method( 'is_connected' )
Expand Down Expand Up @@ -316,6 +351,7 @@ public function test_get_product_statistics_with_product_statuses_job_running()
MCStatus::NOT_SYNCED => 0,
],
'loading' => false,
'error' => null,
]
);

Expand Down Expand Up @@ -521,6 +557,39 @@ function ( $value ) {
$this->merchant_statuses->handle_complete_mc_statuses_fetching();
}

public function test_handle_failed_mc_statuses_fetching() {
$this->options->expects( $this->once() )
->method( 'delete' )->with( OptionsInterface::PRODUCT_STATUSES_COUNT_INTERMEDIATE_DATA );

$this->transients->expects( $this->once() )
->method( 'set' )->with(
Transients::MC_STATUSES,
$this->callback(
function ( $value ) {
$this->assertEquals(
[],
$value['statistics']
);

$this->assertEquals(
'My error message.',
$value['error']
);

$this->assertEquals(
false,
$value['loading']
);

return true;
}
),
self::MC_STATUS_LIFETIME
);

$this->merchant_statuses->handle_failed_mc_statuses_fetching( 'My error message.' );
}

public function test_update_product_with_multiple_variables_and_multiple_batches_with_different_statuses() {
$variable_product = WC_Helper_Product::create_variation_product();
$variations = $variable_product->get_available_variations( 'objects' );
Expand Down
Loading