<?
php
session_start();
require 'config.php';
require 'date_helpers.php';
if (!isset($_SESSION["user_id"])) {
header("Location: login.php");
exit;
}
// Date filtering with validation
$default_start = date('Y-m-01');
$default_end = date('Y-m-d');
$start_date = $_GET['start_date'] ?? $default_start;
$end_date = $_GET['end_date'] ?? $default_end;
if (!validateDate($start_date) || !validateDate($end_date)) {
$_SESSION['error'] = "Invalid date format. Using default dates.";
$start_date = $default_start;
$end_date = $default_end;
}
// Get financial summary with date filtering
$income = $conn->query("SELECT SUM(amount) AS total FROM journal_entries
WHERE credit_account_id = (SELECT id FROM accounts WHERE
account_name = 'Sales Revenue')
AND entry_date BETWEEN '$start_date' AND '$end_date'")
->fetch_assoc()['total'] ?? 0;
$expenses = $conn->query("SELECT SUM(amount) AS total FROM journal_entries
WHERE debit_account_id IN (SELECT id FROM accounts WHERE
account_type = 'expense')
AND entry_date BETWEEN '$start_date' AND '$end_date'")
->fetch_assoc()['total'] ?? 0;
$profit = $income - $expenses;
// Get inventory valuation (as of end date)
$inventory_value = $conn->query("SELECT SUM(quantity * cost_price) AS total FROM
inventory")
->fetch_assoc()['total'] ?? 0;
// Get low stock items
$low_stock = $conn->query("SELECT * FROM inventory WHERE quantity <= reorder_level
ORDER BY quantity ASC");
// Get recent transactions with date filtering
$recent_transactions = $conn->query("SELECT t.*, i.item_name, u.username
FROM transactions t
JOIN inventory i ON t.item_id = i.id
JOIN users u ON t.user_id = u.id
WHERE t.transaction_date BETWEEN '$start_date'
AND '$end_date'
ORDER BY t.transaction_date DESC LIMIT 10");
// Get monthly income data for chart (last 6 months)
$monthly_income = $conn->query("SELECT
DATE_FORMAT(entry_date, '%Y-%m') AS month,
SUM(amount) AS total
FROM journal_entries
WHERE credit_account_id = (SELECT id FROM accounts
WHERE account_name = 'Sales Revenue')
AND entry_date BETWEEN DATE_SUB('$end_date',
INTERVAL 5 MONTH) AND '$end_date'
GROUP BY month
ORDER BY month ASC");
$income_labels = [];
$income_data = [];
while($row = $monthly_income->fetch_assoc()) {
$income_labels[] = date('M Y', strtotime($row['month']));
$income_data[] = $row['total'];
}
// Get expense breakdown
$expense_breakdown = $conn->query("SELECT
a.account_name,
SUM(je.amount) AS total
FROM journal_entries je
JOIN accounts a ON je.debit_account_id = a.id
WHERE a.account_type = 'expense'
AND je.entry_date BETWEEN '$start_date' AND
'$end_date'
GROUP BY a.account_name
ORDER BY total DESC");
?>
<!DOCTYPE html>
<html>
<head>
<title>Reports Dashboard</title>
<link rel="stylesheet" href="style.css">
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
</head>
<body>
<?php include 'header.php'; ?>
<div class="container">
<h2>Financial Reports</h2>
<?php if(isset($_SESSION['success'])): ?>
<div class="alert success">
<?= $_SESSION['success']; unset($_SESSION['success']); ?>
</div>
<?php endif; ?>
<?php if(isset($_SESSION['error'])): ?>
<div class="alert error">
<?= $_SESSION['error']; unset($_SESSION['error']); ?>
</div>
<?php endif; ?>
<!-- Date Filter Section -->
<div class="filter-container compact-filters">
<h3 class="filter-title">Report Period</h3>
<form method="GET" class="filter-form">
<div class="form-group compact-date">
<label for="start_date">From</label>
<input type="date" id="start_date" name="start_date" value="<?=
$start_date ?>">
</div>
<div class="form-group compact-date">
<label for="end_date">To</label>
<input type="date" id="end_date" name="end_date" value="<?=
$end_date ?>">
</div>
<div class="form-group filter-actions">
<button type="submit" class="btn compact-btn">Apply</button>
<a href="reports.php" class="btn compact-btn btn-
secondary">Reset</a>
</div>
</form>
</div>
<!-- Financial Summary Cards -->
<div class="card-container">
<div class="card income">
<h3>Total Income</h3>
<p>GHS <?= number_format($income, 2) ?></p>
<small><?= formatDateForDisplay($start_date) ?> to <?=
formatDateForDisplay($end_date) ?></small>
</div>
<div class="card expense">
<h3>Total Expenses</h3>
<p>GHS <?= number_format($expenses, 2) ?></p>
<small><?= formatDateForDisplay($start_date) ?> to <?=
formatDateForDisplay($end_date) ?></small>
</div>
<div class="card profit">
<h3>Net Profit</h3>
<p>GHS <?= number_format($profit, 2) ?></p>
<small><?= formatDateForDisplay($start_date) ?> to <?=
formatDateForDisplay($end_date) ?></small>
</div>
<div class="card inventory">
<h3>Inventory Value</h3>
<p>GHS <?= number_format($inventory_value, 2) ?></p>
<small>As of <?= formatDateForDisplay($end_date) ?></small>
</div>
</div>
<!-- Charts Section -->
<div class="chart-row">
<div class="chart-container">
<h3>Income Trend (Last 6 Months)</h3>
<canvas id="incomeChart" height="200"></canvas>
</div>
<div class="chart-container">
<h3>Expense Breakdown</h3>
<canvas id="expenseChart" height="200"></canvas>
</div>
</div>
<div class="data-section">
<!-- Low Stock Warning -->
<div class="data-card">
<h3>Low Stock Items</h3>
<div class="table-responsive">
<table>
<thead>
<tr>
<th>Item</th>
<th>Current Qty</th>
<th>Reorder Level</th>
<th>Last Updated</th>
</tr>
</thead>
<tbody>
<?php if($low_stock->num_rows > 0): ?>
<?php while($item = $low_stock->fetch_assoc()): ?>
<tr>
<td><?= $item['item_name'] ?></td>
<td class="low-stock"><?= $item['quantity'] ?
></td>
<td><?= $item['reorder_level'] ?></td>
<td><?=
formatDateForDisplay($item['last_updated']) ?></td>
</tr>
<?php endwhile; ?>
<?php else: ?>
<tr>
<td colspan="4" class="no-data">No low stock
items</td>
</tr>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
<!-- Recent Transactions -->
<div class="data-card">
<h3>Recent Transactions</h3>
<div class="table-responsive">
<table>
<thead>
<tr>
<th>Date</th>
<th>Type</th>
<th>Item</th>
<th>Amount</th>
</tr>
</thead>
<tbody>
<?php if($recent_transactions->num_rows > 0): ?>
<?php while($tran = $recent_transactions-
>fetch_assoc()): ?>
<tr>
<td><?=
formatDateForDisplay($tran['transaction_date']) ?></td>
<td class="tran-type-<?=
$tran['transaction_type'] ?>"><?= ucfirst($tran['transaction_type']) ?></td>
<td><?= $tran['item_name'] ?></td>
<td>GHS <?= number_format($tran['amount'], 2) ?
></td>
</tr>
<?php endwhile; ?>
<?php else: ?>
<tr>
<td colspan="4" class="no-data">No transactions
in selected period</td>
</tr>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
<script>
// Income Trend Chart
const incomeCtx = document.getElementById('incomeChart').getContext('2d');
new Chart(incomeCtx, {
type: 'line',
data: {
labels: <?= json_encode($income_labels) ?>,
datasets: [{
label: 'Monthly Income (GHS)',
data: <?= json_encode($income_data) ?>,
backgroundColor: 'rgba(40, 167, 69, 0.2)',
borderColor: 'rgba(40, 167, 69, 1)',
borderWidth: 2,
tension: 0.3,
fill: true
}]
},
options: {
responsive: true,
plugins: {
legend: {
position: 'top',
}
},
scales: {
y: {
beginAtZero: true,
ticks: {
callback: function(value) {
return 'GHS ' + value.toLocaleString();
}
}
}
}
}
});
// Expense Breakdown Chart
const expenseData = {
labels: [
<?php
$expense_breakdown->data_seek(0);
while($exp = $expense_breakdown->fetch_assoc()) {
echo "'".$exp['account_name']."',";
}
?>
],
datasets: [{
data: [
<?php
$expense_breakdown->data_seek(0);
while($exp = $expense_breakdown->fetch_assoc()) {
echo $exp['total'].",";
}
?>
],
backgroundColor: [
'#dc3545', '#fd7e14', '#ffc107', '#20c997', '#0dcaf0',
'#6610f2'
],
borderWidth: 1
}]
};
const expenseCtx =
document.getElementById('expenseChart').getContext('2d');
new Chart(expenseCtx, {
type: 'doughnut',
data: expenseData,
options: {
responsive: true,
plugins: {
legend: {
position: 'right',
},
tooltip: {
callbacks: {
label: function(context) {
return context.label + ': GHS ' +
context.raw.toLocaleString();
}
}
}
}
}
});
</script>
</body>
</html>