Send Email and Mark Sent modals for invoices and quotes (db 2.7.7)

Send Email opens a contact picker instead of hardcoding the primary contact; Mark Sent asks how it went out and takes a note. Both log recipients / method / note to the document history. Handlers moved GET -> POST.

Fixes two pre-existing bugs in the email path: archived contacts were still receiving billing copies, and every copy was addressed to the primary contact by name.
This commit is contained in:
johnnyq
2026-08-28 13:31:22 -04:00
parent 20b8fb5379
commit 72e6f23e19
14 changed files with 680 additions and 98 deletions

View File

@@ -99,6 +99,17 @@ if (isset($_GET['quote_id'])) {
$company_website = escapeHtml($row['company_website']);
$company_logo = escapeHtml($row['company_logo']);
// Send Email used to be gated on the PRIMARY contact having an email, which
// hid the button on a client whose only emailable contact was a billing or
// secondary one. The modal can send to any of them, so gate on whether the
// client has anybody reachable at all.
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT(contact_id) AS emailable_contacts FROM contacts
WHERE contact_client_id = $client_id
AND contact_archived_at IS NULL
AND contact_email IS NOT NULL
AND contact_email != ''"));
$emailable_contacts = intval($row['emailable_contacts']);
$sql_history = mysqli_query($mysqli, "SELECT history_created_at, history_description, history_status FROM history WHERE history_quote_id = $quote_id ORDER BY history_id DESC");
//Set Badge color based off of quote status
@@ -156,13 +167,15 @@ if (isset($_GET['quote_id'])) {
<i class="fas fa-fw fa-paper-plane me-2"></i>Send
</button>
<div class="dropdown-menu">
<?php if (!empty($config_smtp_provider) && !empty($contact_email)) { ?>
<a class="dropdown-item" href="post.php?email_quote=<?= $quote_id ?>&csrf_token=<?= $_SESSION['csrf_token'] ?>">
<?php if (!empty($config_smtp_provider) && $emailable_contacts > 0) { ?>
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/quote/quote_email.php?quote_id=<?= $quote_id ?>">
<i class="fas fa-fw fa-paper-plane me-2"></i>Send Email
</a>
<div class="dropdown-divider"></div>
<?php } ?>
<a class="dropdown-item" href="post.php?mark_quote_sent=<?= $quote_id ?>&csrf_token=<?= $_SESSION['csrf_token'] ?>">
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/quote/quote_mark_sent.php?quote_id=<?= $quote_id ?>">
<i class="fas fa-fw fa-check me-2"></i>Mark Sent
</a>
</div>
@@ -219,8 +232,9 @@ if (isset($_GET['quote_id'])) {
<a class="dropdown-item" href="post.php?export_quote_pdf=<?= $quote_id ?>&csrf_token=<?= $_SESSION['csrf_token'] ?>" target="_blank">
<i class="fa fa-fw fa-download text-secondary me-2"></i>Download PDF
</a>
<?php if (!empty($config_smtp_provider) && !empty($contact_email)) { ?>
<a class="dropdown-item" href="post.php?email_quote=<?= $quote_id ?>&csrf_token=<?= $_SESSION['csrf_token'] ?>">
<?php if (!empty($config_smtp_provider) && $emailable_contacts > 0) { ?>
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/quote/quote_email.php?quote_id=<?= $quote_id ?>">
<i class="fa fa-fw fa-paper-plane text-secondary me-2"></i>Send Email
</a>
<?php } ?>
@@ -565,7 +579,7 @@ if (isset($_GET['quote_id'])) {
while ($row = mysqli_fetch_assoc($sql_history)) {
$history_created_at = escapeHtml($row['history_created_at']);
$history_status = escapeHtml($row['history_status']);
$history_description = escapeHtml($row['history_description']);
$history_description = nl2br(escapeHtml($row['history_description']));
?>
<tr>