mirror of
https://github.com/itflow-org/itflow
synced 2026-07-23 00:40:45 +00:00
Feature: Add Transactions, reorg Main side nav
This commit is contained in:
@@ -30,8 +30,29 @@
|
||||
</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="/agent/contacts.php" class="nav-link">
|
||||
<i class="fas fa-layer-group nav-icon"></i>
|
||||
<p>All Client Docs</p>
|
||||
<i class="fas fa-angle-right nav-icon float-right"></i>
|
||||
</a>
|
||||
</li>
|
||||
<?php } ?>
|
||||
|
||||
<li class="nav-item">
|
||||
<a href="/agent/vendors.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "vendors.php") { echo "active"; } ?>">
|
||||
<i class="nav-icon fas fa-building"></i>
|
||||
<p>Vendors</p>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<a href="/agent/calendar.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "calendar.php") { echo "active"; } ?>">
|
||||
<i class="nav-icon fas fa-calendar-alt"></i>
|
||||
<p>Calendar</p>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<?php if (lookupUserPermission("module_support") >= 1) { ?>
|
||||
<?php if ($config_module_enable_ticketing == 1) { ?>
|
||||
<li class="nav-header mt-3">SUPPORT</li>
|
||||
@@ -71,12 +92,6 @@
|
||||
<?php } ?>
|
||||
<?php } ?>
|
||||
|
||||
<li class="nav-item">
|
||||
<a href="/agent/calendar.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "calendar.php") { echo "active"; } ?>">
|
||||
<i class="nav-icon fas fa-calendar-alt"></i>
|
||||
<p>Calendar</p>
|
||||
</a>
|
||||
</li>
|
||||
<?php if ($config_module_enable_accounting == 1 && lookupUserPermission("module_sales") >= 1) { ?>
|
||||
<li class="nav-header mt-3">BILLING</li>
|
||||
<li class="nav-item">
|
||||
@@ -112,12 +127,6 @@
|
||||
</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="/agent/revenues.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "revenues.php") { echo "active"; } ?>">
|
||||
<i class="nav-icon fas fa-hand-holding-usd"></i>
|
||||
<p>Revenues</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="/agent/products.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "products.php") { echo "active"; } ?>">
|
||||
<i class="nav-icon fas fa-box-open"></i>
|
||||
@@ -136,9 +145,9 @@
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="/agent/vendors.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "vendors.php") { echo "active"; } ?>">
|
||||
<i class="nav-icon fas fa-building"></i>
|
||||
<p>Vendors</p>
|
||||
<a href="/agent/revenues.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "revenues.php") { echo "active"; } ?>">
|
||||
<i class="nav-icon fas fa-hand-holding-usd"></i>
|
||||
<p>Revenues</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
@@ -158,12 +167,24 @@
|
||||
</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="/agent/trips.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "trips.php") { echo "active"; } ?>">
|
||||
<i class="nav-icon fas fa-route"></i>
|
||||
<p>Trips</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="/agent/accounts.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "accounts.php") { echo "active"; } ?>">
|
||||
<i class="nav-icon fas fa-piggy-bank"></i>
|
||||
<p>Accounts</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="/agent/transactions.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "transactions.php") { echo "active"; } ?>">
|
||||
<i class="nav-icon fas fa-list-alt"></i>
|
||||
<p>Transactions</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="/agent/transfers.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "transfers.php") { echo "active"; } ?>">
|
||||
<i class="nav-icon fas fa-exchange-alt"></i>
|
||||
@@ -171,26 +192,11 @@
|
||||
</a>
|
||||
</li>
|
||||
<?php } ?>
|
||||
<li class="nav-item">
|
||||
<a href="/agent/trips.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "trips.php") { echo "active"; } ?>">
|
||||
<i class="nav-icon fas fa-route"></i>
|
||||
<p>Trips</p>
|
||||
</a>
|
||||
</li>
|
||||
<?php } ?>
|
||||
|
||||
<?php if (lookupUserPermission("module_client") >= 1) { ?>
|
||||
<li class="nav-item mt-3">
|
||||
<a href="/agent/contacts.php" class="nav-link">
|
||||
<i class="fas fa-users nav-icon"></i>
|
||||
<p>Client Overview</p>
|
||||
<i class="fas fa-angle-right nav-icon float-right"></i>
|
||||
</a>
|
||||
</li>
|
||||
<?php } ?>
|
||||
|
||||
<?php if (lookupUserPermission("module_reporting") >= 1) { ?>
|
||||
<li class="nav-item mt-3">
|
||||
<li class="nav-header mt-3">TOOLS</li>
|
||||
<li class="nav-item">
|
||||
<a href="/agent/reports/" class="nav-link">
|
||||
<i class="fas fa-chart-line nav-icon"></i>
|
||||
<p>Reports</p>
|
||||
|
||||
250
agent/modals/transaction/transaction_export.php
Normal file
250
agent/modals/transaction/transaction_export.php
Normal file
@@ -0,0 +1,250 @@
|
||||
<?php
|
||||
|
||||
require_once '../../../includes/modal_header.php';
|
||||
|
||||
// Pre-fill from the transactions page's current filters
|
||||
|
||||
// Account Filter
|
||||
if (isset($_GET['account']) & !empty($_GET['account'])) {
|
||||
$account_filter = intval($_GET['account']);
|
||||
} else {
|
||||
$account_filter = '';
|
||||
}
|
||||
|
||||
// Type Filter
|
||||
$transaction_types_array = ['Revenue', 'Payment', 'Expense', 'Transfer In', 'Transfer Out'];
|
||||
if (isset($_GET['type']) & !empty($_GET['type']) && in_array($_GET['type'], $transaction_types_array)) {
|
||||
$type_filter = $_GET['type'];
|
||||
} else {
|
||||
$type_filter = '';
|
||||
}
|
||||
|
||||
// Category Filter
|
||||
if (isset($_GET['category']) & !empty($_GET['category'])) {
|
||||
$category_filter = intval($_GET['category']);
|
||||
} else {
|
||||
$category_filter = '';
|
||||
}
|
||||
|
||||
// Client Filter
|
||||
if (isset($_GET['client']) & !empty($_GET['client'])) {
|
||||
$client_filter = intval($_GET['client']);
|
||||
} else {
|
||||
$client_filter = '';
|
||||
}
|
||||
|
||||
// Payment Method Filter
|
||||
if (isset($_GET['payment_method']) & !empty($_GET['payment_method'])) {
|
||||
$payment_method_filter = $_GET['payment_method'];
|
||||
} else {
|
||||
$payment_method_filter = '';
|
||||
}
|
||||
|
||||
// Amount Range Filter
|
||||
if (isset($_GET['amount_min']) && $_GET['amount_min'] != '') {
|
||||
$amount_min_filter = floatval($_GET['amount_min']);
|
||||
} else {
|
||||
$amount_min_filter = '';
|
||||
}
|
||||
if (isset($_GET['amount_max']) && $_GET['amount_max'] != '') {
|
||||
$amount_max_filter = floatval($_GET['amount_max']);
|
||||
} else {
|
||||
$amount_max_filter = '';
|
||||
}
|
||||
|
||||
// Search Filter
|
||||
if (isset($_GET['q']) & !empty($_GET['q'])) {
|
||||
$q_filter = $_GET['q'];
|
||||
} else {
|
||||
$q_filter = '';
|
||||
}
|
||||
|
||||
// Date Filter - ignore the all-time defaults so the date fields stay clean
|
||||
if (isset($_GET['dtf']) && !empty($_GET['dtf']) && $_GET['dtf'] !== '1970-01-01') {
|
||||
$date_from_filter = escapeHtml($_GET['dtf']);
|
||||
} else {
|
||||
$date_from_filter = '';
|
||||
}
|
||||
if (isset($_GET['dtt']) && !empty($_GET['dtt']) && $_GET['dtt'] !== '2099-12-31') {
|
||||
$date_to_filter = escapeHtml($_GET['dtt']);
|
||||
} else {
|
||||
$date_to_filter = '';
|
||||
}
|
||||
|
||||
ob_start();
|
||||
|
||||
?>
|
||||
|
||||
<div class="modal-header bg-dark">
|
||||
<h5 class="modal-title"><i class="fa fa-fw fa-download mr-2"></i>Exporting Transactions to CSV</h5>
|
||||
<button type="button" class="close text-white" data-dismiss="modal">
|
||||
<span>×</span>
|
||||
</button>
|
||||
</div>
|
||||
<form action="post.php" method="post" autocomplete="off">
|
||||
<input type="hidden" name="csrf_token" value="<?= $_SESSION['csrf_token'] ?>">
|
||||
|
||||
<div class="modal-body">
|
||||
|
||||
<div class="form-group">
|
||||
<label>Account</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-fw fa-piggy-bank"></i></span>
|
||||
</div>
|
||||
<select class="form-control select2" name="account" required>
|
||||
<option value="">- Select an Account -</option>
|
||||
|
||||
<?php
|
||||
$sql_accounts_filter = mysqli_query($mysqli, "SELECT * FROM accounts WHERE account_archived_at IS NULL ORDER BY account_name ASC");
|
||||
while ($row = mysqli_fetch_assoc($sql_accounts_filter)) {
|
||||
$account_id = intval($row['account_id']);
|
||||
$account_name = escapeHtml($row['account_name']);
|
||||
?>
|
||||
<option <?php if ($account_filter == $account_id) { echo "selected"; } ?> value="<?= $account_id ?>"><?= $account_name ?></option>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Search</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-fw fa-search"></i></span>
|
||||
</div>
|
||||
<input type="text" class="form-control" name="q" value="<?= stripslashes(escapeHtml($q_filter)) ?>" placeholder="Description, category, reference or amount">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Type</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-fw fa-exchange-alt"></i></span>
|
||||
</div>
|
||||
<select class="form-control select2" name="type">
|
||||
<option value="">- All Types -</option>
|
||||
|
||||
<?php foreach ($transaction_types_array as $transaction_type_option) { ?>
|
||||
<option <?php if ($type_filter == $transaction_type_option) { echo "selected"; } ?> value="<?= $transaction_type_option ?>"><?= $transaction_type_option ?></option>
|
||||
<?php } ?>
|
||||
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Category</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-fw fa-list"></i></span>
|
||||
</div>
|
||||
<select class="form-control select2" name="category">
|
||||
<option value="">- All Categories -</option>
|
||||
|
||||
<?php
|
||||
$sql_categories_filter = mysqli_query($mysqli, "SELECT category_id, category_name FROM categories WHERE category_type IN ('Income', 'Expense') ORDER BY category_name ASC");
|
||||
while ($row = mysqli_fetch_assoc($sql_categories_filter)) {
|
||||
$category_id = intval($row['category_id']);
|
||||
$category_name = escapeHtml($row['category_name']);
|
||||
?>
|
||||
<option <?php if ($category_filter == $category_id) { echo "selected"; } ?> value="<?= $category_id ?>"><?= $category_name ?></option>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Client</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-fw fa-user"></i></span>
|
||||
</div>
|
||||
<select class="form-control select2" name="client">
|
||||
<option value="">- All Clients -</option>
|
||||
|
||||
<?php
|
||||
$sql_clients_filter = mysqli_query($mysqli, "SELECT client_id, client_name FROM clients WHERE client_archived_at IS NULL AND (EXISTS (SELECT 1 FROM revenues WHERE revenue_client_id = client_id) OR EXISTS (SELECT 1 FROM expenses WHERE expense_client_id = client_id) OR EXISTS (SELECT 1 FROM invoices WHERE invoice_client_id = client_id)) ORDER BY client_name ASC");
|
||||
while ($row = mysqli_fetch_assoc($sql_clients_filter)) {
|
||||
$client_id = intval($row['client_id']);
|
||||
$client_name = escapeHtml($row['client_name']);
|
||||
?>
|
||||
<option <?php if ($client_filter == $client_id) { echo "selected"; } ?> value="<?= $client_id ?>"><?= $client_name ?></option>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Payment Method</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-fw fa-credit-card"></i></span>
|
||||
</div>
|
||||
<select class="form-control select2" name="payment_method">
|
||||
<option value="">- All Methods -</option>
|
||||
|
||||
<?php
|
||||
$sql_payment_methods_filter = mysqli_query($mysqli, "SELECT payment_method_name FROM payment_methods ORDER BY payment_method_name ASC");
|
||||
while ($row = mysqli_fetch_assoc($sql_payment_methods_filter)) {
|
||||
$payment_method_name = escapeHtml($row['payment_method_name']);
|
||||
?>
|
||||
<option <?php if ($payment_method_filter == $payment_method_name) { echo "selected"; } ?> value="<?= $payment_method_name ?>"><?= $payment_method_name ?></option>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Amount Range</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-fw fa-dollar-sign"></i></span>
|
||||
</div>
|
||||
<input type="number" step="0.01" min="0" class="form-control" name="amount_min" value="<?= $amount_min_filter ?>" placeholder="Min">
|
||||
<input type="number" step="0.01" min="0" class="form-control" name="amount_max" value="<?= $amount_max_filter ?>" placeholder="Max">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Date From</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-fw fa-calendar"></i></span>
|
||||
</div>
|
||||
<input type="date" class="form-control" name="date_from" value="<?= $date_from_filter ?>" max="2999-12-31">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Date To</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-fw fa-calendar"></i></span>
|
||||
</div>
|
||||
<input type="date" class="form-control" name="date_to" value="<?= $date_to_filter ?>" max="2999-12-31">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" name="export_transactions_csv" class="btn btn-primary text-bold"><i class="fas fa-fw fa-download mr-2"></i>Download CSV</button>
|
||||
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Cancel</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<?php
|
||||
require_once '../../../includes/modal_footer.php';
|
||||
216
agent/post/transaction.php
Normal file
216
agent/post/transaction.php
Normal file
@@ -0,0 +1,216 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* ITFlow - Transactions POST request handler
|
||||
*/
|
||||
|
||||
if (!defined('FROM_POST_HANDLER')) {
|
||||
header("HTTP/1.1 401 Unauthorized");
|
||||
exit;
|
||||
}
|
||||
|
||||
if (isset($_POST['export_transactions_csv'])) {
|
||||
|
||||
validateCSRFToken($_POST['csrf_token']);
|
||||
|
||||
enforceUserPermission('module_financial');
|
||||
|
||||
$date_from = escapeSql($_POST['date_from']);
|
||||
$date_to = escapeSql($_POST['date_to']);
|
||||
$account = intval($_POST['account']);
|
||||
$category = intval($_POST['category']);
|
||||
|
||||
// Type Filter
|
||||
$transaction_types_array = ['Revenue', 'Payment', 'Expense', 'Transfer In', 'Transfer Out'];
|
||||
if (!empty($_POST['type']) && in_array($_POST['type'], $transaction_types_array)) {
|
||||
$type_query = "AND (transaction_type = '" . escapeSql($_POST['type']) . "')";
|
||||
} else {
|
||||
// Default - any
|
||||
$type_query = '';
|
||||
}
|
||||
|
||||
// Category Filter
|
||||
if ($category) {
|
||||
$category_query = "AND (transaction_category_id = $category)";
|
||||
} else {
|
||||
// Default - any
|
||||
$category_query = '';
|
||||
}
|
||||
|
||||
// Client Filter
|
||||
$client = intval($_POST['client']);
|
||||
if ($client) {
|
||||
$client_query = "AND (transaction_client_id = $client)";
|
||||
} else {
|
||||
// Default - any
|
||||
$client_query = '';
|
||||
}
|
||||
|
||||
// Payment Method Filter
|
||||
if (!empty($_POST['payment_method'])) {
|
||||
$payment_method_query = "AND (transaction_payment_method = '" . escapeSql($_POST['payment_method']) . "')";
|
||||
} else {
|
||||
// Default - any
|
||||
$payment_method_query = '';
|
||||
}
|
||||
|
||||
// Amount Range Filter - matched on absolute value so direction doesn't matter
|
||||
if (isset($_POST['amount_min']) && $_POST['amount_min'] != '') {
|
||||
$amount_min_query = 'AND (ABS(transaction_amount) >= ' . floatval($_POST['amount_min']) . ')';
|
||||
} else {
|
||||
// Default - any
|
||||
$amount_min_query = '';
|
||||
}
|
||||
if (isset($_POST['amount_max']) && $_POST['amount_max'] != '') {
|
||||
$amount_max_query = 'AND (ABS(transaction_amount) <= ' . floatval($_POST['amount_max']) . ')';
|
||||
} else {
|
||||
// Default - any
|
||||
$amount_max_query = '';
|
||||
}
|
||||
|
||||
// Search Filter - mirrors the transactions page search box
|
||||
$q = escapeSql($_POST['q']);
|
||||
if (!empty($q)) {
|
||||
$search_query = "AND (transaction_description LIKE '%$q%' OR transaction_category LIKE '%$q%' OR transaction_reference LIKE '%$q%' OR transaction_other_account LIKE '%$q%' OR transaction_amount LIKE '%$q%')";
|
||||
} else {
|
||||
// Default - any
|
||||
$search_query = '';
|
||||
}
|
||||
|
||||
// Date Filter
|
||||
if (!empty($date_from) && !empty($date_to)) {
|
||||
$date_query = "AND DATE(transaction_date) BETWEEN '$date_from' AND '$date_to'";
|
||||
} else {
|
||||
$date_query = '';
|
||||
}
|
||||
|
||||
// Account is required - export is a per-account ledger
|
||||
if ($account) {
|
||||
|
||||
// Account details for the running balance and file name
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT * FROM accounts WHERE account_id = $account LIMIT 1"));
|
||||
$account_name = $row['account_name'];
|
||||
$account_opening_balance = floatval($row['opening_balance']);
|
||||
|
||||
// Same ledger as transactions.php - full unfiltered ledger for the balance, filters applied outside
|
||||
$sql = mysqli_query(
|
||||
$mysqli,
|
||||
"SELECT * FROM (
|
||||
SELECT *,
|
||||
$account_opening_balance + SUM(transaction_amount) OVER (ORDER BY transaction_date ASC, transaction_created_at ASC, transaction_type ASC, transaction_id ASC) AS transaction_balance
|
||||
FROM (
|
||||
SELECT
|
||||
CASE WHEN transfer_id IS NOT NULL THEN 'Transfer In' ELSE 'Revenue' END AS transaction_type,
|
||||
revenue_id AS transaction_id,
|
||||
revenue_date AS transaction_date,
|
||||
revenue_created_at AS transaction_created_at,
|
||||
CASE WHEN transfer_id IS NOT NULL THEN transfer_notes ELSE revenue_description END AS transaction_description,
|
||||
from_account.account_name AS transaction_other_account,
|
||||
revenue_reference AS transaction_reference,
|
||||
revenue_client_id AS transaction_client_id,
|
||||
CASE WHEN transfer_id IS NOT NULL THEN transfer_method ELSE revenue_payment_method END AS transaction_payment_method,
|
||||
revenue_category_id AS transaction_category_id,
|
||||
category_name AS transaction_category,
|
||||
revenue_amount AS transaction_amount
|
||||
FROM revenues
|
||||
LEFT JOIN categories ON revenue_category_id = category_id
|
||||
LEFT JOIN transfers ON transfer_revenue_id = revenue_id
|
||||
LEFT JOIN expenses AS transfer_expense ON transfer_expense_id = transfer_expense.expense_id
|
||||
LEFT JOIN accounts AS from_account ON transfer_expense.expense_account_id = from_account.account_id
|
||||
WHERE revenue_account_id = $account
|
||||
AND revenue_archived_at IS NULL
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT
|
||||
CASE WHEN transfer_id IS NOT NULL THEN 'Transfer Out' ELSE 'Expense' END,
|
||||
expense_id,
|
||||
expense_date,
|
||||
expense_created_at,
|
||||
CASE WHEN transfer_id IS NOT NULL THEN transfer_notes ELSE expense_description END,
|
||||
to_account.account_name,
|
||||
expense_reference,
|
||||
expense_client_id,
|
||||
CASE WHEN transfer_id IS NOT NULL THEN transfer_method ELSE expense_payment_method END,
|
||||
expense_category_id,
|
||||
category_name,
|
||||
-expense_amount
|
||||
FROM expenses
|
||||
LEFT JOIN categories ON expense_category_id = category_id
|
||||
LEFT JOIN transfers ON transfer_expense_id = expense_id
|
||||
LEFT JOIN revenues AS transfer_revenue ON transfer_revenue_id = transfer_revenue.revenue_id
|
||||
LEFT JOIN accounts AS to_account ON transfer_revenue.revenue_account_id = to_account.account_id
|
||||
WHERE expense_account_id = $account
|
||||
AND expense_archived_at IS NULL
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT
|
||||
'Payment',
|
||||
payment_id,
|
||||
payment_date,
|
||||
payment_created_at,
|
||||
CONCAT('Payment for Invoice ', invoice_prefix, invoice_number),
|
||||
NULL,
|
||||
payment_reference,
|
||||
invoice_client_id,
|
||||
payment_method,
|
||||
0,
|
||||
'Invoice Payment',
|
||||
payment_amount
|
||||
FROM payments
|
||||
LEFT JOIN invoices ON payment_invoice_id = invoice_id
|
||||
WHERE payment_account_id = $account
|
||||
AND payment_archived_at IS NULL
|
||||
) AS ledger
|
||||
) AS transactions
|
||||
WHERE 1 = 1
|
||||
$date_query
|
||||
$type_query
|
||||
$category_query
|
||||
$client_query
|
||||
$payment_method_query
|
||||
$amount_min_query
|
||||
$amount_max_query
|
||||
$search_query
|
||||
ORDER BY transaction_date ASC, transaction_created_at ASC, transaction_type ASC, transaction_id ASC"
|
||||
);
|
||||
|
||||
$num_rows = mysqli_num_rows($sql);
|
||||
if ($num_rows > 0) {
|
||||
$delimiter = ",";
|
||||
$enclosure = '"';
|
||||
$escape = '\\'; // backslash
|
||||
$filename = sanitizeFilename("$session_company_name-$account_name-Transactions-" . date('Y-m-d_H-i-s') . ".csv");
|
||||
|
||||
//create a file pointer
|
||||
$f = fopen('php://memory', 'w');
|
||||
|
||||
//set column headers
|
||||
$fields = array('Date', 'Type', 'Description', 'Transfer Account', 'Reference', 'Category', 'Payment Method', 'Amount', 'Balance');
|
||||
fputcsv($f, $fields, $delimiter, $enclosure, $escape);
|
||||
|
||||
//output each row of the data, format line as csv and write to file pointer
|
||||
while ($row = mysqli_fetch_assoc($sql)) {
|
||||
$lineData = array($row['transaction_date'], $row['transaction_type'], $row['transaction_description'], $row['transaction_other_account'], $row['transaction_reference'], $row['transaction_category'], $row['transaction_payment_method'], $row['transaction_amount'], $row['transaction_balance']);
|
||||
fputcsv($f, $lineData, $delimiter, $enclosure, $escape);
|
||||
}
|
||||
|
||||
//move back to beginning of file
|
||||
fseek($f, 0);
|
||||
|
||||
//set headers to download file rather than displayed
|
||||
header('Content-Type: text/csv');
|
||||
header('Content-Disposition: attachment; filename="' . $filename . '";');
|
||||
|
||||
//output all remaining data on a file pointer
|
||||
fpassthru($f);
|
||||
}
|
||||
|
||||
logAudit("Transaction", "Export", "$session_name exported $num_rows transaction(s) to CSV file");
|
||||
|
||||
}
|
||||
|
||||
exit;
|
||||
|
||||
}
|
||||
554
agent/transactions.php
Normal file
554
agent/transactions.php
Normal file
@@ -0,0 +1,554 @@
|
||||
<?php
|
||||
|
||||
// Default Column Sortby/Order Filter
|
||||
$sort = "transaction_date";
|
||||
$order = "DESC";
|
||||
|
||||
require_once "includes/inc_all.php";
|
||||
|
||||
// Perms
|
||||
enforceUserPermission('module_financial');
|
||||
|
||||
// Account Filter
|
||||
if (isset($_GET['account']) & !empty($_GET['account'])) {
|
||||
$account_filter = intval($_GET['account']);
|
||||
} else {
|
||||
// Default - none selected
|
||||
$account_filter = '';
|
||||
}
|
||||
|
||||
// Type Filter
|
||||
$transaction_types_array = ['Revenue', 'Payment', 'Expense', 'Transfer In', 'Transfer Out'];
|
||||
if (isset($_GET['type']) & !empty($_GET['type']) && in_array($_GET['type'], $transaction_types_array)) {
|
||||
$type_query = "AND (transaction_type = '" . escapeSql($_GET['type']) . "')";
|
||||
$type_filter = escapeSql($_GET['type']);
|
||||
} else {
|
||||
// Default - any
|
||||
$type_query = '';
|
||||
$type_filter = '';
|
||||
}
|
||||
|
||||
// Category Filter
|
||||
if (isset($_GET['category']) & !empty($_GET['category'])) {
|
||||
$category_query = 'AND (transaction_category_id = ' . intval($_GET['category']) . ')';
|
||||
$category_filter = intval($_GET['category']);
|
||||
} else {
|
||||
// Default - any
|
||||
$category_query = '';
|
||||
$category_filter = '';
|
||||
}
|
||||
|
||||
// Client Filter
|
||||
if (isset($_GET['client']) & !empty($_GET['client'])) {
|
||||
$client_query = 'AND (transaction_client_id = ' . intval($_GET['client']) . ')';
|
||||
$client_filter = intval($_GET['client']);
|
||||
} else {
|
||||
// Default - any
|
||||
$client_query = '';
|
||||
$client_filter = '';
|
||||
}
|
||||
|
||||
// Payment Method Filter
|
||||
if (isset($_GET['payment_method']) & !empty($_GET['payment_method'])) {
|
||||
$payment_method_query = "AND (transaction_payment_method = '" . escapeSql($_GET['payment_method']) . "')";
|
||||
$payment_method_filter = escapeSql($_GET['payment_method']);
|
||||
} else {
|
||||
// Default - any
|
||||
$payment_method_query = '';
|
||||
$payment_method_filter = '';
|
||||
}
|
||||
|
||||
// Amount Range Filter - matched on absolute value so direction doesn't matter (type filter handles direction)
|
||||
if (isset($_GET['amount_min']) && $_GET['amount_min'] != '') {
|
||||
$amount_min_query = 'AND (ABS(transaction_amount) >= ' . floatval($_GET['amount_min']) . ')';
|
||||
$amount_min_filter = floatval($_GET['amount_min']);
|
||||
} else {
|
||||
// Default - any
|
||||
$amount_min_query = '';
|
||||
$amount_min_filter = '';
|
||||
}
|
||||
if (isset($_GET['amount_max']) && $_GET['amount_max'] != '') {
|
||||
$amount_max_query = 'AND (ABS(transaction_amount) <= ' . floatval($_GET['amount_max']) . ')';
|
||||
$amount_max_filter = floatval($_GET['amount_max']);
|
||||
} else {
|
||||
// Default - any
|
||||
$amount_max_query = '';
|
||||
$amount_max_filter = '';
|
||||
}
|
||||
|
||||
// Balance only makes sense in chronological order - hide the column under any other sort
|
||||
if ($sort == 'transaction_date') {
|
||||
$balance_visible = true;
|
||||
} else {
|
||||
$balance_visible = false;
|
||||
}
|
||||
|
||||
if ($account_filter) {
|
||||
|
||||
// Account details - opening balance feeds the running balance, currency feeds the summary
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT * FROM accounts WHERE account_id = $account_filter LIMIT 1"));
|
||||
$account_currency_code = escapeHtml($row['account_currency_code']);
|
||||
$account_opening_balance = floatval($row['opening_balance']);
|
||||
|
||||
// Transfers are stored as a linked expense (from account) + revenue (to account) pair,
|
||||
// so we detect them via the transfers link table and relabel the row accordingly
|
||||
// The running balance is calculated over the account's full ledger BEFORE any filters,
|
||||
// so the balance per transaction stays accurate no matter what is filtered out
|
||||
|
||||
$ledger_query =
|
||||
"SELECT *,
|
||||
$account_opening_balance + SUM(transaction_amount) OVER (ORDER BY transaction_date ASC, transaction_created_at ASC, transaction_type ASC, transaction_id ASC) AS transaction_balance
|
||||
FROM (
|
||||
SELECT
|
||||
CASE WHEN transfer_id IS NOT NULL THEN 'Transfer In' ELSE 'Revenue' END AS transaction_type,
|
||||
revenue_id AS transaction_id,
|
||||
transfer_id AS transaction_transfer_id,
|
||||
0 AS transaction_invoice_id,
|
||||
revenue_date AS transaction_date,
|
||||
revenue_created_at AS transaction_created_at,
|
||||
CASE WHEN transfer_id IS NOT NULL THEN transfer_notes ELSE revenue_description END AS transaction_description,
|
||||
from_account.account_name AS transaction_other_account,
|
||||
revenue_reference AS transaction_reference,
|
||||
revenue_client_id AS transaction_client_id,
|
||||
CASE WHEN transfer_id IS NOT NULL THEN transfer_method ELSE revenue_payment_method END AS transaction_payment_method,
|
||||
revenue_category_id AS transaction_category_id,
|
||||
category_name AS transaction_category,
|
||||
revenue_amount AS transaction_amount,
|
||||
revenue_currency_code AS transaction_currency_code
|
||||
FROM revenues
|
||||
LEFT JOIN categories ON revenue_category_id = category_id
|
||||
LEFT JOIN transfers ON transfer_revenue_id = revenue_id
|
||||
LEFT JOIN expenses AS transfer_expense ON transfer_expense_id = transfer_expense.expense_id
|
||||
LEFT JOIN accounts AS from_account ON transfer_expense.expense_account_id = from_account.account_id
|
||||
WHERE revenue_account_id = $account_filter
|
||||
AND revenue_archived_at IS NULL
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT
|
||||
CASE WHEN transfer_id IS NOT NULL THEN 'Transfer Out' ELSE 'Expense' END,
|
||||
expense_id,
|
||||
transfer_id,
|
||||
0,
|
||||
expense_date,
|
||||
expense_created_at,
|
||||
CASE WHEN transfer_id IS NOT NULL THEN transfer_notes ELSE expense_description END,
|
||||
to_account.account_name,
|
||||
expense_reference,
|
||||
expense_client_id,
|
||||
CASE WHEN transfer_id IS NOT NULL THEN transfer_method ELSE expense_payment_method END,
|
||||
expense_category_id,
|
||||
category_name,
|
||||
-expense_amount,
|
||||
expense_currency_code
|
||||
FROM expenses
|
||||
LEFT JOIN categories ON expense_category_id = category_id
|
||||
LEFT JOIN transfers ON transfer_expense_id = expense_id
|
||||
LEFT JOIN revenues AS transfer_revenue ON transfer_revenue_id = transfer_revenue.revenue_id
|
||||
LEFT JOIN accounts AS to_account ON transfer_revenue.revenue_account_id = to_account.account_id
|
||||
WHERE expense_account_id = $account_filter
|
||||
AND expense_archived_at IS NULL
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT
|
||||
'Payment',
|
||||
payment_id,
|
||||
NULL,
|
||||
payment_invoice_id,
|
||||
payment_date,
|
||||
payment_created_at,
|
||||
CONCAT('Payment for Invoice ', invoice_prefix, invoice_number),
|
||||
NULL,
|
||||
payment_reference,
|
||||
invoice_client_id,
|
||||
payment_method,
|
||||
0,
|
||||
'Invoice Payment',
|
||||
payment_amount,
|
||||
payment_currency_code
|
||||
FROM payments
|
||||
LEFT JOIN invoices ON payment_invoice_id = invoice_id
|
||||
WHERE payment_account_id = $account_filter
|
||||
AND payment_archived_at IS NULL
|
||||
) AS ledger";
|
||||
|
||||
$transaction_filter_query =
|
||||
"WHERE DATE(transaction_date) BETWEEN '$dtf' AND '$dtt'
|
||||
AND (transaction_description LIKE '%$q%' OR transaction_category LIKE '%$q%' OR transaction_reference LIKE '%$q%' OR transaction_other_account LIKE '%$q%' OR transaction_amount LIKE '%$q%')
|
||||
$type_query
|
||||
$category_query
|
||||
$client_query
|
||||
$payment_method_query
|
||||
$amount_min_query
|
||||
$amount_max_query";
|
||||
|
||||
$sql = mysqli_query(
|
||||
$mysqli,
|
||||
"SELECT SQL_CALC_FOUND_ROWS * FROM (
|
||||
$ledger_query
|
||||
) AS transactions
|
||||
$transaction_filter_query
|
||||
ORDER BY $sort $order LIMIT $record_from, $record_to"
|
||||
);
|
||||
|
||||
$num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
|
||||
// Summary - money in / money out / net for the current filtered view, plus current account balance
|
||||
$sql_summary = mysqli_query(
|
||||
$mysqli,
|
||||
"SELECT
|
||||
SUM(CASE WHEN transaction_amount > 0 THEN transaction_amount ELSE 0 END) AS total_in,
|
||||
SUM(CASE WHEN transaction_amount < 0 THEN transaction_amount ELSE 0 END) AS total_out,
|
||||
SUM(transaction_amount) AS total_net
|
||||
FROM (
|
||||
$ledger_query
|
||||
) AS transactions
|
||||
$transaction_filter_query"
|
||||
);
|
||||
$row = mysqli_fetch_assoc($sql_summary);
|
||||
$summary_total_in = floatval($row['total_in']);
|
||||
$summary_total_out = floatval($row['total_out']);
|
||||
$summary_total_net = floatval($row['total_net']);
|
||||
|
||||
} else {
|
||||
$num_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-list-alt mr-2"></i>Transactions</h3>
|
||||
<?php if ($account_filter) { ?>
|
||||
<div class="card-tools">
|
||||
<button type="button" class="btn btn-primary ajax-modal" data-modal-url="modals/transaction/transaction_export.php?account=<?php echo $account_filter; ?>&type=<?php echo urlencode($type_filter); ?>&category=<?php echo $category_filter; ?>&client=<?php echo $client_filter; ?>&payment_method=<?php echo urlencode($payment_method_filter); ?>&amount_min=<?php echo $amount_min_filter; ?>&amount_max=<?php echo $amount_max_filter; ?>&dtf=<?php echo $dtf; ?>&dtt=<?php echo $dtt; ?>&q=<?php echo urlencode($q ?? ''); ?>"><i class="fa fa-download mr-2"></i>Export</button>
|
||||
</div>
|
||||
<?php } ?>
|
||||
</div>
|
||||
|
||||
<div class="card-body">
|
||||
<form class="mb-4" autocomplete="off">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="form-group">
|
||||
<label>Search</label>
|
||||
<div class="input-group">
|
||||
<input type="search" class="form-control" name="q" value="<?php if (isset($q)) { echo stripslashes(escapeHtml($q)); } ?>" placeholder="Search Transactions">
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-primary"><i class="fa fa-search"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<div class="form-group">
|
||||
<label>Account</label>
|
||||
<select class="form-control select2" name="account" onchange="this.form.submit()">
|
||||
<option value="">- Select an Account -</option>
|
||||
|
||||
<?php
|
||||
$sql_accounts_filter = mysqli_query(
|
||||
$mysqli,
|
||||
"SELECT account_id, account_name, account_currency_code,
|
||||
opening_balance
|
||||
+ COALESCE((SELECT SUM(revenue_amount) FROM revenues WHERE revenue_account_id = account_id AND revenue_archived_at IS NULL), 0)
|
||||
+ COALESCE((SELECT SUM(payment_amount) FROM payments WHERE payment_account_id = account_id AND payment_archived_at IS NULL), 0)
|
||||
- COALESCE((SELECT SUM(expense_amount) FROM expenses WHERE expense_account_id = account_id AND expense_archived_at IS NULL), 0)
|
||||
AS account_balance
|
||||
FROM accounts WHERE account_archived_at IS NULL ORDER BY account_name ASC"
|
||||
);
|
||||
while ($row = mysqli_fetch_assoc($sql_accounts_filter)) {
|
||||
$account_id = intval($row['account_id']);
|
||||
$account_name = escapeHtml($row['account_name']);
|
||||
$account_balance_display = numfmt_format_currency($currency_format, floatval($row['account_balance']), $row['account_currency_code']);
|
||||
?>
|
||||
<option <?php if ($account_filter == $account_id) { echo "selected"; } ?> value="<?php echo $account_id; ?>"><?php echo "$account_name ($account_balance_display)"; ?></option>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<div class="form-group">
|
||||
<label>Type</label>
|
||||
<select class="form-control select2" name="type" onchange="this.form.submit()">
|
||||
<option value="">- All Types -</option>
|
||||
|
||||
<?php foreach ($transaction_types_array as $transaction_type_option) { ?>
|
||||
<option <?php if ($type_filter == $transaction_type_option) { echo "selected"; } ?> value="<?php echo $transaction_type_option; ?>"><?php echo $transaction_type_option; ?></option>
|
||||
<?php } ?>
|
||||
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<div class="form-group">
|
||||
<label>Category</label>
|
||||
<select class="form-control select2" name="category" onchange="this.form.submit()">
|
||||
<option value="">- All Categories -</option>
|
||||
|
||||
<?php
|
||||
$sql_categories_filter = mysqli_query($mysqli, "SELECT category_id, category_name FROM categories WHERE category_type IN ('Income', 'Expense') AND (EXISTS (SELECT 1 FROM revenues WHERE revenue_category_id = category_id) OR EXISTS (SELECT 1 FROM expenses WHERE expense_category_id = category_id)) ORDER BY category_name ASC");
|
||||
while ($row = mysqli_fetch_assoc($sql_categories_filter)) {
|
||||
$category_id = intval($row['category_id']);
|
||||
$category_name = escapeHtml($row['category_name']);
|
||||
?>
|
||||
<option <?php if ($category_filter == $category_id) { echo "selected"; } ?> value="<?php echo $category_id; ?>"><?php echo $category_name; ?></option>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="form-group mb-md-0">
|
||||
<label>Client</label>
|
||||
<select class="form-control select2" name="client" onchange="this.form.submit()">
|
||||
<option value="">- All Clients -</option>
|
||||
|
||||
<?php
|
||||
$sql_clients_filter = mysqli_query($mysqli, "SELECT client_id, client_name FROM clients WHERE client_archived_at IS NULL AND (EXISTS (SELECT 1 FROM revenues WHERE revenue_client_id = client_id) OR EXISTS (SELECT 1 FROM expenses WHERE expense_client_id = client_id) OR EXISTS (SELECT 1 FROM invoices WHERE invoice_client_id = client_id)) ORDER BY client_name ASC");
|
||||
while ($row = mysqli_fetch_assoc($sql_clients_filter)) {
|
||||
$client_id = intval($row['client_id']);
|
||||
$client_name = escapeHtml($row['client_name']);
|
||||
?>
|
||||
<option <?php if ($client_filter == $client_id) { echo "selected"; } ?> value="<?php echo $client_id; ?>"><?php echo $client_name; ?></option>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<div class="form-group mb-md-0">
|
||||
<label>Payment Method</label>
|
||||
<select class="form-control select2" name="payment_method" onchange="this.form.submit()">
|
||||
<option value="">- All Methods -</option>
|
||||
|
||||
<?php
|
||||
$sql_payment_methods_filter = mysqli_query($mysqli, "SELECT payment_method_name FROM payment_methods ORDER BY payment_method_name ASC");
|
||||
while ($row = mysqli_fetch_assoc($sql_payment_methods_filter)) {
|
||||
$payment_method_name = escapeHtml($row['payment_method_name']);
|
||||
?>
|
||||
<option <?php if ($payment_method_filter == $payment_method_name) { echo "selected"; } ?> value="<?php echo $payment_method_name; ?>"><?php echo $payment_method_name; ?></option>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<div class="form-group mb-md-0">
|
||||
<label>Amount Range</label>
|
||||
<div class="input-group">
|
||||
<input type="number" step="0.01" min="0" class="form-control" name="amount_min" value="<?php echo $amount_min_filter; ?>" placeholder="Min" onchange="this.form.submit()">
|
||||
<input type="number" step="0.01" min="0" class="form-control" name="amount_max" value="<?php echo $amount_max_filter; ?>" placeholder="Max" onchange="this.form.submit()">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<div class="form-group mb-md-0">
|
||||
<label>Date Range</label>
|
||||
<input type="text" id="dateFilter" class="form-control" autocomplete="off">
|
||||
<input type="hidden" name="canned_date" id="canned_date" value="<?php echo escapeHtml($_GET['canned_date']) ?? ''; ?>">
|
||||
<input type="hidden" name="dtf" id="dtf" value="<?php echo escapeHtml($dtf ?? ''); ?>">
|
||||
<input type="hidden" name="dtt" id="dtt" value="<?php echo escapeHtml($dtt ?? ''); ?>">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<hr>
|
||||
|
||||
<?php if ($account_filter) { ?>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-4 col-md-6 col-sm-12">
|
||||
<!-- small box -->
|
||||
<div class="small-box bg-success">
|
||||
<div class="inner">
|
||||
<h3><?php echo numfmt_format_currency($currency_format, $summary_total_in, $account_currency_code); ?></h3>
|
||||
<p>Money In</p>
|
||||
</div>
|
||||
<div class="icon">
|
||||
<i class="fa fa-hand-holding-usd"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- ./col -->
|
||||
|
||||
<div class="col-lg-4 col-md-6 col-sm-12">
|
||||
<!-- small box -->
|
||||
<div class="small-box bg-danger">
|
||||
<div class="inner">
|
||||
<h3><?php echo numfmt_format_currency($currency_format, $summary_total_out, $account_currency_code); ?></h3>
|
||||
<p>Money Out</p>
|
||||
</div>
|
||||
<div class="icon">
|
||||
<i class="fa fa-shopping-cart"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- ./col -->
|
||||
|
||||
<div class="col-lg-4 col-md-6 col-sm-12">
|
||||
<!-- small box -->
|
||||
<div class="small-box <?php if ($summary_total_net < 0) { echo "bg-danger"; } else { echo "bg-primary"; } ?>">
|
||||
<div class="inner">
|
||||
<h3><?php echo numfmt_format_currency($currency_format, $summary_total_net, $account_currency_code); ?></h3>
|
||||
<p>Net</p>
|
||||
</div>
|
||||
<div class="icon">
|
||||
<i class="fa fa-balance-scale"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- ./col -->
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-borderless table-hover">
|
||||
<thead class="text-dark <?php if ($num_rows[0] == 0) { echo "d-none"; } ?>">
|
||||
<tr>
|
||||
<th>
|
||||
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=transaction_date&order=<?php echo $disp; ?>">
|
||||
Date <?php if ($sort == 'transaction_date') { echo $order_icon; } ?>
|
||||
</a>
|
||||
</th>
|
||||
<th>
|
||||
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=transaction_type&order=<?php echo $disp; ?>">
|
||||
Type <?php if ($sort == 'transaction_type') { echo $order_icon; } ?>
|
||||
</a>
|
||||
</th>
|
||||
<th>
|
||||
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=transaction_category&order=<?php echo $disp; ?>">
|
||||
Category <?php if ($sort == 'transaction_category') { echo $order_icon; } ?>
|
||||
</a>
|
||||
/
|
||||
<a class="text-secondary" href="?<?php echo $url_query_strings_sort; ?>&sort=transaction_description&order=<?php echo $disp; ?>">
|
||||
Description <?php if ($sort == 'transaction_description') { echo $order_icon; } ?>
|
||||
</a>
|
||||
</th>
|
||||
<th class="text-right">
|
||||
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=transaction_amount&order=<?php echo $disp; ?>">
|
||||
Amount <?php if ($sort == 'transaction_amount') { echo $order_icon; } ?>
|
||||
</a>
|
||||
</th>
|
||||
<?php if ($balance_visible) { ?>
|
||||
<th class="text-right">Balance</th>
|
||||
<?php } ?>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
|
||||
while ($row = mysqli_fetch_assoc($sql)) {
|
||||
$transaction_id = intval($row['transaction_id']);
|
||||
$transaction_transfer_id = intval($row['transaction_transfer_id']);
|
||||
$transaction_invoice_id = intval($row['transaction_invoice_id']);
|
||||
$transaction_type = escapeHtml($row['transaction_type']);
|
||||
$transaction_date = escapeHtml($row['transaction_date']);
|
||||
$transaction_description = escapeHtml($row['transaction_description']);
|
||||
$transaction_category = escapeHtml($row['transaction_category']);
|
||||
$transaction_other_account = escapeHtml($row['transaction_other_account']);
|
||||
$transaction_amount = floatval($row['transaction_amount']);
|
||||
$transaction_balance = floatval($row['transaction_balance']);
|
||||
$transaction_currency_code = escapeHtml($row['transaction_currency_code']);
|
||||
|
||||
// Category cell display - transfers show the other account instead of a category
|
||||
if ($transaction_type == 'Transfer In') {
|
||||
$transaction_category_display = "<i class='fas fa-fw fa-arrow-left text-secondary mr-1'></i>From $transaction_other_account";
|
||||
} elseif ($transaction_type == 'Transfer Out') {
|
||||
$transaction_category_display = "<i class='fas fa-fw fa-arrow-right text-secondary mr-1'></i>To $transaction_other_account";
|
||||
} else {
|
||||
$transaction_category_display = $transaction_category;
|
||||
}
|
||||
|
||||
// Badge color based on type
|
||||
if ($transaction_type == 'Revenue' || $transaction_type == 'Payment') {
|
||||
$transaction_badge_color = "success";
|
||||
} elseif ($transaction_type == 'Expense') {
|
||||
$transaction_badge_color = "danger";
|
||||
} else {
|
||||
$transaction_badge_color = "secondary";
|
||||
}
|
||||
|
||||
// Amount text color
|
||||
if ($transaction_amount < 0) {
|
||||
$transaction_amount_color = "text-danger";
|
||||
} else {
|
||||
$transaction_amount_color = "text-success";
|
||||
}
|
||||
|
||||
// Balance text color
|
||||
if ($transaction_balance < 0) {
|
||||
$transaction_balance_color = "text-danger";
|
||||
} else {
|
||||
$transaction_balance_color = "";
|
||||
}
|
||||
|
||||
// Route the date link to the right edit modal based on type
|
||||
if ($transaction_type == 'Transfer In' || $transaction_type == 'Transfer Out') {
|
||||
$transaction_modal_url = "modals/transfer/transfer_edit.php?id=$transaction_transfer_id";
|
||||
} elseif ($transaction_type == 'Expense') {
|
||||
$transaction_modal_url = "modals/expense/expense_edit.php?id=$transaction_id";
|
||||
} elseif ($transaction_type == 'Revenue') {
|
||||
$transaction_modal_url = "modals/revenue/revenue_edit.php?id=$transaction_id";
|
||||
} else {
|
||||
$transaction_modal_url = "";
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<?php if ($transaction_type == 'Payment') { ?>
|
||||
<a class="text-bold" href="invoice.php?invoice_id=<?php echo $transaction_invoice_id; ?>">
|
||||
<?php echo $transaction_date; ?>
|
||||
</a>
|
||||
<?php } else { ?>
|
||||
<a class="text-bold ajax-modal" href="#"
|
||||
data-modal-size="lg"
|
||||
data-modal-url="<?php echo $transaction_modal_url; ?>">
|
||||
<?php echo $transaction_date; ?>
|
||||
</a>
|
||||
<?php } ?>
|
||||
</td>
|
||||
<td><span class="badge badge-<?php echo $transaction_badge_color; ?>"><?php echo $transaction_type; ?></span></td>
|
||||
<td>
|
||||
<?php echo $transaction_category_display; ?>
|
||||
<div class="text-secondary"><small><?php echo truncate($transaction_description, 60); ?></small></div>
|
||||
</td>
|
||||
<td class="text-right text-monospace <?php echo $transaction_amount_color; ?>"><?php echo numfmt_format_currency($currency_format, $transaction_amount, $transaction_currency_code); ?></td>
|
||||
<?php if ($balance_visible) { ?>
|
||||
<td class="text-right text-monospace <?php echo $transaction_balance_color; ?>"><?php echo numfmt_format_currency($currency_format, $transaction_balance, $transaction_currency_code); ?></td>
|
||||
<?php } ?>
|
||||
</tr>
|
||||
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php require_once "../includes/filter_footer.php"; ?>
|
||||
|
||||
<?php } else { ?>
|
||||
|
||||
<p class="text-secondary mb-0">Select an account above to view its transactions.</p>
|
||||
|
||||
<?php } ?>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
require_once "../includes/footer.php";
|
||||
Reference in New Issue
Block a user