Moved admin_ to /admin, user_ to user report_ to /reports each have their own post includes modals directories created seperate headers and footer. Also did the same for xcustom, more work to me done

This commit is contained in:
johnnyq
2025-07-28 13:32:28 -04:00
parent 4906e06bf1
commit 0494bfc1cf
178 changed files with 247 additions and 882 deletions

107
reports/budget.php Normal file
View File

@@ -0,0 +1,107 @@
<?php
require_once "includes/inc_all_reports.php";
enforceUserPermission('module_financial');
if (isset($_GET['year'])) {
$year = intval($_GET['year']);
} else {
$year = date('Y');
}
$sql_expense_years = mysqli_query($mysqli, "SELECT DISTINCT YEAR(expense_date) AS expense_year FROM expenses WHERE expense_category_id > 0 ORDER BY expense_year DESC");
$categories = mysqli_query($mysqli, "SELECT * FROM categories WHERE category_type = 'Expense' ORDER BY category_name ASC");
$monthlyTotals = array_fill(1, 12, 0); // Initialize monthly totals for each month
?>
<div class="card card-dark">
<div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fas fa-fw fa-balance-scale mr-2"></i>Annual Budget</h3>
<div class="card-tools">
<button type="button" class="btn btn-primary d-print-none" onclick="window.print();"><i class="fas fa-fw fa-print mr-2"></i>Print</button>
</div>
</div>
<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 } ?>
</select>
</form>
<canvas id="cashFlow" width="100%" height="20"></canvas>
<div class="table-responsive-sm">
<table class="table table-striped">
<thead class="text-dark">
<tr>
<th>Category</th>
<th class="text-right">January</th>
<th class="text-right">February</th>
<th class="text-right">March</th>
<th class="text-right">April</th>
<th class="text-right">May</th>
<th class="text-right">June</th>
<th class="text-right">July</th>
<th class="text-right">August</th>
<th class="text-right">September</th>
<th class="text-right">October</th>
<th class="text-right">November</th>
<th class="text-right">December</th>
<th class="text-right">Total</th>
</tr>
</thead>
<tbody>
<?php
if ($categories->num_rows > 0) {
while($category = $categories->fetch_assoc()) {
echo "<tr>";
echo "<td>" . nullable_htmlentities($category['category_name']) . "</td>";
$categoryTotal = 0;
for ($month = 1; $month <= 12; $month++) {
// Fetch the monthly budget for this category for 2022
$sql = "SELECT budget_amount FROM budget WHERE budget_category_id = " . $category['category_id'] . " AND budget_month = $month AND budget_year = $year";
$result = $mysqli->query($sql);
if ($result->num_rows > 0) {
$budget = $result->fetch_assoc();
$amount = $budget['budget_amount'];
$categoryTotal += $amount;
$monthlyTotals[$month] += $amount;
echo "<td class='text-right'>" . $amount . "</td>";
} else {
echo "<td class='text-right'>0</td>";
}
}
echo "<td class='text-right'>" . $categoryTotal . "</td>";
echo "</tr>";
}
// Displaying the monthly totals row
echo "<tr><td><strong>Total</strong></td>";
$grandTotal = 0;
for ($month = 1; $month <= 12; $month++) {
$grandTotal += $monthlyTotals[$month];
echo "<td class='text-right'>" . $monthlyTotals[$month] . "</td>";
}
echo "<td class='text-right'>" . $grandTotal . "</td>";
echo "</tr>";
}
?>
</tbody>
</table>
</div>
</div>
</div>
<?php require_once "includes/footer.php";
?>

View File

@@ -0,0 +1,85 @@
<?php
require_once "includes/inc_all_reports.php";
enforceUserPermission('module_financial');
?>
<div class="card card-dark">
<div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fas fa-fw fa-exclamation-triangle mr-2"></i>Clients with a Balance</h3>
<div class="card-tools">
<button type="button" class="btn btn-primary d-print-none" onclick="window.print();"><i class="fas fa-fw fa-print mr-2"></i>Print</button>
</div>
</div>
<div class="card-body">
<?php
$sql_clients = mysqli_query($mysqli, "
SELECT
clients.client_id,
clients.client_name,
IFNULL(SUM(invoices.invoice_amount), 0) - IFNULL(SUM(payments.payment_amount), 0) AS balance
FROM
clients
LEFT JOIN
invoices
ON
clients.client_id = invoices.invoice_client_id
AND invoices.invoice_status != 'Draft'
AND invoices.invoice_status != 'Cancelled'
AND invoice_status != 'Non-Billable'
LEFT JOIN
(SELECT
payment_invoice_id,
SUM(payment_amount) as payment_amount
FROM payments
GROUP BY payment_invoice_id) as payments
ON
invoices.invoice_id = payments.payment_invoice_id
GROUP BY
clients.client_id,
clients.client_name
HAVING
balance > 0
ORDER BY
balance DESC
");
?>
<div class="table-responsive-sm">
<table class="table table-striped">
<thead>
<tr>
<th>Client</th>
<th class="text-right">Balance</th>
</tr>
</thead>
<tbody>
<?php
while ($row = mysqli_fetch_array($sql_clients)) {
$client_id = intval($row['client_id']);
$client_name = nullable_htmlentities($row['client_name']);
$balance = floatval($row['balance']);
?>
<tr>
<td><a href="invoices.php?client_id=<?php echo $client_id; ?>"><?php echo $client_name; ?></a></td>
<td class="text-right"><?php echo numfmt_format_currency($currency_format, $balance, $session_company_currency); ?></td>
</tr>
<?php
}
?>
</tbody>
</table>
</div>
</div>
</div>
<?php
require_once "includes/footer.php";

View File

@@ -0,0 +1,75 @@
<?php
require_once "includes/inc_all_reports.php";
enforceUserPermission('module_credential');
// TODO: Default to 90 but allow input field to change this
if (isset($_GET['days'])) {
$days = intval($_GET['days']);
} else {
$days = 90;
}
$passwords_not_rotated_sql = mysqli_query($mysqli,
"SELECT credential_id, credential_name, credential_description, credential_password_changed_at, credential_client_id, client_id, client_name
FROM credentials
LEFT JOIN clients ON credential_client_id = client_id
WHERE DATE(credential_password_changed_at) < DATE_SUB(CURDATE(), INTERVAL $days DAY)
ORDER BY client_name"
);
?>
<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>Client credentials not changed/rotated in the last 90 days</h3>
<div class="card-tools">
<button type="button" class="btn btn-primary d-print-none" onclick="window.print();"><i class="fas fa-fw fa-print mr-2"></i>Print</button>
</div>
</div>
<div class="card-body">
<div class="table-responsive-sm">
<table class="table table-striped">
<thead>
<tr>
<th>Client</th>
<th class="text-right">Credential Name</th>
<th class="text-right">Credential Description</th>
<th class="text-right">Credential Password Last Changed</th>
</tr>
</thead>
<tbody>
<?php
while ($row = mysqli_fetch_array($passwords_not_rotated_sql)) {
$credential_id = intval($row['credential_id']);
$credential_name = nullable_htmlentities($row['credential_name']);
$credential_description = nullable_htmlentities($row['credential_description']);
$credential_password_changed = nullable_htmlentities($row['credential_password_changed_at']);
$client_id = intval($row['client_id']);
$client_name = nullable_htmlentities($row['client_name']);
?>
<tr>
<td><?php echo $client_name; ?></td>
<td class="text-right"><?php echo $credential_name; ?></td>
<td class="text-right"><?php echo $credential_description; ?></td>
<td class="text-right"><?php echo timeAgo($credential_password_changed) . " (" . $credential_password_changed . ")" ?></td>
</tr>
<?php } ?>
</tbody>
</table>
</div>
</div>
</div>
<?php
require_once "includes/footer.php";

View File

@@ -0,0 +1,97 @@
<?php
require_once "includes/inc_all_reports.php";
enforceUserPermission('module_financial');
if (isset($_GET['year'])) {
if ($_GET['year'] === 'all') {
$year = 'all';
} else {
$year = intval($_GET['year']);
}
} else {
$year = date('Y');
}
$sql_payment_years = mysqli_query($mysqli, "SELECT DISTINCT YEAR(payment_date) AS payment_year FROM payments
UNION SELECT DISTINCT YEAR(revenue_date) AS payment_year FROM revenues
ORDER BY payment_year DESC"
);
$year_condition = ($year == 'all') ? "" : "AND YEAR(expense_date) = $year";
$sql_vendor_expenses = mysqli_query($mysqli, "
SELECT
vendors.*,
SUM(expenses.expense_amount) AS amount_paid
FROM
vendors
LEFT JOIN
expenses ON vendors.vendor_id = expenses.expense_vendor_id $year_condition
GROUP BY
vendors.vendor_id
HAVING
amount_paid > 599
ORDER BY
amount_paid DESC
");
?>
<div class="card card-dark">
<div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fas fa-fw fa-building mr-2"></i>Expense By Vendor <small>(With expense amounts of 600 or more)</small></h3>
<div class="card-tools">
<button type="button" class="btn btn-primary d-print-none" onclick="window.print();"><i class="fas fa-fw fa-print mr-2"></i>Print</button>
</div>
</div>
<div class="card-body">
<form class="mb-3">
<select onchange="this.form.submit()" class="form-control" name="year">
<option value="all" <?php if ($year == 'all') { ?> selected <?php } ?> >All Years</option>
<?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>
<div class="table-responsive-sm">
<table class="table table-striped">
<thead>
<tr>
<th>Vendor</th>
<th class="text-right">Paid</th>
</tr>
</thead>
<tbody>
<?php
while ($row = mysqli_fetch_array($sql_vendor_expenses)) {
$vendor_id = intval($row['vendor_id']);
$vendor_name = nullable_htmlentities($row['vendor_name']);
$amount_paid = floatval($row['amount_paid']); ?>
<tr>
<td><?php echo $vendor_name; ?></td>
<td class="text-right"><?php echo numfmt_format_currency($currency_format, $amount_paid, $session_company_currency); ?></td>
</tr>
<?php
}
?>
</tbody>
</table>
</div>
</div>
</div>
<?php require_once "includes/footer.php";
?>

193
reports/expense_summary.php Normal file
View File

@@ -0,0 +1,193 @@
<?php
require_once "includes/inc_all_reports.php";
enforceUserPermission('module_financial');
if (isset($_GET['year'])) {
$year = intval($_GET['year']);
} else {
$year = date('Y');
}
$sql_expense_years = mysqli_query($mysqli, "SELECT DISTINCT YEAR(expense_date) AS expense_year FROM expenses WHERE expense_category_id > 0 ORDER BY expense_year DESC");
$sql_categories = mysqli_query($mysqli, "SELECT * FROM categories WHERE category_type = 'Expense' ORDER BY category_name ASC");
?>
<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>
<div class="card-tools">
<button type="button" class="btn btn-primary d-print-none" onclick="window.print();"><i class="fas fa-fw fa-print mr-2"></i>Print</button>
</div>
</div>
<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 } ?>
</select>
</form>
<canvas id="cashFlow" width="100%" height="20"></canvas>
<div class="table-responsive-sm">
<table class="table table-striped">
<thead class="text-dark">
<tr>
<th>Category</th>
<th class="text-right">January</th>
<th class="text-right">February</th>
<th class="text-right">March</th>
<th class="text-right">April</th>
<th class="text-right">May</th>
<th class="text-right">June</th>
<th class="text-right">July</th>
<th class="text-right">August</th>
<th class="text-right">September</th>
<th class="text-right">October</th>
<th class="text-right">November</th>
<th class="text-right">December</th>
<th class="text-right">Total</th>
</tr>
</thead>
<tbody>
<?php
while ($row = mysqli_fetch_array($sql_categories)) {
$category_id = intval($row['category_id']);
$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++) {
$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;
?>
<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>
</tr>
<?php } ?>
<tr>
<th>Total</th>
<?php
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;
?>
<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>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<?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';
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
$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,";
} ?>
],
}],
},
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
}
}
});
</script>

