Settings > Invoice says), ready to * change, and goes on as a line at the rate - or, with Bill their time off, * goes on without a line, for work already on the invoice. ?invoice_id= */ require_once '../../../includes/modal_header.php'; enforceUserPermission('module_sales', 2); $invoice_id = intval($_GET['invoice_id'] ?? 0); $invoice = billingRow('invoice', $invoice_id); if (!$invoice) { exit(json_encode(['error' => 'That invoice no longer exists.'])); } $client_id = intval($invoice['client_id']); enforceClientAccess(); if (!billingCanEditItems('invoice', $invoice)) { exit(json_encode(['error' => billingNumber('invoice', $invoice) . " can't take more lines - it is paid, cancelled or non-billable."])); } $tickets = billingUnbilledTickets($client_id); $rules = billingTimeRules(); // One rate for them all, or each its own - a contract's after-hours rate, or a change of contract, makes more than one $rates = array_unique(array_map(function ($t) { return sprintf('%.2f', $t['rate']); }, $tickets)); $rate = count($rates) === 1 ? floatval(reset($rates)) : ($tickets ? null : contractClientRate($client_id)['rate']); $currency = (string) $invoice['invoice_currency_code']; $taxes = billingTaxes(); ob_start(); ?>