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

Get product stats using the Merchant Center report query #2229

Merged
Merged
Show file tree
Hide file tree
Changes from 140 commits
Commits
Show all changes
147 commits
Select commit Hold shift + click to select a range
25db819
WIP
jorgemd24 Oct 25, 2023
81918f5
Add Missing Jetpack functions
jorgemd24 Nov 6, 2023
05ab472
Add JetpackWPCOM to the service provider
jorgemd24 Nov 6, 2023
6975f77
Move out initial code of GoogleListingsAndAdsPlugin file
jorgemd24 Nov 6, 2023
1f7ca4c
Added links to the Jetpack functions and remove duplicated PHPDoc
jorgemd24 Nov 7, 2023
021017b
Merge pull request #2145 from woocommerce/add/missing-functions-jetpa…
jorgemd24 Nov 8, 2023
b4130fe
Filter results for WC Proxy
jorgemd24 Nov 9, 2023
ebe9798
WIP tests
jorgemd24 Nov 9, 2023
dc1fcb6
Rename file
jorgemd24 Nov 10, 2023
e77bdbf
Add tests
jorgemd24 Nov 10, 2023
61a4c5b
Update phpunit polyfills to 1.1 for WP 6.4
Nov 9, 2023
83e016a
Merge branch 'develop' into feature/google-api-project
jorgemd24 Nov 10, 2023
6076fc1
Merge branch 'feature/google-api-project' into add/gla_syncable_filter
jorgemd24 Nov 10, 2023
2f81f35
Fix eslint errors
jorgemd24 Nov 10, 2023
686b966
Fix phpcs tests
jorgemd24 Nov 10, 2023
26f8c7b
Rename post_types_to_filter
jorgemd24 Nov 13, 2023
2a5d4b7
Tweak formatting
jorgemd24 Nov 13, 2023
e78d7d0
Check for the value of gla_syncable
jorgemd24 Nov 13, 2023
5ec640e
Tweaks filter function names and PHPDocs
jorgemd24 Nov 14, 2023
b84999b
Use the ChannelVisibility constants
jorgemd24 Nov 14, 2023
faa9c56
Merge pull request #2152 from woocommerce/add/gla_syncable_filter
jorgemd24 Nov 20, 2023
ef3a011
Merge branch 'develop' into feature/google-api-project
jorgemd24 Dec 5, 2023
f673381
Create NotificationsService
puntope Dec 27, 2023
897e2d1
Call Notify on Product changes
puntope Dec 27, 2023
8587db5
Update tests
puntope Dec 27, 2023
80c27f0
Start `release/2.5.13`.
github-actions[bot] Dec 6, 2023
ca4e35a
Update readme.txt
Dec 6, 2023
caa952a
Set migration version number
Dec 6, 2023
704efb7
Product version bump update
Dec 6, 2023
1781950
Changelog update
Dec 6, 2023
dd7f8de
Update hooks documentation from branch.
github-actions[bot] Dec 6, 2023
7072aea
Add (budget and audiences) tracking for Onboarding completed with Ads
puntope Nov 30, 2023
7da36c0
Add audiences and budget inside existing gla_onboarding_complete_with…
puntope Dec 11, 2023
721c0b2
Prevent undefined country codes
puntope Dec 12, 2023
abf46d0
Change the onboarding to require a connected Google Ads account and m…
eason9487 Dec 13, 2023
c5f5436
Hide the content about the ad budget in the Boost card before a Googl…
eason9487 Dec 13, 2023
4e80346
Update tracking README.
eason9487 Dec 13, 2023
0453a6d
Update budget recommendation text
martynmjones Dec 5, 2023
138b256
Fix the budget recommendation E2E tests for PR #2153 after cherry-pic…
eason9487 Dec 14, 2023
cc8fe7b
Add more utils to mock requests for E2E tests.
eason9487 Dec 14, 2023
2d976e3
Adjust E2E tests to reflect the change of requiring Google Ads connec…
eason9487 Dec 14, 2023
ee00514
Fix the problem that E2E util `checkFAQExpandable` doesn't wait for t…
eason9487 Dec 14, 2023
ebc1830
Change tested PHP versions
mikkamp Dec 15, 2023
5722721
Generate coverage report when testing on PHP 8.2
mikkamp Dec 15, 2023
789400d
Fix price in purchase event
jorgemd24 Dec 15, 2023
1be66fb
Start `release/2.5.14`.
github-actions[bot] Dec 18, 2023
a4f9e73
Update Readme.txt
puntope Dec 18, 2023
fd6fc0d
Product version bump update
puntope Dec 18, 2023
2d50495
Changelog update
puntope Dec 18, 2023
95bad26
Update hooks documentation from branch.
github-actions[bot] Dec 18, 2023
adf7b88
Update link for developer.woo.com
mikkamp Dec 19, 2023
0577969
WIP
jorgemd24 Oct 25, 2023
39eb4e7
Merge branch 'feature/google-api-project' into add/api-pull-update-hooks
puntope Dec 27, 2023
ac29447
Apply review comments
puntope Dec 29, 2023
96fddfb
Merge pull request #2190 from woocommerce/add/api-pull-update-hooks
puntope Dec 29, 2023
ce8b86f
Scheduled batched notifications using meta handler
puntope Jan 18, 2024
d8cebdb
Tweak logic for schedule notifications
puntope Jan 23, 2024
832d0dc
Tests for Notification Service
puntope Jan 23, 2024
94c4fb6
Tests for ProductHelper
puntope Jan 24, 2024
0386c74
Update docs
puntope Jan 24, 2024
51b729f
Update tests
puntope Jan 24, 2024
619123f
Add tests for Notification
puntope Jan 24, 2024
d85d7ed
PHPCS
puntope Jan 24, 2024
a60ac81
Fix package path
puntope Jan 24, 2024
c47b7fa
Fix tests dependencies
puntope Jan 24, 2024
b716805
Fix tests dependencies
puntope Jan 24, 2024
d4c2d37
Remove trailing comma in constructor
puntope Jan 25, 2024
545cd22
Refactor route param name
puntope Jan 25, 2024
8ee54d1
Remove identation
puntope Jan 25, 2024
fd11304
Remove identation from functions
puntope Jan 25, 2024
3d9b4bc
Remove unused dependency
puntope Jan 25, 2024
ba7ed8f
Add params in function signature
puntope Jan 25, 2024
b3b0735
Avoid item id to be null
puntope Jan 25, 2024
8940067
Refactor dependencies
puntope Jan 25, 2024
a1eaad6
Refactor tests
puntope Jan 25, 2024
a1d5f22
PHPCS
puntope Jan 25, 2024
d3a641f
Change doc
puntope Jan 26, 2024
b9af9f1
Remove filter notification products
puntope Jan 26, 2024
82795a7
Remove unused dependency
puntope Jan 26, 2024
99f5b9e
Add useful hooks
puntope Jan 26, 2024
08efcce
Add missing return types
puntope Jan 29, 2024
d93c7b7
Remove extra space
puntope Jan 29, 2024
cbb00a2
Add missing docs
puntope Jan 29, 2024
677e4ec
Clarify docs
puntope Jan 29, 2024
6315209
Verify if product is synced in MC
puntope Jan 29, 2024
de3e24c
Update docs
puntope Jan 29, 2024
65dff81
Add Tests for ProductNotificationJob
puntope Jan 29, 2024
ac3f6cc
Remove PENDING_DELETE as a valid status for has_notified_cretion
puntope Jan 29, 2024
75e4c96
Remove PENDING_DELETE as a valid status for has_notified_cretion
puntope Jan 29, 2024
3056459
Remove unused dependency
puntope Jan 29, 2024
2bb00ca
Add return type for void
puntope Jan 29, 2024
3b1ef31
WIP: Add product view report
jorgemd24 Jan 30, 2024
bd3e0b6
Merge pull request #2202 from woocommerce/add/hooks-api-pull-metas
puntope Jan 30, 2024
252e9ed
Fix PHPCS in GoogleListingsAndAdsPlugin
puntope Jan 30, 2024
75a61ef
Solve PHPCS
puntope Jan 30, 2024
c4fde99
Remove old wrong code
puntope Jan 30, 2024
7fd1766
Remove unsupported return type
puntope Jan 30, 2024
b4fa9c5
PHPCS for tests
puntope Jan 30, 2024
b2839a1
WIP - Get stats with Merchant report
jorgemd24 Jan 30, 2024
bbf3d3c
Refactor to get offer id for new and old products.
jorgemd24 Jan 31, 2024
a2fa2f5
Handle page size
jorgemd24 Jan 31, 2024
e79488c
Merge pull request #2228 from woocommerce/fix/phpcs
puntope Jan 31, 2024
3fdccab
Fix issue with empty results
jorgemd24 Jan 31, 2024
7b5b178
Merge branch 'develop' into add/product-view-report-query
jorgemd24 Jan 31, 2024
50e108c
Fix typo
jorgemd24 Jan 31, 2024
44c7c4d
Merge branch 'develop' into feature/google-api-project
jorgemd24 Jan 31, 2024
fb619db
Merge branch 'feature/google-api-project' into add/product-view-repor…
jorgemd24 Jan 31, 2024
30aa787
Fix PHPDocs
jorgemd24 Jan 31, 2024
2185426
Remove extra comment
jorgemd24 Jan 31, 2024
9f78ac3
Change callback with inline calling
jorgemd24 Feb 4, 2024
d4df943
Change spread operator with array_merge
jorgemd24 Feb 4, 2024
41decb2
Fix typo expiration date
jorgemd24 Feb 4, 2024
82aadc1
Fix typo expiration date
jorgemd24 Feb 4, 2024
9592a80
Refactor get_product_view_query
jorgemd24 Feb 5, 2024
6c1b818
Add UpdateMerchantStatuses Job
jorgemd24 Feb 5, 2024
2657541
Remove unused plugin helper
jorgemd24 Feb 5, 2024
16b27b3
Remove get_offer_id function as we will fetch all products
jorgemd24 Feb 5, 2024
fdaaf30
Rename function convert_aggregated_status_to_mc_status
jorgemd24 Feb 5, 2024
2cfc1f2
Change query not synced products
jorgemd24 Feb 5, 2024
d8da89b
Skip product from status count if it is not sync ready
jorgemd24 Feb 5, 2024
8c6807c
Fix warning undefined index
jorgemd24 Feb 5, 2024
7a13ccc
Add ShoppingContentDateTrait
jorgemd24 Feb 5, 2024
39608de
Rename get_product_view_report method and increase limit size
jorgemd24 Feb 5, 2024
71ba5c5
Refactor calculate product statuses
jorgemd24 Feb 5, 2024
3138785
Rename Update merchant product status job
jorgemd24 Feb 5, 2024
6426ea6
Adjust UpdateMerchantProductStatuses name
jorgemd24 Feb 5, 2024
7d1ef5a
Schedule the job if mc_status is not set
jorgemd24 Feb 5, 2024
ea936e6
Adjust product statiscits controller
jorgemd24 Feb 5, 2024
a68d980
Tweak tests test_find_mc_not_synced_product_ids
jorgemd24 Feb 6, 2024
09ec214
Remove unused ViewReportQuery filter
jorgemd24 Feb 6, 2024
0e92124
Schdule job if force refresh
jorgemd24 Feb 6, 2024
9451680
Remove schedule job from the controller
jorgemd24 Feb 6, 2024
497586b
Remove extra space
jorgemd24 Feb 6, 2024
c0138fa
Remove unused dependency
jorgemd24 Feb 7, 2024
122d684
Remove extra string when logging message
jorgemd24 Feb 7, 2024
930469e
Fix typo DateTime
jorgemd24 Feb 7, 2024
0e90b7d
Move responsability of Merchant Report
jorgemd24 Feb 7, 2024
8b85a6a
Remove unused dependency
jorgemd24 Feb 7, 2024
1cf0178
Add filter product report batch size
jorgemd24 Feb 7, 2024
264cd27
Check if the job is scheduled
jorgemd24 Feb 7, 2024
679b143
Move ShoppingContentDateTrait
jorgemd24 Feb 7, 2024
2123e0b
Update PHPDocs and remove unnecessary $rows variable
jorgemd24 Feb 7, 2024
4c304f3
Show error message when unable to retrieve Product View Report
jorgemd24 Feb 7, 2024
56d20b5
Rename methods
jorgemd24 Feb 7, 2024
319a7a1
Remove ProductMetaHandler::KEY_VISIBILITY from not_synced_product_ids
jorgemd24 Feb 8, 2024
af810b1
Add comment so we can remove ProductMetaHandler::KEY_SYNC_STATUS
jorgemd24 Feb 8, 2024
7b0f3b2
Revert "Merge branch 'feature/google-api-project' into add/product-vi…
jorgemd24 Feb 8, 2024
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
87 changes: 87 additions & 0 deletions src/API/Google/MerchantReport.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Automattic\WooCommerce\Admin\API\Reports\TimeInterval;
use Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query\MerchantFreeListingReportQuery;
use Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query\MerchantProductReportQuery;
use Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query\MerchantProductViewReportQuery;
use Automattic\WooCommerce\GoogleListingsAndAds\Exception\InvalidValue;
use Automattic\WooCommerce\GoogleListingsAndAds\Options\OptionsAwareInterface;
use Automattic\WooCommerce\GoogleListingsAndAds\Options\OptionsAwareTrait;
Expand All @@ -14,6 +15,8 @@
use Automattic\WooCommerce\GoogleListingsAndAds\Vendor\Google\Service\ShoppingContent;
use Automattic\WooCommerce\GoogleListingsAndAds\Vendor\Google\Service\ShoppingContent\ReportRow;
use Automattic\WooCommerce\GoogleListingsAndAds\Vendor\Google\Service\ShoppingContent\Segments;
use Automattic\WooCommerce\GoogleListingsAndAds\Value\MCStatus;
use Automattic\WooCommerce\GoogleListingsAndAds\MerchantCenter\ShoppingContentDateTrait;
use DateTime;
use Exception;

