merchant_id = $merchant_id; $this->logger = $logger; try { $this->authenticate( $service_account ); } catch ( Exception $e ) { $this->logger->error( 'Google API authentication failed: ' . $e->getMessage() ); throw $e; } } /** * Authenticate with Google API. * * @param string $service_account Service account JSON. * @throws Exception If authentication fails. */ private function authenticate( $service_account ) { // Decode service account JSON. $credentials = json_decode( $service_account, true ); if ( json_last_error() !== JSON_ERROR_NONE ) { throw new Exception( 'Invalid service account JSON: ' . json_last_error_msg() ); } // Initialize Google Client. $this->client = new Google_Client(); $this->client->setApplicationName( 'Informatiq Smart Pricing' ); $this->client->setScopes( array( 'https://www.googleapis.com/auth/content' ) ); $this->client->setAuthConfig( $credentials ); // Initialize Shopping Content service. $this->service = new Google_Service_ShoppingContent( $this->client ); } /** * Get competitive pricing for a product. * * @param string $sku Product SKU. * @param string $gtin Product GTIN (optional). * @return float|null Lowest competitor price or null if not found. */ public function get_competitive_price( $sku, $gtin = '' ) { try { // Search for the product using SKU or GTIN. $product_id = $this->find_product_by_identifier( $sku, $gtin ); if ( ! $product_id ) { $this->logger->warning( "Product not found in Google Merchant Center: SKU={$sku}, GTIN={$gtin}" ); return null; } // Get competitive pricing data. $competitive_price = $this->fetch_competitive_price( $product_id ); return $competitive_price; } catch ( Exception $e ) { $this->logger->error( 'Error fetching competitive price: ' . $e->getMessage() ); return null; } } /** * Find product by SKU or GTIN. * * @param string $sku Product SKU. * @param string $gtin Product GTIN. * @return string|null Product ID or null if not found. */ private function find_product_by_identifier( $sku, $gtin ) { try { // List products from merchant center. $parameters = array(); // Add pagination support. $max_results = 250; $parameters['maxResults'] = $max_results; $products = $this->service->products->listProducts( $this->merchant_id, $parameters ); foreach ( $products->getResources() as $product ) { // Check if SKU or GTIN matches. $product_data = $product->toSimpleObject(); if ( isset( $product_data->offerId ) && $product_data->offerId === $sku ) { return $product->getId(); } if ( ! empty( $gtin ) && isset( $product_data->gtin ) && $product_data->gtin === $gtin ) { return $product->getId(); } } return null; } catch ( Exception $e ) { $this->logger->error( 'Error finding product: ' . $e->getMessage() ); return null; } } /** * Fetch competitive price for a product. * * @param string $product_id Product ID. * @return float|null Lowest competitor price or null if not available. */ private function fetch_competitive_price( $product_id ) { try { // Get product status which includes competitive pricing data. $product_status = $this->service->productstatuses->get( $this->merchant_id, $product_id ); // Extract competitive pricing data. $price_insights = $product_status->getItemLevelIssues(); // Try to get the product to access price competitiveness. $product = $this->service->products->get( $this->merchant_id, $product_id ); // Check if we have access to competitive visibility data via Reports API. // Note: This requires the Merchant Center account to have competitor data enabled. $lowest_price = $this->get_lowest_price_from_competitivevisibility( $product_id ); if ( $lowest_price ) { return $lowest_price; } // Fallback: If competitive visibility is not available, we'll need to use // the product's own price as reference (this happens when no competitor data exists). $product_data = $product->toSimpleObject(); if ( isset( $product_data->price->value ) ) { $this->logger->warning( "No competitive data available for product {$product_id}, using own price as reference" ); return (float) $product_data->price->value; } return null; } catch ( Exception $e ) { $this->logger->error( 'Error fetching competitive price: ' . $e->getMessage() ); return null; } } /** * Get lowest price from competitive visibility data. * * @param string $product_id Product ID. * @return float|null Lowest competitor price or null. */ private function get_lowest_price_from_competitivevisibility( $product_id ) { try { // Use the Reports API to get competitive pricing data. // This requires the account to have access to competitive pricing insights. $service = new Google_Service_ShoppingContent_Reports( $this->client ); // Note: The actual implementation depends on the specific API endpoints available. // For this implementation, we'll use a simplified approach. // The competitive visibility API may not be directly accessible via standard API. // In production, you might need to: // 1. Enable Merchant Center competitive visibility // 2. Use the Shopping Ads API // 3. Or scrape data from Google Merchant Center dashboard (not recommended) // For now, return null to indicate no competitive data found. // The calling code will handle this gracefully. return null; } catch ( Exception $e ) { $this->logger->error( 'Error accessing competitive visibility data: ' . $e->getMessage() ); return null; } } /** * Test API connection. * * @return bool True if connection successful. */ public function test_connection() { try { // Try to list products to test connection. $parameters = array( 'maxResults' => 1 ); $this->service->products->listProducts( $this->merchant_id, $parameters ); $this->logger->info( 'Google API connection test successful' ); return true; } catch ( Exception $e ) { $this->logger->error( 'Google API connection test failed: ' . $e->getMessage() ); return false; } } /** * Get all products from Merchant Center. * * @return array Array of products. */ public function get_all_products() { try { $all_products = array(); $page_token = null; do { $parameters = array( 'maxResults' => 250, ); if ( $page_token ) { $parameters['pageToken'] = $page_token; } $response = $this->service->products->listProducts( $this->merchant_id, $parameters ); $products = $response->getResources(); if ( $products ) { $all_products = array_merge( $all_products, $products ); } $page_token = $response->getNextPageToken(); } while ( $page_token ); return $all_products; } catch ( Exception $e ) { $this->logger->error( 'Error fetching products: ' . $e->getMessage() ); return array(); } } }