Initial Work on Client Account Credit System, DB Structure, Credit Balance Calculation, added Apply Credit and add Credit with Expire dates, Added DB Structure for Discount Codes, UI Rewrite on client top header now using grouped cards, more dark mode work as well

This commit is contained in:
johnnyq
2025-07-24 11:31:45 -04:00
parent 99aaeefe8e
commit 197dd9f299
15 changed files with 1093 additions and 620 deletions

View File

@@ -0,0 +1,88 @@
<?php
require_once '../includes/ajax_header.php';
$invoice_id = intval($_GET['id']);
$sql = mysqli_query(
$mysqli,
"SELECT * FROM invoices
LEFT JOIN clients ON invoice_client_id = client_id
LEFT JOIN contacts ON client_id = contact_client_id AND contact_primary = 1
WHERE invoice_id = $invoice_id
LIMIT 1"
);
$row = mysqli_fetch_array($sql);
$invoice_id = intval($row['invoice_id']);
$invoice_prefix = nullable_htmlentities($row['invoice_prefix']);
$invoice_number = intval($row['invoice_number']);
$invoice_amount = floatval($row['invoice_amount']);
$client_id = intval($row['client_id']);
$client_name = nullable_htmlentities($row['client_name']);
$client_currency_code = nullable_htmlentities($row['client_currency_code']);
$contact_name = nullable_htmlentities($row['contact_name']);
$contact_email = nullable_htmlentities($row['contact_email']);
// Get Credit Balance
$sql_credit_balance = mysqli_query($mysqli, "SELECT SUM(credit_amount) AS credit_balance FROM credits WHERE credit_client_id = $client_id");
$row = mysqli_fetch_array($sql_credit_balance);
$credit_balance = floatval($row['credit_balance']);
//Add up all the payments for the invoice and get the total amount paid to the invoice
$sql_amount_paid = mysqli_query($mysqli, "SELECT SUM(payment_amount) AS amount_paid FROM payments WHERE payment_invoice_id = $invoice_id");
$row = mysqli_fetch_array($sql_amount_paid);
$amount_paid = floatval($row['amount_paid']);
$invoice_balance = $invoice_amount - $amount_paid;
// Generate the HTML form content using output buffering.
ob_start();
?>
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-wallet mr-2"></i><?php echo "$invoice_prefix$invoice_number"; ?>: Apply Credit (Balance: <?php echo numfmt_format_currency($currency_format, $credit_balance, $client_currency_code); ?>)</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="invoice_id" value="<?php echo $invoice_id; ?>">
<input type="hidden" name="invoice_balance" value="<?php echo $invoice_balance; ?>">
<input type="hidden" name="currency_code" value="<?php echo $client_currency_code; ?>">
<div class="modal-body">
<div class="form-group">
<label>Credit Amount <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-wallet"></i></span>
</div>
<input type="text" class="form-control" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,2}" name="amount" value="<?php echo number_format($credit_balance, 2, '.', ''); ?>" placeholder="0.00" required>
</div>
</div>
<?php if (!empty($config_smtp_host) && !empty($contact_email)) { ?>
<div class="form-group">
<label>Email Receipt</label>
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" id="customControlAutosizing" name="email_receipt" value="1" checked>
<label class="custom-control-label" for="customControlAutosizing"><?php echo $contact_email; ?></label>
</div>
</div>
<?php } ?>
</div>
<div class="modal-footer">
<button type="submit" name="apply_credit" class="btn btn-primary text-bold"><i class="fas fa-check mr-2"></i>Apply Credit</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fas fa-times mr-2"></i>Cancel</button>
</div>
</form>
<?php
require_once "../includes/ajax_footer.php";

View File

@@ -36,7 +36,7 @@ $balance = $invoice_amount - $amount_paid;
ob_start(); ob_start();
?> ?>
<div class="modal-header"> <div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-credit-card mr-2"></i><?php echo "$invoice_prefix$invoice_number"; ?>: Make Payment</h5> <h5 class="modal-title"><i class="fa fa-fw fa-credit-card mr-2"></i><?php echo "$invoice_prefix$invoice_number"; ?>: Make Payment</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>
@@ -46,7 +46,7 @@ ob_start();
<input type="hidden" name="invoice_id" value="<?php echo $invoice_id; ?>"> <input type="hidden" name="invoice_id" value="<?php echo $invoice_id; ?>">
<input type="hidden" name="balance" value="<?php echo $balance; ?>"> <input type="hidden" name="balance" value="<?php echo $balance; ?>">
<input type="hidden" name="currency_code" value="<?php echo $client_currency_code; ?>"> <input type="hidden" name="currency_code" value="<?php echo $client_currency_code; ?>">
<div class="modal-body bg-white"> <div class="modal-body">
<div class="form-row"> <div class="form-row">
<div class="col-md"> <div class="col-md">
@@ -169,7 +169,7 @@ ob_start();
</div> </div>
<div class="modal-footer bg-white"> <div class="modal-footer">
<button type="submit" name="add_payment" class="btn btn-primary text-bold"><i class="fas fa-check mr-2"></i>Pay</button> <button type="submit" name="add_payment" class="btn btn-primary text-bold"><i class="fas fa-check mr-2"></i>Pay</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>

View File

