0) { ob_end_clean(); } header('Content-Type: application/json'); echo json_encode($data); exit(); // Terminate immediately } // Set a global exception handler to catch any uncaught errors set_exception_handler(function($exception) { error_log($exception->getMessage()); send_json_response(['success' => false, 'message' => 'A server error occurred: ' . $exception->getMessage()]); }); $response_data = [ 'success' => false, 'message' => 'An unknown error occurred.', // Initialize all fields JS expects to avoid 'undefined' issues 'wip' => 0, 'openingBalance' => 0, 'billings' => 0, 'expenses' => 0, 'cost' => 0, 'nsr' => 0, 'margin' => 0, ]; ob_clean(); // Clear any pre-existing output try { $data = $_POST; $projectId = $data['projectId'] ?? null; $month = $data['month'] ?? null; if (!$projectId || !$month) { send_json_response(['success' => false, 'message' => 'Missing project ID or month.']); } $pdo = db(); $metrics_from_form = [ 'wip' => $data['wip'] ?? 0, 'opening_balance' => $data['openingBalance'] ?? 0, 'billing' => $data['billings'] ?? 0, 'expenses' => $data['expenses'] ?? 0, 'cost' => $data['cost'] ?? 0, ]; $pdo->beginTransaction(); // Check if records exist, if not, INSERT them. Otherwise, UPDATE. $select_sql = "SELECT COUNT(*) FROM projectFinanceMonthly WHERE projectId = :projectId AND month = :month AND metricName = :metricName"; $select_stmt = $pdo->prepare($select_sql); $update_sql = "UPDATE projectFinanceMonthly SET value = :value, is_overridden = 1 WHERE projectId = :projectId AND month = :month AND metricName = :metricName"; $update_stmt = $pdo->prepare($update_sql); $insert_sql = "INSERT INTO projectFinanceMonthly (projectId, month, metricName, value, is_overridden) VALUES (:projectId, :month, :metricName, :value, 1)"; $insert_stmt = $pdo->prepare($insert_sql); foreach ($metrics_from_form as $metricName => $value) { $select_stmt->execute([ 'projectId' => $projectId, 'month' => $month, 'metricName' => $metricName ]); $exists = $select_stmt->fetchColumn() > 0; if ($exists) { $update_stmt->execute([ 'value' => $value, 'projectId' => $projectId, 'month' => $month, 'metricName' => $metricName, ]); } else { $insert_stmt->execute([ 'projectId' => $projectId, 'month' => $month, 'metricName' => $metricName, 'value' => $value, ]); } } $pdo->commit(); // Recalculate NSR and Margin $billing = floatval($metrics_from_form['billing']); $expenses = floatval($metrics_from_form['expenses']); $cost = floatval($metrics_from_form['cost']); $wip = floatval($metrics_from_form['wip']); $opening_balance = floatval($metrics_from_form['opening_balance']); $nsr = $wip + $billing - $opening_balance - $expenses; $margin = ($nsr > 0) ? (($nsr - $cost) / $nsr) : 0; // Fetch the updated data to send back $stmt = $pdo->prepare("SELECT metricName, value FROM projectFinanceMonthly WHERE projectId = ? AND month = ?"); $stmt->execute([$projectId, $month]); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); $response_data['success'] = true; $response_data['message'] = 'Override saved successfully.'; foreach ($rows as $row) { // Map db snake_case to form's camelCase if ($row['metricName'] === 'opening_balance') { $response_data['openingBalance'] = $row['value']; } else if ($row['metricName'] === 'billing') { $response_data['billings'] = $row['value']; } else { // Directly map other metrics like 'wip', 'expenses' $response_data[$row['metricName']] = $row['value']; } } $response_data['nsr'] = $nsr; $response_data['margin'] = $margin; send_json_response($response_data); } catch (Exception $e) { if (isset($pdo) && $pdo->inTransaction()) { $pdo->rollBack(); } // Log the error and send a JSON response directly error_log($e->getMessage()); send_json_response(['success' => false, 'message' => 'A server error occurred: ' . $e->getMessage()]); }