mirror of
https://github.com/itflow-org/itflow
synced 2026-08-16 20:45:12 +00:00
Centralize client portal access checks through contactCan()
Replaces the duplicated primary/billing/technical checks across portal pages, post.php handlers, nav, and dashboard with contactCan()/enforceContactCan(). Same behavior, but the rules now live in one place instead of being copy-pasted, which is what let them drift before. file.php keeps its 404 response; ticket-visibility and approval-routing checks are intentionally left as-is.
This commit is contained in:
@@ -8,10 +8,7 @@ header("Content-Security-Policy: default-src 'self'");
|
|||||||
|
|
||||||
require_once "includes/inc_all.php";
|
require_once "includes/inc_all.php";
|
||||||
|
|
||||||
if ($session_contact_primary == 0 && !$session_contact_is_technical_contact) {
|
enforceContactCan('itdoc');
|
||||||
header("Location: post.php?logout");
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
$assets_sql = mysqli_query($mysqli, "SELECT * FROM assets LEFT JOIN contacts ON asset_contact_id = contact_id WHERE asset_client_id = $session_client_id AND asset_archived_at IS NULL ORDER BY asset_type ASC, asset_name ASC");
|
$assets_sql = mysqli_query($mysqli, "SELECT * FROM assets LEFT JOIN contacts ON asset_contact_id = contact_id WHERE asset_client_id = $session_client_id AND asset_archived_at IS NULL ORDER BY asset_type ASC, asset_name ASC");
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -8,10 +8,7 @@ header("Content-Security-Policy: default-src 'self'");
|
|||||||
|
|
||||||
require_once "includes/inc_all.php";
|
require_once "includes/inc_all.php";
|
||||||
|
|
||||||
if ($session_contact_primary == 0 && !$session_contact_is_technical_contact) {
|
enforceContactCan('itdoc');
|
||||||
header("Location: post.php?logout");
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
$certificates_sql = mysqli_query($mysqli, "SELECT certificate_id, certificate_name, certificate_domain, certificate_issued_by, certificate_expire FROM certificates WHERE certificate_client_id = $session_client_id AND certificate_archived_at IS NULL ORDER BY certificate_expire ASC");
|
$certificates_sql = mysqli_query($mysqli, "SELECT certificate_id, certificate_name, certificate_domain, certificate_issued_by, certificate_expire FROM certificates WHERE certificate_client_id = $session_client_id AND certificate_archived_at IS NULL ORDER BY certificate_expire ASC");
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -8,10 +8,7 @@ header("Content-Security-Policy: default-src 'self'");
|
|||||||
|
|
||||||
require_once "includes/inc_all.php";
|
require_once "includes/inc_all.php";
|
||||||
|
|
||||||
if ($session_contact_primary == 0 && !$session_contact_is_technical_contact) {
|
enforceContactCan('contacts');
|
||||||
header("Location: post.php?logout");
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
|
||||||
|
|||||||
@@ -8,10 +8,7 @@ header("Content-Security-Policy: default-src 'self'");
|
|||||||
|
|
||||||
require_once "includes/inc_all.php";
|
require_once "includes/inc_all.php";
|
||||||
|
|
||||||
if ($session_contact_primary == 0 && !$session_contact_is_technical_contact) {
|
enforceContactCan('contacts');
|
||||||
header("Location: post.php?logout");
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for a contact ID
|
// Check for a contact ID
|
||||||
if (!isset($_GET['id']) && !intval($_GET['id'])) {
|
if (!isset($_GET['id']) && !intval($_GET['id'])) {
|
||||||
|
|||||||
@@ -8,10 +8,7 @@ header("Content-Security-Policy: default-src 'self'");
|
|||||||
|
|
||||||
require_once "includes/inc_all.php";
|
require_once "includes/inc_all.php";
|
||||||
|
|
||||||
if ($session_contact_primary == 0 && !$session_contact_is_technical_contact) {
|
enforceContactCan('contacts');
|
||||||
header("Location: post.php?logout");
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
$contacts_sql = mysqli_query($mysqli, "SELECT contact_id, contact_name, contact_email, contact_primary, contact_technical, contact_billing FROM contacts WHERE contact_client_id = $session_client_id AND contacts.contact_archived_at IS NULL ORDER BY contact_created_at");
|
$contacts_sql = mysqli_query($mysqli, "SELECT contact_id, contact_name, contact_email, contact_primary, contact_technical, contact_billing FROM contacts WHERE contact_client_id = $session_client_id AND contacts.contact_archived_at IS NULL ORDER BY contact_created_at");
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -8,10 +8,7 @@ header("Content-Security-Policy: default-src 'self'; img-src 'self' data:");
|
|||||||
|
|
||||||
require_once "includes/inc_all.php";
|
require_once "includes/inc_all.php";
|
||||||
|
|
||||||
if ($session_contact_primary == 0 && !$session_contact_is_technical_contact) {
|
enforceContactCan('itdoc');
|
||||||
header("Location: post.php?logout");
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
//Initialize the HTML Purifier to prevent XSS
|
//Initialize the HTML Purifier to prevent XSS
|
||||||
require_once "../libs/htmlpurifier/HTMLPurifier.standalone.php";
|
require_once "../libs/htmlpurifier/HTMLPurifier.standalone.php";
|
||||||
|
|||||||
@@ -8,10 +8,7 @@ header("Content-Security-Policy: default-src 'self'");
|
|||||||
|
|
||||||
require_once "includes/inc_all.php";
|
require_once "includes/inc_all.php";
|
||||||
|
|
||||||
if ($session_contact_primary == 0 && !$session_contact_is_technical_contact) {
|
enforceContactCan('itdoc');
|
||||||
header("Location: post.php?logout");
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
$documents_sql = mysqli_query($mysqli, "SELECT document_id, document_name, document_created_at, folder_name FROM documents LEFT JOIN folders ON document_folder_id = folder_id WHERE document_client_visible = 1 AND document_client_id = $session_client_id AND document_archived_at IS NULL ORDER BY folder_id, document_name DESC");
|
$documents_sql = mysqli_query($mysqli, "SELECT document_id, document_name, document_created_at, folder_name FROM documents LEFT JOIN folders ON document_folder_id = folder_id WHERE document_client_visible = 1 AND document_client_id = $session_client_id AND document_archived_at IS NULL ORDER BY folder_id, document_name DESC");
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -8,10 +8,7 @@ header("Content-Security-Policy: default-src 'self'");
|
|||||||
|
|
||||||
require_once "includes/inc_all.php";
|
require_once "includes/inc_all.php";
|
||||||
|
|
||||||
if ($session_contact_primary == 0 && !$session_contact_is_technical_contact) {
|
enforceContactCan('itdoc');
|
||||||
header("Location: post.php?logout");
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
$domains_sql = mysqli_query($mysqli, "SELECT domain_id, domain_name, domain_expire FROM domains WHERE domain_client_id = $session_client_id AND domain_archived_at IS NULL ORDER BY domain_expire ASC");
|
$domains_sql = mysqli_query($mysqli, "SELECT domain_id, domain_name, domain_expire FROM domains WHERE domain_client_id = $session_client_id AND domain_archived_at IS NULL ORDER BY domain_expire ASC");
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ require_once 'functions.php';
|
|||||||
|
|
||||||
// Documents section is for primary / technical contacts only -
|
// Documents section is for primary / technical contacts only -
|
||||||
// same gate as client/document.php
|
// same gate as client/document.php
|
||||||
if ($session_contact_primary == 0 && !$session_contact_is_technical_contact) {
|
if (!contactCan('itdoc')) {
|
||||||
http_response_code(404);
|
http_response_code(404);
|
||||||
exit("File not found");
|
exit("File not found");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,7 @@
|
|||||||
/*
|
/*
|
||||||
* Verifies a contact has access to a particular ticket ID, and that the ticket is in the correct state (open/closed) to perform an action
|
* Verifies a contact has access to a particular ticket ID, and that the ticket is in the correct state (open/closed) to perform an action
|
||||||
*/
|
*/
|
||||||
function verifyContactTicketAccess($requested_ticket_id, $expected_ticket_state)
|
function verifyContactTicketAccess($requested_ticket_id, $expected_ticket_state) {
|
||||||
{
|
|
||||||
|
|
||||||
// Access the global variables
|
// Access the global variables
|
||||||
global $mysqli, $session_contact_id, $session_contact_primary, $session_contact_is_technical_contact, $session_client_id;
|
global $mysqli, $session_contact_id, $session_contact_primary, $session_contact_is_technical_contact, $session_client_id;
|
||||||
@@ -38,6 +37,41 @@ function verifyContactTicketAccess($requested_ticket_id, $expected_ticket_state)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Portal access control - single source of truth for what a logged-in contact can do.
|
||||||
|
* Primary contacts have full access; others are gated by their billing / technical flags.
|
||||||
|
* Capabilities are named by area so the rule for one can change without touching callers.
|
||||||
|
*/
|
||||||
|
function contactCan($capability) {
|
||||||
|
global $session_contact_primary, $session_contact_is_billing_contact, $session_contact_is_technical_contact;
|
||||||
|
|
||||||
|
// Primary contacts can do everything in the portal
|
||||||
|
if ($session_contact_primary == 1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($capability) {
|
||||||
|
case 'accounting': // invoices, quotes, recurring invoices, saved payment methods
|
||||||
|
return (bool) $session_contact_is_billing_contact;
|
||||||
|
|
||||||
|
case 'itdoc': // assets, certificates, domains, documents, files
|
||||||
|
case 'contacts': // view / manage contacts
|
||||||
|
return (bool) $session_contact_is_technical_contact;
|
||||||
|
|
||||||
|
default: // unknown capability -> deny (fail closed)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enforce a capability at the top of a page or handler - bounce the contact out if they lack it.
|
||||||
|
*/
|
||||||
|
function enforceContactCan($capability) {
|
||||||
|
if (!contactCan($capability)) {
|
||||||
|
redirect("post.php?logout");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns appropriate FontAwesome icon for file extension
|
* Returns appropriate FontAwesome icon for file extension
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ header("X-Frame-Options: DENY"); // Legacy
|
|||||||
<a class="nav-link <?php if (basename($_SERVER['PHP_SELF']) == "tickets.php" || basename($_SERVER['PHP_SELF']) == "ticket_add.php" || basename($_SERVER['PHP_SELF']) == "ticket.php") {echo "active";} ?>" href="/client/tickets.php">Tickets</a>
|
<a class="nav-link <?php if (basename($_SERVER['PHP_SELF']) == "tickets.php" || basename($_SERVER['PHP_SELF']) == "ticket_add.php" || basename($_SERVER['PHP_SELF']) == "ticket.php") {echo "active";} ?>" href="/client/tickets.php">Tickets</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<?php if (($session_contact_primary == 1 || $session_contact_is_billing_contact) && $config_module_enable_accounting == 1) { ?>
|
<?php if (contactCan('accounting') && $config_module_enable_accounting == 1) { ?>
|
||||||
<li class="nav-item dropdown">
|
<li class="nav-item dropdown">
|
||||||
<a class="nav-link dropdown-toggle <?php echo in_array(basename($_SERVER['PHP_SELF']), ['invoices.php', 'quotes.php', 'autopay.php']) ? 'active' : ''; ?>" href="#" id="navbarDropdown1" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
<a class="nav-link dropdown-toggle <?php echo in_array(basename($_SERVER['PHP_SELF']), ['invoices.php', 'quotes.php', 'autopay.php']) ? 'active' : ''; ?>" href="#" id="navbarDropdown1" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
Finance
|
Finance
|
||||||
@@ -63,7 +63,7 @@ header("X-Frame-Options: DENY"); // Legacy
|
|||||||
</li>
|
</li>
|
||||||
<?php } ?>
|
<?php } ?>
|
||||||
|
|
||||||
<?php if ($config_module_enable_itdoc && ($session_contact_primary == 1 || $session_contact_is_technical_contact)) { ?>
|
<?php if ($config_module_enable_itdoc && contactCan('itdoc')) { ?>
|
||||||
<li class="nav-item dropdown">
|
<li class="nav-item dropdown">
|
||||||
<a class="nav-link dropdown-toggle <?php echo in_array(basename($_SERVER['PHP_SELF']), ['documents.php', 'contacts.php', 'domains.php', 'certificates.php']) ? 'active' : ''; ?>" href="#" id="navbarDropdown2" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
<a class="nav-link dropdown-toggle <?php echo in_array(basename($_SERVER['PHP_SELF']), ['documents.php', 'contacts.php', 'domains.php', 'certificates.php']) ? 'active' : ''; ?>" href="#" id="navbarDropdown2" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
Technical
|
Technical
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ $sql_assigned_assets = mysqli_query(
|
|||||||
</div>
|
</div>
|
||||||
<?php
|
<?php
|
||||||
// Billing Cards
|
// Billing Cards
|
||||||
if ($session_contact_primary == 1 || $session_contact_is_billing_contact) { ?>
|
if (contactCan('accounting')) { ?>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
||||||
@@ -211,7 +211,7 @@ if ($session_contact_primary == 1 || $session_contact_is_billing_contact) { ?>
|
|||||||
|
|
||||||
<?php
|
<?php
|
||||||
// Technical Cards
|
// Technical Cards
|
||||||
if ($session_contact_primary == 1 || $session_contact_is_technical_contact) {
|
if (contactCan('itdoc')) {
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|||||||
@@ -9,10 +9,7 @@ header("Content-Security-Policy: default-src 'self'");
|
|||||||
require_once "includes/inc_all.php";
|
require_once "includes/inc_all.php";
|
||||||
|
|
||||||
|
|
||||||
if ($session_contact_primary == 0 && !$session_contact_is_billing_contact) {
|
enforceContactCan('accounting');
|
||||||
header("Location: post.php?logout");
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
$invoices_sql = mysqli_query($mysqli, "SELECT * FROM invoices WHERE invoice_client_id = $session_client_id AND invoice_status != 'Draft' ORDER BY invoice_date DESC");
|
$invoices_sql = mysqli_query($mysqli, "SELECT * FROM invoices WHERE invoice_client_id = $session_client_id AND invoice_status != 'Draft' ORDER BY invoice_date DESC");
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -398,9 +398,7 @@ if (isset($_POST['add_contact'])) {
|
|||||||
|
|
||||||
validateCSRFToken();
|
validateCSRFToken();
|
||||||
|
|
||||||
if ($session_contact_primary == 0 && !$session_contact_is_technical_contact) {
|
enforceContactCan('contacts');
|
||||||
redirect("post.php?logout");
|
|
||||||
}
|
|
||||||
|
|
||||||
$contact_name = escapeSql($_POST['contact_name']);
|
$contact_name = escapeSql($_POST['contact_name']);
|
||||||
$contact_email = escapeSql($_POST['contact_email']);
|
$contact_email = escapeSql($_POST['contact_email']);
|
||||||
@@ -447,9 +445,7 @@ if (isset($_POST['edit_contact'])) {
|
|||||||
|
|
||||||
validateCSRFToken();
|
validateCSRFToken();
|
||||||
|
|
||||||
if ($session_contact_primary == 0 && !$session_contact_is_technical_contact) {
|
enforceContactCan('contacts');
|
||||||
redirect("post.php?logout");
|
|
||||||
}
|
|
||||||
|
|
||||||
$contact_id = intval($_POST['contact_id']);
|
$contact_id = intval($_POST['contact_id']);
|
||||||
// A contact cannot edit their own record - that would let them change their own roles
|
// A contact cannot edit their own record - that would let them change their own roles
|
||||||
@@ -694,9 +690,7 @@ if (isset($_POST['create_stripe_customer'])) {
|
|||||||
|
|
||||||
validateCSRFToken();
|
validateCSRFToken();
|
||||||
|
|
||||||
if ($session_contact_primary == 0 && !$session_contact_is_billing_contact) {
|
enforceContactCan('accounting');
|
||||||
redirect("post.php?logout");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get Stripe provider
|
// Get Stripe provider
|
||||||
$stripe_provider_result = mysqli_query($mysqli, "
|
$stripe_provider_result = mysqli_query($mysqli, "
|
||||||
@@ -784,9 +778,7 @@ if (isset($_GET['create_stripe_checkout'])) {
|
|||||||
|
|
||||||
// This page is called by autopay_setup_stripe.js, returns a Checkout Session client_secret
|
// This page is called by autopay_setup_stripe.js, returns a Checkout Session client_secret
|
||||||
|
|
||||||
if ($session_contact_primary == 0 && !$session_contact_is_billing_contact) {
|
enforceContactCan('accounting');
|
||||||
redirect("post.php?logout");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch Stripe provider info
|
// Fetch Stripe provider info
|
||||||
$stripe_provider_result = mysqli_query($mysqli, "
|
$stripe_provider_result = mysqli_query($mysqli, "
|
||||||
@@ -854,9 +846,7 @@ if (isset($_GET['stripe_save_card'])) {
|
|||||||
|
|
||||||
// validateCSRFToken(); Broken with Stripe Save Card JQ 2026-5-4
|
// validateCSRFToken(); Broken with Stripe Save Card JQ 2026-5-4
|
||||||
|
|
||||||
if ($session_contact_primary == 0 && !$session_contact_is_billing_contact) {
|
enforceContactCan('accounting');
|
||||||
redirect("post.php?logout");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get Stripe provider
|
// Get Stripe provider
|
||||||
$stripe_provider_result = mysqli_query($mysqli, "
|
$stripe_provider_result = mysqli_query($mysqli, "
|
||||||
@@ -985,9 +975,7 @@ if (isset($_GET['delete_saved_payment'])) {
|
|||||||
|
|
||||||
validateCSRFToken();
|
validateCSRFToken();
|
||||||
|
|
||||||
if ($session_contact_primary == 0 && !$session_contact_is_billing_contact) {
|
enforceContactCan('accounting');
|
||||||
redirect("post.php?logout");
|
|
||||||
}
|
|
||||||
|
|
||||||
$saved_payment_id = intval($_GET['delete_saved_payment']);
|
$saved_payment_id = intval($_GET['delete_saved_payment']);
|
||||||
|
|
||||||
@@ -1144,9 +1132,7 @@ if (isset($_POST['client_add_document'])) {
|
|||||||
validateCSRFToken();
|
validateCSRFToken();
|
||||||
|
|
||||||
// Permission check - only primary or technical contacts can create documents
|
// Permission check - only primary or technical contacts can create documents
|
||||||
if ($session_contact_primary == 0 && !$session_contact_is_technical_contact) {
|
enforceContactCan('itdoc');
|
||||||
redirect("post.php?logout");
|
|
||||||
}
|
|
||||||
|
|
||||||
$document_name = escapeSql($_POST['document_name']);
|
$document_name = escapeSql($_POST['document_name']);
|
||||||
$document_description = escapeSql($_POST['document_description']);
|
$document_description = escapeSql($_POST['document_description']);
|
||||||
@@ -1190,9 +1176,7 @@ if (isset($_POST['client_upload_document'])) {
|
|||||||
validateCSRFToken();
|
validateCSRFToken();
|
||||||
|
|
||||||
// Permission check - only primary or technical contacts can upload documents
|
// Permission check - only primary or technical contacts can upload documents
|
||||||
if ($session_contact_primary == 0 && !$session_contact_is_technical_contact) {
|
enforceContactCan('itdoc');
|
||||||
redirect("post.php?logout");
|
|
||||||
}
|
|
||||||
|
|
||||||
$document_name = escapeSql($_POST['document_name']);
|
$document_name = escapeSql($_POST['document_name']);
|
||||||
$document_description = escapeSql($_POST['document_description']);
|
$document_description = escapeSql($_POST['document_description']);
|
||||||
|
|||||||
@@ -8,10 +8,7 @@ header("Content-Security-Policy: default-src 'self'");
|
|||||||
|
|
||||||
require_once "includes/inc_all.php";
|
require_once "includes/inc_all.php";
|
||||||
|
|
||||||
if ($session_contact_primary == 0 && !$session_contact_is_billing_contact) {
|
enforceContactCan('accounting');
|
||||||
header("Location: post.php?logout");
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
$quotes_sql = mysqli_query($mysqli, "SELECT * FROM quotes WHERE quote_client_id = $session_client_id AND quote_status != 'Draft' ORDER BY quote_date DESC");
|
$quotes_sql = mysqli_query($mysqli, "SELECT * FROM quotes WHERE quote_client_id = $session_client_id AND quote_status != 'Draft' ORDER BY quote_date DESC");
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -9,10 +9,7 @@
|
|||||||
require_once "includes/inc_all.php";
|
require_once "includes/inc_all.php";
|
||||||
|
|
||||||
|
|
||||||
if ($session_contact_primary == 0 && !$session_contact_is_billing_contact) {
|
enforceContactCan('accounting');
|
||||||
header("Location: post.php?logout");
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
$recurring_invoices_sql = mysqli_query($mysqli, "SELECT * FROM recurring_invoices
|
$recurring_invoices_sql = mysqli_query($mysqli, "SELECT * FROM recurring_invoices
|
||||||
LEFT JOIN recurring_payments ON recurring_payment_recurring_invoice_id = recurring_invoice_id
|
LEFT JOIN recurring_payments ON recurring_payment_recurring_invoice_id = recurring_invoice_id
|
||||||
|
|||||||
@@ -5,10 +5,7 @@
|
|||||||
|
|
||||||
require_once "includes/inc_all.php";
|
require_once "includes/inc_all.php";
|
||||||
|
|
||||||
if ($session_contact_primary == 0 && !$session_contact_is_billing_contact) {
|
enforceContactCan('accounting');
|
||||||
header("Location: post.php?logout");
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize Stripe
|
// Initialize Stripe
|
||||||
require_once '../includes/stripe_init.php';
|
require_once '../includes/stripe_init.php';
|
||||||
|
|||||||
@@ -11,10 +11,7 @@ header("Content-Security-Policy: default-src 'self'");
|
|||||||
require_once "includes/inc_all.php";
|
require_once "includes/inc_all.php";
|
||||||
|
|
||||||
|
|
||||||
if ($session_contact_primary == 0 && !$session_contact_is_billing_contact) {
|
enforceContactCan('accounting');
|
||||||
header("Location: post.php?logout");
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
$invoices_sql = mysqli_query($mysqli, "SELECT * FROM invoices WHERE invoice_client_id = $session_client_id AND (invoice_status = 'Viewed' OR invoice_status = 'Sent' OR invoice_status = 'Partial') ORDER BY invoice_date DESC");
|
$invoices_sql = mysqli_query($mysqli, "SELECT * FROM invoices WHERE invoice_client_id = $session_client_id AND (invoice_status = 'Viewed' OR invoice_status = 'Sent' OR invoice_status = 'Partial') ORDER BY invoice_date DESC");
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user