@@ -80,38 +80,38 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
?> ?>
<div class="card card-dark"> <div class="card">
<div class="card-header py-2"> <div class="card-header bg-dark py-2">
<h3 class="card-title mt-2"><i class="fa fa-fw fa-user-friends mr-2"></i><?php if($leads_filter == 0){ echo "Clients"; } else { echo "Leads"; } ?></h3> <h3 class="card-title mt-2"><i class="fa fa-fw fa-user-friends mr-2"></i><?php if($leads_filter == 0){ echo "Clients"; } else { echo "Leads"; } ?></h3>
<div class="card-tools"> <div class="card-tools">
<?php if (lookupUserPermission("module_client") >= 2) { ?> <?php if (lookupUserPermission("module_client") >= 2) { ?>
<div class="btn-group"> <div class="btn-group">
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addClientModal"> <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addClientModal">
<i class="fas fa-plus mr-2"></i>New <i class="fas fa-plus mr-2"></i>New
<?php if ($leads_filter == 0) { echo "Client"; } else { echo "Lead"; } ?> <?php if ($leads_filter == 0) { echo "Client"; } else { echo "Lead"; } ?>
</button> </button>
<button type="button" class="btn btn-primary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown"></button> <button type="button" class="btn btn-primary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown"></button>
<div class="dropdown-menu"> <div class="dropdown-menu">
<a class="dropdown-item text-dark" href="#" data-toggle="modal" data-target="#importClientModal"> <a class="dropdown-item text-dark" href="#" data-toggle="modal" data-target="#importClientModal">
<i class="fa fa-fw fa-upload mr-2"></i>Import <i class="fa fa-fw fa-upload mr-2"></i>Import
</a> </a>
<div class="dropdown-divider"></div> <div class="dropdown-divider"></div>
<a class="dropdown-item text-dark" href="#" data-toggle="modal" data-target="#exportClientModal"> <a class="dropdown-item text-dark" href="#" data-toggle="modal" data-target="#exportClientModal">
<i class="fa fa-fw fa-download mr-2"></i>Export <i class="fa fa-fw fa-download mr-2"></i>Export
</a> </a>
</div>
</div> </div>
<?php } ?> </div>
</div> <?php } ?>
</div> </div>
</div>
<div class="card-body p-2 p-md-3"> <div class="card-header pb-1 pt-3">
<form class="mb-4" autocomplete="off"> <form autocomplete="off">
<input type="hidden" name="leads" value="<?php echo $leads_filter; ?>"> <input type="hidden" name="leads" value="<?php echo $leads_filter; ?>">
<input type="hidden" name="archived" value="<?php echo $archived; ?>"> <input type="hidden" name="archived" value="<?php echo $archived; ?>">
<div class="row"> <div class="row">
<div class="col-md-4"> <div class="col-md-4">
<div class="input-group mb-3 mb-sm-0"> <div class="form-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 <?php if($leads_filter == 0){ echo "clients"; } else { echo "leads"; } ?>" autofocus> <input type="search" class="form-control" name="q" value="<?php if (isset($q)) { echo stripslashes(nullable_htmlentities($q)); } ?>" placeholder="Search <?php if($leads_filter == 0){ echo "clients"; } else { echo "leads"; } ?>" autofocus>
<div class="input-group-append"> <div class="input-group-append">
<button class="btn btn-secondary" type="button" data-toggle="collapse" data-target="#advancedFilter"><i class="fas fa-filter"></i></button> <button class="btn btn-secondary" type="button" data-toggle="collapse" data-target="#advancedFilter"><i class="fas fa-filter"></i></button>
@@ -119,440 +119,450 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
</div> </div>
</div> </div>
</div> </div>
<div class="col-md-8"> </div>
<div class="btn-toolbar float-right"> <div class="col-md-8">
<div class="btn-group mr-2"> <div class="btn-toolbar form-group float-right">
<a href="?leads=0" class="btn btn-<?php if ($leads_filter == 0){ echo "primary"; } else { echo "default"; } ?>"><i class="fa fa-fw fa-user-friends mr-2"></i>Clients</a> <div class="btn-group mr-2">
<a href="?leads=1" class="btn btn-<?php if ($leads_filter == 1){ echo "primary"; } else { echo "default"; } ?>"><i class="fa fa-fw fa-bullhorn mr-2"></i>Leads</a> <a href="?leads=0" class="btn btn-<?php if ($leads_filter == 0){ echo "primary"; } else { echo "default"; } ?>"><i class="fa fa-fw fa-user-friends mr-2"></i>Clients</a>
</div> <a href="?leads=1" class="btn btn-<?php if ($leads_filter == 1){ echo "primary"; } else { echo "default"; } ?>"><i class="fa fa-fw fa-bullhorn mr-2"></i>Leads</a>
</div>
<div class="btn-group"> <div class="btn-group">
<a href="?<?php echo $url_query_strings_sort ?>&archived=<?php if($archived == 1){ echo 0; } else { echo 1; } ?>" <a href="?<?php echo $url_query_strings_sort ?>&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"; } ?>">
<i class="fa fa-fw fa-archive mr-2"></i>Archived <i class="fa fa-fw fa-archive mr-2"></i>Archived
</a> </a>
<div class="dropdown ml-2" id="bulkActionButton" hidden> <div class="dropdown ml-2" id="bulkActionButton" hidden>
<button class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown"> <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>) <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" href="#" data-toggle="modal" data-target="#bulkEditHourlyRateModal">
<i class="fas fa-fw fa-clock mr-2"></i>Set Hourly Rate
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#bulkEditIndustryModal">
<i class="fas fa-fw fa-briefcase mr-2"></i>Set Industry
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#bulkEditReferralModal">
<i class="fas fa-fw fa-link mr-2"></i>Set Referral
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#bulkAssignTagsModal">
<i class="fas fa-fw fa-tags mr-2"></i>Assign Tags
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#bulkSendEmailModal">
<i class="fas fa-fw fa-paper-plane mr-2"></i>Send Email
</a>
<?php if ($archived) { ?>
<div class="dropdown-divider"></div>
<button class="dropdown-item text-info"
type="submit" form="bulkActions" name="bulk_unarchive_clients">
<i class="fas fa-fw fa-redo mr-2"></i>Restore
</button> </button>
<div class="dropdown-menu"> <?php } else { ?>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#bulkEditHourlyRateModal"> <div class="dropdown-divider"></div>
<i class="fas fa-fw fa-clock mr-2"></i>Set Hourly Rate <button class="dropdown-item text-danger confirm-link"
</a> type="submit" form="bulkActions" name="bulk_archive_clients">
<div class="dropdown-divider"></div> <i class="fas fa-fw fa-archive mr-2"></i>Archive
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#bulkEditIndustryModal"> </button>
<i class="fas fa-fw fa-briefcase mr-2"></i>Set Industry <?php } ?>
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#bulkEditReferralModal">
<i class="fas fa-fw fa-link mr-2"></i>Set Referral
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#bulkAssignTagsModal">
<i class="fas fa-fw fa-tags mr-2"></i>Assign Tags
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#bulkSendEmailModal">
<i class="fas fa-fw fa-paper-plane mr-2"></i>Send Email
</a>
<?php if ($archived) { ?>
<div class="dropdown-divider"></div>
<button class="dropdown-item text-info"
type="submit" form="bulkActions" name="bulk_unarchive_clients">
<i class="fas fa-fw fa-redo mr-2"></i>Restore
</button>
<?php } else { ?>
<div class="dropdown-divider"></div>
<button class="dropdown-item text-danger confirm-link"
type="submit" form="bulkActions" name="bulk_archive_clients">
<i class="fas fa-fw fa-archive mr-2"></i>Archive
</button>
<?php } ?>
</div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div </div>
class="collapse mt-3 <div
<?php class="collapse
if ( <?php
isset($_GET['dtf']) if (
|| $industry_filter isset($_GET['dtf'])
|| $referral_filter || $industry_filter
|| (isset($_GET['tags']) && is_array($_GET['tags'])) || $referral_filter
|| $_GET['canned_date'] !== "custom" ) || (isset($_GET['tags']) && is_array($_GET['tags']))
{ || $_GET['canned_date'] !== "custom" )
echo "show"; {
} echo "show";
?> }
" ?>
id="advancedFilter" "
> id="advancedFilter"
<div class="row"> >
<div class="col-md-2"> <div class="row">
<div class="form-group"> <div class="col-md-2">
<label>Canned date</label> <div class="form-group">
<select onchange="this.form.submit()" class="form-control select2" name="canned_date"> <label>Canned date</label>
<option <?php if ($_GET['canned_date'] == "custom") { echo "selected"; } ?> value="custom">Custom</option> <select onchange="this.form.submit()" class="form-control select2" name="canned_date">
<option <?php if ($_GET['canned_date'] == "today") { echo "selected"; } ?> value="today">Today</option> <option <?php if ($_GET['canned_date'] == "custom") { echo "selected"; } ?> value="custom">Custom</option>
<option <?php if ($_GET['canned_date'] == "yesterday") { echo "selected"; } ?> value="yesterday">Yesterday</option> <option <?php if ($_GET['canned_date'] == "today") { echo "selected"; } ?> value="today">Today</option>
<option <?php if ($_GET['canned_date'] == "thisweek") { echo "selected"; } ?> value="thisweek">This Week</option> <option <?php if ($_GET['canned_date'] == "yesterday") { echo "selected"; } ?> value="yesterday">Yesterday</option>
<option <?php if ($_GET['canned_date'] == "lastweek") { echo "selected"; } ?> value="lastweek">Last Week</option> <option <?php if ($_GET['canned_date'] == "thisweek") { echo "selected"; } ?> value="thisweek">This Week</option>
<option <?php if ($_GET['canned_date'] == "thismonth") { echo "selected"; } ?> value="thismonth">This Month</option> <option <?php if ($_GET['canned_date'] == "lastweek") { echo "selected"; } ?> value="lastweek">Last Week</option>
<option <?php if ($_GET['canned_date'] == "lastmonth") { echo "selected"; } ?> value="lastmonth">Last Month</option> <option <?php if ($_GET['canned_date'] == "thismonth") { echo "selected"; } ?> value="thismonth">This Month</option>
<option <?php if ($_GET['canned_date'] == "thisyear") { echo "selected"; } ?> value="thisyear">This Year</option> <option <?php if ($_GET['canned_date'] == "lastmonth") { echo "selected"; } ?> value="lastmonth">Last Month</option>
<option <?php if ($_GET['canned_date'] == "lastyear") { echo "selected"; } ?> value="lastyear">Last Year</option> <option <?php if ($_GET['canned_date'] == "thisyear") { echo "selected"; } ?> value="thisyear">This Year</option>
</select> <option <?php if ($_GET['canned_date'] == "lastyear") { echo "selected"; } ?> value="lastyear">Last Year</option>
</div> </select>
</div> </div>
<div class="col-md-2"> </div>
<div class="form-group"> <div class="col-md-2">
<label>Date from</label> <div class="form-group">
<input onchange="this.form.submit()" type="date" class="form-control" name="dtf" max="2999-12-31" value="<?php echo nullable_htmlentities($dtf); ?>"> <label>Date from</label>
</div> <input onchange="this.form.submit()" type="date" class="form-control" name="dtf" max="2999-12-31" value="<?php echo nullable_htmlentities($dtf); ?>">
</div> </div>
<div class="col-md-2"> </div>
<div class="form-group"> <div class="col-md-2">
<label>Date to</label> <div class="form-group">
<input onchange="this.form.submit()" type="date" class="form-control" name="dtt" max="2999-12-31" value="<?php echo nullable_htmlentities($dtt); ?>"> <label>Date to</label>
</div> <input onchange="this.form.submit()" type="date" class="form-control" name="dtt" max="2999-12-31" value="<?php echo nullable_htmlentities($dtt); ?>">
</div> </div>
<div class="col-md-2"> </div>
<div class="col-md-2">
<div class="form-group">
<label>Tag</label> <label>Tag</label>
<div class="input-group"> <select onchange="this.form.submit()" class="form-control select2" name="tags[]" data-placeholder="- Select Tags -" multiple>
<?php
<select onchange="this.form.submit()" class="form-control select2" name="tags[]" data-placeholder="- Select Tags -" multiple> $sql_tags_filter = mysqli_query($mysqli, "
<?php SELECT tags.tag_id, tags.tag_name
$sql_tags_filter = mysqli_query($mysqli, " FROM tags
SELECT tags.tag_id, tags.tag_name LEFT JOIN client_tags ON client_tags.tag_id = tags.tag_id
FROM tags WHERE tag_type = 1
LEFT JOIN client_tags ON client_tags.tag_id = tags.tag_id GROUP BY tags.tag_id
WHERE tag_type = 1 HAVING COUNT(client_tags.client_id) > 0 OR tags.tag_id IN ($tag_filter)
GROUP BY tags.tag_id ");
HAVING COUNT(client_tags.client_id) > 0 OR tags.tag_id IN ($tag_filter) while ($row = mysqli_fetch_array($sql_tags_filter)) {
"); $tag_id = intval($row['tag_id']);
while ($row = mysqli_fetch_array($sql_tags_filter)) { $tag_name = nullable_htmlentities($row['tag_name']); ?>
$tag_id = intval($row['tag_id']);
$tag_name = nullable_htmlentities($row['tag_name']); ?>
<option value="<?php echo $tag_id ?>" <?php if (isset($_GET['tags']) && is_array($_GET['tags']) && in_array($tag_id, $_GET['tags'])) { echo 'selected'; } ?>> <?php echo $tag_name ?> </option> <option value="<?php echo $tag_id ?>" <?php if (isset($_GET['tags']) && is_array($_GET['tags']) && in_array($tag_id, $_GET['tags'])) { echo 'selected'; } ?>> <?php echo $tag_name ?> </option>
<?php } ?> <?php } ?>
</select> </select>
</div>
</div> </div>
<div class="col-sm-2"> </div>
<div class="form-group"> <div class="col-sm-2">
<label>Industry</label> <div class="form-group">
<select class="form-control select2" name="industry" onchange="this.form.submit()"> <label>Industry</label>
<option value="">- All Industries -</option> <select class="form-control select2" name="industry" onchange="this.form.submit()">
<option value="">- All Industries -</option>
<?php <?php
$sql_industries_filter = mysqli_query($mysqli, "SELECT DISTINCT client_type FROM clients WHERE client_archived_at IS NULL AND client_type != '' ORDER BY client_type ASC"); $sql_industries_filter = mysqli_query($mysqli, "SELECT DISTINCT client_type FROM clients WHERE client_archived_at IS NULL AND client_type != '' ORDER BY client_type ASC");
while ($row = mysqli_fetch_array($sql_industries_filter)) { while ($row = mysqli_fetch_array($sql_industries_filter)) {
$industry_name = nullable_htmlentities($row['client_type']); $industry_name = nullable_htmlentities($row['client_type']);
?> ?>
<option <?php if ($industry_name == $industry_filter) { echo "selected"; } ?>><?php echo $industry_name; ?></option> <option <?php if ($industry_name == $industry_filter) { echo "selected"; } ?>><?php echo $industry_name; ?></option>
<?php <?php
} }
?> ?>
</select> </select>
</div>
</div> </div>
<div class="col-sm-2"> </div>
<div class="form-group"> <div class="col-sm-2">
<label>Referral</label> <div class="form-group">
<select class="form-control select2" name="referral" onchange="this.form.submit()"> <label>Referral</label>
<option value="">- All Referrals -</option> <select class="form-control select2" name="referral" onchange="this.form.submit()">
<option value="">- All Referrals -</option>
<?php <?php
$sql_referrals_filter = mysqli_query($mysqli, "SELECT DISTINCT client_referral FROM clients WHERE client_archived_at IS NULL AND client_referral != '' ORDER BY client_referral ASC"); $sql_referrals_filter = mysqli_query($mysqli, "SELECT DISTINCT client_referral FROM clients WHERE client_archived_at IS NULL AND client_referral != '' ORDER BY client_referral ASC");
while ($row = mysqli_fetch_array($sql_referrals_filter)) { while ($row = mysqli_fetch_array($sql_referrals_filter)) {
$referral_name = nullable_htmlentities($row['client_referral']); $referral_name = nullable_htmlentities($row['client_referral']);
?> ?>
<option <?php if ($referral_name == $referral_filter) { echo "selected"; } ?>><?php echo $referral_name; ?></option> <option <?php if ($referral_name == $referral_filter) { echo "selected"; } ?>><?php echo $referral_name; ?></option>
<?php <?php
} }
?> ?>
</select> </select>
</div>
</div> </div>
</div> </div>
</div> </div>
</form> </div>
<hr> </form>
<form id="bulkActions" action="post.php" method="post" enctype="multipart/form-data"> </div>
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<div class="table-responsive-sm"> <form id="bulkActions" action="post.php" method="post" enctype="multipart/form-data">
<table class="table table-striped table-hover table-borderless"> <input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<thead class="<?php if ($num_rows[0] == 0) { echo "d-none"; } ?> text-nowrap"> <div class="table-responsive-sm">
<table class="table table-hover table-borderless mb-0">
<thead class="<?php if ($num_rows[0] == 0) { echo "d-none"; } ?> text-nowrap bg-light">
<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-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=client_name&order=<?php echo $disp; ?>">
Client Name <?php if ($sort == 'client_name') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=location_city&order=<?php echo $disp; ?>">
Primary Location <?php if ($sort == 'location_city') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=contact_name&order=<?php echo $disp; ?>">
Primary Contact
<?php if ($sort == 'contact_name') { echo $order_icon; } ?>
</a>
</th>
<?php if ((lookupUserPermission("module_financial") >= 1) && $config_module_enable_accounting == 1) { ?> <th class="text-right">Billing</th> <?php } ?>
<?php if (lookupUserPermission("module_client") >= 2) { ?> <th class="text-center">Action</th> <?php } ?>
</tr>
</thead>
<tbody>
<?php
while ($row = mysqli_fetch_array($sql)) {
$client_id = intval($row['client_id']);
$client_name = nullable_htmlentities($row['client_name']);
$client_type = nullable_htmlentities($row['client_type']);
$location_id = intval($row['location_id']);
$location_country = nullable_htmlentities($row['location_country']);
$location_address = nullable_htmlentities($row['location_address']);
$location_city = nullable_htmlentities($row['location_city']);
$location_state = nullable_htmlentities($row['location_state']);
$location_zip = nullable_htmlentities($row['location_zip']);
if (empty($location_address) && empty($location_city) && empty($location_state) && empty($location_zip)) {
$location_address_display = "-";
} else {
$location_address_display = "<i class='fa fa-fw fa-map-marker-alt text-secondary mr-2'></i>$location_address<br><i class='fa fa-fw mr-2'></i>$location_city $location_state $location_zip<br><i class='fa fa-fw mr-2'></i><small>$location_country</small>";
}
$contact_id = intval($row['contact_id']);
$contact_name = nullable_htmlentities($row['contact_name']);
$contact_title = nullable_htmlentities($row['contact_title']);
$contact_phone_country_code = nullable_htmlentities($row['contact_phone_country_code']);
$contact_phone = nullable_htmlentities(formatPhoneNumber($row['contact_phone'], $contact_phone_country_code));
$contact_extension = nullable_htmlentities($row['contact_extension']);
$contact_mobile_country_code = nullable_htmlentities($row['contact_mobile_country_code']);
$contact_mobile = nullable_htmlentities(formatPhoneNumber($row['contact_mobile'], $contact_mobile_country_code));
$contact_email = nullable_htmlentities($row['contact_email']);
$client_website = nullable_htmlentities($row['client_website']);
$client_rate = floatval($row['client_rate']);
$client_currency_code = nullable_htmlentities($row['client_currency_code']);
$client_net_terms = intval($row['client_net_terms']);
$client_tax_id_number = nullable_htmlentities($row['client_tax_id_number']);
$client_referral = nullable_htmlentities($row['client_referral']);
$client_abbreviation = nullable_htmlentities($row['client_abbreviation']);
$client_notes = nullable_htmlentities($row['client_notes']);
$client_created_at = date('Y-m-d', strtotime($row['client_created_at']));
$client_updated_at = nullable_htmlentities($row['client_updated_at']);
$client_archived_at = nullable_htmlentities($row['client_archived_at']);
$client_is_lead = intval($row['client_lead']);
// Abbreviation
if (empty($client_abbreviation)) {
$client_abbreviation = shortenClient($client_name);
}
// Client Tags
$client_tag_name_display_array = array();
$client_tag_id_array = array();
$sql_client_tags = mysqli_query($mysqli, "SELECT * FROM client_tags LEFT JOIN tags ON client_tags.tag_id = tags.tag_id WHERE client_id = $client_id ORDER BY tag_name ASC");
while ($row = mysqli_fetch_array($sql_client_tags)) {
$client_tag_id = intval($row['tag_id']);
$client_tag_name = nullable_htmlentities($row['tag_name']);
$client_tag_color = nullable_htmlentities($row['tag_color']);
if (empty($client_tag_color)) {
$client_tag_color = "dark";
}
$client_tag_icon = nullable_htmlentities($row['tag_icon']);
if (empty($client_tag_icon)) {
$client_tag_icon = "tag";
}
$client_tag_id_array[] = $client_tag_id;
$client_tag_name_display_array[] = "<a href='clients.php?tags[]=$client_tag_id'><span class='badge text-light p-1 mr-1' style='background-color: $client_tag_color;'><i class='fa fa-fw fa-$client_tag_icon mr-2'></i>$client_tag_name</span></a>";
}
$client_tags_display = implode('', $client_tag_name_display_array);
//Add up all the payments for the invoice and get the total amount paid to the invoice
$sql_invoice_amounts = mysqli_query($mysqli, "SELECT SUM(invoice_amount) AS invoice_amounts FROM invoices WHERE invoice_client_id = $client_id AND invoice_status != 'Draft' AND invoice_status != 'Cancelled' AND invoice_status != 'Non-Billable' ");
$row = mysqli_fetch_array($sql_invoice_amounts);
$invoice_amounts = floatval($row['invoice_amounts']);
$sql_amount_paid = mysqli_query($mysqli, "SELECT SUM(payment_amount) AS amount_paid FROM payments, invoices WHERE payment_invoice_id = invoice_id AND invoice_client_id = $client_id");
$row = mysqli_fetch_array($sql_amount_paid);
$amount_paid = floatval($row['amount_paid']);
$balance = $invoice_amounts - $amount_paid;
//set Text color on balance
if ($balance > 0) {
$balance_text_color = "text-danger font-weight-bold";
} else {
$balance_text_color = "";
}
// Get Credit Balance
$sql_credit_balance = mysqli_query($mysqli, "SELECT SUM(credit_amount) AS credit_balance FROM credits WHERE credit_client_id = $client_id");
$row = mysqli_fetch_array($sql_credit_balance);
$credit_balance = floatval($row['credit_balance']);
//Get Monthly Recurring Total
$sql_recurring_monthly_total = mysqli_query($mysqli, "SELECT SUM(recurring_invoice_amount) AS recurring_monthly_total FROM recurring_invoices WHERE recurring_invoice_status = 1 AND recurring_invoice_frequency = 'month' AND recurring_invoice_client_id = $client_id");
$row = mysqli_fetch_array($sql_recurring_monthly_total);
$recurring_monthly_total = floatval($row['recurring_monthly_total']);
//Get Yearly Recurring Total
$sql_recurring_yearly_total = mysqli_query($mysqli, "SELECT SUM(recurring_invoice_amount) AS recurring_yearly_total FROM recurring_invoices WHERE recurring_invoice_status = 1 AND recurring_invoice_frequency = 'year' AND recurring_invoice_client_id = $client_id");
$row = mysqli_fetch_array($sql_recurring_yearly_total);
$recurring_yearly_total = floatval($row['recurring_yearly_total']) / 12;
$recurring_monthly = $recurring_monthly_total + $recurring_yearly_total;
?>
<tr> <tr>
<td class="bg-light pr-0"> <td class="pr-0 bg-light">
<div class="form-check"> <div class="form-check">
<input class="form-check-input" id="selectAllCheckbox" type="checkbox" onclick="checkAll(this)"> <input class="form-check-input bulk-select" type="checkbox" name="client_ids[]" value="<?php echo $client_id ?>">
</div> </div>
</td> </td>
<th> <td>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=client_name&order=<?php echo $disp; ?>"> <a data-toggle="tooltip" data-placement="right" title="Client ID: <?php echo $client_id; ?>" class="font-weight-bold" href="client_overview.php?client_id=<?php echo $client_id; ?>"><?php echo $client_name; ?></a>
Client Name <?php if ($sort == 'client_name') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=location_city&order=<?php echo $disp; ?>">
Primary Location <?php if ($sort == 'location_city') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=contact_name&order=<?php echo $disp; ?>">
Primary Contact
<?php if ($sort == 'contact_name') { echo $order_icon; } ?>
</a>
</th>
<?php if ((lookupUserPermission("module_financial") >= 1) && $config_module_enable_accounting == 1) { ?> <th class="text-right">Billing</th> <?php } ?>
<?php if (lookupUserPermission("module_client") >= 2) { ?> <th class="text-center">Action</th> <?php } ?>
</tr>
</thead>
<tbody>
<?php
while ($row = mysqli_fetch_array($sql)) { <?php
$client_id = intval($row['client_id']); if (!empty($client_type)) {
$client_name = nullable_htmlentities($row['client_name']); ?>
$client_type = nullable_htmlentities($row['client_type']); <div class="text-secondary mt-1">
$location_id = intval($row['location_id']); <?php echo $client_type; ?>
$location_country = nullable_htmlentities($row['location_country']); </div>
$location_address = nullable_htmlentities($row['location_address']); <?php } ?>
$location_city = nullable_htmlentities($row['location_city']); <?php
$location_state = nullable_htmlentities($row['location_state']); if (!empty($client_tags_display)) { ?>
$location_zip = nullable_htmlentities($row['location_zip']); <div class="mt-1">
if (empty($location_address) && empty($location_city) && empty($location_state) && empty($location_zip)) { <?php echo $client_tags_display; ?>
$location_address_display = "-"; </div>
} else { <?php } ?>
$location_address_display = "<i class='fa fa-fw fa-map-marker-alt text-secondary mr-2'></i>$location_address<br><i class='fa fa-fw mr-2'></i>$location_city $location_state $location_zip<br><i class='fa fa-fw mr-2'></i><small>$location_country</small>"; <div class="mt-1 text-secondary">
} <small><strong>Abbreviation: </strong> <?php echo $client_abbreviation; ?></small><br>
$contact_id = intval($row['contact_id']); <small><strong>Created: </strong> <?php echo $client_created_at; ?></small><br>
$contact_name = nullable_htmlentities($row['contact_name']); </div>
$contact_title = nullable_htmlentities($row['contact_title']);
$contact_phone_country_code = nullable_htmlentities($row['contact_phone_country_code']);
$contact_phone = nullable_htmlentities(formatPhoneNumber($row['contact_phone'], $contact_phone_country_code));
$contact_extension = nullable_htmlentities($row['contact_extension']);
$contact_mobile_country_code = nullable_htmlentities($row['contact_mobile_country_code']);
$contact_mobile = nullable_htmlentities(formatPhoneNumber($row['contact_mobile'], $contact_mobile_country_code));
$contact_email = nullable_htmlentities($row['contact_email']);
$client_website = nullable_htmlentities($row['client_website']);
$client_rate = floatval($row['client_rate']);
$client_currency_code = nullable_htmlentities($row['client_currency_code']);
$client_net_terms = intval($row['client_net_terms']);
$client_tax_id_number = nullable_htmlentities($row['client_tax_id_number']);
$client_referral = nullable_htmlentities($row['client_referral']);
$client_abbreviation = nullable_htmlentities($row['client_abbreviation']);
$client_notes = nullable_htmlentities($row['client_notes']);
$client_created_at = date('Y-m-d', strtotime($row['client_created_at']));
$client_updated_at = nullable_htmlentities($row['client_updated_at']);
$client_archived_at = nullable_htmlentities($row['client_archived_at']);
$client_is_lead = intval($row['client_lead']);
// Abbreviation </td>
if (empty($client_abbreviation)) { <td><?php echo $location_address_display; ?></td>
$client_abbreviation = shortenClient($client_name); <td>
} <?php
if (empty($contact_name) && empty($contact_phone) && empty($contact_mobile) && empty($client_email)) {
// Client Tags echo "-";
$client_tag_name_display_array = array();
$client_tag_id_array = array();
$sql_client_tags = mysqli_query($mysqli, "SELECT * FROM client_tags LEFT JOIN tags ON client_tags.tag_id = tags.tag_id WHERE client_id = $client_id ORDER BY tag_name ASC");
while ($row = mysqli_fetch_array($sql_client_tags)) {
$client_tag_id = intval($row['tag_id']);
$client_tag_name = nullable_htmlentities($row['tag_name']);
$client_tag_color = nullable_htmlentities($row['tag_color']);
if (empty($client_tag_color)) {
$client_tag_color = "dark";
}
$client_tag_icon = nullable_htmlentities($row['tag_icon']);
if (empty($client_tag_icon)) {
$client_tag_icon = "tag";
} }
$client_tag_id_array[] = $client_tag_id; if (!empty($contact_name)) { ?>
$client_tag_name_display_array[] = "<a href='clients.php?tags[]=$client_tag_id'><span class='badge text-light p-1 mr-1' style='background-color: $client_tag_color;'><i class='fa fa-fw fa-$client_tag_icon mr-2'></i>$client_tag_name</span></a>"; <div class="text-bold">
} <i class="fa fa-fw fa-user text-secondary mr-2 mb-2"></i><a href="#"
$client_tags_display = implode('', $client_tag_name_display_array); data-toggle="ajax-modal"
data-modal-size="lg"
data-ajax-url="ajax/ajax_contact_details.php?client_id=<?php echo $client_id; ?>"
data-ajax-id="<?php echo $contact_id; ?>"><?php echo $contact_name; ?>
</a>
</div>
<?php } else {
echo "-";
}
//Add up all the payments for the invoice and get the total amount paid to the invoice if (!empty($contact_phone)) { ?>
$sql_invoice_amounts = mysqli_query($mysqli, "SELECT SUM(invoice_amount) AS invoice_amounts FROM invoices WHERE invoice_client_id = $client_id AND invoice_status != 'Draft' AND invoice_status != 'Cancelled' AND invoice_status != 'Non-Billable' "); <div class="mt-1">
$row = mysqli_fetch_array($sql_invoice_amounts); <i class="fa fa-fw fa-phone text-secondary mr-2 mb-2"></i><?php echo $contact_phone; ?> <?php if (!empty($contact_extension)) { echo "x$contact_extension"; } ?>
</div>
<?php }
$invoice_amounts = floatval($row['invoice_amounts']); if (!empty($contact_mobile)) { ?>
<div class="mt-1">
<i class="fa fa-fw fa-mobile-alt text-secondary mr-2"></i><?php echo $contact_mobile; ?>
</div>
<?php }
$sql_amount_paid = mysqli_query($mysqli, "SELECT SUM(payment_amount) AS amount_paid FROM payments, invoices WHERE payment_invoice_id = invoice_id AND invoice_client_id = $client_id"); if (!empty($contact_email)) { ?>
$row = mysqli_fetch_array($sql_amount_paid); <div class="mt-1">
<i class="fa fa-fw fa-envelope text-secondary mr-2"></i><a href="mailto:<?php echo $contact_email; ?>"><?php echo $contact_email; ?></a><button class='btn btn-sm clipboardjs' type="button" data-clipboard-text='<?php echo $contact_email; ?>'><i class='far fa-copy text-secondary'></i></button>
</div>
<?php } ?>
</td>
$amount_paid = floatval($row['amount_paid']); <!-- Show Billing if perms & if accounting module is enabled -->
<?php if ((lookupUserPermission("module_financial") >= 1) && $config_module_enable_accounting == 1) { ?>
$balance = $invoice_amounts - $amount_paid; <td class="text-right">
//set Text color on balance <div>
if ($balance > 0) { <span class="text-secondary">Balance</span> <span class="<?php echo $balance_text_color; ?>"><?php echo numfmt_format_currency($currency_format, $balance, $session_company_currency); ?></span>
$balance_text_color = "text-danger font-weight-bold"; </div>
} else { <div>
$balance_text_color = ""; <span class="text-secondary">Paid</span> <?php echo numfmt_format_currency($currency_format, $amount_paid, $session_company_currency); ?>
} </div>
<div>
//Get Monthly Recurring Total <span class="text-secondary mr-2">Credit</span><span class="text-success"><?php echo numfmt_format_currency($currency_format, $credit_total, $session_company_currency); ?></span>
$sql_recurring_monthly_total = mysqli_query($mysqli, "SELECT SUM(recurring_invoice_amount) AS recurring_monthly_total FROM recurring_invoices WHERE recurring_invoice_status = 1 AND recurring_invoice_frequency = 'month' AND recurring_invoice_client_id = $client_id"); </div>
$row = mysqli_fetch_array($sql_recurring_monthly_total); <div>
<span class="text-secondary">Monthly</span> <?php echo numfmt_format_currency($currency_format, $recurring_monthly, $session_company_currency); ?>
$recurring_monthly_total = floatval($row['recurring_monthly_total']); </div>
<div>
//Get Yearly Recurring Total <span class="text-secondary">Hourly Rate</span> <?php echo numfmt_format_currency($currency_format, $client_rate, $session_company_currency); ?>
$sql_recurring_yearly_total = mysqli_query($mysqli, "SELECT SUM(recurring_invoice_amount) AS recurring_yearly_total FROM recurring_invoices WHERE recurring_invoice_status = 1 AND recurring_invoice_frequency = 'year' AND recurring_invoice_client_id = $client_id");
$row = mysqli_fetch_array($sql_recurring_yearly_total);
$recurring_yearly_total = floatval($row['recurring_yearly_total']) / 12;
$recurring_monthly = $recurring_monthly_total + $recurring_yearly_total;
?>
<tr>
<td class="pr-0 bg-light">
<div class="form-check">
<input class="form-check-input bulk-select" type="checkbox" name="client_ids[]" value="<?php echo $client_id ?>">
</div> </div>
</td> </td>
<?php } ?>
<!-- Actions -->
<?php if (lookupUserPermission("module_client") >= 2) { ?>
<td> <td>
<a data-toggle="tooltip" data-placement="right" title="Client ID: <?php echo $client_id; ?>" class="font-weight-bold" href="client_overview.php?client_id=<?php echo $client_id; ?>"><?php echo $client_name; ?></a> <div class="dropdown dropleft text-center">
<button class="btn btn-secondary btn-sm" type="button" data-toggle="dropdown">
<?php <i class="fas fa-ellipsis-v"></i>
if (!empty($client_type)) { </button>
?> <div class="dropdown-menu">
<div class="text-secondary mt-1"> <a class="dropdown-item" href="#"
<?php echo $client_type; ?>
</div>
<?php } ?>
<?php
if (!empty($client_tags_display)) { ?>
<div class="mt-1">
<?php echo $client_tags_display; ?>
</div>
<?php } ?>
<div class="mt-1 text-secondary">
<small><strong>Abbreviation: </strong> <?php echo $client_abbreviation; ?></small><br>
<small><strong>Created: </strong> <?php echo $client_created_at; ?></small><br>
</div>
</td>
<td><?php echo $location_address_display; ?></td>
<td>
<?php
if (empty($contact_name) && empty($contact_phone) && empty($contact_mobile) && empty($client_email)) {
echo "-";
}
if (!empty($contact_name)) { ?>
<div class="text-bold">
<i class="fa fa-fw fa-user text-secondary mr-2 mb-2"></i><a href="#"
data-toggle="ajax-modal" data-toggle="ajax-modal"
data-modal-size="lg" data-ajax-url="ajax/ajax_client_edit.php"
data-ajax-url="ajax/ajax_contact_details.php?client_id=<?php echo $client_id; ?>" data-ajax-id="<?php echo $client_id; ?>">
data-ajax-id="<?php echo $contact_id; ?>"><?php echo $contact_name; ?> <i class="fas fa-fw fa-edit mr-2"></i>Edit
</a> </a>
</div>
<?php } else {
echo "-";
}
if (!empty($contact_phone)) { ?> <?php if ($client_archived_at) { ?>
<div class="mt-1"> <div class="dropdown-divider"></div>
<i class="fa fa-fw fa-phone text-secondary mr-2 mb-2"></i><?php echo $contact_phone; ?> <?php if (!empty($contact_extension)) { echo "x$contact_extension"; } ?> <a class="dropdown-item text-info confirm-link" href="post.php?restore_client=<?php echo $client_id; ?>&csrf_token=<?php echo $_SESSION['csrf_token'] ?>">
<i class="fas fa-fw fa-redo mr-2"></i>Restore
</a>
<?php } else { ?>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger confirm-link" href="post.php?archive_client=<?php echo $client_id; ?>&csrf_token=<?php echo $_SESSION['csrf_token'] ?>">
<i class="fas fa-fw fa-archive mr-2"></i>Archive
</a>
<?php } ?>
</div> </div>
<?php } </div>
if (!empty($contact_mobile)) { ?>
<div class="mt-1">
<i class="fa fa-fw fa-mobile-alt text-secondary mr-2"></i><?php echo $contact_mobile; ?>
</div>
<?php }
if (!empty($contact_email)) { ?>
<div class="mt-1">
<i class="fa fa-fw fa-envelope text-secondary mr-2"></i><a href="mailto:<?php echo $contact_email; ?>"><?php echo $contact_email; ?></a><button class='btn btn-sm clipboardjs' data-clipboard-text='<?php echo $contact_email; ?>'><i class='far fa-copy text-secondary'></i></button>
</div>
<?php } ?>
</td> </td>
<?php } ?>
</tr>
<!-- Show Billing if perms & if accounting module is enabled --> <?php
<?php if ((lookupUserPermission("module_financial") >= 1) && $config_module_enable_accounting == 1) { ?> } ?>
<td class="text-right">
<div class="mt-1">
<span class="text-secondary">Balance</span> <span class="<?php echo $balance_text_color; ?>"><?php echo numfmt_format_currency($currency_format, $balance, $session_company_currency); ?></span>
</div>
<div class="mt-1">
<span class="text-secondary">Paid</span> <?php echo numfmt_format_currency($currency_format, $amount_paid, $session_company_currency); ?>
</div>
<div class="mt-1">
<span class="text-secondary">Monthly</span> <?php echo numfmt_format_currency($currency_format, $recurring_monthly, $session_company_currency); ?>
</div>
<div class="mt-1">
<span class="text-secondary">Hourly Rate</span> <?php echo numfmt_format_currency($currency_format, $client_rate, $session_company_currency); ?>
</div>
</td>
<?php } ?>
<!-- Actions --> </tbody>
<?php if (lookupUserPermission("module_client") >= 2) { ?> </table>
<td> </div>
<div class="dropdown dropleft text-center"> <?php
<button class="btn btn-secondary btn-sm" type="button" data-toggle="dropdown"> require_once "modals/client_bulk_edit_industry_modal.php";
<i class="fas fa-ellipsis-h"></i> require_once "modals/client_bulk_edit_referral_modal.php";
</button> require_once "modals/client_bulk_edit_hourly_rate_modal.php";
<div class="dropdown-menu"> require_once "modals/client_bulk_assign_tags_modal.php";
<a class="dropdown-item" href="#" require_once "modals/client_bulk_email_modal.php";
data-toggle="ajax-modal" ?>
data-ajax-url="ajax/ajax_client_edit.php" </form>
data-ajax-id="<?php echo $client_id; ?>"> <!-- Ends Card Body -->
<i class="fas fa-fw fa-edit mr-2"></i>Edit <?php require_once "includes/filter_footer.php"; ?>
</a>
</div> <!-- End Card -->
<?php if ($client_archived_at) { ?>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-info confirm-link" href="post.php?restore_client=<?php echo $client_id; ?>&csrf_token=<?php echo $_SESSION['csrf_token'] ?>">
<i class="fas fa-fw fa-redo mr-2"></i>Restore
</a>
<?php } else { ?>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger confirm-link" href="post.php?archive_client=<?php echo $client_id; ?>&csrf_token=<?php echo $_SESSION['csrf_token'] ?>">
<i class="fas fa-fw fa-archive mr-2"></i>Archive
</a>
<?php } ?>
</div>
</div>
</td>
<?php } ?>
</tr>
<?php
} ?>
</tbody>
</table>
</div>
<?php
require_once "modals/client_bulk_edit_industry_modal.php";
require_once "modals/client_bulk_edit_referral_modal.php";
require_once "modals/client_bulk_edit_hourly_rate_modal.php";
require_once "modals/client_bulk_assign_tags_modal.php";
require_once "modals/client_bulk_email_modal.php";
?>
</form>
<?php require_once "includes/filter_footer.php";
?>
</div>
</div>
<script src="js/bulk_actions.js"></script> <script src="js/bulk_actions.js"></script>

View File

@@ -3768,8 +3768,39 @@ if (LATEST_DATABASE_VERSION > CURRENT_DATABASE_VERSION) {
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '2.2.3'"); mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '2.2.3'");
} }
/* 2025-07-21 - JQ For next release Pauyment Provider Switch Over
if (CURRENT_DATABASE_VERSION == '2.2.3') { if (CURRENT_DATABASE_VERSION == '2.2.3') {
mysqli_query($mysqli, "CREATE TABLE `credits` (
`credit_id` INT(11) NOT NULL AUTO_INCREMENT,
`credit_amount` DECIMAL(15,2) NOT NULL,
`credit_reference` VARCHAR(250) DEFAULT NULL,
`credit_created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP(),
`credit_created_by` INT(11) NOT NULL,
`credit_expire_at` DATE DEFAULT NULL,
`credit_client_id` INT(11) NOT NULL,
PRIMARY KEY (`credit_id`)
)");
mysqli_query($mysqli, "ALTER TABLE `invoices` ADD `invoice_credit_amount` DECIMAL(15,2) NOT NULL DEFAULT 0.00 AFTER `invoice_discount_amount`");
mysqli_query($mysqli, "CREATE TABLE `discount_codes` (
`discount_code_id` INT(11) NOT NULL AUTO_INCREMENT,
`discount_code_description` VARCHAR(250) DEFAULT NULL,
`discount_code_amount` DECIMAL(15,2) NOT NULL,
`discount_code` VARCHAR(200) NOT NULL,
`discount_code_created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP(),
`discount_code_created_by` INT(11) NOT NULL,
`discount_code_updated_at` DATETIME NULL ON UPDATE CURRENT_TIMESTAMP,
`discount_code_archived_at` DATETIME NULL DEFAULT NULL,
`discount_code_expire_at` DATE DEFAULT NULL,
PRIMARY KEY (`discount_code_id`)
)");
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '2.2.4'");
}
/* 2025-07-21 - JQ For next release Pauyment Provider Switch Over
if (CURRENT_DATABASE_VERSION == '2.2.4') {
// Delete all Recurring Payments that are Stripe // Delete all Recurring Payments that are Stripe
mysqli_query($mysqli, "DELETE FROM recurring_payments WHERE recurring_payment_method = 'Stripe'"); mysqli_query($mysqli, "DELETE FROM recurring_payments WHERE recurring_payment_method = 'Stripe'");
@@ -3794,14 +3825,14 @@ if (LATEST_DATABASE_VERSION > CURRENT_DATABASE_VERSION) {
DROP `config_ai_api_key` DROP `config_ai_api_key`
"); ");
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '2.2.4'"); mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '2.2.5'");
} }
/* */
// if (CURRENT_DATABASE_VERSION == '2.2.4') { // if (CURRENT_DATABASE_VERSION == '2.2.5') {
// // Insert queries here required to update to DB version 2.2.5 // // Insert queries here required to update to DB version 2.2.6
// // 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.2.5'"); // mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '2.2.6'");
// } // }
} else { } else {

43
db.sql
View File

@@ -838,6 +838,25 @@ CREATE TABLE `credentials` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `credits`
--
DROP TABLE IF EXISTS `credits`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `credits` (
`credit_id` int(11) NOT NULL AUTO_INCREMENT,
`credit_amount` decimal(15,2) NOT NULL,
`credit_reference` varchar(250) DEFAULT NULL,
`credit_created_at` datetime NOT NULL DEFAULT current_timestamp(),
`credit_created_by` int(11) NOT NULL,
`credit_expire_at` date DEFAULT NULL,
`credit_client_id` int(11) NOT NULL,
PRIMARY KEY (`credit_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
-- --
-- Table structure for table `custom_fields` -- Table structure for table `custom_fields`
-- --
@@ -894,6 +913,27 @@ CREATE TABLE `custom_values` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `discount_codes`
--
DROP TABLE IF EXISTS `discount_codes`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `discount_codes` (
`discount_code_id` int(11) NOT NULL AUTO_INCREMENT,
`discount_code_description` varchar(250) DEFAULT NULL,
`discount_code_amount` decimal(15,2) NOT NULL,
`discount_code` varchar(200) NOT NULL,
`discount_code_created_at` datetime NOT NULL DEFAULT current_timestamp(),
`discount_code_created_by` int(11) NOT NULL,
`discount_code_updated_at` datetime DEFAULT NULL ON UPDATE current_timestamp(),
`discount_code_archived_at` datetime DEFAULT NULL,
`discount_code_expire_at` date DEFAULT NULL,
PRIMARY KEY (`discount_code_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
-- --
-- Table structure for table `document_files` -- Table structure for table `document_files`
-- --
@@ -1190,6 +1230,7 @@ CREATE TABLE `invoices` (
`invoice_date` date NOT NULL, `invoice_date` date NOT NULL,
`invoice_due` date NOT NULL, `invoice_due` date NOT NULL,
`invoice_discount_amount` decimal(15,2) NOT NULL DEFAULT 0.00, `invoice_discount_amount` decimal(15,2) NOT NULL DEFAULT 0.00,
`invoice_credit_amount` decimal(15,2) NOT NULL DEFAULT 0.00,
`invoice_amount` decimal(15,2) NOT NULL DEFAULT 0.00, `invoice_amount` decimal(15,2) NOT NULL DEFAULT 0.00,
`invoice_currency_code` varchar(200) NOT NULL, `invoice_currency_code` varchar(200) NOT NULL,
`invoice_note` text DEFAULT NULL, `invoice_note` text DEFAULT NULL,
@@ -2718,4 +2759,4 @@ CREATE TABLE `vendors` (
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-- Dump completed on 2025-07-08 14:06:43 -- Dump completed on 2025-07-24 11:29:27

View File

@@ -5,4 +5,4 @@
* It is used in conjunction with database_updates.php * It is used in conjunction with database_updates.php
*/ */
DEFINE("LATEST_DATABASE_VERSION", "2.2.3"); DEFINE("LATEST_DATABASE_VERSION", "2.2.4");

View File

@@ -15,19 +15,21 @@ if ($total_found_rows > 5) {
?> ?>
<hr> <div class="card-footer pb-0 pt-3 border-top">
<div class="row"> <div class="row">
<div class="col-sm mb-2"> <div class="col-sm">
<form action="post.php" method="post"> <form action="post.php" method="post">
<select onchange="this.form.submit()" class="form-control select2 col-12 col-sm-3" name="change_records_per_page"> <div class="form-group">
<option <?php if ($user_config_records_per_page == 5) { echo "selected"; } ?> >5</option> <select onchange="this.form.submit()" class="form-control select2 col-12 col-sm-3" name="change_records_per_page">
<option <?php if ($user_config_records_per_page == 10) { echo "selected"; } ?> >10</option> <option <?php if ($user_config_records_per_page == 5) { echo "selected"; } ?> >5</option>
<option <?php if ($user_config_records_per_page == 20) { echo "selected"; } ?> >20</option> <option <?php if ($user_config_records_per_page == 10) { echo "selected"; } ?> >10</option>
<option <?php if ($user_config_records_per_page == 50) { echo "selected"; } ?> >50</option> <option <?php if ($user_config_records_per_page == 20) { echo "selected"; } ?> >20</option>
<option <?php if ($user_config_records_per_page == 100) { echo "selected"; } ?> >100</option> <option <?php if ($user_config_records_per_page == 50) { echo "selected"; } ?> >50</option>
<option <?php if ($user_config_records_per_page == 500) { echo "selected"; } ?> >500</option> <option <?php if ($user_config_records_per_page == 100) { echo "selected"; } ?> >100</option>
</select> <option <?php if ($user_config_records_per_page == 500) { echo "selected"; } ?> >500</option>
</select>
</div>
</form> </form>
</div> </div>
@@ -50,16 +52,13 @@ if ($total_found_rows > 5) {
// Now output something like "Showing X to Y of Z records" // Now output something like "Showing X to Y of Z records"
?> ?>
<div class="col-sm mb-2"> <div class="col-sm">
<p class="text-center"> <p class="text-center">
Showing <strong><?php echo $start; ?></strong> to <strong><?php echo $end; ?></strong> of <strong><?php echo $total_found_rows; ?></strong> records Showing <strong><?php echo $start; ?></strong> to <strong><?php echo $end; ?></strong> of <strong><?php echo $total_found_rows; ?></strong> records
</p> </p>
<!--<p class="text-center mt-2"><?php echo $total_found_rows; ?></p> --> <!--<p class="text-center mt-2"><?php echo $total_found_rows; ?></p> -->
</div> </div>
<div class="col-sm mb-2"> <div class="col-sm">
<ul class="pagination justify-content-sm-end"> <ul class="pagination justify-content-sm-end">
<?php <?php
@@ -115,6 +114,7 @@ if ($total_found_rows > 5) {
</ul> </ul>
</div> </div>
</div> </div>
</div>
<?php <?php

View File

@@ -46,5 +46,5 @@ header("X-Frame-Options: DENY");
<script src="plugins/toastr/toastr.min.js"></script> <script src="plugins/toastr/toastr.min.js"></script>
</head> </head>
<body class="hold-transition sidebar-mini layout-fixed layout-navbar-fixed dark-mode accent-<?php if (isset($_GET['client_id'])) { echo "blue"; } else { echo nullable_htmlentities($config_theme); } ?>"> <body class="hold-transition sidebar-mini layout-fixed layout-navbar-fixed dark-moe accent-<?php if (isset($_GET['client_id'])) { echo "blue"; } else { echo nullable_htmlentities($config_theme); } ?>">
<div class="wrapper text-sm"> <div class="wrapper text-sm">

View File

@@ -131,6 +131,12 @@ if (isset($_GET['client_id'])) {
$recurring_monthly = $recurring_monthly_total + $recurring_yearly_total; $recurring_monthly = $recurring_monthly_total + $recurring_yearly_total;
// Get Credit Balance
$sql_credit_balance = mysqli_query($mysqli, "SELECT SUM(credit_amount) AS credit_balance FROM credits WHERE credit_client_id = $client_id");
$row = mysqli_fetch_array($sql_credit_balance);
$credit_balance = floatval($row['credit_balance']);
// Badge Counts // Badge Counts
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('contact_id') AS num FROM contacts WHERE contact_archived_at IS NULL AND contact_client_id = $client_id")); $row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('contact_id') AS num FROM contacts WHERE contact_archived_at IS NULL AND contact_client_id = $client_id"));

View File

@@ -1,176 +1,179 @@
<div class="card d-print-none"> <div class="card d-print-none">
<div class="card-body py-2"> <div class="card-header pb-1 pt-2 px-3">
<div class="row"> <div class="card-title">
<div class="col"> <a href="#" data-toggle="collapse" data-target="#clientHeader"><h4 class="text-dark" data-toggle="tooltip" data-placement="right" title="Client ID: <?php echo $client_id; ?>"><strong><?php echo $client_name; ?></strong> <?php if ($client_archived_at) { echo "(archived)"; } ?></h4></a>
<a href="#" data-toggle="collapse" data-target="#clientHeader"><h4 class="text-secondary" data-toggle="tooltip" data-placement="right" title="Client ID: <?php echo $client_id; ?>"><strong><?php echo $client_name; ?></strong> <?php if ($client_archived_at) { echo "(archived)"; } ?></h4></a> </div>
</div> <?php if (!empty($client_tag_name_display_array)) { ?><div class="card-title ml-2"><?php echo $client_tags_display; ?></div> <?php } ?>
<div class="col"> <?php if (lookupUserPermission("module_client") >= 2) { ?>
<?php if (lookupUserPermission("module_client") >= 2) { ?> <div class="card-tools">
<div class="dropdown dropleft text-center"> <div class="dropdown dropleft text-center">
<button class="btn btn-dark btn-sm float-right" type="button" data-toggle="dropdown"> <button class="btn btn-dark btn-sm" type="button" data-toggle="dropdown">
<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" href="#" <a class="dropdown-item" href="#"
data-toggle="ajax-modal" data-toggle="ajax-modal"
data-ajax-url="ajax/ajax_client_edit.php" data-ajax-url="ajax/ajax_client_edit.php"
data-ajax-id="<?php echo $client_id; ?>"> data-ajax-id="<?php echo $client_id; ?>">
<i class="fas fa-fw fa-edit mr-2"></i>Edit Client <i class="fas fa-fw fa-edit mr-2"></i>Edit Client
</a> </a>
<?php if (lookupUserPermission("module_client") >= 3) { ?> <?php if (lookupUserPermission("module_billing") >= 2) { ?>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#exportClientPDFModal">
<i class="fas fa-fw fa-file-pdf mr-2"></i>Export Data
</a>
<?php } ?>
<?php if (empty($client_archived_at)) { ?>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger confirm-link" href="post.php?archive_client=<?php echo $client_id; ?>&csrf_token=<?php echo $_SESSION['csrf_token'] ?>">
<i class="fas fa-fw fa-archive mr-2"></i>Archive Client
</a>
<?php } else { ?>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-primary confirm-link" href="post.php?undo_archive_client=<?php echo $client_id; ?>">
<i class="fas fa-fw fa-archive mr-2"></i>Unarchive Client
</a>
<?php } ?>
<?php if (lookupUserPermission("module_client") >= 3 && $client_archived_at) { ?>
<div class="dropdown-divider"></div> <div class="dropdown-divider"></div>
<a class="dropdown-item text-danger text-bold" href="#" data-toggle="modal" data-target="#deleteClientModal<?php echo $client_id; ?>"> <a class="dropdown-item" href="#" data-toggle="modal" data-target="#addCreditModal">
<i class="fas fa-fw fa-trash mr-2"></i>Delete Client <i class="fas fa-fw fa-wallet mr-2"></i>Add Credit
</a> </a>
<?php } ?> <?php } ?>
<?php if (lookupUserPermission("module_client") >= 3) { ?>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#exportClientPDFModal">
<i class="fas fa-fw fa-file-pdf mr-2"></i>Export Data
</a>
<?php } ?>
<?php if (empty($client_archived_at)) { ?>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger confirm-link" href="post.php?archive_client=<?php echo $client_id; ?>&csrf_token=<?php echo $_SESSION['csrf_token'] ?>">
<i class="fas fa-fw fa-archive mr-2"></i>Archive Client
</a>
<?php } else { ?>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-primary confirm-link" href="post.php?undo_archive_client=<?php echo $client_id; ?>">
<i class="fas fa-fw fa-archive mr-2"></i>Unarchive Client
</a>
<?php } ?>
<?php if (lookupUserPermission("module_client") >= 3 && $client_archived_at) { ?>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger text-bold" href="#" data-toggle="modal" data-target="#deleteClientModal<?php echo $client_id; ?>">
<i class="fas fa-fw fa-trash mr-2"></i>Delete Client
</a>
<?php } ?>
</div>
</div> </div>
<?php } ?>
</div> </div>
</div> </div>
<?php } ?>
</div>
</div>
<div class="collapse <?php if (basename($_SERVER["PHP_SELF"]) == "client_overview.php") { echo "show"; } ?>" id="clientHeader"> <div class="collapse <?php if (basename($_SERVER["PHP_SELF"]) == "client_overview.php") { echo "show"; } ?>" id="clientHeader">
<div class="row"> <div class="card-group mb-3">
<div class="card card-body px-3 py-2">
<div class="col-md border-top"> <h5>Primary Location</h5>
<h5 class="text-secondary mt-1">Primary Location</h5> <?php if (!empty($location_address)) { ?>
<?php if (!empty($location_address)) { ?> <div>
<a href="//maps.<?php echo $session_map_source; ?>.com/?q=<?php echo "$location_address $location_zip"; ?>" target="_blank">
<i class="fa fa-fw fa-map-marker-alt text-secondary ml-1 mr-2"></i><?php echo $location_address; ?>
<div> <div>
<a href="//maps.<?php echo $session_map_source; ?>.com/?q=<?php echo "$location_address $location_zip"; ?>" target="_blank"> <i class="fa fa-fw ml-1 mr-2"></i><?php echo "$location_city $location_state $location_zip"; ?>
<i class="fa fa-fw fa-map-marker-alt text-secondary ml-1 mr-2"></i><?php echo $location_address; ?>
<div>
<i class="fa fa-fw ml-1 mr-2"></i><?php echo "$location_city $location_state $location_zip"; ?>
</div>
<div>
<i class="fa fa-fw ml-1 mr-2"></i><small><?php echo $location_country; ?></small>
</div>
</a>
</div> </div>
<?php }
if (!empty($location_phone)) { ?>
<div class="mt-1">
<i class="fa fa-fw fa-phone text-secondary ml-1 mr-2"></i><a href="tel:<?php echo $location_phone?>"><?php echo $location_phone; ?></a>
</div>
<hr class="my-2">
<?php }
if (!empty($client_website)) { ?>
<div class="mt-1">
<i class="fa fa-fw fa-globe text-secondary ml-1 mr-2"></i><a target="_blank" href="//<?php echo $client_website; ?>"><?php echo $client_website; ?></a>
</div>
<?php } ?>
</div>
<div class="col-md border-left border-top">
<h5 class="text-secondary mt-1">Primary Contact</h5>
<?php
if (!empty($contact_name)) { ?>
<div> <div>
<i class="fa fa-fw fa-user text-secondary ml-1 mr-2"></i><?php echo $contact_name; ?> <i class="fa fa-fw ml-1 mr-2"></i><small><?php echo $location_country; ?></small>
</div> </div>
<?php } </a>
if (!empty($contact_email)) { ?>
<div class="mt-1">
<i class="fa fa-fw fa-envelope text-secondary ml-1 mr-2"></i><a href="mailto:<?php echo $contact_email; ?>"><?php echo $contact_email; ?></a>
</div>
<?php
}
if (!empty($contact_phone)) { ?>
<div class="mt-1">
<i class="fa fa-fw fa-phone text-secondary ml-1 mr-2"></i><a href="tel:<?php echo $contact_phone; ?>"><?php echo $contact_phone; ?></a>
<?php
if (!empty($contact_extension)) {
echo "<small>x$contact_extension</small>";
}
?>
</div>
<?php
}
if (!empty($contact_mobile)) { ?>
<div class="mt-1">
<i class="fa fa-fw fa-mobile-alt text-secondary ml-1 mr-2"></i><a href="tel:<?php echo $contact_mobile; ?>"><?php echo $contact_mobile; ?></a>
</div>
<?php } ?>
</div> </div>
<?php }
<?php if (lookupUserPermission("module_financial") >= 1 && $config_module_enable_accounting == 1) { ?> if (!empty($location_phone)) { ?>
<div class="col-md border-left border-top"> <div>
<h5 class="text-secondary mt-1">Billing</h5> <i class="fa fa-fw fa-phone text-secondary ml-1 mr-2"></i><a href="tel:<?php echo $location_phone?>"><?php echo $location_phone; ?></a>
<div class="ml-1 text-secondary">Hourly Rate
<span class="text-dark float-right"> <?php echo numfmt_format_currency($currency_format, $client_rate, $client_currency_code); ?></span>
</div>
<div class="ml-1 mt-1 text-secondary">Paid
<span class="text-dark float-right"> <?php echo numfmt_format_currency($currency_format, $amount_paid, $client_currency_code); ?></span>
</div>
<div class="ml-1 mt-1 text-secondary">Balance
<span class="<?php if ($balance > 0) { echo "text-danger"; }else{ echo "text-dark"; } ?> float-right"> <?php echo numfmt_format_currency($currency_format, $balance, $client_currency_code); ?></span>
</div>
<div class="ml-1 mt-1 text-secondary">Monthly Recurring
<span class="text-dark float-right"> <?php echo numfmt_format_currency($currency_format, $recurring_monthly, $client_currency_code); ?></span>
</div>
<div class="ml-1 mt-1 text-secondary">Net Terms
<span class="text-dark float-right"><?php echo $client_net_terms; ?><small class="text-secondary ml-1">Days</small></span>
</div>
<?php if(!empty($client_tax_id_number)) { ?>
<div class="ml-1 mt-1 text-secondary">Tax ID
<span class="text-dark float-right"><?php echo $client_tax_id_number; ?></span>
</div>
<?php } ?>
</div> </div>
<?php } ?> <hr class="my-2">
<?php }
if (!empty($client_website)) { ?>
<div class="mt-1">
<i class="fa fa-fw fa-globe text-secondary ml-1 mr-2"></i><a target="_blank" href="//<?php echo $client_website; ?>"><?php echo $client_website; ?></a>
</div>
<?php } ?>
</div>
<div class="card card-body px-3 py-2">
<h5>Primary Contact</h5>
<?php
if (!empty($contact_name)) { ?>
<div>
<i class="fa fa-fw fa-user text-secondary ml-1 mr-2"></i><?php echo $contact_name; ?>
</div>
<?php }
if (!empty($contact_email)) { ?>
<div class="mt-1">
<i class="fa fa-fw fa-envelope text-secondary ml-1 mr-2"></i><a href="mailto:<?php echo $contact_email; ?>"><?php echo $contact_email; ?></a>
</div>
<?php
}
if (!empty($contact_phone)) { ?>
<div class="mt-1">
<i class="fa fa-fw fa-phone text-secondary ml-1 mr-2"></i><a href="tel:<?php echo $contact_phone; ?>"><?php echo $contact_phone; ?></a>
<?php if (lookupUserPermission("module_support") >= 1 && $config_module_enable_ticketing == 1) { ?>
<div class="col-md border-left border-top">
<h5 class="text-secondary mt-1">Support</h5>
<div class="ml-1 text-secondary">Open Tickets
<span class="text-dark float-right"><?php echo $num_active_tickets; ?></span>
</div>
<div class="ml-1 text-secondary mt-1">Closed Tickets
<span class="text-dark float-right"><?php echo $num_closed_tickets; ?></span>
</div>
<?php <?php
if (!empty($client_tag_name_display_array)) { ?> if (!empty($contact_extension)) {
<hr> echo "<small>x$contact_extension</small>";
<?php echo $client_tags_display; ?> }
<?php } ?> ?>
</div> </div>
<?php } ?> <?php
}
if (!empty($contact_mobile)) { ?>
<div class="mt-1">
<i class="fa fa-fw fa-mobile-alt text-secondary ml-1 mr-2"></i><a href="tel:<?php echo $contact_mobile; ?>"><?php echo $contact_mobile; ?></a>
</div>
<?php } ?>
</div>
<?php if (lookupUserPermission("module_financial") >= 1 && $config_module_enable_accounting == 1) { ?>
<div class="card card-body px-3 py-2">
<h5>Billing</h5>
<div class="ml-1 text-secondary">Hourly Rate
<span class="text-dark float-right"> <?php echo numfmt_format_currency($currency_format, $client_rate, $client_currency_code); ?></span>
</div>
<div class="ml-1 mt-1 text-secondary">Paid
<span class="text-dark float-right"> <?php echo numfmt_format_currency($currency_format, $amount_paid, $client_currency_code); ?></span>
</div>
<div class="ml-1 mt-1 text-secondary">Balance
<span class="<?php if ($balance > 0) { echo "text-danger"; }else{ echo "text-dark"; } ?> float-right"> <?php echo numfmt_format_currency($currency_format, $balance, $client_currency_code); ?></span>
</div>
<?php if ($credit_balance) { ?>
<div class="ml-1 mt-1 text-secondary">Credit
<span class="text-success float-right"><?php echo numfmt_format_currency($currency_format, $credit_balance, $client_currency_code); ?></span>
</div>
<?php } ?>
<div class="ml-1 mt-1 text-secondary">Monthly Recurring
<span class="text-dark float-right"> <?php echo numfmt_format_currency($currency_format, $recurring_monthly, $client_currency_code); ?></span>
</div>
<div class="ml-1 mt-1 text-secondary">Net Terms
<span class="text-dark float-right"><?php echo $client_net_terms; ?><small class="text-secondary ml-1">Days</small></span>
</div>
<?php if(!empty($client_tax_id_number)) { ?>
<div class="ml-1 mt-1 text-secondary">Tax ID
<span class="text-dark float-right"><?php echo $client_tax_id_number; ?></span>
</div>
<?php } ?>
</div>
<?php } ?>
<?php if (lookupUserPermission("module_support") >= 1 && $config_module_enable_ticketing == 1) { ?>
<div class="card card-body px-3 py-2">
<h5>Support</h5>
<div class="ml-1 text-secondary">Open Tickets
<span class="text-dark float-right"><?php echo $num_active_tickets; ?></span>
</div>
<div class="ml-1 text-secondary mt-1">Closed Tickets
<span class="text-dark float-right"><?php echo $num_closed_tickets; ?></span>
</div> </div>
</div> </div>
<?php } ?>
</div> </div>
</div> </div>
<?php <?php
require_once "modals/client_credit_add_modal.php";
require_once "modals/client_delete_modal.php"; require_once "modals/client_delete_modal.php";
require_once "modals/client_download_pdf_modal.php"; require_once "modals/client_download_pdf_modal.php";

View File

@@ -47,6 +47,7 @@ if (isset($_GET['invoice_id'])) {
$invoice_due = nullable_htmlentities($row['invoice_due']); $invoice_due = nullable_htmlentities($row['invoice_due']);
$invoice_amount = floatval($row['invoice_amount']); $invoice_amount = floatval($row['invoice_amount']);
$invoice_discount = floatval($row['invoice_discount_amount']); $invoice_discount = floatval($row['invoice_discount_amount']);
$invoice_credit = floatval($row['invoice_credit_amount']);
$invoice_currency_code = nullable_htmlentities($row['invoice_currency_code']); $invoice_currency_code = nullable_htmlentities($row['invoice_currency_code']);
$invoice_note = nullable_htmlentities($row['invoice_note']); $invoice_note = nullable_htmlentities($row['invoice_note']);
$invoice_url_key = nullable_htmlentities($row['invoice_url_key']); $invoice_url_key = nullable_htmlentities($row['invoice_url_key']);
@@ -142,6 +143,12 @@ if (isset($_GET['invoice_id'])) {
$balance = $invoice_amount - $amount_paid; $balance = $invoice_amount - $amount_paid;
// Get Credit Balance
$sql_credit_balance = mysqli_query($mysqli, "SELECT SUM(credit_amount) AS credit_balance FROM credits WHERE credit_client_id = $client_id");
$row = mysqli_fetch_array($sql_credit_balance);
$credit_balance = floatval($row['credit_balance']);
//check to see if overdue //check to see if overdue
if ($invoice_status !== "Paid" && $invoice_status !== "Draft" && $invoice_status !== "Cancelled" && $invoice_status !== "Non-Billable") { if ($invoice_status !== "Paid" && $invoice_status !== "Draft" && $invoice_status !== "Cancelled" && $invoice_status !== "Non-Billable") {
$unixtime_invoice_due = strtotime($invoice_due) + 86400; $unixtime_invoice_due = strtotime($invoice_due) + 86400;
@@ -240,6 +247,9 @@ if (isset($_GET['invoice_id'])) {
<?php if ($config_stripe_enable) { ?> <?php if ($config_stripe_enable) { ?>
<button type="button" class="btn btn-success dropdown-toggle dropdown-toggle-split" data-toggle="dropdown"></button> <button type="button" class="btn btn-success dropdown-toggle dropdown-toggle-split" data-toggle="dropdown"></button>
<div class="dropdown-menu"> <div class="dropdown-menu">
<?php if ($credit_balance) { ?>
<a class="dropdown-item" href="#" data-toggle="ajax-modal" data-ajax-url="ajax/ajax_invoice_apply_credit.php" data-ajax-id="<?php echo $invoice_id; ?>"><i class="fas fa-fw fa-wallet mr-2"></i>Apply Credit (Balance: <?php echo numfmt_format_currency($currency_format, $credit_balance, $client_currency_code); ?>)</a>
<?php } ?>
<a class="dropdown-item" href="guest/guest_pay_invoice_stripe.php?invoice_id=<?php echo "$invoice_id&url_key=$invoice_url_key"; ?>">Enter Card Manually</a> <a class="dropdown-item" href="guest/guest_pay_invoice_stripe.php?invoice_id=<?php echo "$invoice_id&url_key=$invoice_url_key"; ?>">Enter Card Manually</a>
<?php <?php
if (mysqli_num_rows($sql_saved_payment_methods) > 0) { ?> if (mysqli_num_rows($sql_saved_payment_methods) > 0) { ?>
@@ -543,6 +553,16 @@ if (isset($_GET['invoice_id'])) {
<?php <?php
} }
?> ?>
<?php
if ($invoice_credit > 0) {
?>
<tr>
<td>Credit:</td>
<td class="text-right">-<?php echo numfmt_format_currency($currency_format, $invoice_credit, $invoice_currency_code); ?></td>
</tr>
<?php
}
?>
<?php if ($total_tax > 0) { ?> <?php if ($total_tax > 0) { ?>
<tr> <tr>
<td>Tax:</td> <td>Tax:</td>

View File

@@ -7,32 +7,31 @@
<span>&times;</span> <span>&times;</span>
</button> </button>
</div> </div>
<ul class="modal-header nav nav-pills nav-justified">
<li class="nav-item">
<a class="nav-link active" data-toggle="pill" href="#pills-details">Details</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="pill" href="#pills-location">Location</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="pill" href="#pills-contact" id="contactNavPill">Contact</a>
</li>
<?php if ($config_module_enable_accounting) { ?>
<li class="nav-item">
<a class="nav-link" data-toggle="pill" href="#pills-billing">Billing</a>
</li>
<?php } ?>
<li class="nav-item">
<a class="nav-link" data-toggle="pill" href="#pills-notes">Notes</a>
</li>
</ul>
<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'] ?>">
<div class="modal-body"> <div class="modal-body">
<ul class="nav nav-pills nav-justified mb-3">
<li class="nav-item">
<a class="nav-link active" data-toggle="pill" href="#pills-details">Details</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="pill" href="#pills-location">Location</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="pill" href="#pills-contact" id="contactNavPill">Contact</a>
</li>
<?php if ($config_module_enable_accounting) { ?>
<li class="nav-item">
<a class="nav-link" data-toggle="pill" href="#pills-billing">Billing</a>
</li>
<?php } ?>
<li class="nav-item">
<a class="nav-link" data-toggle="pill" href="#pills-notes">Notes</a>
</li>
</ul>
<hr>
<div class="tab-content"> <div class="tab-content">
<div class="tab-pane fade show active" id="pills-details"> <div class="tab-pane fade show active" id="pills-details">
@@ -373,7 +372,7 @@
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="submit" name="add_client" class="btn btn-primary text-bold" onclick="promptPrimaryContact()"><i class="fa fa-check mr-2"></i>Create</button> <button type="submit" name="add_client" class="btn btn-primary text-bold" onclick="promptPrimaryContact()"><i class="fa fa-check mr-2"></i>Create</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Close</button> <button type="button" class="btn btn-outline-secondary" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Close</button>
</div> </div>
</form> </form>
</div> </div>

View File

@@ -0,0 +1,82 @@
<div class="modal" id="addCreditModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content border-dark">
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-wallet mr-2"></i>Adding <strong>Credit</strong> (Credit Balance: <?php echo numfmt_format_currency($currency_format, $credit_balance, $client_currency_code); ?>)</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="<?php echo $_SESSION['csrf_token'] ?>">
<div class="modal-body">
<div class="form-group">
<label>Expire</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-calendar-day"></i></span>
</div>
<input type="date" class="form-control" name="expire" max="2999-12-31">
</div>
</div>
<div class="form-group">
<label>Amount<strong class="text-danger ml-2">*</strong></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="numeric" pattern="[0-9]*\.?[0-9]{0,2}" name="amount" placeholder="0.00" required>
</div>
</div>
<div class="form-group">
<label>Reference<strong class="text-danger ml-2">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-file-alt"></i></span>
</div>
<input type="text" class="form-control" name="reference" placeholder="Enter a reference" maxlength="250">
</div>
</div>
<?php if (isset($_GET['client_id'])) { ?>
<input type="hidden" name="client" value="<?php echo $client_id; ?>">
<?php } else { ?>
<div class="form-group col-md">
<label>Client</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-user"></i></span>
</div>
<select class="form-control select2" name="client" required>
<option value="0">- Client (Optional) -</option>
<?php
$sql = mysqli_query($mysqli, "SELECT client_id, client_name FROM clients ORDER BY client_name ASC");
while ($row = mysqli_fetch_array($sql)) {
$client_id = intval($row['client_id']);
$client_name = nullable_htmlentities($row['client_name']);
?>
<option value="<?php echo $client_id; ?>"><?php echo $client_name; ?></option>
<?php
}
?>
</select>
</div>
</div>
<?php } ?>
</div>
<div class="modal-footer">
<button type="submit" name="add_credit" class="btn btn-primary text-bold"><i class="fa fa-fw fa-check mr-2"></i>Add</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Cancel</button>
</div>
</form>
</div>
</div>
</div>

29
post/user/credit.php Normal file
View File

@@ -0,0 +1,29 @@
<?php
/*
* ITFlow - GET/POST request handler for credits
*/
defined('FROM_POST_HANDLER') || die("Direct file access is not allowed");
if (isset($_POST['add_credit'])) {
validateCSRFToken($_POST['csrf_token']);
enforceUserPermission('module_sales', 2);
$client_id = intval($_POST['client']);
$amount = floatval($_POST['amount']);
$expire = sanitizeInput($_POST['expire']);
$reference = sanitizeInput($_POST['reference']);
mysqli_query($mysqli,"INSERT INTO credits SET credit_amount = $amount, credit_reference = '$reference', credit_created_by = $session_user_id, credit_client_id = $client_id");
$credit_id = mysqli_insert_id($mysqli);
// Logging
logAction("Credit", "Create", "$session_name added " . numfmt_format_currency($currency_format, $amount, $session_company_currency) . "", $client_id, $credit_id);
$_SESSION['alert_message'] = "" . numfmt_format_currency($currency_format, $amount, $session_company_currency) . " Credit Added ";
header("Location: " . $_SERVER["HTTP_REFERER"]);
}

View File

@@ -894,6 +894,170 @@ if (isset($_POST['add_payment'])) {
} }
} }
if (isset($_POST['apply_credit'])) {
enforceUserPermission('module_sales', 2);
enforceUserPermission('module_financial', 2);
$invoice_id = intval($_POST['invoice_id']);
$amount = floatval($_POST['amount']);
$invoice_balance = floatval($_POST['invoice_balance']);
$currency_code = sanitizeInput($_POST['currency_code']);
$email_receipt = intval($_POST['email_receipt'] ?? 0);
$client_id = getFieldByID('invoices',$invoice_id,'invoice_client_id');
$invoice_prefix = getFieldByID('invoices',$invoice_id,'invoice_prefix');
$invoice_number = getFieldByID('invoices',$invoice_id,'invoice_number');
$invoice_status = getFieldByID('invoices',$invoice_id,'invoice_status');
//Check to see if amount entered is greater than the balance of the invoice
if ($amount > $invoice_balance) {
$_SESSION['alert_message'] = "Credit is more than the balance";
header("Location: " . $_SERVER["HTTP_REFERER"]);
} else {
mysqli_query($mysqli,"UPDATE invoices SET invoice_credit_amount = $amount WHERE invoice_id = $invoice_id");
/*
//Add up all the payments for the invoice and get the total amount paid to the invoice
$sql_total_payments_amount = mysqli_query($mysqli,"SELECT SUM(payment_amount) AS payments_amount FROM payments WHERE payment_invoice_id = $invoice_id");
$row = mysqli_fetch_array($sql_total_payments_amount);
$total_payments_amount = floatval($row['payments_amount']);
//Get the invoice total
$sql = mysqli_query($mysqli,"SELECT * FROM invoices
LEFT JOIN clients ON invoice_client_id = client_id
LEFT JOIN contacts ON clients.client_id = contacts.contact_client_id AND contact_primary = 1
WHERE invoice_id = $invoice_id"
);
$row = mysqli_fetch_array($sql);
$invoice_amount = floatval($row['invoice_amount']);
$invoice_prefix = sanitizeInput($row['invoice_prefix']);
$invoice_number = intval($row['invoice_number']);
$invoice_url_key = sanitizeInput($row['invoice_url_key']);
$invoice_currency_code = sanitizeInput($row['invoice_currency_code']);
$client_id = intval($row['client_id']);
$client_name = sanitizeInput($row['client_name']);
$contact_name = sanitizeInput($row['contact_name']);
$contact_email = sanitizeInput($row['contact_email']);
$contact_phone = sanitizeInput(formatPhoneNumber($row['contact_phone'], $row['contact_phone_country_code']));
$contact_extension = preg_replace("/[^0-9]/", '',$row['contact_extension']);
$contact_mobile = sanitizeInput(formatPhoneNumber($row['contact_mobile'], $row['contact_mobile_country_code']));
$sql = mysqli_query($mysqli,"SELECT * FROM companies WHERE company_id = 1");
$row = mysqli_fetch_array($sql);
$company_name = sanitizeInput($row['company_name']);
$company_country = sanitizeInput($row['company_country']);
$company_address = sanitizeInput($row['company_address']);
$company_city = sanitizeInput($row['company_city']);
$company_state = sanitizeInput($row['company_state']);
$company_zip = sanitizeInput($row['company_zip']);
$company_phone = sanitizeInput(formatPhoneNumber($row['company_phone'], $row['company_phone_country_code']));
$company_email = sanitizeInput($row['company_email']);
$company_website = sanitizeInput($row['company_website']);
$company_logo = sanitizeInput($row['company_logo']);
// Sanitize Config vars from get_settings.php
$config_invoice_from_name = sanitizeInput($config_invoice_from_name);
$config_invoice_from_email = sanitizeInput($config_invoice_from_email);
//Calculate the Invoice balance
$invoice_balance = $invoice_amount - $total_payments_amount;
$email_data = [];
//Determine if invoice has been paid then set the status accordingly
if ($invoice_balance == 0) {
$invoice_status = "Paid";
if ($email_receipt == 1) {
$subject = "Payment Received - Invoice $invoice_prefix$invoice_number";
$body = "Hello $contact_name,<br><br>We have received your payment in full for the amount of " . numfmt_format_currency($currency_format, $amount, $invoice_currency_code) . " for invoice <a href=\'https://$config_base_url/guest/guest_view_invoice.php?invoice_id=$invoice_id&url_key=$invoice_url_key\'>$invoice_prefix$invoice_number</a>. Please keep this email as a receipt for your records.<br><br>Amount Paid: " . numfmt_format_currency($currency_format, $amount, $invoice_currency_code) . "<br>Payment Method: $payment_method<br>Payment Reference: $reference<br><br>Thank you for your business!<br><br><br>--<br>$company_name - Billing Department<br>$config_invoice_from_email<br>$company_phone";
// Queue Mail
$email = [
'from' => $config_invoice_from_email,
'from_name' => $config_invoice_from_name,
'recipient' => $contact_email,
'recipient_name' => $contact_name,
'subject' => $subject,
'body' => $body
];
$email_data[] = $email;
// Add email to queue
if (!empty($email)) {
addToMailQueue($email_data);
}
// Get Email ID for reference
$email_id = mysqli_insert_id($mysqli);
// Email Logging
mysqli_query($mysqli,"INSERT INTO history SET history_status = 'Sent', history_description = 'Payment Receipt sent to mail queue ID: $email_id!', history_invoice_id = $invoice_id");
logAction("Invoice", "Payment", "Payment receipt for invoice $invoice_prefix$invoice_number queued to $contact_email Email ID: $email_id", $client_id, $invoice_id);
}
} else {
$invoice_status = "Partial";
if ($email_receipt == 1) {
$subject = "Partial Payment Received - Invoice $invoice_prefix$invoice_number";
$body = "Hello $contact_name,<br><br>We have received partial payment in the amount of " . numfmt_format_currency($currency_format, $amount, $invoice_currency_code) . " and it has been applied to invoice <a href=\'https://$config_base_url/guest/guest_view_invoice.php?invoice_id=$invoice_id&url_key=$invoice_url_key\'>$invoice_prefix$invoice_number</a>. Please keep this email as a receipt for your records.<br><br>Amount Paid: " . numfmt_format_currency($currency_format, $amount, $invoice_currency_code) . "<br>Payment Method: $payment_method<br>Payment Reference: $reference<br>Invoice Balance: " . numfmt_format_currency($currency_format, $invoice_balance, $invoice_currency_code) . "<br><br>Thank you for your business!<br><br><br>~<br>$company_name - Billing<br>$config_invoice_from_email<br>$company_phone";
// Queue Mail
$email = [
'from' => $config_invoice_from_email,
'from_name' => $config_invoice_from_name,
'recipient' => $contact_email,
'recipient_name' => $contact_name,
'subject' => $subject,
'body' => $body
];
$email_data[] = $email;
// Add email to queue
if (!empty($email)) {
addToMailQueue($email_data);
}
// Get Email ID for reference
$email_id = mysqli_insert_id($mysqli);
// Email Logging
mysqli_query($mysqli,"INSERT INTO history SET history_status = 'Sent', history_description = 'Payment Receipt sent to mail queue ID: $email_id!', history_invoice_id = $invoice_id");
logAction("Invoice", "Payment", "Payment receipt for invoice $invoice_prefix$invoice_number queued to $contact_email Email ID: $email_id", $client_id, $invoice_id);
}
}
//Update Invoice Status
mysqli_query($mysqli,"UPDATE invoices SET invoice_status = '$invoice_status' WHERE invoice_id = $invoice_id");
*/
//Add Payment to History
mysqli_query($mysqli,"INSERT INTO history SET history_status = '$invoice_status', history_description = 'Credit applied', history_invoice_id = $invoice_id");
// Logging
logAction("Invoice", "Payment", "Credit" . numfmt_format_currency($currency_format, $amount, $session_company_currency) . " added to invoice $invoice_prefix$invoice_number", $client_id, $invoice_id);
customAction('invoice_pay', $invoice_id);
$_SESSION['alert_message'] .= "Credit amount <strong>" . numfmt_format_currency($currency_format, $amount, $session_company_currency) . "</strong> applied";
header("Location: " . $_SERVER["HTTP_REFERER"]);
}
}
if (isset($_GET['add_payment_stripe'])) { if (isset($_GET['add_payment_stripe'])) {
enforceUserPermission('module_sales', 2); enforceUserPermission('module_sales', 2);