diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 000000000..e10cd9eab
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,50 @@
+# Changelog
+
+All notable changes to ITFlow will be documented in this file.
+
+## [25.1]
+
+### Added / Changed
+- Added ability to save cards in Stripe for automatic invoice payment
+- Page titles now reflect the page name, client selection, company name, ticket info, invoice info etc. for easier multi tab navigation.
+- Admin pages now once again use the new admin role-check
+- Admin roles can now be archived
+- Debug now shows the current git branch
+- Auto-acknowledgement email for email-parsed tickets now contains a guest link
+- Recurring tickets no longer require a contact
+- Stripe online payment setup now prompts you to set the income/expense account
+- New cron/cli scripts are in the scripts subfolder - please update your cron configurations!
+- Moved all modal includes to /modals to tidy root directory
+- Moved most include files to /includes to tidy root directory
+- Moved guest pages to /guest to tidy directory structure
+- Renamed include file pagination.php to filter_footer.php as it is used in conjunction with filter_header.php for page filtering
+- Guest ticket feedback now shows friendly ticket prefix & number, rather than just the ID
+- Individual POST handler logic pages can no longer be accessed directly
+- Added payment deletion on Payments and client Payments Page
+- Added Domains history tracking
+- Added Asset Interface Linking / Connections to determine what interface is connected to what interface port of another asset
+- Added Force Recurring Ticket in more places instead of just recurring tickets
+- Row span and center devices that take up multiple units in a rack
+- Added Tooltips to main nav badge counts to show what its actually counting
+- Changed the Max records per page from 500 to 100 to prevent performance issues
+
+### Fixed
+- Fixed ticket edit modal not showing multi-client/no-client projects
+- Fixed asset interface losing DHCP setting
+- Fixed creating / editing recurring expenses causing 500 error due to incorrect var name
+- Fixed tickets created via portal/email not being marked as billable
+- Fixed editing Recurring Expense
+- Fixed a regression TinyMCE Editor not showing when adding or editing ticket templates
+
+### Removed / Deprecated
+- Deprecated the current cron scripts in the root directory - change cron to use the ones in the scripts subfolder instead
+
+### BREAKING CHANGES
+- Moved Client portal from /portal to /client - Links will be broken on previous emails, also you may need to update any other links for example website, support page etc?
+- Moved guest links from / to /guest - Links will be broken on previous emails.
+
+
+## [24.12]
+
+### Added / Changed
+- First introduced versioned releases!
diff --git a/README.md b/README.md
index 6c1791cc6..4863620df 100644
--- a/README.md
+++ b/README.md
@@ -3,15 +3,10 @@
[![Contributors][contributors-shield]][contributors-url]
[![Stargazers][stars-shield]][stars-url]
-[![Issues][issues-shield]][issues-url]
[![Commits][commit-shield]][commit-url]
[![GPL License][license-shield]][license-url]
-
+
+
+
+
+ Save card details
+ In order to set up automatic payments, you must create a customer record in Stripe.
+ First, you must authorize Stripe to store your card details for the purpose of automatic payment.
+
+
+
+
+
+
+
+ elseif (empty($stripe_pm)) { ?>
+
+ Save card details
+ Please add the payment details you would like to save.
+ By adding payment details here, you grant consent for future automatic payments of invoices.
+ 1) {
+ // If your data might have multiple devices in the same row,
+ // you have to decide how to handle them.
+ // For now, we can fallback to older logic or display them all in one cell, etc.
+ ?>
+
Ticket: $ticket_prefix$ticket_number Subject: $ticket_subject Status: Open Portal: https://$config_base_url/client/ticket.php?id=$id
-- $company_name - Support $config_ticket_from_email $company_phone";
$email = [
'from' => $config_ticket_from_email,
@@ -360,7 +363,7 @@
}
// Add to the mail queue
- addToMailQueue($mysqli, $data);
+ addToMailQueue($data);
// Set the next run date
if ($frequency == "weekly") {
@@ -482,9 +485,9 @@
$subject = "Overdue Invoice $invoice_prefix$invoice_number";
$body = "Hello $contact_name,
Our records indicate that we have not yet received payment for the invoice $invoice_prefix$invoice_number. We kindly request that you submit your payment as soon as possible. If you have any questions or concerns, please do not hesitate to contact us at $company_email or $company_phone.
- Kindly review the invoice details mentioned below.
Invoice: $invoice_prefix$invoice_number Issue Date: $invoice_date Total: " . numfmt_format_currency($currency_format, $invoice_amount, $invoice_currency_code) . " Due Date: $invoice_due Over Due By: $day Days
-- $company_name - Billing $config_invoice_from_email $company_phone";
- $mail = addToMailQueue($mysqli, [
+ $mail = addToMailQueue([
[
'from' => $config_invoice_from_email,
'from_name' => $config_invoice_from_name,
@@ -663,7 +666,7 @@
]
];
- addToMailQueue($mysqli, $data);
+ addToMailQueue($data);
}
} //End if Autosend is on
@@ -1003,8 +1006,9 @@
* ###############################################################################################################
*/
-// Send Alert to inform Cron was run
-appNotify("Cron", "Cron successfully executed", "admin_audit_log.php");
+// Alert we're using the old cron path
+appNotify("Cron", "Cron ran OK, but paths need updating - cron scripts are now in the scripts subfolder", "admin_audit_log.php");
// Logging
logApp("Cron", "info", "Cron executed successfully");
+logApp("Cron", "warning", "Cron ran using an old script path");
\ No newline at end of file
diff --git a/cron_ticket_email_parser.php b/cron_ticket_email_parser.php
index e8b3e6376..61bcca501 100644
--- a/cron_ticket_email_parser.php
+++ b/cron_ticket_email_parser.php
@@ -155,7 +155,7 @@ function addTicket($contact_id, $contact_name, $contact_email, $client_id, $date
$data = [];
if ($config_ticket_client_general_notifications == 1) {
$subject_email = "Ticket created - [$config_ticket_prefix$ticket_number] - $subject";
- $body = "##- Please type your reply above this line -##
Hello $contact_name,
Thank you for your email. A ticket regarding \"$subject\" has been automatically created for you.
Ticket: $config_ticket_prefix$ticket_number Subject: $subject Status: New https://$config_base_url/portal/ticket.php?id=$id
-- $company_name - Support $config_ticket_from_email $company_phone";
+ $body = "##- Please type your reply above this line -##
Hello $contact_name,
Thank you for your email. A ticket regarding \"$subject\" has been automatically created for you.
Ticket: $config_ticket_prefix$ticket_number Subject: $subject Status: New https://$config_base_url/client/ticket.php?id=$id
-- $company_name - Support $config_ticket_from_email $company_phone";
$data[] = [
'from' => $config_ticket_from_email,
'from_name' => $config_ticket_from_name,
@@ -187,7 +187,7 @@ function addTicket($contact_id, $contact_name, $contact_email, $client_id, $date
];
}
- addToMailQueue($mysqli, $data);
+ addToMailQueue($data);
// Custom action/notif handler
customAction('ticket_create', $id);
@@ -249,7 +249,7 @@ function addReply($from_email, $date, $subject, $ticket_number, $message, $attac
]
];
- addToMailQueue($mysqli, $data);
+ addToMailQueue($data);
return true;
}
@@ -319,7 +319,7 @@ function addReply($from_email, $date, $subject, $ticket_number, $message, $attac
]
];
- addToMailQueue($mysqli, $data);
+ addToMailQueue($data);
}
}
diff --git a/dashboard.php b/dashboard.php
index 20a9d4cde..79d89916c 100644
--- a/dashboard.php
+++ b/dashboard.php
@@ -1,5 +1,5 @@
-
+
diff --git a/database_updates.php b/database_updates.php
index c29c68edf..0cabb96d3 100644
--- a/database_updates.php
+++ b/database_updates.php
@@ -2404,12 +2404,71 @@ function processFile($file_path, $file_name, $mysqli) {
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.7.5'");
}
- // if (CURRENT_DATABASE_VERSION == '1.7.5') {
- // // Insert queries here required to update to DB version 1.7.6
+ if (CURRENT_DATABASE_VERSION == '1.7.5') {
+ mysqli_query($mysqli, "CREATE TABLE `client_stripe` (`client_id` INT(11) NOT NULL, `stripe_id` VARCHAR(255) NOT NULL, `stripe_pm` varchar(255) NULL) ENGINE = InnoDB CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci; ");
+
+ mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.7.6'");
+ }
+
+ if (CURRENT_DATABASE_VERSION == '1.7.6') {
+ // Create a field to show connected interface of a foreign asset
+ mysqli_query($mysqli, "ALTER TABLE `asset_interfaces` ADD `interface_connected_asset_interface` INT(11) NOT NULL DEFAULT 0 AFTER `interface_network_id`");
+
+ mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.7.7'");
+ }
+
+ if (CURRENT_DATABASE_VERSION == '1.7.7') {
+ // Domain history
+ mysqli_query($mysqli, "CREATE TABLE `domain_history` (`domain_history_id` INT(11) NOT NULL AUTO_INCREMENT , `domain_history_column` VARCHAR(200) NOT NULL , `domain_history_old_value` TEXT NOT NULL , `domain_history_new_value` TEXT NOT NULL , `domain_history_domain_id` INT(11) NOT NULL , `domain_history_modified_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP , PRIMARY KEY (`domain_history_id`)) ENGINE = InnoDB CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci;");
+
+ mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.7.8'");
+ }
+
+ if (CURRENT_DATABASE_VERSION == '1.7.8') {
+
+ // Use a seperate table for Interface connections / links. This will make it easier to manage.
+ $createInterfaceLinksTable = "
+ CREATE TABLE IF NOT EXISTS `asset_interface_links` (
+ `interface_link_id` INT AUTO_INCREMENT PRIMARY KEY,
+ `interface_a_id` INT NOT NULL,
+ `interface_b_id` INT NOT NULL,
+ `interface_link_type` VARCHAR(100) NULL,
+ `interface_link_status` VARCHAR(50) NULL,
+ `interface_link_created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `interface_link_updated_at` DATETIME NULL ON UPDATE CURRENT_TIMESTAMP,
+
+ CONSTRAINT `fk_interface_a`
+ FOREIGN KEY (`interface_a_id`)
+ REFERENCES `asset_interfaces` (`interface_id`)
+ ON DELETE CASCADE
+ ON UPDATE CASCADE,
+
+ CONSTRAINT `fk_interface_b`
+ FOREIGN KEY (`interface_b_id`)
+ REFERENCES `asset_interfaces` (`interface_id`)
+ ON DELETE CASCADE
+ ON UPDATE CASCADE
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+ ";
+ mysqli_query($mysqli, $createInterfaceLinksTable) or die(mysqli_error($mysqli));
+
+ // Drop the old column from asset_interfaces if it exists
+ $dropConnectedColumn = "
+ ALTER TABLE `asset_interfaces`
+ DROP COLUMN IF EXISTS `interface_connected_asset_interface`
+ ";
+ mysqli_query($mysqli, $dropConnectedColumn) or die(mysqli_error($mysqli));
+
+ mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.7.9'");
+ }
+
+ // if (CURRENT_DATABASE_VERSION == '1.7.9') {
+ // // Insert queries here required to update to DB version 1.8.0
// // Then, update the database to the next sequential version
- // mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.7.6'");
+ // mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.8.0'");
// }
} else {
// Up-to-date
}
+
diff --git a/database_version.php b/database_version.php
index 589a6c56b..3627c05e1 100644
--- a/database_version.php
+++ b/database_version.php
@@ -5,4 +5,4 @@
* It is used in conjunction with database_updates.php
*/
-DEFINE("LATEST_DATABASE_VERSION", "1.7.5");
+DEFINE("LATEST_DATABASE_VERSION", "1.7.9");
diff --git a/db.sql b/db.sql
index 664915d83..48aaa2731 100644
--- a/db.sql
+++ b/db.sql
@@ -134,6 +134,29 @@ CREATE TABLE `asset_history` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
+--
+-- Table structure for table `asset_interface_links`
+--
+
+DROP TABLE IF EXISTS `asset_interface_links`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+CREATE TABLE `asset_interface_links` (
+ `interface_link_id` int(11) NOT NULL AUTO_INCREMENT,
+ `interface_a_id` int(11) NOT NULL,
+ `interface_b_id` int(11) NOT NULL,
+ `interface_link_type` varchar(100) DEFAULT NULL,
+ `interface_link_status` varchar(50) DEFAULT NULL,
+ `interface_link_created_at` datetime NOT NULL DEFAULT current_timestamp(),
+ `interface_link_updated_at` datetime DEFAULT NULL ON UPDATE current_timestamp(),
+ PRIMARY KEY (`interface_link_id`),
+ KEY `fk_interface_a` (`interface_a_id`),
+ KEY `fk_interface_b` (`interface_b_id`),
+ CONSTRAINT `fk_interface_a` FOREIGN KEY (`interface_a_id`) REFERENCES `asset_interfaces` (`interface_id`) ON DELETE CASCADE ON UPDATE CASCADE,
+ CONSTRAINT `fk_interface_b` FOREIGN KEY (`interface_b_id`) REFERENCES `asset_interfaces` (`interface_id`) ON DELETE CASCADE ON UPDATE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
+/*!40101 SET character_set_client = @saved_cs_client */;
+
--
-- Table structure for table `asset_interfaces`
--
@@ -342,6 +365,21 @@ CREATE TABLE `client_notes` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
+--
+-- Table structure for table `client_stripe`
+--
+
+DROP TABLE IF EXISTS `client_stripe`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+CREATE TABLE `client_stripe` (
+ `client_id` int(11) NOT NULL,
+ `stripe_id` varchar(255) NOT NULL,
+ `stripe_pm` varchar(255) DEFAULT NULL,
+ PRIMARY KEY (`client_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+/*!40101 SET character_set_client = @saved_cs_client */;
+
--
-- Table structure for table `client_tags`
--
@@ -636,6 +674,24 @@ CREATE TABLE `documents` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
+--
+-- Table structure for table `domain_history`
+--
+
+DROP TABLE IF EXISTS `domain_history`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+CREATE TABLE `domain_history` (
+ `domain_history_id` int(11) NOT NULL AUTO_INCREMENT,
+ `domain_history_column` varchar(200) NOT NULL,
+ `domain_history_old_value` text NOT NULL,
+ `domain_history_new_value` text NOT NULL,
+ `domain_history_domain_id` int(11) NOT NULL,
+ `domain_history_modified_at` datetime NOT NULL DEFAULT current_timestamp(),
+ PRIMARY KEY (`domain_history_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+/*!40101 SET character_set_client = @saved_cs_client */;
+
--
-- Table structure for table `domains`
--
@@ -2287,4 +2343,4 @@ CREATE TABLE `vendors` (
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
--- Dump completed on 2024-12-21 20:24:14
+-- Dump completed on 2025-01-18 13:03:55
diff --git a/expenses.php b/expenses.php
index e3c7d7ccc..dffee9dad 100644
--- a/expenses.php
+++ b/expenses.php
@@ -4,7 +4,7 @@
$sort = "expense_date";
$order = "DESC";
-require_once "inc_all.php";
+require_once "includes/inc_all.php";
// Perms
enforceUserPermission('module_financial');
@@ -12,31 +12,31 @@
// Account Filter
if (isset($_GET['account']) & !empty($_GET['account'])) {
$account_query = 'AND (expense_account_id = ' . intval($_GET['account']) . ')';
- $account = intval($_GET['account']);
+ $account_filter = intval($_GET['account']);
} else {
// Default - any
$account_query = '';
- $account = '';
+ $account_filter = '';
}
// Vendor Filter
if (isset($_GET['vendor']) & !empty($_GET['vendor'])) {
$vendor_query = 'AND (vendor_id = ' . intval($_GET['vendor']) . ')';
- $vendor = intval($_GET['vendor']);
+ $vendor_filter = intval($_GET['vendor']);
} else {
// Default - any
$vendor_query = '';
- $vendor = '';
+ $vendor_filter = '';
}
// Category Filter
if (isset($_GET['category']) & !empty($_GET['category'])) {
$category_query = 'AND (category_id = ' . intval($_GET['category']) . ')';
- $category = intval($_GET['category']);
+ $category_filter = intval($_GET['category']);
} else {
// Default - any
$category_query = '';
- $category = '';
+ $category_filter = '';
}
//Rebuild URL
@@ -120,7 +120,7 @@