View file File name : api.php Content :<?php session_start(); date_default_timezone_set('America/Belize'); require 'db_config.php'; require '_helpers.php'; header('Content-Type: application/json'); // --- HELPER FUNCTIONS (keep local to api.php) --- function send_json_error($message, $code = 400) { http_response_code($code); echo json_encode(['success' => false, 'message' => $message]); exit(); } function send_json_success($data = []) { echo json_encode(['success' => true, 'data' => $data]); exit(); } // --- DATABASE CONNECTION --- $conn = get_db_connection(); // --- ACTION ROUTER --- $action = $_POST['action'] ?? ''; if (empty($action)) { send_json_error('No action specified.'); } // --- PUBLIC ACTIONS (NO SESSION REQUIRED) --- if ($action === 'login') { $username_in = $_POST['username'] ?? ''; $password_in = $_POST['password'] ?? ''; if (empty($username_in) || empty($password_in)) { send_json_error('Username and password are required.'); } $stmt = $conn->prepare("SELECT * FROM admins WHERE username = ?"); if (!$stmt) send_json_error("Database query failed.", 500); $stmt->bind_param("s", $username_in); $stmt->execute(); $user_results = fetch_all_assoc($stmt); $user = !empty($user_results) ? $user_results[0] : null; $stmt->close(); if ($user && $password_in === $user['password']) { $_SESSION['user_id'] = $user['id']; $_SESSION['user_name'] = $user['name']; send_json_success(['redirect' => 'dashboard.php']); } else { send_json_error('Invalid username or password.', 401); } } elseif ($action === 'logout') { session_unset(); session_destroy(); send_json_success(['redirect' => 'index.php']); } else { // --- AUTHENTICATED ACTIONS --- if (!isset($_SESSION['user_id'])) { send_json_error('Authentication required.', 401); } switch ($action) { case 'record_payment': $invoice_id = $_POST['invoice_id'] ?? null; $payment_date = $_POST['payment_date'] ?? date('Y-m-d'); $method = $_POST['method'] ?? null; $account = $_POST['account'] ?? null; $amount = (float)($_POST['amount'] ?? 0); if (!$invoice_id || $amount <= 0) { send_json_error('Invoice ID and a positive payment amount are required.'); } $conn->begin_transaction(); try { $stmt = $conn->prepare("SELECT total, amount_paid, payment_history, due_date, status FROM invoices WHERE id = ? FOR UPDATE"); $stmt->bind_param("s", $invoice_id); $stmt->execute(); $result = fetch_all_assoc($stmt); if (empty($result)) { throw new Exception('Invoice not found.'); } $invoice = $result[0]; $stmt->close(); $new_amount_paid = (float)$invoice['amount_paid'] + $amount; $total = (float)$invoice['total']; $new_status = $invoice['status']; if ($new_amount_paid >= $total) { $new_status = 'Paid'; } else if ($new_amount_paid > 0) { $new_status = 'Partially Paid'; } $payment_history_json = $invoice['payment_history'] ?? '[]'; $payment_history = json_decode($payment_history_json, true); if (json_last_error() !== JSON_ERROR_NONE) $payment_history = []; // Reset if invalid JSON $payment_history[] = [ 'date' => $payment_date, 'amount' => $amount, 'method' => $method, 'account' => $account ]; $stmt = $conn->prepare("UPDATE invoices SET status = ?, amount_paid = ?, paid_at = ?, paymentMethod = ?, paymentAccount = ?, payment_history = ? WHERE id = ?"); $new_payment_history_json = json_encode($payment_history); // Use the latest payment date as the main paid_at for simplicity $latest_paid_at = $new_status === 'Paid' ? $payment_date : null; $stmt->bind_param("sdsssss", $new_status, $new_amount_paid, $latest_paid_at, $method, $account, $new_payment_history_json, $invoice_id); if ($stmt->execute()) { $conn->commit(); $message = 'Payment recorded.'; send_json_success(['message' => $message]); } else { throw new Exception('Failed to record payment: ' . $stmt->error); } $stmt->close(); } catch (Exception $e) { $conn->rollback(); send_json_error($e->getMessage(), 500); } break; case 'remove_payment': $invoice_id = $_POST['invoice_id'] ?? null; if (!$invoice_id) send_json_error('Invoice ID is required.'); $stmt_fetch = $conn->prepare("SELECT due_date FROM invoices WHERE id = ?"); $stmt_fetch->bind_param("s", $invoice_id); $stmt_fetch->execute(); $result = fetch_all_assoc($stmt_fetch); $stmt_fetch->close(); if (empty($result)) send_json_error('Invoice not found', 404); $due_date = new DateTime($result[0]['due_date']); $today = new DateTime(); $new_status = ($due_date < $today) ? 'Overdue' : 'Due'; $stmt_update = $conn->prepare("UPDATE invoices SET status = ?, paid_at = NULL, paymentMethod = NULL, paymentAccount = NULL, amount_paid = 0, payment_history = NULL WHERE id = ?"); $stmt_update->bind_param("ss", $new_status, $invoice_id); if($stmt_update->execute()){ send_json_success(['message' => "Payment removed. Invoice status updated to {$new_status}."]); } else { send_json_error('Failed to remove payment: ' . $stmt_update->error, 500); } $stmt_update->close(); break; default: send_json_error('Invalid action specified for authenticated user.'); break; } } $conn->close(); ?>