View File

@@ -0,0 +1,53 @@
<?php
require_once "../includes/inc_confirm_modal.php";
?>
<?php
if (str_contains(basename($_SERVER["PHP_SELF"]), "admin_")) { ?>
<p class="text-right font-weight-light">ITFlow <?php echo APP_VERSION ?> &nbsp; · &nbsp; <a target="_blank" href="https://docs.itflow.org">Docs</a> &nbsp; · &nbsp; <a target="_blank" href="https://forum.itflow.org">Forum</a> &nbsp; · &nbsp; <a target="_blank" href="https://services.itflow.org">Services</a></p>
<br>
<?php } ?>
</div><!-- /.container-fluid -->
</div> <!-- /.content -->
</div> <!-- /.content-wrapper -->
</div> <!-- ./wrapper -->
<!-- Set the browser window title to the clients name -->
<script>document.title = <?php echo json_encode("$tab_title - $page_title"); ?>;</script>
<!-- REQUIRED SCRIPTS -->
<!-- Bootstrap 4 -->
<script src="../plugins/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- Custom js-->
<script src="../plugins/moment/moment.min.js"></script>
<script src="../plugins/chart.js/Chart.min.js"></script>
<script src="../plugins/tempusdominus-bootstrap-4/js/tempusdominus-bootstrap-4.min.js"></script>
<script src='../plugins/daterangepicker/daterangepicker.js'></script>
<script src='../plugins/select2/js/select2.min.js'></script>
<script src='../plugins/inputmask/jquery.inputmask.min.js'></script>
<script src="../plugins/tinymce/tinymce.min.js" referrerpolicy="origin"></script>
<script src="../plugins/Show-Hide-Passwords-Bootstrap-4/bootstrap-show-password.min.js"></script>
<script src="../plugins/clipboardjs/clipboard.min.js"></script>
<script src="../js/keepalive.js"></script>
<script src="../plugins/DataTables/datatables.min.js"></script>
<script src="../plugins/intl-tel-input/js/intlTelInput.min.js"></script>
<!-- AdminLTE App -->
<script src="../plugins/adminlte/js/adminlte.min.js"></script>
<script src="../js/app.js"></script>
<script src="../js/ajax_modal.js"></script>
<script src="../js/confirm_modal.js"></script>
</body>
</html>
<?php
// Calculate Execution time Uncomment for test
//$time_end = microtime(true);
//$execution_time = ($time_end - $time_start);
//echo '<h2>Total Execution Time: '.number_format((float) $execution_time, 10) .' seconds</h2>';

View File

@@ -0,0 +1,54 @@
<?php
// Calculate Execution time start
// uncomment for test
// $time_start = microtime(true);
header("X-Frame-Options: DENY");
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="robots" content="noindex">
<title><?php echo $session_company_name; ?></title>
<!--
Favicon
If Fav Icon exists else use the default one
-->
<?php if(file_exists('../uploads/favicon.ico')) { ?>
<link rel="icon" type="image/x-icon" href="/uploads/favicon.ico">
<?php } ?>
<!-- Font Awesome Icons -->
<link rel="stylesheet" href="../plugins/fontawesome-free/css/all.min.css">
<!-- Custom Style Sheet -->
<link href="../plugins/tempusdominus-bootstrap-4/css/tempusdominus-bootstrap-4.min.css" rel="stylesheet" type="text/css">
<link href="../plugins/select2/css/select2.min.css" rel="stylesheet" type="text/css">
<link href="../plugins/select2-bootstrap4-theme/select2-bootstrap4.min.css" rel="stylesheet" type="text/css">
<link href='../plugins/daterangepicker/daterangepicker.css' rel='stylesheet' />
<link href="../plugins/toastr/toastr.min.css" rel="stylesheet">
<link href="../plugins/DataTables/datatables.min.css" rel="stylesheet">
<link href="../plugins/intl-tel-input/css/intlTelInput.min.css" rel="stylesheet">
<!-- CSS to allow regular button to show as block button in mobile response view using the class btn-responsive -->
<link href="../css/itflow_custom.css" rel="stylesheet">
<!-- Theme style -->
<link rel="stylesheet" href="../plugins/adminlte/css/adminlte.min.css">
<!-- jQuery -->
<script src="../plugins/jquery/jquery.min.js"></script>
<script src="../plugins/toastr/toastr.min.js"></script>
</head>
<body class="
hold-transition sidebar-mini layout-fixed layout-navbar-fixed
accent-<?php if (isset($_GET['client_id'])) { echo "blue"; } else { echo nullable_htmlentities($config_theme); } ?>
<?php if ($config_theme_dark) { echo "dark-mode"; } ?>
">
<div class="wrapper text-sm">

View File

@@ -0,0 +1,19 @@
<?php
require_once "../config.php";
require_once "../functions.php";
require_once "../includes/check_login.php";
require_once "../includes/page_title.php";
// Reporting Perms
enforceUserPermission('module_reporting');
require_once "includes/header.php";
require_once "../includes/top_nav.php";
require_once "includes/side_nav.php";
require_once "../includes/inc_wrapper.php";
require_once "../includes/inc_alert_feedback.php";
require_once "../includes/filter_header.php";
// Set variable default values
$largest_income_month = 0;
$largest_invoice_month = 0;
$recurring_total = 0;

View File

@@ -0,0 +1,9 @@
<script src="js/app.js"></script>
<script src="plugins/Show-Hide-Passwords-Bootstrap-4/bootstrap-show-password.min.js"></script>
<?php
$content = ob_get_clean();
// Return the title and content as a JSON response
echo json_encode(['content' => $content]);
?>

View File

@@ -0,0 +1,13 @@
<?php
require_once "../../../config.php";
require_once "../../../functions.php";
require_once "../../../includes/check_login.php";
header('Content-Type: application/json');
// Check for the 'id' parameter
//if (!isset($_GET['id'])) {
// echo json_encode(['error' => 'ID missing.']);
// exit;
//}

View File

