Bump and Migrate logic chartjs 2.9.4 to 4.5.0, bump stripe-php from 17.2.1 to 17.6.0, fontawesome-free from 5.15.4 to 7.0.0, fullcalendar from 6.1.17 to 6.1.19, TinyMCE from 7.9.1 to 8.0.2, bootsatrap js bundle from 4.6.1 to 4.6.2, DataTables from 2.3.1 to 2.3.3

This commit is contained in:
johnnyq
2025-08-28 13:57:42 -04:00
parent 9f50c9355a
commit 39d6c42c71
359 changed files with 3058 additions and 25716 deletions

View File

@@ -32,9 +32,19 @@ $sql_years_select = mysqli_query($mysqli, "
UNION DISTINCT SELECT YEAR(user_created_at) FROM users
ORDER BY all_years DESC
");
?>
<!-- Responsive chart helpers -->
<style>
.chart-h-320 { position: relative; height: 320px; }
.chart-h-240 { position: relative; height: 240px; }
/* If you want charts to shrink on very small screens, you can tweak with media queries:
@media (max-width: 576px) {
.chart-h-320 { height: 240px; }
.chart-h-240 { height: 200px; }
} */
</style>
<div class="card card-body">
<form class="form-inline">
<input type="hidden" name="enable_financial" value="0">
@@ -337,7 +347,9 @@ if ($user_config_dashboard_financial_enable == 1) {
</div>
</div>
<div class="card-body">
<canvas id="cashFlow" width="100%" height="20"></canvas>
<div class="chart-h-320">
<canvas id="cashFlow"></canvas>
</div>
</div>
</div>
</div>
@@ -353,7 +365,9 @@ if ($user_config_dashboard_financial_enable == 1) {
</div>
</div>
<div class="card-body">
<canvas id="incomeByCategoryPieChart" width="100%" height="60"></canvas>
<div class="chart-h-240">
<canvas id="incomeByCategoryPieChart"></canvas>
</div>
</div>
</div>
</div>
@@ -369,7 +383,9 @@ if ($user_config_dashboard_financial_enable == 1) {
</div>
</div>
<div class="card-body">
<canvas id="expenseByCategoryPieChart" width="100%" height="60"></canvas>
<div class="chart-h-240">
<canvas id="expenseByCategoryPieChart"></canvas>
</div>
</div>
</div>
</div>
@@ -385,7 +401,9 @@ if ($user_config_dashboard_financial_enable == 1) {
</div>
</div>
<div class="card-body">
<canvas id="expenseByVendorPieChart" width="100%" height="60"></canvas>
<div class="chart-h-240">
<canvas id="expenseByVendorPieChart"></canvas>
</div>
</div>
</div>
</div>
@@ -533,7 +551,9 @@ if ($user_config_dashboard_financial_enable == 1) {
</div>
</div>
<div class="card-body">
<canvas id="tripFlow" width="100%" height="20"></canvas>
<div class="chart-h-320">
<canvas id="tripFlow"></canvas>
</div>
</div>
</div>
</div>
@@ -739,404 +759,411 @@ if ($user_config_dashboard_technical_enable == 1) {
<?php if ($user_config_dashboard_financial_enable == 1) { ?>
<script>
// Set new default font family and font color to mimic Bootstrap's default styling
Chart.defaults.global.defaultFontFamily = '-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif';
Chart.defaults.global.defaultFontColor = '#292b2c';
// Bootstrap-like defaults for Chart.js v4
Chart.defaults.font.family = '-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif';
Chart.defaults.color = '#292b2c';
// Area Chart Example
var ctx = document.getElementById("cashFlow");
var myLineChart = new Chart(ctx, {
type: 'line',
data: {
labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
datasets: [{
label: "Income",
fill: false,
borderColor: "#007bff",
pointBackgroundColor: "#007bff",
pointBorderColor: "#007bff",
pointHoverRadius: 5,
pointHoverBackgroundColor: "#007bff",
pointHitRadius: 50,
pointBorderWidth: 2,
data: [
<?php
for ($month = 1; $month <= 12; $month++) {
$sql_payments = mysqli_query($mysqli, "SELECT SUM(payment_amount) AS payment_amount_for_month FROM payments, invoices WHERE payment_invoice_id = invoice_id AND YEAR(payment_date) = $year AND MONTH(payment_date) = $month");
$row = mysqli_fetch_array($sql_payments);
$payments_for_month = floatval($row['payment_amount_for_month']);
// CASH FLOW
(function () {
var ctx = document.getElementById("cashFlow");
if (!ctx) return;
$sql_revenues = mysqli_query($mysqli, "SELECT SUM(revenue_amount) AS revenue_amount_for_month FROM revenues WHERE revenue_category_id > 0 AND YEAR(revenue_date) = $year AND MONTH(revenue_date) = $month");
$row = mysqli_fetch_array($sql_revenues);
$revenues_for_month = floatval($row['revenue_amount_for_month']);
var myLineChart = new Chart(ctx, {
type: 'line',
data: {
labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
datasets: [
{
label: "Income",
fill: false,
borderColor: "#007bff",
pointBackgroundColor: "#007bff",
pointBorderColor: "#007bff",
pointHoverRadius: 5,
pointHoverBackgroundColor: "#007bff",
pointBorderWidth: 2,
data: [
<?php
for ($month = 1; $month <= 12; $month++) {
$sql_payments = mysqli_query($mysqli, "SELECT SUM(payment_amount) AS payment_amount_for_month FROM payments, invoices WHERE payment_invoice_id = invoice_id AND YEAR(payment_date) = $year AND MONTH(payment_date) = $month");
$row = mysqli_fetch_array($sql_payments);
$payments_for_month = floatval($row['payment_amount_for_month']);
$income_for_month = $payments_for_month + $revenues_for_month;
$sql_revenues = mysqli_query($mysqli, "SELECT SUM(revenue_amount) AS revenue_amount_for_month FROM revenues WHERE revenue_category_id > 0 AND YEAR(revenue_date) = $year AND MONTH(revenue_date) = $month");
$row = mysqli_fetch_array($sql_revenues);
$revenues_for_month = floatval($row['revenue_amount_for_month']);
if ($income_for_month > 0 && $income_for_month > $largest_income_month) {
$largest_income_month = $income_for_month;
$income_for_month = $payments_for_month + $revenues_for_month;
if ($income_for_month > 0 && $income_for_month > $largest_income_month) {
$largest_income_month = $income_for_month;
}
echo "$income_for_month,";
}
?>
<?php echo "$income_for_month,"; ?>
<?php } ?>
],
},
{
label: "LY Income",
fill: false,
borderColor: "#9932CC",
pointBackgroundColor: "#9932CC",
pointBorderColor: "#9932CC",
pointHoverRadius: 5,
pointHoverBackgroundColor: "#9932CC",
pointHitRadius: 50,
pointBorderWidth: 2,
data: [
<?php
for ($month = 1; $month <= 12; $month++) {
$sql_payments = mysqli_query($mysqli, "SELECT SUM(payment_amount) AS payment_amount_for_month FROM payments, invoices WHERE payment_invoice_id = invoice_id AND YEAR(payment_date) = $year-1 AND MONTH(payment_date) = $month");
$row = mysqli_fetch_array($sql_payments);
$payments_for_month = floatval($row['payment_amount_for_month']);
$sql_revenues = mysqli_query($mysqli, "SELECT SUM(revenue_amount) AS revenue_amount_for_month FROM revenues WHERE revenue_category_id > 0 AND YEAR(revenue_date) = $year-1 AND MONTH(revenue_date) = $month");
$row = mysqli_fetch_array($sql_revenues);
$revenues_for_month = floatval($row['revenue_amount_for_month']);
$income_for_month = $payments_for_month + $revenues_for_month;
if ($income_for_month > 0 && $income_for_month > $largest_income_month) {
$largest_income_month = $income_for_month;
}
?>
<?php echo "$income_for_month,"; ?>
<?php } ?>
],
},
{
label: "Projected",
fill: false,
borderColor: "black",
pointBackgroundColor: "black",
pointBorderColor: "black",
pointHoverRadius: 5,
pointHoverBackgroundColor: "black",
pointHitRadius: 50,
pointBorderWidth: 2,
data: [
<?php
$largest_invoice_month = 0;
for ($month = 1; $month <= 12; $month++) {
$sql_projected = mysqli_query($mysqli, "SELECT SUM(invoice_amount) AS invoice_amount_for_month FROM invoices WHERE YEAR(invoice_due) = $year AND MONTH(invoice_due) = $month AND invoice_status != 'Cancelled' AND invoice_status != 'Draft' AND invoice_status != 'Non-Billable'");
$row = mysqli_fetch_array($sql_projected);
$invoice_for_month = floatval($row['invoice_amount_for_month']);
if ($invoice_for_month > 0 && $invoice_for_month > $largest_invoice_month) {
$largest_invoice_month = $invoice_for_month;
}
?>
<?php echo "$invoice_for_month,"; ?>
<?php } ?>
],
},
{
label: "Expense",
lineTension: 0.3,
fill: false,
borderColor: "#dc3545",
pointBackgroundColor: "#dc3545",
pointBorderColor: "#dc3545",
pointHoverRadius: 5,
pointHoverBackgroundColor: "#dc3545",
pointHitRadius: 50,
pointBorderWidth: 2,
data: [
<?php
$largest_expense_month = 0;
for ($month = 1; $month <= 12; $month++) {
$sql_expenses = mysqli_query($mysqli, "SELECT SUM(expense_amount) AS expense_amount_for_month FROM expenses WHERE YEAR(expense_date) = $year AND MONTH(expense_date) = $month AND expense_vendor_id > 0");
$row = mysqli_fetch_array($sql_expenses);
$expenses_for_month = floatval($row['expense_amount_for_month']);
if ($expenses_for_month > 0 && $expenses_for_month > $largest_expense_month) {
$largest_expense_month = $expenses_for_month;
}
?>
<?php echo "$expenses_for_month,"; ?>
<?php } ?>
],
}
],
},
options: {
scales: {
xAxes: [{
time: {
unit: 'date'
?>
],
},
gridLines: {
display: false
{
label: "LY Income",
fill: false,
borderColor: "#9932CC",
pointBackgroundColor: "#9932CC",
pointBorderColor: "#9932CC",
pointHoverRadius: 5,
pointHoverBackgroundColor: "#9932CC",
pointBorderWidth: 2,
data: [
<?php
for ($month = 1; $month <= 12; $month++) {
$sql_payments = mysqli_query($mysqli, "SELECT SUM(payment_amount) AS payment_amount_for_month FROM payments, invoices WHERE payment_invoice_id = invoice_id AND YEAR(payment_date) = $year-1 AND MONTH(payment_date) = $month");
$row = mysqli_fetch_array($sql_payments);
$payments_for_month = floatval($row['payment_amount_for_month']);
$sql_revenues = mysqli_query($mysqli, "SELECT SUM(revenue_amount) AS revenue_amount_for_month FROM revenues WHERE revenue_category_id > 0 AND YEAR(revenue_date) = $year-1 AND MONTH(revenue_date) = $month");
$row = mysqli_fetch_array($sql_revenues);
$revenues_for_month = floatval($row['revenue_amount_for_month']);
$income_for_month = $payments_for_month + $revenues_for_month;
if ($income_for_month > 0 && $income_for_month > $largest_income_month) {
$largest_income_month = $income_for_month;
}
echo "$income_for_month,";
}
?>
],
},
ticks: {
maxTicksLimit: 12
{
label: "Projected",
fill: false,
borderColor: "black",
pointBackgroundColor: "black",
pointBorderColor: "black",
pointHoverRadius: 5,
pointHoverBackgroundColor: "black",
pointBorderWidth: 2,
data: [
<?php
$largest_invoice_month = 0;
for ($month = 1; $month <= 12; $month++) {
$sql_projected = mysqli_query($mysqli, "SELECT SUM(invoice_amount) AS invoice_amount_for_month FROM invoices WHERE YEAR(invoice_due) = $year AND MONTH(invoice_due) = $month AND invoice_status != 'Cancelled' AND invoice_status != 'Draft' AND invoice_status != 'Non-Billable'");
$row = mysqli_fetch_array($sql_projected);
$invoice_for_month = floatval($row['invoice_amount_for_month']);
if ($invoice_for_month > 0 && $invoice_for_month > $largest_invoice_month) {
$largest_invoice_month = $invoice_for_month;
}
echo "$invoice_for_month,";
}
?>
],
},
{
label: "Expense",
tension: 0.3, // v4 name; v2 used lineTension
fill: false,
borderColor: "#dc3545",
pointBackgroundColor: "#dc3545",
pointBorderColor: "#dc3545",
pointHoverRadius: 5,
pointHoverBackgroundColor: "#dc3545",
pointBorderWidth: 2,
data: [
<?php
$largest_expense_month = 0;
for ($month = 1; $month <= 12; $month++) {
$sql_expenses = mysqli_query($mysqli, "SELECT SUM(expense_amount) AS expense_amount_for_month FROM expenses WHERE YEAR(expense_date) = $year AND MONTH(expense_date) = $month AND expense_vendor_id > 0");
$row = mysqli_fetch_array($sql_expenses);
$expenses_for_month = floatval($row['expense_amount_for_month']);
if ($expenses_for_month > 0 && $expenses_for_month > $largest_expense_month) {
$largest_expense_month = $expenses_for_month;
}
echo "$expenses_for_month,";
}
?>
],
}
}],
yAxes: [{
ticks: {
min: 0,
max: <?php $max = max(1000, $largest_expense_month, $largest_income_month, $largest_invoice_month);
echo roundUpToNearestMultiple($max); ?>,
maxTicksLimit: 5
},
gridLines: {
color: "rgba(0, 0, 0, .125)",
}
}],
],
},
legend: {
display: true
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
x: {
grid: { display: false },
ticks: { maxTicksLimit: 12 }
},
y: {
beginAtZero: true,
min: 0,
max: <?php $max = max(1000, $largest_expense_month, $largest_income_month, $largest_invoice_month); echo roundUpToNearestMultiple($max); ?>,
ticks: { maxTicksLimit: 5 },
grid: { color: "rgba(0, 0, 0, .125)" }
}
},
plugins: {
legend: { display: true }
}
}
}
});
});
})();
// Set new default font family and font color to mimic Bootstrap's default styling
Chart.defaults.global.defaultFontFamily = '-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif';
Chart.defaults.global.defaultFontColor = '#292b2c';
// TRIP FLOW
(function () {
var ctx = document.getElementById("tripFlow");
if (!ctx) return;
// Area Chart Example
var ctx = document.getElementById("tripFlow");
var myLineChart = new Chart(ctx, {
type: 'line',
data: {
labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
datasets: [{
label: "Trip",
lineTension: 0.3,
backgroundColor: "red",
borderColor: "darkred",
pointRadius: 5,
pointBackgroundColor: "red",
pointBorderColor: "red",
pointHoverRadius: 5,
pointHoverBackgroundColor: "darkred",
pointHitRadius: 50,
pointBorderWidth: 2,
data: [
<?php
$largest_trip_miles_month = 0;
for ($month = 1; $month <= 12; $month++) {
$sql_trips = mysqli_query($mysqli, "SELECT SUM(trip_miles) AS trip_miles_for_month FROM trips WHERE YEAR(trip_date) = $year AND MONTH(trip_date) = $month");
$row = mysqli_fetch_array($sql_trips);
$trip_miles_for_month = floatval($row['trip_miles_for_month']);
var myLineChart = new Chart(ctx, {
type: 'line',
data: {
labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
datasets: [{
label: "Trip",
tension: 0.3,
fill: false,
backgroundColor: "red",
borderColor: "darkred",
pointRadius: 5,
pointBackgroundColor: "red",
pointBorderColor: "red",
pointHoverRadius: 5,
pointHoverBackgroundColor: "darkred",
pointBorderWidth: 2,
data: [
<?php
$largest_trip_miles_month = 0;
for ($month = 1; $month <= 12; $month++) {
$sql_trips = mysqli_query($mysqli, "SELECT SUM(trip_miles) AS trip_miles_for_month FROM trips WHERE YEAR(trip_date) = $year AND MONTH(trip_date) = $month");
$row = mysqli_fetch_array($sql_trips);
$trip_miles_for_month = floatval($row['trip_miles_for_month']);
if ($trip_miles_for_month > 0 && $trip_miles_for_month > $largest_trip_miles_month) {
$largest_trip_miles_month = $trip_miles_for_month;
if ($trip_miles_for_month > 0 && $trip_miles_for_month > $largest_trip_miles_month) {
$largest_trip_miles_month = $trip_miles_for_month;
}
echo "$trip_miles_for_month,";
}
?>
<?php echo "$trip_miles_for_month,"; ?>
<?php } ?>
],
}],
},
options: {
scales: {
xAxes: [{
time: {
unit: 'date'
},
gridLines: {
display: false
},
ticks: {
maxTicksLimit: 12
}
}],
yAxes: [{
ticks: {
min: 0,
max: <?php $max = max(1000, $largest_trip_miles_month);
echo roundUpToNearestMultiple($max); ?>,
maxTicksLimit: 5
},
gridLines: {
color: "rgba(0, 0, 0, .125)",
}
?>
],
}],
},
legend: {
display: false
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
x: {
grid: { display: false },
ticks: { maxTicksLimit: 12 }
},
y: {
beginAtZero: true,
min: 0,
max: <?php $max = max(1000, $largest_trip_miles_month); echo roundUpToNearestMultiple($max); ?>,
ticks: { maxTicksLimit: 5 },
grid: { color: "rgba(0, 0, 0, .125)" }
},
},
plugins: {
legend: { display: false }
}
}
}
});
});
})();
// Pie Chart Example
var ctx = document.getElementById("incomeByCategoryPieChart");
var myPieChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: [
<?php
mysqli_query($mysqli, "CREATE TEMPORARY TABLE TopCategories SELECT category_name, category_id, SUM(invoice_amount) AS total_income FROM categories, invoices WHERE invoice_category_id = category_id AND invoice_status = 'Paid' AND YEAR(invoice_date) = $year GROUP BY category_name, category_id ORDER BY total_income DESC LIMIT 5");
$sql_categories = mysqli_query($mysqli, "SELECT category_name FROM TopCategories");
while ($row = mysqli_fetch_array($sql_categories)) {
$category_name = json_encode($row['category_name']);
echo "$category_name,";
}
// INCOME BY CATEGORY (Doughnut)
(function () {
var ctx = document.getElementById("incomeByCategoryPieChart");
if (!ctx) return;
$sql_other_categories = mysqli_query($mysqli, "SELECT SUM(invoices.invoice_amount) AS other_income FROM categories LEFT JOIN TopCategories ON categories.category_id = TopCategories.category_id INNER JOIN invoices ON categories.category_id = invoices.invoice_category_id WHERE TopCategories.category_id IS NULL AND invoice_status = 'Paid' AND YEAR(invoice_date) = $year");
$row = mysqli_fetch_array($sql_other_categories);
$other_income = floatval($row['other_income']);
if ($other_income > 0) {
echo "'Others',";
}
?>
],
datasets: [{
data: [
var myPieChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: [
<?php
$sql_categories = mysqli_query($mysqli, "SELECT total_income FROM TopCategories");
mysqli_query($mysqli, "CREATE TEMPORARY TABLE TopCategories SELECT category_name, category_id, SUM(invoice_amount) AS total_income FROM categories, invoices WHERE invoice_category_id = category_id AND invoice_status = 'Paid' AND YEAR(invoice_date) = $year GROUP BY category_name, category_id ORDER BY total_income DESC LIMIT 5");
$sql_categories = mysqli_query($mysqli, "SELECT category_name FROM TopCategories");
while ($row = mysqli_fetch_array($sql_categories)) {
$total_income = floatval($row['total_income']);
echo "$total_income,";
$category_name = json_encode($row['category_name']);
echo "$category_name,";
}
$sql_other_categories = mysqli_query($mysqli, "SELECT SUM(invoices.invoice_amount) AS other_income FROM categories LEFT JOIN TopCategories ON categories.category_id = TopCategories.category_id INNER JOIN invoices ON categories.category_id = invoices.invoice_category_id WHERE TopCategories.category_id IS NULL AND invoice_status = 'Paid' AND YEAR(invoice_date) = $year");
$row = mysqli_fetch_array($sql_other_categories);
$other_income = floatval($row['other_income']);
if ($other_income > 0) {
echo "$other_income,";
echo "'Others',";
}
?>
],
backgroundColor: [
<?php
$sql_categories = mysqli_query($mysqli, "SELECT category_color FROM TopCategories JOIN categories ON TopCategories.category_id = categories.category_id");
while ($row = mysqli_fetch_array($sql_categories)) {
$category_color = json_encode($row['category_color']);
echo "$category_color,";
datasets: [{
data: [
<?php
$sql_categories = mysqli_query($mysqli, "SELECT total_income FROM TopCategories");
while ($row = mysqli_fetch_array($sql_categories)) {
$total_income = floatval($row['total_income']);
echo "$total_income,";
}
if ($other_income > 0) {
echo "$other_income,";
}
?>
],
backgroundColor: [
<?php
$sql_categories = mysqli_query($mysqli, "SELECT category_color FROM TopCategories JOIN categories ON TopCategories.category_id = categories.category_id");
while ($row = mysqli_fetch_array($sql_categories)) {
$category_color = json_encode($row['category_color']);
echo "$category_color,";
}
if ($other_income > 0) {
echo "'#999999',"; // color for 'Others'
}
?>
],
}],
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: true,
position: 'right'
}
if ($other_income > 0) {
echo "'#999999',"; // color for 'Others' category
}
?>
],
}],
},
options: {
legend: {
display: true,
position: 'right'
}
}
}
});
});
})();
// Pie Chart Example
var ctx = document.getElementById("expenseByCategoryPieChart");
var myPieChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: [
<?php
mysqli_query($mysqli, "CREATE TEMPORARY TABLE TopExpenseCategories SELECT category_name, category_id, SUM(expense_amount) AS total_expense FROM categories, expenses WHERE expense_category_id = category_id AND expense_vendor_id > 0 AND YEAR(expense_date) = $year GROUP BY category_name, category_id ORDER BY total_expense DESC LIMIT 5");
$sql_categories = mysqli_query($mysqli, "SELECT category_name FROM TopExpenseCategories");
while ($row = mysqli_fetch_array($sql_categories)) {
$category_name = json_encode($row['category_name']);
echo "$category_name,";
}
// EXPENSE BY CATEGORY (Doughnut)
(function () {
var ctx = document.getElementById("expenseByCategoryPieChart");
if (!ctx) return;
$sql_other_categories = mysqli_query($mysqli, "SELECT SUM(expenses.expense_amount) AS other_expense FROM categories LEFT JOIN TopExpenseCategories ON categories.category_id = TopExpenseCategories.category_id INNER JOIN expenses ON categories.category_id = expenses.expense_category_id WHERE TopExpenseCategories.category_id IS NULL AND expense_vendor_id > 0 AND YEAR(expense_date) = $year");
$row = mysqli_fetch_array($sql_other_categories);
$other_expense = floatval($row['other_expense']);
if ($other_expense > 0) {
echo "'Others',";
}
?>
],
datasets: [{
data: [
var myPieChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: [
<?php
$sql_categories = mysqli_query($mysqli, "SELECT total_expense FROM TopExpenseCategories");
mysqli_query($mysqli, "CREATE TEMPORARY TABLE TopExpenseCategories SELECT category_name, category_id, SUM(expense_amount) AS total_expense FROM categories, expenses WHERE expense_category_id = category_id AND expense_vendor_id > 0 AND YEAR(expense_date) = $year GROUP BY category_name, category_id ORDER BY total_expense DESC LIMIT 5");
$sql_categories = mysqli_query($mysqli, "SELECT category_name FROM TopExpenseCategories");
while ($row = mysqli_fetch_array($sql_categories)) {
$total_expense = floatval($row['total_expense']);
echo "$total_expense,";
$category_name = json_encode($row['category_name']);
echo "$category_name,";
}
$sql_other_categories = mysqli_query($mysqli, "SELECT SUM(expenses.expense_amount) AS other_expense FROM categories LEFT JOIN TopExpenseCategories ON categories.category_id = TopExpenseCategories.category_id INNER JOIN expenses ON categories.category_id = expenses.expense_category_id WHERE TopExpenseCategories.category_id IS NULL AND expense_vendor_id > 0 AND YEAR(expense_date) = $year");
$row = mysqli_fetch_array($sql_other_categories);
$other_expense = floatval($row['other_expense']);
if ($other_expense > 0) {
echo "$other_expense,";
echo "'Others',";
}
?>
],
backgroundColor: [
<?php
$sql_categories = mysqli_query($mysqli, "SELECT category_color FROM TopExpenseCategories JOIN categories ON TopExpenseCategories.category_id = categories.category_id");
while ($row = mysqli_fetch_array($sql_categories)) {
$category_color = json_encode($row['category_color']);
echo "$category_color,";
datasets: [{
data: [
<?php
$sql_categories = mysqli_query($mysqli, "SELECT total_expense FROM TopExpenseCategories");
while ($row = mysqli_fetch_array($sql_categories)) {
$total_expense = floatval($row['total_expense']);
echo "$total_expense,";
}
if ($other_expense > 0) {
echo "$other_expense,";
}
?>
],
backgroundColor: [
<?php
$sql_categories = mysqli_query($mysqli, "SELECT category_color FROM TopExpenseCategories JOIN categories ON TopExpenseCategories.category_id = categories.category_id");
while ($row = mysqli_fetch_array($sql_categories)) {
$category_color = json_encode($row['category_color']);
echo "$category_color,";
}
if ($other_expense > 0) {
echo "'#999999',"; // color for 'Others'
}
?>
],
}],
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: true,
position: 'right'
}
if ($other_expense > 0) {
echo "'#999999',"; // color for 'Others' category
}
?>
],
}],
},
options: {
legend: {
display: true,
position: 'right'
}
}
}
});
});
})();
// Pie Chart Example
var ctx = document.getElementById("expenseByVendorPieChart");
var myPieChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: [
<?php
mysqli_query($mysqli, "CREATE TEMPORARY TABLE TopVendors SELECT vendor_name, vendor_id, SUM(expense_amount) AS total_expense FROM vendors, expenses WHERE expense_vendor_id = vendor_id AND YEAR(expense_date) = $year GROUP BY vendor_name, vendor_id ORDER BY total_expense DESC LIMIT 5");
$sql_vendors = mysqli_query($mysqli, "SELECT vendor_name FROM TopVendors");
while ($row = mysqli_fetch_array($sql_vendors)) {
$vendor_name = json_encode($row['vendor_name']);
echo "$vendor_name,";
}
// EXPENSE BY VENDOR (Doughnut)
(function () {
var ctx = document.getElementById("expenseByVendorPieChart");
if (!ctx) return;
$sql_other_vendors = mysqli_query($mysqli, "SELECT SUM(expenses.expense_amount) AS other_expense FROM vendors LEFT JOIN TopVendors ON vendors.vendor_id = TopVendors.vendor_id INNER JOIN expenses ON vendors.vendor_id = expenses.expense_vendor_id WHERE TopVendors.vendor_id IS NULL AND YEAR(expense_date) = $year");
$row = mysqli_fetch_array($sql_other_vendors);
$other_expense = floatval($row['other_expense']);
if ($other_expense > 0) {
echo "'Others',";
}
?>
],
datasets: [{
data: [
var myPieChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: [
<?php
$sql_vendors = mysqli_query($mysqli, "SELECT total_expense FROM TopVendors");
mysqli_query($mysqli, "CREATE TEMPORARY TABLE TopVendors SELECT vendor_name, vendor_id, SUM(expense_amount) AS total_expense FROM vendors, expenses WHERE expense_vendor_id = vendor_id AND YEAR(expense_date) = $year GROUP BY vendor_name, vendor_id ORDER BY total_expense DESC LIMIT 5");
$sql_vendors = mysqli_query($mysqli, "SELECT vendor_name FROM TopVendors");
while ($row = mysqli_fetch_array($sql_vendors)) {
$total_expense = floatval($row['total_expense']);
echo "$total_expense,";
$vendor_name = json_encode($row['vendor_name']);
echo "$vendor_name,";
}
$sql_other_vendors = mysqli_query($mysqli, "SELECT SUM(expenses.expense_amount) AS other_expense FROM vendors LEFT JOIN TopVendors ON vendors.vendor_id = TopVendors.vendor_id INNER JOIN expenses ON vendors.vendor_id = expenses.expense_vendor_id WHERE TopVendors.vendor_id IS NULL AND YEAR(expense_date) = $year");
$row = mysqli_fetch_array($sql_other_vendors);
$other_expense = floatval($row['other_expense']);
if ($other_expense > 0) {
echo "$other_expense,";
echo "'Others',";
}
?>
],
backgroundColor: [
<?php
$sql_vendors = mysqli_query($mysqli, "SELECT vendor_id FROM TopVendors");
while ($row = mysqli_fetch_array($sql_vendors)) {
// Generate random color for each vendor
echo "'#" . substr(md5(rand()), 0, 6) . "',";
datasets: [{
data: [
<?php
$sql_vendors = mysqli_query($mysqli, "SELECT total_expense FROM TopVendors");
while ($row = mysqli_fetch_array($sql_vendors)) {
$total_expense = floatval($row['total_expense']);
echo "$total_expense,";
}
if ($other_expense > 0) {
echo "$other_expense,";
}
?>
],
backgroundColor: [
<?php
$sql_vendors = mysqli_query($mysqli, "SELECT vendor_id FROM TopVendors");
while ($row = mysqli_fetch_array($sql_vendors)) {
// Generate random color for each vendor
echo "'#" . substr(md5(rand()), 0, 6) . "',";
}
if ($other_expense > 0) {
echo "'#999999',"; // color for 'Others'
}
?>
],
}],
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: true,
position: 'right'
}
if ($other_expense > 0) {
echo "'#999999',"; // color for 'Others' vendor
}
?>
],
}],
},
options: {
legend: {
display: true,
position: 'right'
}
}
}
});
});
})();
</script>
<?php } ?>

