Quotes / Invoicing

- Ability to manually mark a quote as invoiced (weird css fix for this, we can remove the custom css if we make the parent button just a dropdown, but don't want to introduce extra clicks)
- When converting a quote to an invoice, show the new invoice number in the quote history
- Quotes can now be sent from the main Send dropdown, instead of having to use the send button in the options menu / main quotes.php page
This commit is contained in:
wrongecho 2025-05-14 10:41:32 +01:00
parent 0df5c01bb7
commit be66ad9a4c
4 changed files with 65 additions and 8 deletions

View File

@ -0,0 +1,15 @@
/*!
* AdminLTE 3.2.0 Specific Dropdown Fix
* Targets .fix-quote-dropdown only
* Prevents alignment bugs in split button dropdowns going too far left
* (ChatGPT)
*/
.fix-quote-dropdown .dropdown-menu {
left: auto !important;
right: 0 !important;
top: calc(100% + 0.25rem) !important;
transform: none !important;
min-width: max-content;
z-index: 1050;
}

View File

@ -27,7 +27,7 @@
</div>
<div class="modal-footer bg-white">
<button type="submit" name="add_invoice_recurring" class="btn btn-primary text-bold"><i class="fas fa-check mr-2"></i>Create Invoice</button>
<button type="submit" name="add_invoice_recurring" class="btn btn-primary text-bold"><i class="fas fa-check mr-2"></i>Create Recurring Invoice</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fas fa-times mr-2"></i>Cancel</button>
</div>
</form>

View File

@ -155,9 +155,10 @@ if (isset($_POST['add_quote_to_invoice'])) {
}
mysqli_query($mysqli,"UPDATE quotes SET quote_status = 'Invoiced' WHERE quote_id = $quote_id");
mysqli_query($mysqli,"INSERT INTO history SET history_status = 'Invoiced', history_description = 'Quote invoiced as $config_invoice_prefix$invoice_number', history_quote_id = $quote_id");
// Logging
logAction("Invoice", "Create", "$session_name created invoice $config_invoice_prefix$config_invoice_number from quote $config_quote_prefix$quote_number", $client_id, $new_invoice_id);
logAction("Invoice", "Create", "$session_name created invoice $config_invoice_prefix$invoice_number from quote $config_quote_prefix$quote_number", $client_id, $new_invoice_id);
customAction('invoice_create', $new_invoice_id);
@ -521,6 +522,31 @@ if (isset($_GET['email_quote'])) {
}
if (isset($_GET['mark_quote_invoiced'])) {
enforceUserPermission('module_sales', 2);
$quote_id = intval($_GET['mark_quote_invoiced']);
$sql = mysqli_query($mysqli,"SELECT * FROM quotes WHERE quote_id = $quote_id");
$row = mysqli_fetch_array($sql);
$quote_prefix = sanitizeInput($row['quote_prefix']);
$quote_number = sanitizeInput($row['quote_number']);
$client_id = intval($row['quote_client_id']);
mysqli_query($mysqli,"UPDATE quotes SET quote_status = 'Invoiced' WHERE quote_id = $quote_id");
mysqli_query($mysqli,"INSERT INTO history SET history_status = 'Invoiced', history_description = 'Quote marked as invoiced', history_quote_id = $quote_id");
// Logging
logAction("Quote", "Sent", "$session_name marked quote $quote_prefix$quote_number as invoiced", $client_id, $quote_id);
$_SESSION['alert_message'] = "Quote marked invoiced";
header("Location: " . $_SERVER["HTTP_REFERER"]);
}
if(isset($_POST['export_quotes_csv'])){
enforceUserPermission('module_sales');

View File

@ -137,7 +137,7 @@ if (isset($_GET['quote_id'])) {
<a href="quotes.php">Global Quotes</a>
</li>
<li class="breadcrumb-item">
<a href="quotes.php?client_id=<?php echo $client_id; ?>"><?php echo $client_name; ?>Quotes</a>
<a href="quotes.php?client_id=<?php echo $client_id; ?>"><?php echo $client_name; ?> Quotes</a>
</li>
<?php } ?>
<li class="breadcrumb-item active"><?php echo "$quote_prefix$quote_number"; ?></li>
@ -151,10 +151,15 @@ if (isset($_GET['quote_id'])) {
<div class="col-8">
<?php if ($quote_status == 'Draft' && lookupUserPermission("module_sales") >= 2) { ?>
<button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">
<i class="fas fa-paper-plane mr-2"></i>Send
<i class="fas fa-fw fa-paper-plane mr-2"></i>Send
</button>
<div class="dropdown-menu">
<?php if (!empty($config_smtp_host) && !empty($contact_email)) { ?>
<a class="dropdown-item" href="post.php?email_quote=<?php echo $quote_id; ?>">
<i class="fas fa-fw fa-paper-plane mr-2"></i>Send Email
</a>
<div class="dropdown-divider"></div>
<?php } ?>
<a class="dropdown-item" href="post.php?mark_quote_sent=<?php echo $quote_id; ?>">
<i class="fas fa-fw fa-check mr-2"></i>Mark Sent
</a>
@ -171,9 +176,19 @@ if (isset($_GET['quote_id'])) {
<?php } ?>
<?php if ($quote_status == 'Accepted') { ?>
<a class="btn btn-primary" href="#" data-toggle="modal" data-target="#addQuoteToInvoiceModal<?php echo $quote_id; ?>">
<i class="fas fa-check mr-2"></i>Invoice
</a>
<div class="btn-group fix-quote-dropdown">
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addQuoteToInvoiceModal<?php echo $quote_id; ?>">
<i class="fas fa-check mr-2"></i>Invoice
</button>
<button type="button" class="btn btn-primary dropdown-toggle dropdown-icon" data-toggle="dropdown" aria-expanded="false">
<span class="sr-only">Toggle Dropdown</span>
</button>
<div class="dropdown-menu dropdown-menu-right">
<a class="dropdown-item" href="post.php?mark_quote_invoiced=<?php echo $quote_id; ?>">
<i class="fas fa-fw fa-check mr-2"></i>Mark Invoiced
</a>
</div>
</div>
<?php } ?>
</div>
@ -1021,3 +1036,4 @@ new Sortable(document.querySelector('table#items tbody'), {
}
});
</script>
<link rel="stylesheet" href="css/quote_dropdowns_fix.css">