false, 'message' => 'An error occurred.']; $pdo = null; try { $pdo = db(); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $data = json_decode($raw_input, true); if (empty($data['project_id']) || empty($data['overrides'])) { throw new Exception("Project ID or overrides data not provided."); } $project_id = $data['project_id']; $overrides = $data['overrides']; $rows_affected_total = 0; $pdo->beginTransaction(); $sql = " INSERT INTO projectFinanceMonthly (projectId, month, opening_balance, payment, wip, expenses, cost, nsr, margin, is_confirmed) VALUES (:project_id, :month, :opening_balance, :payment, :wip, :expenses, :cost, :nsr, :margin, :is_confirmed) ON DUPLICATE KEY UPDATE opening_balance = VALUES(opening_balance), payment = VALUES(payment), wip = VALUES(wip), expenses = VALUES(expenses), cost = VALUES(cost), nsr = VALUES(nsr), margin = VALUES(margin), is_confirmed = VALUES(is_confirmed) "; $stmt = $pdo->prepare($sql); foreach ($overrides as $override) { $date = new DateTime($override['month']); $month = $date->format('Y-m-d'); $params = [ ':project_id' => $project_id, ':month' => $month, ':opening_balance' => $override['opening_balance'] ?? null, ':payment' => $override['payment'] ?? null, ':wip' => $override['wip'] ?? null, ':expenses' => $override['expenses'] ?? null, ':cost' => $override['cost'] ?? null, ':nsr' => $override['nsr'] ?? null, ':margin' => $override['margin'] ?? null, ':is_confirmed' => $override['is_confirmed'] ?? 0, ]; $stmt->execute($params); $rows_affected_total += $stmt->rowCount(); } if ($rows_affected_total === 0) { // It's possible that the data is identical, so 0 affected rows is not strictly an error. // We can consider it a "soft" success. $pdo->rollBack(); // Rollback to not leave an open transaction $response['success'] = true; // Report success to the frontend $response['message'] = 'No changes were detected. Nothing was saved.'; echo json_encode($response); exit; } $pdo->commit(); $response['success'] = true; $response['message'] = 'Override data saved successfully. ' . $rows_affected_total . ' records were updated.'; } catch (PDOException $e) { if ($pdo && $pdo->inTransaction()) { $pdo->rollBack(); } error_log("save_override.php: PDOException caught: " . $e->getMessage()); $response['message'] = "Database Error: " . $e->getMessage(); http_response_code(500); } catch (Exception $e) { if ($pdo && $pdo->inTransaction()) { $pdo->rollBack(); } error_log("save_override.php: Exception caught: " . $e->getMessage()); $response['message'] = "General Error: " . $e->getMessage(); http_response_code(500); } echo json_encode($response); ?>