Expand All @@ -26,6 +29,7 @@ class MerchantReport implements OptionsAwareInterface {

use OptionsAwareTrait;
use ReportTrait;
use ShoppingContentDateTrait;

/**
* The shopping service.
Expand All @@ -52,6 +56,89 @@ public function __construct( ShoppingContent $service, ProductHelper $product_he
$this->product_helper = $product_helper;
}

/**
* Get ProductView Query response.
*
* @param string|null $next_page_token The next page token.
* @return array Array of products along with their statuses.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what the best description is here, but it's also including the next_page token.

*
* @throws Exception If the product view report data can't be retrieved.
*/
public function get_product_view_report( $next_page_token = null ): array {
$batch_size = apply_filters( 'woocommerce_gla_product_view_report_page_size', 1000 );

try {
$product_view_data = [
'statuses' => [],
'next_page' => null,
];

$query = new MerchantProductViewReportQuery(
[
'next_page' => $next_page_token,
'per_page' => $batch_size,
]
);

$response = $query
->set_client( $this->service, $this->options->get_merchant_id() )
->get_results();

$rows = $response->getResults();

foreach ( $rows as $row ) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a big deal, but we might as well shorten this to one line since $rows isn't referenced anywhere else.


/** @var ProductView $product_view */
$product_view = $row->getProductView();

$wc_product_id = $this->product_helper->get_wc_product_id( $product_view->getId() );
$mc_product_status = $this->convert_aggregated_status_to_mc_status( $product_view->getAggregatedDestinationStatus() );

// Skip if the product id does not exist
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a big deal, but technically we've only tried extracting the product ID from the string, we haven't actually checked if it exists.

This makes me wonder though, we are extracting from $product_view->getId(), why is both the offer_id and id included in the query MerchantProductViewReportQuery then? Not a big deal to leave it there, but was just curious. Seems like getOfferId() would return a much shorter string.

if ( ! $wc_product_id ) {
continue;
}

$product_view_data['statuses'][] = [
'product_id' => $wc_product_id,
'status' => $mc_product_status,
'expiration_date' => $this->convert_shopping_content_date( $product_view->getExpirationDate() ),
];

}

$product_view_data['next_page'] = $response->getNextPageToken();

return $product_view_data;
} catch ( GoogleException $e ) {
do_action( 'woocommerce_gla_mc_client_exception', $e, __METHOD__ );
throw new Exception( __( 'Unable to retrieve Product View Report.', 'google-listings-and-ads' ), $e->getCode() );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just wondering, since this is going to be recorded as a failure in a Scheduled Action scheduler job, do you think it will be useful to include both $e->getMessage and $e->getCode? Otherwise they have to look up the matching timestamp to see more details in the log.

Suggested change
throw new Exception( __( 'Unable to retrieve Product View Report.', 'google-listings-and-ads' ), $e->getCode() );
throw new Exception( __( 'Unable to retrieve Product View Report: ', 'google-listings-and-ads' ) . $e->getMessage(), $e->getCode() );

Or format the error with sprintf if we want to allow for greater translation/RTL support.

}
}

