diff --git a/htdocs/ai/js/ai_assistant.js b/htdocs/ai/js/ai_assistant.js index ab175c42f2b..1b620f16f9c 100644 --- a/htdocs/ai/js/ai_assistant.js +++ b/htdocs/ai/js/ai_assistant.js @@ -944,8 +944,16 @@ document.addEventListener('DOMContentLoaded', () => { } function handleConfirmation(action, details, originalIntent) { - pendingIntent = originalIntent.arguments.original_intent || originalIntent; - const toolName = pendingIntent.tool || 'unknown tool'; + // original_intent must be provided by parse_intent.php. + // If missing, treat as a malformed confirmation and abort. + if (!originalIntent.arguments || !originalIntent.arguments.original_intent) { + appendMsg('error', t('AIError') + ': malformed confirmation response (missing original_intent). Please try again.'); + input.disabled = false; + input.focus(); + return; + } + pendingIntent = originalIntent.arguments.original_intent; + const toolName = pendingIntent.tool || 'unknown tool'; let template = t('ConfirmAiAction'); let messageHtml = template.replace('%1$s', `${action}`).replace('%2$s', `${toolName}`); let html = `
${t('confirmation')}

${messageHtml}

${details ? `

${details}

` : ''}
`; @@ -1022,6 +1030,17 @@ document.addEventListener('DOMContentLoaded', () => { appendMsg('system', ` ${t('ExecutingTool')} ${pendingIntent.tool || ''}...`); const loadingMsg = chat.lastElementChild; input.disabled = true; + // PendingIntent must be a real action tool, never a system tool. + // This catches the edge case where handleConfirmation stored the wrong intent. + const systemTools = ['ask_for_confirmation', 'ask_for_clarification', 'respond_to_user', 'reject_general_question']; + if (!pendingIntent || !pendingIntent.tool || systemTools.includes(pendingIntent.tool)) { + loadingMsg.remove(); + appendMsg('error', t('AIError') + ': cannot execute system tool "' + (pendingIntent && pendingIntent.tool || 'unknown') + '" as an action. Please try again.'); + pendingIntent = null; + input.disabled = false; + input.focus(); + return; + } try { const toolRes = await fetch('execute_tool.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, diff --git a/htdocs/comm/propal/messaging.php b/htdocs/comm/propal/messaging.php index 5fe4b9c0ca7..f8f44ae8338 100644 --- a/htdocs/comm/propal/messaging.php +++ b/htdocs/comm/propal/messaging.php @@ -215,17 +215,6 @@ if (!empty($object->id)) { $messagingUrl = DOL_URL_ROOT . '/comm/propal/agenda.php?id=' . $object->id; // Changed from projet $morehtmlright .= dolGetButtonTitle($langs->trans('MessageListViewType'), '', 'fa fa-bars imgforviewmode', $messagingUrl, '', 1); - - // // Show link to send an email (if read and not closed) - // $btnstatus = $object->status < Ticket::STATUS_CLOSED && $action != "presend" && $action != "presend_addmessage"; - // $url = 'card.php?track_id='.$object->track_id.'&action=presend_addmessage&mode=init&private_message=0&send_email=1&backtopage='.urlencode($_SERVER["PHP_SELF"].'?track_id='.$object->track_id).'#formmailbeforetitle'; - // $morehtmlright .= dolGetButtonTitle($langs->trans('SendMail'), '', 'fa fa-paper-plane', $url, 'email-title-button', $btnstatus); - - // // Show link to add a private message (if read and not closed) - // $btnstatus = $object->status < Ticket::STATUS_CLOSED && $action != "presend" && $action != "presend_addmessage"; - // $url = 'card.php?track_id='.$object->track_id.'&action=presend_addmessage&mode=init&backtopage='.urlencode($_SERVER["PHP_SELF"].'?track_id='.$object->track_id).'#formmailbeforetitle'; - // $morehtmlright .= dolGetButtonTitle($langs->trans('TicketAddMessage'), '', 'fa fa-comment-dots', $url, 'add-new-ticket-title-button', $btnstatus); - // Show link to add event if (isModEnabled('agenda')) { $addActionBtnRight = $user->hasRight('agenda', 'myactions', 'create') || $user->hasRight('agenda', 'allactions', 'create'); diff --git a/htdocs/takepos/index.php b/htdocs/takepos/index.php index 4f8338fe24e..23821db4d3b 100644 --- a/htdocs/takepos/index.php +++ b/htdocs/takepos/index.php @@ -2,7 +2,7 @@ /* Copyright (C) 2018 Andreu Bisquerra * Copyright (C) 2019 Josep Lluís Amador * Copyright (C) 2020 Thibault FOUCART - * Copyright (C) 2024-2025 MDW + * Copyright (C) 2024-2026 MDW * Copyright (C) 2024-2025 Frédéric France * * This program is free software; you can redistribute it and/or modify @@ -499,7 +499,7 @@ function MoreProducts(moreorless) { } var nb_cat_shown = $('.div5 div.wrapper2[data-iscat=1]').length; - var offset = * pageproducts - nb_cat_shown; + var offset = * pageproducts - nb_cat_shown; // Get socid let socid = jQuery('#thirdpartyid').val(); @@ -566,7 +566,7 @@ function MoreProducts(moreorless) { ClearSearch(false); } -function ClickProduct(position, qty = 1) { +function ClickProduct(position, qty = 1, qty_std = 0) { console.log("ClickProduct at position"+position); if ($('#invoiceid').val() == "") { invoiceid = $('#invoiceid').val(); @@ -585,9 +585,9 @@ function ClickProduct(position, qty = 1) { if (idproduct == "") { return; } - addInvoiceLine = function(qty) { + addInvoiceLine = function(qty, qty_std_inner = 0) { // Call page invoice.php to generate the section with product lines - $("#poslines").load("invoice.php?action=addline&token=&place="+place+"&idproduct="+idproduct+"&qty="+qty+"&invoiceid="+invoiceid, function() { + $("#poslines").load("invoice.php?action=addline&token=&place="+place+"&idproduct="+idproduct+"&qty="+qty+"&invoiceid="+invoiceid+(qty_std_inner ? '&qty_std=1' : ''), function() { idproduct = ""; - addInvoiceLine(qty); + addInvoiceLine(qty, qty_std); } @@ -893,7 +893,7 @@ function Search2(keyCodeForEnter, moreorless) { } else if ('product' == data[0]['object'] && $('#search').val() == data[0]['barcode']) { console.log("There is only 1 answer and we found search on a barcode, so we add the product in basket, qty="+data[0]['qty']); - ClickProduct(0, data[0]['qty']); + ClickProduct(0, data[0]['qty'], 1); } } if (eventKeyCode == keyCodeForEnter){ @@ -1607,7 +1607,7 @@ if ($reshook == 0) { //add buttons } } elseif ($reshook == 1) { $r = 0; //replace buttons - if (is_array($hookmanager->resArray) ) { + if (is_array($hookmanager->resArray)) { foreach ($hookmanager->resArray as $resArray) { foreach ($resArray as $butmenu) { $menus[$r++] = $butmenu; @@ -1720,14 +1720,14 @@ if ($reshook == 0) { //add buttons while ($count < $MAXPRODUCT) { print '
- onclick="MoreProducts('less')" onclick="MoreProducts('more')" > + onclick="MoreProducts('less')" onclick="MoreProducts('more')" > '; diff --git a/htdocs/takepos/invoice.php b/htdocs/takepos/invoice.php index 56fdbf23277..db81c959614 100644 --- a/htdocs/takepos/invoice.php +++ b/htdocs/takepos/invoice.php @@ -761,7 +761,7 @@ if (empty($reshook)) { $datapriceofproduct = $prod->getSellPrice($mysoc, $customer, 0); - $qty = GETPOSTISSET('qty') ? GETPOSTFLOAT('qty') : 1; + $qty = GETPOSTISSET('qty') ? GETPOSTFLOAT('qty', '', GETPOSTINT('qty_std') ? 1 : 2) : 1; $price = $datapriceofproduct['pu_ht']; $price_ttc = $datapriceofproduct['pu_ttc']; //$price_min = $datapriceofproduct['price_min'];