prepare($sql); $stmt->execute([$criterias['version'],$username,$criterias['sn']]); } //check if current hw_version is send and update the equipment record if(isset($criterias['hw_version']) && $criterias['hw_version'] !=''){ // Translate hardware version to standardized format $translated_hw_version = translateDeviceHardwareVersion($criterias['hw_version']); $sql = 'UPDATE equipment SET hw_version = ?, updatedby = ? WHERE serialnumber = ? '; $stmt = $pdo->prepare($sql); $stmt->execute([$translated_hw_version,$username,$criterias['sn']]); } //GET EQUIPMENT AND PRODUCT DATA BASED ON SERIAL NUMBER $sql = "SELECT p.rowID as product_rowid, p.productcode, e.sw_version as current_sw_version, e.hw_version, e.sw_version_license, e.sw_version_upgrade, e.rowID as equipment_rowid, partner.* FROM equipment e JOIN products p ON e.productrowid = p.rowID LEFT JOIN partner ON partner.partnerID = SUBSTRING_INDEX(JSON_UNQUOTE(JSON_EXTRACT(e.accounthierarchy, '$.soldto')), '-', 1) AND partner.is_dealer = 1 AND partner.status = 1 WHERE e.serialnumber = ?"; $stmt = $pdo->prepare($sql); $stmt->execute([$criterias['sn']]); $equipment_data = $stmt->fetch(PDO::FETCH_ASSOC); if (!$equipment_data) { $messages = ["error" => "No equipment found for serialnumber"]; } else { $product_rowid = $equipment_data['product_rowid']; $productcode = $equipment_data['productcode']; $current_sw_version = $equipment_data['current_sw_version']; $hw_version = $equipment_data['hw_version']; $sw_version_license = $equipment_data['sw_version_license']; $sw_version_upgrade = $equipment_data['sw_version_upgrade']; $equipment_rowid = $equipment_data['equipment_rowid']; $dealer_info = [ 'is_dealer' => $equipment_data['is_dealer'] ?? 0, 'name' => $equipment_data['name'] ?? '', 'address' => $equipment_data['address'] ?? '', 'city' => $equipment_data['city'] ?? '', 'postalcode' => $equipment_data['postalcode'] ?? '', 'country' => $equipment_data['country'] ?? '', 'email' => $equipment_data['email'] ?? '', 'phone' => $equipment_data['phone'] ?? '' ]; if (debug) { $debug['equipment_data'] = [ 'product_rowid' => $product_rowid, 'productcode' => $productcode, 'current_sw_version_raw' => $current_sw_version, 'hw_version' => $hw_version, 'sw_version_license' => $sw_version_license, 'sw_version_upgrade' => $sw_version_upgrade ]; } // Normalize software version for comparison (lowercase, trim leading zeros) $current_sw_version = strtolower(ltrim($current_sw_version, '0')); // Translate incoming hw_version parameter for comparison if provided $comparison_hw_version = $hw_version; $hw_version_from_request = null; if(isset($criterias['hw_version']) && $criterias['hw_version'] !=''){ $hw_version_from_request = $criterias['hw_version']; $comparison_hw_version = translateDeviceHardwareVersion($criterias['hw_version']); } if (debug) { $debug['normalized_data'] = [ 'current_sw_version' => $current_sw_version, 'hw_version_from_request' => $hw_version_from_request, 'comparison_hw_version' => $comparison_hw_version, 'hw_version_valid' => ($comparison_hw_version !== '') ]; } // Check if hardware version is invalid (all zeros) if ($hw_version_from_request && $comparison_hw_version === '') { $messages = ["error" => "Invalid hardware version (000000) - device may not be properly initialized"]; if (debug) { $messages['debug'] = $debug; } echo json_encode($messages, JSON_UNESCAPED_UNICODE); exit; } // Check if sw_version_upgrade is set - this overrides normal availability check if (!empty($sw_version_upgrade)) { if (debug) { $debug['sw_version_upgrade_check'] = [ 'sw_version_upgrade_id' => $sw_version_upgrade, 'checking_override' => true ]; } // Check if this version exists and is active $sql = 'SELECT psv.rowID as version_id, psv.version, psv.name, psv.description, psv.mandatory, psv.latest, psv.hw_version, psv.file_path, psv.status FROM products_software_versions psv WHERE psv.rowID = ?'; $stmt = $pdo->prepare($sql); $stmt->execute([$sw_version_upgrade]); $upgrade_version = $stmt->fetch(PDO::FETCH_ASSOC); if ($upgrade_version && $upgrade_version['status'] == 1) { // Valid override found - check if different from current version $normalized_upgrade_version = strtolower(ltrim($upgrade_version['version'], '0')); if (debug) { $debug['sw_version_upgrade_check']['found_version'] = [ 'version' => $upgrade_version['version'], 'name' => $upgrade_version['name'], 'normalized' => $normalized_upgrade_version, 'status' => $upgrade_version['status'], 'is_different_from_current' => ($current_sw_version != $normalized_upgrade_version) ]; } if (!$current_sw_version || $current_sw_version == '' || $normalized_upgrade_version != $current_sw_version) { // Override version is different from current (or no current) - return only this upgrade $output[] = [ "productcode" => $productcode, "name" => $upgrade_version['name'] ?? '', "version" => $upgrade_version['version'], "version_id" => $upgrade_version['version_id'], "description" => $upgrade_version['description'] ?? '', "hw_version" => $upgrade_version['hw_version'] ?? '', "mandatory" => $upgrade_version['mandatory'] ?? '', "latest" => $upgrade_version['latest'] ?? '', "software" => $upgrade_version['file_path'] ?? '', "source" => '', "source_type" => '', "price" => '0.00', "currency" => '', "is_current" => false ]; // Generate download token $download_token = create_download_url_token($criterias['sn'], $upgrade_version['version_id']); $download_url = 'https://'.$_SERVER['SERVER_NAME'].'/api.php/v2/software_download?token='.$download_token; $output[0]['source'] = $download_url; $output[0]['source_type'] = 'token_url'; if (debug) { $debug['sw_version_upgrade_check']['decision'] = 'Override version returned as only upgrade'; $output[0]['_debug'] = $debug; } } else { // Override version is same as current - no upgrades if (debug) { $debug['sw_version_upgrade_check']['decision'] = 'Override version is same as current version - no upgrades'; $output = ['message' => 'No upgrades available', 'debug' => $debug]; } } $messages = $output; echo json_encode($messages, JSON_UNESCAPED_UNICODE); exit; } else { // Override version not found or inactive - fall back to standard check if (debug) { $debug['sw_version_upgrade_check']['found_version'] = $upgrade_version ? 'found but inactive' : 'not found'; $debug['sw_version_upgrade_check']['decision'] = 'Falling back to standard check'; } } } //GET ALL ACTIVE SOFTWARE ASSIGNMENTS for this product with matching HW version $sql = 'SELECT psv.rowID as version_id, psv.version, psv.name, psv.description, psv.mandatory, psv.latest, psv.hw_version, psv.file_path FROM products_software_assignment psa JOIN products_software_versions psv ON psa.software_version_id = psv.rowID WHERE psa.product_id = ? AND psa.status = 1 AND (psv.hw_version = ? OR psv.hw_version IS NULL OR psv.hw_version = "")'; $stmt = $pdo->prepare($sql); $stmt->execute([$product_rowid, $comparison_hw_version]); $versions = $stmt->fetchAll(PDO::FETCH_ASSOC); if (debug) { $debug['active_assignments'] = [ 'count' => count($versions), 'versions' => array_map(function($v) { return [ 'version_id' => $v['version_id'], 'version' => $v['version'], 'name' => $v['name'], 'hw_version' => $v['hw_version'], 'latest' => $v['latest'] ]; }, $versions) ]; } if (empty($versions)) { $messages = ["error" => "No active software assignments found for product"]; if (debug) { $messages['debug'] = $debug; } } else { // First check if current version has paid upgrade paths FROM it $has_paid_upgrade_from_current = false; if ($current_sw_version) { $sql = 'SELECT COUNT(*) as paid_count FROM products_software_upgrade_paths pup JOIN products_software_versions from_ver ON pup.from_version_id = from_ver.rowID WHERE LOWER(TRIM(LEADING "0" FROM from_ver.version)) = ? AND pup.price > 0 AND pup.is_active = 1'; $stmt = $pdo->prepare($sql); $stmt->execute([$current_sw_version]); $paid_check = $stmt->fetch(PDO::FETCH_ASSOC); $has_paid_upgrade_from_current = ($paid_check['paid_count'] > 0); } if (debug) { $debug['has_paid_upgrade_from_current'] = $has_paid_upgrade_from_current; $debug['version_decisions'] = []; } foreach ($versions as $version) { //Normalize version for comparison (lowercase, trim leading zeros) $normalized_version = strtolower(ltrim($version['version'], '0')); $is_current_version = ($current_sw_version && $normalized_version == $current_sw_version); //All versions with matching HW are potential upgrades $show_version = false; $final_price = '0.00'; $final_currency = ''; $is_current = false; $decision_reason = ''; if (debug) { $version_debug = [ 'version' => $version['version'], 'name' => $version['name'], 'normalized_version' => $normalized_version, 'is_current_version' => $is_current_version, 'latest' => $version['latest'] ]; } if (!$current_sw_version || $current_sw_version == '') { //No current version - show all as free upgrades if (!$is_current_version) { $show_version = true; $decision_reason = 'No current version stored - showing as free upgrade'; } else { $decision_reason = 'Skipped - is current version but no upgrades scenario'; } } else { //Check if this is the current version - always show it if ($is_current_version) { $show_version = true; $is_current = true; $final_price = '0.00'; $final_currency = ''; $decision_reason = 'Showing as CURRENT - always show current version'; } else if (!$is_current_version) { //Check if this version is part of ANY upgrade path system (either FROM or TO) $sql = 'SELECT COUNT(*) as path_count FROM products_software_upgrade_paths WHERE (to_version_id = ? OR from_version_id = ?) AND is_active = 1'; $stmt = $pdo->prepare($sql); $stmt->execute([$version['version_id'], $version['version_id']]); $path_check = $stmt->fetch(PDO::FETCH_ASSOC); if (debug) { $version_debug['upgrade_path_count'] = $path_check['path_count']; } if ($path_check['path_count'] == 0) { //Not part of any upgrade path system - show as free upgrade $show_version = true; $decision_reason = 'Showing as FREE - no upgrade paths defined for this version'; } else { //Part of an upgrade path system //Only show if there's an explicit path FROM current version TO this version // OR a wildcard path (from_version_id = 9999999) $sql = 'SELECT pup.price, pup.currency FROM products_software_upgrade_paths pup JOIN products_software_versions from_ver ON pup.from_version_id = from_ver.rowID WHERE pup.to_version_id = ? AND (LOWER(TRIM(LEADING "0" FROM from_ver.version)) = ? OR pup.from_version_id = 9999999) AND pup.is_active = 1'; $stmt = $pdo->prepare($sql); $stmt->execute([$version['version_id'], $current_sw_version]); $upgrade_path = $stmt->fetch(PDO::FETCH_ASSOC); if ($upgrade_path) { //Valid upgrade path found FROM current version or wildcard $show_version = true; $final_price = $upgrade_path['price'] ?? '0.00'; $final_currency = $upgrade_path['currency'] ?? ''; $decision_reason = 'Showing - found upgrade path FROM current (' . $current_sw_version . ') or wildcard with price: ' . $final_price . ' ' . $final_currency; } else { $decision_reason = 'Skipped - has upgrade paths but none FROM current version (' . $current_sw_version . ') or wildcard'; } //If no path from current version or wildcard exists, don't show (show_version stays false) } } } if (debug) { $version_debug['decision'] = [ 'show_version' => $show_version, 'is_current' => $is_current, 'final_price' => $final_price, 'final_currency' => $final_currency, 'reason' => $decision_reason ]; } if ($show_version) { //Check if there's a valid license for this upgrade $license_applied = false; if ($final_price > 0 && $sw_version_license) { //Check if the license is valid $sql = 'SELECT status, starts_at, expires_at FROM products_software_licenses WHERE license_key = ?'; $stmt = $pdo->prepare($sql); $stmt->execute([$sw_version_license]); $license = $stmt->fetch(PDO::FETCH_ASSOC); if ($license && $license['status'] == 1) { $now = date('Y-m-d H:i:s'); $start_at = $license['starts_at']; $expires_at = $license['expires_at']; //Check if license is within valid date range if ((!$start_at || $start_at <= $now) && (!$expires_at || $expires_at >= $now)) { $original_price = $final_price; $final_price = '0.00'; $license_applied = true; if (debug) { $version_debug['license_applied'] = [ 'license_key' => $sw_version_license, 'original_price' => $original_price, 'new_price' => $final_price ]; } } } } $entry = [ "productcode" => $productcode, "name" => $version['name'] ?? '', "version" => $version['version'], "version_id" => $version['version_id'], "description" => $version['description'] ?? '', "hw_version" => $version['hw_version'] ?? '', "mandatory" => $version['mandatory'] ?? '', "latest" => $version['latest'] ?? '', "software" => $version['file_path'] ?? '', "source" => '', "source_type" => '', "price" => $final_price, "currency" => $final_currency, "is_current" => $is_current, "dealer_info" => $dealer_info ]; $output[] = $entry; } if (debug) { $debug['version_decisions'][] = $version_debug; } } //PREVENT DOWNGRADE FROM PAID VERSION TO FREE VERSION (if config enabled) if (defined('PREVENT_PAID_VERSION_DOWNGRADE') && PREVENT_PAID_VERSION_DOWNGRADE && $current_sw_version) { // Check if user is currently on a paid version (check if there was a paid upgrade path TO current version) $sql = 'SELECT COUNT(*) as paid_to_current FROM products_software_upgrade_paths pup JOIN products_software_versions to_ver ON pup.to_version_id = to_ver.rowID WHERE LOWER(TRIM(LEADING "0" FROM to_ver.version)) = ? AND pup.price > 0 AND pup.is_active = 1'; $stmt = $pdo->prepare($sql); $stmt->execute([$current_sw_version]); $paid_check = $stmt->fetch(PDO::FETCH_ASSOC); $is_current_paid_version = ($paid_check['paid_to_current'] > 0); if (debug) { $debug['downgrade_prevention'] = [ 'enabled' => true, 'current_version' => $current_sw_version, 'is_current_paid_version' => $is_current_paid_version ]; } // If current version is paid, remove all free versions from the output (except current) if ($is_current_paid_version) { $output = array_filter($output, function($option) { $price = floatval($option['price']); $is_current = $option['is_current']; // Keep if it's the current version OR if it's a paid version return $is_current || $price > 0; }); // Re-index array after filtering $output = array_values($output); if (debug) { $debug['downgrade_prevention']['filtered_count'] = count($output); $debug['downgrade_prevention']['message'] = 'Removed free versions to prevent downgrade from paid version'; } } } //GENERATE DOWNLOAD TOKENS FOR EACH OPTION foreach ($output as &$option) { // Generate time-based download token $download_token = create_download_url_token($criterias['sn'], $option['version_id']); // Create secure download URL $download_url = 'https://'.$_SERVER['SERVER_NAME'].'/api.php/v2/software_download?token='.$download_token; // Set source as download URL $option['source'] = $download_url; $option['source_type'] = 'token_url'; } if (debug) { $debug['final_output'] = [ 'total_versions_shown' => count($output), 'versions' => array_map(function($o) { return [ 'name' => $o['name'], 'version' => $o['version'], 'price' => $o['price'], 'is_current' => $o['is_current'] ]; }, $output) ]; } // Sort output: is_current = true first, then by price low to high usort($output, function($a, $b) { // First priority: is_current (true comes before false) if ($a['is_current'] !== $b['is_current']) { return $b['is_current'] - $a['is_current']; } // Second priority: price (low to high) return floatval($a['price']) - floatval($b['price']); }); $messages = $output; if (debug && !empty($output)) { // Add debug as separate field in response foreach ($messages as &$msg) { $msg['_debug'] = $debug; break; // Only add to first item } } elseif (debug && empty($output)) { $messages = ['message' => 'No upgrades available', 'debug' => $debug]; } } } } else { $messages = ["error" => "No serialnumber found"]; } //Encrypt results $messages = json_encode($messages, JSON_UNESCAPED_UNICODE); //Send results echo $messages; ?>