diff --git a/admin/post/settings_theme.php b/admin/post/settings_theme.php index a67388f37..732ede75d 100644 --- a/admin/post/settings_theme.php +++ b/admin/post/settings_theme.php @@ -10,7 +10,7 @@ if (isset($_POST['edit_theme_settings'])) { mysqli_query($mysqli,"UPDATE settings SET config_theme = '$theme' WHERE company_id = 1"); - logAudit("Settings", "Edit", "$session_name edited theme settings $dark_mode"); + logAudit("Settings", "Edit", "$session_name edited theme settings to $theme"); flashAlert("Changed theme to $theme"); diff --git a/admin/post/ticket_status.php b/admin/post/ticket_status.php index faf7e454c..b653e0897 100644 --- a/admin/post/ticket_status.php +++ b/admin/post/ticket_status.php @@ -61,7 +61,7 @@ if (isset($_GET['delete_ticket_status'])) { exit("Can't delete built-in statuses"); } - $ticlet_status_name = escapeSql(getFieldById('ticket_statuses', $ticket_status_id, 'ticket_status_name')); + $ticket_status_name = escapeSql(getFieldById('ticket_statuses', $ticket_status_id, 'ticket_status_name')); mysqli_query($mysqli, "DELETE FROM ticket_statuses WHERE ticket_status_id = $ticket_status_id"); diff --git a/agent/income.php b/agent/income.php index 95c5b4b0e..e74f044fa 100644 --- a/agent/income.php +++ b/agent/income.php @@ -278,6 +278,38 @@ $summary_total_income = floatval($row['total_income']); + = 3 && lookupUserPermission("module_financial") >= 3) { ?> +
+
+
+ +
+
+
+
" id="advancedFilter">
@@ -342,6 +374,13 @@ $summary_total_income = floatval($row['total_income']); text-nowrap"> + = 3 && lookupUserPermission("module_financial") >= 3) { ?> + + + = 3 && lookupUserPermission("module_financial") >= 3) { ?> + +
+
+ +
+
Date @@ -435,6 +474,13 @@ $summary_total_income = floatval($row['total_income']); ?>
+
+ +
+
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ +$asset_name linked with credential $crdential_name"); + flashAlert("Asset $asset_name linked with credential $credential_name"); redirect(); diff --git a/agent/post/contact.php b/agent/post/contact.php index adb4cc49e..2a8ff379c 100644 --- a/agent/post/contact.php +++ b/agent/post/contact.php @@ -374,7 +374,7 @@ if (isset($_POST['bulk_assign_contact_location'])) { mysqli_query($mysqli,"UPDATE contacts SET contact_location_id = $location_id WHERE contact_id = $contact_id"); - logAudit("Contact", "Edit", "$session_name assigned $contaxt_name to location $location_name", $client_id, $contact_id); + logAudit("Contact", "Edit", "$session_name assigned $contact_name to location $location_name", $client_id, $contact_id); } // End Assign Location Loop diff --git a/agent/post/expense.php b/agent/post/expense.php index 5efa7fcdc..213a1b737 100644 --- a/agent/post/expense.php +++ b/agent/post/expense.php @@ -158,7 +158,7 @@ if (isset($_POST['bulk_edit_expense_category'])) { mysqli_query($mysqli,"UPDATE expenses SET expense_category_id = $category_id WHERE expense_id = $expense_id"); - logAudit("Expense", "Edit", "$session_name assigned expense $expense_descrition to category $category_name", $client_id, $expense_id); + logAudit("Expense", "Edit", "$session_name assigned expense $expense_description to category $category_name", $client_id, $expense_id); } // End Assign Loop @@ -203,7 +203,7 @@ if (isset($_POST['bulk_edit_expense_account'])) { mysqli_query($mysqli,"UPDATE expenses SET expense_account_id = $account_id WHERE expense_id = $expense_id"); - logAudit("Expense", "Edit", "$session_name assigned expense $expense_descrition to account $account_name", $client_id, $expense_id); + logAudit("Expense", "Edit", "$session_name assigned expense $expense_description to account $account_name", $client_id, $expense_id); } // End Assign Loop @@ -243,11 +243,11 @@ if (isset($_POST['bulk_edit_expense_client'])) { mysqli_query($mysqli,"UPDATE expenses SET expense_client_id = $client_id WHERE expense_id = $expense_id"); - logAudit("Expense", "Edit", "$session_name assigned expense $expense_descrition to client $client_name", $client_id, $expense_id); + logAudit("Expense", "Edit", "$session_name assigned expense $expense_description to client $client_name", $client_id, $expense_id); } // End Assign Loop - flashAlert("You assigned Client $client_name to $expense_count expenses"); + flashAlert("You assigned client $client_name to $count expense(s)"); } redirect(); @@ -284,7 +284,7 @@ if (isset($_POST['bulk_delete_expenses'])) { mysqli_query($mysqli, "DELETE FROM expenses WHERE expense_id = $expense_id"); - logAudit("Expense", "Delete", "$session_name deleted expense $expense_descrition", $client_id); + logAudit("Expense", "Delete", "$session_name deleted expense $expense_description", $client_id); } diff --git a/agent/post/income.php b/agent/post/income.php index cc1900e28..40cf87cd6 100644 --- a/agent/post/income.php +++ b/agent/post/income.php @@ -9,6 +9,304 @@ if (!defined('FROM_POST_HANDLER')) { exit; } +// The Income page merges payments and revenues, so its bulk actions have to fan out across both +// tables. Selection parsing is shared - see income_model.php. +// Gating: these are the multi-row form of the row Edit action on the Income page, so they gate the +// same way the payment edit handler does (the strictest of the two row types). + +if (isset($_POST['bulk_edit_income_account'])) { + + validateCSRFToken(); + + enforceUserPermission('module_sales', 3); + enforceUserPermission('module_financial', 3); + + require_once 'income_model.php'; + + $account_id = intval($_POST['bulk_account_id']); + + // Get Account name for logging and Notification - and confirm it is a real, un-archived account + $sql_account = mysqli_query($mysqli, "SELECT account_name FROM accounts WHERE account_id = $account_id AND account_archived_at IS NULL LIMIT 1"); + $row = mysqli_fetch_assoc($sql_account); + + if (!$row || !$income_count) { + flashAlert("Nothing to update", 'error'); + redirect(); + } + + $account_name = escapeSql($row['account_name']); + + $updated_count = 0; + + // Payments - client comes from the invoice the payment was made against + foreach ($payment_ids as $payment_id) { + + $sql = mysqli_query($mysqli, "SELECT payment_reference, invoice_client_id FROM payments LEFT JOIN invoices ON payment_invoice_id = invoice_id WHERE payment_id = $payment_id AND payment_archived_at IS NULL"); + $row = mysqli_fetch_assoc($sql); + + if (!$row) { + continue; + } + + $payment_reference = escapeSql($row['payment_reference']); + $client_id = intval($row['invoice_client_id']); + + if ($client_id) { + enforceClientAccess($client_id); + } + + mysqli_query($mysqli, "UPDATE payments SET payment_account_id = $account_id WHERE payment_id = $payment_id"); + + logAudit("Payment", "Edit", "$session_name assigned payment $payment_reference to account $account_name", $client_id, $payment_id); + + $updated_count++; + + } + + // Revenues + foreach ($revenue_ids as $revenue_id) { + + $sql = mysqli_query($mysqli, "SELECT revenue_description, revenue_client_id FROM revenues WHERE revenue_id = $revenue_id AND revenue_archived_at IS NULL"); + $row = mysqli_fetch_assoc($sql); + + if (!$row) { + continue; + } + + $revenue_description = escapeSql($row['revenue_description']); + $client_id = intval($row['revenue_client_id']); + + if ($client_id) { + enforceClientAccess($client_id); + } + + mysqli_query($mysqli, "UPDATE revenues SET revenue_account_id = $account_id WHERE revenue_id = $revenue_id"); + + logAudit("Revenue", "Edit", "$session_name assigned revenue $revenue_description to account $account_name", $client_id, $revenue_id); + + $updated_count++; + + } + + if ($updated_count) { + logAudit("Income", "Bulk Edit", "$session_name assigned $updated_count income record(s) to account $account_name"); + flashAlert("You assigned account $account_name to $updated_count income record(s)"); + } else { + flashAlert("No income records were updated", 'error'); + } + + redirect(); + +} + +if (isset($_POST['bulk_edit_income_category'])) { + + validateCSRFToken(); + + enforceUserPermission('module_sales', 3); + enforceUserPermission('module_financial', 3); + + require_once 'income_model.php'; + + $category_id = intval($_POST['bulk_category_id']); + + // Get Category name for logging and Notification - and confirm it is a live Income category + $sql_category = mysqli_query($mysqli, "SELECT category_name FROM categories WHERE category_id = $category_id AND category_type = 'Income' AND category_archived_at IS NULL LIMIT 1"); + $row = mysqli_fetch_assoc($sql_category); + + if (!$row || !$income_count) { + flashAlert("Nothing to update", 'error'); + redirect(); + } + + $category_name = escapeSql($row['category_name']); + + $revenue_updated_count = 0; + $invoice_updated_count = 0; + $skipped_count = 0; + + // Revenues carry their own category + foreach ($revenue_ids as $revenue_id) { + + $sql = mysqli_query($mysqli, "SELECT revenue_description, revenue_client_id FROM revenues WHERE revenue_id = $revenue_id AND revenue_archived_at IS NULL"); + $row = mysqli_fetch_assoc($sql); + + if (!$row) { + $skipped_count++; + continue; + } + + $revenue_description = escapeSql($row['revenue_description']); + $client_id = intval($row['revenue_client_id']); + + if ($client_id) { + enforceClientAccess($client_id); + } + + mysqli_query($mysqli, "UPDATE revenues SET revenue_category_id = $category_id WHERE revenue_id = $revenue_id"); + + logAudit("Revenue", "Edit", "$session_name assigned revenue $revenue_description to category $category_name", $client_id, $revenue_id); + + $revenue_updated_count++; + + } + + // A payment has no category of its own - it inherits the one on the invoice it was paid + // against, so this writes to the INVOICE. Two selected payments against the same invoice + // therefore collapse into a single invoice update, and a payment with no invoice is skipped. + $invoice_ids = []; + + foreach ($payment_ids as $payment_id) { + + $sql = mysqli_query($mysqli, "SELECT payment_invoice_id FROM payments WHERE payment_id = $payment_id AND payment_archived_at IS NULL"); + $row = mysqli_fetch_assoc($sql); + $payment_invoice_id = intval($row['payment_invoice_id'] ?? 0); + + if ($payment_invoice_id) { + $invoice_ids[$payment_invoice_id] = $payment_invoice_id; + } else { + $skipped_count++; + } + + } + + foreach ($invoice_ids as $invoice_id) { + + $sql = mysqli_query($mysqli, "SELECT invoice_prefix, invoice_number, invoice_client_id FROM invoices WHERE invoice_id = $invoice_id"); + $row = mysqli_fetch_assoc($sql); + + if (!$row) { + $skipped_count++; + continue; + } + + $invoice_prefix = escapeSql($row['invoice_prefix']); + $invoice_number = intval($row['invoice_number']); + $client_id = intval($row['invoice_client_id']); + + enforceClientAccess($client_id); + + mysqli_query($mysqli, "UPDATE invoices SET invoice_category_id = $category_id WHERE invoice_id = $invoice_id"); + + logAudit("Invoice", "Edit", "$session_name assigned invoice $invoice_prefix$invoice_number to category $category_name", $client_id, $invoice_id); + + $invoice_updated_count++; + + } + + // Spell out the invoice leg - the user selected payments, not invoices + $updated_summary = []; + if ($revenue_updated_count) { + $updated_summary[] = "$revenue_updated_count revenue(s)"; + } + if ($invoice_updated_count) { + $updated_summary[] = "$invoice_updated_count invoice(s) behind the selected payment(s)"; + } + + if ($updated_summary) { + + logAudit("Income", "Bulk Edit", "$session_name assigned category $category_name to $revenue_updated_count revenue(s) and $invoice_updated_count invoice(s)"); + + $skipped_note = ''; + if ($skipped_count) { + $skipped_note = " - $skipped_count record(s) skipped"; + } + + flashAlert("You assigned category $category_name to " . implode(' and ', $updated_summary) . $skipped_note); + + } else { + flashAlert("No income records were categorised - a payment can only take a category from the invoice it was paid against", 'error'); + } + + redirect(); + +} + +if (isset($_POST['bulk_edit_income_method'])) { + + validateCSRFToken(); + + enforceUserPermission('module_sales', 3); + enforceUserPermission('module_financial', 3); + + require_once 'income_model.php'; + + // The method is stored by name on both tables, so validate it against the lookup list + $payment_method = escapeSql($_POST['bulk_payment_method']); + + $sql_payment_method = mysqli_query($mysqli, "SELECT payment_method_name FROM payment_methods WHERE payment_method_name = '$payment_method' LIMIT 1"); + $row = mysqli_fetch_assoc($sql_payment_method); + + if (!$row || !$income_count) { + flashAlert("Nothing to update", 'error'); + redirect(); + } + + $payment_method = escapeSql($row['payment_method_name']); + + $updated_count = 0; + + // Payments - client comes from the invoice the payment was made against + foreach ($payment_ids as $payment_id) { + + $sql = mysqli_query($mysqli, "SELECT payment_reference, invoice_client_id FROM payments LEFT JOIN invoices ON payment_invoice_id = invoice_id WHERE payment_id = $payment_id AND payment_archived_at IS NULL"); + $row = mysqli_fetch_assoc($sql); + + if (!$row) { + continue; + } + + $payment_reference = escapeSql($row['payment_reference']); + $client_id = intval($row['invoice_client_id']); + + if ($client_id) { + enforceClientAccess($client_id); + } + + mysqli_query($mysqli, "UPDATE payments SET payment_method = '$payment_method' WHERE payment_id = $payment_id"); + + logAudit("Payment", "Edit", "$session_name set payment $payment_reference to payment method $payment_method", $client_id, $payment_id); + + $updated_count++; + + } + + // Revenues + foreach ($revenue_ids as $revenue_id) { + + $sql = mysqli_query($mysqli, "SELECT revenue_description, revenue_client_id FROM revenues WHERE revenue_id = $revenue_id AND revenue_archived_at IS NULL"); + $row = mysqli_fetch_assoc($sql); + + if (!$row) { + continue; + } + + $revenue_description = escapeSql($row['revenue_description']); + $client_id = intval($row['revenue_client_id']); + + if ($client_id) { + enforceClientAccess($client_id); + } + + mysqli_query($mysqli, "UPDATE revenues SET revenue_payment_method = '$payment_method' WHERE revenue_id = $revenue_id"); + + logAudit("Revenue", "Edit", "$session_name set revenue $revenue_description to payment method $payment_method", $client_id, $revenue_id); + + $updated_count++; + + } + + if ($updated_count) { + logAudit("Income", "Bulk Edit", "$session_name set $updated_count income record(s) to payment method $payment_method"); + flashAlert("You set payment method $payment_method on $updated_count income record(s)"); + } else { + flashAlert("No income records were updated", 'error'); + } + + redirect(); + +} + if (isset($_POST['export_income'])) { validateCSRFToken(); diff --git a/agent/post/income_model.php b/agent/post/income_model.php new file mode 100644 index 000000000..2e094482e --- /dev/null +++ b/agent/post/income_model.php @@ -0,0 +1,36 @@ +$network_name restored"); diff --git a/agent/post/rack.php b/agent/post/rack.php index c3f71c2ae..afd5f871a 100644 --- a/agent/post/rack.php +++ b/agent/post/rack.php @@ -272,7 +272,7 @@ if (isset($_GET['remove_rack_unit'])) { $unit_id = intval($_GET['remove_rack_unit']); // Get Name and Client ID for logging and alert message - $sql = mysqli_query($mysqli,"SELECT rack_name, rack_id, rack_client_id FROM racks LEFT JOIN rack_units ON unit_rack_id = rack_id WHERE unit_id = $unit_id"); + $sql = mysqli_query($mysqli,"SELECT rack_name, rack_id, rack_client_id, unit_device FROM racks LEFT JOIN rack_units ON unit_rack_id = rack_id WHERE unit_id = $unit_id"); $row = mysqli_fetch_assoc($sql); $rack_name = escapeSql($row['rack_name']); $unit_device = escapeSql($row['unit_device']); @@ -283,9 +283,9 @@ if (isset($_GET['remove_rack_unit'])) { mysqli_query($mysqli,"DELETE FROM rack_units WHERE unit_id = $unit_id"); - logAudit("Rack", "Edit", "$session_name removed device $device_name from rack $rack_name", $client_id, $rack_id); + logAudit("Rack", "Edit", "$session_name removed device $unit_device from rack $rack_name", $client_id, $rack_id); - flashAlert("Device $device_name removed from rack", 'error'); + flashAlert("Device $unit_device removed from rack", 'error'); redirect(); diff --git a/agent/post/ticket.php b/agent/post/ticket.php index d5a7840b4..b59372ea3 100644 --- a/agent/post/ticket.php +++ b/agent/post/ticket.php @@ -1246,7 +1246,7 @@ if (isset($_POST['bulk_edit_ticket_category'])) { // Update ticket mysqli_query($mysqli, "UPDATE tickets SET ticket_category = '$category_id' WHERE ticket_id = $ticket_id"); - logAudit("Ticket", "Edit", "$session_name updated the category on ticket $ticket_prefix$ticket_number - $ticket_subject from $previous_category_name to $category_name", $client_id, $ticket_id); + logAudit("Ticket", "Edit", "$session_name updated the category on ticket $ticket_prefix$ticket_number - $ticket_subject from $previous_ticket_category_name to $category_name", $client_id, $ticket_id); triggerCustomAction('ticket_update', $ticket_id); } // End For Each Ticket ID Loop