@@ -0,0 +1,127 @@
<!-- Main Sidebar Container -->
<aside class="main-sidebar sidebar-dark-primary d-print-none">
<a class="pb-1 mt-1 brand-link" href="../">
<p class="h5"><i class="nav-icon fas fa-arrow-left ml-3 mr-2"></i>
<span class="brand-text ">Back | <strong>Reports</strong>
</p>
</a>
<!-- Sidebar -->
<div class="sidebar">
<!-- Sidebar Menu -->
<nav>
<ul class="nav nav-pills nav-sidebar flex-column mt-2" data-widget="treeview" data-accordion="false">
<li class="nav-header">FINANCIAL</li>
<?php if ($config_module_enable_accounting == 1 && lookupUserPermission("module_financial") >= 1) { ?>
<li class="nav-item">
<a href="income_summary.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "income_summary.php") { echo "active"; } ?>">
<i class="far fa-circle nav-icon"></i>
<p>Income</p>
</a>
</li>
<li class="nav-item">
<a href="income_by_client.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "income_by_client.php") { echo "active"; } ?>">
<i class="far fa-user nav-icon"></i>
<p>Income By Client</p>
</a>
</li>
<li class="nav-item">
<a href="recurring_by_client.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "recurring_by_client.php") { echo "active"; } ?>">
<i class="fa fa-sync nav-icon"></i>
<p>Recurring Income By Client</p>
</a>
</li>
<li class="nav-item">
<a href="clients_with_balance.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "clients_with_balance.php") { echo "active"; } ?>">
<i class="fa fa-exclamation-triangle nav-icon"></i>
<p>Clients with a Balance</p>
</a>
</li>
<li class="nav-item">
<a href="expense_summary.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "expense_summary.php") { echo "active"; } ?>">
<i class="far fa-credit-card nav-icon"></i>
<p>Expense</p>
</a>
</li>
<li class="nav-item">
<a href="expense_by_vendor.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "expense_by_vendor.php") { echo "active"; } ?>">
<i class="far fa-building nav-icon"></i>
<p>Expense By Vendor</p>
</a>
</li>
<li class="nav-item">
<a href="budget.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "budget.php") { echo "active"; } ?>">
<i class="fas fa-list nav-icon"></i>
<p>Budget</p>
</a>
</li>
<li class="nav-item">
<a href="tax_summary.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "tax_summary.php") { echo "active"; } ?>">
<i class="fas fa-percent nav-icon"></i>
<p>Tax Summary</p>
</a>
</li>
<li class="nav-item">
<a href="profit_loss.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "profit_loss.php") { echo "active"; } ?>">
<i class="fas fa-file-invoice-dollar nav-icon"></i>
<p>Profit & Loss</p>
</a>
</li>
<li class="nav-item">
<a href="tickets_unbilled.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "tickets_unbilled.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-life-ring"></i>
<p>Unbilled Tickets</p>
</a>
</li>
<?php } // End financial reports IF statement ?>
<li class="nav-header">TECHNICAL</li>
<?php if ($config_module_enable_ticketing && lookupUserPermission("module_support") >= 1) { ?>
<li class="nav-item">
<a href="ticket_summary.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "ticket_summary.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-life-ring"></i>
<p>Tickets</p>
</a>
</li>
<li class="nav-item">
<a href="ticket_by_client.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "ticket_by_client.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-life-ring"></i>
<p>Tickets by Client</p>
</a>
</li>
<li class="nav-item">
<a href="time_by_tech.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "time_by_tech.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-life-ring"></i>
<p>Time by Technician</p>
</a>
</li>
<?php } ?>
<?php if (lookupUserPermission("module_credential") >= 1) { ?>
<li class="nav-item">
<a href="credential_rotation.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "credential_rotation.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-key"></i>
<p>Credential rotation</p>
</a>
</li>
<?php } ?>
</ul>
</nav>
<!-- /.sidebar-menu -->
<div class="sidebar-custom mb-3">
</div>
</div>
<!-- /.sidebar -->
</aside>

View File

@@ -0,0 +1,95 @@
<?php
require_once "includes/inc_all_reports.php";
enforceUserPermission('module_financial');
if (isset($_GET['year'])) {
if ($_GET['year'] === 'all') {
$year = 'all';
} else {
$year = intval($_GET['year']);
}
} else {
$year = date('Y');
}
$sql_payment_years = mysqli_query($mysqli, "SELECT DISTINCT YEAR(payment_date) AS payment_year FROM payments
UNION SELECT DISTINCT YEAR(revenue_date) AS payment_year FROM revenues
ORDER BY payment_year DESC"
);
?>
<div class="card card-dark">
<div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fas fa-fw fa-users mr-2"></i>Income By Client <small>(With payments of 600 or more)</small></h3>
<div class="card-tools">
<button type="button" class="btn btn-primary d-print-none" onclick="window.print();"><i class="fas fa-fw fa-print mr-2"></i>Print</button>
</div>
</div>
<div class="card-body">
<form class="mb-3">
<select onchange="this.form.submit()" class="form-control" name="year">
<option value="all" <?php if ($year == 'all') { ?> selected <?php } ?> >All Years</option>
<?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>
<?php
$sql_clients = "SELECT c.client_id, c.client_name, SUM(p.payment_amount) AS amount_paid
FROM clients AS c
JOIN invoices AS i ON c.client_id = i.invoice_client_id
JOIN payments AS p ON i.invoice_id = p.payment_invoice_id";
if ($year != 'all') {
$sql_clients .= " WHERE YEAR(p.payment_date) = $year";
}
$sql_clients .= " GROUP BY c.client_id
HAVING amount_paid > 599
ORDER BY amount_paid DESC";
$sql_clients = mysqli_query($mysqli, $sql_clients);
?>
<div class="table-responsive-sm">
<table class="table table-striped">
<thead>
<tr>
<th>Client</th>
<th class="text-right">Paid</th>
</tr>
</thead>
<tbody>
<?php
while ($row = mysqli_fetch_array($sql_clients)) {
$client_id = intval($row['client_id']);
$client_name = nullable_htmlentities($row['client_name']);
$amount_paid = floatval($row['amount_paid']);
?>
<tr>
<td><a href="client_overview.php?client_id=<?php echo $client_id; ?>"><?php echo $client_name; ?></a></td>
<td class="text-right"><?php echo numfmt_format_currency($currency_format, $amount_paid, $session_company_currency); ?></td>
</tr>
<?php
}
?>
</tbody>
</table>
</div>
</div>
</div>
<?php
require_once "includes/footer.php";

234
reports/income_summary.php Normal file
View File

@@ -0,0 +1,234 @@
<?php
require_once "includes/inc_all_reports.php";
enforceUserPermission('module_financial');
if (isset($_GET['year'])) {
$year = intval($_GET['year']);
} else {
$year = date('Y');
}
$sql_payment_years = mysqli_query($mysqli, "SELECT DISTINCT YEAR(payment_date) AS payment_year FROM payments
UNION SELECT DISTINCT YEAR(revenue_date) AS payment_year FROM revenues
ORDER BY payment_year DESC");
$sql_categories = mysqli_query($mysqli, "SELECT * FROM categories WHERE category_type = 'Income' ORDER BY category_name ASC");
?>
<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>
<div class="card-tools">
<button type="button" class="btn btn-primary d-print-none" onclick="window.print();"><i class="fas fa-fw fa-print mr-2"></i>Print</button>
</div>
</div>
<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
}
?>
</select>
</form>
<canvas id="cashFlow" width="100%" height="20"></canvas>
<div class="table-responsive-sm">
<table class="table table-striped">
<thead>
<tr>
<th>Category</th>
<th class="text-right">January</th>
<th class="text-right">February</th>
<th class="text-right">March</th>
<th class="text-right">April</th>
<th class="text-right">May</th>
<th class="text-right">June</th>
<th class="text-right">July</th>
<th class="text-right">August</th>
<th class="text-right">September</th>
<th class="text-right">October</th>
<th class="text-right">November</th>
<th class="text-right">December</th>
<th class="text-right">Total</th>
</tr>
</thead>
<tbody>
<?php
while ($row = mysqli_fetch_array($sql_categories)) {
$category_id = intval($row['category_id']);
$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
$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']);
//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']);
$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;
?>
<td class="text-right"><?php echo numfmt_format_currency($currency_format, $payment_amount_for_month, $session_company_currency); ?></td>
<?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
}
?>
<tr>
<th>Total</th>
<?php
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']);
$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;
?>
<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>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<?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';
// 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']);
$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']);
$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
}
?>
],
}],
},
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)",
}
}],
},
legend: {
display: false
}
}
});
</script>

20
reports/index.php Normal file
View File

@@ -0,0 +1,20 @@
<?php
require_once "includes/inc_all_reports.php";
?>
<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>Reports</h3>
</div>
<div class="card-body p-0">
<form class="p-3">
<h3>Access different reports using the menu on the left</h3>
<small class="text-muted">In addition to the general reporting permission, you must have read permissions to the reporting area you wish to view (e.g. support/financial).</small>
</div>
</div>
<?php require_once "includes/footer.php"; ?>

437
reports/profit_loss.php Normal file
View File