/**
* Convert the product view aggregated status to the MC status.
*
* @param string $status The status of the product.
*
* @return array The MC status.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we just make a small clarification that this is "The aggregated status of the product".
Also I think the return status was intended to be a string here.

*/
protected function convert_aggregated_status_to_mc_status( string $status ): string {
switch ( $status ) {
case 'ELIGIBLE':
return MCStatus::APPROVED;
case 'ELIGIBLE_LIMITED':
return MCStatus::PARTIALLY_APPROVED;
case 'NOT_ELIGIBLE_OR_DISAPPROVED':
return MCStatus::DISAPPROVED;
case 'PENDING':
return MCStatus::PENDING;
default:
return MCStatus::NOT_SYNCED;
}
}


/**
* Get report data for free listings.
*
Expand Down
54 changes: 54 additions & 0 deletions src/API/Google/Query/MerchantProductViewReportQuery.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php
declare( strict_types=1 );

namespace Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query;

defined( 'ABSPATH' ) || exit;

/**
* Class MerchantProductViewReportQuery
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query
*/
class MerchantProductViewReportQuery extends MerchantQuery {

use ReportQueryTrait;

/**
* Query constructor.
*
* @param array $args Query arguments.
*/
public function __construct( array $args ) {
parent::__construct( 'ProductView' );
$this->set_initial_columns();
$this->handle_query_args( $args );
}


/**
* Filter the query by a list of ID's.
*
* @param array $ids list of ID's to filter by.
*
* @return $this
*/
public function filter( array $ids ): QueryInterface {
// No filtering used for product view report.
return $this;
}

/**
* Set the initial columns for this query.
*/
protected function set_initial_columns() {
$this->columns(
[
'id' => 'product_view.id',
'offer_id' => 'product_view.offer_id',
'expiration_date' => 'product_view.expiration_date',
'status' => 'product_view.aggregated_destination_status',
]
);
}
}
140 changes: 140 additions & 0 deletions src/Google/NotificationsService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
<?php
declare( strict_types=1 );

