false, 'error' => 'Invalid request']; if ($_SERVER['REQUEST_METHOD'] === 'POST') { $project_id = $_POST['projectId'] ?? null; $month = $_POST['month'] ?? null; $metrics = [ 'wip' => $_POST['wip'] ?? null, 'opening_balance' => $_POST['openingBalance'] ?? null, 'billings' => $_POST['billings'] ?? null, 'expenses' => $_POST['expenses'] ?? null, 'cost' => $_POST['cost'] ?? null, ]; if ($project_id && $month && !in_array(null, $metrics, true)) { try { $pdo = db(); $sql = "INSERT INTO projectFinanceMonthly (projectId, month, metricName, value, is_overridden) VALUES (:pid, :m, :metric, :value, 1) ON DUPLICATE KEY UPDATE value = :value, is_overridden = 1"; $stmt = $pdo->prepare($sql); $metric_map = [ 'wip' => 'wip', 'opening_balance' => 'opening_balance', 'billings' => 'billing', 'expenses' => 'expenses', 'cost' => 'cost' ]; foreach ($metrics as $metricKey => $value) { if (isset($metric_map[$metricKey])) { $metricName = $metric_map[$metricKey]; $stmt->execute([ ':pid' => $project_id, ':m' => $month, ':metric' => $metricName, ':value' => $value ]); } } // Use the newly submitted values from POST as the source of truth for calculation $wip = (float)($metrics['wip'] ?? 0); $billings = (float)($metrics['billings'] ?? 0); $opening_balance = (float)($metrics['opening_balance'] ?? 0); $expenses = (float)($metrics['expenses'] ?? 0); $cost = (float)($metrics['cost'] ?? 0); // Calculate NSR $nsr = $wip + $billings - $opening_balance - $expenses; // Calculate Margin $margin = ($nsr != 0) ? (($nsr - $cost) / $nsr) : 0; // Save NSR and Margin $stmt->execute([ ':pid' => $project_id, ':m' => $month, ':metric' => 'nsr', ':value' => $nsr ]); $stmt->execute([ ':pid' => $project_id, ':m' => $month, ':metric' => 'margin', ':value' => $margin ]); $response = [ 'success' => true, 'wip' => $wip, 'openingBalance' => $opening_balance, 'billings' => $billings, 'expenses' => $expenses, 'cost' => $cost, 'nsr' => $nsr, 'margin' => $margin ]; } catch (PDOException $e) { $response['error'] = 'Database error: ' . $e->getMessage(); error_log($e->getMessage()); } } else { $response['error'] = 'Missing required fields.'; } } try { echo json_encode($response, JSON_THROW_ON_ERROR); } catch (JsonException $e) { error_log('JSON encoding error: ' . $e->getMessage()); http_response_code(500); echo json_encode(['success' => false, 'error' => 'Internal server error during JSON encoding.']); } exit;