diff --git a/agent/invoice.php b/agent/invoice.php index 6695faa4..296d1c81 100644 --- a/agent/invoice.php +++ b/agent/invoice.php @@ -163,7 +163,7 @@ if (isset($_GET['invoice_id'])) { //Product autocomplete $products_sql = mysqli_query($mysqli, " SELECT - CONCAT(product_code, ' - ', product_name) AS label, + IF(product_code IS NULL OR product_code = '', product_name, CONCAT(product_code, ' - ', product_name)) AS label, product_name, product_code, product_type AS type, @@ -178,6 +178,7 @@ if (isset($_GET['invoice_id'])) { LEFT JOIN taxes ON product_tax_id = tax_id WHERE product_archived_at IS NULL GROUP BY product_id + ORDER BY product_name ASC "); if (mysqli_num_rows($products_sql) > 0) { @@ -449,7 +450,7 @@ if (isset($_GET['invoice_id'])) {
- + @@ -752,21 +753,32 @@ $(function() { var term = $.ui.autocomplete.escapeRegex(request.term.toLowerCase()); var matcher = new RegExp(term, "i"); var matches = $.grep(availableProducts, function(item) { - return matcher.test(item.label) || matcher.test(item.product_name) || matcher.test(item.product_code); + return matcher.test(item.label || "") || matcher.test(item.product_name || "") || matcher.test(item.product_code || ""); }); response(matches); }, select: function (event, ui) { - $("#name").val(ui.item.label); + $("#name").val(ui.item.product_name); $("#desc").val(ui.item.description); $("#qty").val(1); $("#price").val(ui.item.price); - $("#tax").val(ui.item.tax); + $("#tax").val(ui.item.tax).trigger('change'); $("#product_id").val(ui.item.prod_id); return false; } }); + // Typing over the name by hand breaks the link to the product + $("#name").on("input", function() { + $("#product_id").val(0); + }); + + // Product names and descriptions are user supplied - escape before + // building markup, the default renderer uses .text() for this reason + function esc(value) { + return $("
").text(value == null ? "" : value).html(); + } + // Keep it simple: default jQuery UI look, just richer content $("#name").autocomplete("instance")._renderItem = function(ul, item) { var typeText = item.type ? item.type.charAt(0).toUpperCase() + item.type.slice(1).toLowerCase() : ""; @@ -774,21 +786,22 @@ $(function() { var taxText = (item.tax_percent != null) ? (parseFloat(item.tax_percent) + "%") : "No tax"; var priceText = (item.price != null && item.price !== "") ? String(item.price) : ""; + var stockText = (item.available_stock ?? 0); var infoLeft = "
" + "
" + - "
" + (item.label || "") + - (typeText ? " (" + typeText + ")" : "") + + "
" + esc(item.label) + + (typeText ? " (" + esc(typeText) + ")" : "") + "
" + - "
" + (item.description || "") + "
" + + "
" + esc(item.description) + "
" + "
" + - "Tax: " + taxText + "" + - (showStock ? "Stock: " + (item.available_stock ?? 0) + "" : "") + + "Tax: " + esc(taxText) + "" + + (showStock ? "Stock: " + esc(stockText) + "" : "") + "
" + "
" + "
" + - "
" + priceText + "
" + + "
" + esc(priceText) + "
" + "
" + "
"; diff --git a/agent/quote.php b/agent/quote.php index 9f35b9db..197775ea 100644 --- a/agent/quote.php +++ b/agent/quote.php @@ -584,7 +584,7 @@ require_once "../includes/footer.php";