mirror of
https://github.com/itflow-org/itflow
synced 2026-08-31 11:55:11 +00:00
Email Invoice Only shows Billing and Primary, Quote shows Important Billing, Primary and Technical contacts that can be selected
This commit is contained in:
@@ -106,15 +106,15 @@ if (isset($_GET['invoice_id'])) {
|
||||
}
|
||||
$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.
|
||||
// Must use the same rule as the Send Email picker in
|
||||
// modals/invoice/invoice_email.php, or the button offers a modal that then
|
||||
// reports there is nobody to send to.
|
||||
$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 != ''"));
|
||||
AND contact_email != ''
|
||||
" . documentContactFilterSql('invoice')));
|
||||
$emailable_contacts = intval($row['emailable_contacts']);
|
||||
|
||||
$sql_history = mysqli_query($mysqli, "SELECT history_created_at, history_description, history_status FROM history WHERE history_invoice_id = $invoice_id ORDER BY history_id DESC");
|
||||
|
||||
@@ -16,9 +16,10 @@ $client_id = intval($row['invoice_client_id']);
|
||||
|
||||
enforceClientAccess();
|
||||
|
||||
// Everyone at the client who can actually receive mail. Primary and billing
|
||||
// contacts lead because they are the ones checked by default below - that
|
||||
// pairing is the behaviour the old one-click Send Email link had baked in.
|
||||
// Billing-facing contacts only - see documentContactFilterSql(). Everyone
|
||||
// shown is also checked by default, which is the behaviour the old one-click
|
||||
// Send Email link had baked in; the checkboxes are here to drop one, not to
|
||||
// go hunting for somebody.
|
||||
$sql_contacts = mysqli_query(
|
||||
$mysqli,
|
||||
"SELECT contact_billing, contact_email, contact_id, contact_name, contact_primary, contact_title
|
||||
@@ -27,6 +28,7 @@ $sql_contacts = mysqli_query(
|
||||
AND contact_archived_at IS NULL
|
||||
AND contact_email IS NOT NULL
|
||||
AND contact_email != ''
|
||||
" . documentContactFilterSql('invoice') . "
|
||||
ORDER BY contact_primary DESC, contact_billing DESC, contact_name ASC"
|
||||
);
|
||||
|
||||
@@ -51,9 +53,9 @@ ob_start();
|
||||
<?php if ($contact_count == 0) { ?>
|
||||
|
||||
<p class="text-muted mb-0">
|
||||
This client has no contacts with an email address, so there is nobody to send to.
|
||||
Add a contact with an email address, or use Mark Sent to record that the invoice
|
||||
went out some other way.
|
||||
This client has no primary or billing contact with an email address, so there is
|
||||
nobody to send an invoice to. Flag a contact as billing, or use Mark Sent to record
|
||||
that the invoice went out some other way.
|
||||
</p>
|
||||
|
||||
<?php } else { ?>
|
||||
|
||||
@@ -16,15 +16,19 @@ $client_id = intval($row['quote_client_id']);
|
||||
|
||||
enforceClientAccess();
|
||||
|
||||
// Wider than the invoice picker - see documentContactFilterSql(). A quote is
|
||||
// read by whoever scoped the work as often as by whoever signs it.
|
||||
$sql_contacts = mysqli_query(
|
||||
$mysqli,
|
||||
"SELECT contact_billing, contact_email, contact_id, contact_name, contact_primary, contact_title
|
||||
"SELECT contact_billing, contact_email, contact_id, contact_important, contact_name,
|
||||
contact_primary, contact_technical, contact_title
|
||||
FROM contacts
|
||||
WHERE contact_client_id = $client_id
|
||||
AND contact_archived_at IS NULL
|
||||
AND contact_email IS NOT NULL
|
||||
AND contact_email != ''
|
||||
ORDER BY contact_primary DESC, contact_billing DESC, contact_name ASC"
|
||||
" . documentContactFilterSql('quote') . "
|
||||
ORDER BY contact_primary DESC, contact_billing DESC, contact_technical DESC, contact_name ASC"
|
||||
);
|
||||
|
||||
$contact_count = mysqli_num_rows($sql_contacts);
|
||||
@@ -48,9 +52,9 @@ ob_start();
|
||||
<?php if ($contact_count == 0) { ?>
|
||||
|
||||
<p class="text-muted mb-0">
|
||||
This client has no contacts with an email address, so there is nobody to send to.
|
||||
Add a contact with an email address, or use Mark Sent to record that the quote
|
||||
went out some other way.
|
||||
This client has no primary, billing, technical or important contact with an email
|
||||
address, so there is nobody to send a quote to. Flag a contact with one of those
|
||||
roles, or use Mark Sent to record that the quote went out some other way.
|
||||
</p>
|
||||
|
||||
<?php } else { ?>
|
||||
@@ -68,6 +72,8 @@ ob_start();
|
||||
$contact_title = escapeHtml($row['contact_title']);
|
||||
$contact_primary = intval($row['contact_primary']);
|
||||
$contact_billing = intval($row['contact_billing']);
|
||||
$contact_technical = intval($row['contact_technical']);
|
||||
$contact_important = intval($row['contact_important']);
|
||||
|
||||
// Default selection reproduces the old link: quotes went to
|
||||
// the primary contact only. Billing contacts are listed and
|
||||
@@ -88,6 +94,12 @@ ob_start();
|
||||
<?php if ($contact_billing == 1) { ?>
|
||||
<span class="badge text-bg-success ms-1">Billing</span>
|
||||
<?php } ?>
|
||||
<?php if ($contact_technical == 1) { ?>
|
||||
<span class="badge text-bg-info ms-1">Technical</span>
|
||||
<?php } ?>
|
||||
<?php if ($contact_important == 1) { ?>
|
||||
<span class="badge text-bg-warning ms-1">Important</span>
|
||||
<?php } ?>
|
||||
<?php if (!empty($contact_title)) { ?>
|
||||
<span class="text-muted ms-1"><?= $contact_title ?></span>
|
||||
<?php } ?>
|
||||
|
||||
@@ -99,15 +99,15 @@ 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.
|
||||
// Must use the same rule as the Send Email picker in
|
||||
// modals/quote/quote_email.php, or the button offers a modal that then
|
||||
// reports there is nobody to send to.
|
||||
$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 != ''"));
|
||||
AND contact_email != ''
|
||||
" . documentContactFilterSql('quote')));
|
||||
$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");
|
||||
|
||||
@@ -786,6 +786,34 @@ function createiCalStrCancel($datetime, $title, $uid) {
|
||||
return $cal_event->export();
|
||||
}
|
||||
|
||||
/*
|
||||
* Which contacts a document's Send Email picker offers, as a SQL fragment.
|
||||
*
|
||||
* A client with fifty contacts should not hand the agent a fifty-row list to
|
||||
* scroll, so the picker is narrowed to the people a given document type is
|
||||
* actually addressed to:
|
||||
*
|
||||
* invoice - primary and billing. A bill goes to whoever pays it.
|
||||
* quote - primary, billing, technical and important. A quote gets read by
|
||||
* the person who scoped the work as often as the one who signs it.
|
||||
*
|
||||
* Lives here rather than inline in the modals because the Send Email button on
|
||||
* agent/invoice.php and agent/quote.php gates on a COUNT using the same rule -
|
||||
* if the two drift, the button appears and then the modal it opens reports
|
||||
* there is nobody to send to.
|
||||
*
|
||||
* Note the post handlers deliberately do NOT re-apply this filter. It is a
|
||||
* shortlist, not a permission boundary: any agent who can send a document can
|
||||
* already set these flags on a contact.
|
||||
*/
|
||||
function documentContactFilterSql($document_type) {
|
||||
if ($document_type === 'quote') {
|
||||
return "AND (contact_primary = 1 OR contact_billing = 1 OR contact_technical = 1 OR contact_important = 1)";
|
||||
}
|
||||
|
||||
return "AND (contact_primary = 1 OR contact_billing = 1)";
|
||||
}
|
||||
|
||||
/*
|
||||
* The delivery methods offered by the Mark Sent modal on invoices and quotes.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user