@@ -0,0 +1,437 @@
<?php
require_once "includes/inc_all_reports.php";
enforceUserPermission('module_financial');
if (isset($_GET['year'])) {
$year = intval($_GET['year']);
} else {
$year = date('Y');
}
//GET unique years from expenses, payments and revenues
$sql_all_years = mysqli_query($mysqli, "SELECT YEAR(expense_date) AS all_years FROM expenses
UNION DISTINCT SELECT YEAR(payment_date) FROM payments
UNION DISTINCT SELECT YEAR(revenue_date) FROM revenues
ORDER BY all_years DESC"
);
$sql_categories_income = mysqli_query($mysqli, "SELECT * FROM categories WHERE category_type = 'Income' ORDER BY category_name ASC");
$sql_categories_expense = mysqli_query($mysqli, "SELECT * FROM categories WHERE category_type = 'Expense' ORDER BY category_name ASC");
?>
<div class="card card-dark">
<div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fas fa-fw fa-balance-scale mr-2"></i>Profit & Loss</h3>
<div class="card-tools">
<button type="button" class="btn btn-primary d-print-none" onclick="window.print();"><i class="fas fa-fw fa-print mr-2"></i>Print</button>
</div>
</div>
<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_all_years)) {
$all_years = intval($row['all_years']);
?>
<option <?php if ($year == $all_years) { ?> selected <?php } ?> > <?php echo $all_years; ?></option>
<?php
}
?>
</select>
</form>
<div class="table-responsive-sm">
<table class="table table-sm">
<thead class="text-dark">
<tr>
<th></th>
<th class="text-right">Jan-Mar</th>
<th class="text-right">Apr-Jun</th>
<th class="text-right">Jul-Sep</th>
<th class="text-right">Oct-Dec</th>
<th class="text-right">Total</th>
</tr>
<tr>
<th><br><br>Income</th>
<th colspan="5"></th>
</tr>
</thead>
<tbody>
<?php
while ($row = mysqli_fetch_array($sql_categories_income)) {
$category_id = intval($row['category_id']);
$category_name = nullable_htmlentities($row['category_name']);
?>
<tr>
<td><?php echo $category_name; ?></td>
<?php
$payment_amount_for_quarter_one = 0;
for($month = 1; $month<=3; $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 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']);
$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);
$revenue_amount_for_month = floatval($row['revenue_amount_for_month']);
$payment_amount_for_month = $payment_amount_for_month + $revenue_amount_for_month;
$payment_amount_for_quarter_one = $payment_amount_for_quarter_one + $payment_amount_for_month;
}
?>
<td class="text-right"><?php echo numfmt_format_currency($currency_format, $payment_amount_for_quarter_one, $session_company_currency); ?></td>
<?php
$payment_amount_for_quarter_two = 0;
for($month = 4; $month<=6; $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 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']);
$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);
$revenue_amount_for_month = floatval($row['revenue_amount_for_month']);
$payment_amount_for_month = $payment_amount_for_month + $revenue_amount_for_month;
$payment_amount_for_quarter_two = $payment_amount_for_quarter_two + $payment_amount_for_month;
}
?>
<td class="text-right"><?php echo numfmt_format_currency($currency_format, $payment_amount_for_quarter_two, $session_company_currency); ?></td>
<?php
$payment_amount_for_quarter_three = 0;
for($month = 7; $month<=9; $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 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']);
$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);
$revenue_amount_for_month = floatval($row['revenue_amount_for_month']);
$payment_amount_for_month = $payment_amount_for_month + $revenue_amount_for_month;
$payment_amount_for_quarter_three = $payment_amount_for_quarter_three + $payment_amount_for_month;
}
?>
<td class="text-right"><?php echo numfmt_format_currency($currency_format, $payment_amount_for_quarter_three, $session_company_currency); ?></td>
<?php
$payment_amount_for_quarter_four = 0;
for($month = 10; $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 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']);
$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);
$revenue_amount_for_month = floatval($row['revenue_amount_for_month']);
$payment_amount_for_month = $payment_amount_for_month + $revenue_amount_for_month;
$payment_amount_for_quarter_four = $payment_amount_for_quarter_four + $payment_amount_for_month;
}
$total_payments_for_all_four_quarters = $payment_amount_for_quarter_one + $payment_amount_for_quarter_two + $payment_amount_for_quarter_three + $payment_amount_for_quarter_four;
?>
<td class="text-right"><?php echo numfmt_format_currency($currency_format, $payment_amount_for_quarter_four, $session_company_currency); ?></td>
<td class="text-right"><?php echo numfmt_format_currency($currency_format, $total_payments_for_all_four_quarters, $session_company_currency); ?></td>
</tr>
<?php
$total_payment_for_all_months = 0;
}
?>
<tr>
<th>Gross Profit</th>
<?php
$payment_total_amount_for_quarter_one = 0;
for($month = 1; $month<=3; $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']);
$sql_revenues = mysqli_query($mysqli, "SELECT SUM(revenue_amount) AS revenue_total_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);
$revenue_total_amount_for_month = floatval($row['revenue_total_amount_for_month']);
$payment_total_amount_for_month = $payment_total_amount_for_month + $revenue_total_amount_for_month;
$payment_total_amount_for_quarter_one = $payment_total_amount_for_quarter_one + $payment_total_amount_for_month;
}
?>
<th class="text-right"><?php echo numfmt_format_currency($currency_format, $payment_total_amount_for_quarter_one, $session_company_currency); ?></th>
<?php
$payment_total_amount_for_quarter_two = 0;
for($month = 4; $month<=6; $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']);
$sql_revenues = mysqli_query($mysqli, "SELECT SUM(revenue_amount) AS revenue_total_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);
$revenue_total_amount_for_month = floatval($row['revenue_total_amount_for_month']);
$payment_total_amount_for_month = $payment_total_amount_for_month + $revenue_total_amount_for_month;
$payment_total_amount_for_quarter_two = $payment_total_amount_for_quarter_two + $payment_total_amount_for_month;
}
?>
<th class="text-right"><?php echo numfmt_format_currency($currency_format, $payment_total_amount_for_quarter_two, $session_company_currency); ?></th>
<?php
$payment_total_amount_for_quarter_three = 0;
for($month = 7; $month<=9; $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']);
$sql_revenues = mysqli_query($mysqli, "SELECT SUM(revenue_amount) AS revenue_total_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);
$revenue_total_amount_for_month = floatval($row['revenue_total_amount_for_month']);
$payment_total_amount_for_month = $payment_total_amount_for_month + $revenue_total_amount_for_month;
$payment_total_amount_for_quarter_three = $payment_total_amount_for_quarter_three + $payment_total_amount_for_month;
}
?>
<th class="text-right"><?php echo numfmt_format_currency($currency_format, $payment_total_amount_for_quarter_three, $session_company_currency); ?></th>
<?php
$payment_total_amount_for_quarter_four = 0;
for($month = 10; $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']);
$sql_revenues = mysqli_query($mysqli, "SELECT SUM(revenue_amount) AS revenue_total_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);
$revenue_total_amount_for_month = floatval($row['revenue_total_amount_for_month']);
$payment_total_amount_for_month = $payment_total_amount_for_month + $revenue_total_amount_for_month;
$payment_total_amount_for_quarter_four = $payment_total_amount_for_quarter_four + $payment_total_amount_for_month;
}
$total_payments_for_all_four_quarters = $payment_total_amount_for_quarter_one + $payment_total_amount_for_quarter_two + $payment_total_amount_for_quarter_three + $payment_total_amount_for_quarter_four;
?>
<th class="text-right"><?php echo numfmt_format_currency($currency_format, $payment_total_amount_for_quarter_four, $session_company_currency); ?></th>
<th class="text-right"><?php echo numfmt_format_currency($currency_format, $total_payments_for_all_four_quarters, $session_company_currency); ?></th>
</tr>
<tr>
<th><br><br>Expenses</th>
<th colspan="5"></th>
</tr>
<?php
while ($row = mysqli_fetch_array($sql_categories_expense)) {
$category_id = intval($row['category_id']);
$category_name = nullable_htmlentities($row['category_name']);
?>
<tr>
<td><?php echo $category_name; ?></td>
<?php
$expense_amount_for_quarter_one = 0;
for($month = 1; $month<=3; $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_quarter_one = $expense_amount_for_quarter_one + floatval($row['expense_amount_for_month']);
}
?>
<td class="text-right"><?php echo numfmt_format_currency($currency_format, $expense_amount_for_quarter_one, $session_company_currency); ?></td>
<?php
$expense_amount_for_quarter_two = 0;
for($month = 4; $month<=6; $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_quarter_two = $expense_amount_for_quarter_two + floatval($row['expense_amount_for_month']);
}
?>
<td class="text-right"><?php echo numfmt_format_currency($currency_format, $expense_amount_for_quarter_two, $session_company_currency); ?></td>
<?php
$expense_amount_for_quarter_three = 0;
for($month = 7; $month<=9; $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_quarter_three = $expense_amount_for_quarter_three + floatval($row['expense_amount_for_month']);
}
?>
<td class="text-right"><?php echo numfmt_format_currency($currency_format, $expense_amount_for_quarter_three, $session_company_currency); ?></td>
<?php
$expense_amount_for_quarter_four = 0;
for($month = 10; $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_quarter_four = $expense_amount_for_quarter_four + floatval($row['expense_amount_for_month']);
}
$total_expenses_for_all_four_quarters = $expense_amount_for_quarter_one + $expense_amount_for_quarter_two + $expense_amount_for_quarter_three + $expense_amount_for_quarter_four;
?>
<td class="text-right"><?php echo numfmt_format_currency($currency_format, $expense_amount_for_quarter_four, $session_company_currency); ?></td>
<td class="text-right"><?php echo numfmt_format_currency($currency_format, $total_expenses_for_all_four_quarters, $session_company_currency); ?></td>
</tr>
<?php
$total_expense_for_all_months = 0;
}
?>
<tr>
<th>Total Expenses<br><br><br></th>
<?php
$expense_total_amount_for_quarter_one = 0;
for($month = 1; $month<=3; $month++) {
$sql_expenses = mysqli_query($mysqli, "SELECT SUM(expense_amount) AS expense_total_amount_for_month FROM expenses WHERE expense_category_id > 0 AND YEAR(expense_date) = $year AND MONTH(expense_date) = $month AND expense_vendor_id > 0");
$row = mysqli_fetch_array($sql_expenses);
$expense_total_amount_for_quarter_one = $expense_total_amount_for_quarter_one + floatval($row['expense_total_amount_for_month']);
}
?>
<th class="text-right"><?php echo numfmt_format_currency($currency_format, $expense_total_amount_for_quarter_one, $session_company_currency); ?></th>
<?php
$expense_total_amount_for_quarter_two = 0;
for($month = 4; $month<=6; $month++) {
$sql_expenses = mysqli_query($mysqli, "SELECT SUM(expense_amount) AS expense_total_amount_for_month FROM expenses WHERE expense_category_id > 0 AND YEAR(expense_date) = $year AND MONTH(expense_date) = $month AND expense_vendor_id > 0");
$row = mysqli_fetch_array($sql_expenses);
$expense_total_amount_for_quarter_two = $expense_total_amount_for_quarter_two + floatval($row['expense_total_amount_for_month']);
}
?>
<th class="text-right"><?php echo numfmt_format_currency($currency_format, $expense_total_amount_for_quarter_two, $session_company_currency); ?></th>
<?php
$expense_total_amount_for_quarter_three = 0;
for($month = 7; $month<=9; $month++) {
$sql_expenses = mysqli_query($mysqli, "SELECT SUM(expense_amount) AS expense_total_amount_for_month FROM expenses WHERE expense_category_id > 0 AND YEAR(expense_date) = $year AND MONTH(expense_date) = $month AND expense_vendor_id > 0");
$row = mysqli_fetch_array($sql_expenses);
$expense_total_amount_for_quarter_three = $expense_total_amount_for_quarter_three + floatval($row['expense_total_amount_for_month']);
}
?>
<th class="text-right"><?php echo numfmt_format_currency($currency_format, $expense_total_amount_for_quarter_three, $session_company_currency); ?></th>
<?php
$expense_total_amount_for_quarter_four = 0;
for($month = 10; $month<=12; $month++) {
$sql_expenses = mysqli_query($mysqli, "SELECT SUM(expense_amount) AS expense_total_amount_for_month FROM expenses WHERE expense_category_id > 0 AND YEAR(expense_date) = $year AND MONTH(expense_date) = $month AND expense_vendor_id > 0");
$row = mysqli_fetch_array($sql_expenses);
$expense_total_amount_for_quarter_four = $expense_total_amount_for_quarter_four + floatval($row['expense_total_amount_for_month']);
}
$total_expenses_for_all_four_quarters = $expense_total_amount_for_quarter_one + $expense_total_amount_for_quarter_two + $expense_total_amount_for_quarter_three + $expense_total_amount_for_quarter_four;
?>
<th class="text-right"><?php echo numfmt_format_currency($currency_format, $expense_total_amount_for_quarter_four, $session_company_currency); ?></th>
<th class="text-right"><?php echo numfmt_format_currency($currency_format, $total_expenses_for_all_four_quarters, $session_company_currency); ?></th>
</tr>
<tr>
<?php
$net_profit_quarter_one = $payment_total_amount_for_quarter_one - $expense_total_amount_for_quarter_one;
$net_profit_quarter_two = $payment_total_amount_for_quarter_two - $expense_total_amount_for_quarter_two;
$net_profit_quarter_three = $payment_total_amount_for_quarter_three - $expense_total_amount_for_quarter_three;
$net_profit_quarter_four = $payment_total_amount_for_quarter_four - $expense_total_amount_for_quarter_four;
$net_profit_year = $total_payments_for_all_four_quarters - $total_expenses_for_all_four_quarters;
?>
<th>Net Profit</th>
<th class="text-right"><?php echo numfmt_format_currency($currency_format, $net_profit_quarter_one, $session_company_currency); ?></th>
<th class="text-right"><?php echo numfmt_format_currency($currency_format, $net_profit_quarter_two, $session_company_currency); ?></th>
<th class="text-right"><?php echo numfmt_format_currency($currency_format, $net_profit_quarter_three, $session_company_currency); ?></th>
<th class="text-right"><?php echo numfmt_format_currency($currency_format, $net_profit_quarter_four, $session_company_currency); ?></th>
<th class="text-right"><?php echo numfmt_format_currency($currency_format, $net_profit_year, $session_company_currency); ?></th>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<?php require_once "includes/footer.php";

View File

@@ -0,0 +1,67 @@
<?php
require_once "includes/inc_all_reports.php";
validateAccountantRole();
$sql = mysqli_query($mysqli, "
SELECT client_id, client_name,
SUM(CASE WHEN recurring_invoice_frequency = 'month' THEN recurring_invoice_amount
WHEN recurring_invoice_frequency = 'year' THEN recurring_invoice_amount / 12 END) AS recurring_monthly_total
FROM clients
LEFT JOIN recurring_invoices ON client_id = recurring_invoice_client_id
WHERE recurring_invoice_status = 1
GROUP BY clients.client_id
HAVING recurring_monthly_total > 0
ORDER BY recurring_monthly_total DESC
");
?>
<div class="card card-dark">
<div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fas fa-fw fa-sync mr-2"></i>Recurring Income By Client</h3>
<div class="card-tools">
<button type="button" class="btn btn-primary d-print-none" onclick="window.print();"><i class="fas fa-fw fa-print mr-2"></i>Print</button>
</div>
</div>
<div class="card-body">
<div class="table-responsive-sm">
<table class="table table-striped table-sm">
<thead>
<tr>
<th>Client</th>
<th class="text-right">Monthly Recurring</th>
</tr>
</thead>
<tbody>
<?php
while ($row = mysqli_fetch_array($sql)) {
$client_id = intval($row['client_id']);
$client_name = nullable_htmlentities($row['client_name']);
$recurring_monthly_total = floatval($row['recurring_monthly_total']);
$recurring_total = $recurring_total + $recurring_monthly_total;
?>
<tr>
<td><a href="client_overview.php?client_id=<?php echo $client_id; ?>"><?php echo $client_name; ?></a></td>
<td class="text-right"><?php echo numfmt_format_currency($currency_format, $recurring_monthly_total, $session_company_currency); ?></td>
</tr>
<?php
}
?>
<tr>
<th>Total Monthly Income</th>
<th class="text-right"><?php echo numfmt_format_currency($currency_format, $recurring_total, $session_company_currency); ?></th>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<?php require_once "includes/footer.php";
?>

121
reports/tax_summary.php Normal file
View File

@@ -0,0 +1,121 @@
<?php
require_once "includes/inc_all_reports.php";
enforceUserPermission('module_financial');
$year = isset($_GET['year']) ? intval($_GET['year']) : date('Y');
$view = isset($_GET['view']) ? $_GET['view'] : 'quarterly';
$currency_row = mysqli_fetch_array(mysqli_query($mysqli,"SELECT company_currency FROM companies WHERE company_id = 1"));
$company_currency = nullable_htmlentities($currency_row['company_currency']);
// GET unique years from expenses, payments and revenues
$sql_all_years = mysqli_query($mysqli, "SELECT DISTINCT(YEAR(item_created_at)) AS all_years FROM invoice_items ORDER BY all_years DESC");
$sql_tax = mysqli_query($mysqli, "SELECT `tax_name` FROM `taxes`");
?>
<div class="card card-dark">
<div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fas fa-fw fa-balance-scale mr-2"></i>Collected Tax Summary</h3>
<div class="card-tools">
<button type="button" class="btn btn-primary d-print-none" onclick="window.print();"><i class="fas fa-fw fa-print mr-2"></i>Print</button>
</div>
</div>
<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_all_years)) {
$all_years = intval($row['all_years']);
?>
<option <?php if ($year == $all_years) { echo "selected"; } ?> > <?php echo $all_years; ?></option>
<?php
}
?>
</select>
<!-- View Selection Dropdown -->
<select onchange="this.form.submit()" class="form-control" name="view">
<option value="monthly" <?php if ($view == 'monthly') echo "selected"; ?>>Monthly</option>
<option value="quarterly" <?php if ($view == 'quarterly') echo "selected"; ?>>Quarterly</option>
</select>
</form>
<div class="table-responsive-sm">
<table class="table table-sm">
<thead class="text-dark">
<tr>
<th>Tax</th>
<?php
if ($view == 'monthly') {
for ($i = 1; $i <= 12; $i++) {
echo "<th class='text-right'>" . date('M', mktime(0, 0, 0, $i, 10)) . "</th>";
}
} else {
echo "<th class='text-right'>Jan-Mar</th>";
echo "<th class='text-right'>Apr-Jun</th>";
echo "<th class='text-right'>Jul-Sep</th>";
echo "<th class='text-right'>Oct-Dec</th>";
}
?>
<th class="text-right">Total</th>
</tr>
</thead>
<tbody>
<?php
while ($row = mysqli_fetch_array($sql_tax)) {
$tax_name = sanitizeInput($row['tax_name']);
echo "<tr>";
echo "<td>" . $row['tax_name'] . "</td>";
if ($view == 'monthly') {
for ($i = 1; $i <= 12; $i++) {
$monthly_tax = getMonthlyTax($tax_name, $i, $year, $mysqli);
echo "<td class='text-right'>" . numfmt_format_currency($currency_format, $monthly_tax, $company_currency) . "</td>";
}
} else {
for ($q = 1; $q <= 4; $q++) {
$quarterly_tax = getQuarterlyTax($tax_name, $q, $year, $mysqli);
echo "<td class='text-right'>" . numfmt_format_currency($currency_format, $quarterly_tax, $company_currency) . "</td>";
}
}
// Calculate total for row and echo bold
$total_tax = getTotalTax($tax_name, $year, $mysqli);
echo "<td class='text-right text-bold'>" . numfmt_format_currency($currency_format, $total_tax, $company_currency) . "</td>";
echo "</tr>";
}
?>
<tr>
<th>Total</th>
<?php
if ($view == 'monthly') {
for ($i = 1; $i <= 12; $i++) {
$monthly_tax = getMonthlyTax($tax_name, $i, $year, $mysqli);
echo "<th class='text-right'>" . numfmt_format_currency($currency_format, $monthly_tax, $company_currency) . "</th>";
}
} else {
for ($q = 1; $q <= 4; $q++) {
$quarterly_tax = getQuarterlyTax($tax_name, $q, $year, $mysqli);
echo "<th class='text-right'>" . numfmt_format_currency($currency_format, $quarterly_tax, $company_currency) . "</th>";
}
}
?>
<td class="text-right"></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<?php require_once "includes/footer.php";

View File

@@ -0,0 +1,300 @@
<?php
require_once "includes/inc_all_reports.php";
enforceUserPermission('module_support');
function secondsToTime($inputSeconds) {
$inputSeconds = floor($inputSeconds);
$secondsInAMinute = 60;
$secondsInAnHour = 60 * $secondsInAMinute;
$secondsInADay = 24 * $secondsInAnHour;
// Extract days
$days = floor($inputSeconds / $secondsInADay);
// Extract hours
$hourSeconds = $inputSeconds % $secondsInADay;
$hours = floor($hourSeconds / $secondsInAnHour);
// Extract minutes
$minuteSeconds = $hourSeconds % $secondsInAnHour;
$minutes = floor($minuteSeconds / $secondsInAMinute);
// Extract the remaining seconds
$remainingSeconds = $minuteSeconds % $secondsInAMinute;
$seconds = ceil($remainingSeconds);
// Format and return
$timeParts = [];
$sections = [
'day' => (int)$days,
'hour' => (int)$hours,
'minute' => (int)$minutes,
'second' => (int)$seconds,
];
foreach ($sections as $name => $value){
if ($value > 0){
$timeParts[] = $value. ' '.$name.($value == 1 ? '' : 's');
}
}
return implode(', ', $timeParts);
}
if (isset($_GET['year'])) {
$year = intval($_GET['year']);
} else {
$year = date('Y');
}
if (isset($_GET['month'])) {
$month = intval($_GET['month']);
} else {
$month = date('m');
}
$sql_ticket_years = mysqli_query($mysqli, "SELECT DISTINCT YEAR(ticket_created_at) AS ticket_year FROM tickets ORDER BY ticket_year DESC");
$sql_clients = mysqli_query($mysqli, "SELECT client_id, client_name FROM clients WHERE client_archived_at IS NULL ORDER BY client_name ASC");
?>
<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>Tickets By Client</h3>
<div class="card-tools">
<button type="button" class="btn btn-primary d-print-none" onclick="window.print();"><i class="fas fa-fw fa-print mr-2"></i>Print</button>
</div>
</div>
<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_ticket_years)) {
$ticket_year = intval($row['ticket_year']); ?>
<option <?php if ($year == $ticket_year) { ?> selected <?php } ?> > <?php echo $ticket_year; ?></option>
<?php } ?>
</select>
<select onchange="this.form.submit()" class="form-control" name="month">
<option <?php if ($month == 1) { echo 'selected'; } ?> value="1">January</option>
<option <?php if ($month == 2) { echo 'selected'; } ?> value="2">February</option>
<option <?php if ($month == 3) { echo 'selected'; } ?> value="3">March</option>
<option <?php if ($month == 4) { echo 'selected'; } ?> value="4">April</option>
<option <?php if ($month == 5) { echo 'selected'; } ?> value="5">May</option>
<option <?php if ($month == 6) { echo 'selected'; } ?> value="6">June</option>
<option <?php if ($month == 7) { echo 'selected'; } ?> value="7">July</option>
<option <?php if ($month == 8) { echo 'selected'; } ?> value="8">August</option>
<option <?php if ($month == 9) { echo 'selected'; } ?> value="9">September</option>
<option <?php if ($month == 10) { echo 'selected'; } ?> value="10">October</option>
<option <?php if ($month == 11) { echo 'selected'; } ?> value="11">November</option>
<option <?php if ($month == 12) { echo 'selected'; } ?> value="12">December</option>
</select>
</form>
<div class="card card-dark mb-3">
<div class="card-header">
<h3 class="card-title"><i class="fas fa-fw fa-chart-area mr-2"></i>Yearly (<?php echo $year; ?>)</h3>
</div>
<div class="card-body">
<div class="table-responsive-sm">
<table class="table table-striped">
<thead>
<tr>
<th>Client</th>
<th class="text-right">Tickets raised</th>
<th class="text-right">By priority: Low</th>
<th class="text-right">By priority: Med</th>
<th class="text-right">By priority: High</th>
<th class="text-right">Tickets resolved</th>
<th class="text-right">Total Time worked <i>(H:M:S)</i></th>
<th class="text-right">Avg time to resolve</th>
</tr>
</thead>
<tbody>
<?php
while ($row = mysqli_fetch_array($sql_clients)) {
$client_id = intval($row['client_id']);
$client_name = nullable_htmlentities($row['client_name']);
// Calculate total tickets raised in period
$sql_ticket_raised_count = mysqli_query($mysqli, "SELECT COUNT(ticket_id) AS ticket_raised_count FROM tickets WHERE YEAR(ticket_created_at) = $year AND ticket_client_id = $client_id");
$row = mysqli_fetch_array($sql_ticket_raised_count);
$ticket_raised_count = intval($row['ticket_raised_count']);
// Calculate total tickets raised in period that are resolved
$sql_ticket_resolved_count = mysqli_query($mysqli, "SELECT COUNT(ticket_id) AS ticket_resolved_count FROM tickets WHERE YEAR(ticket_created_at) = $year AND ticket_client_id = $client_id AND ticket_resolved_at IS NOT NULL");
$row = mysqli_fetch_array($sql_ticket_resolved_count);
$ticket_resolved_count = intval($row['ticket_resolved_count']);
// Breakdown tickets for each priority - Low
$sql_low_ticket_count = mysqli_query($mysqli, "SELECT COUNT(ticket_id) AS low_ticket_count FROM tickets WHERE YEAR(ticket_created_at) = $year AND ticket_client_id = $client_id AND ticket_priority = 'Low'");
$row = mysqli_fetch_array($sql_low_ticket_count);
$low_ticket_count = intval($row['low_ticket_count']);
// Breakdown tickets for each priority - Low
$sql_med_ticket_count = mysqli_query($mysqli, "SELECT COUNT(ticket_id) AS med_ticket_count FROM tickets WHERE YEAR(ticket_created_at) = $year AND ticket_client_id = $client_id AND ticket_priority = 'Medium'");
$row = mysqli_fetch_array($sql_med_ticket_count);
$med_ticket_count = intval($row['med_ticket_count']);
// Breakdown tickets for each priority - Low
$sql_high_ticket_count = mysqli_query($mysqli, "SELECT COUNT(ticket_id) AS high_ticket_count FROM tickets WHERE YEAR(ticket_created_at) = $year AND ticket_client_id = $client_id AND ticket_priority = 'High'");
$row = mysqli_fetch_array($sql_high_ticket_count);
$high_ticket_count = intval($row['high_ticket_count']);
// Used to calculate average time to resolve tickets that were raised in period specified
$sql_tickets = mysqli_query($mysqli, "SELECT ticket_created_at, ticket_resolved_at FROM tickets WHERE YEAR(ticket_created_at) = $year AND ticket_client_id = $client_id AND ticket_resolved_at IS NOT NULL");
// Calculate total time tracked towards tickets in the period
$sql_time = mysqli_query($mysqli, "SELECT SEC_TO_TIME(SUM(TIME_TO_SEC(ticket_reply_time_worked))) as total_time FROM ticket_replies LEFT JOIN tickets ON tickets.ticket_id = ticket_replies.ticket_reply_ticket_id WHERE YEAR(ticket_created_at) = $year AND ticket_client_id = $client_id AND ticket_reply_time_worked IS NOT NULL");
$row = mysqli_fetch_array($sql_time);
$ticket_total_time_worked = nullable_htmlentities($row['total_time']);
if ($ticket_raised_count > 0 || $ticket_resolved_count > 0) {
$avg_time_to_resolve = '-';
if ($ticket_resolved_count > 0) {
// Calculate average time to solve
$count = 0;
$total = 0;
while ($row = mysqli_fetch_array($sql_tickets)) {
$openedTime = new DateTime($row['ticket_created_at']);
$resolvedTime = new DateTime($row['ticket_resolved_at']);
$total += ($resolvedTime->getTimestamp() - $openedTime->getTimestamp());
$count++;
}
$avg_time_to_resolve = secondsToTime($total / $count);
}
?>
<tr>
<td><?php echo $client_name; ?></td>
<td class="text-right"><?php echo $ticket_raised_count; ?></td>
<td class="text-right"><?php echo $low_ticket_count; ?></td>
<td class="text-right"><?php echo $med_ticket_count; ?></td>
<td class="text-right"><?php echo $high_ticket_count; ?></td>
<td class="text-right"><?php echo $ticket_resolved_count; ?></td>
<td class="text-right"><?php echo $ticket_total_time_worked; ?></td>
<td class="text-right"><?php echo $avg_time_to_resolve; ?></td>
</tr>
<?php
}
}
?>
</tbody>
</table>
</div>
</div>
</div>
<div class="card card-dark mb-3">
<div class="card-header">
<h3 class="card-title"><i class="fas fa-fw fa-chart-area mr-2"></i>Monthly (<?php echo date("F", mktime(1, 1, 1, $month, 1)) . ' ' . $year; ?>)</h3>
</div>
<div class="card-body">
<div class="table-responsive-sm">
<table class="table table-striped">
<thead>
<tr>
<th>Client</th>
<th class="text-right">Tickets raised</th>
<th class="text-right">By priority: Low</th>
<th class="text-right">By priority: Med</th>
<th class="text-right">By priority: High</th>
<th class="text-right">Tickets resolved</th>
<th class="text-right">Total Time worked <i>(H:M:S)</i></th>
<th class="text-right">Avg time to resolve</th>
</tr>
</thead>
<tbody>
<?php
mysqli_data_seek($sql_clients, 0); // Reset
while ($row = mysqli_fetch_array($sql_clients)) {
$client_id = intval($row['client_id']);
$client_name = nullable_htmlentities($row['client_name']);
// Calculate total tickets raised in period
$sql_ticket_raised_count = mysqli_query($mysqli, "SELECT COUNT(ticket_id) AS ticket_raised_count FROM tickets WHERE YEAR(ticket_created_at) = $year AND MONTH(ticket_created_at) = $month AND ticket_client_id = $client_id");
$row = mysqli_fetch_array($sql_ticket_raised_count);
$ticket_raised_count = intval($row['ticket_raised_count']);
// Calculate total tickets raised in period that are resolved
$sql_ticket_resolved_count = mysqli_query($mysqli, "SELECT COUNT(ticket_id) AS ticket_resolved_count FROM tickets WHERE YEAR(ticket_created_at) = $year AND MONTH(ticket_created_at) = $month AND ticket_client_id = $client_id AND ticket_resolved_at IS NOT NULL");
$row = mysqli_fetch_array($sql_ticket_resolved_count);
$ticket_resolved_count = intval($row['ticket_resolved_count']);
// Breakdown tickets for each priority - Low
$sql_low_ticket_count = mysqli_query($mysqli, "SELECT COUNT(ticket_id) AS low_ticket_count FROM tickets WHERE YEAR(ticket_created_at) = $year AND MONTH(ticket_created_at) = $month AND ticket_client_id = $client_id AND ticket_priority = 'Low'");
$row = mysqli_fetch_array($sql_low_ticket_count);
$low_ticket_count = intval($row['low_ticket_count']);
// Breakdown tickets for each priority - Low
$sql_med_ticket_count = mysqli_query($mysqli, "SELECT COUNT(ticket_id) AS med_ticket_count FROM tickets WHERE YEAR(ticket_created_at) = $year AND MONTH(ticket_created_at) = $month AND ticket_client_id = $client_id AND ticket_priority = 'Medium'");
$row = mysqli_fetch_array($sql_med_ticket_count);
$med_ticket_count = intval($row['med_ticket_count']);
// Breakdown tickets for each priority - Low
$sql_high_ticket_count = mysqli_query($mysqli, "SELECT COUNT(ticket_id) AS high_ticket_count FROM tickets WHERE YEAR(ticket_created_at) = $year AND MONTH(ticket_created_at) = $month AND ticket_client_id = $client_id AND ticket_priority = 'High'");
$row = mysqli_fetch_array($sql_high_ticket_count);
$high_ticket_count = intval($row['high_ticket_count']);
// Used to calculate average time to resolve tickets that were raised in period specified
$sql_tickets = mysqli_query($mysqli, "SELECT ticket_created_at, ticket_resolved_at FROM tickets WHERE YEAR(ticket_created_at) = $year AND MONTH(ticket_created_at) = $month AND ticket_client_id = $client_id AND ticket_resolved_at IS NOT NULL");
// Calculate total time tracked towards tickets in the period
$sql_time = mysqli_query($mysqli, "SELECT SEC_TO_TIME(SUM(TIME_TO_SEC(ticket_reply_time_worked))) as total_time FROM ticket_replies LEFT JOIN tickets ON tickets.ticket_id = ticket_replies.ticket_reply_ticket_id WHERE YEAR(ticket_created_at) = $year AND MONTH(ticket_created_at) = $month AND ticket_client_id = $client_id AND ticket_reply_time_worked IS NOT NULL");
$row = mysqli_fetch_array($sql_time);
$ticket_total_time_worked = nullable_htmlentities($row['total_time']);
if ($ticket_raised_count > 0 || $ticket_resolved_count > 0) {
$avg_time_to_resolve = '-';
if ($ticket_resolved_count > 0) {
// Calculate average time to solve
$count = 0;
$total = 0;
while ($row = mysqli_fetch_array($sql_tickets)) {
$openedTime = new DateTime($row['ticket_created_at']);
$resolvedTime = new DateTime($row['ticket_resolved_at']);
$total += ($resolvedTime->getTimestamp() - $openedTime->getTimestamp());
$count++;
}
$avg_time_to_resolve = secondsToTime($total / $count);
}
?>
<tr>
<td><?php echo $client_name; ?></td>
<td class="text-right"><?php echo $ticket_raised_count; ?></td>
<td class="text-right"><?php echo $low_ticket_count; ?></td>
<td class="text-right"><?php echo $med_ticket_count; ?></td>
<td class="text-right"><?php echo $high_ticket_count; ?></td>
<td class="text-right"><?php echo $ticket_resolved_count; ?></td>
<td class="text-right"><?php echo $ticket_total_time_worked; ?></td>
<td class="text-right"><?php echo $avg_time_to_resolve; ?></td>
</tr>
<?php
}
}
?>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<?php
require_once "includes/footer.php";

161
reports/ticket_summary.php Normal file
View File

@@ -0,0 +1,161 @@
<?php
require_once "includes/inc_all_reports.php";
enforceUserPermission('module_support');
if (isset($_GET['year'])) {
$year = intval($_GET['year']);
} else {
$year = date('Y');
}
$sql_ticket_years = mysqli_query($mysqli, "SELECT DISTINCT YEAR(ticket_created_at) AS ticket_year FROM tickets ORDER BY ticket_year DESC");
$sql_tickets = mysqli_query($mysqli, "SELECT ticket_id FROM tickets");
?>
<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>
<div class="card-tools">
<button type="button" class="btn btn-primary d-print-none" onclick="window.print();"><i class="fas fa-fw fa-print mr-2"></i>Print</button>
</div>
</div>
<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_ticket_years)) {
$ticket_year = intval($row['ticket_year']); ?>
<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="table-responsive-sm">
<table class="table table-striped">
<thead>
<tr>
<th class="text-right">January</th>
<th class="text-right">February</th>
<th class="text-right">March</th>
<th class="text-right">April</th>
<th class="text-right">May</th>
<th class="text-right">June</th>
<th class="text-right">July</th>
<th class="text-right">August</th>
<th class="text-right">September</th>
<th class="text-right">October</th>
<th class="text-right">November</th>
<th class="text-right">December</th>
<th class="text-right">Total</th>
</tr>
</thead>
<tbody>
<?php
$total_tickets_for_all_months = 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']);
$total_tickets_for_all_months = $tickets_for_month + $total_tickets_for_all_months;
?>
<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>
</table>
</div>
</div>
</div>
<?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';
// 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
$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
}
}
});
</script>

