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 = `
${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'];