61 Commits

Author SHA1 Message Date
wrongecho
216db04d32 Flag duplicate numbering in debug 2025-11-27 10:27:54 +00:00
wrongecho
13b8f93e17 Add unique index to ticket, quote and invoice numbers 2025-11-27 10:27:11 +00:00
wrongecho
0347382a34 Invoices - Allow specifying discount during creation 2025-11-27 09:53:35 +00:00
johnnyq
840460afe7 Update Bulk Action JS to accept and pass multiple custom name selector arrays but default to selected_ids if data-bulk-names is not specified 2025-11-26 16:12:19 -05:00
johnnyq
c851e54e1d Fix Decimal not showing on the iphone for specific fields associated to price cost percentage etc 2025-11-26 13:54:24 -05:00
johnnyq
5ef53b569c Create upload folders for recurring tickets and ticket_templates 2025-11-24 13:09:01 -05:00
johnnyq
698b4166e8 Add back deleted client edit in post 2025-11-24 11:27:01 -05:00
johnnyq
1a9a36829b Process base64 Images for document creation and editing for the API and Client Portal 2025-11-24 00:14:27 -05:00
johnnyq
155b8598ff Introduce cleanupUnusedImages function to delete referenced files that have been deleted when editing content which as been added to document template edit. Did not do this for documents as they are versioned and images will remain until the document is fully deleted 2025-11-23 15:36:11 -05:00
johnnyq
4153c91f84 Add function copyDirectory so when creating a document from a template copy the document_template folder to documents folder and update links 2025-11-23 15:26:29 -05:00
johnnyq
a99b19a1b5 Update add and edit Document template to extract base64 images and place them into files instead also delete the document_template/document_template_id folder when deleting a document template 2025-11-23 15:09:03 -05:00
johnnyq
18429fda2c Remove all side nav Quick adds 2025-11-23 14:53:39 -05:00
johnnyq
435da991ec Add custom folder to uploads for custom uploading for custom modules 2025-11-23 14:32:57 -05:00
johnnyq
ebd9aae924 Add Document Templates to uploads dir 2025-11-23 14:30:50 -05:00
johnnyq
414a84d5ec Focus on Author and Date values 2025-11-23 14:24:20 -05:00
johnnyq
a3b2517603 Fix up UI on document details header 2025-11-23 14:10:45 -05:00
johnnyq
43535082f6 Cleanup UI for document details title header 2025-11-23 14:02:01 -05:00
johnnyq
e73af9980e Also Delete Documents/Document_id folder during bulk delete 2025-11-23 13:43:12 -05:00
johnnyq
0bdd5784ee use saveBase64Image function for edit document as well and when document is deleted, delete the corresponding folder uploads/documents/document_id 2025-11-23 13:35:45 -05:00
johnnyq
48719ce29c Add Exclude uploads/documents to gitignore 2025-11-23 13:05:56 -05:00
johnnyq
29839d3b23 Implemented saveBase64Images() to convert base64 <img> tags into real files stored under /uploads/<module>/<id>/ with secure filenames. Added wrapper functions and updated document creation to use processed image paths. 2025-11-23 13:03:03 -05:00
johnnyq
185ea7d6ac Fix 'Email from at' On tickets that come from emails, was cuasing dup html head body tags causing htmlPurifier to strip it in ticket viewing, so we removed html body and head tags also remove orginal reply on reply ticket emails this removed ##- Please type your reply above this line -## and anything after it. Also removed the custom CSS that was embedded for all email sent out from ITFlow 2025-11-22 17:40:44 -05:00
johnnyq
ac7623d4f5 Update Add Client to use prepared statments 2025-11-21 20:53:04 -05:00
johnnyq
3d119261cc Add cleanInput function without mysqli_escape_string and converted add and edit payment method to Procedural mysqli Prepared Statments 2025-11-21 19:54:50 -05:00
wrongecho
169619c9b9 Merge branch 'develop' of https://github.com/itflow-org/itflow into develop 2025-11-18 13:08:17 +00:00
wrongecho
b991f787a2 Introduce subject-based automatic ticket merging/reply detection where e-mail is sent from a known contact or domain and the subject is a 95% match for a ticket opened in the last 7 days for that client 2025-11-18 13:08:02 +00:00
johnnyq
215fc6803e Fix Bulk Ticket Merging due to missing modal footer 2025-11-17 15:27:23 -05:00
johnnyq
a79c1c8246 Remove Duplicate get_query_strings code as this is all handled in the the filter header 2025-11-17 14:55:05 -05:00
johnnyq
1aa6419b1b Fix Broken Updating asset noted in asset details modal 2025-11-17 13:51:19 -05:00
johnnyq
02694f6720 Fix Broken Links in Email to Agent via Client Portal Ticket Update, update changelog 2025-11-17 12:10:10 -05:00
johnnyq
f50aabb570 Update Changelog 2025-11-17 11:59:43 -05:00
johnnyq
19b8d09bfd Update Ticket Detail card to use the adminlte's Card Collapse 2025-11-17 11:55:03 -05:00
johnnyq
66fb999a8c Update Test IMAP to use a Raw connection instead of depending on the Deprecated php-imap extension 2025-11-17 11:29:05 -05:00
johnnyq
0c5883b61b Use btn-tool for side references in Ticket details and some cleanup 2025-11-16 20:56:30 -05:00
johnnyq
ef66d5172c Move Ticket edit from top Right Menu to Ticket Details Section 2025-11-16 20:27:58 -05:00
johnnyq
118f9a34d8 Update Changelog 2025-11-16 20:02:26 -05:00
johnnyq
b61dfac569 Ticket Details Checks, Dont display Add/edit relations if no cliet in selected, dont show relations in ticket edit if no client assigned to ticket, also dont display public and email response type if no contact_email exists 2025-11-16 19:56:59 -05:00
johnnyq
79160f9b5c Dont show Client Tickets in Ticket Details Breadcrumbs if not client is assigned a ticket 2025-11-16 19:35:42 -05:00
johnnyq
d2523cff4a Add Tag Displays in edit and listing, remove unused type column 2025-11-16 18:41:30 -05:00
johnnyq
1839599769 Added Tag Type Filter Nav to tags 2025-11-16 18:21:01 -05:00
johnnyq
29e1b56e78 Hide contract side nav as its not yet complete 2025-11-16 17:58:07 -05:00
johnnyq
47e647c712 Update Changelog and bunp App Version 2025-11-16 17:55:13 -05:00
johnnyq
a87b0b0447 Fix regression in dashboard has client 2025-11-16 17:40:06 -05:00
johnnyq
96b8fcad3a Fix Pay With a Saved Card in Invoice Listing if Saved Cards are on files for that client 2025-11-16 17:34:37 -05:00
johnnyq
cf0fa0024c Update Wording on delete provider 2025-11-16 17:16:46 -05:00
johnnyq
aba5ed9271 Add Back Delete Payment Provider, the db will cascade delete all related recurring payments, related saved cards and client payment provider relation 2025-11-16 17:12:02 -05:00
johnnyq
63141f3578 Composer updates 2025-11-16 16:00:57 -05:00
johnnyq
612041635d Updated symfony/http-foundation from 7.3.3 to 7.3.7 2025-11-16 15:49:11 -05:00
johnnyq
efcc0fd5cb Add Where clause to only accept saved payment by logged in session_client_id in Client Portal 2025-11-16 15:33:45 -05:00
johnnyq
b0724f5b66 Add TOTP Secret to Export / Offboard Client Documentation PDF 2025-11-15 19:17:03 -05:00
johnnyq
66a2b4b6d2 Afer Ticket Merge Redirect to new ticket Details 2025-11-15 17:09:46 -05:00
johnnyq
77b4dfa50a Add UserID: on hover in users 2025-11-15 16:59:39 -05:00
johnnyq
1e6e7fd6d8 If ticket doesn't have a client dont show client section 2025-11-15 16:51:31 -05:00
johnnyq
46a1b673ba Fix Add Ticket Watcher 2025-11-13 00:01:35 -05:00
johnnyq
7230325e62 Migrate Ticket Template add to ajax-modal, add category type option if not defined, add product type if not defined 2025-11-12 17:04:53 -05:00
johnnyq
af8e733cfb Added Quick Add Links to the majority of Side bars navs 2025-11-12 16:27:03 -05:00
johnnyq
26ab43c57f Fix Mail Queue link when sending a test email, updated the quote send email wording to Quote sent 2025-11-12 14:50:05 -05:00
johnnyq
15ed4ef1ce Fix unable to delete Vendor Templates 2025-11-12 14:35:06 -05:00
johnnyq
0ac76766bd Add Asset Tags Display in Contact Details, asset details, along with their detail modals 2025-11-11 21:05:59 -05:00
johnnyq
abb97ad99f [Feature] Added Asset Tags 2025-11-11 19:57:51 -05:00
johnnyq
6cdc26b55b Fix broken edit payment methods due to missing hidden field 2025-11-09 12:24:04 -05:00
121 changed files with 3841 additions and 1116 deletions

10
.gitignore vendored
View File

