36293-vm/save_override.php
2025-11-27 13:28:19 +00:00

141 lines
4.6 KiB
PHP

<?php
ini_set('display_errors', 0);
error_reporting(0);
require_once 'db/config.php';
// Function to send a consistent JSON response, aggressively cleaning any output.
function send_json_response($data) {
// Ensure no stray output is included.
if (ob_get_level() > 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()]);
}