View File

@@ -0,0 +1,182 @@
<?php
require_once "includes/inc_all_reports.php";
enforceUserPermission('module_sales', 1);
function secondsToTime($inputSeconds) {
$secondsInAMinute = 60;
$secondsInAnHour = 60 * $secondsInAMinute;
$secondsInADay = 24 * $secondsInAnHour;
// Extract days
$days = floor($inputSeconds / $secondsInADay);
// Extract hours
$hourSeconds = $inputSeconds % $secondsInADay;
$hours = floor($hourSeconds / $secondsInAnHour);
// Extract minutes
$minuteSeconds = $hourSeconds % $secondsInAnHour;
$minutes = floor($minuteSeconds / $secondsInAMinute);
// Extract the remaining seconds
$remainingSeconds = $minuteSeconds % $secondsInAMinute;
$seconds = ceil($remainingSeconds);
// Format and return
$timeParts = [];
$sections = [
'day' => (int)$days,
'hour' => (int)$hours,
'minute' => (int)$minutes,
'second' => (int)$seconds,
];
foreach ($sections as $name => $value){
if ($value > 0){
$timeParts[] = $value. ' '.$name.($value == 1 ? '' : 's');
}
}
return implode(', ', $timeParts);
}
if (isset($_GET['year'])) {
$year = intval($_GET['year']);
} else {
$year = date('Y');
}
$sql_ticket_years = mysqli_query($mysqli, "SELECT DISTINCT YEAR(ticket_created_at) AS ticket_year FROM tickets ORDER BY ticket_year DESC");
$sql_clients = mysqli_query($mysqli, "SELECT client_id, client_name FROM clients ORDER BY client_name ASC");
$rows = 0;
?>
<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>Unbilled Tickets By Client</h3>
<div class="card-tools">
<button type="button" class="btn btn-primary d-print-none" onclick="window.print();"><i class="fas fa-fw fa-print mr-2"></i>Print</button>
</div>
</div>
<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_ticket_years)) {
$ticket_year = intval($row['ticket_year']); ?>
<option <?php if ($year == $ticket_year) { ?> selected <?php } ?> > <?php echo $ticket_year; ?></option>
<?php } ?>
</select>
</form>
<div class="table-responsive-sm">
<table class="table table-striped">
<thead>
<tr>
<th>Client</th>
<th class="text-right">Tickets Raised</th>
<th class="text-right">Billable Tickets</th>
<th class="text-right">Unbilled Tickets</th>
</tr>
</thead>
<tbody>
<?php
while ($row = mysqli_fetch_array($sql_clients)) {
$client_id = intval($row['client_id']);
$client_name = nullable_htmlentities($row['client_name']);
// Calculate total tickets raised in period
$sql_ticket_raised_count = mysqli_query(
$mysqli,
"SELECT
COUNT(ticket_id) AS ticket_raised_count
FROM
tickets
WHERE
YEAR(ticket_created_at) = $year
AND
ticket_client_id = $client_id"
);
$row = mysqli_fetch_array($sql_ticket_raised_count);
$ticket_raised_count = intval($row['ticket_raised_count']);
// Calculate total tickets raised in period that are closed and billable
$sql_ticket_closed_count = mysqli_query(
$mysqli,
"SELECT
COUNT(ticket_id) AS ticket_closed_count
FROM
tickets
WHERE
YEAR(ticket_created_at) = $year
AND
ticket_client_id = $client_id
AND
ticket_closed_at IS NOT NULL
AND
ticket_billable = 1
");
$row = mysqli_fetch_array($sql_ticket_closed_count);
$ticket_closed_count = intval($row['ticket_closed_count']);
// Calculate total tickets raised in period that are closed and billable, but not invoiced
$sql_ticket_unbilled_count = mysqli_query(
$mysqli,
"SELECT
COUNT(ticket_id) AS ticket_unbilled_count
FROM
tickets
WHERE
YEAR(ticket_created_at) = $year
AND
ticket_client_id = $client_id
AND
ticket_closed_at IS NOT NULL
AND
ticket_billable = 1
AND
ticket_invoice_id = 0");
$row = mysqli_fetch_array($sql_ticket_unbilled_count);
$ticket_unbilled_count = intval($row['ticket_unbilled_count']);
if ($ticket_unbilled_count > 0) {
$rows = $rows + 1;
?>
<tr>
<td>
<a href="tickets.php?client_id=<?php echo $client_id; ?>&billable=1&unbilled"><?php echo $client_name; ?></a>
</td>
<td class="text-right"><?php echo $ticket_raised_count; ?></td>
<td class="text-right"><?php echo $ticket_closed_count; ?></td>
<td class="text-right"><?php echo $ticket_unbilled_count; ?></td>
</tr>
<?php
}
}
if ($rows == 0) {
?>
<tr>
<td colspan="4">You are all caught up! There are no unbilled tickets for this year.
</td>
</tr>
<?php
}
?>
</tbody>
</table>
</div>
</div>
</div>
<?php
require_once "includes/footer.php";

181
reports/time_by_tech.php Normal file
View File

@@ -0,0 +1,181 @@
<?php
require_once "includes/inc_all_reports.php";
enforceUserPermission('module_support');
function secondsToTime($inputSeconds) {
$inputSeconds = floor($inputSeconds);
$secondsInAMinute = 60;
$secondsInAnHour = 60 * $secondsInAMinute;
$secondsInADay = 24 * $secondsInAnHour;
// Extract days
$days = floor($inputSeconds / $secondsInADay);
// Extract hours
$hourSeconds = $inputSeconds % $secondsInADay;
$hours = floor($hourSeconds / $secondsInAnHour);
// Extract minutes
$minuteSeconds = $hourSeconds % $secondsInAnHour;
$minutes = floor($minuteSeconds / $secondsInAMinute);
// Extract the remaining seconds
$remainingSeconds = $minuteSeconds % $secondsInAMinute;
$seconds = ceil($remainingSeconds);
// Format and return
$timeParts = [];
$sections = [
'day' => (int)$days,
'hour' => (int)$hours,
'minute' => (int)$minutes,
'second' => (int)$seconds,
];
foreach ($sections as $name => $value){
if ($value > 0){
$timeParts[] = $value. ' '.$name.($value == 1 ? '' : 's');
}
}
return implode(', ', $timeParts);
}
if (isset($_GET['year'])) {
$year = intval($_GET['year']);
} else {
$year = date('Y');
}
if (isset($_GET['month'])) {
$month = intval($_GET['month']);
} else {
$month = date('m');
}
$sql_ticket_years = mysqli_query($mysqli, "SELECT DISTINCT YEAR(ticket_created_at) AS ticket_year FROM tickets ORDER BY ticket_year DESC");
$sql_clients = mysqli_query($mysqli, "SELECT client_id, client_name FROM clients WHERE client_archived_at IS NULL ORDER BY client_name ASC");
$sql_users = mysqli_query($mysqli, "
SELECT users.user_id, user_name FROM users
LEFT JOIN user_settings on users.user_id = user_settings.user_id
WHERE user_type = 1
AND user_status = 1
AND user_archived_at IS NULL
ORDER BY user_name DESC"
);
// TODO: Maybe try and filter this to just users with the support module perm
?>
<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>Time Logged By Technician</h3>
<div class="card-tools">
<button type="button" class="btn btn-primary d-print-none" onclick="window.print();"><i class="fas fa-fw fa-print mr-2"></i>Print</button>
</div>
</div>
<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_ticket_years)) {
$ticket_year = intval($row['ticket_year']); ?>
<option <?php if ($year == $ticket_year) { ?> selected <?php } ?> > <?php echo $ticket_year; ?></option>
<?php } ?>
</select>
</form>
<div class="card card-dark mb-3">
<div class="card-header">
<h3 class="card-title"><i class="fas fa-fw fa-chart-area mr-2"></i>Yearly (<?php echo $year; ?>)</h3>
</div>
<div class="card-body">
<div class="table-responsive-sm">
<table class="table table-striped">
<thead>
<tr>
<th>Technician</th>
<th class="text-right">Tickets assigned</th>
<th class="text-right">Tickets touched</th>
<th class="text-right">Total time worked <i>(H:M:S)</i></th>
</tr>
</thead>
<tbody>
<?php
while ($agent_row = mysqli_fetch_array($sql_users)) {
$user_id = intval($agent_row['user_id']);
$user_name = nullable_htmlentities($agent_row['user_name']);
// Get tickets in period that are still assigned to the technician/agent
$sql_ticket_count = mysqli_query($mysqli, "SELECT COUNT(ticket_id) AS ticket_count FROM tickets WHERE YEAR(ticket_created_at) = $year AND ticket_assigned_to = $user_id");
$row = mysqli_fetch_array($sql_ticket_count);
$ticket_raised_count = intval($row['ticket_count']);
// Get unique tickets in period that the agent replied to/touched
$sql_tickets_touched = mysqli_query($mysqli, "
SELECT COUNT(DISTINCT ticket_id) AS tickets_touched
FROM (
-- Tickets the agent replied to
SELECT ticket_reply_ticket_id AS ticket_id
FROM ticket_replies
WHERE YEAR(ticket_reply_created_at) = $year AND ticket_reply_by = $user_id
UNION
-- Tickets the agent opened
SELECT ticket_id
FROM tickets
WHERE YEAR(ticket_created_at) = $year AND ticket_created_by = $user_id
UNION
-- Tickets the agent closed
SELECT ticket_id
FROM tickets
WHERE YEAR(ticket_created_at) = $year AND ticket_closed_by = $user_id
)
AS tickets_touched
");
$row = mysqli_fetch_array($sql_tickets_touched);
$tickets_touched = intval($row['tickets_touched']);
// Calculate total time tracked towards tickets in the period (for this agent)
$sql_time = mysqli_query($mysqli, "SELECT SEC_TO_TIME(SUM(TIME_TO_SEC(ticket_reply_time_worked))) as total_time FROM ticket_replies LEFT JOIN tickets ON tickets.ticket_id = ticket_replies.ticket_reply_ticket_id WHERE YEAR(ticket_created_at) = $year AND ticket_reply_by = $user_id AND ticket_reply_time_worked IS NOT NULL");
$row = mysqli_fetch_array($sql_time);
$ticket_total_time_worked = nullable_htmlentities($row['total_time']);
?>
<tr>
<td><?php echo $user_name; ?></td>
<td class="text-right"><?php echo $ticket_raised_count; ?></td>
<td class="text-right"><?php echo $tickets_touched; ?></td>
<td class="text-right"><?php echo $ticket_total_time_worked; ?></td>
</tr>
<?php
}
?>
</tbody>
</table>
</div>
</div>
</div>
<!-- TODO: Monthly version of this report -->
</div>
</div>
<?php
require_once "includes/footer.php";