View File

@@ -14,8 +14,17 @@ $sql_expense_years = mysqli_query($mysqli, "SELECT DISTINCT YEAR(expense_date) A
$sql_categories = mysqli_query($mysqli, "SELECT * FROM categories WHERE category_type = 'Expense' ORDER BY category_name ASC");
// For chart Y-axis max
$largest_expense_month = 0;
?>
<!-- Responsive chart helpers -->
<style>
.chart-h-320 { position: relative; height: 320px; }
@media (max-width: 576px) { .chart-h-320 { height: 260px; } }
</style>
<div class="card card-dark">
<div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fas fa-fw fa-coins mr-2"></i>Expense Summary</h3>
@@ -26,19 +35,16 @@ $sql_categories = mysqli_query($mysqli, "SELECT * FROM categories WHERE category
<div class="card-body">
<form class="mb-3">
<select onchange="this.form.submit()" class="form-control" name="year">
<?php
while ($row = mysqli_fetch_array($sql_expense_years)) {
$expense_year = $row['expense_year'];
?>
<option <?php if ($year == $expense_year) { ?> selected <?php } ?> > <?php echo $expense_year; ?></option>
<?php while ($row = mysqli_fetch_array($sql_expense_years)) {
$expense_year = intval($row['expense_year']); ?>
<option <?php if ($year == $expense_year) { ?> selected <?php } ?>><?php echo $expense_year; ?></option>
<?php } ?>
</select>
</form>
<canvas id="cashFlow" width="100%" height="20"></canvas>
<div class="chart-h-320 mb-3">
<canvas id="cashFlow"></canvas>
</div>
<div class="table-responsive-sm">
<table class="table table-striped">
@@ -61,53 +67,54 @@ $sql_categories = mysqli_query($mysqli, "SELECT * FROM categories WHERE category
</tr>
</thead>
<tbody>
<?php
while ($row = mysqli_fetch_array($sql_categories)) {
<?php while ($row = mysqli_fetch_array($sql_categories)) {
$category_id = intval($row['category_id']);
$category_name = nullable_htmlentities($row['category_name']);
?>
$category_name = nullable_htmlentities($row['category_name']); ?>
<tr>
<td><?php echo $category_name; ?></td>
<?php
$total_expense_for_all_months = 0;
for ($month = 1; $month<=12; $month++) {
for ($month = 1; $month <= 12; $month++) {
$sql_expenses = mysqli_query($mysqli, "SELECT SUM(expense_amount) AS expense_amount_for_month FROM expenses WHERE expense_category_id = $category_id AND YEAR(expense_date) = $year AND MONTH(expense_date) = $month");
$row = mysqli_fetch_array($sql_expenses);
$expense_amount_for_month = floatval($row['expense_amount_for_month']);
$total_expense_for_all_months = $expense_amount_for_month + $total_expense_for_all_months;
$rowm = mysqli_fetch_array($sql_expenses);
$expense_amount_for_month = floatval($rowm['expense_amount_for_month']);
$total_expense_for_all_months += $expense_amount_for_month;
?>
<td class="text-right"><a class="text-dark" href="expenses.php?q=<?php echo $category_name; ?>&dtf=<?php echo "$year-$month"; ?>-01&dtt=<?php echo "$year-$month"; ?>-31"><?php echo numfmt_format_currency($currency_format, $expense_amount_for_month, $session_company_currency); ?></a></td>
<td class="text-right">
<a class="text-dark" href="expenses.php?q=<?php echo $category_name; ?>&dtf=<?php echo "$year-$month"; ?>-01&dtt=<?php echo "$year-$month"; ?>-31">
<?php echo numfmt_format_currency($currency_format, $expense_amount_for_month, $session_company_currency); ?>
</a>
</td>
<?php } ?>
<th class="text-right"><a class="text-dark" href="expenses.php?q=<?php echo $category_name; ?>&dtf=<?php echo $year; ?>-01-01&dtt=<?php echo $year; ?>-12-31"><?php echo numfmt_format_currency($currency_format, $total_expense_for_all_months, $session_company_currency); ?></a></th>
<th class="text-right">
<a class="text-dark" href="expenses.php?q=<?php echo $category_name; ?>&dtf=<?php echo $year; ?>-01-01&dtt=<?php echo $year; ?>-12-31">
<?php echo numfmt_format_currency($currency_format, $total_expense_for_all_months, $session_company_currency); ?>
</a>
</th>
</tr>
<?php } ?>
<tr>
<th>Total</th>
<?php
for ($month = 1; $month<=12; $month++) {
$grand_total_all_months = 0;
for ($month = 1; $month <= 12; $month++) {
$sql_expenses = mysqli_query($mysqli, "SELECT SUM(expense_amount) AS expense_total_amount_for_month FROM expenses WHERE YEAR(expense_date) = $year AND MONTH(expense_date) = $month AND expense_vendor_id > 0");
$row = mysqli_fetch_array($sql_expenses);
$expense_total_amount_for_month = floatval($row['expense_total_amount_for_month']);
$total_expense_for_all_months = $expense_total_amount_for_month + $total_expense_for_all_months;
$rowt = mysqli_fetch_array($sql_expenses);
$expense_total_amount_for_month = floatval($rowt['expense_total_amount_for_month']);
$grand_total_all_months += $expense_total_amount_for_month;
?>
<th class="text-right"><a class="text-dark" href="expenses.php?dtf=<?php echo "$year-$month"; ?>-01&dtt=<?php echo "$year-$month"; ?>-31"><?php echo numfmt_format_currency($currency_format, $expense_total_amount_for_month, $session_company_currency); ?></a></th>
<th class="text-right">
<a class="text-dark" href="expenses.php?dtf=<?php echo "$year-$month"; ?>-01&dtt=<?php echo "$year-$month"; ?>-31">
<?php echo numfmt_format_currency($currency_format, $expense_total_amount_for_month, $session_company_currency); ?>
</a>
</th>
<?php } ?>
<th class="text-right"><a class="text-dark" href="expenses.php?dtf=<?php echo $year; ?>-01-01&dtt=<?php echo $year; ?>-12-31"><?php echo numfmt_format_currency($currency_format, $total_expense_for_all_months, $session_company_currency); ?></th>
<th class="text-right">
<a class="text-dark" href="expenses.php?dtf=<?php echo $year; ?>-01-01&dtt=<?php echo $year; ?>-12-31">
<?php echo numfmt_format_currency($currency_format, $grand_total_all_months, $session_company_currency); ?>
</a>
</th>
</tr>
</tbody>
</table>
@@ -115,79 +122,74 @@ $sql_categories = mysqli_query($mysqli, "SELECT * FROM categories WHERE category
</div>
</div>
<?php require_once "../includes/footer.php";
?>
<?php require_once "../includes/footer.php"; ?>
<script>
// Set new default font family and font color to mimic Bootstrap's default styling
Chart.defaults.global.defaultFontFamily = '-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif';
Chart.defaults.global.defaultFontColor = '#292b2c';
// Bootstrap-like defaults for Chart.js v4
Chart.defaults.font.family = '-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif';
Chart.defaults.color = '#292b2c';
var ctx = document.getElementById("cashFlow");
var myLineChart = new Chart(ctx, {
type: 'line',
data: {
labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
datasets: [{
label: "Expense",
lineTension: 0.3,
fill: false,
borderColor: "#dc3545",
pointBackgroundColor: "#dc3545",
pointBorderColor: "#dc3545",
pointHoverRadius: 5,
pointHoverBackgroundColor: "#dc3545",
pointHitRadius: 50,
pointBorderWidth: 2,
data: [
<?php
// EXPENSES LINE CHART
(function () {
var ctx = document.getElementById("cashFlow");
if (!ctx) return;
$largest_expense_month = 0;
var dataPoints = [
<?php
// Build series and track the largest month for axis max
for ($month = 1; $month <= 12; $month++) {
$sql_expenses = mysqli_query($mysqli, "SELECT SUM(expense_amount) AS expense_amount_for_month FROM expenses WHERE YEAR(expense_date) = $year AND MONTH(expense_date) = $month AND expense_vendor_id > 0");
$rowm = mysqli_fetch_array($sql_expenses);
$expenses_for_month = floatval($rowm['expense_amount_for_month']);
for ($month = 1; $month<=12; $month++) {
$sql_expenses = mysqli_query($mysqli, "SELECT SUM(expense_amount) AS expense_amount_for_month FROM expenses WHERE YEAR(expense_date) = $year AND MONTH(expense_date) = $month AND expense_vendor_id > 0");
$row = mysqli_fetch_array($sql_expenses);
$expenses_for_month = floatval($row['expense_amount_for_month']);
if ($expenses_for_month > 0 && $expenses_for_month > $largest_expense_month) {
$largest_expense_month = $expenses_for_month;
}
echo "$expenses_for_month,";
} ?>
],
}],
},
options: {
scales: {
xAxes: [{
time: {
unit: 'date'
},
gridLines: {
display: false
},
ticks: {
maxTicksLimit: 12
}
}],
yAxes: [{
ticks: {
min: 0,
max: <?php $max = max(1000, $largest_expense_month, $largest_income_month, $largest_invoice_month); echo roundUpToNearestMultiple($max); ?>,
maxTicksLimit: 5
},
gridLines: {
color: "rgba(0, 0, 0, .125)",
}
}],
},
legend: {
display: false
if ($expenses_for_month > 0 && $expenses_for_month > $largest_expense_month) {
$largest_expense_month = $expenses_for_month;
}
echo "$expenses_for_month,";
}
}
});
?>
];
new Chart(ctx, {
type: 'line',
data: {
labels: ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],
datasets: [{
label: "Expense",
tension: 0.3, // v4 name (v2: lineTension)
fill: false,
borderColor: "#dc3545",
pointBackgroundColor: "#dc3545",
pointBorderColor: "#dc3545",
pointHoverRadius: 5,
pointHoverBackgroundColor: "#dc3545",
pointBorderWidth: 2,
data: dataPoints
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
x: {
grid: { display: false },
ticks: { maxTicksLimit: 12 }
},
y: {
beginAtZero: true,
min: 0,
max: <?php
$max = max(1000, $largest_expense_month);
echo roundUpToNearestMultiple($max);
?>,
ticks: { maxTicksLimit: 5 },
grid: { color: "rgba(0, 0, 0, .125)" }
}
},
plugins: {
legend: { display: false }
}
}
});
})();
</script>

View File

@@ -16,8 +16,17 @@ $sql_payment_years = mysqli_query($mysqli, "SELECT DISTINCT YEAR(payment_date) A
$sql_categories = mysqli_query($mysqli, "SELECT * FROM categories WHERE category_type = 'Income' ORDER BY category_name ASC");
// Used for chart y-axis max calculation
$largest_income_month = 0;
?>
<!-- Responsive chart helpers -->
<style>
.chart-h-320 { position: relative; height: 320px; }
@media (max-width: 576px) { .chart-h-320 { height: 260px; } }
</style>
<div class="card card-dark">
<div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fas fa-fw fa-coins mr-2"></i>Income Summary</h3>
@@ -28,21 +37,18 @@ $sql_categories = mysqli_query($mysqli, "SELECT * FROM categories WHERE category
<div class="card-body p-0">
<form class="p-3">
<select onchange="this.form.submit()" class="form-control" name="year">
<?php
while ($row = mysqli_fetch_array($sql_payment_years)) {
$payment_year = intval($row['payment_year']);
?>
<option <?php if ($year == $payment_year) { ?> selected <?php } ?> > <?php echo $payment_year; ?></option>
<?php
}
?>
<?php while ($row = mysqli_fetch_array($sql_payment_years)) {
$payment_year = intval($row['payment_year']); ?>
<option <?php if ($year == $payment_year) { ?> selected <?php } ?>><?php echo $payment_year; ?></option>
<?php } ?>
</select>
</form>
<canvas id="cashFlow" width="100%" height="20"></canvas>
<div class="px-3 pb-3">
<div class="chart-h-320">
<canvas id="cashFlow"></canvas>
</div>
</div>
<div class="table-responsive-sm">
<table class="table table-striped">
@@ -65,81 +71,52 @@ $sql_categories = mysqli_query($mysqli, "SELECT * FROM categories WHERE category
</tr>
</thead>
<tbody>
<?php
while ($row = mysqli_fetch_array($sql_categories)) {
<?php while ($row = mysqli_fetch_array($sql_categories)) {
$category_id = intval($row['category_id']);
$category_name = nullable_htmlentities($row['category_name']);
?>
$category_name = nullable_htmlentities($row['category_name']); ?>
<tr>
<td><?php echo $category_name; ?></td>
<?php
$total_payment_for_all_months = 0;
for($month = 1; $month<=12; $month++) {
//Payments to Invoices
for ($month = 1; $month <= 12; $month++) {
// Payments to Invoices
$sql_payments = mysqli_query($mysqli, "SELECT SUM(payment_amount) AS payment_amount_for_month FROM payments, invoices WHERE payment_invoice_id = invoice_id AND invoice_category_id = $category_id AND YEAR(payment_date) = $year AND MONTH(payment_date) = $month");
$row = mysqli_fetch_array($sql_payments);
$payment_amount_for_month = floatval($row['payment_amount_for_month']);
$row2 = mysqli_fetch_array($sql_payments);
$payment_amount_for_month = floatval($row2['payment_amount_for_month']);
//Revenues
// Revenues
$sql_revenues = mysqli_query($mysqli, "SELECT SUM(revenue_amount) AS revenue_amount_for_month FROM revenues WHERE revenue_category_id = $category_id AND YEAR(revenue_date) = $year AND MONTH(revenue_date) = $month");
$row = mysqli_fetch_array($sql_revenues);
$revenues_amount_for_month = floatval($row['revenue_amount_for_month']);
$row3 = mysqli_fetch_array($sql_revenues);
$revenues_amount_for_month = floatval($row3['revenue_amount_for_month']);
$payment_amount_for_month = $payment_amount_for_month + $revenues_amount_for_month;
$total_payment_for_all_months = $payment_amount_for_month + $total_payment_for_all_months;
$total_payment_for_all_months += $payment_amount_for_month;
?>
<td class="text-right"><?php echo numfmt_format_currency($currency_format, $payment_amount_for_month, $session_company_currency); ?></td>
<?php
}
?>
<?php } ?>
<td class="text-right text-bold"><?php echo numfmt_format_currency($currency_format, $total_payment_for_all_months, $session_company_currency); ?></td>
</tr>
<?php
}
?>
<?php } ?>
<tr>
<th>Total</th>
<?php
for($month = 1; $month<=12; $month++) {
$grand_total_all_months = 0;
for ($month = 1; $month <= 12; $month++) {
$sql_payments = mysqli_query($mysqli, "SELECT SUM(payment_amount) AS payment_total_amount_for_month FROM payments, invoices WHERE payment_invoice_id = invoice_id AND YEAR(payment_date) = $year AND MONTH(payment_date) = $month");
$row = mysqli_fetch_array($sql_payments);
$payment_total_amount_for_month = floatval($row['payment_total_amount_for_month']);
$row4 = mysqli_fetch_array($sql_payments);
$payment_total_amount_for_month = floatval($row4['payment_total_amount_for_month']);
$sql_revenues = mysqli_query($mysqli, "SELECT SUM(revenue_amount) AS revenue_amount_for_month FROM revenues WHERE revenue_category_id > 0 AND YEAR(revenue_date) = $year AND MONTH(revenue_date) = $month");
$row = mysqli_fetch_array($sql_revenues);
$revenues_total_amount_for_month = floatval($row['revenue_amount_for_month']);
$payment_total_amount_for_month = $payment_total_amount_for_month + $revenues_total_amount_for_month;
$total_payment_for_all_months = $payment_total_amount_for_month + $total_payment_for_all_months;
$row5 = mysqli_fetch_array($sql_revenues);
$revenues_total_amount_for_month = floatval($row5['revenue_amount_for_month']);
$payment_total_amount_for_month += $revenues_total_amount_for_month;
$grand_total_all_months += $payment_total_amount_for_month;
?>
<th class="text-right"><?php echo numfmt_format_currency($currency_format, $payment_total_amount_for_month, $session_company_currency); ?></th>
<?php
}
?>
<th class="text-right"><?php echo numfmt_format_currency($currency_format, $total_payment_for_all_months, $session_company_currency); ?></th>
<?php } ?>
<th class="text-right"><?php echo numfmt_format_currency($currency_format, $grand_total_all_months, $session_company_currency); ?></th>
</tr>
</tbody>
</table>
@@ -150,85 +127,75 @@ $sql_categories = mysqli_query($mysqli, "SELECT * FROM categories WHERE category
<?php require_once "../includes/footer.php"; ?>
<script>
// Set new default font family and font color to mimic Bootstrap's default styling
Chart.defaults.global.defaultFontFamily = '-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif';
Chart.defaults.global.defaultFontColor = '#292b2c';
// Bootstrap-like defaults for Chart.js v4
Chart.defaults.font.family = '-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif';
Chart.defaults.color = '#292b2c';
// Area Chart Example
var ctx = document.getElementById("cashFlow");
var myLineChart = new Chart(ctx, {
type: 'line',
data: {
labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
datasets: [{
label: "Income",
fill: false,
borderColor: "#007bff",
pointBackgroundColor: "#007bff",
pointBorderColor: "#007bff",
pointHoverRadius: 5,
pointHoverBackgroundColor: "#007bff",
pointHitRadius: 50,
pointBorderWidth: 2,
data: [
<?php
// INCOME (Line)
(function () {
var ctx = document.getElementById("cashFlow");
if (!ctx) return;
for ($month = 1; $month<=12; $month++) {
$sql_payments = mysqli_query($mysqli, "SELECT SUM(payment_amount) AS payment_amount_for_month FROM payments, invoices WHERE payment_invoice_id = invoice_id AND YEAR(payment_date) = $year AND MONTH(payment_date) = $month");
$row = mysqli_fetch_array($sql_payments);
$payments_for_month = floatval($row['payment_amount_for_month']);
var myLineChart = new Chart(ctx, {
type: 'line',
data: {
labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
datasets: [{
label: "Income",
fill: false,
borderColor: "#007bff",
pointBackgroundColor: "#007bff",
pointBorderColor: "#007bff",
pointHoverRadius: 5,
pointHoverBackgroundColor: "#007bff",
pointBorderWidth: 2,
data: [
<?php
// Build series and track the largest month for axis max
for ($month = 1; $month <= 12; $month++) {
$sql_payments = mysqli_query($mysqli, "SELECT SUM(payment_amount) AS payment_amount_for_month FROM payments, invoices WHERE payment_invoice_id = invoice_id AND YEAR(payment_date) = $year AND MONTH(payment_date) = $month");
$r1 = mysqli_fetch_array($sql_payments);
$payments_for_month = floatval($r1['payment_amount_for_month']);
$sql_revenues = mysqli_query($mysqli, "SELECT SUM(revenue_amount) AS revenue_amount_for_month FROM revenues WHERE revenue_category_id > 0 AND YEAR(revenue_date) = $year AND MONTH(revenue_date) = $month");
$row = mysqli_fetch_array($sql_revenues);
$revenues_for_month = floatval($row['revenue_amount_for_month']);
$sql_revenues = mysqli_query($mysqli, "SELECT SUM(revenue_amount) AS revenue_amount_for_month FROM revenues WHERE revenue_category_id > 0 AND YEAR(revenue_date) = $year AND MONTH(revenue_date) = $month");
$r2 = mysqli_fetch_array($sql_revenues);
$revenues_for_month = floatval($r2['revenue_amount_for_month']);
$income_for_month = $payments_for_month + $revenues_for_month;
$income_for_month = $payments_for_month + $revenues_for_month;
if ($income_for_month > 0 && $income_for_month > $largest_income_month) {
$largest_income_month = $income_for_month;
}
if ($income_for_month > 0 && $income_for_month > $largest_income_month) {
$largest_income_month = $income_for_month;
}
?>
<?php echo "$income_for_month,"; ?>
<?php
}
?>
],
}],
},
options: {
scales: {
xAxes: [{
time: {
unit: 'date'
},
gridLines: {
display: false
},
ticks: {
maxTicksLimit: 12
}
}],
yAxes: [{
ticks: {
min: 0,
max: <?php $max = max(1000, $largest_income_month, $largest_invoice_month); echo roundUpToNearestMultiple($max); ?>,
maxTicksLimit: 5
},
gridLines: {
color: "rgba(0, 0, 0, .125)",
}
echo "$income_for_month,";
}
?>
],
}],
},
legend: {
display: false
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
x: {
grid: { display: false },
ticks: { maxTicksLimit: 12 }
},
y: {
beginAtZero: true,
min: 0,
max: <?php
$max = max(1000, $largest_income_month);
echo roundUpToNearestMultiple($max);
?>,
ticks: { maxTicksLimit: 5 },
grid: { color: "rgba(0, 0, 0, .125)" }
}
},
plugins: {
legend: { display: false }
}
}
}
});
});
})();
</script>

View File

@@ -14,8 +14,17 @@ $sql_ticket_years = mysqli_query($mysqli, "SELECT DISTINCT YEAR(ticket_created_a
$sql_tickets = mysqli_query($mysqli, "SELECT ticket_id FROM tickets");
// Track largest month for chart y-axis max
$largest_ticket_month = 0;
?>
<!-- Responsive chart helpers -->
<style>
.chart-h-320 { position: relative; height: 320px; }
@media (max-width: 576px) { .chart-h-320 { height: 260px; } }
</style>
<div class="card card-dark">
<div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fas fa-fw fa-life-ring mr-2"></i>Ticket Summary</h3>
@@ -29,12 +38,16 @@ $sql_tickets = mysqli_query($mysqli, "SELECT ticket_id FROM tickets");
<?php
while ($row = mysqli_fetch_array($sql_ticket_years)) {
$ticket_year = intval($row['ticket_year']); ?>
<option <?php if ($year == $ticket_year) { ?> selected <?php } ?> > <?php echo $ticket_year; ?></option>
<option <?php if ($year == $ticket_year) { ?> selected <?php } ?>><?php echo $ticket_year; ?></option>
<?php } ?>
</select>
</form>
<canvas id="tickets" width="100%" height="20"></canvas>
<div class="px-3 pb-3">
<div class="chart-h-320">
<canvas id="tickets"></canvas>
</div>
</div>
<div class="table-responsive-sm">
<table class="table table-striped">
@@ -58,23 +71,22 @@ $sql_tickets = mysqli_query($mysqli, "SELECT ticket_id FROM tickets");
<tbody>
<?php
$total_tickets_for_all_months = 0;
for ($month = 1; $month<=12; $month++) {
for ($month = 1; $month <= 12; $month++) {
$sql_tickets = mysqli_query($mysqli, "SELECT COUNT(ticket_id) AS tickets_for_month FROM tickets WHERE YEAR(ticket_created_at) = $year AND MONTH(ticket_created_at) = $month");
$row = mysqli_fetch_array($sql_tickets);
$tickets_for_month = intval($row['tickets_for_month']);
$total_tickets_for_all_months = $tickets_for_month + $total_tickets_for_all_months;
?>
if ($tickets_for_month > 0 && $tickets_for_month > $largest_ticket_month) {
$largest_ticket_month = $tickets_for_month;
}
$total_tickets_for_all_months += $tickets_for_month; ?>
<td class="text-right"><?php echo $tickets_for_month; ?></td>
<?php } ?>
<td class="text-right"><b><?php echo $total_tickets_for_all_months; ?></b></td>
</tbody>
@@ -83,79 +95,69 @@ $sql_tickets = mysqli_query($mysqli, "SELECT ticket_id FROM tickets");
</div>
</div>
<?php require_once "../includes/footer.php";
?>
<?php require_once "../includes/footer.php"; ?>
<script>
// Set new default font family and font color to mimic Bootstrap's default styling
Chart.defaults.global.defaultFontFamily = '-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif';
Chart.defaults.global.defaultFontColor = '#292b2c';
// Bootstrap-like defaults for Chart.js v4
Chart.defaults.font.family = '-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif';
Chart.defaults.color = '#292b2c';
// Area Chart Example
var ctx = document.getElementById("tickets");
var myLineChart = new Chart(ctx, {
type: 'line',
data: {
labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
datasets: [{
label: "Tickets Raised",
fill: false,
borderColor: "#007bff",
pointBackgroundColor: "#007bff",
pointBorderColor: "#007bff",
pointHoverRadius: 5,
pointHoverBackgroundColor: "#007bff",
pointHitRadius: 50,
pointBorderWidth: 2,
data: [
<?php
(function () {
var ctx = document.getElementById("tickets");
if (!ctx) return;
$largest_ticket_month = 0;
for ($month = 1; $month<=12; $month++) {
$sql_tickets = mysqli_query($mysqli, "SELECT COUNT(ticket_id) AS tickets_for_month FROM tickets WHERE YEAR(ticket_created_at) = $year AND MONTH(ticket_created_at) = $month");
$row = mysqli_fetch_array($sql_tickets);
$tickets_for_month = intval($row['tickets_for_month']);
if ($tickets_for_month > 0 && $tickets_for_month > $largest_ticket_month) {
$largest_ticket_month = $tickets_for_month;
}
echo "$tickets_for_month,";
}
?>
],
}],
},
options: {
scales: {
xAxes: [{
time: {
unit: 'date'
},
gridLines: {
display: false
},
ticks: {
maxTicksLimit: 12
}
}],
yAxes: [{
ticks: {
min: 0,
max: <?php echo $largest_ticket_month ?>,
maxTicksLimit: 5
},
gridLines: {
color: "rgba(0, 0, 0, .125)",
}
}],
},
legend: {
display: false
var dataPoints = [
<?php
// Recompute for the chart dataset (values already gathered above, but we echo directly again)
for ($month = 1; $month <= 12; $month++) {
$sql_tickets = mysqli_query($mysqli, "SELECT COUNT(ticket_id) AS tickets_for_month FROM tickets WHERE YEAR(ticket_created_at) = $year AND MONTH(ticket_created_at) = $month");
$row = mysqli_fetch_array($sql_tickets);
$tickets_for_month = intval($row['tickets_for_month']);
echo "$tickets_for_month,";
}
}
});
?>
];
new Chart(ctx, {
type: 'line',
data: {
labels: ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],
datasets: [{
label: "Tickets Raised",
fill: false,
borderColor: "#007bff",
pointBackgroundColor: "#007bff",
pointBorderColor: "#007bff",
pointHoverRadius: 5,
pointHoverBackgroundColor: "#007bff",
pointBorderWidth: 2,
data: dataPoints
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
x: {
grid: { display: false },
ticks: { maxTicksLimit: 12 }
},
y: {
beginAtZero: true,
min: 0,
max: <?php
// use your helper if available, otherwise largest_ticket_month as-is
$max = max(5, $largest_ticket_month);
echo function_exists('roundUpToNearestMultiple') ? roundUpToNearestMultiple($max) : $max;
?>,
ticks: { maxTicksLimit: 5, precision: 0 },
grid: { color: "rgba(0, 0, 0, .125)" }
}
},
plugins: {
legend: { display: false }
}
}
});
})();
</script>