namespace Automattic\WooCommerce\GoogleListingsAndAds\Google;

use Automattic\Jetpack\Connection\Client;
use Automattic\WooCommerce\GoogleListingsAndAds\Infrastructure\Service;
use Jetpack_Options;

defined( 'ABSPATH' ) || exit;

/**
* Class NotificationsService
* This class implements a service to Notify a partner about Shop Data Updates
*
* @since x.x.x
* @package Automattic\WooCommerce\GoogleListingsAndAds\Google
*/
class NotificationsService implements Service {

// List of Topics to be used.
public const TOPIC_PRODUCT_CREATED = 'product.create';
public const TOPIC_PRODUCT_DELETED = 'product.delete';
public const TOPIC_PRODUCT_UPDATED = 'product.update';
public const TOPIC_COUPON_CREATED = 'coupon.create';
public const TOPIC_COUPON_DELETED = 'coupon.delete';
public const TOPIC_COUPON_UPDATED = 'coupon.update';
public const TOPIC_SHIPPING_SAVED = 'action.woocommerce_after_shipping_zone_object_save';
public const TOPIC_SHIPPING_DELETED = 'action.woocommerce_delete_shipping_zone';

/**
* The url to send the notification
*
* @var string $notification_url
*/
private $notification_url;


/**
* Class constructor
*/
public function __construct() {
$blog_id = Jetpack_Options::get_option( 'id' );
$this->notification_url = "https://public-api.wordpress.com/wpcom/v2/sites/{$blog_id}/partners/google/notifications";
}

/**
* Calls the Notification endpoint in WPCOM.
* https://public-api.wordpress.com/wpcom/v2/sites/{site}/partners/google/notifications
*
* @param int $item_id
* @param string $topic
* @return bool True is the notification is successful. False otherwise.
*/
public function notify( int $item_id, string $topic ): bool {
/**
* Allow users to disable the notification request.
*
* @since x.x.x
*
* @param bool $value The current filter value. True by default.
* @param int $item_id The item_id for the notification.
* @param string $topic The topic for the notification.
*/
if ( ! apply_filters( 'woocommerce_gla_notify', true, $item_id, $topic ) ) {
return false;
}

do_action(
'woocommerce_gla_debug_message',
sprintf( 'Notification - Item ID: %d - Topic: %s', $item_id, $topic ),
__METHOD__
);

$remote_args = [
'method' => 'POST',
'timeout' => 30,
'headers' => [
'x-woocommerce-topic' => $topic,
],
'body' => [
'item_id' => $item_id,
],
'url' => $this->get_notification_url(),
];

$response = $this->do_request( $remote_args );

if ( is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) >= 400 ) {
$error = is_wp_error( $response ) ? $response->get_error_message() : wp_remote_retrieve_body( $response );
$this->notification_error( $item_id, $topic, $error );
return false;
}

return true;
}

/**
* Logs an error.
*
* @param int $item_id
* @param string $topic
* @param string $error
*/
private function notification_error( int $item_id, string $topic, string $error ): void {
do_action(
'woocommerce_gla_error',
sprintf( 'Error sending notification for Item ID %d with topic %s. %s', $item_id, $topic, $error ),
__METHOD__
);
}

/**
* Performs a Remote Request
*
* @param array $args
* @return array|\WP_Error
*/
protected function do_request( array $args ) {
return Client::remote_request( $args, wp_json_encode( $args['body'] ) );
}

/**
* Get the route
*
* @return string The route.
*/
public function get_notification_url(): string {
return $this->notification_url;
}

/**
* If the Notifications are enabled
*
* @return bool
*/
public function is_enabled(): bool {
return apply_filters( 'woocommerce_gla_notifications_enabled', true );
}
}
Loading
Loading