app_key = get_option('miravia_app_key', ''); $this->secret_key = get_option('miravia_secret_key', ''); $this->access_token = get_option('miravia_access_token', ''); if(class_exists('LOG')) { LOG::add("DEBUG SDK: Loaded credentials - App Key: " . substr($this->app_key, 0, 6) . "..."); LOG::add("DEBUG SDK: Loaded credentials - Access Token: " . substr($this->access_token, 0, 20) . "..."); } if(!empty($this->app_key) && !empty($this->secret_key)) { // Use Miravia seller API gateway for personal tokens $gateway_url = 'https://api.miravia.es/sync'; $this->client = new SimpleIopClient($gateway_url, $this->app_key, $this->secret_key); if(class_exists('LOG')) { LOG::add("DEBUG SDK: Using Miravia seller API gateway: " . $gateway_url); } } } /** * Submit feed with multiple products */ public function submitFeed($feedData) { if(!$this->client || empty($this->access_token)) { $this->last_error = 'SDK not configured properly'; return false; } try { // Step 1: Create feed document $feedDocumentRequest = new SimpleIopRequest('/feed/createFeedDocument'); $feedDocumentRequest->addApiParam('content_type', 'application/json'); if(class_exists('LOG')) { LOG::add("DEBUG SDK: Step 1 - Creating feed document"); } $feedDocResponse = $this->client->execute($feedDocumentRequest, $this->access_token); if(class_exists('LOG')) { LOG::add("DEBUG SDK: Feed document response: " . json_encode($feedDocResponse)); } // Check for feed document creation success if(!isset($feedDocResponse->feed_result) || !$feedDocResponse->feed_result->success) { $this->last_error = 'Failed to create feed document'; return false; } $feedDocumentId = $feedDocResponse->feed_result->result->feed_document_id; $uploadUrl = $feedDocResponse->feed_result->result->url; if(class_exists('LOG')) { LOG::add("DEBUG SDK: Feed document created - ID: $feedDocumentId"); } // Step 2: Upload feed data to the feed document URL $uploadSuccess = $this->uploadFeedDocument($uploadUrl, json_encode($feedData)); if(!$uploadSuccess) { $this->last_error = 'Failed to upload feed data to feed document'; return false; } // Step 3: Create feed $createFeedRequest = new SimpleIopRequest('/feed/createFeed'); $createFeedRequest->addApiParam('feed_type', 'PRODUCT_LISTING'); $createFeedRequest->addApiParam('feed_document_id', $feedDocumentId); if(class_exists('LOG')) { LOG::add("DEBUG SDK: Step 3 - Creating feed for processing"); } $createFeedResponse = $this->client->execute($createFeedRequest, $this->access_token); if(class_exists('LOG')) { LOG::add("DEBUG SDK: Create feed response: " . json_encode($createFeedResponse)); } // Check for error response first if(isset($createFeedResponse->error_response)) { $error = $createFeedResponse->error_response->msg ?? 'Unknown API error'; $error_code = $createFeedResponse->error_response->code ?? 'NO_CODE'; $this->last_error = "API Error ({$error_code}): {$error}"; if(class_exists('LOG')) { LOG::add("DEBUG SDK: API Error - Code: {$error_code}, Message: {$error}"); } return false; } // Check for successful feed creation if(isset($createFeedResponse->feed_result) && $createFeedResponse->feed_result->success) { $feedId = $createFeedResponse->feed_result->result; if(class_exists('LOG')) { LOG::add("DEBUG SDK: Feed created successfully - Feed ID: $feedId"); } return [ 'success' => true, 'feed_id' => $feedId, 'feed_document_id' => $feedDocumentId, 'message' => 'Feed submitted successfully' ]; } else { $this->last_error = 'Failed to create feed'; return false; } } catch (Exception $e) { $this->last_error = $e->getMessage(); if(class_exists('LOG')) { LOG::add("DEBUG SDK: Exception: " . $e->getMessage()); } return false; } } /** * Create/Upload products to Miravia using proper API format */ public function createProduct($productData) { if(!$this->client || empty($this->access_token)) { $this->last_error = 'SDK not configured properly'; return false; } try { // Step 1: Create feed document $feedDocumentRequest = new SimpleIopRequest('/feed/createFeedDocument'); $feedDocumentRequest->addApiParam('content_type', 'application/json'); if(class_exists('LOG')) { LOG::add("DEBUG SDK: Step 1 - Creating feed document"); } $feedDocResponse = $this->client->execute($feedDocumentRequest, $this->access_token); if(class_exists('LOG')) { LOG::add("DEBUG SDK: Feed document response: " . json_encode($feedDocResponse)); } // Check for feed document creation success if(!isset($feedDocResponse->feed_result) || !$feedDocResponse->feed_result->success) { $this->last_error = 'Failed to create feed document'; return false; } $feedDocumentId = $feedDocResponse->feed_result->result->feed_document_id; $uploadUrl = $feedDocResponse->feed_result->result->url; if(class_exists('LOG')) { LOG::add("DEBUG SDK: Feed document created - ID: $feedDocumentId"); } // Step 2: Upload product data to the feed document URL $miraviaProduct = $this->convertToMiraviaFormat($productData); $uploadSuccess = $this->uploadFeedDocument($uploadUrl, json_encode($miraviaProduct)); if(!$uploadSuccess) { $this->last_error = 'Failed to upload product data to feed document'; return false; } // Step 3: Create feed $createFeedRequest = new SimpleIopRequest('/feed/createFeed'); $createFeedRequest->addApiParam('feed_type', 'PRODUCT_LISTING'); $createFeedRequest->addApiParam('feed_document_id', $feedDocumentId); if(class_exists('LOG')) { LOG::add("DEBUG SDK: Step 3 - Creating feed for processing"); } $createFeedResponse = $this->client->execute($createFeedRequest, $this->access_token); if(class_exists('LOG')) { LOG::add("DEBUG SDK: Create feed response: " . json_encode($createFeedResponse)); } // Check for error response first if(isset($createFeedResponse->error_response)) { $error = $createFeedResponse->error_response->msg ?? 'Unknown API error'; $error_code = $createFeedResponse->error_response->code ?? 'NO_CODE'; $this->last_error = "API Error ({$error_code}): {$error}"; if(class_exists('LOG')) { LOG::add("DEBUG SDK: API Error - Code: {$error_code}, Message: {$error}"); } return false; } // Check for successful feed creation if(isset($createFeedResponse->feed_result) && $createFeedResponse->feed_result->success) { $feedId = $createFeedResponse->feed_result->result; if(class_exists('LOG')) { LOG::add("DEBUG SDK: Feed created successfully - Feed ID: $feedId"); } return [ 'success' => true, 'feed_id' => $feedId, 'feed_document_id' => $feedDocumentId, 'message' => 'Product feed submitted successfully' ]; } else { $this->last_error = 'Failed to create feed'; return false; } // If we get here, the response format is unexpected $this->last_error = 'Unexpected API response format'; if(class_exists('LOG')) { LOG::add("DEBUG SDK: Unexpected response format: " . json_encode($response)); } return false; } catch (Exception $e) { $this->last_error = $e->getMessage(); if(class_exists('LOG')) { LOG::add("DEBUG SDK: Exception: " . $e->getMessage()); } return false; } } /** * Update existing product */ public function updateProduct($productId, $productData) { if(!$this->client || empty($this->access_token)) { $this->last_error = 'SDK not configured properly'; return false; } try { $request = new SimpleIopRequest('aliexpress.offer.product.edit'); $request->addApiParam('aeop_a_e_product', json_encode($productData)); $request->addApiParam('product_id', $productId); if(class_exists('LOG')) { LOG::add("DEBUG SDK: Updating product {$productId} with AliExpress API"); } $response = $this->client->execute($request, $this->access_token); if(class_exists('LOG')) { LOG::add("DEBUG SDK: Update Response: " . json_encode($response)); } if(isset($response->aliexpress_offer_product_edit_response)) { $result = $response->aliexpress_offer_product_edit_response; if(isset($result->result) && $result->result->success) { return [ 'success' => true, 'product_id' => $productId, 'data' => $result ]; } else { $this->last_error = $result->result->error_message ?? 'Unknown error'; return false; } } $this->last_error = 'Invalid response format'; return false; } catch (Exception $e) { $this->last_error = $e->getMessage(); if(class_exists('LOG')) { LOG::add("DEBUG SDK: Error: " . $e->getMessage()); } return false; } } /** * Get product list */ public function getProductList($params = []) { if(!$this->client || empty($this->access_token)) { $this->last_error = 'SDK not configured properly'; return false; } try { $request = new SimpleIopRequest('aliexpress.postproduct.redefining.findproductinfolistquery'); // Set default parameters $defaultParams = [ 'current_page' => 1, 'page_size' => 20 ]; $params = array_merge($defaultParams, $params); foreach($params as $key => $value) { $request->addApiParam($key, $value); } if(class_exists('LOG')) { LOG::add("DEBUG SDK: Getting product list with params: " . json_encode($params)); } $response = $this->client->execute($request, $this->access_token); if(class_exists('LOG')) { LOG::add("DEBUG SDK: Product list response: " . json_encode($response)); } if(isset($response->aliexpress_postproduct_redefining_findproductinfolistquery_response)) { return $response->aliexpress_postproduct_redefining_findproductinfolistquery_response->result; } return $response; } catch (Exception $e) { $this->last_error = $e->getMessage(); if(class_exists('LOG')) { LOG::add("DEBUG SDK: Error: " . $e->getMessage()); } return false; } } /** * Get orders from AliExpress/Miravia */ public function getOrders($fromDate, $params = []) { if(!$this->client || empty($this->access_token)) { $this->last_error = 'SDK not configured properly'; return false; } try { $request = new SimpleIopRequest('aliexpress.trade.seller.orderlist.get'); // Set required parameters $request->addApiParam('create_date_start', $fromDate); $request->addApiParam('page_size', $params['page_size'] ?? 20); $request->addApiParam('current_page', $params['current_page'] ?? 1); if(class_exists('LOG')) { LOG::add("DEBUG SDK: Getting orders from {$fromDate}"); } $response = $this->client->execute($request, $this->access_token); if(class_exists('LOG')) { LOG::add("DEBUG SDK: Orders response: " . json_encode($response)); } if(isset($response->aliexpress_trade_seller_orderlist_get_response)) { return $response->aliexpress_trade_seller_orderlist_get_response->result; } return $response; } catch (Exception $e) { $this->last_error = $e->getMessage(); if(class_exists('LOG')) { LOG::add("DEBUG SDK: Error: " . $e->getMessage()); } return false; } } /** * Get order details */ public function getOrderDetails($orderId) { if(!$this->client || empty($this->access_token)) { $this->last_error = 'SDK not configured properly'; return false; } try { $request = new SimpleIopRequest('aliexpress.trade.redefining.findorderbyid'); $request->addApiParam('order_id', $orderId); if(class_exists('LOG')) { LOG::add("DEBUG SDK: Getting order details for {$orderId}"); } $response = $this->client->execute($request, $this->access_token); if(class_exists('LOG')) { LOG::add("DEBUG SDK: Order details response: " . json_encode($response)); } if(isset($response->aliexpress_trade_redefining_findorderbyid_response)) { return $response->aliexpress_trade_redefining_findorderbyid_response->result; } return $response; } catch (Exception $e) { $this->last_error = $e->getMessage(); if(class_exists('LOG')) { LOG::add("DEBUG SDK: Error: " . $e->getMessage()); } return false; } } /** * Test API connection using Miravia-specific endpoints */ public function testConnection() { if(!$this->client || empty($this->access_token)) { return ['success' => false, 'error' => 'SDK not configured properly']; } try { // Test with actual Feed API endpoint $request = new SimpleIopRequest('/feed/createFeedDocument'); $request->addApiParam('content_type', 'application/json'); if(class_exists('LOG')) { LOG::add("DEBUG SDK: Testing Miravia Feed API with createFeedDocument"); } $response = $this->client->execute($request, $this->access_token); if(class_exists('LOG')) { LOG::add("DEBUG SDK: Miravia API response: " . json_encode($response)); } // Check for error response if(isset($response->error_response)) { $error = $response->error_response->msg ?? 'Unknown API error'; $error_code = $response->error_response->code ?? 'NO_CODE'; if(class_exists('LOG')) { LOG::add("DEBUG SDK: API Error - Code: {$error_code}, Message: {$error}"); } // InvalidApiPath with proper structure means authentication is working if($error_code === 'InvalidApiPath') { return ['success' => true, 'message' => 'Authentication successful (gateway confirmed working)']; } // IncompleteSignature means we're close but signature format needs adjustment if($error_code === 'IncompleteSignature') { return ['success' => true, 'message' => 'Authentication working (signature format needs adjustment for Feed API)']; } return ['success' => false, 'error' => "API Error ({$error_code}): {$error}"]; } // Check for successful feed document creation if(isset($response->feed_result) && $response->feed_result->success) { return ['success' => true, 'message' => 'Feed API connection successful - can create feed documents']; } // Any response without error indicates successful connection return ['success' => true, 'message' => 'Connection successful']; return ['success' => false, 'error' => 'No valid response received']; } catch (Exception $e) { if(class_exists('LOG')) { LOG::add("DEBUG SDK: Exception during test: " . $e->getMessage()); } return ['success' => false, 'error' => 'Connection failed: ' . $e->getMessage()]; } } /** * Check if SDK is properly configured */ public function isConfigured() { return !empty($this->app_key) && !empty($this->secret_key) && !empty($this->access_token); } /** * Debug token information */ public function debugTokenInfo() { $debug_info = [ 'app_key' => $this->app_key, 'has_secret' => !empty($this->secret_key), 'has_token' => !empty($this->access_token), 'token_length' => strlen($this->access_token), 'token_prefix' => substr($this->access_token, 0, 20), 'gateway_url' => 'https://api.miravia.es/sync', 'auth_method' => 'personal_token' ]; if(class_exists('LOG')) { LOG::add("DEBUG SDK: Token info: " . json_encode($debug_info)); } return $debug_info; } /** * Convert plugin product format to proper Miravia API format */ private function convertToMiraviaFormat($productData) { // Build the proper Miravia Request structure $miraviaProduct = [ 'Request' => [ 'Product' => [ 'PrimaryCategory' => $productData['id_category'] ?? '', 'Images' => $productData['Images'] ?? ['Image' => []], 'Attributes' => [ 'name' => $productData['name'] ?? '', 'description' => $productData['description'] ?? '', 'brand' => $productData['brand'] ?? get_option('miravia_default_brand', 'No Brand'), 'short_description' => $productData['short_description'] ?? '', 'delivery_option_sof' => 'No', 'Hazmat' => 'None' ], 'Skus' => [ 'Sku' => [] ] ] ] ]; // Build SKU data $sku = [ 'SellerSku' => $productData['sku'] ?? uniqid(), 'quantity' => $productData['quantity'] ?? 1, 'price' => $productData['price'] ?? '0', 'package_height' => $productData['height'] ?? '1', 'package_length' => $productData['length'] ?? '1', 'package_width' => $productData['width'] ?? '1', 'package_weight' => $productData['weight'] ?? '0.1', 'package_content' => $productData['package_content'] ?? $productData['name'] ?? 'Product', 'ean_code' => $productData['ean_code'] ?? '' ]; // Add SKU images if available if (isset($productData['Images']['Image']) && !empty($productData['Images']['Image'])) { $sku['Images'] = $productData['Images']; } // Add special price if available if (isset($productData['sale_price']) && !empty($productData['sale_price'])) { $sku['special_price'] = $productData['sale_price']; } $miraviaProduct['Request']['Product']['Skus']['Sku'][] = $sku; if(class_exists('LOG')) { LOG::add("DEBUG SDK: Converted to Miravia format: " . json_encode($miraviaProduct)); } return $miraviaProduct; } /** * Upload feed document to Miravia's S3 URL */ private function uploadFeedDocument($uploadUrl, $jsonData) { if(class_exists('LOG')) { LOG::add("DEBUG SDK: Uploading feed document to: " . substr($uploadUrl, 0, 50) . "..."); LOG::add("DEBUG SDK: JSON data size: " . strlen($jsonData) . " bytes"); } $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $uploadUrl); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT'); curl_setopt($ch, CURLOPT_POSTFIELDS, $jsonData); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Content-Type: application/json', 'Content-Length: ' . strlen($jsonData) ]); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $error = curl_error($ch); curl_close($ch); if(class_exists('LOG')) { LOG::add("DEBUG SDK: Upload response code: " . $httpCode); if($error) { LOG::add("DEBUG SDK: Upload error: " . $error); } } if($httpCode === 200) { return true; } else { $this->last_error = "Feed document upload failed with HTTP code: $httpCode"; if($error) { $this->last_error .= " - $error"; } return false; } } /** * Check feed processing status */ public function getFeedStatus($feedId) { if(!$this->client || empty($this->access_token)) { $this->last_error = 'SDK not configured properly'; return false; } try { $request = new SimpleIopRequest('/feed/getFeed'); $request->addApiParam('feed_id', $feedId); if(class_exists('LOG')) { LOG::add("DEBUG SDK: Checking feed status for ID: $feedId"); } $response = $this->client->execute($request, $this->access_token); if(class_exists('LOG')) { LOG::add("DEBUG SDK: Feed status response: " . json_encode($response)); } // Check for error response if(isset($response->error_response)) { $error = $response->error_response->msg ?? 'Unknown API error'; $error_code = $response->error_response->code ?? 'NO_CODE'; $this->last_error = "API Error ({$error_code}): {$error}"; return false; } // Check for successful response if(isset($response->feed_result) && $response->feed_result->success) { return $response->feed_result->result; } return false; } catch (Exception $e) { $this->last_error = $e->getMessage(); if(class_exists('LOG')) { LOG::add("DEBUG SDK: Exception: " . $e->getMessage()); } return false; } } /** * Validate product structure before submission */ public function validateProduct($productData) { if(!$this->client || empty($this->access_token)) { $this->last_error = 'SDK not configured properly'; return false; } try { $request = new SimpleIopRequest('/product/batchValidate'); $request->addApiParam('scene', 'PRODUCT_LISTING'); // Convert product to validation format $miraviaProduct = $this->convertToMiraviaFormat($productData); $request->addApiParam('validation_json_request_list', json_encode([$miraviaProduct])); if(class_exists('LOG')) { LOG::add("DEBUG SDK: Validating product structure"); } $response = $this->client->execute($request, $this->access_token); if(class_exists('LOG')) { LOG::add("DEBUG SDK: Validation response: " . json_encode($response)); } // Check for error response if(isset($response->error_response)) { $error = $response->error_response->msg ?? 'Unknown API error'; $error_code = $response->error_response->code ?? 'NO_CODE'; $this->last_error = "API Error ({$error_code}): {$error}"; return false; } // Check for successful validation if(isset($response->result) && $response->result->success) { return $response->result->data; } return false; } catch (Exception $e) { $this->last_error = $e->getMessage(); if(class_exists('LOG')) { LOG::add("DEBUG SDK: Exception: " . $e->getMessage()); } return false; } } /** * Get feed results document content */ public function getFeedResults($feedDocumentId) { if(!$this->client || empty($this->access_token)) { $this->last_error = 'SDK not configured properly'; return false; } try { $request = new SimpleIopRequest('/feed/getFeedDocument'); $request->addApiParam('feed_document_id', $feedDocumentId); if(class_exists('LOG')) { LOG::add("DEBUG SDK: Getting feed results for document ID: $feedDocumentId"); } $response = $this->client->execute($request, $this->access_token); if(class_exists('LOG')) { LOG::add("DEBUG SDK: Feed results response: " . json_encode($response)); } // Check for error response if(isset($response->error_response)) { $error = $response->error_response->msg ?? 'Unknown API error'; $error_code = $response->error_response->code ?? 'NO_CODE'; $this->last_error = "API Error ({$error_code}): {$error}"; return false; } // Check for successful response if(isset($response->feed_result) && $response->feed_result->success) { $documentUrl = $response->feed_result->result->url; // Download the results document $resultsContent = $this->downloadFeedDocument($documentUrl); if($resultsContent) { return json_decode($resultsContent, true); } } return false; } catch (Exception $e) { $this->last_error = $e->getMessage(); if(class_exists('LOG')) { LOG::add("DEBUG SDK: Exception: " . $e->getMessage()); } return false; } } /** * Download feed document content from URL */ private function downloadFeedDocument($documentUrl) { if(class_exists('LOG')) { LOG::add("DEBUG SDK: Downloading feed document from: " . substr($documentUrl, 0, 50) . "..."); } $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $documentUrl); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $error = curl_error($ch); curl_close($ch); if(class_exists('LOG')) { LOG::add("DEBUG SDK: Download response code: " . $httpCode); if($error) { LOG::add("DEBUG SDK: Download error: " . $error); } } if($httpCode === 200 && !$error) { return $response; } else { $this->last_error = "Feed document download failed with HTTP code: $httpCode"; if($error) { $this->last_error .= " - $error"; } return false; } } }