@@ -4,8 +4,16 @@ config.php
uploads/favicon.ico uploads/favicon.ico
uploads/clients/* uploads/clients/*
!uploads/clients/index.php !uploads/clients/index.php
uploads/custom/*
!uploads/custom/index.php
uploads/documents/*
!uploads/documents/index.php
uploads/document_templates/*
!uploads/document_templates/index.php
uploads/expenses/* uploads/expenses/*
!uploads/expenses/index.php !uploads/expenses/index.php
uploads/recurring_tickets/*
!uploads/recurring_tickets/index.php
uploads/settings/* uploads/settings/*
!uploads/settings/index.php !uploads/settings/index.php
uploads/users/* uploads/users/*
@@ -14,6 +22,8 @@ uploads/tmp/*
!uploads/tmp/index.php !uploads/tmp/index.php
uploads/tickets/* uploads/tickets/*
!uploads/tickets/index.php !uploads/tickets/index.php
uploads/ticket_templates/*
!uploads/ticket_templates/index.php
.idea/* .idea/*
plugins/htmlpurifier/standalone/HTMLPurifier/DefinitionCache/Serializer/HTML/* plugins/htmlpurifier/standalone/HTMLPurifier/DefinitionCache/Serializer/HTML/*
!plugins/htmlpurifier/standalone/HTMLPurifier/DefinitionCache/Serializer/HTML/.gitkeep !plugins/htmlpurifier/standalone/HTMLPurifier/DefinitionCache/Serializer/HTML/.gitkeep

View File

@@ -2,7 +2,37 @@
This file documents all notable changes made to ITFlow. This file documents all notable changes made to ITFlow.
## [25.11] Changelog ## [25.11.1] Maint Release
### Fixes
- Fix broken edit Payment Method.
- Fix unable to delete Vendor Template.
- Fix Mail Queue link in flash alert for testing email and sending a quote.
- Add Show Category Type select if not defined.
- Add Show Product Type select if not defined.
- Fix add ticket watcher.
- Fix if Client isn't assigned to a ticket dont show client view.
- Fix missing session client id check when paying an invoice from client portal.
- Update Composer Webklex-IMAP library dependency symfony/http-foundation from 7.3.3 to 7.3.7 to fix security related issues.
- Add back delete Payment provider the database will handle cascade deletes to saved cards, recurring payments and client payment provider reference.
- Don't show Client Tickets Breadcrumb if no client is assigned to a ticket.
- Don't Show Contact or Assignment Tab in edit ticket if no Client is Assigned.
- Don't Show add contact, asset, vendor, watcher if not client is assigned to a ticket.
- Don't Show Public Comment & Email if contact email doesn't exist.
- Fixed IMAP Test whicn now uses RAW TCP Connection instead of the depracated php-imap extension.
- Fix Broken Link in Ticket Updates via Client Portal to agent.
### Added / Changed
- [Feature] Added Asset Tags.
- [Feature] Added Quick Add Links to most side bar navs example quickly add a client from sidebar.
- Migrate ticket template add to ajax modal.
- Add TOTP secret to Client Export PDF in Credential section.
- Add UserID on hover in users listing.
- Merge ticket now redirects to the new ticket details page.
- [Feature] Add Pay via saved card under invoice Listings.
- Ticket Related Side Items UI Cleanup to use btn-tool class.
## [25.11] Stable
### Deprecation Notice: ### Deprecation Notice:
- **Outdated CRON Scripts**: The following scripts are removed. - **Outdated CRON Scripts**: The following scripts are removed.

View File

@@ -4059,9 +4059,7 @@ if (LATEST_DATABASE_VERSION > CURRENT_DATABASE_VERSION) {
`contract_template_created_at` DATETIME DEFAULT CURRENT_TIMESTAMP, `contract_template_created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
`contract_template_updated_at` DATETIME NULL ON UPDATE CURRENT_TIMESTAMP, `contract_template_updated_at` DATETIME NULL ON UPDATE CURRENT_TIMESTAMP,
`contract_template_archived_at` DATETIME NULL DEFAULT NULL, `contract_template_archived_at` DATETIME NULL DEFAULT NULL
`company_id` INT(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;"); ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;");
@@ -4115,10 +4113,31 @@ if (LATEST_DATABASE_VERSION > CURRENT_DATABASE_VERSION) {
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '2.3.7'"); mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '2.3.7'");
} }
// if (CURRENT_DATABASE_VERSION == '2.3.7') { if (CURRENT_DATABASE_VERSION == '2.3.7') {
// // Insert queries here required to update to DB version 2.3.8
mysqli_query($mysqli, "
CREATE TABLE `asset_tags` (
`asset_tag_asset_id` INT(11) NOT NULL,
`asset_tag_tag_id` INT(11) NOT NULL,
PRIMARY KEY (`asset_tag_asset_id`, `asset_tag_tag_id`),
CONSTRAINT `fk_asset`
FOREIGN KEY (`asset_tag_asset_id`)
REFERENCES `assets`(`asset_id`)
ON DELETE CASCADE,
CONSTRAINT `fk_tag`
FOREIGN KEY (`asset_tag_tag_id`)
REFERENCES `tags`(`tag_id`)
ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
");
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '2.3.8'");
}
// if (CURRENT_DATABASE_VERSION == '2.3.8') {
// // Insert queries here required to update to DB version 2.3.9
// // Then, update the database to the next sequential version // // Then, update the database to the next sequential version
// mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '2.3.8'"); // mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '2.3.9'");
// } // }
} else { } else {

View File

@@ -502,6 +502,12 @@ if (file_exists($dbSqlFile)) {
]; ];
} }
// Duplicate checks
$duplicate_tickets_sql = mysqli_query($mysqli, "SELECT ticket_number, COUNT(*) AS count FROM tickets GROUP BY ticket_number HAVING count > 1");
$duplicate_quotes_sql = mysqli_query($mysqli, "SELECT quote_number, COUNT(*) AS count FROM quotes GROUP BY quote_number HAVING count > 1");
$duplicate_invoices_sql = mysqli_query($mysqli, "SELECT invoice_number, COUNT(*) AS count FROM invoices GROUP BY invoice_number HAVING count > 1");
$mysqli->close(); $mysqli->close();
?> ?>
@@ -758,6 +764,40 @@ $mysqli->close();
</table> </table>
</div> </div>
<!-- Duplicated ticket/quote/invoice numbers -->
<h3 class="mt-3">Duplicated Numbering</h3>
<h4>Tickets</h4>
<ul>
<?php if (mysqli_num_rows($duplicate_tickets_sql) > 0 ) {
while ($row = $duplicate_tickets_sql->fetch_assoc()) {
echo "<li>" . $config_ticket_prefix . nullable_htmlentities($row['ticket_number']) . " (" . $row['count'] . ")" . "</li>";
}
} else {
echo "No duplicate ticket numbers.";
} ?>
</ul>
<h4>Quotes</h4>
<ul>
<?php if (mysqli_num_rows($duplicate_quotes_sql) > 0 ) {
while ($row = $duplicate_quotes_sql->fetch_assoc()) {
echo "<li>" . $config_quote_prefix . nullable_htmlentities($row['quote_number']) . " (" . $row['count'] . ")" . "</li>";
}
} else {
echo "No duplicate quote numbers.";
} ?>
</ul>
<h4>Invoices</h4>
<ul>
<?php if (mysqli_num_rows($duplicate_invoices_sql) > 0 ) {
while ($row = $duplicate_invoices_sql->fetch_assoc()) {
echo "<li>" . $config_invoice_prefix . nullable_htmlentities($row['invoice_number']) . " (" . $row['count'] . ")" . "</li>";
}
} else {
echo "No duplicate invoice numbers.";
} ?>
</ul>
</div> </div>
</div> </div>

View File

@@ -110,12 +110,17 @@
<?php if ($config_module_enable_itdoc) { ?> <?php if ($config_module_enable_itdoc) { ?>
<li class="nav-header">TEMPLATES</li> <li class="nav-header">TEMPLATES</li>
<!-- 2025-11-16 JQ - Hide Contracts not yet ready
<li class="nav-item"> <li class="nav-item">
<a href="/admin/contract_templates.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'contract_templates.php' ? 'active' : ''); ?>"> <a href="/admin/contract_template.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'contract_template.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-file-contract"></i> <i class="nav-icon fas fa-file-contract"></i>
<p>Contract Templates</p> <p>
<span href="#" class="fas fa-plus-circle right ajax-modal" data-modal-url="/admin/modals/contract_template/contract_template_add.php" data-modal-size="lg"></span>
Contract Templates
</p>
</a> </a>
</li> </li>
-->
<li class="nav-item"> <li class="nav-item">
<a href="/admin/project_template.php" class="nav-link <?php echo (in_array(basename($_SERVER['PHP_SELF']), ['project_template.php', 'project_template_details.php']) ? 'active' : ''); ?>"> <a href="/admin/project_template.php" class="nav-link <?php echo (in_array(basename($_SERVER['PHP_SELF']), ['project_template.php', 'project_template_details.php']) ? 'active' : ''); ?>">
<i class="nav-icon fas fa-project-diagram"></i> <i class="nav-icon fas fa-project-diagram"></i>

View File

@@ -2,7 +2,9 @@
require_once '../../../includes/modal_header.php'; require_once '../../../includes/modal_header.php';
$category = nullable_htmlentities($_GET['category']); $category = nullable_htmlentities($_GET['category'] ?? '');
$category_types_array = ['Expense', 'Income', 'Referral', 'Ticket'];
?> ?>
@@ -13,10 +15,30 @@ $category = nullable_htmlentities($_GET['category']);
</button> </button>
</div> </div>
<form action="post.php" method="post" autocomplete="off"> <form action="post.php" method="post" autocomplete="off">
<input type="hidden" name="type" value="<?php echo ($category); ?>">
<div class="modal-body"> <div class="modal-body">
<?php if ($category) { ?>
<input type="hidden" name="type" value="<?= $category ?>">
<?php } else { ?>
<div class="form-group">
<label>Type <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-tag"></i></span>
</div>
<select class="form-control select2" name="type" required>
<option value="">- Select Type -</option>
<?php foreach ($category_types_array as $type_select) { ?>
<option><?= $type_select ?></option>
<?php } ?>
</select>
</div>
</div>
<?php } ?>
<div class="form-group"> <div class="form-group">
<label>Name <strong class="text-danger">*</strong></label> <label>Name <strong class="text-danger">*</strong></label>
<div class="input-group"> <div class="input-group">
@@ -39,7 +61,7 @@ $category = nullable_htmlentities($_GET['category']);
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="submit" name="add_category" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Create</button> <button type="submit" name="add_category" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Create Category</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Cancel</button> <button type="button" class="btn btn-light" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Cancel</button>
</div> </div>
</form> </form>

View File

@@ -1,15 +1,18 @@
<?php <?php
require_once '../../../includes/modal_header.php'; require_once '../../../includes/modal_header.php';
ob_start();
$contract_types_array = ['Fully Managed', 'Partialy Managed', 'Break/Fix']; $contract_types_array = ['Fully Managed', 'Partialy Managed', 'Break/Fix'];
$update_frequency_array = ['Manual', 'Annually', '2 Year', '3 Year', '5 Year', '7 Year']; $renewal_frequency_array = ['Manual', 'Annually', '2 Year', '3 Year', '5 Year', '7 Year'];
ob_start();
?> ?>
<div class="modal-header bg-dark"> <div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-file-contract mr-2"></i>New Contract Template</h5> <h5 class="modal-title"><i class="fa fa-fw fa-file-contract mr-2"></i>New Contract Template</h5>
<button type="button" class="close text-white" data-dismiss="modal"><span>&times;</span></button> <button type="button" class="close text-white" data-dismiss="modal"><span>&times;</span></button>
</div> </div>
<!-- Tabs Navigation --> <!-- Tabs Navigation -->
<ul class="modal-header nav nav-pills nav-justified"> <ul class="modal-header nav nav-pills nav-justified">
<li class="nav-item"> <li class="nav-item">
@@ -25,37 +28,62 @@ $update_frequency_array = ['Manual', 'Annually', '2 Year', '3 Year', '5 Year', '
<a class="nav-link" id="details-tab" data-toggle="tab" href="#details" role="tab">Details</a> <a class="nav-link" id="details-tab" data-toggle="tab" href="#details" role="tab">Details</a>
</li> </li>
</ul> </ul>
<form action="post.php" method="post" autocomplete="off"> <form action="post.php" method="post" autocomplete="off">
<div class="modal-body"> <div class="modal-body">
<div class="tab-content" id="contractTemplateTabContent"> <div class="tab-content" id="contractTemplateTabContent">
<!-- General Info Tab --> <!-- General Info Tab -->
<div class="tab-pane fade show active" id="general" role="tabpanel"> <div class="tab-pane fade show active" id="general" role="tabpanel">
<div class="form-group"> <div class="form-group">
<label>Template Name <strong class="text-danger">*</strong></label> <label>Template Name <strong class="text-danger">*</strong></label>
<input type="text" class="form-control" name="contract_template_name" placeholder="Contract Template Name" maxlength="200" required autofocus> <div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-file-contract"></i></span>
</div>
<input type="text" class="form-control" name="name" placeholder="Contract Template Name" maxlength="200" required autofocus>
</div>
</div>
<div class="form-group">
<label>Template Description <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-align-left"></i></span>
</div>
<input type="text" class="form-control" name="description"
placeholder="Contract Template Description" maxlength="200" required>
</div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label>Contract Type <strong class="text-danger">*</strong></label> <label>Contract Type <strong class="text-danger">*</strong></label>
<select class="form-control select2" name="contract_template_type" required> <div class="input-group">
<option value="">- Select Type -</option> <div class="input-group-prepend">
<?php foreach ($contract_types_array as $type) { ?> <span class="input-group-text"><i class="fa fa-fw fa-list"></i></span>
<option><?php echo $type; ?></option> </div>
<?php } ?> <select class="form-control select2" name="type" required>
</select> <option value="">- Select Type -</option>
<?php foreach ($contract_types_array as $type) { ?>
<option><?= $type ?></option>
<?php } ?>
</select>
</div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label>Update Frequency</label> <label>Renewal Frequency</label>
<select class="form-control select2" name="contract_template_update_frequency"> <div class="input-group">
<option value="">- Select Frequency -</option> <div class="input-group-prepend">
<?php foreach ($update_frequency_array as $freq) { ?> <span class="input-group-text"><i class="fa fa-fw fa-sync-alt"></i></span>
<option><?php echo $freq; ?></option> </div>
<?php } ?> <select class="form-control select2" name="renewal_frequency">
</select> <option value="">- Select Frequency -</option>
<?php foreach ($renewal_frequency_array as $renewal_frequency) { ?>
<option><?= $renewal_frequency ?></option>
<?php } ?>
</select>
</div>
</div> </div>
</div> </div>
@@ -64,33 +92,63 @@ $update_frequency_array = ['Manual', 'Annually', '2 Year', '3 Year', '5 Year', '
<div class="form-row"> <div class="form-row">
<div class="form-group col-md-6"> <div class="form-group col-md-6">
<label>Low Priority Response (hrs)</label> <label>Low Priority Response (hrs)</label>
<input type="number" class="form-control" name="sla_low_response_time" placeholder="e.g., 24"> <div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-clock"></i></span>
</div>
<input type="number" class="form-control" name="sla_low_response_time" placeholder="e.g., 24">
</div>
</div> </div>
<div class="form-group col-md-6"> <div class="form-group col-md-6">
<label>Low Priority Resolution (hrs)</label> <label>Low Priority Resolution (hrs)</label>
<input type="number" class="form-control" name="sla_low_resolution_time" placeholder="e.g., 48"> <div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-hourglass-half"></i></span>
</div>
<input type="number" class="form-control" name="sla_low_resolution_time" placeholder="e.g., 48">
</div>
</div> </div>
</div> </div>
<div class="form-row"> <div class="form-row">
<div class="form-group col-md-6"> <div class="form-group col-md-6">
<label>Medium Priority Response (hrs)</label> <label>Medium Priority Response (hrs)</label>
<input type="number" class="form-control" name="sla_medium_response_time" placeholder="e.g., 12"> <div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-clock"></i></span>
</div>
<input type="number" class="form-control" name="sla_medium_response_time" placeholder="e.g., 12">
</div>
</div> </div>
<div class="form-group col-md-6"> <div class="form-group col-md-6">
<label>Medium Priority Resolution (hrs)</label> <label>Medium Priority Resolution (hrs)</label>
<input type="number" class="form-control" name="sla_medium_resolution_time" placeholder="e.g., 24"> <div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-hourglass-half"></i></span>
</div>
<input type="number" class="form-control" name="sla_medium_resolution_time" placeholder="e.g., 24">
</div>
</div> </div>
</div> </div>
<div class="form-row"> <div class="form-row">
<div class="form-group col-md-6"> <div class="form-group col-md-6">
<label>High Priority Response (hrs)</label> <label>High Priority Response (hrs)</label>
<input type="number" class="form-control" name="sla_high_response_time" placeholder="e.g., 1"> <div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-bolt"></i></span>
</div>
<input type="number" class="form-control" name="sla_high_response_time" placeholder="e.g., 1">
</div>
</div> </div>
<div class="form-group col-md-6"> <div class="form-group col-md-6">
<label>High Priority Resolution (hrs)</label> <label>High Priority Resolution (hrs)</label>
<input type="number" class="form-control" name="sla_high_resolution_time" placeholder="e.g., 4"> <div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-stopwatch"></i></span>
</div>
<input type="number" class="form-control" name="sla_high_resolution_time" placeholder="e.g., 4">
</div>
</div> </div>
</div> </div>
</div> </div>
@@ -99,29 +157,49 @@ $update_frequency_array = ['Manual', 'Annually', '2 Year', '3 Year', '5 Year', '
<div class="tab-pane fade" id="rates" role="tabpanel"> <div class="tab-pane fade" id="rates" role="tabpanel">
<div class="form-group"> <div class="form-group">
<label>Standard Hourly Rate</label> <label>Standard Hourly Rate</label>
<input type="text" class="form-control" name="contract_template_hourly_rate" placeholder="e.g., 100"> <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="text" class="form-control" name="rate_standard" placeholder="e.g., 100">
</div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label>After Hours Hourly Rate</label> <label>After Hours Hourly Rate</label>
<input type="text" class="form-control" name="contract_template_after_hours_hourly_rate" placeholder="e.g., 150"> <div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-moon"></i></span>
</div>
<input type="text" class="form-control" name="rate_after_hours" placeholder="e.g., 150">
</div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label>Support Hours</label> <label>Support Hours</label>
<input type="text" class="form-control" name="contract_template_support_hours" placeholder="e.g., Mon-Fri 9am-5pm"> <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="text" class="form-control" name="support_hours" placeholder="e.g., Mon-Fri 9am-5pm">
</div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label>Net Terms</label> <label>Net Terms</label>
<input type="text" class="form-control" name="contract_template_net_terms" placeholder="e.g., Net 30"> <div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-file-invoice-dollar"></i></span>
</div>
<input type="text" class="form-control" name="net_terms" placeholder="e.g., Net 30">
</div>
</div> </div>
</div> </div>
<!-- Details Tab --> <!-- Details Tab -->
<div class="tab-pane fade" id="details" role="tabpanel"> <div class="tab-pane fade" id="details" role="tabpanel">
<div class="form-group"> <div class="form-group">
<textarea class="form-control tinymce" rows="6" name="contract_template_details" placeholder="Enter Contract Details"></textarea> <textarea class="form-control tinymce" rows="6" name="details" placeholder="Enter Contract Details"></textarea>
</div> </div>
</div> </div>
@@ -129,8 +207,12 @@ $update_frequency_array = ['Manual', 'Annually', '2 Year', '3 Year', '5 Year', '
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="submit" name="add_contract_template" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Create Template</button> <button type="submit" name="add_contract_template" class="btn btn-primary text-bold">
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Cancel</button> <i class="fa fa-check mr-2"></i>Create Template
</button>
<button type="button" class="btn btn-light" data-dismiss="modal">
<i class="fa fa-times mr-2"></i>Cancel
</button>
</div> </div>
</form> </form>

View File

@@ -0,0 +1,265 @@
<?php
require_once '../../../includes/modal_header.php';
$contract_template_id = intval($_GET['id']);
$contract_types_array = ['Fully Managed', 'Partialy Managed', 'Break/Fix'];
$update_frequency_array = ['Manual', 'Annually', '2 Year', '3 Year', '5 Year', '7 Year'];
// Fetch existing template
$sql = mysqli_query($mysqli, "SELECT * FROM contract_templates WHERE contract_template_id = $contract_template_id LIMIT 1");
$row = mysqli_fetch_array($sql);
// Assign locals
$name = nullable_htmlentities($row['contract_template_name']);
$description = nullable_htmlentities($row['contract_template_description']);
$type = nullable_htmlentities($row['contract_template_type']);
$renewal_frequency = nullable_htmlentities($row['contract_template_renewal_frequency']);
$sla_low_resp = intval($row['contract_template_sla_low_response_time']);
$sla_med_resp = intval($row['contract_template_sla_medium_response_time']);
$sla_high_resp = intval($row['contract_template_sla_high_response_time']);
$sla_low_res = intval($row['contract_template_sla_low_resolution_time']);
$sla_med_res = intval($row['contract_template_sla_medium_resolution_time']);
$sla_high_res = intval($row['contract_template_sla_high_resolution_time']);
$hourly_rate = intval($row['contract_template_rate_standard']);
$after_hours = intval($row['contract_template_rate_after_hours']);
$support_hours = nullable_htmlentities($row['contract_template_support_hours']);
$net_terms = intval($row['contract_template_net_terms']);
$details = nullable_htmlentities($row['contract_template_details']);
ob_start();
?>
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-file-contract mr-2"></i>Edit Contract Template</h5>
<button type="button" class="close text-white" data-dismiss="modal"><span>&times;</span></button>
</div>
<!-- Tabs Navigation -->
<ul class="modal-header nav nav-pills nav-justified">
<li class="nav-item">
<a class="nav-link active" id="general-tab" data-toggle="tab" href="#general" role="tab">General Info</a>
</li>
<li class="nav-item">
<a class="nav-link" id="sla-tab" data-toggle="tab" href="#sla" role="tab">SLA</a>
</li>
<li class="nav-item">
<a class="nav-link" id="rates-tab" data-toggle="tab" href="#rates" role="tab">Rates & Support</a>
</li>
<li class="nav-item">
<a class="nav-link" id="details-tab" data-toggle="tab" href="#details" role="tab">Details</a>
</li>
</ul>
<form action="post.php" method="post" autocomplete="off">
<input type="hidden" name="contract_template_id" value="<?php echo $contract_template_id; ?>">
<div class="modal-body">
<div class="tab-content" id="contractTemplateTabContent">
<!-- General Info Tab -->
<div class="tab-pane fade show active" id="general" role="tabpanel">
<div class="form-group">
<label>Template Name <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-file-contract"></i></span>
</div>
<input type="text" class="form-control" name="name"
placeholder="Contract Template Name" maxlength="200" required autofocus
value="<?= $name ?>">
</div>
</div>
<div class="form-group">
<label>Template Description <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-align-left"></i></span>
</div>
<input type="text" class="form-control" name="description"
placeholder="Contract Template Description" maxlength="200" required
value="<?= $description ?>">
</div>
</div>
<div class="form-group">
<label>Contract Type <strong class="text-danger">*</strong></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="type" required>
<option value="">- Select Type -</option>
<?php foreach ($contract_types_array as $type_select) { ?>
<option <?php if ($type == $type_select) { echo "selected"; } ?>><?= $type_select ?></option>
<?php } ?>
</select>
</div>
</div>
<div class="form-group">
<label>Renewal Frequency</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-sync-alt"></i></span>
</div>
<select class="form-control select2" name="renewal_frequency">
<option value="">- Select Frequency -</option>
<?php foreach ($renewal_frequency_array as $renewal_frequency_select) { ?>
<option <?php if ($renewal_frequency == $renewal_frequency_select) { echo "selected"; } ?>><?= $renewal_frequency_select ?></option>
<?php } ?>
</select>
</div>
</div>
</div>
<!-- SLA Tab -->
<div class="tab-pane fade" id="sla" role="tabpanel">
<div class="form-row">
<div class="form-group col-md-6">
<label>Low Priority Response (hrs)</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-clock"></i></span>
</div>
<input type="number" class="form-control" name="sla_low_response_time" placeholder="e.g., 24"
value="<?= $sla_low_resp ?>">
</div>
</div>
<div class="form-group col-md-6">
<label>Low Priority Resolution (hrs)</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-hourglass-half"></i></span>
</div>
<input type="number" class="form-control" name="sla_low_resolution_time" placeholder="e.g., 48"
value="<?= $sla_low_res ?>">
</div>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-6">
<label>Medium Priority Response (hrs)</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-clock"></i></span>
</div>
<input type="number" class="form-control" name="sla_medium_response_time" placeholder="e.g., 12"
value="<?= $sla_med_resp ?>">
</div>
</div>
<div class="form-group col-md-6">
<label>Medium Priority Resolution (hrs)</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-hourglass-half"></i></span>
</div>
<input type="number" class="form-control" name="sla_medium_resolution_time" placeholder="e.g., 24"
value="<?= $sla_med_res ?>">
</div>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-6">
<label>High Priority Response (hrs)</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-bolt"></i></span>
</div>
<input type="number" class="form-control" name="sla_high_response_time" placeholder="e.g., 1"
value="<?= $sla_high_resp ?>">
</div>
</div>
<div class="form-group col-md-6">
<label>High Priority Resolution (hrs)</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-stopwatch"></i></span>
</div>
<input type="number" class="form-control" name="sla_high_resolution_time" placeholder="e.g., 4"
value="<?= $sla_high_res ?>">
</div>
</div>
</div>
</div>
<!-- Rates & Support Tab -->
<div class="tab-pane fade" id="rates" role="tabpanel">
<div class="form-group">
<label>Standard Hourly Rate</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="text" class="form-control" name="rate_standard" placeholder="e.g., 100"
value="<?= $rate_standard ?>">
</div>
</div>
<div class="form-group">
<label>After Hours Hourly Rate</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-moon"></i></span>
</div>
<input type="text" class="form-control" name="rate_after_hours" placeholder="e.g., 150"
value="<?= $rate_after_hours ?>">
</div>
</div>
<div class="form-group">
<label>Support Hours</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="text" class="form-control" name="support_hours" placeholder="e.g., Mon-Fri 9am-5pm"
value="<?= $support_hours ?>">
</div>
</div>
<div class="form-group">
<label>Net Terms</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-file-invoice-dollar"></i></span>
</div>
<input type="text" class="form-control" name="net_terms" placeholder="e.g., Net 30"
value="<?= $net_terms ?>">
</div>
</div>
</div>
<!-- Details Tab -->
<div class="tab-pane fade" id="details" role="tabpanel">
<div class="form-group">
<label>Contract Details</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-align-left"></i></span>
</div>
<textarea class="form-control tinymce" rows="6" name="details"
placeholder="Enter Contract Details"><?= $details ?></textarea>
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" name="edit_contract_template" class="btn btn-primary text-bold">
<i class="fa fa-check mr-2"></i>Save Changes
</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';
?>

View File

@@ -22,7 +22,7 @@ ob_start();
</div> </div>
<form action="post.php" method="post" autocomplete="off"> <form action="post.php" method="post" autocomplete="off">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>"> <input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<input type="hidden" name="payment_method_id" value="<?= $payment_method_id ?>">
<div class="modal-body"> <div class="modal-body">
<div class="form-group"> <div class="form-group">

View File

@@ -59,7 +59,7 @@ ob_start();
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-shopping-cart"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-shopping-cart"></i></span>
</div> </div>
<input type="text" class="form-control" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,2}" name="threshold" placeholder="1000.00"> <input type="text" class="form-control" inputmode="decimal" pattern="[0-9]*\.?[0-9]{0,2}" name="threshold" placeholder="1000.00">
</div> </div>
<small class="form-text text-muted">Will not show as an option at Checkout if invoice amount is above this number, 0 disables the threshold check.</small> <small class="form-text text-muted">Will not show as an option at Checkout if invoice amount is above this number, 0 disables the threshold check.</small>
</div> </div>
@@ -79,7 +79,7 @@ ob_start();
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-percent"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-percent"></i></span>
</div> </div>
<input type="text" class="form-control" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,2}" name="percentage_fee" placeholder="Enter Percentage"> <input type="text" class="form-control" inputmode="decimal" pattern="[0-9]*\.?[0-9]{0,2}" name="percentage_fee" placeholder="Enter Percentage">
</div> </div>
<small class="form-text text-muted">See <a href="https://stripe.com/pricing" target="_blank">here <i class="fas fa-fw fa-external-link-alt"></i></a> for the latest Stripe Fees.</small> <small class="form-text text-muted">See <a href="https://stripe.com/pricing" target="_blank">here <i class="fas fa-fw fa-external-link-alt"></i></a> for the latest Stripe Fees.</small>
</div> </div>
@@ -90,7 +90,7 @@ ob_start();
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-shopping-cart"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-shopping-cart"></i></span>
</div> </div>
<input type="text" class="form-control" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,3}" name="flat_fee" placeholder="0.030"> <input type="text" class="form-control" inputmode="decimal" pattern="[0-9]*\.?[0-9]{0,3}" name="flat_fee" placeholder="0.030">
</div> </div>
<small class="form-text text-muted">See <a href="https://stripe.com/pricing" target="_blank">here <i class="fas fa-fw fa-external-link-alt"></i></a> for the latest Stripe Fees.</small> <small class="form-text text-muted">See <a href="https://stripe.com/pricing" target="_blank">here <i class="fas fa-fw fa-external-link-alt"></i></a> for the latest Stripe Fees.</small>
</div> </div>

View File

@@ -58,7 +58,7 @@ ob_start();
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-shopping-cart"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-shopping-cart"></i></span>
</div> </div>
<input type="text" class="form-control" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,2}" name="threshold" placeholder="1000.00" value="<?php echo $threshold; ?>"> <input type="text" class="form-control" inputmode="decimal" pattern="[0-9]*\.?[0-9]{0,2}" name="threshold" placeholder="1000.00" value="<?php echo $threshold; ?>">
</div> </div>
<small class="form-text text-muted">Will not show as an option at Checkout if above this number</small> <small class="form-text text-muted">Will not show as an option at Checkout if above this number</small>
</div> </div>
@@ -79,7 +79,7 @@ ob_start();
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-percent"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-percent"></i></span>
</div> </div>
<input type="text" class="form-control" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,2}" name="percentage_fee" value="<?php echo $percent_fee; ?>" placeholder="Enter Percentage"> <input type="text" class="form-control" inputmode="decimal" pattern="[0-9]*\.?[0-9]{0,2}" name="percentage_fee" value="<?php echo $percent_fee; ?>" placeholder="Enter Percentage">
</div> </div>
<small class="form-text text-muted">See <a href="https://stripe.com/pricing" target="_blank">here <i class="fas fa-fw fa-external-link-alt"></i></a> for the latest Stripe Fees.</small> <small class="form-text text-muted">See <a href="https://stripe.com/pricing" target="_blank">here <i class="fas fa-fw fa-external-link-alt"></i></a> for the latest Stripe Fees.</small>
</div> </div>
@@ -90,7 +90,7 @@ ob_start();
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-shopping-cart"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-shopping-cart"></i></span>
</div> </div>
<input type="text" class="form-control" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,3}" name="flat_fee" value="<?php echo $flat_fee; ?>" placeholder="0.030"> <input type="text" class="form-control" inputmode="decimal" pattern="[0-9]*\.?[0-9]{0,3}" name="flat_fee" value="<?php echo $flat_fee; ?>" placeholder="0.030">
</div> </div>
<small class="form-text text-muted">See <a href="https://stripe.com/pricing" target="_blank">here <i class="fas fa-fw fa-external-link-alt"></i></a> for the latest Stripe Fees.</small> <small class="form-text text-muted">See <a href="https://stripe.com/pricing" target="_blank">here <i class="fas fa-fw fa-external-link-alt"></i></a> for the latest Stripe Fees.</small>
</div> </div>

View File

@@ -15,6 +15,8 @@ if (isset($_GET['type'])) {
$type_display = "Contact"; $type_display = "Contact";
} elseif ($type === 4) { } elseif ($type === 4) {
$type_display = "Credential"; $type_display = "Credential";
} elseif ($type === 5) {
$type_display = "Asset";
} }
} }
ob_start(); ob_start();
@@ -58,6 +60,7 @@ ob_start();
<option value="2">Location Tag</option> <option value="2">Location Tag</option>
<option value="3">Contact Tag</option> <option value="3">Contact Tag</option>
<option value="4">Credential Tag</option> <option value="4">Credential Tag</option>
<option value="5">Asset Tag</option>
</select> </select>
</div> </div>
</div> </div>
@@ -86,7 +89,7 @@ ob_start();
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="submit" name="add_tag" class="btn btn-primary text-bold"><i class="fas fa-check mr-2"></i>Create</button> <button type="submit" name="add_tag" class="btn btn-primary text-bold"><i class="fas fa-check mr-2"></i>Create Tag</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fas fa-times mr-2"></i>Cancel</button> <button type="button" class="btn btn-light" data-dismiss="modal"><i class="fas fa-times mr-2"></i>Cancel</button>
</div> </div>
</form> </form>

View File

@@ -12,11 +12,24 @@ $tag_type = intval($row['tag_type']);
$tag_color = nullable_htmlentities($row['tag_color']); $tag_color = nullable_htmlentities($row['tag_color']);
$tag_icon = nullable_htmlentities($row['tag_icon']); $tag_icon = nullable_htmlentities($row['tag_icon']);
// Generate the HTML form content using output buffering. if ($tag_type == 1) {
$tag_type_display = "Client";
} elseif ( $tag_type == 2) {
$tag_type_display = "Location";
} elseif ( $tag_type == 3) {
$tag_type_display = "Contact";
} elseif ( $tag_type == 4) {
$tag_type_display = "Credential";
} elseif ( $tag_type == 5) {
$tag_type_display = "Asset";
} else {
$tag_type_display = "Unknown";
}
ob_start(); ob_start();
?> ?>
<div class="modal-header bg-dark"> <div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fas fa-fw fa-tag mr-2"></i>Editing tag: <strong><?php echo $tag_name; ?></strong></h5> <h5 class="modal-title"><i class="fas fa-fw fa-tag mr-2"></i><?= $tag_type_display ?> Tag: <strong><?php echo $tag_name; ?></strong></h5>
<button type="button" class="close text-white" data-dismiss="modal"> <button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span> <span>&times;</span>
</button> </button>
@@ -35,22 +48,6 @@ ob_start();
</div> </div>
</div> </div>
<div class="form-group">
<label>Type <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-th"></i></span>
</div>
<select class="form-control select2" name="type" required>
<option value="">- Type -</option>
<option value="1" <?php if ($tag_type == 1) { echo "selected"; } ?>>Client Tag</option>
<option value="2" <?php if ($tag_type == 2) { echo "selected"; } ?>>Location Tag</option>
<option value="3" <?php if ($tag_type == 3) { echo "selected"; } ?>>Contact Tag</option>
<option value="4" <?php if ($tag_type == 4) { echo "selected"; } ?>>Credential Tag</option>
</select>
</div>
</div>
<div class="form-group"> <div class="form-group">
<label>Color <strong class="text-danger">*</strong></label> <label>Color <strong class="text-danger">*</strong></label>
<div class="input-group"> <div class="input-group">
@@ -73,7 +70,7 @@ ob_start();
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="submit" name="edit_tag" class="btn btn-primary text-bold"><i class="fas fa-check mr-2"></i>Save</button> <button type="submit" name="edit_tag" class="btn btn-primary text-bold"><i class="fas fa-check mr-2"></i>Save changes</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fas fa-times mr-2"></i>Cancel</button> <button type="button" class="btn btn-light" data-dismiss="modal"><i class="fas fa-times mr-2"></i>Cancel</button>
</div> </div>
</form> </form>

View File

@@ -1,75 +1,79 @@
<div class="modal" id="addTicketTemplateModal" tabindex="-1"> <?php
<div class="modal-dialog modal-lg">
<div class="modal-content"> require_once '../../../includes/modal_header.php';
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-life-ring mr-2"></i>Creating Ticket Template</h5> ob_start();
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span> ?>
</button> <div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-life-ring mr-2"></i>New Ticket Template</h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="post.php" method="post" autocomplete="off">
<div class="modal-body">
<div class="form-group">
<label>Template Name <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-life-ring"></i></span>
</div>
<input type="text" class="form-control" name="name" placeholder="Template name" maxlength="200" required autofocus>
</div> </div>
<form action="post.php" method="post" autocomplete="off"> </div>
<div class="modal-body">
<div class="form-group"> <div class="form-group">
<label>Template Name <strong class="text-danger">*</strong></label> <label>Subject</label>
<div class="input-group"> <div class="input-group">
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-life-ring"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-angle-right"></i></span>
</div>
<input type="text" class="form-control" name="name" placeholder="Template name" maxlength="200" required autofocus>
</div>
</div>
<div class="form-group">
<label>Subject</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-angle-right"></i></span>
</div>
<input type="text" class="form-control" name="subject" placeholder="Subject" maxlength="500">
</div>
</div>
<div class="form-group">
<textarea class="form-control tinymceTicket" name="details"></textarea>
</div>
<div class="form-group">
<label>Description</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-angle-right"></i></span>
</div>
<input type="text" class="form-control" name="description" placeholder="Short description">
</div>
</div>
<div class="form-group">
<label>Add it to a Project Template?</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-project-diagram"></i></span>
</div>
<select class="form-control select2" name="project_template">
<option value="0">- No -</option>
<?php
$sql_project_templates = mysqli_query($mysqli, "SELECT * FROM project_templates WHERE project_template_archived_at IS NULL ORDER BY project_template_name ASC");
while ($row = mysqli_fetch_array($sql_project_templates)) {
$project_template_id_select = intval($row['project_template_id']);
$project_template_name_select = nullable_htmlentities($row['project_template_name']); ?>
<option value="<?php echo $project_template_id_select; ?>"><?php echo $project_template_name_select; ?></option>
<?php } ?>
</select>
</div>
</div>
</div> </div>
<div class="modal-footer"> <input type="text" class="form-control" name="subject" placeholder="Subject" maxlength="500">
<button type="submit" name="add_ticket_template" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Create</button> </div>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Cancel</button> </div>
<div class="form-group">
<textarea class="form-control tinymceTicket" name="details"></textarea>
</div>
<div class="form-group">
<label>Description</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-angle-right"></i></span>
</div> </div>
</form> <input type="text" class="form-control" name="description" placeholder="Short description">
</div>
</div>
<div class="form-group">
<label>Add it to a Project Template?</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-project-diagram"></i></span>
</div>
<select class="form-control select2" name="project_template">
<option value="0">- No -</option>
<?php
$sql_project_templates = mysqli_query($mysqli, "SELECT * FROM project_templates WHERE project_template_archived_at IS NULL ORDER BY project_template_name ASC");
while ($row = mysqli_fetch_array($sql_project_templates)) {
$project_template_id_select = intval($row['project_template_id']);
$project_template_name_select = nullable_htmlentities($row['project_template_name']); ?>
<option value="<?php echo $project_template_id_select; ?>"><?php echo $project_template_name_select; ?></option>
<?php } ?>
</select>
</div>
</div> </div>
</div> </div>
</div> <div class="modal-footer">
<button type="submit" name="add_ticket_template" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Create Template</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';

View File

@@ -106,12 +106,14 @@ $num_rows = mysqli_num_rows($sql);
<i class="fas fa-fw fa-edit mr-2"></i>Edit <i class="fas fa-fw fa-edit mr-2"></i>Edit
</a> </a>
<div class="dropdown-divider"></div> <div class="dropdown-divider"></div>
<!-- <a class="dropdown-item text-danger confirm-link" href="post.php?disable_payment_provider=--><?php //echo $provider_id; ?><!--&csrf_token=--><?php //echo $_SESSION['csrf_token'] ?><!--">--> <a class="dropdown-item text-danger confirm-link" href="post.php?delete_payment_provider=<?= $provider_id ?>&csrf_token=<?= $_SESSION['csrf_token'] ?>">
<!-- <i class="fas fa-fw fa-thumbs-down mr-2"></i>Disable--> <i class="fas fa-fw fa-trash mr-2"></i><strong>Delete Provider and</strong>
<!-- </a>--> <ul class="text-xs">
<!-- <a class="dropdown-item text-danger confirm-link" href="post.php?delete_payment_provider=--><?php //echo $provider_id; ?><!--&csrf_token=--><?php //echo $_SESSION['csrf_token'] ?><!--">--> <li>Related Recurring Payments</li>
<!-- <i class="fas fa-fw fa-trash mr-2"></i>Delete--> <li>Related Saved cards</li>
<!-- </a>--> <li>Client Provider Relations</li>
</ul>
</a>
</div> </div>
</div> </div>
</td> </td>

View File

@@ -9,11 +9,12 @@ defined('FROM_POST_HANDLER') || die("Direct file access is not allowed");
if (isset($_POST['add_contract_template'])) { if (isset($_POST['add_contract_template'])) {
// Sanitize text inputs // Sanitize text inputs
$name = sanitizeInput($_POST['contract_template_name']); $name = sanitizeInput($_POST['name']);
$type = sanitizeInput($_POST['contract_template_type']); $description = sanitizeInput($_POST['description']);
$update_frequency = sanitizeInput($_POST['contract_template_update_frequency']); $type = sanitizeInput($_POST['type']);
$support_hours = sanitizeInput($_POST['contract_template_support_hours']); $renewal_frequency = sanitizeInput($_POST['renewal_frequency']);
$details = mysql_escape_string($mysqli, $_POST['contract_template_details']); $support_hours = sanitizeInput($_POST['support_hours']);
$details = mysqli_escape_string($mysqli, $_POST['details']);
// Numeric fields cast to integer // Numeric fields cast to integer
$sla_low_resp = intval($_POST['sla_low_response_time']); $sla_low_resp = intval($_POST['sla_low_response_time']);
@@ -22,9 +23,9 @@ if (isset($_POST['add_contract_template'])) {
$sla_low_res = intval($_POST['sla_low_resolution_time']); $sla_low_res = intval($_POST['sla_low_resolution_time']);
$sla_med_res = intval($_POST['sla_medium_resolution_time']); $sla_med_res = intval($_POST['sla_medium_resolution_time']);
$sla_high_res = intval($_POST['sla_high_resolution_time']); $sla_high_res = intval($_POST['sla_high_resolution_time']);
$hourly_rate = intval($_POST['contract_template_hourly_rate']); $rate_standard = intval($_POST['rate_standard']);
$after_hours_rate = intval($_POST['contract_template_after_hours_hourly_rate']); $rate_after_hours = intval($_POST['hourly_rate_after_hours']);
$net_terms = intval($_POST['contract_template_net_terms']); $net_terms = intval($_POST['net_terms']);
// Insert into database (numbers not quoted) // Insert into database (numbers not quoted)
mysqli_query($mysqli, " mysqli_query($mysqli, "
@@ -33,19 +34,17 @@ if (isset($_POST['add_contract_template'])) {
contract_template_description = '$description', contract_template_description = '$description',
contract_template_details = '$details', contract_template_details = '$details',
contract_template_type = '$type', contract_template_type = '$type',
contract_template_update_frequency = '$update_frequency', contract_template_renewal_frequency = '$renewal_frequency',
sla_low_response_time = $sla_low_resp, contract_template_sla_low_response_time = $sla_low_resp,
sla_medium_response_time = $sla_med_resp, contract_template_sla_medium_response_time = $sla_med_resp,
sla_high_response_time = $sla_high_resp, contract_template_sla_high_response_time = $sla_high_resp,
sla_low_resolution_time = $sla_low_res, contract_template_sla_low_resolution_time = $sla_low_res,
sla_medium_resolution_time = $sla_med_res, contract_template_sla_medium_resolution_time = $sla_med_res,
sla_high_resolution_time = $sla_high_res, contract_template_sla_high_resolution_time = $sla_high_res,
contract_template_hourly_rate = $hourly_rate, contract_template_rate_standard = $rate_standard,
contract_template_after_hours_hourly_rate = $after_hours_rate, contract_template_rate_after_hours = $rate_after_hours,
contract_template_support_hours = '$support_hours', contract_template_support_hours = '$support_hours',
contract_template_net_terms = $net_terms, contract_template_net_terms = $net_terms
contract_template_created_by = $session_user_id,
contract_template_created_at = NOW()
"); ");
$contract_template_id = mysqli_insert_id($mysqli); $contract_template_id = mysqli_insert_id($mysqli);
@@ -60,4 +59,99 @@ if (isset($_POST['add_contract_template'])) {
redirect(); redirect();
} }
if (isset($_POST['edit_contract_template'])) {
$contract_template_id = intval($_POST['contract_template_id']);
$name = sanitizeInput($_POST['name']);
$description = sanitizeInput($_POST['description']);
$type = sanitizeInput($_POST['type']);
$renewal_frequency= sanitizeInput($_POST['renewal_frequency']);
$support_hours = sanitizeInput($_POST['support_hours']);
$details = mysqli_escape_string($mysqli, $_POST['details']);
$sla_low_resp = intval($_POST['sla_low_response_time']);
$sla_med_resp = intval($_POST['sla_medium_response_time']);
$sla_high_resp = intval($_POST['sla_high_response_time']);
$sla_low_res = intval($_POST['sla_low_resolution_time']);
$sla_med_res = intval($_POST['sla_medium_resolution_time']);
$sla_high_res = intval($_POST['sla_high_resolution_time']);
$rate_standard = intval($_POST['rate_standard']);
$rate_after_hours = intval($_POST['rate_after_hours']);
$net_terms = intval($_POST['net_terms']);
mysqli_query($mysqli, "
UPDATE contract_templates SET
contract_template_name = '$name',
contract_template_description = '$description',
contract_template_details = '$details',
contract_template_type = '$type',
contract_template_renewal_frequency = '$renewal_frequency',
contract_template_sla_low_response_time = $sla_low_resp,
contract_template_sla_medium_response_time = $sla_med_resp,
contract_template_sla_high_response_time = $sla_high_resp,
contract_template_sla_low_resolution_time = $sla_low_res,
contract_template_sla_medium_resolution_time = $sla_med_res,
contract_template_sla_high_resolution_time = $sla_high_res,
contract_template_rate_standard = $rate_standard,
contract_template_rate_after_hours = $rate_after_hours,
contract_template_support_hours = '$support_hours',
contract_template_net_terms = $net_terms
WHERE contract_template_id = $contract_template_id
");
// Log action
logAction("Contract Template", "Update", "$session_name updated contract template $name", 0, $contract_template_id);
// Flash + redirect
flash_alert("Contract Template <strong>$name</strong> updated");
redirect();
}
if (isset($_GET['archive_contract_template'])) {
$contract_template_id = intval($_GET['archive_contract_template']);
$name = getFieldById('contract_templates', $contract_template_id, 'contract_template_name');
mysqli_query($mysqli, "
UPDATE contract_templates SET contract_template_archived_at = NOW()
WHERE contract_template_id = $contract_template_id
LIMIT 1
");
logAction("Contract Template", "Archive", "$session_name archived contract template $name", 0, $contract_template_id);
flash_alert("Contract Template <strong>$name</strong> archived", "danger");
redirect();
}
if (isset($_GET['restore_contract_template'])) {
$contract_template_id = intval($_GET['restore_contract_template']);
$name = getFieldById('contract_templates', $contract_template_id, 'contract_template_name');
mysqli_query($mysqli, "
UPDATE contract_templates SET contract_template_archived_at = NULL
WHERE contract_template_id = $contract_template_id
LIMIT 1
");
logAction("Contract Template", "Restore", "$session_name restored contract template $name", 0, $contract_template_id);
flash_alert("Contract Template <strong>$name</strong> restored");
redirect();
}
if (isset($_GET['delete_contract_template'])) {
$contract_template_id = intval($_GET['delete_contract_template']);
$name = getFieldById('contract_templates', $contract_template_id, 'contract_template_name');
mysqli_query($mysqli, "
DELETE FROM contract_templates
WHERE contract_template_id = $contract_template_id
LIMIT 1
");
logAction("Contract Template", "Delete", "$session_name deleted contract template $name", 0, $contract_template_id);
flash_alert("Contract Template <strong>$name</strong> deleted", "danger");
redirect();
}
?> ?>

View File

@@ -8,12 +8,24 @@ if (isset($_POST['add_document_template'])) {
$name = sanitizeInput($_POST['name']); $name = sanitizeInput($_POST['name']);
$description = sanitizeInput($_POST['description']); $description = sanitizeInput($_POST['description']);
$content = mysqli_real_escape_string($mysqli,$_POST['content']);
mysqli_query($mysqli,"INSERT INTO document_templates SET document_template_name = '$name', document_template_description = '$description', document_template_content = '$content', document_template_created_by = $session_user_id"); mysqli_query($mysqli,"INSERT INTO document_templates SET document_template_name = '$name', document_template_description = '$description', document_template_content = '', document_template_created_by = $session_user_id");
$document_template_id = mysqli_insert_id($mysqli); $document_template_id = mysqli_insert_id($mysqli);
$processed_content = mysqli_escape_string(
$mysqli,
saveBase64Images(
$_POST['content'],
$_SERVER['DOCUMENT_ROOT'] . "/uploads/document_templates/",
"uploads/document_templates/",
$document_template_id
)
);
// Document template update content
mysqli_query($mysqli,"UPDATE document_templates SET document_template_content = '$processed_content' WHERE document_template_id = $document_template_id");
logAction("Document Template", "Create", "$session_name created document template $name", 0, $document_template_id); logAction("Document Template", "Create", "$session_name created document template $name", 0, $document_template_id);
flash_alert("Document template <strong>$name</strong> created"); flash_alert("Document template <strong>$name</strong> created");
@@ -27,10 +39,25 @@ if (isset($_POST['edit_document_template'])) {
$document_template_id = intval($_POST['document_template_id']); $document_template_id = intval($_POST['document_template_id']);
$name = sanitizeInput($_POST['name']); $name = sanitizeInput($_POST['name']);
$description = sanitizeInput($_POST['description']); $description = sanitizeInput($_POST['description']);
$content = mysqli_real_escape_string($mysqli,$_POST['content']);
$processed_content = saveBase64Images(
$_POST['content'],
$_SERVER['DOCUMENT_ROOT'] . "/uploads/document_templates/",
"uploads/document_templates/",
$document_template_id
);
$processed_content_escaped = mysqli_escape_string($mysqli, $processed_content);
// CLEAN UP unused images
cleanupUnusedImages(
$processed_content,
$_SERVER['DOCUMENT_ROOT'] . "/uploads/document_templates/" . $document_template_id,
"/uploads/document_templates/" . $document_template_id
);
// Document edit query // Document edit query
mysqli_query($mysqli,"UPDATE document_templates SET document_template_name = '$name', document_template_description = '$description', document_template_content = '$content', document_template_updated_by = $session_user_id WHERE document_template_id = $document_template_id"); mysqli_query($mysqli,"UPDATE document_templates SET document_template_name = '$name', document_template_description = '$description', document_template_content = '$processed_content_escaped', document_template_updated_by = $session_user_id WHERE document_template_id = $document_template_id");
logAction("Document Template", "Edit", "$session_name edited document template $name", 0, $document_template_id); logAction("Document Template", "Edit", "$session_name edited document template $name", 0, $document_template_id);
@@ -48,6 +75,9 @@ if (isset($_GET['delete_document_template'])) {
mysqli_query($mysqli,"DELETE FROM document_templates WHERE document_template_id = $document_template_id"); mysqli_query($mysqli,"DELETE FROM document_templates WHERE document_template_id = $document_template_id");
// Delete uploads/document_templates/$document_template_id if exists
removeDirectory($_SERVER['DOCUMENT_ROOT'] . "/uploads/document_templates/" . $document_template_id);
logAction("Document Template", "Delete", "$session_name deleted document template $document_template_name"); logAction("Document Template", "Delete", "$session_name deleted document template $document_template_name");
flash_alert("Document Template <strong>$document_template_name</strong> deleted", 'error'); flash_alert("Document Template <strong>$document_template_name</strong> deleted", 'error');

View File

@@ -10,10 +10,17 @@ if (isset($_POST['add_payment_method'])) {
validateCSRFToken($_POST['csrf_token']); validateCSRFToken($_POST['csrf_token']);
$name = sanitizeInput($_POST['name']); $name = cleanInput($_POST['name']);
$description = sanitizeInput($_POST['description']); $description = cleanInput($_POST['description']);
mysqli_query($mysqli,"INSERT INTO payment_methods SET payment_method_name = '$name', payment_method_description = '$description'"); $query = mysqli_prepare(
$mysqli, "INSERT INTO payment_methods
SET payment_method_name = ?, payment_method_description = ?"
);
mysqli_stmt_bind_param($query, "ss", $name, $description);
mysqli_stmt_execute($query);
logAction("Payment Method", "Create", "$session_name created Payment Method $name"); logAction("Payment Method", "Create", "$session_name created Payment Method $name");
@@ -28,10 +35,19 @@ if (isset($_POST['edit_payment_method'])) {
validateCSRFToken($_POST['csrf_token']); validateCSRFToken($_POST['csrf_token']);
$payment_method_id = intval($_POST['payment_method_id']); $payment_method_id = intval($_POST['payment_method_id']);
$name = sanitizeInput($_POST['name']); $name = cleanInput($_POST['name']);
$description = sanitizeInput($_POST['description']); $description = cleanInput($_POST['description']);
mysqli_query($mysqli,"UPDATE payment_methods SET payment_method_name = '$name', payment_method_description = '$description' WHERE payment_method_id = $payment_method_id"); $query = mysqli_prepare(
$mysqli,
"UPDATE payment_methods
SET payment_method_name = ?, payment_method_description = ?
WHERE payment_method_id = ?"
);
mysqli_stmt_bind_param($query, "ssi", $name, $description, $payment_method_id);
mysqli_stmt_execute($query);
logAction("Payment Method", "Edit", "$session_name edited Payment Method $name"); logAction("Payment Method", "Edit", "$session_name edited Payment Method $name");

View File

@@ -101,6 +101,11 @@ if (isset($_GET['delete_payment_provider'])) {
$provider_id = intval($_GET['delete_payment_provider']); $provider_id = intval($_GET['delete_payment_provider']);
// When deleted it cascades deletes
// all Recurring paymentes related to payment provider
// Delete all Saved Cards related
// Delete Client Payment Provider Releation
$provider_name = sanitizeInput(getFieldById('payment_providers', $provider_id, 'provider_name')); $provider_name = sanitizeInput(getFieldById('payment_providers', $provider_id, 'provider_name'));
// Delete provider // Delete provider

View File

@@ -42,7 +42,7 @@ if (isset($_GET['delete_saved_payment'])) {
try { try {
// Initialize stripe // Initialize stripe
require_once 'plugins/stripe-php/init.php'; require_once '../plugins/stripe-php/init.php';
$stripe = new \Stripe\StripeClient($private_key); $stripe = new \Stripe\StripeClient($private_key);
// Detach PM // Detach PM
@@ -56,7 +56,7 @@ if (isset($_GET['delete_saved_payment'])) {
} }
// Remove payment method from ITFlow // Remove payment method from ITFlow. This will also cascade delete related recurring payments setup
mysqli_query($mysqli, "DELETE FROM client_saved_payment_methods WHERE saved_payment_id = $saved_payment_id"); mysqli_query($mysqli, "DELETE FROM client_saved_payment_methods WHERE saved_payment_id = $saved_payment_id");
// SQL Cascade delete will Remove All Associated Auto Payment Methods on recurring invoices in the recurring payments table. // SQL Cascade delete will Remove All Associated Auto Payment Methods on recurring invoices in the recurring payments table.

View File

@@ -150,7 +150,7 @@ if (isset($_POST['test_email_smtp'])) {
$mail = addToMailQueue($data); $mail = addToMailQueue($data);
if ($mail === true) { if ($mail === true) {
flash_alert("Test email queued! <a class='text-bold text-light' href='admin_mail_queue.php'>Check Admin > Mail queue</a>"); flash_alert("Test email queued! <a class='text-bold text-light' href='mail_queue.php'>Check Admin > Mail queue</a>");
} else { } else {
flash_alert("Failed to add test mail to queue", 'error'); flash_alert("Failed to add test mail to queue", 'error');
} }
@@ -163,24 +163,125 @@ if (isset($_POST['test_email_imap'])) {
validateCSRFToken($_POST['csrf_token']); validateCSRFToken($_POST['csrf_token']);
// Setup your IMAP connection parameters $host = $config_imap_host;
$hostname = "{" . $config_imap_host . ":" . $config_imap_port . "/" . $config_imap_encryption . "/novalidate-cert}INBOX"; $port = (int) $config_imap_port;
$username = $config_imap_username; $encryption = strtolower(trim($config_imap_encryption)); // e.g. "ssl", "tls", "none"
$password = $config_imap_password; $username = $config_imap_username;
$password = $config_imap_password;
// Build remote socket (implicit SSL vs plain TCP)
$transport = 'tcp';
if ($encryption === 'ssl') {
$transport = 'ssl';
}
$remote_socket = $transport . '://' . $host . ':' . $port;
// Stream context (you can tighten these if you want strict validation)
$contextOptions = [];
if (in_array($encryption, ['ssl', 'tls'], true)) {
$contextOptions['ssl'] = [
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true,
];
}
$context = stream_context_create($contextOptions);
try { try {
$inbox = @imap_open($hostname, $username, $password); $errno = 0;
$errstr = '';
if ($inbox) { // 10-second timeout, adjust as needed
imap_close($inbox); $fp = @stream_socket_client(
$remote_socket,
$errno,
$errstr,
10,
STREAM_CLIENT_CONNECT,
$context
);
if (!$fp) {
throw new Exception("Could not connect to IMAP server: [$errno] $errstr");
}
stream_set_timeout($fp, 10);
// Read server greeting (IMAP servers send something like: * OK Dovecot ready)
$greeting = fgets($fp, 1024);
if ($greeting === false || strpos($greeting, '* OK') !== 0) {
fclose($fp);
throw new Exception("Invalid IMAP greeting: " . trim((string) $greeting));
}
// If you really want STARTTLS for "tls" (port 143), you can do it here
if ($encryption === 'tls' && stripos($greeting, 'STARTTLS') !== false) {
// Request STARTTLS
fwrite($fp, "A0001 STARTTLS\r\n");
$line = fgets($fp, 1024);
if ($line === false || stripos($line, 'A0001 OK') !== 0) {
fclose($fp);
throw new Exception("STARTTLS failed: " . trim((string) $line));
}
// Enable crypto on the stream
if (!stream_socket_enable_crypto($fp, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
fclose($fp);
throw new Exception("Unable to enable TLS encryption on IMAP connection.");
}
}
// --- Do LOGIN command ---
$tag = 'A0002';
// Simple quoting; this may fail with some special chars in username/password.
$loginCmd = sprintf(
"%s LOGIN \"%s\" \"%s\"\r\n",
$tag,
addcslashes($username, "\\\""),
addcslashes($password, "\\\"")
);
fwrite($fp, $loginCmd);
$success = false;
$errorLine = '';
while (!feof($fp)) {
$line = fgets($fp, 2048);
if ($line === false) {
break;
}
// Look for tagged response for our LOGIN
if (strpos($line, $tag . ' ') === 0) {
if (stripos($line, $tag . ' OK') === 0) {
$success = true;
} else {
$errorLine = trim($line);
}
break;
}
}
// Always logout / close
fwrite($fp, "A0003 LOGOUT\r\n");
fclose($fp);
if ($success) {
flash_alert("Connected successfully"); flash_alert("Connected successfully");
} else { } else {
throw new Exception(imap_last_error()); if (!$errorLine) {
$errorLine = 'Unknown IMAP authentication error';
}
throw new Exception($errorLine);
} }
} catch (Exception $e) { } catch (Exception $e) {
flash_alert("<strong>IMAP connection failed:</strong> " . $e->getMessage(), 'error'); flash_alert("<strong>IMAP connection failed:</strong> " . htmlspecialchars($e->getMessage()), 'error');
} }
redirect(); redirect();
} }

View File

@@ -28,7 +28,7 @@ if (isset($_POST['edit_tag'])) {
$tag_id = intval($_POST['tag_id']); $tag_id = intval($_POST['tag_id']);
mysqli_query($mysqli,"UPDATE tags SET tag_name = '$name', tag_type = $type, tag_color = '$color', tag_icon = '$icon' WHERE tag_id = $tag_id"); mysqli_query($mysqli,"UPDATE tags SET tag_name = '$name', tag_color = '$color', tag_icon = '$icon' WHERE tag_id = $tag_id");
logAction("Tag", "Edit", "$session_name edited tag $name", 0, $tag_id); logAction("Tag", "Edit", "$session_name edited tag $name", 0, $tag_id);

View File

@@ -214,7 +214,7 @@ require_once "includes/inc_all_admin.php";
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-clock"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-clock"></i></span>
</div> </div>
<input type="text" class="form-control" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,2}" name="hourly_rate" value="<?php echo number_format($config_default_hourly_rate, 2, '.', ''); ?>" placeholder="0.00" required> <input type="text" class="form-control" inputmode="decimal" pattern="[0-9]*\.?[0-9]{0,2}" name="hourly_rate" value="<?php echo number_format($config_default_hourly_rate, 2, '.', ''); ?>" placeholder="0.00" required>
</div> </div>
</div> </div>

View File

@@ -6,10 +6,31 @@ $order = "ASC";
require_once "includes/inc_all_admin.php"; require_once "includes/inc_all_admin.php";
if (isset($_GET['type'])) {
$type_filter = intval($_GET['type']);
} else {
$type_filter = 1;
}
if ($type_filter == 1) {
$tag_type_display = "Client";
} elseif ( $type_filter == 2) {
$tag_type_display = "Location";
} elseif ( $type_filter == 3) {
$tag_type_display = "Contact";
} elseif ( $type_filter == 4) {
$tag_type_display = "Credential";
} elseif ( $type_filter == 5) {
$tag_type_display = "Asset";
} else {
$tag_type_display = "Unknown";
}
$sql = mysqli_query( $sql = mysqli_query(
$mysqli, $mysqli,
"SELECT SQL_CALC_FOUND_ROWS * FROM tags "SELECT SQL_CALC_FOUND_ROWS * FROM tags
WHERE tag_name LIKE '%$q%' WHERE tag_name LIKE '%$q%'
AND tag_type = $type_filter
ORDER BY $sort $order LIMIT $record_from, $record_to" ORDER BY $sort $order LIMIT $record_from, $record_to"
); );
@@ -19,9 +40,9 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<div class="card card-dark"> <div class="card card-dark">
<div class="card-header py-2"> <div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fas fa-fw fa-tags mr-2"></i>Tags</h3> <h3 class="card-title mt-2"><i class="fas fa-fw fa-tags mr-2"></i><?= $tag_type_display ?> Tags</h3>
<div class="card-tools"> <div class="card-tools">
<button type="button" class="btn btn-primary ajax-modal" data-modal-url="modals/tag/tag_add.php"><i class="fas fa-plus mr-2"></i>New Tag</button> <button type="button" class="btn btn-primary ajax-modal" data-modal-url="modals/tag/tag_add.php?type=<?= $type_filter ?>"><i class="fas fa-plus mr-2"></i>New <?= $tag_type_display ?> Tag</button>
</div> </div>
</div> </div>
@@ -30,7 +51,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<div class="col-sm-4 mb-2"> <div class="col-sm-4 mb-2">
<form autocomplete="off"> <form autocomplete="off">
<div class="input-group"> <div class="input-group">
<input type="search" class="form-control" name="q" value="<?php if (isset($q)) { echo stripslashes(nullable_htmlentities($q)); } ?>" placeholder="Search Tags"> <input type="search" class="form-control" name="q" value="<?php if (isset($q)) { echo stripslashes(nullable_htmlentities($q)); } ?>" placeholder="Search <?= $tag_type_display ?> Tags">
<div class="input-group-append"> <div class="input-group-append">
<button class="btn btn-primary"><i class="fa fa-search"></i></button> <button class="btn btn-primary"><i class="fa fa-search"></i></button>
</div> </div>
@@ -38,6 +59,45 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
</form> </form>
</div> </div>
<div class="col-sm-8"> <div class="col-sm-8">
<div class="btn-group float-right">
<a href="?type=1"
class="btn <?php if ($type_filter == 1) {
echo 'btn-primary';
} else {
echo 'btn-default';
} ?>">Client</a>
<a href="?type=2"
class="btn <?php if ($type_filter == 2) {
echo 'btn-primary';
} else {
echo 'btn-default';
} ?>">Location</a>
<a href="?type=3"
class="btn <?php if ($type_filter == 3) {
echo 'btn-primary';
} else {
echo 'btn-default';
} ?>">Contact</a>
<a href="?type=4"
class="btn <?php if ($type_filter == 4) {
echo 'btn-primary';
} else {
echo 'btn-default';
} ?>">Credential</a>
<a href="?type=5"
class="btn <?php if ($type_filter == 5) {
echo 'btn-primary';
} else {
echo 'btn-default';
} ?>">Asset</a>
<a href="?<?= $url_query_strings_sort ?>&archived=1"
class="btn <?php if (isset($_GET['archived'])) {
echo 'btn-primary';
} else {
echo 'btn-default';
} ?>"><i
class="fas fa-fw fa-archive mr-2"></i>Archived</a>
</div>
</div> </div>
</div> </div>
@@ -51,11 +111,6 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
Name <?php if ($sort == 'tag_name') { echo $order_icon; } ?> Name <?php if ($sort == 'tag_name') { echo $order_icon; } ?>
</a> </a>
</th> </th>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=tag_type&order=<?php echo $disp; ?>">
Type <?php if ($sort == 'tag_type') { echo $order_icon; } ?>
</a>
</th>
<th class="text-center">Action</th> <th class="text-center">Action</th>
</tr> </tr>
</thead> </thead>
@@ -65,18 +120,6 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
while ($row = mysqli_fetch_array($sql)) { while ($row = mysqli_fetch_array($sql)) {
$tag_id = intval($row['tag_id']); $tag_id = intval($row['tag_id']);
$tag_name = nullable_htmlentities($row['tag_name']); $tag_name = nullable_htmlentities($row['tag_name']);
$tag_type = intval($row['tag_type']);
if ( $tag_type == 1) {
$tag_type_display = "Client Tag";
} elseif ( $tag_type == 2) {
$tag_type_display = "Location Tag";
} elseif ( $tag_type == 3) {
$tag_type_display = "Contact Tag";
} elseif ( $tag_type == 4) {
$tag_type_display = "Credential Tag";
} else {
$tag_type_display = "Unknown Tag";
}
$tag_color = nullable_htmlentities($row['tag_color']); $tag_color = nullable_htmlentities($row['tag_color']);
$tag_icon = nullable_htmlentities($row['tag_icon']); $tag_icon = nullable_htmlentities($row['tag_icon']);
@@ -88,7 +131,6 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<span class='badge text-light p-2 mr-1' style="background-color: <?php echo $tag_color; ?>"><i class="fa fa-fw fa-<?php echo $tag_icon; ?> mr-2"></i><?php echo $tag_name; ?></span> <span class='badge text-light p-2 mr-1' style="background-color: <?php echo $tag_color; ?>"><i class="fa fa-fw fa-<?php echo $tag_icon; ?> mr-2"></i><?php echo $tag_name; ?></span>
</a> </a>
</td> </td>
<td><?php echo $tag_type_display; ?></td>
<td> <td>
<div class="dropdown dropleft text-center"> <div class="dropdown dropleft text-center">
<button class="btn btn-secondary btn-sm" type="button" data-toggle="dropdown"> <button class="btn btn-secondary btn-sm" type="button" data-toggle="dropdown">
@@ -117,8 +159,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
</tbody> </tbody>
</table> </table>
</div> </div>
<?php require_once "../includes/filter_footer.php"; <?php require_once "../includes/filter_footer.php"; ?>
?>
</div> </div>
</div> </div>

View File

@@ -27,7 +27,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<div class="card-header py-2"> <div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fas fa-fw fa-life-ring mr-2"></i>Ticket Templates</h3> <h3 class="card-title mt-2"><i class="fas fa-fw fa-life-ring mr-2"></i>Ticket Templates</h3>
<div class="card-tools"> <div class="card-tools">
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addTicketTemplateModal"><i class="fas fa-plus mr-2"></i>New Ticket Template</button> <button type="button" class="btn btn-primary ajax-modal" data-modal-url="modals/ticket_template/ticket_template_add.php" data-modal-size="lg"><i class="fas fa-plus mr-2"></i>New Ticket Template</button>
</div> </div>
</div> </div>
<div class="card-body"> <div class="card-body">
@@ -120,5 +120,4 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
</div> </div>
<?php <?php
require_once "modals/ticket_template/ticket_template_add.php";
require_once "../includes/footer.php"; require_once "../includes/footer.php";

View File

@@ -156,7 +156,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
?> ?>
<tr> <tr>
<td class="text-center"> <td class="text-center">
<a href="#" <a href="#" title="UserID: <?= $user_id ?>"
<?php if ($user_id !== $session_user_id) { // Prevent modifying self ?> <?php if ($user_id !== $session_user_id) { // Prevent modifying self ?>
class="ajax-modal" class="ajax-modal"
data-modal-url="modals/user/user_edit.php?id=<?= $user_id ?>" data-modal-url="modals/user/user_edit.php?id=<?= $user_id ?>"

View File

@@ -140,7 +140,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
</a> </a>
<?php if ($session_user_role == 3) { ?> <?php if ($session_user_role == 3) { ?>
<div class="dropdown-divider"></div> <div class="dropdown-divider"></div>
<a class="dropdown-item text-danger text-bold confirm-link" href="post.php?delete_vendor=<?php echo $vendor_template_id; ?>"> <a class="dropdown-item text-danger text-bold confirm-link" href="post.php?delete_vendor_template=<?= $vendor_template_id ?>">
<i class="fas fa-fw fa-trash mr-2"></i>Delete <i class="fas fa-fw fa-trash mr-2"></i>Delete
</a> </a>
<?php } ?> <?php } ?>

View File

@@ -118,6 +118,28 @@ if (isset($_GET['asset_id'])) {
); );
$document_count = mysqli_num_rows($sql_related_documents); $document_count = mysqli_num_rows($sql_related_documents);
// Tags - many to many relationship
$asset_tag_name_display_array = array();
$asset_tag_id_array = array();
$sql_asset_tags = mysqli_query($mysqli, "SELECT * FROM asset_tags LEFT JOIN tags ON asset_tag_tag_id = tag_id WHERE asset_tag_asset_id = $asset_id ORDER BY tag_name ASC");
while ($row = mysqli_fetch_array($sql_asset_tags)) {
$asset_tag_id = intval($row['tag_id']);
$asset_tag_name = nullable_htmlentities($row['tag_name']);
$asset_tag_color = nullable_htmlentities($row['tag_color']);
if (empty($asset_tag_color)) {
$asset_tag_color = "dark";
}
$asset_tag_icon = nullable_htmlentities($row['tag_icon']);
if (empty($asset_tag_icon)) {
$asset_tag_icon = "tag";
}
$asset_tag_id_array[] = $asset_tag_id;
$asset_tag_name_display_array[] = "<a href='client_assets.php?client_id=$client_id&q=$asset_tag_name'><span class='badge text-light p-1 mr-1' style='background-color: $asset_tag_color;'><i class='fa fa-fw fa-$asset_tag_icon mr-2'></i>$asset_tag_name</span></a>";
}
$asset_tags_display = implode('', $asset_tag_name_display_array);
// Network Interfaces // Network Interfaces
$sql_related_interfaces = mysqli_query($mysqli, " $sql_related_interfaces = mysqli_query($mysqli, "
SELECT SELECT
@@ -257,8 +279,13 @@ if (isset($_GET['asset_id'])) {
<?php } ?> <?php } ?>
</div> </div>
<div class="card-body"> <div class="card-body">
<?php if ($asset_tags_display) { ?>
<div>
<?= $asset_tags_display ?>
</div>
<?php } ?>
<?php if ($asset_type) { ?> <?php if ($asset_type) { ?>
<div><i class="fa fa-fw fa-tag text-secondary mr-3"></i><?= $asset_type; ?></div> <div class="mt-1"><i class="fa fa-fw fa-tag text-secondary mr-3"></i><?= $asset_type; ?></div>
<?php } <?php }
if ($asset_make) { ?> if ($asset_make) { ?>
<div class="mt-2"><i class="fa fa-fw fa-circle text-secondary mr-3"></i><?= "$asset_make $asset_model"; ?></div> <div class="mt-2"><i class="fa fa-fw fa-circle text-secondary mr-3"></i><?= "$asset_make $asset_model"; ?></div>

View File

@@ -78,6 +78,18 @@ if ($client_url && isset($_GET['location']) && !empty($_GET['location'])) {
$location_filter = 0; $location_filter = 0;
} }
// Tags Filter
if (isset($_GET['tags']) && is_array($_GET['tags']) && !empty($_GET['tags'])) {
// Sanitize each element of the tags array
$sanitizedTags = array_map('intval', $_GET['tags']);
// Convert the sanitized tags into a comma-separated string
$tag_filter = implode(",", $sanitizedTags);
$tag_query = "AND tag_id IN ($tag_filter)";
} else {
$tag_filter = 0;
$tag_query = '';
}
//Get Asset Counts //Get Asset Counts
$row = mysqli_fetch_assoc(mysqli_query($mysqli, " $row = mysqli_fetch_assoc(mysqli_query($mysqli, "
SELECT SELECT
@@ -93,9 +105,13 @@ $row = mysqli_fetch_assoc(mysqli_query($mysqli, "
LEFT JOIN contacts ON asset_contact_id = contact_id LEFT JOIN contacts ON asset_contact_id = contact_id
LEFT JOIN locations ON asset_location_id = location_id LEFT JOIN locations ON asset_location_id = location_id
LEFT JOIN asset_interfaces ON interface_asset_id = asset_id AND interface_primary = 1 LEFT JOIN asset_interfaces ON interface_asset_id = asset_id AND interface_primary = 1
LEFT JOIN asset_tags ON asset_tag_asset_id = asset_id
LEFT JOIN tags ON tag_id = asset_tag_tag_id
WHERE $archive_query WHERE $archive_query
$tag_query
$access_permission_query $access_permission_query
$client_query $client_query
GROUP BY asset_id
) AS filtered_assets; ) AS filtered_assets;
")); "));
@@ -117,9 +133,6 @@ $network_count = intval($row['network_count']);
//Other Count //Other Count
$other_count = intval($row['other_count']); $other_count = intval($row['other_count']);
//Rebuild URL
$url_query_strings_sort = http_build_query($get_copy);
$sql = mysqli_query( $sql = mysqli_query(
$mysqli, $mysqli,
"SELECT SQL_CALC_FOUND_ROWS * FROM assets "SELECT SQL_CALC_FOUND_ROWS * FROM assets
@@ -127,13 +140,16 @@ $sql = mysqli_query(
LEFT JOIN contacts ON asset_contact_id = contact_id LEFT JOIN contacts ON asset_contact_id = contact_id
LEFT JOIN locations ON asset_location_id = location_id LEFT JOIN locations ON asset_location_id = location_id
LEFT JOIN asset_interfaces ON interface_asset_id = asset_id AND interface_primary = 1 LEFT JOIN asset_interfaces ON interface_asset_id = asset_id AND interface_primary = 1
LEFT JOIN asset_tags ON asset_tag_asset_id = asset_id
LEFT JOIN tags ON tag_id = asset_tag_tag_id
WHERE $archive_query WHERE $archive_query
AND (asset_name LIKE '%$q%' OR asset_description LIKE '%$q%' OR asset_type LIKE '%$q%' OR interface_ip LIKE '%$q%' OR interface_ipv6 LIKE '%$q%' OR interface_mac LIKE '%$q%' OR asset_make LIKE '%$q%' OR asset_model LIKE '%$q%' OR asset_serial LIKE '%$q%' OR asset_os LIKE '%$q%' OR contact_name LIKE '%$q%' OR location_name LIKE '%$q%' OR client_name LIKE '%$q%') $tag_query
AND (asset_name LIKE '%$q%' OR asset_description LIKE '%$q%' OR asset_type LIKE '%$q%' OR interface_ip LIKE '%$q%' OR interface_ipv6 LIKE '%$q%' OR interface_mac LIKE '%$q%' OR asset_make LIKE '%$q%' OR asset_model LIKE '%$q%' OR asset_serial LIKE '%$q%' OR asset_os LIKE '%$q%' OR contact_name LIKE '%$q%' OR location_name LIKE '%$q%' OR client_name LIKE '%$q%' OR tag_name LIKE '%$q%')
AND ($type_query) AND ($type_query)
$access_permission_query $access_permission_query
$location_query $location_query
$client_query $client_query
GROUP BY asset_id
ORDER BY $sort $order LIMIT $record_from, $record_to" ORDER BY $sort $order LIMIT $record_from, $record_to"
); );
@@ -270,7 +286,32 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
</div> </div>
</div> </div>
<?php } ?> <?php } ?>
<div class="col-md-3"> <div class="col-md-2">
<div class="input-group mb-3 mb-md-0">
<select onchange="this.form.submit()" class="form-control select2" name="tags[]" data-placeholder="- Select Tags -" multiple>
<?php
$sql_tags_filter = mysqli_query($mysqli, "
SELECT tag_id, tag_name
FROM tags
LEFT JOIN asset_tags ON asset_tag_tag_id = tag_id
LEFT JOIN assets ON asset_tag_asset_id = asset_id
WHERE tag_type = 5
$client_query OR tag_id IN ($tag_filter)
GROUP BY tag_id
HAVING COUNT(asset_tag_asset_id) > 0 OR tag_id IN ($tag_filter)
");
while ($row = mysqli_fetch_array($sql_tags_filter)) {
$tag_id = intval($row['tag_id']);
$tag_name = nullable_htmlentities($row['tag_name']); ?>
<option value="<?php echo $tag_id ?>" <?php if (isset($_GET['tags']) && in_array($tag_id, $_GET['tags'])) { echo 'selected'; } ?>> <?php echo $tag_name ?> </option>
<?php } ?>
</select>
</div>
</div>
<div class="col-md-2">
<div class="form-group"> <div class="form-group">
<select onchange="this.form.submit()" class="form-control select2" name="show_column[]" data-placeholder="- Show Additional Columns -" multiple> <select onchange="this.form.submit()" class="form-control select2" name="show_column[]" data-placeholder="- Show Additional Columns -" multiple>
<option <option
@@ -291,7 +332,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
</select> </select>
</div> </div>
</div> </div>
<div class="col-md-3"> <div class="col-md-2">
<div class="btn-group float-right"> <div class="btn-group float-right">
<a href="?<?php echo $client_url; ?>&archived=<?php if($archived == 1){ echo 0; } else { echo 1; } ?>" <a href="?<?php echo $client_url; ?>&archived=<?php if($archived == 1){ echo 0; } else { echo 1; } ?>"
class="btn btn-<?php if($archived == 1){ echo "primary"; } else { echo "default"; } ?>"> class="btn btn-<?php if($archived == 1){ echo "primary"; } else { echo "default"; } ?>">
@@ -314,7 +355,14 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
data-bulk="true"> data-bulk="true">
<i class="fas fa-fw fa-map-marker-alt mr-2"></i>Assign Location <i class="fas fa-fw fa-map-marker-alt mr-2"></i>Assign Location
</a> </a>
<div class="dropdown-divider"></div>
<?php } ?> <?php } ?>
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/asset/asset_bulk_assign_tags.php"
data-bulk="true">
<i class="fas fa-fw fa-tags mr-2"></i>Assign Tags
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item ajax-modal" href="#" <a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/asset/asset_bulk_assign_physical_location.php" data-modal-url="modals/asset/asset_bulk_assign_physical_location.php"
data-bulk="true"> data-bulk="true">
@@ -576,20 +624,48 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
$sql_credentials = mysqli_query($mysqli, "SELECT * FROM credentials WHERE credential_asset_id = $asset_id"); $sql_credentials = mysqli_query($mysqli, "SELECT * FROM credentials WHERE credential_asset_id = $asset_id");
$credential_count = mysqli_num_rows($sql_credentials); $credential_count = mysqli_num_rows($sql_credentials);
// Tags
$asset_tag_name_display_array = array();
$asset_tag_id_array = array();
$sql_asset_tags = mysqli_query($mysqli, "SELECT * FROM asset_tags LEFT JOIN tags ON asset_tag_tag_id = tag_id WHERE asset_tag_asset_id = $asset_id ORDER BY tag_name ASC");
while ($row = mysqli_fetch_array($sql_asset_tags)) {
$asset_tag_id = intval($row['tag_id']);
$asset_tag_name = nullable_htmlentities($row['tag_name']);
$asset_tag_color = nullable_htmlentities($row['tag_color']);
if (empty($asset_tag_color)) {
$asset_tag_color = "dark";
}
$asset_tag_icon = nullable_htmlentities($row['tag_icon']);
if (empty($asset_tag_icon)) {
$asset_tag_icon = "tag";
}
$asset_tag_id_array[] = $asset_tag_id;
$asset_tag_name_display_array[] = "<a href='assets.php?$client_url tags[]=$asset_tag_id'><span class='badge text-light p-1 mr-1' style='background-color: $asset_tag_color;'><i class='fa fa-fw fa-$asset_tag_icon mr-2'></i>$asset_tag_name</span></a>";
}
$asset_tags_display = implode('', $asset_tag_name_display_array);
?> ?>
<tr> <tr>
<td class="pr-0 bg-light"> <td class="pr-0 bg-light">
<div class="form-check"> <div class="form-check">
<input class="form-check-input bulk-select" type="checkbox" name="asset_ids[]" value="<?php echo $asset_id ?>"> <input class="form-check-input bulk-select" type="checkbox" name="asset_ids[]" value="<?= $asset_id ?>">
</div> </div>
</td> </td>
<td> <td>
<a class="text-dark" href="asset_details.php?client_id=<?php echo $client_id; ?>&asset_id=<?php echo $asset_id; ?>"> <a class="text-dark" href="asset_details.php?client_id=<?= $client_id ?>&asset_id=<?= $asset_id ?>">
<div class="media"> <div class="media">
<i class="fa fa-fw fa-2x fa-<?php echo $device_icon; ?> mr-3 mt-1"></i> <i class="fa fa-fw fa-2x fa-<?= $device_icon ?> mr-3 mt-1"></i>
<div class="media-body"> <div class="media-body">
<div><?php echo $asset_name; ?></div> <div><?= $asset_name ?></div>
<div><small class="text-secondary"><?php echo $asset_description; ?></small></div> <div><small class="text-secondary"><?= $asset_description ?></small></div>
<?php
if ($asset_tags_display) { ?>
<div class="mt-1">
<?= $asset_tags_display ?>
</div>
<?php } ?>
</div> </div>
</div> </div>
</a> </a>

View File

@@ -64,7 +64,14 @@ if (isset($_GET['contact_id'])) {
} }
// Related Assets Query - 1 to 1 relationship // Related Assets Query - 1 to 1 relationship
$sql_related_assets = mysqli_query($mysqli, "SELECT * FROM assets LEFT JOIN asset_interfaces ON interface_asset_id = asset_id AND interface_primary = 1 WHERE asset_contact_id = $contact_id ORDER BY asset_name DESC"); $sql_related_assets = mysqli_query($mysqli, "SELECT * FROM assets
LEFT JOIN asset_interfaces ON interface_asset_id = asset_id AND interface_primary = 1
LEFT JOIN asset_tags ON asset_tag_asset_id = asset_id
LEFT JOIN tags ON tag_id = asset_tag_tag_id
WHERE asset_contact_id = $contact_id
GROUP BY asset_id
ORDER BY asset_name ASC"
);
$asset_count = mysqli_num_rows($sql_related_assets); $asset_count = mysqli_num_rows($sql_related_assets);
// Linked Software Licenses // Linked Software Licenses
@@ -90,7 +97,7 @@ if (isset($_GET['contact_id'])) {
LEFT JOIN tags ON tags.tag_id = credential_tags.tag_id LEFT JOIN tags ON tags.tag_id = credential_tags.tag_id
WHERE credential_contact_id = $contact_id WHERE credential_contact_id = $contact_id
GROUP BY credentials.credential_id GROUP BY credentials.credential_id
ORDER BY credential_name DESC ORDER BY credential_name ASC
"); ");
$credential_count = mysqli_num_rows($sql_related_credentials); $credential_count = mysqli_num_rows($sql_related_credentials);
@@ -401,6 +408,28 @@ if (isset($_GET['contact_id'])) {
$asset_created_at = nullable_htmlentities($row['asset_created_at']); $asset_created_at = nullable_htmlentities($row['asset_created_at']);
$device_icon = getAssetIcon($asset_type); $device_icon = getAssetIcon($asset_type);
// Tags
$asset_tag_name_display_array = array();
$asset_tag_id_array = array();
$sql_asset_tags = mysqli_query($mysqli, "SELECT * FROM asset_tags LEFT JOIN tags ON asset_tag_tag_id = tag_id WHERE asset_tag_asset_id = $asset_id ORDER BY tag_name ASC");
while ($row = mysqli_fetch_array($sql_asset_tags)) {
$asset_tag_id = intval($row['tag_id']);
$asset_tag_name = nullable_htmlentities($row['tag_name']);
$asset_tag_color = nullable_htmlentities($row['tag_color']);
if (empty($asset_tag_color)) {
$asset_tag_color = "dark";
}
$asset_tag_icon = nullable_htmlentities($row['tag_icon']);
if (empty($asset_tag_icon)) {
$asset_tag_icon = "tag";
}
$asset_tag_id_array[] = $asset_tag_id;
$asset_tag_name_display_array[] = "<a href='assets.php?$client_url tags[]=$asset_tag_id'><span class='badge text-light p-1 mr-1' style='background-color: $asset_tag_color;'><i class='fa fa-fw fa-$asset_tag_icon mr-2'></i>$asset_tag_name</span></a>";
}
$asset_tags_display = implode('', $asset_tag_name_display_array);
?> ?>
<tr> <tr>
<th> <th>
@@ -413,6 +442,12 @@ if (isset($_GET['contact_id'])) {
<div class="mt-0"> <div class="mt-0">
<small class="text-muted"><?php echo $asset_description; ?></small> <small class="text-muted"><?php echo $asset_description; ?></small>
</div> </div>
<?php
if ($asset_tags_display) { ?>
<div class="mt-1">
<?= $asset_tags_display ?>
</div>
<?php } ?>
</th> </th>
<td><?php echo $asset_type; ?></td> <td><?php echo $asset_type; ?></td>
<td> <td>

View File

@@ -729,13 +729,22 @@ if ($user_config_dashboard_technical_enable == 1) {
$client_name = nullable_htmlentities($row['client_name']); $client_name = nullable_htmlentities($row['client_name']);
$contact_id = intval($row['ticket_contact_id']); $contact_id = intval($row['ticket_contact_id']);
$contact_name = nullable_htmlentities($row['contact_name']); $contact_name = nullable_htmlentities($row['contact_name']);
if ($client_id) {
$has_client = "&client_id=$client_id";
} else {
$has_client = "";
}
$ticket_priority_color = $ticket_priority == "High" ? "danger" : ($ticket_priority == "Medium" ? "warning" : "info"); $ticket_priority_color = $ticket_priority == "High" ? "danger" : ($ticket_priority == "Medium" ? "warning" : "info");
$contact_display = empty($contact_name) ? "-" : "<a href='contact_details.php?client_id=$client_id&contact_id=$contact_id'>$contact_name</a>"; $contact_display = empty($contact_name) ? "-" : "<a href='contact_details.php?client_id=$client_id&contact_id=$contact_id'>$contact_name</a>";
?> ?>
<tr class="<?php echo empty($ticket_updated_at) ? 'text-bold' : ''; ?>"> <tr class="<?php echo empty($ticket_updated_at) ? 'text-bold' : ''; ?>">
<td><a class="text-dark" href="ticket.php?client_id=<?= $client_id ?>&ticket_id=<?php echo $ticket_id; ?>"><?php echo "$ticket_prefix$ticket_number"; ?></a></td> <td>
<td><a href="ticket.php?client_id=<?= $client_id ?>&ticket_id=<?php echo $ticket_id; ?>"><?php echo $ticket_subject; ?></a></td> <a class="text-dark"
href="ticket.php?ticket_id=<?= "$ticket_id$has_client" ?>"><?= "$ticket_prefix$ticket_number" ?>
</a>
</td>
<td><a href="ticket.php?ticket_id=<?= "$ticket_id$has_client" ?>"><?= $ticket_subject ?></a></td>
<td><a href="tickets.php?client_id=<?php echo $client_id; ?>"><strong><?php echo $client_name; ?></strong></a></td> <td><a href="tickets.php?client_id=<?php echo $client_id; ?>"><strong><?php echo $client_name; ?></strong></a></td>
<td><?php echo $contact_display; ?></td> <td><?php echo $contact_display; ?></td>
<td><span class='p-2 badge badge-pill badge-<?php echo $ticket_priority_color; ?>'><?php echo $ticket_priority; ?></span></td> <td><span class='p-2 badge badge-pill badge-<?php echo $ticket_priority_color; ?>'><?php echo $ticket_priority; ?></span></td>

View File

@@ -104,18 +104,31 @@ $page_title = $row['document_name'];
<div class="col-md-9"> <div class="col-md-9">
<div class="card"> <div class="card">
<div class="card-header bg-dark"> <div class="card-header bg-dark">
<h3><?php echo $document_name; ?> <?php if (!empty($document_description)) { ?><span class="h6 text-muted">(<?php echo $document_description; ?>)</span><?php } ?></h3>
<div class="row"> <div class="row">
<div class="col"><strong>Date:</strong> <?php echo date('Y-m-d', strtotime($document_created_at)); ?></div> <div class="col">
<?php if(!empty($document_created_by_name)){ ?> <div class="h4 mb-0"><?= $document_name ?></div>
<div class="col"><strong>Prepared By:</strong> <?php echo $document_created_by_name; ?></div> <?php if ($document_description) { ?>
<?php } ?> <div class="text-light"><?= $document_description ?></div>
<?php } ?>
</div>
<div class="col">
<div class="float-right">
<div>
Date:
<strong><?= date('Y-m-d', strtotime($document_created_at)); ?></strong>
</div>
<?php if($document_created_by_name) { ?>
<div>
Prepared By:
<strong><?= $document_created_by_name ?></strong>
</div>
<?php } ?>
</div>
</div>
</div> </div>
</div> </div>
<div class="card-body prettyContent"> <div class="card-body prettyContent">
<?php echo $document_content; ?> <?= $document_content ?>
<hr> <hr>
<h4>Documentation Revision History</h4> <h4>Documentation Revision History</h4>
@@ -151,11 +164,11 @@ $page_title = $row['document_name'];
?> ?>
<tr> <tr>
<td><?php echo $document_version_count; ?></td> <td><?= $document_version_count ?></td>
<td><?php echo $document_version_created_date; ?></td> <td><?= $document_version_created_date ?></td>
<td><?php echo $document_version_name; ?></td> <td><?= $document_version_name ?></td>
<td><?php echo $document_version_description_display; ?></td> <td><?= $document_version_description_display ?></td>
<td><?php echo $document_version_author; ?></td> <td><?= $document_version_author ?></td>
</tr> </tr>
<?php <?php
$document_version_count++; // Increment the counter $document_version_count++; // Increment the counter
@@ -176,10 +189,10 @@ $page_title = $row['document_name'];
<i class="fas fa-fw fa-edit" title="Edit"></i> <i class="fas fa-fw fa-edit" title="Edit"></i>
</button> </button>
<button type="button" class="btn btn-secondary mr-1" data-toggle="modal" data-target="#shareModal" <button type="button" class="btn btn-secondary mr-1" data-toggle="modal" data-target="#shareModal"
onclick="populateShareModal(<?php echo "$client_id, 'Document', $document_id"; ?>)"> onclick="populateShareModal(<?= "$client_id, 'Document', $document_id"; ?>)">
<i class="fas fa-fw fa-share" title="Share"></i> <i class="fas fa-fw fa-share" title="Share"></i>
</button> </button>
<a class="btn btn-success mr-1" href="post.php?export_document=<?php echo $document_id; ?>"><i class='fas fa-fw fa-file-pdf' title="PDF Export"></i></a> <a class="btn btn-success mr-1" href="post.php?export_document=<?= $document_id ?>"><i class='fas fa-fw fa-file-pdf' title="PDF Export"></i></a>
<button type="button" class="btn btn-secondary mr-4" onclick="window.print();"><i class="fas fa-fw fa-print" title="Print"></i></button> <button type="button" class="btn btn-secondary mr-4" onclick="window.print();"><i class="fas fa-fw fa-print" title="Print"></i></button>
<a class="btn btn-warning mr-1 confirm-link" href="post.php?archive_document=<?= $document_id ?>" title="Archive"><i class='fas fa-fw fa-archive'></i></a> <a class="btn btn-warning mr-1 confirm-link" href="post.php?archive_document=<?= $document_id ?>" title="Archive"><i class='fas fa-fw fa-archive'></i></a>
<a class="btn btn-danger confirm-link" href="post.php?delete_document=<?= $document_id ?>&from=document_details" title="Delete"><i class='fas fa-fw fa-trash-alt'></i></a> <a class="btn btn-danger confirm-link" href="post.php?delete_document=<?= $document_id ?>&from=document_details" title="Delete"><i class='fas fa-fw fa-trash-alt'></i></a>

View File

@@ -23,9 +23,6 @@ if (!empty($q)) {
$query_snippet = ""; // empty $query_snippet = ""; // empty
} }
//Rebuild URL
$url_query_strings_sort = http_build_query($get_copy);
// Folder ID // Folder ID
$get_folder_id = 0; $get_folder_id = 0;
if (!empty($_GET['folder_id'])) { if (!empty($_GET['folder_id'])) {

File diff suppressed because it is too large Load Diff

622
agent/files_legacy.php Normal file
View File

@@ -0,0 +1,622 @@
<?php
// Default Column Sortby Filter
$sort = "file_name";
$order = "ASC";
require_once "includes/inc_all_client.php";
// Folder
if (!empty($_GET['folder_id'])) {
$folder_id = intval($_GET['folder_id']);
} else {
$folder_id = 0;
}
// Folder ID
$get_folder_id = 0;
if (!empty($_GET['folder_id'])) {
$get_folder_id = intval($_GET['folder_id']);
}
// View Mode -- 0 List, 1 Thumbnail
if (!empty($_GET['view'])) {
$view = intval($_GET['view']);
} else {
$view = 0;
}
if ($view == 1) {
$query_images = "AND (file_ext LIKE 'JPG' OR file_ext LIKE 'jpg' OR file_ext LIKE 'JPEG' OR file_ext LIKE 'jpeg' OR file_ext LIKE 'png' OR file_ext LIKE 'PNG' OR file_ext LIKE 'webp' OR file_ext LIKE 'WEBP')";
} else {
$query_images = '';
}
// Set Folder Location Var used when creating folders
$folder_location = 1;
if ($get_folder_id == 0 && isset($_GET["q"])) {
$sql = mysqli_query(
$mysqli,
"SELECT SQL_CALC_FOUND_ROWS * FROM files
LEFT JOIN users ON file_created_by = user_id
WHERE file_client_id = $client_id
AND file_archived_at IS NULL
AND (file_name LIKE '%$q%' OR file_ext LIKE '%$q%' OR file_description LIKE '%$q%')
$query_images
ORDER BY $sort $order LIMIT $record_from, $record_to"
);
}else{
$sql = mysqli_query(
$mysqli,
"SELECT SQL_CALC_FOUND_ROWS * FROM files
LEFT JOIN users ON file_created_by = user_id
WHERE file_client_id = $client_id
AND file_folder_id = $folder_id
AND file_archived_at IS NULL
AND (file_name LIKE '%$q%' OR file_ext LIKE '%$q%' OR file_description LIKE '%$q%')
$query_images
ORDER BY $sort $order LIMIT $record_from, $record_to"
);
}
$num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
$num_of_files = mysqli_num_rows($sql);
// Breadcrumbs
// Build the full folder path
$folder_id = $get_folder_id;
$folder_path = array();
while ($folder_id > 0) {
$sql_folder = mysqli_query($mysqli, "SELECT folder_name, parent_folder FROM folders WHERE folder_id = $folder_id");
if ($row_folder = mysqli_fetch_assoc($sql_folder)) {
$folder_name = nullable_htmlentities($row_folder['folder_name']);
$parent_folder = intval($row_folder['parent_folder']);
// Prepend the folder to the beginning of the array
array_unshift($folder_path, array('folder_id' => $folder_id, 'folder_name' => $folder_name));
// Move up to the parent folder
$folder_id = $parent_folder;
} else {
// If the folder is not found, break the loop
break;
}
}
?>
<div class="card card-dark">
<div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fa fa-fw fa-paperclip mr-2"></i>Files</h3>
<div class="card-tools">
<div class="btn-group">
<button type="button" class="btn btn-primary ajax-modal" data-modal-url="modals/file/file_upload.php?client_id=<?= $client_id ?>&folder_id=<?= $get_folder_id ?>">
<i class="fas fa-fw fa-cloud-upload-alt mr-2"></i>Upload
</button>
<button type="button" class="btn btn-primary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown"></button>
<div class="dropdown-menu">
<a class="dropdown-item text-dark ajax-modal" href="#" data-modal-url="modals/folder/folder_add.php?client_id=<?= $client_id ?>&folder_location=1&current_folder_id=<?= $get_folder_id ?>">
<i class="fa fa-fw fa-folder-plus mr-2"></i>New Folder
</a>
</div>
</div>
</div>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-3 border-right mb-3">
<h4>Folders</h4>
<hr>
<ul class="nav nav-pills flex-column bg-light">
<li class="nav-item">
<a class="nav-link <?php if ($get_folder_id == 0) { echo "active"; } ?>" href="?client_id=<?php echo $client_id; ?>&folder_id=0">/</a>
</li>
<?php
// Function to check if a folder is an ancestor of the current folder
function is_ancestor_folder($folder_id, $current_folder_id, $client_id) {
global $mysqli;
// Base case: if current_folder_id is 0 or equal to folder_id
if ($current_folder_id == 0) {
return false;
}
if ($current_folder_id == $folder_id) {
return true;
}
// Get the parent folder of the current folder
$result = mysqli_query($mysqli, "SELECT parent_folder FROM folders WHERE folder_id = $current_folder_id AND folder_client_id = $client_id");
if ($row = mysqli_fetch_assoc($result)) {
$parent_folder_id = intval($row['parent_folder']);
// Recursive call to check the parent folder
return is_ancestor_folder($folder_id, $parent_folder_id, $client_id);
} else {
// Folder not found
return false;
}
}
// Recursive function to display folders and subfolders
function display_folders($parent_folder_id, $client_id, $indent = 0) {
global $mysqli, $get_folder_id, $session_user_role;
$sql_folders = mysqli_query($mysqli, "SELECT * FROM folders WHERE parent_folder = $parent_folder_id AND folder_location = 1 AND folder_client_id = $client_id ORDER BY folder_name ASC");
while ($row = mysqli_fetch_array($sql_folders)) {
$folder_id = intval($row['folder_id']);
$folder_name = nullable_htmlentities($row['folder_name']);
// Get the number of files in the folder
$row2 = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('file_id') AS num FROM files WHERE file_folder_id = $folder_id AND file_archived_at IS NULL"));
$num_files = intval($row2['num']);
// Get the number of subfolders
$subfolder_result = mysqli_query($mysqli, "SELECT COUNT(*) AS count FROM folders WHERE parent_folder = $folder_id AND folder_client_id = $client_id");
$subfolder_count = intval(mysqli_fetch_assoc($subfolder_result)['count']);
echo '<li class="nav-item">';
echo '<div class="row">';
echo '<div class="col-10">';
echo '<a class="nav-link ';
if ($get_folder_id == $folder_id) { echo "active"; }
echo '" href="?client_id=' . $client_id . '&folder_id=' . $folder_id . '">';
// Indentation for subfolders
echo str_repeat('&nbsp;', $indent * 4);
// Determine if the folder is open
if ($get_folder_id == $folder_id || is_ancestor_folder($folder_id, $get_folder_id, $client_id)) {
echo '<i class="fas fa-fw fa-folder-open"></i>';
} else {
echo '<i class="fas fa-fw fa-folder"></i>';
}
echo ' ' . $folder_name;
if ($num_files > 0) {
echo "<span class='badge badge-pill badge-dark float-right mt-1'>$num_files</span>";
}
echo '</a>';
echo '</div>';
echo '<div class="col-2">';
?>
<div class="dropdown">
<button class="btn btn-sm" type="button" data-toggle="dropdown">
<i class="fas fa-ellipsis-v"></i>
</button>
<div class="dropdown-menu">
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/folder/folder_rename.php?id=<?= $folder_id ?>">
<i class="fas fa-fw fa-edit mr-2"></i>Rename
</a>
<?php
// Only show delete option if user is admin, folder has no files, and no subfolders
if ($session_user_role == 3 && $num_files == 0 && $subfolder_count == 0) { ?>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger text-bold confirm-link" href="post.php?delete_folder=<?php echo $folder_id; ?>">
<i class="fas fa-fw fa-trash mr-2"></i>Delete
</a>
<?php } ?>
</div>
</div>
<?php
echo '</div>';
echo '</div>';
if ($subfolder_count > 0) {
// Display subfolders
echo '<ul class="nav nav-pills flex-column bg-light">';
display_folders($folder_id, $client_id, $indent + 1);
echo '</ul>';
}
echo '</li>';
}
}
// Start displaying folders from the root (parent_folder = 0)
display_folders(0, $client_id);
?>
</ul>
<?php //require_once "modals/folder/folder_add.php"; ?>
</div>
<div class="col-md-9">
<form autocomplete="off">
<input type="hidden" name="client_id" value="<?php echo $client_id; ?>">
<input type="hidden" name="view" value="<?php echo $view; ?>">
<input type="hidden" name="folder_id" value="<?php echo $get_folder_id; ?>">
<div class="row">
<div class="col-md-5">
<div class="input-group mb-3 mb-md-0">
<input type="search" class="form-control" name="q" value="<?php if (isset($q)) { echo stripslashes(nullable_htmlentities($q)); } ?>" placeholder="Search for files in <?php if($get_folder_id == 0) { echo "all folders"; } else { echo "current folder"; } ?>">
<div class="input-group-append">
<button class="btn btn-dark"><i class="fa fa-search"></i></button>
</div>
</div>
</div>
<div class="col-md-7">
<div class="btn-group float-right">
<a href="?<?php echo $url_query_strings_sort; ?>&view=0" class="btn <?php if($view == 0){ echo "btn-primary"; } else { echo "btn-outline-secondary"; } ?>"><i class="fas fa-list-ul"></i></a>
<a href="?<?php echo $url_query_strings_sort; ?>&view=1" class="btn <?php if($view == 1){ echo "btn-primary"; } else { echo "btn-outline-secondary"; } ?>"><i class="fas fa-th-large"></i></a>
<div class="dropdown ml-2" id="bulkActionButton" hidden>
<button class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">
<i class="fas fa-fw fa-layer-group mr-2"></i>Bulk Action (<span id="selectedCount">0</span>)
</button>
<div class="dropdown-menu">
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/file/file_bulk_move.php?client_id=<?= $client_id ?>"
data-bulk="true">
<i class="fas fa-fw fa-exchange-alt mr-2"></i>Move
</a>
<div class="dropdown-divider"></div>
<button class="dropdown-item text-danger text-bold"
type="submit" form="bulkActions" name="bulk_delete_files">
<i class="fas fa-fw fa-trash mr-2"></i>Delete
</button>
</div>
</div>
</div>
</div>
</div>
</form>
<nav class="mt-3">
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a href="?client_id=<?php echo $client_id; ?>&folder_id=0">
<i class="fas fa-fw fa-folder mr-2"></i>Root
</a>
</li>
<?php
// Output breadcrumb items for each folder in the path
foreach ($folder_path as $folder) {
$bread_crumb_folder_id = $folder['folder_id']; // Already Sanitized before it was pushed into array
$bread_crumb_folder_name = $folder['folder_name']; // Already Sanitized before it was pushed into array
?>
<li class="breadcrumb-item">
<a href="?client_id=<?php echo $client_id; ?>&folder_id=<?php echo $bread_crumb_folder_id; ?>">
<i class="fas fa-fw fa-folder-open mr-2"></i><?php echo $bread_crumb_folder_name; ?>
</a>
</li>
<?php
}
?>
</ol>
</nav>
<hr>
<?php
if($view == 1){
?>
<div class="row">
<?php
$files = [];
while ($row = mysqli_fetch_array($sql)) {
$file_id = intval($row['file_id']);
$file_name = nullable_htmlentities($row['file_name']);
$file_reference_name = nullable_htmlentities($row['file_reference_name']);
$file_ext = nullable_htmlentities($row['file_ext']);
$file_size = intval($row['file_size']);
$file_size_KB = number_format($file_size / 1024);
$file_mime_type = nullable_htmlentities($row['file_mime_type']);
$file_uploaded_by = nullable_htmlentities($row['user_name']);
// Store file data into an array for JS
$files[] = [
'id' => $file_id,
'name' => $file_name,
'preview' => "../uploads/clients/$client_id/$file_reference_name"
];
?>
<div class="col-xl-2 col-lg-2 col-md-6 col-sm-6 mb-3 text-center">
<a href="#" onclick="openModal(<?php echo count($files)-1; ?>)"><!-- passing the index -->
<img class="img-thumbnail" src="<?php echo "../uploads/clients/$client_id/$file_reference_name"; ?>" alt="<?php echo $file_reference_name ?>">
</a>
<div>
<div class="dropdown float-right">
<button class="btn btn-link btn-sm" type="button" data-toggle="dropdown">
<i class="fas fa-ellipsis-v"></i>
</button>
<div class="dropdown-menu">
<a class="dropdown-item" href="<?php echo "../uploads/clients/$client_id/$file_reference_name"; ?>" download="<?php echo $file_name; ?>">
<i class="fas fa-fw fa-cloud-download-alt mr-2"></i>Download
</a>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#shareModal" onclick="populateShareModal(<?php echo "$client_id, 'File', $file_id"; ?>)">
<i class="fas fa-fw fa-share mr-2"></i>Share
</a>
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/file/file_rename.php?id=<?= $file_id ?>">
<i class="fas fa-fw fa-edit mr-2"></i>Rename
</a>
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/file/file_move.php?id=<?= $file_id ?>">
<i class="fas fa-fw fa-exchange-alt mr-2"></i>Move
</a>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#linkAssetToFileModal<?php echo $file_id; ?>">
<i class="fas fa-fw fa-desktop mr-2"></i>Asset
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger confirm-link" href="post.php?archive_file=<?php echo $file_id; ?>">
<i class="fas fa-fw fa-archive mr-2"></i>Archive
</a>
<?php if ($session_user_role == 3) { ?>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger text-bold" href="#" data-toggle="modal" data-target="#deleteFileModal" onclick="populateFileDeleteModal(<?php echo "$file_id , '$file_name'" ?>)">
<i class="fas fa-fw fa-trash mr-2"></i>Delete
</a>
<?php } ?>
</div>
</div>
<small class="text-secondary"><?php echo $file_name; ?></small>
</div>
</div>
<?php
require "modals/file/file_view.php";
}
?>
<script>
// Pass PHP array to JavaScript
var files = <?php echo json_encode($files); ?>;
var currentIndex = 0; // Keep track of which file is displayed
</script>
</div>
<?php } else { ?>
<form id="bulkActions" action="post.php" method="post">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<div class="table-responsive-sm">
<table class="table border">
<thead class="thead-light <?php if ($num_rows[0] == 0) { echo "d-none"; } ?>">
<tr>
<td class="bg-light pr-0">
<div class="form-check">
<input class="form-check-input" id="selectAllCheckbox" type="checkbox" onclick="checkAll(this)">
</div>
</td>
<th>
<a class="text-secondary" href="?<?php echo $url_query_strings_sort; ?>&sort=file_name&order=<?php echo $disp; ?>">
Name <?php if ($sort == 'file_name') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-secondary" href="?<?php echo $url_query_strings_sort; ?>&sort=file_mime_type&order=<?php echo $disp; ?>">
Type <?php if ($sort == 'file_mime_type') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-secondary" href="?<?php echo $url_query_strings_sort; ?>&sort=file_size&order=<?php echo $disp; ?>">
Size <?php if ($sort == 'file_size') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-secondary" href="?<?php echo $url_query_strings_sort; ?>&sort=file_created_at&order=<?php echo $disp; ?>">
Uploaded <?php if ($sort == 'file_created_at') { echo $order_icon; } ?>
</a>
</th>
<th></th>
<th class="text-center">Action</th>
</tr>
</thead>
<tbody>
<?php
while ($row = mysqli_fetch_array($sql)) {
$file_id = intval($row['file_id']);
$file_name = nullable_htmlentities($row['file_name']);
$file_description = nullable_htmlentities($row['file_description']);
$file_reference_name = nullable_htmlentities($row['file_reference_name']);
$file_ext = nullable_htmlentities($row['file_ext']);
if ($file_ext == 'pdf') {
$file_icon = "file-pdf";
} elseif ($file_ext == 'gz' || $file_ext == 'tar' || $file_ext == 'zip' || $file_ext == '7z' || $file_ext == 'rar') {
$file_icon = "file-archive";
} elseif ($file_ext == 'txt' || $file_ext == 'md') {
$file_icon = "file-alt";
} elseif ($file_ext == 'msg') {
$file_icon = "envelope";
} elseif ($file_ext == 'doc' || $file_ext == 'docx' || $file_ext == 'odt') {
$file_icon = "file-word";
} elseif ($file_ext == 'xls' || $file_ext == 'xlsx' || $file_ext == 'ods') {
$file_icon = "file-excel";
} elseif ($file_ext == 'pptx' || $file_ext == 'odp') {
$file_icon = "file-powerpoint";
} elseif ($file_ext == 'mp3' || $file_ext == 'wav' || $file_ext == 'ogg') {
$file_icon = "file-audio";
} elseif ($file_ext == 'mov' || $file_ext == 'mp4' || $file_ext == 'av1') {
$file_icon = "file-video";
} elseif ($file_ext == 'jpg' || $file_ext == 'jpeg' || $file_ext == 'png' || $file_ext == 'gif' || $file_ext == 'webp' || $file_ext == 'bmp' || $file_ext == 'tif') {
$file_icon = "file-image";
} else {
$file_icon = "file";
}
$file_size = intval($row['file_size']);
$file_size_KB = number_format($file_size / 1024);
$file_mime_type = nullable_htmlentities($row['file_mime_type']);
$file_size = intval($row['file_size']);
$file_uploaded_by = nullable_htmlentities($row['user_name']);
$file_created_at = nullable_htmlentities($row['file_created_at']);
$file_folder_id = intval($row['file_folder_id']);
// Check if shared
$sql_shared = mysqli_query(
$mysqli,
"SELECT * FROM shared_items
WHERE item_client_id = $client_id
AND item_active = 1
AND item_views != item_view_limit
AND item_expire_at > NOW()
AND item_type = 'File'
AND item_related_id = $file_id
LIMIT 1"
);
$file_shared = (mysqli_num_rows($sql_shared) > 0) ? true : false;
if ($file_shared) {
$row = mysqli_fetch_array($sql_shared);
$item_id = intval($row['item_id']);
$item_active = nullable_htmlentities($row['item_active']);
$item_key = nullable_htmlentities($row['item_key']);
$item_type = nullable_htmlentities($row['item_type']);
$item_related_id = intval($row['item_related_id']);
$item_note = nullable_htmlentities($row['item_note']);
$item_recipient = nullable_htmlentities($row['item_recipient']);
$item_views = nullable_htmlentities($row['item_views']);
$item_view_limit = nullable_htmlentities($row['item_view_limit']);
$item_created_at = nullable_htmlentities($row['item_created_at']);
$item_expire_at = nullable_htmlentities($row['item_expire_at']);
$item_expire_at_human = timeAgo($row['item_expire_at']);
}
?>
<tr>
<td class="bg-light pr-0">
<div class="form-check">
<input class="form-check-input bulk-select" type="checkbox" name="file_ids[]" value="<?php echo $file_id ?>">
</div>
</td>
<td>
<a href="<?php echo "../uploads/clients/$client_id/$file_reference_name"; ?>" target="_blank">
<div class="media">
<i class="fa fa-fw fa-2x fa-<?php echo $file_icon; ?> text-dark mr-3"></i>
<div class="media-body">
<p>
<?php echo basename($file_name); ?>
<br>
<small class="text-secondary"><?php echo $file_description; ?></small>
</p>
</div>
</div>
</a>
</td>
<td><?php echo $file_mime_type; ?></td>
<td><?php echo $file_size_KB; ?> KB</td>
<td>
<?php echo $file_created_at; ?>
<div class="text-secondary mt-1"><?php echo $file_uploaded_by; ?></div>
</td>
<td>
<?php if ($file_shared) { ?>
<div class="media" title="Expires <?php echo $item_expire_at_human; ?>">
<i class="fas fa-link mr-2 mt-1"></i>
<div class="media-body">Shared
<br>
<small class="text-secondary"><?php echo $item_recipient; ?></small>
</div>
</div>
<?php } ?>
</td>
<td>
<div class="dropdown dropleft text-center">
<button class="btn btn-secondary btn-sm" type="button" data-toggle="dropdown">
<i class="fas fa-ellipsis-h"></i>
</button>
<div class="dropdown-menu">
<a class="dropdown-item" href="<?php echo "../uploads/clients/$client_id/$file_reference_name"; ?>" download="<?php echo $file_name; ?>">
<i class="fas fa-fw fa-cloud-download-alt mr-2"></i>Download
</a>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#shareModal" onclick="populateShareModal(<?php echo "$client_id, 'File', $file_id"; ?>)">
<i class="fas fa-fw fa-share mr-2"></i>Share
</a>
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/file/file_rename.php?id=<?= $file_id ?>">
<i class="fas fa-fw fa-edit mr-2"></i>Rename
</a>
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/file/file_move.php?id=<?= $file_id ?>">
<i class="fas fa-fw fa-exchange-alt mr-2"></i>Move
</a>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#linkAssetToFileModal<?php echo $file_id; ?>">
<i class="fas fa-fw fa-desktop mr-2"></i>Asset
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger confirm-link" href="post.php?archive_file=<?php echo $file_id; ?>">
<i class="fas fa-fw fa-archive mr-2"></i>Archive
</a>
<?php if ($session_user_role == 3) { ?>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger text-bold" href="#" data-toggle="modal" data-target="#deleteFileModal" onclick="populateFileDeleteModal(<?php echo "$file_id , '$file_name'" ?>)">
<i class="fas fa-fw fa-trash mr-2"></i>Delete
</a>
<?php } ?>
</div>
</div>
</td>
</tr>
<?php
require "modals/file/file_link_asset.php";
}
?>
</tbody>
</table>
</div>
</form>
<?php } ?>
<?php require_once "../includes/filter_footer.php"; ?>
</div>
</div>
</div>
</div>
<script>
function openModal(index) {
currentIndex = index;
updateModalContent();
$('#viewFileModal').modal('show');
}
function updateModalContent() {
document.getElementById('modalTitle').innerText = files[currentIndex].name;
document.getElementById('modalImage').src = files[currentIndex].preview;
}
function nextFile() {
currentIndex = (currentIndex + 1) % files.length; // loop around
updateModalContent();
}
function prevFile() {
currentIndex = (currentIndex - 1 + files.length) % files.length; // loop around
updateModalContent();
}
</script>
<script src="../js/bulk_actions.js"></script>
<?php
require_once "modals/share_modal.php";
require_once "modals/file/file_delete.php";
require_once "../includes/footer.php";

View File

@@ -53,6 +53,7 @@ $num_software = $row['num'];
<i class="nav-icon fas fa-address-book"></i> <i class="nav-icon fas fa-address-book"></i>
<p> <p>
Contacts Contacts
<span href="#" class="fas fa-plus-circle right ajax-modal" data-modal-url="/agent/modals/contact/contact_add.php"></span>
<?php <?php
if ($num_contacts > 0) { ?> if ($num_contacts > 0) { ?>
<span class="right badge text-light"><?php echo $num_contacts; ?></span> <span class="right badge text-light"><?php echo $num_contacts; ?></span>
@@ -65,6 +66,7 @@ $num_software = $row['num'];
<i class="nav-icon fas fa-map-marker-alt"></i> <i class="nav-icon fas fa-map-marker-alt"></i>
<p> <p>
Locations Locations
<span href="#" class="fas fa-plus-circle right ajax-modal" data-modal-url="/agent/modals/location/location_add.php"></span>
<?php <?php
if ($num_locations > 0) { ?> if ($num_locations > 0) { ?>
<span class="right badge text-light"><?php echo $num_locations; ?></span> <span class="right badge text-light"><?php echo $num_locations; ?></span>
@@ -77,6 +79,7 @@ $num_software = $row['num'];
<i class="nav-icon fas fa-desktop"></i> <i class="nav-icon fas fa-desktop"></i>
<p> <p>
Assets Assets
<span href="#" class="fas fa-plus-circle right ajax-modal" data-modal-url="/agent/modals/asset/asset_add.php"></span>
<?php <?php
if ($num_assets > 0) { ?> if ($num_assets > 0) { ?>
<span class="right badge text-light"><?php echo $num_assets; ?></span> <span class="right badge text-light"><?php echo $num_assets; ?></span>
@@ -89,6 +92,7 @@ $num_software = $row['num'];
<i class="nav-icon fas fa-cube"></i> <i class="nav-icon fas fa-cube"></i>
<p> <p>
Licenses Licenses
<span href="#" class="fas fa-plus-circle right ajax-modal" data-modal-url="/agent/modals/software/software_add.php"></span>
<?php <?php
if ($num_software > 0) { ?> if ($num_software > 0) { ?>
<span class="right badge text-light"><?php echo $num_software; ?></span> <span class="right badge text-light"><?php echo $num_software; ?></span>
@@ -101,6 +105,7 @@ $num_software = $row['num'];
<i class="nav-icon fas fa-key"></i> <i class="nav-icon fas fa-key"></i>
<p> <p>
Credentials Credentials
<span href="#" class="fas fa-plus-circle right ajax-modal" data-modal-url="/agent/modals/credential/credential_add.php"></span>
<?php <?php
if ($num_credentials > 0) { ?> if ($num_credentials > 0) { ?>
<span class="right badge text-light"><?php echo $num_credentials; ?></span> <span class="right badge text-light"><?php echo $num_credentials; ?></span>
@@ -113,6 +118,7 @@ $num_software = $row['num'];
<i class="nav-icon fas fa-network-wired"></i> <i class="nav-icon fas fa-network-wired"></i>
<p> <p>
Networks Networks
<span href="#" class="fas fa-plus-circle right ajax-modal" data-modal-url="/agent/modals/network/network_add.php"></span>
<?php <?php
if ($num_networks > 0) { ?> if ($num_networks > 0) { ?>
<span class="right badge text-light"><?php echo $num_networks; ?></span> <span class="right badge text-light"><?php echo $num_networks; ?></span>
@@ -125,6 +131,7 @@ $num_software = $row['num'];
<i class="nav-icon fas fa-lock"></i> <i class="nav-icon fas fa-lock"></i>
<p> <p>
Certificates Certificates
<span href="#" class="fas fa-plus-circle right ajax-modal" data-modal-url="/agent/modals/certificate/certificate_add.php"></span>
<?php <?php
if ($num_certificates > 0) { ?> if ($num_certificates > 0) { ?>
<span class="right badge text-light"><?php echo $num_certificates; ?></span> <span class="right badge text-light"><?php echo $num_certificates; ?></span>
@@ -137,6 +144,7 @@ $num_software = $row['num'];
<i class="nav-icon fas fa-globe"></i> <i class="nav-icon fas fa-globe"></i>
<p> <p>
Domains Domains
<span href="#" class="fas fa-plus-circle right ajax-modal" data-modal-url="/agent/modals/domain/domain_add.php"></span>
<?php <?php
if ($num_domains > 0) { ?> if ($num_domains > 0) { ?>
<span class="right badge text-light"><?php echo $num_domains; ?></span> <span class="right badge text-light"><?php echo $num_domains; ?></span>
@@ -149,6 +157,7 @@ $num_software = $row['num'];
<i class="nav-icon fas fa-stream"></i> <i class="nav-icon fas fa-stream"></i>
<p> <p>
Services Services
<span href="#" class="fas fa-plus-circle right ajax-modal" data-modal-url="/agent/modals/service/service_add.php"></span>
<?php <?php
if ($num_services > 0) { ?> if ($num_services > 0) { ?>
<span class="right badge text-light"><?php echo $num_services; ?></span> <span class="right badge text-light"><?php echo $num_services; ?></span>

View File

@@ -199,7 +199,6 @@
<i class="nav-icon fas fa-lock"></i> <i class="nav-icon fas fa-lock"></i>
<p> <p>
Certificates Certificates
<?php <?php
if ($num_certificates > 0) { ?> if ($num_certificates > 0) { ?>
<span class="right badge <?php if ($num_certificates_expiring > 0) { ?> badge-warning text-dark <?php } ?> <?php if ($num_certificates_expired > 0) { ?> badge-danger <?php } ?> text-white"><?php echo $num_certificates; ?></span> <span class="right badge <?php if ($num_certificates_expiring > 0) { ?> badge-warning text-dark <?php } ?> <?php if ($num_certificates_expired > 0) { ?> badge-danger <?php } ?> text-white"><?php echo $num_certificates; ?></span>
@@ -213,7 +212,6 @@
<i class="nav-icon fas fa-globe"></i> <i class="nav-icon fas fa-globe"></i>
<p> <p>
Domains Domains
<?php <?php
if ($num_domains > 0) { ?> if ($num_domains > 0) { ?>
<span class="right badge <?php if (isset($num_domains_expiring)) { ?> badge-warning text-dark<?php } ?> <?php if (isset($num_domains_expired)) { ?> badge-danger <?php } ?> text-white"><?php echo $num_domains; ?></span> <span class="right badge <?php if (isset($num_domains_expiring)) { ?> badge-warning text-dark<?php } ?> <?php if (isset($num_domains_expired)) { ?> badge-danger <?php } ?> text-white"><?php echo $num_domains; ?></span>
@@ -235,25 +233,12 @@
</a> </a>
</li> </li>
<li class="nav-item">
<a href="/agent/documents.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "documents.php" || basename($_SERVER["PHP_SELF"]) == "document_details.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-folder"></i>
<p>
Documents
<?php
if ($num_documents > 0) { ?>
<span class="right badge text-light"><?php echo $num_documents; ?></span>
<?php } ?>
</p>
</a>
</li>
<?php } ?> <?php } ?>
<!-- Allow files even without module_support for things like contracts, etc. ) --> <!-- Allow files even without module_support for things like contracts, etc. ) -->
<li class="nav-item"> <li class="nav-item">
<a href="/agent/files.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "files.php") { echo "active"; } ?>"> <a href="/agent/files.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "files.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-paperclip"></i> <i class="nav-icon fas fa-folder"></i>
<p> <p>
Files Files
<?php <?php

View File

@@ -29,8 +29,8 @@ if (isset($_GET['client_id'])) {
$sql = mysqli_query( $sql = mysqli_query(
$mysqli, $mysqli,
"SELECT * FROM clients "SELECT * FROM clients
LEFT JOIN locations ON clients.client_id = locations.location_client_id AND location_primary = 1 LEFT JOIN locations ON client_id = location_client_id AND location_primary = 1
LEFT JOIN contacts ON clients.client_id = contacts.contact_client_id AND contact_primary = 1 LEFT JOIN contacts ON client_id = contact_client_id AND contact_primary = 1
WHERE client_id = $client_id" WHERE client_id = $client_id"
); );

View File

@@ -23,10 +23,10 @@
<a href="/agent/clients.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "clients.php") { echo "active"; } ?>"> <a href="/agent/clients.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "clients.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-users"></i> <i class="nav-icon fas fa-users"></i>
<p> <p>
Clients Clients
<?php if ($num_active_clients) { ?> <?php if ($num_active_clients) { ?>
<span class="right badge text-light" data-toggle="tooltip" title="Active Clients"><?php echo $num_active_clients; ?></span> <span class="right badge text-light" data-toggle="tooltip" title="Active Clients"><?php echo $num_active_clients; ?></span>
<?php } ?> <?php } ?>
</p> </p>
</a> </a>
</li> </li>

View File

@@ -18,8 +18,8 @@ if (isset($_GET['invoice_id'])) {
$mysqli, $mysqli,
"SELECT * FROM invoices "SELECT * FROM invoices
LEFT JOIN clients ON invoice_client_id = client_id LEFT JOIN clients ON invoice_client_id = client_id
LEFT JOIN contacts ON clients.client_id = contacts.contact_client_id AND contact_primary = 1 LEFT JOIN contacts ON client_id = contact_client_id AND contact_primary = 1
LEFT JOIN locations ON clients.client_id = locations.location_client_id AND location_primary = 1 LEFT JOIN locations ON client_id = location_client_id AND location_primary = 1
WHERE invoice_id = $invoice_id WHERE invoice_id = $invoice_id
$access_permission_query $access_permission_query
LIMIT 1" LIMIT 1"
@@ -456,10 +456,10 @@ if (isset($_GET['invoice_id'])) {
<textarea class="form-control" rows="2" id="desc" name="description" placeholder="Enter a Description"></textarea> <textarea class="form-control" rows="2" id="desc" name="description" placeholder="Enter a Description"></textarea>
</td> </td>
<td> <td>
<input type="text" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,2}" class="form-control" style="text-align: center;" id="qty" name="qty" placeholder="Qty"> <input type="text" inputmode="decimal" pattern="[0-9]*\.?[0-9]{0,2}" class="form-control" style="text-align: center;" id="qty" name="qty" placeholder="Qty">
</td> </td>
<td> <td>
<input type="text" class="form-control" inputmode="numeric" pattern="-?[0-9]*\.?[0-9]{0,2}" style="text-align: right;" id="price" name="price" placeholder="Price (<?php echo $invoice_currency_code; ?>)"> <input type="text" class="form-control" inputmode="decimal" pattern="-?[0-9]*\.?[0-9]{0,2}" style="text-align: right;" id="price" name="price" placeholder="Price (<?php echo $invoice_currency_code; ?>)">
</td> </td>
<td> <td>
<select class="form-control select2" name="tax_id" id="tax" required> <select class="form-control select2" name="tax_id" id="tax" required>

View File

@@ -344,8 +344,6 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
$recurring_invoice_display = "-"; $recurring_invoice_display = "-";
} }
$now = time(); $now = time();
if (($invoice_status == "Sent" || $invoice_status == "Partial" || $invoice_status == "Viewed") && strtotime($invoice_due) + 86400 < $now) { if (($invoice_status == "Sent" || $invoice_status == "Partial" || $invoice_status == "Viewed") && strtotime($invoice_due) + 86400 < $now) {
@@ -356,6 +354,15 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
$invoice_badge_color = getInvoiceBadgeColor($invoice_status); $invoice_badge_color = getInvoiceBadgeColor($invoice_status);
// Saved Payment Methods
$sql_saved_payment_methods = mysqli_query($mysqli, "
SELECT * FROM client_saved_payment_methods
LEFT JOIN payment_providers
ON client_saved_payment_methods.saved_payment_provider_id = payment_providers.payment_provider_id
WHERE saved_payment_client_id = $client_id
AND payment_provider_active = 1;
");
?> ?>
<tr> <tr>
@@ -395,10 +402,8 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<i class="fa fa-fw fa-credit-card mr-2"></i>Add Payment <i class="fa fa-fw fa-credit-card mr-2"></i>Add Payment
</a> </a>
<div class="dropdown-divider"></div> <div class="dropdown-divider"></div>
<?php if ($invoice_status !== 'Partial' && $config_stripe_enable && $stripe_id && $stripe_pm) { ?> <?php if (mysqli_num_rows($sql_saved_payment_methods) > 0 && ($invoice_status === 'Sent' || $invoice_status === 'Viewed')) { ?>
<a class="dropdown-item confirm-link" href="post.php?add_payment_stripe&invoice_id=<?php echo $invoice_id; ?>&csrf_token=<?php echo $_SESSION['csrf_token']; ?>"> <a class="dropdown-item ajax-modal" href="#" data-modal-url="modals/payment/payment_saved_method_add.php?id=<?= $invoice_id ?>"><i class="fas fa-fw fa-wallet mr-2"></i>Pay with Saved Card</a>
<i class="fa fa-fw fa-credit-card mr-2"></i>Pay via saved card
</a>
<div class="dropdown-divider"></div> <div class="dropdown-divider"></div>
<?php } ?> <?php } ?>
<?php } ?> <?php } ?>

View File

@@ -32,7 +32,7 @@ ob_start();
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-dollar-sign"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-dollar-sign"></i></span>
</div> </div>
<input type="text" class="form-control" inputmode="numeric" pattern="-?[0-9]*\.?[0-9]{0,2}" name="opening_balance" placeholder="0.00" required> <input type="text" class="form-control" inputmode="decimal" pattern="-?[0-9]*\.?[0-9]{0,2}" name="opening_balance" placeholder="0.00" required>
</div> </div>
</div> </div>

View File

@@ -27,6 +27,8 @@ if ($os_sql && mysqli_num_rows($os_sql) > 0) {
$json_os = json_encode($os_arr); $json_os = json_encode($os_arr);
} }
$sql_tags_select = mysqli_query($mysqli, "SELECT tag_id, tag_name FROM tags WHERE tag_type = 5 ORDER BY tag_name ASC");
ob_start(); ob_start();
?> ?>
@@ -465,6 +467,33 @@ ob_start();
<textarea class="form-control" rows="8" placeholder="Enter some notes" name="notes"></textarea> <textarea class="form-control" rows="8" placeholder="Enter some notes" name="notes"></textarea>
</div> </div>
<div class="form-group">
<label>Tags</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-tags"></i></span>
</div>
<select class="form-control select2" name="tags[]" data-placeholder="Add some tags" multiple>
<?php
while ($row = mysqli_fetch_array($sql_tags_select)) {
$tag_id = intval($row['tag_id']);
$tag_name = nullable_htmlentities($row['tag_name']);
?>
<option value="<?= $tag_id ?>"><?= $tag_name ?></option>
<?php } ?>
</select>
<div class="input-group-append">
<button class="btn btn-secondary ajax-modal" type="button"
data-modal-url="../admin/modals/tag/tag_add.php?type=5">
<i class="fas fa-plus"></i>
</button>
</div>
</div>
</div>
</div> </div>
</div> </div>

View File

@@ -0,0 +1,61 @@
<?php
require_once '../../../includes/modal_header.php';
$selected_ids = array_map('intval', $_GET['selected_ids'] ?? []);
$count = count($selected_ids);
ob_start();
?>
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-tags mr-2"></i>Assign Tags for <strong><?= $count ?></strong> Assets</h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="post.php" method="post" autocomplete="off">
<input type="hidden" name="csrf_token" value="<?= $_SESSION['csrf_token'] ?>">
<?php foreach ($selected_ids as $id) { ?><input type="hidden" name="asset_ids[]" value="<?= $id ?>"><?php } ?>
<div class="modal-body">
<input type="hidden" name="remove_tags" value="0">
<div class="form-group form-check">
<input type="checkbox" class="form-check-input" name="remove_tags" value="1">
<label class="form-check-label text-danger">Remove Existing Tags</label>
</div>
<div class="form-group">
<label>Tags</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-tags"></i></span>
</div>
<select class="form-control select2" name="tags[]" data-placeholder="Add some tags" multiple>
<?php
$sql_tags_select = mysqli_query($mysqli, "SELECT * FROM tags WHERE tag_type = 5 ORDER BY tag_name ASC");
while ($row = mysqli_fetch_array($sql_tags_select)) {
$tag_id_select = intval($row['tag_id']);
$tag_name_select = nullable_htmlentities($row['tag_name']);
?>
<option value="<?php echo $tag_id_select; ?>"><?php echo $tag_name_select; ?></option>
<?php } ?>
</select>
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" name="bulk_assign_asset_tags" class="btn btn-primary text-bold"><i class="fas fa-check mr-2"></i>Assign Tags</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';

View File

@@ -70,6 +70,28 @@ if ($location_archived_at) {
$location_name_display = $location_name; $location_name_display = $location_name;
} }
// Tags - many to many relationship
$asset_tag_name_display_array = array();
$asset_tag_id_array = array();
$sql_asset_tags = mysqli_query($mysqli, "SELECT * FROM asset_tags LEFT JOIN tags ON asset_tag_tag_id = tag_id WHERE asset_tag_asset_id = $asset_id ORDER BY tag_name ASC");
while ($row = mysqli_fetch_array($sql_asset_tags)) {
$asset_tag_id = intval($row['tag_id']);
$asset_tag_name = nullable_htmlentities($row['tag_name']);
$asset_tag_color = nullable_htmlentities($row['tag_color']);
if (empty($asset_tag_color)) {
$asset_tag_color = "dark";
}
$asset_tag_icon = nullable_htmlentities($row['tag_icon']);
if (empty($asset_tag_icon)) {
$asset_tag_icon = "tag";
}
$asset_tag_id_array[] = $asset_tag_id;
$asset_tag_name_display_array[] = "<a href='client_assets.php?client_id=$client_id&q=$asset_tag_name'><span class='badge text-light p-1 mr-1' style='background-color: $asset_tag_color;'><i class='fa fa-fw fa-$asset_tag_icon mr-2'></i>$asset_tag_name</span></a>";
}
$asset_tags_display = implode('', $asset_tag_name_display_array);
// Network Interfaces // Network Interfaces
$sql_related_interfaces = mysqli_query($mysqli, " $sql_related_interfaces = mysqli_query($mysqli, "
SELECT SELECT
@@ -262,8 +284,13 @@ ob_start();
<?php } ?> <?php } ?>
</div> </div>
<div class="card-body"> <div class="card-body">
<?php if ($asset_tags_display) { ?>
<div>
<?= $asset_tags_display ?>
</div>
<?php } ?>
<?php if ($asset_type) { ?> <?php if ($asset_type) { ?>
<div><i class="fa fa-fw fa-tag text-secondary mr-2"></i><?php echo $asset_type; ?></div> <div class="mt-1"><i class="fa fa-fw fa-tag text-secondary mr-2"></i><?php echo $asset_type; ?></div>
<?php } <?php }
if ($asset_make) { ?> if ($asset_make) { ?>
<div class="mt-2"><i class="fa fa-fw fa-circle text-secondary mr-2"></i><?php echo "$asset_make $asset_model"; ?></div> <div class="mt-2"><i class="fa fa-fw fa-circle text-secondary mr-2"></i><?php echo "$asset_make $asset_model"; ?></div>
@@ -353,7 +380,7 @@ ob_start();
// Send a POST request to ajax.php as ajax.php with data contact_set_notes=true, contact_id=NUM, notes=NOTES // Send a POST request to ajax.php as ajax.php with data contact_set_notes=true, contact_id=NUM, notes=NOTES
jQuery.post( jQuery.post(
"../ajax.php", "ajax.php",
{ {
asset_set_notes: 'TRUE', asset_set_notes: 'TRUE',
asset_id: asset_id, asset_id: asset_id,

View File

@@ -50,7 +50,14 @@ $sql_asset_history = mysqli_query($mysqli, "SELECT * FROM asset_history
DESC LIMIT 10" DESC LIMIT 10"
); );
// Generate the HTML form content using output buffering. // Tags
$asset_tag_id_array = array();
$sql_asset_tags = mysqli_query($mysqli, "SELECT asset_tag_tag_id FROM asset_tags WHERE asset_tag_asset_id = $asset_id");
while ($row = mysqli_fetch_array($sql_asset_tags)) {
$asset_tag_tag_id = intval($row['asset_tag_tag_id']);
$asset_tag_id_array[] = $asset_tag_tag_id;
}
ob_start(); ob_start();
?> ?>
@@ -462,6 +469,33 @@ ob_start();
<textarea class="form-control" rows="8" placeholder="Enter some notes" name="notes"><?= $asset_notes ?></textarea> <textarea class="form-control" rows="8" placeholder="Enter some notes" name="notes"><?= $asset_notes ?></textarea>
</div> </div>
<div class="form-group">
<label>Tags</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-tags"></i></span>
</div>
<select class="form-control select2" name="tags[]" data-placeholder="Add some tags" multiple>
<?php
$sql_tags_select = mysqli_query($mysqli, "SELECT * FROM tags WHERE tag_type = 5 ORDER BY tag_name ASC");
while ($row = mysqli_fetch_array($sql_tags_select)) {
$tag_id_select = intval($row['tag_id']);
$tag_name_select = nullable_htmlentities($row['tag_name']);
?>
<option value="<?= $tag_id_select ?>" <?php if (in_array($tag_id_select, $asset_tag_id_array)) { echo "selected"; } ?>><?php echo $tag_name_select; ?></option>
<?php } ?>
</select>
<div class="input-group-append">
<button class="btn btn-secondary ajax-modal" type="button"
data-modal-url="../admin/modals/tag/tag_add.php?type=5">
<i class="fas fa-plus"></i>
</button>
</div>
</div>
</div>
<p class="text-muted text-right">Asset ID: <?= $asset_id ?></p> <p class="text-muted text-right">Asset ID: <?= $asset_id ?></p>
</div> </div>

View File

@@ -324,7 +324,7 @@ ob_start();
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-clock"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-clock"></i></span>
</div> </div>
<input type="text" class="form-control" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,2}" name="rate" placeholder="0.00" value="<?php echo "$config_default_hourly_rate"; ?>"> <input type="text" class="form-control" inputmode="decimal" pattern="[0-9]*\.?[0-9]{0,2}" name="rate" placeholder="0.00" value="<?php echo "$config_default_hourly_rate"; ?>">
</div> </div>
</div> </div>

View File

@@ -29,7 +29,7 @@ ob_start();
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-clock"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-clock"></i></span>
</div> </div>
<input type="text" class="form-control" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,2}" name="bulk_rate" placeholder="0.00" required> <input type="text" class="form-control" inputmode="decimal" pattern="[0-9]*\.?[0-9]{0,2}" name="bulk_rate" placeholder="0.00" required>
</div> </div>
</div> </div>

View File

@@ -42,7 +42,7 @@
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-dollar-sign"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-dollar-sign"></i></span>
</div> </div>
<input type="text" class="form-control" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,2}" name="amount" placeholder="0.00" required> <input type="text" class="form-control" inputmode="decimal" pattern="[0-9]*\.?[0-9]{0,2}" name="amount" placeholder="0.00" required>
</div> </div>
</div> </div>

View File

@@ -181,7 +181,7 @@ ob_start();
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-clock"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-clock"></i></span>
</div> </div>
<input type="text" class="form-control" inputmode="numeric" <input type="text" class="form-control" inputmode="decimal"
pattern="[0-9]*\.?[0-9]{0,2}" name="rate" placeholder="0.00" pattern="[0-9]*\.?[0-9]{0,2}" name="rate" placeholder="0.00"
value="<?php echo number_format($client_rate, 2, '.', ''); ?>"> value="<?php echo number_format($client_rate, 2, '.', ''); ?>">
</div> </div>

View File

@@ -51,7 +51,14 @@ $auth_method = nullable_htmlentities($row['user_auth_method']);
$contact_client_id = intval($row['contact_client_id']); $contact_client_id = intval($row['contact_client_id']);
// Related Assets Query - 1 to 1 relationship // Related Assets Query - 1 to 1 relationship
$sql_related_assets = mysqli_query($mysqli, "SELECT * FROM assets LEFT JOIN asset_interfaces ON interface_asset_id = asset_id AND interface_primary = 1 WHERE asset_contact_id = $contact_id ORDER BY asset_name DESC"); $sql_related_assets = mysqli_query($mysqli, "SELECT * FROM assets
LEFT JOIN asset_interfaces ON interface_asset_id = asset_id AND interface_primary = 1
LEFT JOIN asset_tags ON asset_tag_asset_id = asset_id
LEFT JOIN tags ON tag_id = asset_tag_tag_id
WHERE asset_contact_id = $contact_id
GROUP BY asset_id
ORDER BY asset_name ASC"
);
$asset_count = mysqli_num_rows($sql_related_assets); $asset_count = mysqli_num_rows($sql_related_assets);
// Linked Software Licenses // Linked Software Licenses
@@ -77,7 +84,7 @@ $sql_related_credentials = mysqli_query($mysqli, "
LEFT JOIN tags ON tags.tag_id = credential_tags.tag_id LEFT JOIN tags ON tags.tag_id = credential_tags.tag_id
WHERE credential_contact_id = $contact_id WHERE credential_contact_id = $contact_id
GROUP BY credentials.credential_id GROUP BY credentials.credential_id
ORDER BY credential_name DESC ORDER BY credential_name ASC
"); ");
$credential_count = mysqli_num_rows($sql_related_credentials); $credential_count = mysqli_num_rows($sql_related_credentials);
@@ -376,6 +383,27 @@ ob_start();
$asset_notes = nullable_htmlentities($row['asset_notes']); $asset_notes = nullable_htmlentities($row['asset_notes']);
$asset_created_at = nullable_htmlentities($row['asset_created_at']); $asset_created_at = nullable_htmlentities($row['asset_created_at']);
$device_icon = getAssetIcon($asset_type); $device_icon = getAssetIcon($asset_type);
// Tags
$asset_tag_name_display_array = array();
$asset_tag_id_array = array();
$sql_asset_tags = mysqli_query($mysqli, "SELECT * FROM asset_tags LEFT JOIN tags ON asset_tag_tag_id = tag_id WHERE asset_tag_asset_id = $asset_id ORDER BY tag_name ASC");
while ($row = mysqli_fetch_array($sql_asset_tags)) {
$asset_tag_id = intval($row['tag_id']);
$asset_tag_name = nullable_htmlentities($row['tag_name']);
$asset_tag_color = nullable_htmlentities($row['tag_color']);
if (empty($asset_tag_color)) {
$asset_tag_color = "dark";
}
$asset_tag_icon = nullable_htmlentities($row['tag_icon']);
if (empty($asset_tag_icon)) {
$asset_tag_icon = "tag";
}
$asset_tag_id_array[] = $asset_tag_id;
$asset_tag_name_display_array[] = "<a href='assets.php?$client_url tags[]=$asset_tag_id'><span class='badge text-light p-1 mr-1' style='background-color: $asset_tag_color;'><i class='fa fa-fw fa-$asset_tag_icon mr-2'></i>$asset_tag_name</span></a>";
}
$asset_tags_display = implode('', $asset_tag_name_display_array);
?> ?>
<tr> <tr>
@@ -389,6 +417,12 @@ ob_start();
<div class="mt-0"> <div class="mt-0">
<small class="text-muted"><?= $asset_description ?></small> <small class="text-muted"><?= $asset_description ?></small>
</div> </div>
<?php
if ($asset_tags_display) { ?>
<div class="mt-1">
<?= $asset_tags_display ?>
</div>
<?php } ?>
</th> </th>
<td><?= $asset_type ?></td> <td><?= $asset_type ?></td>
<td> <td>

View File

@@ -33,7 +33,7 @@ ob_start();
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-dollar-sign"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-dollar-sign"></i></span>
</div> </div>
<input type="text" class="form-control" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,2}" name="amount" placeholder="0.00" required> <input type="text" class="form-control" inputmode="decimal" pattern="[0-9]*\.?[0-9]{0,2}" name="amount" placeholder="0.00" required>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -50,7 +50,7 @@ ob_start();
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-dollar-sign"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-dollar-sign"></i></span>
</div> </div>
<input type="text" class="form-control" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,2}" name="amount" value="<?php echo number_format($expense_amount, 2, '.', ''); ?>" placeholder="0.00" required> <input type="text" class="form-control" inputmode="decimal" pattern="[0-9]*\.?[0-9]{0,2}" name="amount" value="<?php echo number_format($expense_amount, 2, '.', ''); ?>" placeholder="0.00" required>
</div> </div>
</div> </div>
@@ -211,4 +211,3 @@ ob_start();
require_once '../../../includes/modal_footer.php'; require_once '../../../includes/modal_footer.php';
?> ?>

View File

@@ -59,7 +59,7 @@ ob_start();
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-dollar-sign"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-dollar-sign"></i></span>
</div> </div>
<input type="text" class="form-control" inputmode="numeric" pattern="-?[0-9]*\.?[0-9]{0,2}" name="amount" value="<?php echo number_format($expense_amount, 2, '.', ''); ?>" placeholder="0.00" required> <input type="text" class="form-control" inputmode="decimal" pattern="-?[0-9]*\.?[0-9]{0,2}" name="amount" value="<?php echo number_format($expense_amount, 2, '.', ''); ?>" placeholder="0.00" required>
</div> </div>
</div> </div>

View File

@@ -54,7 +54,7 @@ ob_start();
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-dollar-sign"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-dollar-sign"></i></span>
</div> </div>
<input type="text" class="form-control" inputmode="numeric" pattern="-?[0-9]*\.?[0-9]{0,2}" name="amount" value="-<?php echo number_format($expense_amount, 2, '.', ''); ?>" placeholder="-0.00" required> <input type="text" class="form-control" inputmode="decimal" pattern="-?[0-9]*\.?[0-9]{0,2}" name="amount" value="-<?php echo number_format($expense_amount, 2, '.', ''); ?>" placeholder="-0.00" required>
</div> </div>
</div> </div>
</div> </div>
@@ -89,4 +89,3 @@ ob_start();
<?php <?php
require_once '../../../includes/modal_footer.php'; require_once '../../../includes/modal_footer.php';

View File

@@ -97,6 +97,16 @@ ob_start();
</div> </div>
</div> </div>
<div class='form-group'>
<label>Discount Amount</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='text' class='form-control' inputmode="decimal" pattern="-?[0-9]*\.?[0-9]{0,2}" name='invoice_discount' placeholder='0.00'>
</div>
</div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="submit" name="add_invoice" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Create</button> <button type="submit" name="add_invoice" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Create</button>

View File

@@ -91,7 +91,7 @@ ob_start();
<div class='input-group-prepend'> <div class='input-group-prepend'>
<span class='input-group-text'><i class='fa fa-fw fa-dollar-sign'></i></span> <span class='input-group-text'><i class='fa fa-fw fa-dollar-sign'></i></span>
</div> </div>
<input type='text' class='form-control' inputmode="numeric" pattern="-?[0-9]*\.?[0-9]{0,2}" name='invoice_discount' placeholder='0.00' value="<?php echo number_format($invoice_discount, 2, '.', ''); ?>"> <input type='text' class='form-control' inputmode="decimal" pattern="-?[0-9]*\.?[0-9]{0,2}" name='invoice_discount' placeholder='0.00' value="<?php echo number_format($invoice_discount, 2, '.', ''); ?>">
</div> </div>
</div> </div>

View File

@@ -47,7 +47,7 @@ ob_start();
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-balance-scale"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-balance-scale"></i></span>
</div> </div>
<input type="text" class="form-control" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,2}" name="qty" value="<?php echo number_format($item_quantity, 2); ?>" placeholder="0.00" required> <input type="text" class="form-control" inputmode="decimal" pattern="[0-9]*\.?[0-9]{0,2}" name="qty" value="<?php echo number_format($item_quantity, 2); ?>" placeholder="0.00" required>
</div> </div>
</div> </div>
</div> </div>
@@ -59,7 +59,7 @@ ob_start();
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-dollar-sign"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-dollar-sign"></i></span>
</div> </div>
<input type="text" class="form-control" inputmode="numeric" pattern="-?[0-9]*\.?[0-9]{0,2}" name="price" value="<?php echo number_format($item_price, 2, '.', ''); ?>" placeholder="0.00" required> <input type="text" class="form-control" inputmode="decimal" pattern="-?[0-9]*\.?[0-9]{0,2}" name="price" value="<?php echo number_format($item_price, 2, '.', ''); ?>" placeholder="0.00" required>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -39,7 +39,7 @@ ob_start();
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-wallet"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-wallet"></i></span>
</div> </div>
<input type="text" class="form-control" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,2}" name="amount_credit_applied" value="<?php echo number_format($credit_balance, 2, '.', ''); ?>" placeholder="0.00" required> <input type="text" class="form-control" inputmode="decimal" pattern="[0-9]*\.?[0-9]{0,2}" name="amount_credit_applied" value="<?php echo number_format($credit_balance, 2, '.', ''); ?>" placeholder="0.00" required>
</div> </div>
</div> </div>

View File

@@ -71,7 +71,7 @@ ob_start();
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-dollar-sign"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-dollar-sign"></i></span>
</div> </div>
<input type="text" class="form-control" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,2}" name="amount" value="<?php echo number_format($balance, 2, '.', ''); ?>" placeholder="0.00" required> <input type="text" class="form-control" inputmode="decimal" pattern="[0-9]*\.?[0-9]{0,2}" name="amount" value="<?php echo number_format($balance, 2, '.', ''); ?>" placeholder="0.00" required>
</div> </div>
</div> </div>

View File

@@ -74,7 +74,7 @@ ob_start();
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-dollar-sign"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-dollar-sign"></i></span>
</div> </div>
<input type="text" class="form-control" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,2}" name="amount" value="<?php echo number_format($balance, 2, '.', ''); ?>" placeholder="0.00" required> <input type="text" class="form-control" inputmode="decimal" pattern="[0-9]*\.?[0-9]{0,2}" name="amount" value="<?php echo number_format($balance, 2, '.', ''); ?>" placeholder="0.00" required>
</div> </div>
</div> </div>

View File

@@ -9,9 +9,12 @@ if ($type == 'product') {
$type_icon = "fa-wrench"; $type_icon = "fa-wrench";
} }
$product_types_array = ['product', 'service'];
ob_start(); ob_start();
?> ?>
<div class="modal-header bg-dark"> <div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fas fa-fw <?= $type_icon ?> mr-2"></i>New <strong><?= ucwords($type); ?></strong></h5> <h5 class="modal-title"><i class="fas fa-fw <?= $type_icon ?> mr-2"></i>New <strong><?= ucwords($type); ?></strong></h5>
<button type="button" class="close text-white" data-dismiss="modal"> <button type="button" class="close text-white" data-dismiss="modal">
@@ -19,7 +22,6 @@ ob_start();
</button> </button>
</div> </div>
<form action="post.php" method="post" autocomplete="off"> <form action="post.php" method="post" autocomplete="off">
<input type="hidden" name="type" value="<?= $type ?>">
<div class="modal-body"> <div class="modal-body">
@@ -33,6 +35,27 @@ ob_start();
</div> </div>
</div> </div>
<?php if ($type) { ?>
<input type="hidden" name="type" value="<?= $type ?>">
<?php } else { ?>
<div class="form-group">
<label>Type <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-tag"></i></span>
</div>
<select class="form-control select2" name="type" required>
<option value="">- Select Type -</option>
<?php foreach ($product_types_array as $type_select) { ?>
<option><?= $type_select ?></option>
<?php } ?>
</select>
</div>
</div>
<?php } ?>
<div class="form-group"> <div class="form-group">
<label>Category <strong class="text-danger">*</strong></label> <label>Category <strong class="text-danger">*</strong></label>
<div class="input-group"> <div class="input-group">
@@ -71,7 +94,7 @@ ob_start();
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-dollar-sign"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-dollar-sign"></i></span>
</div> </div>
<input type="text" class="form-control" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,2}" name="price" placeholder="0.00" required> <input type="text" class="form-control" inputmode="decimal" pattern="[0-9]*\.?[0-9]{0,2}" name="price" placeholder="0.00" required>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -78,7 +78,7 @@ ob_start();
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-dollar-sign"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-dollar-sign"></i></span>
</div> </div>
<input type="text" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,2}" class="form-control" name="price" value="<?php echo number_format($product_price, 2, '.', ''); ?>" placeholder="0.00" required> <input type="text" inputmode="decimal" pattern="[0-9]*\.?[0-9]{0,2}" class="form-control" name="price" value="<?php echo number_format($product_price, 2, '.', ''); ?>" placeholder="0.00" required>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -88,7 +88,7 @@ ob_start();
<div class='input-group-prepend'> <div class='input-group-prepend'>
<span class='input-group-text'><i class='fa fa-fw fa-dollar-sign'></i></span> <span class='input-group-text'><i class='fa fa-fw fa-dollar-sign'></i></span>
</div> </div>
<input type='text' class='form-control' inputmode="numeric" pattern="-?[0-9]*\.?[0-9]{0,2}" name='quote_discount' placeholder='0.00' value="<?php echo number_format($quote_discount, 2, '.', ''); ?>"> <input type='text' class='form-control' inputmode="decimal" pattern="-?[0-9]*\.?[0-9]{0,2}" name='quote_discount' placeholder='0.00' value="<?php echo number_format($quote_discount, 2, '.', ''); ?>">
</div> </div>
</div> </div>

View File

@@ -74,7 +74,7 @@ ob_start();
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-dollar-sign"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-dollar-sign"></i></span>
</div> </div>
<input type="text" class="form-control" inputmode="numeric" pattern="-?[0-9]*\.?[0-9]{0,2}" name="amount" placeholder="0.00" required> <input type="text" class="form-control" inputmode="decimal" pattern="-?[0-9]*\.?[0-9]{0,2}" name="amount" placeholder="0.00" required>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -97,7 +97,7 @@ ob_start();
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-dollar-sign"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-dollar-sign"></i></span>
</div> </div>
<input type="text" class="form-control" inputmode="numeric" pattern="-?[0-9]*\.?[0-9]{0,2}" name="amount" value="<?php echo number_format($recurring_expense_amount, 2, '.', ''); ?>" required> <input type="text" class="form-control" inputmode="decimal" pattern="-?[0-9]*\.?[0-9]{0,2}" name="amount" value="<?php echo number_format($recurring_expense_amount, 2, '.', ''); ?>" required>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -102,7 +102,7 @@ ob_start();
<div class='input-group-prepend'> <div class='input-group-prepend'>
<span class='input-group-text'><i class='fa fa-fw fa-dollar-sign'></i></span> <span class='input-group-text'><i class='fa fa-fw fa-dollar-sign'></i></span>
</div> </div>
<input type='text' class='form-control' inputmode="numeric" pattern="-?[0-9]*\.?[0-9]{0,2}" name='recurring_invoice_discount' placeholder='0.00' value="<?php echo number_format($recurring_invoice_discount, 2, '.', ''); ?>"> <input type='text' class='form-control' inputmode="decimal" pattern="-?[0-9]*\.?[0-9]{0,2}" name='recurring_invoice_discount' placeholder='0.00' value="<?php echo number_format($recurring_invoice_discount, 2, '.', ''); ?>">
</div> </div>
</div> </div>

View File

@@ -32,7 +32,7 @@ ob_start();
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-dollar-sign"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-dollar-sign"></i></span>
</div> </div>
<input type="text" class="form-control" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,2}" name="amount" placeholder="0.00" required> <input type="text" class="form-control" inputmode="decimal" pattern="[0-9]*\.?[0-9]{0,2}" name="amount" placeholder="0.00" required>
</div> </div>
</div> </div>

View File

@@ -49,7 +49,7 @@ ob_start();
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-dollar-sign"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-dollar-sign"></i></span>
</div> </div>
<input type="text" class="form-control" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,2}" name="amount" value="<?php echo number_format($revenue_amount, 2, '.', ''); ?>" placeholder="0.00" required> <input type="text" class="form-control" inputmode="decimal" pattern="[0-9]*\.?[0-9]{0,2}" name="amount" value="<?php echo number_format($revenue_amount, 2, '.', ''); ?>" placeholder="0.00" required>
</div> </div>
</div> </div>

View File

@@ -3,6 +3,7 @@
require_once '../../../includes/modal_header.php'; require_once '../../../includes/modal_header.php';
$ticket_id = intval($_GET['ticket_id']); $ticket_id = intval($_GET['ticket_id']);
$client_id = intval(getFieldById('tickets', $ticket_id, 'ticket_client_id'));
ob_start(); ob_start();

View File

@@ -10,7 +10,7 @@ ob_start();
?> ?>
<div class="modal-header bg-dark"> <div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-clone mr-2"></i>Merge & close <strong><?= $count ?></strong>tickets</h5> <h5 class="modal-title"><i class="fa fa-fw fa-clone mr-2"></i>Merge & close <strong><?= $count ?></strong> tickets</h5>
<button type="button" class="close text-white" data-dismiss="modal"> <button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span> <span>&times;</span>
</button> </button>
@@ -75,3 +75,5 @@ ob_start();
<!-- Ticket merge JS --> <!-- Ticket merge JS -->
<script src="/agent/js/ticket_merge.js"></script> <script src="/agent/js/ticket_merge.js"></script>
<?php require_once '../../../includes/modal_footer.php';

View File

@@ -38,33 +38,35 @@ while ($row = mysqli_fetch_array($sql_additional_assets)) {
ob_start(); ob_start();
?> ?>
<div class="modal-header bg-dark"> <div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-life-ring mr-2"></i>Editing ticket: <strong><?php echo "$ticket_prefix$ticket_number"; ?></strong> - <?php echo $client_name; ?></h5> <h5 class="modal-title"><i class="fa fa-fw fa-life-ring mr-2"></i>Ticket: <strong><?= "$ticket_prefix$ticket_number" ?></strong> - <?= $client_name ?></h5>
<button type="button" class="close text-white" data-dismiss="modal"> <button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span> <span>&times;</span>
</button> </button>
</div> </div>
<form action="post.php" method="post" autocomplete="off"> <form action="post.php" method="post" autocomplete="off">
<input type="hidden" name="ticket_id" value="<?php echo $ticket_id; ?>"> <input type="hidden" name="ticket_id" value="<?= $ticket_id ?>">
<div class="modal-body"> <div class="modal-body">
<?php if ($client_id) { ?>
<ul class="nav nav-pills nav-justified mb-3"> <ul class="nav nav-pills nav-justified mb-3">
<li class="nav-item"> <li class="nav-item">
<a class="nav-link active" data-toggle="pill" href="#pills-details<?php echo $ticket_id; ?>"><i class="fa fa-fw fa-life-ring mr-2"></i>Details</a> <a class="nav-link active" data-toggle="pill" href="#pills-details"><i class="fa fa-fw fa-life-ring mr-2"></i>Details</a>
</li> </li>
<li class="nav-item">
<a class="nav-link" data-toggle="pill" href="#pills-contacts<?php echo $ticket_id; ?>"><i class="fa fa-fw fa-users mr-2"></i>Contact</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="pill" href="#pills-assignment<?php echo $ticket_id; ?>"><i class="fa fa-fw fa-desktop mr-2"></i>Assignment</a>
</li>
</ul>
<li class="nav-item">
<a class="nav-link" data-toggle="pill" href="#pills-contacts"><i class="fa fa-fw fa-users mr-2"></i>Contact</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="pill" href="#pills-assignment"><i class="fa fa-fw fa-desktop mr-2"></i>Assignment</a>
</li>
</ul>
<hr> <hr>
<?php } ?>
<div class="tab-content" <?php if (lookupUserPermission('module_support') <= 1) { echo 'inert'; } ?>> <div class="tab-content" <?php if (lookupUserPermission('module_support') <= 1) { echo 'inert'; } ?>>
<div class="tab-pane fade show active" id="pills-details<?php echo $ticket_id; ?>"> <div class="tab-pane fade show active" id="pills-details">
<div class="form-group"> <div class="form-group">
<label>Subject <strong class="text-danger">*</strong></label> <label>Subject <strong class="text-danger">*</strong></label>
@@ -182,7 +184,9 @@ ob_start();
</div> </div>
<div class="tab-pane fade" id="pills-contacts<?php echo $ticket_id; ?>"> <?php if ($client_id) { ?>
<div class="tab-pane fade" id="pills-contacts">
<div class="form-group"> <div class="form-group">
<label>Contact</label> <label>Contact</label>
@@ -236,7 +240,7 @@ ob_start();
</div> </div>
<div class="tab-pane fade" id="pills-assignment<?php echo $ticket_id; ?>"> <div class="tab-pane fade" id="pills-assignment">
<div class="form-group"> <div class="form-group">
<label>Asset</label> <label>Asset</label>
@@ -372,7 +376,7 @@ ob_start();
while ($row = mysqli_fetch_array($sql_projects)) { while ($row = mysqli_fetch_array($sql_projects)) {
$project_id_select = intval($row['project_id']); $project_id_select = intval($row['project_id']);
$project_name_select = nullable_htmlentities($row['project_name']); ?> $project_name_select = nullable_htmlentities($row['project_name']); ?>
<option <?php if ($project_id == $project_id_select) { echo "selected"; } ?> value="<?php echo $project_id_select; ?>"><?php echo $project_name_select; ?></option> <option <?php if ($project_id == $project_id_select) { echo "selected"; } ?> value="<?= $project_id_select ?>"><?= $project_name_select ?></option>
<?php } ?> <?php } ?>
</select> </select>
@@ -380,13 +384,14 @@ ob_start();
</div> </div>
</div> </div>
<?php } // End client_id check ?>
</div> </div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="submit" name="edit_ticket" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Save</button> <button type="submit" name="edit_ticket" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Save changes</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Cancel</button> <button type="button" class="btn btn-light" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Cancel</button>
</div> </div>

View File

@@ -260,7 +260,7 @@ ob_start();
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-balance-scale"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-balance-scale"></i></span>
</div> </div>
<input type="text" class="form-control" inputmode="numeric" pattern="-?[0-9]*\.?[0-9]{0,2}" name="qty" value="<?php echo roundToNearest15($ticket_total_reply_time); ?>" required> <input type="text" class="form-control" inputmode="decimal" pattern="-?[0-9]*\.?[0-9]{0,2}" name="qty" value="<?php echo roundToNearest15($ticket_total_reply_time); ?>" required>
</div> </div>
<small class="form-text text-muted"> <small class="form-text text-muted">
Based off Ticket time spent <strong><?= $ticket_total_reply_time ?></strong> in 15 Min Increments rounded up. Based off Ticket time spent <strong><?= $ticket_total_reply_time ?></strong> in 15 Min Increments rounded up.
@@ -277,7 +277,7 @@ ob_start();
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-dollar-sign"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-dollar-sign"></i></span>
</div> </div>
<input type="text" class="form-control" inputmode="numeric" pattern="-?[0-9]*\.?[0-9]{0,2}" name="price" value="<?php echo number_format($client_rate, 2, '.', ''); ?>" required> <input type="text" class="form-control" inputmode="decimal" pattern="-?[0-9]*\.?[0-9]{0,2}" name="price" value="<?php echo number_format($client_rate, 2, '.', ''); ?>" required>
</div> </div>
<small class="form-text text-muted"> <small class="form-text text-muted">
Based off Hourly Client rate of <strong><?= numfmt_format_currency($currency_format, $client_rate, $session_company_currency); ?></strong> Based off Hourly Client rate of <strong><?= numfmt_format_currency($currency_format, $client_rate, $session_company_currency); ?></strong>

View File

@@ -32,7 +32,7 @@ ob_start();
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-dollar-sign"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-dollar-sign"></i></span>
</div> </div>
<input type="text" class="form-control" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,2}" name="amount" placeholder="0.00" required> <input type="text" class="form-control" inputmode="decimal" pattern="[0-9]*\.?[0-9]{0,2}" name="amount" placeholder="0.00" required>
</div> </div>
</div> </div>

View File

@@ -57,7 +57,7 @@ ob_start();
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-dollar-sign"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-dollar-sign"></i></span>
</div> </div>
<input type="text" class="form-control" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,2}" name="amount" placeholder="0.00" value="<?php echo number_format($transfer_amount, 2, '.', ''); ?>" required> <input type="text" class="form-control" inputmode="decimal" pattern="[0-9]*\.?[0-9]{0,2}" name="amount" placeholder="0.00" value="<?php echo number_format($transfer_amount, 2, '.', ''); ?>" required>
</div> </div>
</div> </div>

View File

@@ -34,7 +34,7 @@ ob_start();
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-bicycle"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-bicycle"></i></span>
</div> </div>
<input type="text" class="form-control" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,1}" name="miles" placeholder="0.0" required autofocus> <input type="text" class="form-control" inputmode="decimal" pattern="[0-9]*\.?[0-9]{0,1}" name="miles" placeholder="0.0" required autofocus>
<div class="input-group-append"> <div class="input-group-append">
<div class="input-group-text"> <div class="input-group-text">
<input type="checkbox" name="roundtrip" value="1"> <input type="checkbox" name="roundtrip" value="1">

View File

@@ -49,7 +49,7 @@ ob_start();
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-bicycle"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-bicycle"></i></span>
</div> </div>
<input type="text" class="form-control" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,1}" name="miles" value="<?php echo $trip_miles; ?>" placeholder="0.0" required> <input type="text" class="form-control" inputmode="decimal" pattern="[0-9]*\.?[0-9]{0,1}" name="miles" value="<?php echo $trip_miles; ?>" placeholder="0.0" required>
<div class="input-group-append"> <div class="input-group-append">
<div class="input-group-text"> <div class="input-group-text">
<input type="checkbox" name="roundtrip" value="1" <?php if ($round_trip == 1) { echo "checked"; } ?>> <input type="checkbox" name="roundtrip" value="1" <?php if ($round_trip == 1) { echo "checked"; } ?>>

View File

@@ -50,7 +50,7 @@ ob_start();
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-bicycle"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-bicycle"></i></span>
</div> </div>
<input type="text" class="form-control" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,1}" name="miles" value="<?php echo $trip_miles; ?>" placeholder="0.0" required> <input type="text" class="form-control" inputmode="decimal" pattern="[0-9]*\.?[0-9]{0,1}" name="miles" value="<?php echo $trip_miles; ?>" placeholder="0.0" required>
<div class="input-group-append"> <div class="input-group-append">
<div class="input-group-text"> <div class="input-group-text">
<input type="checkbox" name="roundtrip" value="1" <?php if ($round_trip == 1) { echo "checked"; } ?>> <input type="checkbox" name="roundtrip" value="1" <?php if ($round_trip == 1) { echo "checked"; } ?>>

View File

@@ -38,9 +38,6 @@ if (isset($_GET['account']) & !empty($_GET['account'])) {
$account_filter = ''; $account_filter = '';
} }
//Rebuild URL
$url_query_strings_sort = http_build_query($get_copy);
$sql = mysqli_query( $sql = mysqli_query(
$mysqli, $mysqli,
"SELECT SQL_CALC_FOUND_ROWS * FROM payments "SELECT SQL_CALC_FOUND_ROWS * FROM payments

View File

@@ -20,6 +20,14 @@ if (isset($_POST['add_asset'])) {
$asset_id = mysqli_insert_id($mysqli); $asset_id = mysqli_insert_id($mysqli);
// Add Tags
if (isset($_POST['tags'])) {
foreach($_POST['tags'] as $tag) {
$tag = intval($tag);
mysqli_query($mysqli, "INSERT INTO asset_tags SET asset_tag_asset_id = $asset_id, asset_tag_tag_id = $tag");
}
}
// Add Photo // Add Photo
if (isset($_FILES['file']['tmp_name'])) { if (isset($_FILES['file']['tmp_name'])) {
if ($new_file_name = checkFileUpload($_FILES['file'], array('jpg', 'jpeg', 'gif', 'png', 'webp'))) { if ($new_file_name = checkFileUpload($_FILES['file'], array('jpg', 'jpeg', 'gif', 'png', 'webp'))) {
@@ -108,6 +116,18 @@ if (isset($_POST['edit_asset'])) {
mysqli_query($mysqli,"UPDATE assets SET asset_photo = '$new_file_name' WHERE asset_id = $asset_id"); mysqli_query($mysqli,"UPDATE assets SET asset_photo = '$new_file_name' WHERE asset_id = $asset_id");
} }
// Tags
// Delete existing tags
mysqli_query($mysqli, "DELETE FROM asset_tags WHERE asset_tag_asset_id = $asset_id");
// Add new tags
if (isset($_POST['tags'])) {
foreach($_POST['tags'] as $tag) {
$tag = intval($tag);
mysqli_query($mysqli, "INSERT INTO asset_tags SET asset_tag_asset_id = $asset_id, asset_tag_tag_id = $tag");
}
}
logAction("Asset", "Edit", "$session_name edited asset $name", $client_id, $asset_id); logAction("Asset", "Edit", "$session_name edited asset $name", $client_id, $asset_id);
flash_alert("Asset <strong>$name</strong> edited"); flash_alert("Asset <strong>$name</strong> edited");
@@ -188,6 +208,50 @@ if (isset($_GET['delete_asset'])) {
} }
if (isset($_POST['bulk_assign_asset_tags'])) {
enforceUserPermission('module_client', 2);
if (isset($_POST['asset_ids'])) {
$count = count($_POST['asset_ids']);
foreach($_POST['asset_ids'] as $asset_id) {
$asset_id = intval($asset_id);
$sql = mysqli_query($mysqli,"SELECT asset_name, asset_client_id FROM assets WHERE asset_id = $asset_id");
$row = mysqli_fetch_array($sql);
$asset_name = sanitizeInput($row['asset_name']);
$client_id = intval($row['asset_client_id']);
if($_POST['remove_tags']) {
mysqli_query($mysqli, "DELETE FROM asset_tags WHERE asset_tag_asset_id = $asset_id");
}
if (isset($_POST['tags'])) {
foreach($_POST['tags'] as $tag) {
$tag = intval($tag);
$sql = mysqli_query($mysqli,"SELECT * FROM asset_tags WHERE asset_tag_asset_id = $asset_id AND asset_tag_tag_id = $tag");
if (mysqli_num_rows($sql) == 0) {
mysqli_query($mysqli, "INSERT INTO asset_tags SET asset_tag_asset_id = $asset_id, asset_tag_tag_id = $tag");
}
}
}
logAction("Asset", "Edit", "$session_name added tags to asset $asset_name", $client_id, $asset_id);
}
logAction("Asset", "Bulk Edit", "$session_name added tags for $asset_count assets", $client_id);
flash_alert("Assigned tags for <strong>$count</strong> assets");
}
redirect();
}
if (isset($_POST['bulk_assign_asset_location'])) { if (isset($_POST['bulk_assign_asset_location'])) {
validateCSRFToken($_POST['csrf_token']); validateCSRFToken($_POST['csrf_token']);

View File

@@ -14,107 +14,232 @@ if (isset($_POST['add_client'])) {
require_once 'client_model.php'; require_once 'client_model.php';
// Location inputs
$location_phone_country_code = preg_replace("/[^0-9]/", '', $_POST['location_phone_country_code']); $location_phone_country_code = preg_replace("/[^0-9]/", '', $_POST['location_phone_country_code']);
$location_phone = preg_replace("/[^0-9]/", '', $_POST['location_phone']); $location_phone = preg_replace("/[^0-9]/", '', $_POST['location_phone']);
$location_extension = preg_replace("/[^0-9]/", '', $_POST['location_extension']); $location_extension = preg_replace("/[^0-9]/", '', $_POST['location_extension']);
$location_fax_country_code = preg_replace("/[^0-9]/", '', $_POST['location_fax_country_code']); $location_fax_country_code = preg_replace("/[^0-9]/", '', $_POST['location_fax_country_code']);
$location_fax = preg_replace("/[^0-9]/", '', $_POST['location_fax']); $location_fax = preg_replace("/[^0-9]/", '', $_POST['location_fax']);
$address = sanitizeInput($_POST['address']); $address = cleanInput($_POST['address']);
$city = sanitizeInput($_POST['city']); $city = cleanInput($_POST['city']);
$state = sanitizeInput($_POST['state']); $state = cleanInput($_POST['state']);
$zip = sanitizeInput($_POST['zip']); $zip = cleanInput($_POST['zip']);
$country = sanitizeInput($_POST['country']); $country = cleanInput($_POST['country']);
$contact = sanitizeInput($_POST['contact']);
$title = sanitizeInput($_POST['title']); // Contact inputs
$contact = cleanInput($_POST['contact']);
$title = cleanInput($_POST['title']);
$contact_phone_country_code = preg_replace("/[^0-9]/", '', $_POST['contact_phone_country_code']); $contact_phone_country_code = preg_replace("/[^0-9]/", '', $_POST['contact_phone_country_code']);
$contact_phone = preg_replace("/[^0-9]/", '', $_POST['contact_phone']); $contact_phone = preg_replace("/[^0-9]/", '', $_POST['contact_phone']);
$contact_extension = preg_replace("/[^0-9]/", '', $_POST['contact_extension']); $contact_extension = preg_replace("/[^0-9]/", '', $_POST['contact_extension']);
$contact_mobile_country_code = preg_replace("/[^0-9]/", '', $_POST['contact_mobile_country_code']); $contact_mobile_country_code = preg_replace("/[^0-9]/", '', $_POST['contact_mobile_country_code']);
$contact_mobile = preg_replace("/[^0-9]/", '', $_POST['contact_mobile']); $contact_mobile = preg_replace("/[^0-9]/", '', $_POST['contact_mobile']);
$contact_email = sanitizeInput($_POST['contact_email']); $contact_email = cleanInput($_POST['contact_email']);
$extended_log_description = ''; $extended_log_description = '';
// Create client // Insert client using SET
mysqli_query($mysqli, "INSERT INTO clients SET client_name = '$name', client_type = '$type', client_website = '$website', client_referral = '$referral', client_rate = $rate, client_currency_code = '$session_company_currency', client_net_terms = $net_terms, client_tax_id_number = '$tax_id_number', client_lead = $lead, client_abbreviation = '$abbreviation', client_notes = '$notes', client_accessed_at = NOW()"); $query = mysqli_prepare(
$mysqli,
"INSERT INTO clients SET
client_name = ?,
client_type = ?,
client_website = ?,
client_referral = ?,
client_rate = ?,
client_currency_code = ?,
client_net_terms = ?,
client_tax_id_number = ?,
client_lead = ?,
client_abbreviation = ?,
client_notes = ?,
client_accessed_at = NOW()"
);
mysqli_stmt_bind_param(
$query,
"ssssdsiisss",
$name,
$type,
$website,
$referral,
$rate,
$session_company_currency,
$net_terms,
$tax_id_number,
$lead,
$abbreviation,
$notes
);
mysqli_stmt_execute($query);
$client_id = mysqli_insert_id($mysqli); $client_id = mysqli_insert_id($mysqli);
if (!file_exists($_SERVER['DOCUMENT_ROOT'] . "/uploads/clients/$client_id")) { // Create client folder
mkdir($_SERVER['DOCUMENT_ROOT'] . "/uploads/clients/$client_id"); $client_folder = $_SERVER['DOCUMENT_ROOT'] . "/uploads/clients/$client_id";
file_put_contents($_SERVER['DOCUMENT_ROOT'] . "/uploads/clients/$client_id/index.php", ""); if (!file_exists($client_folder)) {
mkdir($client_folder);
file_put_contents("$client_folder/index.php", "");
} }
// Create Referral if it doesn't exist // Create referral category if it doesn't exist
$sql = mysqli_query($mysqli, "SELECT category_name FROM categories WHERE category_type = 'Referral' AND category_archived_at IS NULL AND category_name = '$referral'"); $query = mysqli_prepare($mysqli, "SELECT category_name FROM categories WHERE category_type = 'Referral' AND category_archived_at IS NULL AND category_name = ?");
if(mysqli_num_rows($sql) == 0) { mysqli_stmt_bind_param($query, "s", $referral);
mysqli_query($mysqli, "INSERT INTO categories SET category_name = '$referral', category_type = 'Referral'"); mysqli_stmt_execute($query);
mysqli_stmt_store_result($query);
if (mysqli_stmt_num_rows($query) == 0) {
$query = mysqli_prepare($mysqli, "INSERT INTO categories SET category_name = ?, category_type = 'Referral'");
mysqli_stmt_bind_param($query, "s", $referral);
mysqli_stmt_execute($query);
logAction("Category", "Create", "$session_name created referral category $referral"); logAction("Category", "Create", "$session_name created referral category $referral");
} }
// Create Location // Insert primary location using SET
if (!empty($location_phone) || !empty($address) || !empty($city) || !empty($state) || !empty($zip)) { if (!empty($location_phone) || !empty($address) || !empty($city) || !empty($state) || !empty($zip)) {
mysqli_query($mysqli, "INSERT INTO locations SET location_name = 'Primary', location_address = '$address', location_city = '$city', location_state = '$state', location_zip = '$zip', location_phone_country_code = '$location_phone_country_code', location_phone = '$location_phone', location_phone_extension = '$location_extension', location_fax_country_code = '$location_fax_country_code', location_fax = '$location_fax', location_country = '$country', location_primary = 1, location_client_id = $client_id"); $query = mysqli_prepare(
$mysqli,
//Extended Logging "INSERT INTO locations SET
location_name = 'Primary',
location_address = ?,
location_city = ?,
location_state = ?,
location_zip = ?,
location_phone_country_code = ?,
location_phone = ?,
location_phone_extension = ?,
location_fax_country_code = ?,
location_fax = ?,
location_country = ?,
location_primary = 1,
location_client_id = ?"
);
mysqli_stmt_bind_param(
$query,
"ssssssssssi",
$address,
$city,
$state,
$zip,
$location_phone_country_code,
$location_phone,
$location_extension,
$location_fax_country_code,
$location_fax,
$country,
$client_id
);
mysqli_stmt_execute($query);
$extended_log_description .= ", primary location $address added"; $extended_log_description .= ", primary location $address added";
} }
// Insert primary contact using SET
// Create Contact
if (!empty($contact) || !empty($title) || !empty($contact_phone) || !empty($contact_mobile) || !empty($contact_email)) { if (!empty($contact) || !empty($title) || !empty($contact_phone) || !empty($contact_mobile) || !empty($contact_email)) {
mysqli_query($mysqli, "INSERT INTO contacts SET contact_name = '$contact', contact_title = '$title', contact_phone_country_code = '$contact_phone_country_code', contact_phone = '$contact_phone', contact_extension = '$contact_extension', contact_mobile_country_code = '$contact_mobile_country_code', contact_mobile = '$contact_mobile', contact_email = '$contact_email', contact_primary = 1, contact_important = 1, contact_client_id = $client_id"); $query = mysqli_prepare(
$mysqli,
//Extended Logging "INSERT INTO contacts SET
contact_name = ?,
contact_title = ?,
contact_phone_country_code = ?,
contact_phone = ?,
contact_extension = ?,
contact_mobile_country_code = ?,
contact_mobile = ?,
contact_email = ?,
contact_primary = 1,
contact_important = 1,
contact_client_id = ?"
);
mysqli_stmt_bind_param(
$query,
"ssssssssi",
$contact,
$title,
$contact_phone_country_code,
$contact_phone,
$contact_extension,
$contact_mobile_country_code,
$contact_mobile,
$contact_email,
$client_id
);
mysqli_stmt_execute($query);
$extended_log_description .= ", primary contact $contact added"; $extended_log_description .= ", primary contact $contact added";
} }
// Add Tags // Add tags
if (isset($_POST['tags'])) { if (isset($_POST['tags'])) {
$query = mysqli_prepare($mysqli, "INSERT INTO client_tags SET client_id = ?, tag_id = ?");
foreach ($_POST['tags'] as $tag) { foreach ($_POST['tags'] as $tag) {
$tag = intval($tag); $tag = intval($tag);
mysqli_query($mysqli, "INSERT INTO client_tags SET client_id = $client_id, tag_id = $tag"); mysqli_stmt_bind_param($query, "ii", $client_id, $tag);
mysqli_stmt_execute($query);
} }
} }
// Create domain in domains/certificates // Insert domain and SSL using SET
if (!empty($website) && filter_var($website, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME)) { if (!empty($website) && filter_var($website, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME)) {
// Get domain expiry date
$expire = getDomainExpirationDate($website); $expire = getDomainExpirationDate($website);
// NS, MX, A and WHOIS records/data
$records = getDomainRecords($website); $records = getDomainRecords($website);
$a = sanitizeInput($records['a']); $a = cleanInput($records['a']);
$ns = sanitizeInput($records['ns']); $ns = cleanInput($records['ns']);
$mx = sanitizeInput($records['mx']); $mx = cleanInput($records['mx']);
$whois = sanitizeInput($records['whois']); $whois = cleanInput($records['whois']);
// Add domain record info using whois, or not
try { try {
mysqli_query($mysqli, "INSERT INTO domains SET domain_name = '$website', domain_registrar = 0, domain_webhost = 0, domain_expire = '$expire', domain_ip = '$a', domain_name_servers = '$ns', domain_mail_servers = '$mx', domain_raw_whois = '$whois', domain_client_id = $client_id"); $query = mysqli_prepare(
$extended_log_description .= ", domain $website added"; //Extended Logging $mysqli,
"INSERT INTO domains SET
domain_name = ?,
domain_registrar = 0,
domain_webhost = 0,
domain_expire = ?,
domain_ip = ?,
domain_name_servers = ?,
domain_mail_servers = ?,
domain_raw_whois = ?,
domain_client_id = ?"
);
mysqli_stmt_bind_param($query, "ssssssi", $website, $expire, $a, $ns, $mx, $whois, $client_id);
mysqli_stmt_execute($query);
$extended_log_description .= ", domain $website added";
} catch (Exception $e) { } catch (Exception $e) {
$extended_log_description .= ", domain not added"; //Extended Logging $extended_log_description .= ", domain not added";
logApp("Client", "warning", "Failed to add domain $website during client creation (usually a whois result error)"); logApp("Client", "warning", "Failed to add domain $website during client creation");
} }
// Get inserted ID (for linking certificate, if exists)
$domain_id = mysqli_insert_id($mysqli); $domain_id = mysqli_insert_id($mysqli);
// Get SSL cert for domain (if exists)
$certificate = getSSL($website); $certificate = getSSL($website);
if ($certificate['success'] == "TRUE") { if ($certificate['success'] == "TRUE") {
$expire = sanitizeInput($certificate['expire']); $expire = cleanInput($certificate['expire']);
$issued_by = sanitizeInput($certificate['issued_by']); $issued_by = cleanInput($certificate['issued_by']);
$public_key = sanitizeInput($certificate['public_key']); $public_key = cleanInput($certificate['public_key']);
mysqli_query($mysqli, "INSERT INTO certificates SET certificate_name = '$website', certificate_domain = '$website', certificate_issued_by = '$issued_by', certificate_expire = '$expire', certificate_public_key = '$public_key', certificate_domain_id = $domain_id, certificate_client_id = $client_id"); $query = mysqli_prepare(
$mysqli,
"INSERT INTO certificates SET
certificate_name = ?,
certificate_domain = ?,
certificate_issued_by = ?,
certificate_expire = ?,
certificate_public_key = ?,
certificate_domain_id = ?,
certificate_client_id = ?"
);
mysqli_stmt_bind_param(
$query,
"sssssii",
$website,
$website,
$issued_by,
$expire,
$public_key,
$domain_id,
$client_id
);
mysqli_stmt_execute($query);
//Extended Logging
$extended_log_description .= ", SSL certificate $website added"; $extended_log_description .= ", SSL certificate $website added";
} }
} }
logAction("Client", "Create", "$session_name created client $name$extended_log_description", $client_id, $client_id); logAction("Client", "Create", "$session_name created client $name$extended_log_description", $client_id, $client_id);
@@ -1390,22 +1515,25 @@ if (isset($_POST["export_client_pdf"])) {
<th>Description</th> <th>Description</th>
<th>Username</th> <th>Username</th>
<th>Password</th> <th>Password</th>
<th>TOTP</th>
<th>URI</th> <th>URI</th>
</tr> </tr>
</thead> </thead>
<tbody>"; <tbody>";
while ($row = mysqli_fetch_array($sql_credentials)) { while ($row = mysqli_fetch_array($sql_credentials)) {
$credential_name = nullable_htmlentities($row["credential_name"]); $credential_name = nullable_htmlentities($row["credential_name"]);
$credential_description = nullable_htmlentities($row["credential_description"]); $credential_description = getFallback(nullable_htmlentities($row["credential_description"]));
$credential_username = nullable_htmlentities(decryptCredentialEntry($row["credential_username"])); $credential_username = nullable_htmlentities(decryptCredentialEntry($row["credential_username"]));
$credential_password = nullable_htmlentities(decryptCredentialEntry($row["credential_password"])); $credential_password = nullable_htmlentities(decryptCredentialEntry($row["credential_password"]));
$credential_uri = nullable_htmlentities($row["credential_uri"]); $credential_totp_secret = getFallback(nullable_htmlentities($row['credential_otp_secret']));
$credential_uri = getFallback(nullable_htmlentities($row["credential_uri"]));
$html .= " $html .= "
<tr> <tr>
<td>$credential_name</td> <td>$credential_name</td>
<td>$credential_description</td> <td>$credential_description</td>
<td>$credential_username</td> <td>$credential_username</td>
<td>$credential_password</td> <td>$credential_password</td>
<td>$credential_totp_secret</td>
<td>$credential_uri</td> <td>$credential_uri</td>
</tr>"; </tr>";
} }

View File

@@ -1,16 +1,16 @@
<?php <?php
defined('FROM_POST_HANDLER') || die("Direct file access is not allowed"); defined('FROM_POST_HANDLER') || die("Direct file access is not allowed");
$name = sanitizeInput($_POST['name']); $name = cleanInput($_POST['name']);
$type = sanitizeInput($_POST['type']); $type = cleanInput($_POST['type']);
$website = preg_replace("(^https?://)", "", sanitizeInput($_POST['website'])); $website = preg_replace("(^https?://)", "", cleanInput($_POST['website']));
$referral = sanitizeInput($_POST['referral']); $referral = cleanInput($_POST['referral']);
$rate = floatval($_POST['rate'] ?? 0); $rate = floatval($_POST['rate'] ?? 0);
$net_terms = intval($_POST['net_terms'] ?? $config_default_net_terms); $net_terms = intval($_POST['net_terms'] ?? $config_default_net_terms);
$tax_id_number = sanitizeInput($_POST['tax_id_number'] ?? ''); $tax_id_number = cleanInput($_POST['tax_id_number'] ?? '');
$abbreviation = sanitizeInput($_POST['abbreviation']); $abbreviation = cleanInput($_POST['abbreviation'] ?? '');
if (empty($abbreviation)) { if (empty($abbreviation)) {
$abbreviation = shortenClient($name); $abbreviation = shortenClient($name);
} }
$notes = sanitizeInput($_POST['notes']); $notes = cleanInput($_POST['notes'] ?? '');
$lead = intval($_POST['lead'] ?? 0); $lead = intval($_POST['lead'] ?? 0);

View File

@@ -16,10 +16,23 @@ if (isset($_POST['add_document'])) {
$asset_id = intval($_POST['asset'] ?? 0); $asset_id = intval($_POST['asset'] ?? 0);
// Document add query // Document add query
mysqli_query($mysqli,"INSERT INTO documents SET document_name = '$name', document_description = '$description', document_content = '$content', document_content_raw = '$content_raw', document_folder_id = $folder, document_created_by = $session_user_id, document_client_id = $client_id"); mysqli_query($mysqli,"INSERT INTO documents SET document_name = '$name', document_description = '$description', document_content = '', document_content_raw = '$content_raw', document_folder_id = $folder, document_created_by = $session_user_id, document_client_id = $client_id");
$document_id = mysqli_insert_id($mysqli); $document_id = mysqli_insert_id($mysqli);
$processed_content = mysqli_escape_string(
$mysqli,
saveBase64Images(
$_POST['content'],
$_SERVER['DOCUMENT_ROOT'] . "/uploads/documents/",
"uploads/documents/",
$document_id
)
);
// Document update content
mysqli_query($mysqli,"UPDATE documents SET document_content = '$processed_content' WHERE document_id = $document_id");
if ($contact_id) { if ($contact_id) {
mysqli_query($mysqli,"INSERT INTO contact_documents SET contact_id = $contact_id, document_id = $document_id"); mysqli_query($mysqli,"INSERT INTO contact_documents SET contact_id = $contact_id, document_id = $document_id");
} }
@@ -38,36 +51,82 @@ if (isset($_POST['add_document'])) {
if (isset($_POST['add_document_from_template'])) { if (isset($_POST['add_document_from_template'])) {
// ROLE Check
enforceUserPermission('module_support', 2); enforceUserPermission('module_support', 2);
// GET POST Data $client_id = intval($_POST['client_id']);
$client_id = intval($_POST['client_id']); $document_name = sanitizeInput($_POST['name']);
$document_name = sanitizeInput($_POST['name']); $document_description = sanitizeInput($_POST['description']);
$document_description = sanitizeInput($_POST['description']); $document_template_id = intval($_POST['document_template_id']);
$document_template_id = intval($_POST['document_template_id']); $folder = intval($_POST['folder']);
$folder = intval($_POST['folder']);
// GET Document Template Info // Get template
$sql_document = mysqli_query($mysqli,"SELECT * FROM document_templates WHERE document_template_id = $document_template_id"); $sql_document = mysqli_query(
$mysqli,
"SELECT * FROM document_templates
WHERE document_template_id = $document_template_id"
);
$row = mysqli_fetch_array($sql_document); $row = mysqli_fetch_array($sql_document);
$document_template_name = sanitizeInput($row['document_template_name']); $document_template_name = sanitizeInput($row['document_template_name']);
$content = mysqli_real_escape_string($mysqli,$row['document_template_content']); $template_content_html = $row['document_template_content']; // raw HTML from template
$content_raw = sanitizeInput($_POST['name'] . " " . str_replace("<", " <", $row['document_content']));
// Document add query // 1) Create the new document with placeholder content to get an ID
mysqli_query($mysqli,"INSERT INTO documents SET document_name = '$document_name', document_description = '$document_description', document_content = '$content', document_content_raw = '$content_raw', document_folder_id = $folder, document_created_by = $session_user_id, document_client_id = $client_id"); mysqli_query(
$mysqli,
"INSERT INTO documents SET
document_name = '$document_name',
document_description = '$document_description',
document_content = '',
document_content_raw = '',
document_folder_id = $folder,
document_created_by = $session_user_id,
document_client_id = $client_id"
);
$document_id = mysqli_insert_id($mysqli); $document_id = mysqli_insert_id($mysqli);
logAction("Document", "Create", "$session_name created document $name from template $document_template_name", $client_id, $document_id); // 2) Copy template images to the document's folder
$templateFsPath = $_SERVER['DOCUMENT_ROOT'] . "/uploads/document_templates/" . $document_template_id;
$documentFsPath = $_SERVER['DOCUMENT_ROOT'] . "/uploads/documents/" . $document_id;
copyDirectory($templateFsPath, $documentFsPath);
// 3) Rewrite image paths in the HTML
// /uploads/document_templates/{template_id}/ -> /uploads/documents/{document_id}/
$oldPath = "/uploads/document_templates/" . $document_template_id . "/";
$newPath = "/uploads/documents/" . $document_id . "/";
$processed_html = str_replace($oldPath, $newPath, $template_content_html);
// 4) Prepare content + content_raw
$content = mysqli_real_escape_string($mysqli, $processed_html);
$content_raw = sanitizeInput(
$document_name . " " . str_replace("<", " <", $processed_html)
);
$content_raw = mysqli_real_escape_string($mysqli, $content_raw);
// 5) Update the document with final content
mysqli_query(
$mysqli,
"UPDATE documents SET
document_content = '$content',
document_content_raw = '$content_raw'
WHERE document_id = $document_id"
);
logAction(
"Document",
"Create",
"$session_name created document $document_name from template $document_template_name",
$client_id,
$document_id
);
flash_alert("Document <strong>$document_name</strong> created from template"); flash_alert("Document <strong>$document_name</strong> created from template");
redirect("document_details.php?client_id=$client_id&document_id=$document_id"); redirect("document_details.php?client_id=$client_id&document_id=$document_id");
} }
if (isset($_POST['edit_document'])) { if (isset($_POST['edit_document'])) {
@@ -75,22 +134,26 @@ if (isset($_POST['edit_document'])) {
enforceUserPermission('module_support', 2); enforceUserPermission('module_support', 2);
require_once 'document_model.php'; require_once 'document_model.php';
$document_id = intval($_POST['document_id']); $document_id = intval($_POST['document_id']);
// Save Original Document as a Version // 1) Load the current document to create a version
$sql_original_document = mysqli_query($mysqli, "SELECT * FROM documents $sql_original_document = mysqli_query(
WHERE document_client_id = $client_id AND document_id = $document_id" $mysqli,
"SELECT * FROM documents
WHERE document_client_id = $client_id
AND document_id = $document_id"
); );
$row = mysqli_fetch_array($sql_original_document); $row = mysqli_fetch_array($sql_original_document);
$original_document_name = sanitizeInput($row['document_name']); $original_document_name = sanitizeInput($row['document_name']);
$original_document_description = sanitizeInput($row['document_description']); $original_document_description = sanitizeInput($row['document_description']);
$original_document_content = mysqli_escape_string($mysqli, $row['document_content']); $original_document_content = mysqli_real_escape_string($mysqli, $row['document_content']);
$original_document_created_by = intval($row['document_created_by']); $original_document_created_by = intval($row['document_created_by']);
$original_document_updated_by = intval($row['document_updated_by']); $original_document_updated_by = intval($row['document_updated_by']);
$original_document_created_at = sanitizeInput($row['document_created_at']); $original_document_created_at = sanitizeInput($row['document_created_at']);
$original_document_updated_at = sanitizeInput($row['document_updated_at']); $original_document_updated_at = sanitizeInput($row['document_updated_at']);
if ($original_document_updated_at) { if ($original_document_updated_at) {
$document_version_created_at = $original_document_updated_at; $document_version_created_at = $original_document_updated_at;
@@ -104,19 +167,66 @@ if (isset($_POST['edit_document'])) {
$document_version_created_by = $original_document_created_by; $document_version_created_by = $original_document_created_by;
} }
// Document add query // 2) Save the current version into document_versions
mysqli_query($mysqli,"INSERT INTO document_versions SET document_version_name = '$original_document_name', document_version_description = '$original_document_description', document_version_content = '$original_document_content', document_version_created_by = $document_version_created_by, document_version_created_at = '$document_version_created_at', document_version_document_id = $document_id"); mysqli_query(
$mysqli,
"INSERT INTO document_versions SET
document_version_name = '$original_document_name',
document_version_description = '$original_document_description',
document_version_content = '$original_document_content',
document_version_created_by = $document_version_created_by,
document_version_created_at = '$document_version_created_at',
document_version_document_id = $document_id"
);
$document_version_id = mysqli_insert_id($mysqli); $document_version_id = mysqli_insert_id($mysqli);
// Update Document // 3) Process the NEW content from the form:
mysqli_query($mysqli,"UPDATE documents SET document_name = '$name', document_description = '$description', document_content = '$content', document_content_raw = '$content_raw', document_folder_id = $folder, document_updated_by = $session_user_id WHERE document_id = $document_id"); // - convert base64 <img> tags to files under /uploads/documents/<document_id>/
// - rewrite <img src> to file URLs
$raw_post_content = $_POST['content'];
logAction("Document", "Edit", "$session_name edited document $name, previous version kept", $client_id, $document_version_id); $processed_html = saveBase64Images(
$raw_post_content,
$_SERVER['DOCUMENT_ROOT'] . "/uploads/documents/",
"uploads/documents/",
$document_id
);
// Escape for DB
$content = mysqli_real_escape_string($mysqli, $processed_html);
// Rebuild content_raw for full-text search
$content_raw = sanitizeInput(
$name . " " . str_replace("<", " <", $processed_html)
);
$content_raw = mysqli_real_escape_string($mysqli, $content_raw);
// 4) Update the document with the new content + metadata
mysqli_query(
$mysqli,
"UPDATE documents SET
document_name = '$name',
document_description = '$description',
document_content = '$content',
document_content_raw = '$content_raw',
document_folder_id = $folder,
document_updated_by = $session_user_id
WHERE document_id = $document_id"
);
logAction(
"Document",
"Edit",
"$session_name edited document $name, previous version kept",
$client_id,
$document_version_id
);
flash_alert("Document <strong>$name</strong> edited, previous version kept"); flash_alert("Document <strong>$name</strong> edited, previous version kept");
redirect("document_details.php?client_id=$client_id&document_id=$document_id"); redirect("document_details.php?client_id=$client_id&document_id=$document_id");
} }
if (isset($_POST['move_document'])) { if (isset($_POST['move_document'])) {
@@ -629,6 +739,9 @@ if (isset($_GET['delete_document'])) {
// Delete all versions associated with the master document // Delete all versions associated with the master document
mysqli_query($mysqli,"DELETE FROM document_versions WHERE document_version_document_id = $document_id"); mysqli_query($mysqli,"DELETE FROM document_versions WHERE document_version_document_id = $document_id");
// Delete uploads/document/$document_id if exists
removeDirectory($_SERVER['DOCUMENT_ROOT'] . "/uploads/documents/" . $document_id);
logAction("Document", "Delete", "$session_name deleted document $document_name and all versions", $client_id); logAction("Document", "Delete", "$session_name deleted document $document_name and all versions", $client_id);
flash_alert("Document <strong>$document_name</strong> deleted and all versions", 'error'); flash_alert("Document <strong>$document_name</strong> deleted and all versions", 'error');
@@ -670,6 +783,9 @@ if (isset($_POST['bulk_delete_documents'])) {
// Delete all versions associated with the master document // Delete all versions associated with the master document
mysqli_query($mysqli,"DELETE FROM document_versions WHERE document_version_document_id = $document_id"); mysqli_query($mysqli,"DELETE FROM document_versions WHERE document_version_document_id = $document_id");
// Delete uploads/document/$document_id if exists
removeDirectory($_SERVER['DOCUMENT_ROOT'] . "/uploads/documents/" . $document_id);
logAction("Document", "Delete", "$session_name deleted document $document_name and all versions", $client_id); logAction("Document", "Delete", "$session_name deleted document $document_name and all versions", $client_id);
} }

View File

@@ -12,6 +12,8 @@ if (isset($_POST['add_invoice'])) {
$client_id = intval($_POST['client']); $client_id = intval($_POST['client']);
$invoice_amount = 0 - $invoice_discount; // Calc amount if discount is applied, otherwise wrongly shows 0
// Get Net Terms // Get Net Terms
$client_net_terms = intval(getFieldById('clients', $client_id, 'client_net_terms')); $client_net_terms = intval(getFieldById('clients', $client_id, 'client_net_terms'));
@@ -23,7 +25,7 @@ if (isset($_POST['add_invoice'])) {
//Generate a unique URL key for clients to access //Generate a unique URL key for clients to access
$url_key = randomString(156); $url_key = randomString(156);
mysqli_query($mysqli,"INSERT INTO invoices SET invoice_prefix = '$config_invoice_prefix', invoice_number = $invoice_number, invoice_scope = '$scope', invoice_date = '$date', invoice_due = DATE_ADD('$date', INTERVAL $client_net_terms day), invoice_currency_code = '$session_company_currency', invoice_category_id = $category, invoice_status = 'Draft', invoice_url_key = '$url_key', invoice_client_id = $client_id"); mysqli_query($mysqli,"INSERT INTO invoices SET invoice_prefix = '$config_invoice_prefix', invoice_number = $invoice_number, invoice_scope = '$scope', invoice_date = '$date', invoice_due = DATE_ADD('$date', INTERVAL $client_net_terms day), invoice_discount_amount = '$invoice_discount', invoice_amount = '$invoice_amount', invoice_currency_code = '$session_company_currency', invoice_category_id = $category, invoice_status = 'Draft', invoice_url_key = '$url_key', invoice_client_id = $client_id");
$invoice_id = mysqli_insert_id($mysqli); $invoice_id = mysqli_insert_id($mysqli);

View File

@@ -497,7 +497,7 @@ if (isset($_GET['email_quote'])) {
logAction("Quote", "Email", "$session_name emailed quote $quote_prefix$quote_number to $contact_email", $client_id, $quote_id); logAction("Quote", "Email", "$session_name emailed quote $quote_prefix$quote_number to $contact_email", $client_id, $quote_id);
flash_alert("Quote has been queued successfully! <a class='text-bold text-light' href='admin_mail_queue.php'>See Mail Queue</a>"); flash_alert("Quote sent!");
//Don't change the status to sent if the status is anything but draft //Don't change the status to sent if the status is anything but draft
if ($quote_status == 'Draft') { if ($quote_status == 'Draft') {

View File

@@ -1814,14 +1814,19 @@ if (isset($_POST['merge_ticket'])) {
// NEW PARENT ticket details // NEW PARENT ticket details
// Get merge into ticket id (as it may differ from the number) // Get merge into ticket id (as it may differ from the number)
$sql = mysqli_query($mysqli, "SELECT ticket_id FROM tickets WHERE ticket_number = $merge_into_ticket_number"); $sql = mysqli_query($mysqli, "SELECT ticket_id, ticket_client_id FROM tickets WHERE ticket_number = $merge_into_ticket_number");
if (mysqli_num_rows($sql) == 0) { if (mysqli_num_rows($sql) == 0) {
flash_alert("Cannot merge into that ticket.", 'error'); flash_alert("Cannot merge into that ticket.", 'error');
redirect(); redirect();
} }
$merge_row = mysqli_fetch_array($sql); $merge_row = mysqli_fetch_array($sql);
$merge_into_ticket_id = intval($merge_row['ticket_id']); $merge_into_ticket_id = intval($merge_row['ticket_id']);
$client_id = intval($merge_row['ticket_client_id']);
if ($client_id) {
$has_client = "&client_id=$client_id";
} else {
$has_client = "";
}
// Sanity check // Sanity check
if ($ticket_number == $merge_into_ticket_number) { if ($ticket_number == $merge_into_ticket_number) {
flash_alert("Cannot merge into the same ticket.", 'error'); flash_alert("Cannot merge into the same ticket.", 'error');
@@ -1853,7 +1858,7 @@ if (isset($_POST['merge_ticket'])) {
flash_alert("Ticket merged into $ticket_prefix$merge_into_ticket_number"); flash_alert("Ticket merged into $ticket_prefix$merge_into_ticket_number");
redirect(); redirect("ticket.php?ticket_id=$merge_into_ticket_id$has_client");
} }

View File

@@ -382,10 +382,10 @@ if (isset($_GET['quote_id'])) {
<textarea class="form-control" rows="2" name="description" id="desc" placeholder="Enter a Description"></textarea> <textarea class="form-control" rows="2" name="description" id="desc" placeholder="Enter a Description"></textarea>
</td> </td>
<td> <td>
<input type="text" class="form-control" inputmode="numeric" pattern="-?[0-9]*\.?[0-9]{0,2}" id="qty" style="text-align: center;" name="qty" placeholder="Qty"> <input type="text" class="form-control" inputmode="decimal" pattern="-?[0-9]*\.?[0-9]{0,2}" id="qty" style="text-align: center;" name="qty" placeholder="Qty">
</td> </td>
<td> <td>
<input type="text" class="form-control" inputmode="numeric" pattern="-?[0-9]*\.?[0-9]{0,2}" id="price" style="text-align: right;" name="price" placeholder="Price (<?php echo $quote_currency_code; ?>)"> <input type="text" class="form-control" inputmode="decimal" pattern="-?[0-9]*\.?[0-9]{0,2}" id="price" style="text-align: right;" name="price" placeholder="Price (<?php echo $quote_currency_code; ?>)">
</td> </td>
<td> <td>
<select class="form-control select2" id="tax" name="tax_id" required> <select class="form-control select2" id="tax" name="tax_id" required>

View File

@@ -9,9 +9,6 @@ require_once "includes/inc_all.php";
// Perms // Perms
enforceUserPermission('module_financial'); enforceUserPermission('module_financial');
//Rebuild URL
$url_query_strings_sort = http_build_query($get_copy);
$sql = mysqli_query( $sql = mysqli_query(
$mysqli, $mysqli,
"SELECT SQL_CALC_FOUND_ROWS * FROM recurring_expenses "SELECT SQL_CALC_FOUND_ROWS * FROM recurring_expenses

View File

@@ -340,10 +340,10 @@ if (isset($_GET['recurring_invoice_id'])) {
<textarea class="form-control" rows="2" id="desc" name="description" placeholder="Enter a Description"></textarea> <textarea class="form-control" rows="2" id="desc" name="description" placeholder="Enter a Description"></textarea>
</td> </td>
<td> <td>
<input type="text" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,2}" class="form-control" style="text-align: center;" id="qty" name="qty" placeholder="Qty"> <input type="text" inputmode="decimal" pattern="[0-9]*\.?[0-9]{0,2}" class="form-control" style="text-align: center;" id="qty" name="qty" placeholder="Qty">
</td> </td>
<td> <td>
<input type="text" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,2}" class="form-control" style="text-align: right;" id="price" name="price" placeholder="Price (<?php echo $recurring_invoice_currency_code; ?>)"> <input type="text" inputmode="decimal" pattern="[0-9]*\.?[0-9]{0,2}" class="form-control" style="text-align: right;" id="price" name="price" placeholder="Price (<?php echo $recurring_invoice_currency_code; ?>)">
</td> </td>
<td> <td>
<select class="form-control" name="tax_id" id="tax" required> <select class="form-control" name="tax_id" id="tax" required>

View File

@@ -9,9 +9,6 @@ require_once "includes/inc_all.php";
// Perms // Perms
enforceUserPermission('module_financial'); enforceUserPermission('module_financial');
//Rebuild URL
$url_query_strings_sort = http_build_query($get_copy);
$sql = mysqli_query( $sql = mysqli_query(
$mysqli, $mysqli,
"SELECT SQL_CALC_FOUND_ROWS * FROM revenues "SELECT SQL_CALC_FOUND_ROWS * FROM revenues

View File

@@ -39,7 +39,6 @@ if (isset($_GET['ticket_id'])) {
LEFT JOIN ticket_statuses ON ticket_status = ticket_status_id LEFT JOIN ticket_statuses ON ticket_status = ticket_status_id
LEFT JOIN categories ON ticket_category = category_id LEFT JOIN categories ON ticket_category = category_id
WHERE ticket_id = $ticket_id WHERE ticket_id = $ticket_id
$access_permission_query
LIMIT 1" LIMIT 1"
); );
@@ -358,9 +357,11 @@ if (isset($_GET['ticket_id'])) {
<li class="breadcrumb-item"> <li class="breadcrumb-item">
<a href="tickets.php">All Tickets</a> <a href="tickets.php">All Tickets</a>
</li> </li>
<?php if ($client_url) { ?>
<li class="breadcrumb-item"> <li class="breadcrumb-item">
<a href="tickets.php?client_id=<?php echo $client_id; ?>"><?= $client_name ?> Tickets</a> <a href="tickets.php?client_id=<?php echo $client_id; ?>"><?= $client_name ?> Tickets</a>
</li> </li>
<?php } ?>
<li class="breadcrumb-item active"><?php echo "$ticket_prefix$ticket_number";?></li> <li class="breadcrumb-item active"><?php echo "$ticket_prefix$ticket_number";?></li>
</ol> </ol>
@@ -415,18 +416,13 @@ if (isset($_GET['ticket_id'])) {
<i class="fas fa-fw fa-ellipsis-v"></i> <i class="fas fa-fw fa-ellipsis-v"></i>
</button> </button>
<div class="dropdown-menu"> <div class="dropdown-menu">
<a class="dropdown-item ajax-modal" href="#"
data-modal-size = "lg"
data-modal-url="modals/ticket/ticket_edit.php?id=<?= $ticket_id ?>">
<i class="fas fa-fw fa-edit mr-2"></i>Edit
</a>
<a class="dropdown-item ajax-modal" href="#" data-modal-url="modals/ticket/ticket_summary.php?ticket_id=<?= $ticket_id ?>" data-modal-size="lg"> <a class="dropdown-item ajax-modal" href="#" data-modal-url="modals/ticket/ticket_summary.php?ticket_id=<?= $ticket_id ?>" data-modal-size="lg">
<i class="fas fa-fw fa-lightbulb mr-2"></i>Summarize <i class="fas fa-fw fa-lightbulb mr-2"></i>Summarize
</a> </a>
<a class="dropdown-item ajax-modal" href="#" data-modal-url="modals/ticket/ticket_merge.php?ticket_id=<?= $ticket_id ?>"> <a class="dropdown-item ajax-modal" href="#" data-modal-url="modals/ticket/ticket_merge.php?ticket_id=<?= $ticket_id ?>">
<i class="fas fa-fw fa-clone mr-2"></i>Merge <i class="fas fa-fw fa-clone mr-2"></i>Merge
</a> </a>
<?php if (empty($ticket_closed_at)) { ?> <?php if (empty($ticket_closed_at) && $client_id) { ?>
<div class="dropdown-divider"></div> <div class="dropdown-divider"></div>
<a class="dropdown-item ajax-modal" href="#" <a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/ticket/ticket_contact.php?id=<?= $ticket_id ?>"> data-modal-url="modals/ticket/ticket_contact.php?id=<?= $ticket_id ?>">
@@ -564,9 +560,14 @@ if (isset($_GET['ticket_id'])) {
<div class="card card-dark mb-3"> <div class="card card-dark mb-3">
<div class="card-header bg-dark"> <div class="card-header bg-dark">
<h3 class="card-title"> <h5 class="card-title">
Ticket Details Ticket Details
</h3> </h5>
<?php if (empty($ticket_closed_at)) { ?>
<div class="card-tools">
<button type="button" class="btn btn-tool ajax-modal" data-modal-url="modals/ticket/ticket_edit.php?id=<?= $ticket_id ?>" data-modal-size="lg"><i class="fas fa-edit"></i></button>
</div>
<?php } ?>
</div> </div>
<div class="card-body prettyContent" id="ticketDetails"> <div class="card-body prettyContent" id="ticketDetails">
@@ -599,9 +600,11 @@ if (isset($_GET['ticket_id'])) {
<label class="btn btn-outline-dark active"> <label class="btn btn-outline-dark active">
<input type="radio" name="public_reply_type" value="0" checked>Internal Note <input type="radio" name="public_reply_type" value="0" checked>Internal Note
</label> </label>
<?php if ($contact_email) { ?>
<label class="btn btn-outline-info"> <label class="btn btn-outline-info">
<input type="radio" name="public_reply_type" value="2">Public Comment & Email <input type="radio" name="public_reply_type" value="2">Public Comment & Email
</label> </label>
<?php } ?>
<label class="btn btn-outline-info"> <label class="btn btn-outline-info">
<input type="radio" name="public_reply_type" value="1">Public Comment <input type="radio" name="public_reply_type" value="1">Public Comment
</label> </label>
@@ -807,16 +810,17 @@ if (isset($_GET['ticket_id'])) {
<div class="col-md-3"> <div class="col-md-3">
<!-- Ticket details right card --> <!-- Ticket details right card -->
<div class="card"> <div class="card <?php if(!$ticket_resolved_at) { echo "collapsed-card"; } ?>">
<div class="card-header"> <div class="card-header">
<a class="text-reset text-decoration-none" href="#" data-toggle="collapse" data-target="#ticketDetailsCard"> <h5 class="card-title"><i class="fas fa-fw fa-life-ring mr-2"></i>Ticket Details</h5>
<h5 class="card-title mt-1"><i class="fas fa-fw fa-life-ring mr-2"></i>Ticket Details</h5>
</a>
<div class="card-tools"> <div class="card-tools">
<a class="fa fa-chevron-down" href="#" data-toggle="collapse" data-target="#ticketDetailsCard"></a> <button type="button" class="btn btn-tool" data-card-widget="collapse">
<i class="fas fa-chevron-down"></i>
</button>
</div> </div>
</div> </div>
<div class="card-body collapse <?php echo !empty($ticket_resolved_at) ? 'show' : ''; ?>" id="ticketDetailsCard"> <div class="card-body">
<!-- Created --> <!-- Created -->
<div title="<?php echo $ticket_created_at; ?>"> <div title="<?php echo $ticket_created_at; ?>">
@@ -912,12 +916,12 @@ if (isset($_GET['ticket_id'])) {
<!-- Tasks Card --> <!-- Tasks Card -->
<?php if (empty($ticket_resolved_at) || (!empty($ticket_resolved_at) && $task_count > 0)) { ?> <?php if (empty($ticket_resolved_at) || (!empty($ticket_resolved_at) && $task_count > 0)) { ?>
<div class="card"> <div class="card">
<div class="card-header py-2"> <div class="card-header">
<h5 class="card-title"><i class="fas fa-fw fa-tasks mr-2 mt-2"></i>Tasks</h5> <h5 class="card-title"><i class="fas fa-fw fa-tasks mr-2"></i>Tasks</h5>
<?php if (empty($ticket_resolved_at) && lookupUserPermission("module_support") >= 2) { ?>
<div class="card-tools"> <div class="card-tools">
<?php if (empty($ticket_resolved_at) && lookupUserPermission("module_support") >= 2) { ?>
<div class="dropdown dropleft text-center"> <div class="dropdown dropleft text-center">
<button class="btn btn-light text-secondary btn-sm" type="button" data-toggle="dropdown"> <button class="btn btn-tool" type="button" data-toggle="dropdown">
<i class="fas fa-ellipsis-v"></i> <i class="fas fa-ellipsis-v"></i>
</button> </button>
<div class="dropdown-menu"> <div class="dropdown-menu">
@@ -934,8 +938,8 @@ if (isset($_GET['ticket_id'])) {
</a> </a>
</div> </div>
</div> </div>
<?php } ?>
</div> </div>
<?php } ?>
</div> </div>
<div class="card-body p-0"> <div class="card-body p-0">
@@ -964,7 +968,7 @@ if (isset($_GET['ticket_id'])) {
$task_completion_estimate = intval($row['task_completion_estimate']); $task_completion_estimate = intval($row['task_completion_estimate']);
$task_completed_at = nullable_htmlentities($row['task_completed_at']); $task_completed_at = nullable_htmlentities($row['task_completed_at']);
?> ?>
<tr data-task-id="<?php echo $task_id; ?>"> <tr data-task-id="<?= $task_id ?>">
<td> <td>
<?php if ($task_completed_at) { ?> <?php if ($task_completed_at) { ?>
<i class="far fa-check-square text-success"></i> <i class="far fa-check-square text-success"></i>
@@ -1022,16 +1026,16 @@ if (isset($_GET['ticket_id'])) {
<!-- Contact card --> <!-- Contact card -->
<?php if ($contact_id) { ?> <?php if ($contact_id) { ?>
<div class="card"> <div class="card">
<div class="card-header py-2"> <div class="card-header">
<h5 class="card-title"><i class="fas fa-fw fa-user-check mr-2 mt-2"></i>Contact</h5> <h5 class="card-title"><i class="fas fa-fw fa-user-check mr-2"></i>Contact</h5>
<?php if (empty($ticket_resolved_at) && lookupUserPermission("module_support") >= 2) { ?>
<div class="card-tools"> <div class="card-tools">
<?php if (empty($ticket_resolved_at) && lookupUserPermission("module_support") >= 2) { ?> <a class="btn btn-tool ajax-modal" href="#"
<a class="btn btn-light text-secondary btn-sm ajax-modal" href="#" data-modal-url="modals/ticket/ticket_contact.php?id=<?= $ticket_id ?>">
data-modal-url="modals/ticket/ticket_contact.php?id=<?= $ticket_id ?>"> <i class="fas fa-edit"></i>
<i class="fas fa-edit"></i> </a>
</a>
<?php } ?>
</div> </div>
<?php } ?>
</div> </div>
<div class="card-body"> <div class="card-body">
@@ -1073,23 +1077,19 @@ if (isset($_GET['ticket_id'])) {
<?php } ?> <?php } ?>
<!-- End contact card --> <!-- End contact card -->
<!-- Ticket watchers card --> <!-- Ticket watchers card -->
<?php if (empty($ticket_closed_at) && mysqli_num_rows($sql_ticket_watchers) > 0) { ?> <?php if (empty($ticket_closed_at) && mysqli_num_rows($sql_ticket_watchers) > 0) { ?>
<div class="card"> <div class="card">
<div class="card-header py-2"> <div class="card-header">
<h5 class="card-title"><i class="fas fa-fw fa-eye mr-2 mt-2"></i>Watchers</h5> <h5 class="card-title"><i class="fas fa-fw fa-eye mr-2"></i>Watchers</h5>
<?php if (empty($ticket_resolved_at) && lookupUserPermission("module_support") >= 2) { ?>
<div class="card-tools"> <div class="card-tools">
<?php if (empty($ticket_resolved_at) && lookupUserPermission("module_support") >= 2) { ?> <a class="btn btn-tool ajax-modal" href="#" data-modal-url="modals/ticket/ticket_add_watcher.php?ticket_id=<?= $ticket_id ?>">
<a class="btn btn-light text-secondary btn-sm ajax-modal" href="#" data-modal-url="modals/ticket/ticket_add_watcher.php?ticket_id=<?= $ticket_id ?>"> <i class="fas fa-fw fa-plus"></i>
<i class="fas fa-fw fa-plus"></i> </a>
</a>
<?php } ?>
</div> </div>
<?php } ?>
</div> </div>
<div class="card-body"> <div class="card-body">
@@ -1117,15 +1117,15 @@ if (isset($_GET['ticket_id'])) {
<!-- Asset card --> <!-- Asset card -->
<?php if ($asset_id) { ?> <?php if ($asset_id) { ?>
<div class="card mb-3"> <div class="card mb-3">
<div class="card-header py-2"> <div class="card-header">
<h5 class="card-title"><i class="fas fa-fw fa-desktop mr-2 mt-2"></i>Assets</h5> <h5 class="card-title"><i class="fas fa-fw fa-desktop mr-2"></i>Assets</h5>
<?php if (empty($ticket_resolved_at) && lookupUserPermission("module_support") >= 2) { ?>
<div class="card-tools"> <div class="card-tools">
<?php if (empty($ticket_resolved_at) && lookupUserPermission("module_support") >= 2) { ?> <a class="btn btn-tool ajax-modal" href="#" data-modal-url="modals/ticket/ticket_edit_asset.php?id=<?= $ticket_id ?>">
<a class="btn btn-light text-secondary btn-sm ajax-modal" href="#" data-modal-url="modals/ticket/ticket_edit_asset.php?id=<?= $ticket_id ?>"> <i class="fas fa-fw fa-edit"></i>
<i class="fas fa-fw fa-edit"></i> </a>
</a>
<?php } ?>
</div> </div>
<?php } ?>
</div> </div>
<div class="card-body"> <div class="card-body">
<div> <div>
@@ -1165,15 +1165,15 @@ if (isset($_GET['ticket_id'])) {
<!-- Vendor card --> <!-- Vendor card -->
<?php if ($vendor_id) { ?> <?php if ($vendor_id) { ?>
<div class="card mb-3"> <div class="card mb-3">
<div class="card-header py-2"> <div class="card-header">
<h5 class="card-title"><i class="fas fa-fw fa-building mr-2 mt-2"></i>Vendor</h5> <h5 class="card-title"><i class="fas fa-fw fa-building mr-2"></i>Vendor</h5>
<?php if (empty($ticket_resolved_at) && lookupUserPermission("module_support") >= 2) { ?>
<div class="card-tools"> <div class="card-tools">
<?php if (empty($ticket_resolved_at) && lookupUserPermission("module_support") >= 2) { ?> <a class="btn btn-tool ajax-modal" href="#" data-modal-url="modals/ticket/ticket_edit_vendor.php?ticket_id=<?= $ticket_id ?>">
<a class="btn btn-light text-secondary btn-sm ajax-modal" href="#" data-modal-url="modals/ticket/ticket_edit_vendor.php?ticket_id=<?= $ticket_id ?>"> <i class="fas fa-fw fa-edit"></i>
<i class="fas fa-fw fa-edit"></i> </a>
</a>
<?php } ?>
</div> </div>
<?php } ?>
</div> </div>
<div class="card-body"> <div class="card-body">
@@ -1220,15 +1220,15 @@ if (isset($_GET['ticket_id'])) {
<!-- project card --> <!-- project card -->
<?php if ($project_id) { ?> <?php if ($project_id) { ?>
<div class="card"> <div class="card">
<div class="card-header py-2"> <div class="card-header">
<h5 class="card-title"><i class="fas fa-fw fa-project-diagram mr-2 mt-2"></i>Project</h5> <h5 class="card-title"><i class="fas fa-fw fa-project-diagram mr-2"></i>Project</h5>
<?php if (empty($ticket_resolved_at) && lookupUserPermission("module_support") >= 2) { ?>
<div class="card-tools"> <div class="card-tools">
<?php if (empty($ticket_resolved_at) && lookupUserPermission("module_support") >= 2) { ?> <button type="button" class="btn btn-tool ajax-modal" data-modal-url="modals/ticket/ticket_edit_project.php?id=<?= $ticket_id ?>">
<button type="button" class="btn btn-light text-secondary btn-sm ajax-modal" data-modal-url="modals/ticket/ticket_edit_project.php?id=<?= $ticket_id ?>"> <i class="fas fa-edit"></i>
<i class="fas fa-edit"></i> </button>
</button>
<?php } ?>
</div> </div>
<?php } ?>
</div> </div>
<div class="card-body"> <div class="card-body">
<div> <div>

View File

@@ -108,6 +108,11 @@
$contact_id = intval($row['contact_id']); $contact_id = intval($row['contact_id']);
$contact_name = nullable_htmlentities($row['contact_name']); $contact_name = nullable_htmlentities($row['contact_name']);
$contact_email = nullable_htmlentities($row['contact_email']); $contact_email = nullable_htmlentities($row['contact_email']);
if ($client_id) {
$has_client = "&client_id=$client_id";
} else {
$has_client = "";
}
if ($ticket_priority == "High") { if ($ticket_priority == "High") {
$ticket_priority_color = "danger"; $ticket_priority_color = "danger";
@@ -197,14 +202,14 @@
<!-- Ticket Number --> <!-- Ticket Number -->
<td> <td>
<a href="ticket.php?client_id=<?= $client_id ?>&ticket_id=<?= $ticket_id ?>"> <a href="ticket.php?ticket_id=<?= "$ticket_id$has_client" ?>">
<span class="badge badge-pill badge-secondary p-3"><?php echo "$ticket_prefix$ticket_number"; ?></span> <span class="badge badge-pill badge-secondary p-3"><?php echo "$ticket_prefix$ticket_number"; ?></span>
</a> </a>
</td> </td>
<!-- Ticket Subject --> <!-- Ticket Subject -->
<td> <td>
<a href="ticket.php?client_id=<?= $client_id ?>&ticket_id=<?= $ticket_id ?>"><?= $ticket_subject ?></a> <a href="ticket.php?ticket_id=<?= "$ticket_id$has_client" ?>"><?= $ticket_subject ?></a>
<?php if($task_count && $completed_task_count > 0) { ?> <?php if($task_count && $completed_task_count > 0) { ?>
<div class="progress mt-2" style="height: 20px;"> <div class="progress mt-2" style="height: 20px;">

View File

@@ -28,10 +28,6 @@ if (isset($_GET['account_to']) & !empty($_GET['account_to'])) {
$account_to_filter = ''; $account_to_filter = '';
} }
//Rebuild URL
$url_query_strings_sort = http_build_query($get_copy);
$sql = mysqli_query( $sql = mysqli_query(
$mysqli, $mysqli,
"SELECT SQL_CALC_FOUND_ROWS transfer_created_at, expense_date AS transfer_date, expense_amount AS transfer_amount, expense_account_id AS transfer_account_from, revenue_account_id AS transfer_account_to, transfer_expense_id, transfer_revenue_id , transfer_id, transfer_method, transfer_notes FROM transfers, expenses, revenues "SELECT SQL_CALC_FOUND_ROWS transfer_created_at, expense_date AS transfer_date, expense_amount AS transfer_amount, expense_account_id AS transfer_account_from, revenue_account_id AS transfer_account_to, transfer_expense_id, transfer_revenue_id , transfer_id, transfer_method, transfer_notes FROM transfers, expenses, revenues

View File

@@ -15,9 +15,6 @@ if (isset($_GET['client_id'])) {
$client_url = ''; $client_url = '';
} }
//Rebuild URL
$url_query_strings_sort = http_build_query($get_copy);
$sql = mysqli_query( $sql = mysqli_query(
$mysqli, $mysqli,
"SELECT SQL_CALC_FOUND_ROWS * FROM trips "SELECT SQL_CALC_FOUND_ROWS * FROM trips

View File

@@ -13,12 +13,25 @@ $insert_id = false;
if (!empty($name) && !(empty($content))) { if (!empty($name) && !(empty($content))) {
// Create document // Create document
$insert_sql = mysqli_query($mysqli,"INSERT INTO documents SET document_name = '$name', document_description = '$description', document_content = '$content', document_content_raw = '$content_raw', document_folder_id = $folder, document_created_by = 0, document_client_id = $client_id"); $insert_sql = mysqli_query($mysqli,"INSERT INTO documents SET document_name = '$name', document_description = '$description', document_content = '', document_content_raw = '$content_raw', document_folder_id = $folder, document_created_by = 0, document_client_id = $client_id");
// Check insert & get insert ID // Check insert & get insert ID
if ($insert_sql) { if ($insert_sql) {
$insert_id = mysqli_insert_id($mysqli); $insert_id = mysqli_insert_id($mysqli);
$processed_content = mysqli_escape_string(
$mysqli,
saveBase64Images(
$content,
$_SERVER['DOCUMENT_ROOT'] . "/uploads/documents/",
"uploads/documents/",
$insert_id
)
);
// Document update content
mysqli_query($mysqli,"UPDATE documents SET document_content = '$processed_content' WHERE document_id = $insert_id");
// Logging // Logging
logAction("Document", "Create", "$name via API ($api_key_name)", $client_id, $insert_id); logAction("Document", "Create", "$name via API ($api_key_name)", $client_id, $insert_id);
logAction("API", "Success", "Created document $name via API ($api_key_name)", $client_id); logAction("API", "Success", "Created document $name via API ($api_key_name)", $client_id);

View File

@@ -17,7 +17,17 @@ if (!empty($document_id)) {
// Variable assignment from POST - assigning the current database value if a value is not provided // Variable assignment from POST - assigning the current database value if a value is not provided
require_once 'document_model.php'; require_once 'document_model.php';
$update_insert_sql = mysqli_query($mysqli,"UPDATE documents SET document_name = '$name', document_description = '$description', document_content = '$content', document_content_raw = '$content_raw', document_folder_id = $folder, document_updated_by = 0, document_client_id = $client_id"); $processed_content = mysqli_escape_string(
$mysqli,
saveBase64Images(
$content,
$_SERVER['DOCUMENT_ROOT'] . "/uploads/documents/",
"uploads/documents/",
$document_id
)
);
$update_insert_sql = mysqli_query($mysqli,"UPDATE documents SET document_name = '$name', document_description = '$description', document_content = '$processed_content', document_content_raw = '$content_raw', document_folder_id = $folder, document_updated_by = 0, document_client_id = $client_id");
// Logging // Logging
logAction("Document", "Edit", "$name via API ($api_key_name)", $client_id, $document_id); logAction("Document", "Edit", "$name via API ($api_key_name)", $client_id, $document_id);

View File

@@ -49,7 +49,7 @@ if (isset($_POST['add_ticket'])) {
$details = removeEmoji($details); $details = removeEmoji($details);
$email_subject = "ITFlow - New Ticket - $client_name: $subject"; $email_subject = "ITFlow - New Ticket - $client_name: $subject";
$email_body = "Hello, <br><br>This is a notification that a new ticket has been raised in ITFlow. <br>Client: $client_name<br>Priority: $priority<br>Link: https://$config_base_url/ticket.php?ticket_id=$ticket_id <br><br><b>$subject</b><br>$details"; $email_body = "Hello, <br><br>This is a notification that a new ticket has been raised in ITFlow. <br>Client: $client_name<br>Priority: $priority<br>Link: https://$config_base_url/agent/ticket.php?ticket_id=$ticket_id&client_id=$session_client_id <br><br><b>$subject</b><br>$details";
// Queue Mail // Queue Mail
$data = [ $data = [
@@ -113,7 +113,7 @@ if (isset($_POST['add_ticket_comment'])) {
$tech_name = sanitizeInput($tech_details['user_name']); $tech_name = sanitizeInput($tech_details['user_name']);
$subject = "$config_app_name Ticket updated - [$config_ticket_prefix$ticket_number] $ticket_subject"; $subject = "$config_app_name Ticket updated - [$config_ticket_prefix$ticket_number] $ticket_subject";
$body = "Hello $tech_name,<br><br>A new reply has been added to the below ticket, check ITFlow for full details.<br><br>Client: $client_name<br>Ticket: $config_ticket_prefix$ticket_number<br>Subject: $ticket_subject<br><br>https://$config_base_url/ticket.php?ticket_id=$ticket_id"; $body = "Hello $tech_name,<br><br>A new reply has been added to the below ticket, check ITFlow for full details.<br><br>Client: $client_name<br>Ticket: $config_ticket_prefix$ticket_number<br>Subject: $ticket_subject<br><br>https://$config_base_url/agent/ticket.php?ticket_id=$ticket_id&client_id=$session_client_id";
$data = [ $data = [
[ [
@@ -440,7 +440,7 @@ if (isset($_GET['add_payment_by_provider'])) {
$sql = mysqli_query($mysqli,"SELECT * FROM invoices $sql = mysqli_query($mysqli,"SELECT * FROM invoices
LEFT JOIN clients ON invoice_client_id = client_id LEFT JOIN clients ON invoice_client_id = client_id
LEFT JOIN contacts ON client_id = contact_client_id AND contact_primary = 1 LEFT JOIN contacts ON client_id = contact_client_id AND contact_primary = 1
WHERE invoice_id = $invoice_id" WHERE invoice_id = $invoice_id AND client_id = $session_client_id"
); );
$row = mysqli_fetch_array($sql); $row = mysqli_fetch_array($sql);
$invoice_number = intval($row['invoice_number']); $invoice_number = intval($row['invoice_number']);
@@ -1075,14 +1075,13 @@ if (isset($_POST['client_add_document'])) {
$document_name = sanitizeInput($_POST['document_name']); $document_name = sanitizeInput($_POST['document_name']);
$document_description = sanitizeInput($_POST['document_description']); $document_description = sanitizeInput($_POST['document_description']);
$document_content = mysqli_real_escape_string($mysqli, $_POST['document_content']);
$document_content_raw = sanitizeInput($document_name . " " . strip_tags($_POST['document_content'])); $document_content_raw = sanitizeInput($document_name . " " . strip_tags($_POST['document_content']));
// Create document // Create document
mysqli_query($mysqli, "INSERT INTO documents SET mysqli_query($mysqli, "INSERT INTO documents SET
document_name = '$document_name', document_name = '$document_name',
document_description = '$document_description', document_description = '$document_description',
document_content = '$document_content', document_content = '',
document_content_raw = '$document_content_raw', document_content_raw = '$document_content_raw',
document_client_visible = 1, document_client_visible = 1,
document_client_id = $session_client_id, document_client_id = $session_client_id,
@@ -1090,6 +1089,19 @@ if (isset($_POST['client_add_document'])) {
$document_id = mysqli_insert_id($mysqli); $document_id = mysqli_insert_id($mysqli);
$processed_content = mysqli_escape_string(
$mysqli,
saveBase64Images(
$_POST['document_content'],
$_SERVER['DOCUMENT_ROOT'] . "/uploads/documents/",
"uploads/documents/",
$document_id
)
);
// Document update content
mysqli_query($mysqli,"UPDATE documents SET document_content = '$processed_content' WHERE document_id = $document_id");
logAction("Document", "Create", "Client contact $session_contact_name created document $document_name", $session_client_id, $document_id); logAction("Document", "Create", "Client contact $session_contact_name created document $document_name", $session_client_id, $document_id);
flash_alert("Document <strong>$document_name</strong> created successfully"); flash_alert("Document <strong>$document_name</strong> created successfully");

View File

@@ -186,10 +186,7 @@ function sendQueueEmail(
$mail->addAddress($to_email, $to_name); $mail->addAddress($to_email, $to_name);
$mail->isHTML(true); $mail->isHTML(true);
$mail->Subject = $subject; $mail->Subject = $subject;
$mail->Body = "<html><head><style> $mail->Body = $html_body;
body { font-family: Arial, sans-serif; color: #333; line-height: 1.6; }
.email-container { max-width: 600px; margin: auto; padding: 20px; border: 1px solid #ddd; border-radius: 5px; }
</style></head><body><div class='email-container'>{$html_body}</div></body></html>";
if (!empty($ics_str)) { if (!empty($ics_str)) {
$mail->addStringAttachment($ics_str, 'Scheduled_ticket.ics', 'base64', 'text/calendar'); $mail->addStringAttachment($ics_str, 'Scheduled_ticket.ics', 'base64', 'text/calendar');

View File

@@ -83,8 +83,16 @@ function addTicket($contact_id, $contact_name, $contact_email, $client_id, $date
// Clean up the message // Clean up the message
$message = trim($message); $message = trim($message);
// Remove DOCTYPE and meta tags
$message = preg_replace('/<!DOCTYPE[^>]*>/i', '', $message);
$message = preg_replace('/<meta[^>]*>/i', '', $message);
// Remove <html>, <head>, <body> and their closing tags
$message = preg_replace('/<\/?(html|head|body)[^>]*>/i', '', $message);
// Collapse excess whitespace
$message = preg_replace('/\s+/', ' ', $message); $message = preg_replace('/\s+/', ' ', $message);
// Convert newlines to <br>
$message = nl2br($message); $message = nl2br($message);
// Wrap final formatted message
$message = "<i>Email from: <b>$contact_name</b> &lt;$contact_email&gt; at $date:-</i> <br><br><div style='line-height:1.5;'>$message</div>"; $message = "<i>Email from: <b>$contact_name</b> &lt;$contact_email&gt; at $date:-</i> <br><br><div style='line-height:1.5;'>$message</div>";
$ticket_prefix_esc = mysqli_real_escape_string($mysqli, $config_ticket_prefix); $ticket_prefix_esc = mysqli_real_escape_string($mysqli, $config_ticket_prefix);
@@ -181,13 +189,37 @@ function addReply($from_email, $date, $subject, $ticket_number, $message, $attac
global $mysqli, $config_app_name, $company_name, $company_phone, $config_ticket_prefix, $config_base_url, $config_ticket_from_name, $config_ticket_from_email, $allowed_extensions; global $mysqli, $config_app_name, $company_name, $company_phone, $config_ticket_prefix, $config_base_url, $config_ticket_from_name, $config_ticket_from_email, $allowed_extensions;
$ticket_reply_type = 'Client'; $ticket_reply_type = 'Client';
$message_parts = explode("##- Please type your reply above this line -##", $message); // $message contains the raw HTML body from IMAP
$message_body = $message_parts[0];
$message_body = trim($message_body);
$message_body = preg_replace('/\r\n|\r|\n/', ' ', $message_body);
$message_body = nl2br($message_body);
$message = "<i>Email from: $from_email at $date:-</i> <br><br><div style='line-height:1.5;'>$message_body</div>"; // 1) Remove the reply separator and everything below it (HTML-aware)
// This matches: <i ...>##- Please type your reply above this line -##</i> and EVERYTHING after it
$message = preg_replace(
'/<i[^>]*>##-\s*Please\s+type\s+your\s+reply\s+above\s+this\s+line\s*-##<\/i>.*$/is',
'',
$message
);
// 2) Clean up the remaining message
// Remove DOCTYPE and meta tags
$message = preg_replace('/<!DOCTYPE[^>]*>/i', '', $message);
$message = preg_replace('/<meta[^>]*>/i', '', $message);
// Remove <html>, <head>, <body> and their closing tags
$message = preg_replace('/<\/?(html|head|body)[^>]*>/i', '', $message);
// Trim leading/trailing whitespace
$message = trim($message);
// Normalize line breaks to spaces
$message = preg_replace('/\r\n|\r|\n/', ' ', $message);
// Convert to <br> for HTML display
$message = nl2br($message);
// 3) Final wrapper
$message = "<i>Email from: $from_email at $date:-</i><br><br>
<div style='line-height:1.5;'>$message</div>";
$ticket_number_esc = intval($ticket_number); $ticket_number_esc = intval($ticket_number);
$message_esc = mysqli_real_escape_string($mysqli, $message); $message_esc = mysqli_real_escape_string($mysqli, $message);
@@ -598,16 +630,65 @@ foreach ($messages as $message) {
} }
} }
// Decide whether it's a reply to an existing ticket or a new ticket // 1. Reply to existing ticket with the number in subject
if (preg_match("/\[$config_ticket_prefix(\d+)\]/", $subject, $ticket_number_matches)) { if (preg_match("/\[$config_ticket_prefix(\d+)\]/", $subject, $ticket_number_matches)) {
$ticket_number = intval($ticket_number_matches[1]); $ticket_number = intval($ticket_number_matches[1]);
if (addReply($from_email, $date, $subject, $ticket_number, $message_body, $attachments)) { $email_processed = addReply($from_email, $date, $subject, $ticket_number, $message_body, $attachments);
$email_processed = true; }
}
} else { // 2. Fuzzy duplicate check using a known contact/domain and similar_text subject
// Known contact? if (!$email_processed && strlen(trim($subject)) > 10) {
$contact_id = 0;
$client_id = 0;
// First: check if sender is a registered contact
$from_email_esc = mysqli_real_escape_string($mysqli, $from_email); $from_email_esc = mysqli_real_escape_string($mysqli, $from_email);
$any_contact_sql = mysqli_query($mysqli, "SELECT * FROM contacts WHERE contact_email = '$from_email_esc' LIMIT 1"); $contact_sql = mysqli_query($mysqli, "SELECT * FROM contacts WHERE contact_email = '$from_email_esc' AND contact_archived_at IS NULL LIMIT 1");
$contact_row = mysqli_fetch_array($contact_sql);
if ($contact_row) {
$contact_id = intval($contact_row['contact_id']);
$client_id = intval($contact_row['contact_client_id']);
} else {
// Else: check if sender domain is registered
$from_domain_esc = mysqli_real_escape_string($mysqli, $from_domain);
$domain_sql = mysqli_query($mysqli, "SELECT * FROM domains WHERE domain_name = '$from_domain_esc' AND domain_archived_at IS NULL LIMIT 1");
$domain_row = mysqli_fetch_assoc($domain_sql);
if ($domain_row && $from_domain == $domain_row['domain_name']) {
$client_id = intval($domain_row['domain_client_id']);
}
}
// If we found either a contact or a domain, check recent tickets for a matching subject
if ($client_id) {
$recent_tickets_sql = mysqli_query($mysqli,
"SELECT ticket_id, ticket_number, ticket_subject
FROM tickets
WHERE ticket_client_id = $client_id AND ticket_resolved_at IS NULL
AND ticket_created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY)"
);
while ($rowt = mysqli_fetch_assoc($recent_tickets_sql)) {
$ticket_number = intval($rowt['ticket_number']);
$existing_subject = $rowt['ticket_subject'];
// Calculate similarity percentage
similar_text(strtolower($subject), strtolower($existing_subject), $percent);
if ($percent >= 95) {
// Treat as a reply/duplicate
$email_processed = addReply($from_email, $date, $subject, $ticket_number, $message_body, $attachments);
break;
}
}
}
}
// 3. A known, registered contact?
if (!$email_processed) {
$from_email_esc = mysqli_real_escape_string($mysqli, $from_email);
$any_contact_sql = mysqli_query($mysqli, "SELECT * FROM contacts WHERE contact_email = '$from_email_esc' AND contact_archived_at IS NULL LIMIT 1");
$rowc = mysqli_fetch_array($any_contact_sql); $rowc = mysqli_fetch_array($any_contact_sql);
if ($rowc) { if ($rowc) {
@@ -616,43 +697,41 @@ foreach ($messages as $message) {
$contact_email = sanitizeInput($rowc['contact_email']); $contact_email = sanitizeInput($rowc['contact_email']);
$client_id = intval($rowc['contact_client_id']); $client_id = intval($rowc['contact_client_id']);
if (addTicket($contact_id, $contact_name, $contact_email, $client_id, $date, $subject, $message_body, $attachments, $original_message_file)) { $email_processed = addTicket($contact_id, $contact_name, $contact_email, $client_id, $date, $subject, $message_body, $attachments, $original_message_file);
$email_processed = true;
}
} else {
// Known domain?
$from_domain_esc = mysqli_real_escape_string($mysqli, $from_domain);
$domain_sql = mysqli_query($mysqli, "SELECT * FROM domains WHERE domain_name = '$from_domain_esc' LIMIT 1");
$rowd = mysqli_fetch_assoc($domain_sql);
if ($rowd && $from_domain == $rowd['domain_name']) {
$client_id = intval($rowd['domain_client_id']);
// Create a new contact
$contact_name = $from_name;
$contact_email = $from_email;
mysqli_query($mysqli, "INSERT INTO contacts SET contact_name = '".mysqli_real_escape_string($mysqli, $contact_name)."', contact_email = '".mysqli_real_escape_string($mysqli, $contact_email)."', contact_notes = 'Added automatically via email parsing.', contact_client_id = $client_id");
$contact_id = mysqli_insert_id($mysqli);
// Logging
logAction("Contact", "Create", "Email parser: created contact " . mysqli_real_escape_string($mysqli, $contact_name) . "", $client_id, $contact_id);
customAction('contact_create', $contact_id);
if (addTicket($contact_id, $contact_name, $contact_email, $client_id, $date, $subject, $message_body, $attachments, $original_message_file)) {
$email_processed = true;
}
} elseif ($config_ticket_email_parse_unknown_senders) {
// Unknown sender allowed?
$bad_from_pattern = "/daemon|postmaster/i";
if (!(preg_match($bad_from_pattern, $from_email))) {
if (addTicket(0, $from_name, $from_email, 0, $date, $subject, $message_body, $attachments, $original_message_file)) {
$email_processed = true;
}
}
}
} }
} }
// 4. A known domain?
if (!$email_processed) {
$from_domain_esc = mysqli_real_escape_string($mysqli, $from_domain);
$domain_sql = mysqli_query($mysqli, "SELECT * FROM domains WHERE domain_name = '$from_domain_esc' AND domain_archived_at IS NULL LIMIT 1");
$rowd = mysqli_fetch_assoc($domain_sql);
if ($rowd && $from_domain == $rowd['domain_name']) {
$client_id = intval($rowd['domain_client_id']);
// Create a new contact
$contact_name = $from_name;
$contact_email = $from_email;
mysqli_query($mysqli, "INSERT INTO contacts SET contact_name = '".mysqli_real_escape_string($mysqli, $contact_name)."', contact_email = '".mysqli_real_escape_string($mysqli, $contact_email)."', contact_notes = 'Added automatically via email parsing.', contact_client_id = $client_id");
$contact_id = mysqli_insert_id($mysqli);
logAction("Contact", "Create", "Email parser: created contact " . mysqli_real_escape_string($mysqli, $contact_name), $client_id, $contact_id);
customAction('contact_create', $contact_id);
$email_processed = addTicket($contact_id, $contact_name, $contact_email, $client_id, $date, $subject, $message_body, $attachments, $original_message_file);
}
}
// 5. Unknown sender allowed?
if (!$email_processed && $config_ticket_email_parse_unknown_senders) {
$bad_from_pattern = "/daemon|postmaster/i";
if (!preg_match($bad_from_pattern, $from_email)) {
$email_processed = addTicket(0, $from_name, $from_email, 0, $date, $subject, $message_body, $attachments, $original_message_file);
}
}
// Flag/move based on processing result // Flag/move based on processing result
if ($email_processed) { if ($email_processed) {
$processed_count++; // increment first so a move failure doesn't hide the success $processed_count++; // increment first so a move failure doesn't hide the success

Some files were not shown because too many files have changed in this diff Show More