'Missing required fields: serial_number, version_id'], JSON_UNESCAPED_UNICODE); exit; } $serial_number = $post_content['serial_number']; $version_id = $post_content['version_id']; $user_data = $post_content['user_data'] ?? []; //+++++++++++++++++++++++++++++++++++++++++++++++++++++ // STEP 1: Get equipment data from serial_number //+++++++++++++++++++++++++++++++++++++++++++++++++++++ $sql = 'SELECT rowID, sw_version, sw_version_license, hw_version FROM equipment WHERE serialnumber = ?'; $stmt = $pdo->prepare($sql); $stmt->execute([$serial_number]); $equipment = $stmt->fetch(PDO::FETCH_ASSOC); if (!$equipment) { http_response_code(404); echo json_encode(['error' => 'Device not found with serial number: ' . $serial_number], JSON_UNESCAPED_UNICODE); exit; } $equipment_id = $equipment['rowID']; $current_sw_version = trim(strtolower(ltrim($equipment['sw_version'], '0'))); $sw_version_license = $equipment['sw_version_license'] ?? null; $hw_version = $equipment['hw_version'] ?? ''; //+++++++++++++++++++++++++++++++++++++++++++++++++++++ // STEP 2: Get version data from version_id //+++++++++++++++++++++++++++++++++++++++++++++++++++++ $sql = 'SELECT v.rowID as version_id, v.version, v.name, v.description, v.hw_version, p.productcode FROM products_software_versions v JOIN products_software p ON v.product_software_id = p.rowID WHERE v.rowID = ? AND v.is_active = 1'; $stmt = $pdo->prepare($sql); $stmt->execute([$version_id]); $version = $stmt->fetch(PDO::FETCH_ASSOC); if (!$version) { http_response_code(404); echo json_encode(['error' => 'Software version not found or inactive'], JSON_UNESCAPED_UNICODE); exit; } //+++++++++++++++++++++++++++++++++++++++++++++++++++++ // STEP 3: Calculate price SERVER-SIDE (same logic as software_update.php) //+++++++++++++++++++++++++++++++++++++++++++++++++++++ $final_price = '0.00'; $final_currency = ''; // Check if version has upgrade paths defined $sql = 'SELECT COUNT(*) as path_count FROM products_software_upgrade_paths WHERE to_version_id = ? AND is_active = 1'; $stmt = $pdo->prepare($sql); $stmt->execute([$version_id]); $path_count_result = $stmt->fetch(PDO::FETCH_ASSOC); $has_upgrade_paths = ($path_count_result['path_count'] > 0); if (!$has_upgrade_paths) { // No upgrade paths defined = FREE (lines 240-242 in software_update.php) $final_price = '0.00'; } else { // Check for valid upgrade path FROM current version $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)) = ? AND pup.is_active = 1'; $stmt = $pdo->prepare($sql); $stmt->execute([$version_id, $current_sw_version]); $upgrade_path = $stmt->fetch(PDO::FETCH_ASSOC); if ($upgrade_path) { $final_price = $upgrade_path['price'] ?? '0.00'; $final_currency = $upgrade_path['currency'] ?? 'EUR'; } else { // No upgrade path FROM current version http_response_code(400); echo json_encode(['error' => 'No valid upgrade path from current version'], JSON_UNESCAPED_UNICODE); exit; } } //+++++++++++++++++++++++++++++++++++++++++++++++++++++ // STEP 4: Check license validity (lines 280-311 in software_update.php) //+++++++++++++++++++++++++++++++++++++++++++++++++++++ if ($final_price > 0 && $sw_version_license) { $sql = 'SELECT status, start_at, expires_at FROM products_software_licenses WHERE license_key = ? AND equipment_id = ?'; $stmt = $pdo->prepare($sql); $stmt->execute([$sw_version_license, $equipment_id]); $license = $stmt->fetch(PDO::FETCH_ASSOC); if ($license && $license['status'] == 1) { $now = date('Y-m-d H:i:s'); $start_at = $license['start_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)) { $final_price = '0.00'; } } } //+++++++++++++++++++++++++++++++++++++++++++++++++++++ // STEP 5: Verify price > 0 (free upgrades shouldn't reach payment API) //+++++++++++++++++++++++++++++++++++++++++++++++++++++ if ($final_price <= 0) { http_response_code(400); echo json_encode(['error' => 'This upgrade is free. No payment required.'], JSON_UNESCAPED_UNICODE); exit; } //+++++++++++++++++++++++++++++++++++++++++++++++++++++ // STEP 6: DEBUG MODE - Simulate payment without Mollie //+++++++++++++++++++++++++++++++++++++++++++++++++++++ if (debug) { // Generate fake payment ID $fake_payment_id = 'DEBUG_' . uniqid() . '_' . time(); $checkout_url = 'https://'.$_SERVER['SERVER_NAME'].'/softwaretool.php?payment_return=1&payment_id=' . $fake_payment_id; // Store transaction in DB $sql = 'INSERT INTO transactions (txn_id, payment_amount, payment_status, payer_email, first_name, last_name, address_street, address_city, address_state, address_zip, address_country, account_id, payment_method, created) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'; $stmt = $pdo->prepare($sql); $stmt->execute([ $fake_payment_id, $final_price, 0, // 0 = pending $user_data['email'] ?? '', $user_data['first_name'] ?? '', $user_data['last_name'] ?? '', $user_data['address_street'] ?? '', $user_data['address_city'] ?? '', $user_data['address_state'] ?? '', $user_data['address_zip'] ?? '', $user_data['address_country'] ?? '', $serial_number, 0, // payment method date('Y-m-d H:i:s') ]); // Store transaction item with serial_number in item_options $item_options = json_encode([ 'serial_number' => $serial_number, 'equipment_id' => $equipment_id, 'hw_version' => $hw_version ], JSON_UNESCAPED_UNICODE); $sql = 'INSERT INTO transactions_items (txn_id, item_id, item_price, item_quantity, item_options, created) VALUES (?, ?, ?, ?, ?, ?)'; $stmt = $pdo->prepare($sql); $stmt->execute([ $fake_payment_id, $version_id, $final_price, 1, $item_options, date('Y-m-d H:i:s') ]); // Return fake checkout URL $messages = json_encode([ 'checkout_url' => $checkout_url, 'payment_id' => $fake_payment_id, 'debug_mode' => true ], JSON_UNESCAPED_UNICODE); echo $messages; exit; } //+++++++++++++++++++++++++++++++++++++++++++++++++++++ // STEP 7: Call Mollie API to create payment //+++++++++++++++++++++++++++++++++++++++++++++++++++++ try { // Initialize Mollie require dirname(__FILE__, 3).'/initialize.php'; // Format price for Mollie (must be string with 2 decimals) $formatted_price = number_format((float)$final_price, 2, '.', ''); // Create payment with Mollie $payment = $mollie->payments->create([ 'amount' => [ 'currency' => $final_currency ?: 'EUR', 'value' => $formatted_price ], 'description' => 'Software upgrade to ' . $version['name'] . ' (v' . $version['version'] . ')', 'redirectUrl' => 'https://'.$_SERVER['SERVER_NAME'].'/softwaretool.php?payment_return=1&payment_id={id}', 'webhookUrl' => 'https://'.$_SERVER['SERVER_NAME'].'/webhook_mollie.php', 'metadata' => [ 'order_id' => $payment->id // Store payment ID in metadata ] ]); $mollie_payment_id = $payment->id; $checkout_url = $payment->getCheckoutUrl(); //+++++++++++++++++++++++++++++++++++++++++++++++++++++ // STEP 8: Store transaction in DB //+++++++++++++++++++++++++++++++++++++++++++++++++++++ $sql = 'INSERT INTO transactions (txn_id, payment_amount, payment_status, payer_email, first_name, last_name, address_street, address_city, address_state, address_zip, address_country, account_id, payment_method, created) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'; $stmt = $pdo->prepare($sql); $stmt->execute([ $mollie_payment_id, $final_price, 0, // 0 = pending $user_data['email'] ?? '', $user_data['first_name'] ?? '', $user_data['last_name'] ?? '', $user_data['address_street'] ?? '', $user_data['address_city'] ?? '', $user_data['address_state'] ?? '', $user_data['address_zip'] ?? '', $user_data['address_country'] ?? '', $serial_number, 0, // payment method date('Y-m-d H:i:s') ]); //+++++++++++++++++++++++++++++++++++++++++++++++++++++ // STEP 9: Store transaction item with serial_number in item_options //+++++++++++++++++++++++++++++++++++++++++++++++++++++ $item_options = json_encode([ 'serial_number' => $serial_number, 'equipment_id' => $equipment_id, 'hw_version' => $hw_version ], JSON_UNESCAPED_UNICODE); $sql = 'INSERT INTO transactions_items (txn_id, item_id, item_price, item_quantity, item_options, created) VALUES (?, ?, ?, ?, ?, ?)'; $stmt = $pdo->prepare($sql); $stmt->execute([ $mollie_payment_id, $version_id, $final_price, 1, $item_options, date('Y-m-d H:i:s') ]); //+++++++++++++++++++++++++++++++++++++++++++++++++++++ // STEP 10: Return checkout URL and payment ID //+++++++++++++++++++++++++++++++++++++++++++++++++++++ $messages = json_encode([ 'checkout_url' => $checkout_url, 'payment_id' => $mollie_payment_id ], JSON_UNESCAPED_UNICODE); echo $messages; } catch (Exception $e) { http_response_code(500); echo json_encode(['error' => 'Payment creation failed: ' . $e->getMessage()], JSON_UNESCAPED_UNICODE); exit; } ?>