Implement Google Price Insights with update functionality
Major rewrite using correct Google Merchant API: - Use price_insights_product_view table (correct API endpoint) - Fetch suggested_price and predicted performance changes - Show predicted impact on impressions, clicks, conversions New features: - Individual "Update" button per product - Bulk update with checkbox selection - Pagination (50 products per page) - Sort by potential gain (highest first) Price handling: - Always use tax-inclusive prices for comparison with Google - Convert back to store format when saving (handles tax-exclusive stores) - Set as sale price when updating UI improvements: - Color-coded gain/loss values - Color-coded predicted changes - Summary stats showing products that can increase/decrease - Total potential gain calculation Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -457,27 +457,32 @@ class Informatiq_SP_Google_API {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all benchmark prices from Price Competitiveness Report.
|
||||
* Get price insights from Google's price_insights_product_view.
|
||||
*
|
||||
* @return array Associative array of offer_id => benchmark_price.
|
||||
* Returns suggested prices and predicted performance impact.
|
||||
*
|
||||
* @return array Associative array of offer_id => price insight data.
|
||||
*/
|
||||
public function get_all_benchmark_prices() {
|
||||
public function get_price_insights() {
|
||||
try {
|
||||
$endpoint = "/reports/v1beta/accounts/{$this->merchant_id}/reports:search";
|
||||
|
||||
$all_benchmarks = array();
|
||||
$all_insights = array();
|
||||
$page_token = null;
|
||||
|
||||
do {
|
||||
// New Merchant API uses snake_case table names.
|
||||
// Fields from product are prefixed with product_view.
|
||||
$query = array(
|
||||
'query' => "SELECT
|
||||
product_view.offer_id,
|
||||
product_view.gtin,
|
||||
product_view.title,
|
||||
benchmark_price
|
||||
FROM price_competitiveness_product_view",
|
||||
id,
|
||||
offer_id,
|
||||
title,
|
||||
brand,
|
||||
price,
|
||||
suggested_price,
|
||||
predicted_impressions_change_fraction,
|
||||
predicted_clicks_change_fraction,
|
||||
predicted_conversions_change_fraction
|
||||
FROM price_insights_product_view",
|
||||
);
|
||||
|
||||
if ( $page_token ) {
|
||||
@@ -486,53 +491,56 @@ class Informatiq_SP_Google_API {
|
||||
|
||||
$response = $this->api_request( 'POST', $endpoint, $query );
|
||||
|
||||
$this->logger->info( 'Benchmark API response keys: ' . wp_json_encode( array_keys( $response ) ) );
|
||||
if ( ! empty( $response['results'][0] ) ) {
|
||||
$this->logger->info( 'Sample benchmark result: ' . wp_json_encode( $response['results'][0] ) );
|
||||
// Log first result for debugging.
|
||||
if ( empty( $all_insights ) && ! empty( $response['results'][0] ) ) {
|
||||
$this->logger->info( 'Sample price insight: ' . wp_json_encode( $response['results'][0] ) );
|
||||
}
|
||||
|
||||
if ( ! empty( $response['results'] ) ) {
|
||||
foreach ( $response['results'] as $result ) {
|
||||
// Extract data - response nests product fields under productView.
|
||||
$product_view = $result['productView'] ?? array();
|
||||
$offer_id = $product_view['offerId'] ?? ( $product_view['offer_id'] ?? null );
|
||||
$gtin = $product_view['gtin'] ?? null;
|
||||
$title = $product_view['title'] ?? '';
|
||||
$insight = $result['priceInsightsProductView'] ?? $result;
|
||||
|
||||
$benchmark_price = null;
|
||||
// Try different possible response structures for benchmark.
|
||||
if ( isset( $result['benchmarkPrice']['amountMicros'] ) ) {
|
||||
$benchmark_price = (float) $result['benchmarkPrice']['amountMicros'] / 1000000;
|
||||
} elseif ( isset( $result['benchmark_price']['amountMicros'] ) ) {
|
||||
$benchmark_price = (float) $result['benchmark_price']['amountMicros'] / 1000000;
|
||||
} elseif ( isset( $result['priceBenchmark']['priceBenchmarkValue']['amountMicros'] ) ) {
|
||||
$benchmark_price = (float) $result['priceBenchmark']['priceBenchmarkValue']['amountMicros'] / 1000000;
|
||||
$offer_id = $insight['offerId'] ?? ( $insight['offer_id'] ?? null );
|
||||
$product_id = $insight['id'] ?? null;
|
||||
|
||||
// Extract offer_id from product_id if needed (format: lang~country~offerId).
|
||||
if ( ! $offer_id && $product_id ) {
|
||||
$parts = explode( '~', $product_id );
|
||||
if ( count( $parts ) >= 3 ) {
|
||||
$offer_id = $parts[ count( $parts ) - 1 ];
|
||||
}
|
||||
}
|
||||
|
||||
$own_price = null;
|
||||
if ( isset( $product_view['price']['amountMicros'] ) ) {
|
||||
$own_price = (float) $product_view['price']['amountMicros'] / 1000000;
|
||||
} elseif ( isset( $result['price']['amountMicros'] ) ) {
|
||||
$own_price = (float) $result['price']['amountMicros'] / 1000000;
|
||||
$current_price = null;
|
||||
if ( isset( $insight['price']['amountMicros'] ) ) {
|
||||
$current_price = (float) $insight['price']['amountMicros'] / 1000000;
|
||||
}
|
||||
|
||||
if ( $offer_id && $benchmark_price ) {
|
||||
$all_benchmarks[ 'offer_' . $offer_id ] = array(
|
||||
'benchmark_price' => $benchmark_price,
|
||||
'own_price' => $own_price,
|
||||
'title' => $title,
|
||||
'gtin' => $gtin,
|
||||
$suggested_price = null;
|
||||
if ( isset( $insight['suggestedPrice']['amountMicros'] ) ) {
|
||||
$suggested_price = (float) $insight['suggestedPrice']['amountMicros'] / 1000000;
|
||||
}
|
||||
|
||||
if ( $offer_id ) {
|
||||
$data = array(
|
||||
'offer_id' => $offer_id,
|
||||
'product_id' => $product_id,
|
||||
'title' => $insight['title'] ?? '',
|
||||
'brand' => $insight['brand'] ?? '',
|
||||
'google_price' => $current_price,
|
||||
'suggested_price' => $suggested_price,
|
||||
'predicted_impressions_change' => isset( $insight['predictedImpressionsChangeFraction'] )
|
||||
? (float) $insight['predictedImpressionsChangeFraction'] * 100
|
||||
: null,
|
||||
'predicted_clicks_change' => isset( $insight['predictedClicksChangeFraction'] )
|
||||
? (float) $insight['predictedClicksChangeFraction'] * 100
|
||||
: null,
|
||||
'predicted_conversions_change' => isset( $insight['predictedConversionsChangeFraction'] )
|
||||
? (float) $insight['predictedConversionsChangeFraction'] * 100
|
||||
: null,
|
||||
);
|
||||
|
||||
// Also index by GTIN if available.
|
||||
if ( $gtin ) {
|
||||
$all_benchmarks[ 'gtin_' . $gtin ] = array(
|
||||
'benchmark_price' => $benchmark_price,
|
||||
'own_price' => $own_price,
|
||||
'title' => $title,
|
||||
'offer_id' => $offer_id,
|
||||
);
|
||||
}
|
||||
$all_insights[ 'offer_' . $offer_id ] = $data;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -541,12 +549,12 @@ class Informatiq_SP_Google_API {
|
||||
|
||||
} while ( $page_token );
|
||||
|
||||
$this->logger->info( sprintf( 'Fetched benchmark prices for %d products', count( $all_benchmarks ) ) );
|
||||
$this->logger->info( sprintf( 'Fetched price insights for %d products', count( $all_insights ) ) );
|
||||
|
||||
return $all_benchmarks;
|
||||
return $all_insights;
|
||||
|
||||
} catch ( Exception $e ) {
|
||||
$this->logger->error( 'Error fetching benchmark prices: ' . $e->getMessage() );
|
||||
$this->logger->error( 'Error fetching price insights: ' . $e->getMessage() );
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user