';
print '
' . $langs->trans("ClaudeDesktopConfig") . '';
print '
';
- echo htmlspecialchars('{
+ echo htmlspecialchars('
+ {
"mcpServers": {
"dolibarr": {
"command": "node",
diff --git a/htdocs/ai/assistant/parse_intent.php b/htdocs/ai/assistant/parse_intent.php
index 897f524f110..cfb04707ad7 100644
--- a/htdocs/ai/assistant/parse_intent.php
+++ b/htdocs/ai/assistant/parse_intent.php
@@ -270,7 +270,16 @@ try {
}
// If we are sending a lot of tools (Non-Latin or Fallback), we strip descriptions.
- $isLargeSchema = count($toolsSchema) > 20;
+ // The 20-tool threshold was likely chosen for GPT-3.5 (4K context window). Modern
+ // LLMs handle the full schema trivially: Gemini 2.5 Flash has a 1M token context,
+ // GPT-4o has 128K, Claude Sonnet has 1M. Compression hurts more than it helps
+ // today because it also truncates tool *descriptions* (down to 3 words), which
+ // breaks tool selection (e.g. "create_other_document" becomes "Create documents
+ // other" -- the LLM then thinks supplier_invoice creation is not available).
+ // We raise the threshold to 100 to effectively disable compression for the
+ // default install (~30 tools), while still leaving a safety net for very large
+ // custom installs that register dozens of additional addMcpTools hooks.
+ $isLargeSchema = count($toolsSchema) > 100;
$toolsForLLM = cleanToolSchemaForLLM($toolsSchema, $isLargeSchema);
// Build System Prompt
@@ -293,8 +302,34 @@ try {
$defUrl = $servicesList[$serviceKey]['url'] ?? '';
$url = getDolGlobalString('AI_API_' . strtoupper($serviceKey) . '_URL') ?: $defUrl;
- $defModel = $servicesList[$serviceKey]['textgeneration'] ?? 'gpt-4o-mini';
- $model = getDolGlobalString('AI_API_' . strtoupper($serviceKey) . '_MODEL') ?: $defModel;
+ // The model defaults declared in getListOfAIServices() are nested:
+ // $servicesList[$key]['textgeneration'] = ['default' => 'model-name']
+ // Reading 'textgeneration' without ['default'] returns the inner array, which
+ // then fails the (string) type-hint of UniversalLLMAdapter's 4th argument with:
+ // "Argument #4 ($model) must be of type string, array given"
+ //
+ // The admin UI (htdocs/ai/admin/setup.php "Prompt and custom AI models" tab) also
+ // stores the per-function model under AI_API__MODEL_TEXT (matching the
+ // convention already used by Ai::generateContent() for the same data). The
+ // previous lookup used AI_API__MODEL which is never written by that
+ // form, so the user-configured model was silently ignored.
+ $rawDefault = $servicesList[$serviceKey]['textgeneration'] ?? null;
+ if (is_array($rawDefault)) {
+ $defModel = $rawDefault['default'] ?? 'gpt-4o-mini';
+ } else {
+ $defModel = $rawDefault ?: 'gpt-4o-mini';
+ }
+ $prefix = 'AI_API_' . strtoupper($serviceKey);
+ $model = getDolGlobalString($prefix . '_MODEL_TEXT')
+ ?: getDolGlobalString($prefix . '_MODEL')
+ ?: $defModel;
+ // Defensive: coerce to string if anyone stored an array in this constant
+ if (is_array($model)) {
+ $model = $model['default'] ?? $defModel;
+ }
+ if (!is_string($model) || $model === '') {
+ $model = (string) $defModel;
+ }
$adapterType = $servicesList[$serviceKey]['adapter_type'] ?? 'openai';
if (!empty($apiKey)) {
@@ -727,12 +762,15 @@ function cleanToolSchemaForLLM(array $tools, bool $isLargeSchema = false)
$cleaned = [];
foreach ($tools as $tool) {
- // Tool Description: Max 3 words
+ // Tool descriptions are how the LLM selects the right tool -- never truncate
+ // them, even when the schema is large. Truncating to 3 words ("Create documents
+ // other", "Add a single") breaks tool selection. If the schema really is too
+ // big for the chosen model, the right answer is to filter the toolset before
+ // it reaches the LLM (which is what filterToolsProfessional() already does
+ // upstream of this function), not to mutilate each tool's description.
+ // Parameter-level compression (stripping defaults, descriptions of optional
+ // fields, etc.) remains gated on $isLargeSchema below.
$desc = $tool['description'];
- if ($isLargeSchema) {
- $words = explode(' ', $desc);
- $desc = implode(' ', array_slice($words, 0, 3));
- }
// Get parameters
$toolParams = $tool['parameters'] ?? $tool['inputSchema'] ?? [];
diff --git a/htdocs/ai/class/ai.class.php b/htdocs/ai/class/ai.class.php
index 3bd792c5e5e..a5396347ec8 100644
--- a/htdocs/ai/class/ai.class.php
+++ b/htdocs/ai/class/ai.class.php
@@ -140,7 +140,14 @@ class Ai
$this->apiEndpoint .= (preg_match('/\/$/', $this->apiEndpoint) ? '' : '/').'threads';
} else { // if $function == 'docparsing', 'text...', ...
$this->apiEndpoint = getDolGlobalString('AI_API_'.strtoupper($this->apiService).'_URL', $arrayofai[$this->apiService]['url']);
- $this->apiEndpoint .= (preg_match('/\/$/', $this->apiEndpoint) ? '' : '/').'chat/completions';
+ if ($this->apiService == 'google') {
+ // Google Gemini native API: the /models/:generateContent suffix is
+ // appended later (once $model has been resolved). The OpenAI-style
+ // /chat/completions does not exist on the native Gemini endpoint.
+ $this->apiEndpoint = rtrim($this->apiEndpoint, '/');
+ } else {
+ $this->apiEndpoint .= (preg_match('/\/$/', $this->apiEndpoint) ? '' : '/').'chat/completions';
+ }
}
}
if ($moreendpoint) {
@@ -170,6 +177,12 @@ class Ai
}
}
+ // Google Gemini: append /models/:generateContent now that $model is resolved.
+ if ($this->apiService == 'google' && !in_array($function, array('file', 'assistant', 'thread'))
+ && strpos($this->apiEndpoint, ':generateContent') === false) {
+ $this->apiEndpoint .= '/models/'.rawurlencode($model).':generateContent';
+ }
+
dol_syslog("Call API for apiKey=".substr($this->apiKey, 0, 5).'***********, apiEndpoint='.$this->apiEndpoint.", model=".$model.", format=".$format);
if (getDolGlobalString("AI_DEBUG")) {
if (@is_writable($dolibarr_main_data_root)) { // Avoid fatal error on fopen with open_basedir
@@ -269,18 +282,33 @@ class Ai
"top_p": 0.95
}*/
- $arrayforpayload = array(
- 'messages' => array(array('role' => 'user', 'content' => $fullInstructions)),
- 'model' => $model,
- );
-
// Add a system message
$addDateTimeContext = false;
if ($addDateTimeContext) { // @phpstan-ignore-line
$prePrompt = ($prePrompt ? $prePrompt.(preg_match('/[\.\!\?]$/', $prePrompt) ? '' : '.').' ' : '').'Today we are '.dol_print_date(dol_now(), 'dayhourtext');
}
- if ($prePrompt) {
- $arrayforpayload['messages'][] = array('role' => 'system', 'content' => $prePrompt);
+
+ if ($this->apiService == 'google') {
+ // Google Gemini native payload format (different from OpenAI's "messages").
+ $arrayforpayload = array(
+ 'contents' => array(
+ array('role' => 'user', 'parts' => array(array('text' => $fullInstructions)))
+ )
+ );
+ if ($prePrompt) {
+ $arrayforpayload['system_instruction'] = array(
+ 'parts' => array(array('text' => $prePrompt))
+ );
+ }
+ } else {
+ // OpenAI-compatible payload format (chatgpt, mistral, groq, anthropic-compat, custom, ...)
+ $arrayforpayload = array(
+ 'messages' => array(array('role' => 'user', 'content' => $fullInstructions)),
+ 'model' => $model,
+ );
+ if ($prePrompt) {
+ $arrayforpayload['messages'][] = array('role' => 'system', 'content' => $prePrompt);
+ }
}
}
@@ -296,9 +324,16 @@ class Ai
$payload = json_encode($arrayforpayload);
}
- $headers = array(
- 'Authorization: Bearer ' . $this->apiKey,
- );
+ if ($this->apiService == 'google') {
+ // Google Gemini uses the x-goog-api-key header (Bearer is not accepted by the native API).
+ $headers = array(
+ 'x-goog-api-key: ' . $this->apiKey,
+ );
+ } else {
+ $headers = array(
+ 'Authorization: Bearer ' . $this->apiKey,
+ );
+ }
if ($function != 'file') {
$headers[] = 'Content-Type: application/json';
}
@@ -388,6 +423,18 @@ class Ai
} else {
$generatedContent = var_export($decodedResponse['error'], true);
}
+ } elseif ($this->apiService == 'google') {
+ // Google Gemini response shape: candidates[0].content.parts[*].text
+ // (parts is an array because Gemini can return mixed-modality output;
+ // we concatenate the textual parts.)
+ $generatedContent = '';
+ if (!empty($decodedResponse['candidates'][0]['content']['parts'])) {
+ foreach ($decodedResponse['candidates'][0]['content']['parts'] as $part) {
+ if (isset($part['text'])) {
+ $generatedContent .= $part['text'];
+ }
+ }
+ }
} else {
$generatedContent = $decodedResponse['choices'][0]['message']['content'];
}
diff --git a/htdocs/ai/class/llmadapter.class.php b/htdocs/ai/class/llmadapter.class.php
index b897f3d8402..b5bb2394f36 100644
--- a/htdocs/ai/class/llmadapter.class.php
+++ b/htdocs/ai/class/llmadapter.class.php
@@ -195,32 +195,42 @@ class UniversalLLMAdapter
*/
private function curl(string $url, array $data, array $headers, bool $isClaude = false, bool $isGemini = false): ?string
{
- $ch = curl_init($url);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
- curl_setopt($ch, CURLOPT_POST, true);
+ include_once DOL_DOCUMENT_ROOT.'/core/lib/geturl.lib.php';
- $payload = json_encode($data);
- if ($payload === false) {
- return "Error: Failed to encode JSON payload.";
+ // By default, we accept only external endpoints ($dolibarr_ai_allow_local_endpoints is not set).
+ // To allow local endpoints, we must set $dolibarr_ai_allow_local_endpoints to 1 or 2 in conf.php.
+ global $dolibarr_ai_allow_local_endpoints;
+ $localurl = $dolibarr_ai_allow_local_endpoints ?? 0;
+
+ // Pass $this->timeout as the response timeout so the LLM-specific value configured
+ // at construction time is honored (getURLContent's $timeoutresponse is the 10th arg;
+ // preceding args $ssl_verifypeer=-1 and $timeoutconnect=0 keep their defaults).
+ $result = getURLContent($url, 'POST', json_encode($data), 1, $headers, array('http', 'https'), $localurl, -1, 0, $this->timeout);
+
+ $body = (string) ($result['content'] ?? '');
+ $httpCode = (int) ($result['http_code'] ?? 0);
+ $effectiveUrl = (string) ($result['url'] ?? $url);
+ // Store an enriched payload so the admin Log Viewer ("VIEW LOGS" in the AI Server
+ // MCP setup page) shows something actionable when something goes wrong, not just
+ // a bare "Invalid JSON response from API." with an empty body.
+ $this->lastResponse = "HTTP " . $httpCode . " from " . $effectiveUrl
+ . "\n--- body (" . strlen($body) . " bytes) ---\n"
+ . $body;
+
+ if (!empty($result['curl_error_no'])) {
+ return "Error: cURL #" . $result['curl_error_no'] . " " . $result['curl_error_msg'] . " (url=" . $effectiveUrl . ")";
}
- curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
- curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
- curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout);
- $res = curl_exec($ch);
- $this->lastResponse = (string) $res;
-
- if (curl_errno($ch)) {
- $error = curl_error($ch);
- curl_close($ch);
- return "Error: " . $error;
- }
- curl_close($ch);
-
- $json = json_decode((string) $res, true);
+ $json = json_decode($body, true);
if ($json === null && json_last_error() !== JSON_ERROR_NONE) {
- return "Error: Invalid JSON response from API.";
+ // Common real-world causes: HTTP 4xx/5xx with empty body, HTML error page
+ // from a proxy, gateway timeout, etc. Surface the HTTP code and a short
+ // body snippet so the admin can diagnose without re-running with curl.
+ $snippet = substr($body, 0, 500);
+ return "Error: Invalid JSON response from API (HTTP " . $httpCode . ", "
+ . strlen($body) . " bytes). Body snippet: "
+ . ($snippet !== '' ? $snippet : '');
}
if (isset($json['error'])) {
diff --git a/htdocs/ai/js/ai_assistant.js b/htdocs/ai/js/ai_assistant.js
index 9b00e48450d..ab175c42f2b 100644
--- a/htdocs/ai/js/ai_assistant.js
+++ b/htdocs/ai/js/ai_assistant.js
@@ -589,7 +589,20 @@ document.addEventListener('DOMContentLoaded', () => {
try {
const { getDocument } = await getPdfLib();
const arrayBuffer = await file.arrayBuffer();
- const pdf = await getDocument({ data: arrayBuffer }).promise;
+ // cMapUrl + standardFontDataUrl are REQUIRED for PDFs that ship with
+ // custom CID fonts referencing ToUnicode CMaps (extremely common with
+ // generators like TCPDF, wkhtmltopdf, iText, etc.). Without these,
+ // getTextContent() returns raw glyph codes that look like garbled
+ // base64. jsdelivr is used here because cdnjs (used elsewhere for the
+ // pdf.js bundle) does not distribute the cmaps/ and standard_fonts/
+ // resource directories.
+ const PDFJS_RES = 'https://cdn.jsdelivr.net/npm/pdfjs-dist@5.4.149';
+ const pdf = await getDocument({
+ data: arrayBuffer,
+ cMapUrl: PDFJS_RES + '/cmaps/',
+ cMapPacked: true,
+ standardFontDataUrl: PDFJS_RES + '/standard_fonts/',
+ }).promise;
let fullText = "";
const totalPages = pdf.numPages; // Get total pages
@@ -688,7 +701,7 @@ document.addEventListener('DOMContentLoaded', () => {
class SpeechPipeline {
static task = 'automatic-speech-recognition';
- static model = 'Xenova/whisper-small.en';
+ static model = 'Xenova/whisper-small.en';
static instance = null;
static async getInstance(progress_callback = null) {
diff --git a/htdocs/ai/server/mcp_server.php b/htdocs/ai/server/mcp_server.php
index b7fd42c1821..854170c07f6 100644
--- a/htdocs/ai/server/mcp_server.php
+++ b/htdocs/ai/server/mcp_server.php
@@ -76,12 +76,20 @@ $headers = array_change_key_case($headers, CASE_LOWER);
$authHeader = $headers['authorization'] ?? '';
$apiKeyHeader = $headers['x-api-key'] ?? '';
+// Fallback: also accept the key in a query string parameter (?api_key=XXX or ?key=XXX).
+// Required for MCP clients that don't support custom auth headers in their connector UI
+// (e.g. Claude Desktop "Custom Connectors" in beta only exposes OAuth fields).
+// SECURITY NOTE: query-string keys appear in webserver access logs and possibly in Referer
+// headers. Header-based auth (X-API-Key / Authorization) remains preferred and is tried first.
+// Administrators relying on the fallback should restrict access at the webserver level
+// and/or rotate AI_MCP_API_KEY regularly.
+$apiKeyQuery = $_GET['api_key'] ?? $_GET['key'] ?? '';
$storedKey = getDolGlobalString('AI_MCP_API_KEY');
$valid = false;
if (!empty($storedKey)) {
- // X-API-Key
+ // X-API-Key header (preferred)
if (!empty($apiKeyHeader)) {
$valid = hash_equals($storedKey, $apiKeyHeader);
}
@@ -94,6 +102,11 @@ if (!empty($storedKey)) {
$valid = hash_equals($storedKey, $token);
}
}
+
+ // Query-string fallback (last resort for header-less clients)
+ if (!$valid && !empty($apiKeyQuery)) {
+ $valid = hash_equals($storedKey, $apiKeyQuery);
+ }
}
if (!$valid) {
@@ -133,8 +146,74 @@ if ($userId > 0) {
exit;
}
+// Load the AI request log helper so we can persist tools/call invocations to
+// llx_ai_request_log (same table the AI Assistant web UI logs to). This gives
+// administrators a single place to audit external MCP client activity.
+require_once DOL_DOCUMENT_ROOT . '/ai/lib/ai.lib.php';
+
+/**
+ * Persist an MCP tools/call invocation to the llx_ai_request_log table.
+ * Mirrors what parse_intent.php does for the web AI Assistant.
+ * Only tools/call is logged -- lifecycle methods (initialize, ping,
+ * notifications/initialized, tools/list, ...) are skipped to avoid noise.
+ *
+ * @param array $req The JSON-RPC request
+ * @param mixed $resp The JSON-RPC response (null for notifications)
+ * @param float $tStart microtime(true) captured before processing
+ * @param string $rawInput Raw request body
+ * @return void
+ */
+function mcp_log_request(array $req, $resp, float $tStart, string $rawInput): void
+{
+ global $db, $serviceUser;
+
+ $method = isset($req['method']) ? (string) $req['method'] : '';
+ if ($method !== 'tools/call' || !function_exists('ai_log_request')) {
+ return;
+ }
+
+ $params = isset($req['params']) && is_array($req['params']) ? $req['params'] : [];
+ $toolName = isset($params['name']) ? (string) $params['name'] : '';
+ $toolArgs = isset($params['arguments']) ? $params['arguments'] : [];
+
+ $argsJson = is_string($toolArgs) ? $toolArgs : (string) json_encode($toolArgs);
+ $query = '[MCP] ' . $toolName . ' ' . dol_substr($argsJson, 0, 1000);
+
+ $responseShape = ['tool' => $toolName, 'arguments' => $toolArgs];
+
+ $status = 'Success';
+ $errorMsg = '';
+ if (is_array($resp) && isset($resp['error'])) {
+ $status = 'Error';
+ $errorMsg = is_array($resp['error']) && isset($resp['error']['message'])
+ ? (string) $resp['error']['message']
+ : (string) json_encode($resp['error']);
+ } elseif (is_array($resp) && isset($resp['result']['isError']) && $resp['result']['isError']) {
+ $status = 'Error';
+ $errorMsg = is_array($resp['result']['content'] ?? null) ? (string) json_encode($resp['result']['content']) : '';
+ }
+
+ $rawResStr = is_string($resp) ? $resp : (string) json_encode($resp);
+
+ ai_log_request(
+ $db,
+ $serviceUser,
+ $query,
+ $responseShape,
+ 'mcp',
+ microtime(true) - $tStart,
+ 1.0,
+ $status,
+ $errorMsg,
+ $rawInput,
+ $rawResStr
+ );
+}
+
// Request handling
try {
+ $tStart = microtime(true);
+
// Basic payload size limit
$rawInput = file_get_contents('php://input');
if ($rawInput === false || strlen($rawInput) > 1024 * 1024) {
@@ -168,11 +247,15 @@ try {
continue;
}
+ $reqStart = microtime(true);
$res = $server->handleRequest($req);
if ($res !== null) {
$responses[] = $res;
}
+
+ // Log each tools/call separately so the admin log viewer shows them individually.
+ mcp_log_request($req, $res, $reqStart, (string) json_encode($req));
}
echo json_encode($responses);
@@ -187,6 +270,10 @@ try {
if ($response !== null) {
echo json_encode($response);
}
+
+ // Log this tools/call to llx_ai_request_log (no-op unless AI_LOG_REQUESTS is enabled
+ // and the method is tools/call).
+ mcp_log_request($request, $response, $tStart, $rawInput);
}
} catch (Exception $e) {
dol_syslog(
diff --git a/htdocs/ai/tools/crud_objects.class.php b/htdocs/ai/tools/crud_objects.class.php
index 7c57d92a11f..61933736148 100644
--- a/htdocs/ai/tools/crud_objects.class.php
+++ b/htdocs/ai/tools/crud_objects.class.php
@@ -196,6 +196,12 @@ If user says 'order' without any qualifier, they mean a SALES ORDER - use this t
"header" => [
"type" => "object",
"description" => "Invoice header data. Must include 'socid' (Customer ID).",
+ "properties" => [
+ "socid" => ["type" => "integer", "description" => "Customer ID (Thirdparty ID)"],
+ "date" => ["type" => "string", "description" => "Invoice date (YYYY-MM-DD)"],
+ "note_public" => ["type" => "string", "description" => "Public note"],
+ "note_private" => ["type" => "string", "description" => "Private note"]
+ ],
"required" => ["socid"]
],
"lines" => [
@@ -233,6 +239,13 @@ If user says 'order' without any qualifier, they mean a SALES ORDER - use this t
"header" => [
"type" => "object",
"description" => "Header data. Must include 'socid'.",
+ "properties" => [
+ "socid" => ["type" => "integer", "description" => "Thirdparty ID (Customer for proposal, Supplier for supplier_*)"],
+ "date" => ["type" => "string", "description" => "Document date (YYYY-MM-DD)"],
+ "duree_validite" => ["type" => "integer", "description" => "Validity in days (proposal only)"],
+ "note_public" => ["type" => "string", "description" => "Public note"],
+ "note_private" => ["type" => "string", "description" => "Private note"]
+ ],
"required" => ["socid"]
],
"lines" => [
@@ -539,8 +552,17 @@ If user says 'order' without any qualifier, they mean a SALES ORDER - use this t
if ($productIdentifier !== '') {
$findResult = $this->findProduct($productIdentifier);
if (is_array($findResult) && isset($findResult['error'])) {
- // Ensure the return array matches the expected shape by adding 'success' => false
- return array_merge(['success' => false], $findResult);
+ // Only abort if the caller EXPLICITLY asked for a product (via the 'product'
+ // argument). If they only provided a free-text 'description', we silently
+ // fall through with $prod = null so Dolibarr creates a free-text line item,
+ // which is a perfectly valid Dolibarr feature.
+ // Previous behaviour aborted ALL line creations whose description didn't
+ // match an existing product reference, which broke AI-driven creation of
+ // invoices/orders/proposals from one-off line descriptions.
+ if (isset($args['product'])) {
+ return array_merge(['success' => false], $findResult);
+ }
+ // fall through: $prod stays null
}
if (is_object($findResult)) {
$prod = $findResult;
@@ -599,7 +621,14 @@ If user says 'order' without any qualifier, they mean a SALES ORDER - use this t
$res = $object->addline($desc, $price, $qty, $vat, 0, 0, $fkProduct, $discount, 'HT', 0, 0, $prodType);
} elseif ($docType === 'supplier_invoice') {
/** @var FactureFournisseur $object */
- $res = $object->addline($desc, $price, $qty, $vat, 0, 0, $fkProduct, $discount, 0, 0, '', 0, 'HT', 0, $prodType);
+ // IMPORTANT: FactureFournisseur::addline() does NOT share the same signature
+ // as Facture::addline(). Its parameter order is:
+ // ($desc, $pu, $txtva, $txlocaltax1, $txlocaltax2, $qty, $fk_product, $remise_percent, ...)
+ // i.e. $qty is in position 6, not 3 (unlike customer Facture / Commande / Propal).
+ // The previous call passed our $qty as $txtva (-> a 1% VAT rate) and our $vat
+ // as $txlocaltax1, and position 6 ended up being a hardcoded 0 -> a line was
+ // inserted with qty=0, which Dolibarr silently dropped from the visible totals.
+ $res = $object->addline($desc, $price, $vat, 0, 0, $qty, $fkProduct, $discount, '', '', 0, 0, 'HT', $prodType);
} elseif ($docType === 'supplier_order') {
/** @var CommandeFournisseur $object */
$res = $object->addline($desc, $price, $qty, $vat, 0, 0, $fkProduct, $discount, 0, 0, 'HT', 0, '', '', $prodType);
diff --git a/htdocs/ai/tools/reports.class.php b/htdocs/ai/tools/reports.class.php
index f795579b795..738eb244866 100644
--- a/htdocs/ai/tools/reports.class.php
+++ b/htdocs/ai/tools/reports.class.php
@@ -230,77 +230,129 @@ class ToolReports extends McpTool
{
global $langs;
- $langs->loadLangs(array("main", "bills", "companies"));
+ $langs->loadLangs(array("main", "bills", "companies", "products"));
- $limit = isset($args['limit']) ? (int) $args['limit'] : 50;
+ $limit = isset($args['limit']) ? (int) $args['limit'] : 50;
$dateStart = dol_stringtotime($args['date_start']);
- $dateEnd = dol_stringtotime($args['date_end']);
- $socid = $this->resolveThirdparty($args);
-
- $sql = "SELECT f.rowid, f.ref, f.total_ttc, f.fk_statut, f.paye, f.datef, s.nom
- FROM " . MAIN_DB_PREFIX . "facture as f
- LEFT JOIN " . MAIN_DB_PREFIX . "societe as s ON f.fk_soc = s.rowid
- WHERE f.entity IN (" . getEntity('facture') . ")";
-
- $sql .= " AND f.datef >= '" . $this->db->idate($dateStart) . "'";
- $sql .= " AND f.datef <= '" . $this->db->idate($dateEnd) . "'";
+ $dateEnd = dol_stringtotime($args['date_end']);
+ $socid = $this->resolveThirdparty($args);
+ $groupBy = isset($args['group_by']) ? (string) $args['group_by'] : 'thirdparty';
+ $list = [];
+ $totalSum = 0.0;
// Status Filter: Valid (1) and Paid (2). Exclude Draft (0) and Abandoned (3).
- $sql .= " AND f.fk_statut IN (1, 2)";
+ $dateRange = " AND f.datef >= '" . $this->db->idate($dateStart)
+ . "' AND f.datef <= '" . $this->db->idate($dateEnd)
+ . "' AND f.fk_statut IN (1, 2)";
+ // CASE 1 -- Detailed list for a specific thirdparty.
if ($socid) {
- $sql .= " AND f.fk_soc = " . (int) $socid;
- }
+ $sql = "SELECT f.rowid, f.ref, f.total_ttc, f.fk_statut, f.paye, f.datef, s.nom FROM "
+ . MAIN_DB_PREFIX . "facture as f LEFT JOIN "
+ . MAIN_DB_PREFIX . "societe as s ON f.fk_soc = s.rowid WHERE f.entity IN ("
+ . getEntity('facture') . ")"
+ . $dateRange
+ . " AND f.fk_soc = " . (int) $socid
+ . " ORDER BY f.datef DESC LIMIT " . ((int) $limit);
- $sql .= " ORDER BY f.datef DESC LIMIT " . ((int) $limit);
+ $resql = $this->db->query($sql);
+ if ($resql) {
+ while ($r = $this->db->fetch_object($resql)) {
+ $totalSum += (float) $r->total_ttc;
- $resql = $this->db->query($sql);
- $list = [];
- $totalSum = 0.0;
+ $statusLabel = $langs->transnoentitiesnoconv("Unknown");
+ if ($r->fk_statut == 1 && $r->paye == 0) {
+ $statusLabel = $langs->transnoentitiesnoconv("BillStatusNotPaid");
+ } elseif ($r->fk_statut == 1 && $r->paye == 1) {
+ $statusLabel = $langs->transnoentitiesnoconv("BillStatusStarted");
+ } elseif ($r->fk_statut == 2) {
+ $statusLabel = $langs->transnoentitiesnoconv("BillStatusPaid");
+ }
- if ($resql) {
- while ($r = $this->db->fetch_object($resql)) {
- $totalSum += (float) $r->total_ttc;
+ $url = DOL_URL_ROOT . "/compta/facture/card.php?id=" . $r->rowid;
+ $refHtml = '' . $r->ref . '';
- // Determine Localized Status
- $statusLabel = $langs->transnoentitiesnoconv("Unknown");
- if ($r->fk_statut == 1 && $r->paye == 0) {
- $statusLabel = $langs->transnoentitiesnoconv("BillStatusNotPaid");
- } elseif ($r->fk_statut == 1 && $r->paye == 1) {
- $statusLabel = $langs->transnoentitiesnoconv("BillStatusStarted");
- } elseif ($r->fk_statut == 2) {
- $statusLabel = $langs->transnoentitiesnoconv("BillStatusPaid");
+ $list[] = [
+ $langs->transnoentitiesnoconv("Ref") => $refHtml,
+ $langs->transnoentitiesnoconv("Date") => dol_print_date($this->db->jdate($r->datef), 'day'),
+ $langs->transnoentitiesnoconv("Customer") => $r->nom,
+ $langs->transnoentitiesnoconv("Amount") => price($r->total_ttc),
+ $langs->transnoentitiesnoconv("Status") => $statusLabel
+ ];
}
-
- // Build relative URL
- $url = DOL_URL_ROOT . "/compta/facture/card.php?id=" . $r->rowid;
-
- // Make Ref clickable
- $refHtml = '' . $r->ref . '';
-
- $list[] = [
- $langs->transnoentitiesnoconv("Ref") => $refHtml,
- $langs->transnoentitiesnoconv("Date") => dol_print_date($this->db->jdate($r->datef), 'day'),
- $langs->transnoentitiesnoconv("Customer") => $r->nom,
- $langs->transnoentitiesnoconv("Amount") => price($r->total_ttc),
- $langs->transnoentitiesnoconv("Status") => $statusLabel
- ];
+ $this->db->free($resql);
+ }
+ } else {
+ // CASE 2 -- Global grouped report.
+ // Mirrors the pattern already used by getPurchaseReport(); previous implementation
+ // of getSalesReport() ignored $groupBy entirely and always returned a flat list.
+ $sanitizedSqlGroup = '';
+ $colName = '';
+ $sqlJoin = " LEFT JOIN " . MAIN_DB_PREFIX . "societe as s ON f.fk_soc = s.rowid";
+
+ if ($groupBy === 'month') {
+ $sanitizedSqlGroup = "DATE_FORMAT(f.datef, '%Y-%m')";
+ $colName = $langs->transnoentitiesnoconv("Month");
+ } elseif ($groupBy === 'product') {
+ // Aggregate on product line items. Lines without product_id fall back to their description.
+ $sanitizedSqlGroup = "COALESCE(p.ref, fd.description, '?')";
+ $colName = $langs->transnoentitiesnoconv("Product");
+ $sqlJoin .= " INNER JOIN " . MAIN_DB_PREFIX . "facturedet as fd ON fd.fk_facture = f.rowid LEFT JOIN "
+ . MAIN_DB_PREFIX . "product as p ON fd.fk_product = p.rowid";
+ } else {
+ // Default: group by customer
+ $sanitizedSqlGroup = "s.nom";
+ $colName = $langs->transnoentitiesnoconv("Customer");
+ }
+
+ // For product grouping we sum line totals (more accurate per-product);
+ // otherwise we sum the invoice total_ttc.
+ $amountExpr = ($groupBy === 'product') ? "SUM(fd.total_ttc)" : "SUM(f.total_ttc)";
+ $countExpr = ($groupBy === 'product') ? "COUNT(DISTINCT f.rowid)" : "COUNT(f.rowid)";
+
+ $sql = "SELECT " . $sanitizedSqlGroup . " as group_key, "
+ . $amountExpr . " as total_amount, "
+ . $countExpr . " as count_inv FROM "
+ . MAIN_DB_PREFIX . "facture as f"
+ . $sqlJoin
+ . " WHERE f.entity IN (" . getEntity('facture') . ")"
+ . $dateRange
+ . " GROUP BY group_key ORDER BY total_amount DESC LIMIT "
+ . ((int) max(1, $limit));
+
+ $resql = $this->db->query($sql);
+ if ($resql) {
+ while ($r = $this->db->fetch_object($resql)) {
+ $totalSum += (float) $r->total_amount;
+ $list[] = [
+ $colName => $r->group_key ? $r->group_key : $langs->transnoentitiesnoconv('Unknown'),
+ $langs->transnoentitiesnoconv("Number") => (int) $r->count_inv,
+ $langs->transnoentitiesnoconv("Amount") => price($r->total_amount)
+ ];
+ }
+ $this->db->free($resql);
}
- $this->db->free($resql);
}
if (empty($list)) {
return [[$langs->transnoentitiesnoconv("Info") => $langs->transnoentitiesnoconv("NoRecordFound")]];
}
- // Append Total Row
- $list[] = [
- $langs->transnoentitiesnoconv("Ref") => $langs->transnoentitiesnoconv("Total"),
- $langs->transnoentitiesnoconv("Date") => "",
- $langs->transnoentitiesnoconv("Customer") => "",
- $langs->transnoentitiesnoconv("Amount") => price($totalSum),
- $langs->transnoentitiesnoconv("Status") => ""
- ];
+ // Append Total Row (shape depends on detailed-vs-grouped path)
+ if ($socid) {
+ $list[] = [
+ $langs->transnoentitiesnoconv("Ref") => $langs->transnoentitiesnoconv("Total"),
+ $langs->transnoentitiesnoconv("Date") => "",
+ $langs->transnoentitiesnoconv("Customer") => "",
+ $langs->transnoentitiesnoconv("Amount") => price($totalSum),
+ $langs->transnoentitiesnoconv("Status") => ""
+ ];
+ } else {
+ $list[] = [
+ $langs->transnoentitiesnoconv("Total") => $langs->transnoentitiesnoconv("Total"),
+ $langs->transnoentitiesnoconv("Amount") => price($totalSum)
+ ];
+ }
return $list;
}
diff --git a/htdocs/ai/tools/thirdparty.class.php b/htdocs/ai/tools/thirdparty.class.php
index 2aea57b8137..2fa9541c612 100644
--- a/htdocs/ai/tools/thirdparty.class.php
+++ b/htdocs/ai/tools/thirdparty.class.php
@@ -72,8 +72,9 @@ class ToolThirdParty extends McpTool
"inputSchema" => [
"type" => "object",
"properties" => [
- "id" => ["type" => "integer", "required" => true]
- ]
+ "id" => ["type" => "integer", "description" => "The unique numerical ID of the thirdparty."]
+ ],
+ "required" => ["id"]
]
],
[
@@ -82,7 +83,7 @@ class ToolThirdParty extends McpTool
"inputSchema" => [
"type" => "object",
"properties" => [
- "name" => ["type" => "string", "description" => "Name of the thirdparty", "required" => true],
+ "name" => ["type" => "string", "description" => "Name of the thirdparty"],
"type" => ["type" => "string", "enum" => ["customer", "prospect", "supplier", "both", "none"], "default" => "customer", "description" => "Type of thirdparty. 'none' means not a customer or prospect."],
"email" => ["type" => "string", "description" => "Email address"],
"phone" => ["type" => "string", "description" => "Phone number"],
@@ -105,7 +106,7 @@ class ToolThirdParty extends McpTool
"inputSchema" => [
"type" => "object",
"properties" => [
- "id" => ["type" => "integer", "description" => "The ID of the thirdparty to update.", "required" => true],
+ "id" => ["type" => "integer", "description" => "The ID of the thirdparty to update."],
"name" => ["type" => "string", "description" => "The new name for the thirdparty."],
"email" => ["type" => "string", "description" => "The new email address."],
"phone" => ["type" => "string", "description" => "The new phone number."],
@@ -123,7 +124,7 @@ class ToolThirdParty extends McpTool
"inputSchema" => [
"type" => "object",
"properties" => [
- "id" => ["type" => "integer", "description" => "The ID of the thirdparty.", "required" => true]
+ "id" => ["type" => "integer", "description" => "The ID of the thirdparty."]
],
"required" => ["id"]
]
@@ -136,11 +137,10 @@ class ToolThirdParty extends McpTool
"properties" => [
"thirdparty_identifier" => [
"type" => ["string", "integer"],
- "description" => "The ID or name of the thirdparty to add the contact to.",
- "required" => true
+ "description" => "The ID or name of the thirdparty to add the contact to."
],
- "firstname" => ["type" => "string", "description" => "Contact's first name.", "required" => true],
- "lastname" => ["type" => "string", "description" => "Contact's last name.", "required" => true],
+ "firstname" => ["type" => "string", "description" => "Contact's first name."],
+ "lastname" => ["type" => "string", "description" => "Contact's last name."],
"email" => ["type" => "string", "description" => "Contact's email address."],
"phone" => ["type" => "string", "description" => "Contact's phone number."],
"role" => ["type" => "string", "description" => "Contact's role or position within the company."]
diff --git a/htdocs/asset/admin/asset_extrafields.php b/htdocs/asset/admin/asset_extrafields.php
index 5883ec96a91..2bd0658b338 100644
--- a/htdocs/asset/admin/asset_extrafields.php
+++ b/htdocs/asset/admin/asset_extrafields.php
@@ -40,7 +40,6 @@ require '../../main.inc.php';
*/
require_once DOL_DOCUMENT_ROOT.'/core/lib/asset.lib.php';
-require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
// Load translation files required by the page
$langs->loadLangs(array("assets", "admin", "companies"));
diff --git a/htdocs/asset/admin/assetmodel_extrafields.php b/htdocs/asset/admin/assetmodel_extrafields.php
index 6e0a320731f..57ae24740aa 100644
--- a/htdocs/asset/admin/assetmodel_extrafields.php
+++ b/htdocs/asset/admin/assetmodel_extrafields.php
@@ -40,7 +40,6 @@ require '../../main.inc.php';
*/
require_once DOL_DOCUMENT_ROOT.'/core/lib/asset.lib.php';
-require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
// Load translation files required by the page
$langs->loadLangs(array("assets", "admin", "companies"));
diff --git a/htdocs/bookcal/admin/availabilities_extrafields.php b/htdocs/bookcal/admin/availabilities_extrafields.php
index f72a1c04462..bcc14522aa0 100644
--- a/htdocs/bookcal/admin/availabilities_extrafields.php
+++ b/htdocs/bookcal/admin/availabilities_extrafields.php
@@ -37,7 +37,6 @@ require '../../main.inc.php';
* @var Translate $langs
* @var User $user
*/
-require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
require_once '../lib/bookcal.lib.php';
// Load translation files required by the page
diff --git a/htdocs/bookcal/admin/calendar_extrafields.php b/htdocs/bookcal/admin/calendar_extrafields.php
index 6a9c813ed67..3ee4bcc4eba 100644
--- a/htdocs/bookcal/admin/calendar_extrafields.php
+++ b/htdocs/bookcal/admin/calendar_extrafields.php
@@ -38,7 +38,6 @@ require '../../main.inc.php';
* @var Translate $langs
* @var User $user
*/
-require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
require_once '../lib/bookcal.lib.php';
// Load translation files required by the page
diff --git a/htdocs/comm/action/card.php b/htdocs/comm/action/card.php
index c1227aec42f..ccefebf0843 100644
--- a/htdocs/comm/action/card.php
+++ b/htdocs/comm/action/card.php
@@ -36,11 +36,11 @@ require '../../main.inc.php';
/**
* @var Conf $conf
* @var DoliDB $db
+ * @var ExtraFields $extrafields
* @var HookManager $hookmanager
* @var Translate $langs
* @var User $user
*/
-require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
@@ -131,7 +131,6 @@ $donotclearsession = GETPOST('donotclearsession') ? GETPOST('donotclearsession')
$object = new ActionComm($db);
$cactioncomm = new CActionComm($db);
$contact = new Contact($db);
-$extrafields = new ExtraFields($db);
$formfile = new FormFile($db);
$form = new Form($db);
@@ -420,11 +419,22 @@ if (empty($reshook) && $action == 'add' && $usercancreate) {
$elProp = getElementProperties(GETPOST("elementtype", 'alpha'));
$modulecodetouseforpermissioncheck = $elProp['module'];
// Keep permission check aligned with rights class aliases (see restrictedArea()).
- if ($modulecodetouseforpermissioncheck == 'productbatch') {
- $modulecodetouseforpermissioncheck = 'produit';
- }
$submodulecodetouseforpermissioncheck = $elProp['subelement'];
+ switch ($modulecodetouseforpermissioncheck) {
+ case 'productbatch':
+ $modulecodetouseforpermissioncheck = 'produit';
+ break;
+ case 'eventorganization':
+ // Event organization relies on Project permissions
+ $modulecodetouseforpermissioncheck = 'projet';
+ $submodulecodetouseforpermissioncheck = ''; // Project doesn't use submodules for read
+ break;
+ default:
+ // No mapping needed, keep original values
+ break;
+ }
+
$hasPermissionOnLinkedObject = 0;
if ($user->hasRight($modulecodetouseforpermissioncheck, 'read')) {
$hasPermissionOnLinkedObject = 1;
@@ -1001,8 +1011,20 @@ if (empty($reshook) && $action == 'update' && $usercancreate) {
$elProp = getElementProperties(GETPOST("elementtype", 'alpha'));
$modulecodetouseforpermissioncheck = $elProp['module'];
// Keep permission check aligned with rights class aliases (see restrictedArea()).
- if ($modulecodetouseforpermissioncheck == 'productbatch') {
- $modulecodetouseforpermissioncheck = 'produit';
+ $submodulecodetouseforpermissioncheck = $elProp['subelement'];
+
+ switch ($modulecodetouseforpermissioncheck) {
+ case 'productbatch':
+ $modulecodetouseforpermissioncheck = 'produit';
+ break;
+ case 'eventorganization':
+ // Event organization relies on Project permissions
+ $modulecodetouseforpermissioncheck = 'projet';
+ $submodulecodetouseforpermissioncheck = ''; // Project doesn't use submodules for read
+ break;
+ default:
+ // No mapping needed, keep original values
+ break;
}
$hasPermissionOnLinkedObject = 0;
@@ -1869,9 +1891,22 @@ if ($action == 'create') {
$elProp = getElementProperties($origin);
$modulecodetouseforpermissioncheck = $elProp['module'];
// Keep permission check aligned with rights class aliases (see restrictedArea()).
- if ($modulecodetouseforpermissioncheck == 'productbatch') {
- $modulecodetouseforpermissioncheck = 'produit';
+ $submodulecodetouseforpermissioncheck = $elProp['subelement'];
+
+ switch ($modulecodetouseforpermissioncheck) {
+ case 'productbatch':
+ $modulecodetouseforpermissioncheck = 'produit';
+ break;
+ case 'eventorganization':
+ // Event organization relies on Project permissions
+ $modulecodetouseforpermissioncheck = 'projet';
+ $submodulecodetouseforpermissioncheck = ''; // Project doesn't use submodules for read
+ break;
+ default:
+ // No mapping needed, keep original values
+ break;
}
+
if ($user->hasRight($modulecodetouseforpermissioncheck, 'read') || $user->hasRight($modulecodetouseforpermissioncheck, $elProp['element'], 'read')) {
$hasPermissionOnLinkedObject = 1;
}
diff --git a/htdocs/comm/action/list.php b/htdocs/comm/action/list.php
index 6e865812432..3e7e1bcb71d 100644
--- a/htdocs/comm/action/list.php
+++ b/htdocs/comm/action/list.php
@@ -4,7 +4,7 @@
* Copyright (C) 2004-2016 Laurent Destailleur
* Copyright (C) 2005-2012 Regis Houssin
* Copyright (C) 2017 Open-DSI
- * Copyright (C) 2018-2025 Frédéric France
+ * Copyright (C) 2018-2026 Frédéric France
* Copyright (C) 2020 Tobias Sekan
* Copyright (C) 2024-2025 MDW
* Copyright (C) 2024 Alexandre Spangaro
@@ -34,6 +34,7 @@ require '../../main.inc.php';
/**
* @var Conf $conf
* @var DoliDB $db
+ * @var ExtraFields $extrafields
* @var HookManager $hookmanager
* @var Translate $langs
* @var User $user
@@ -42,9 +43,8 @@ require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/agenda.lib.php';
-require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
-include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
-include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
+require_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
+require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
// Load translation files required by the page
$langs->loadLangs(array("users", "companies", "agenda", "commercial", "other", "orders", "bills"));
@@ -123,8 +123,6 @@ $search_categ_cus = GETPOST("search_categ_cus", "intcomma", 3) ? GETPOST("search
$object = new ActionComm($db);
$hookmanager->initHooks(array('agendalist'));
-$extrafields = new ExtraFields($db);
-
// fetch optionals attributes and labels
$extrafields->fetch_name_optionals_label($object->table_element);
diff --git a/htdocs/comm/admin/propal_extrafields.php b/htdocs/comm/admin/propal_extrafields.php
index acc54325a48..7bc2b8c2810 100644
--- a/htdocs/comm/admin/propal_extrafields.php
+++ b/htdocs/comm/admin/propal_extrafields.php
@@ -3,7 +3,7 @@
* Copyright (C) 2003 Jean-Louis Bergamo
* Copyright (C) 2004-2011 Laurent Destailleur
* Copyright (C) 2012 Regis Houssin
- * Copyright (C) 2024 Frédéric France
+ * Copyright (C) 2024-2026 Frédéric France
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -27,21 +27,19 @@
// Load Dolibarr environment
require '../../main.inc.php';
-require_once DOL_DOCUMENT_ROOT.'/core/lib/propal.lib.php';
-require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
-
/**
* @var Conf $conf
* @var DoliDB $db
+ * @var ExtraFields $extrafields
* @var HookManager $hookmanager
* @var Translate $langs
* @var User $user
*/
+require_once DOL_DOCUMENT_ROOT.'/core/lib/propal.lib.php';
// Load translation files required by the page
$langs->loadLangs(array('companies', 'admin', 'propal'));
-$extrafields = new ExtraFields($db);
$form = new Form($db);
// List of supported format
@@ -63,7 +61,6 @@ if (!$user->admin) {
require DOL_DOCUMENT_ROOT.'/core/actions_extrafields.inc.php';
-
/*
* View
*/
diff --git a/htdocs/comm/admin/propaldet_extrafields.php b/htdocs/comm/admin/propaldet_extrafields.php
index 5f939d6edce..4f4463de61e 100644
--- a/htdocs/comm/admin/propaldet_extrafields.php
+++ b/htdocs/comm/admin/propaldet_extrafields.php
@@ -6,7 +6,7 @@
* Copyright (C) 2012 Florian Henry
* Copyright (C) 2013 Philippe Grand
* Copyright (C) 2013 Florian Henry
- * Copyright (C) 2024 Frédéric France
+ * Copyright (C) 2024-2026 Frédéric France
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -30,21 +30,19 @@
// Load Dolibarr environment
require '../../main.inc.php';
-require_once DOL_DOCUMENT_ROOT.'/core/lib/propal.lib.php';
-require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
-
/**
* @var Conf $conf
* @var DoliDB $db
+ * @var ExtraFields $extrafields
* @var HookManager $hookmanager
* @var Translate $langs
* @var User $user
*/
+require_once DOL_DOCUMENT_ROOT.'/core/lib/propal.lib.php';
// Load translation files required by the page
$langs->loadlangs(array('admin', 'other', 'propal'));
-$extrafields = new ExtraFields($db);
$form = new Form($db);
// List of supported format
diff --git a/htdocs/comm/card.php b/htdocs/comm/card.php
index 0969aeab7da..c22610350f9 100644
--- a/htdocs/comm/card.php
+++ b/htdocs/comm/card.php
@@ -7,7 +7,7 @@
* Copyright (C) 2008 Raphael Bertrand (Resultic)
* Copyright (C) 2010-2020 Juanjo Menent
* Copyright (C) 2013-2024 Alexandre Spangaro
- * Copyright (C) 2021-2025 Frédéric France
+ * Copyright (C) 2021-2026 Frédéric France
* Copyright (C) 2015 Marcos García
* Copyright (C) 2020 Open-Dsi
* Copyright (C) 2022 Anthony Berton
@@ -38,6 +38,7 @@ require '../main.inc.php';
/**
* @var Conf $conf
* @var DoliDB $db
+ * @var ExtraFields $extrafields
* @var HookManager $hookmanager
* @var Societe $mysoc
* @var Translate $langs
@@ -128,7 +129,6 @@ if (!$sortfield) {
$cancel = GETPOST('cancel', 'alpha');
$object = new Client($db);
-$extrafields = new ExtraFields($db);
$formfile = new FormFile($db);
// fetch optionals attributes and labels
diff --git a/htdocs/comm/mailing/advtargetemailing.php b/htdocs/comm/mailing/advtargetemailing.php
index 53f9006a026..48b5b839c0d 100644
--- a/htdocs/comm/mailing/advtargetemailing.php
+++ b/htdocs/comm/mailing/advtargetemailing.php
@@ -2,7 +2,7 @@
/* Copyright (C) 2014 Florian Henry
* Copyright (C) 2016 Laurent Destailleur
* Copyright (C) 2024 MDW
- * Copyright (C) 2024 Frédéric France
+ * Copyright (C) 2024-2026 Frédéric France
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -27,6 +27,14 @@
// Load Dolibarr environment
require '../../main.inc.php';
+/**
+ * @var Conf $conf
+ * @var DoliDB $db
+ * @var ExtraFields $extrafields
+ * @var HookManager $hookmanager
+ * @var Translate $langs
+ * @var User $user
+ */
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formmailing.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
@@ -39,14 +47,6 @@ require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
-/**
- * @var Conf $conf
- * @var DoliDB $db
- * @var HookManager $hookmanager
- * @var Translate $langs
- * @var User $user
- */
-
// Load translation files required by the page
$langs->loadLangs(array('mails', 'admin', 'companies', 'categories'));
@@ -895,8 +895,6 @@ if ($object->fetch($id) >= 0) {
$socstatic = new Societe($db);
$elementtype = $socstatic->table_element;
// fetch optionals attributes and labels
- require_once DOL_DOCUMENT_ROOT . '/core/class/extrafields.class.php';
- $extrafields = new ExtraFields($db);
$extrafields->fetch_name_optionals_label($elementtype);
foreach ($extrafields->attributes[$elementtype]['label'] as $key => $val) {
if ($key != 'ts_nameextra' && $key != 'ts_payeur') {
@@ -1086,8 +1084,6 @@ if ($object->fetch($id) >= 0) {
$contactstatic = new Contact($db);
$elementype = $contactstatic->table_element;
// fetch optionals attributes and labels
- dol_include_once('/core/class/extrafields.class.php');
- $extrafields = new ExtraFields($db);
$extrafields->fetch_name_optionals_label($elementype);
if (!empty($extrafields->attributes[$elementtype]['type'])) {
foreach ($extrafields->attributes[$elementtype]['type'] as $key => &$value) {
diff --git a/htdocs/comm/mailing/card.php b/htdocs/comm/mailing/card.php
index c1f742c2ab3..90c6cad64d8 100644
--- a/htdocs/comm/mailing/card.php
+++ b/htdocs/comm/mailing/card.php
@@ -5,7 +5,7 @@
* Copyright (C) 2021 Waël Almoman
* Copyright (C) 2024-2025 MDW
* Copyright (C) 2025 Jon Bendtsen
- * Copyright (C) 2024-2025 Frédéric France
+ * Copyright (C) 2024-2026 Frédéric France
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -36,6 +36,7 @@ require '../../main.inc.php';
/**
* @var Conf $conf
* @var DoliDB $db
+ * @var ExtraFields $extrafields
* @var HookManager $hookmanager
* @var Translate $langs
* @var User $user
@@ -49,7 +50,6 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
require_once DOL_DOCUMENT_ROOT.'/comm/mailing/class/mailing.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
-require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
if (isModEnabled('project')) {
require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
require_once DOL_DOCUMENT_ROOT . '/core/class/html.formprojet.class.php';
@@ -70,7 +70,6 @@ $backtopageforcancel = GETPOST('backtopageforcancel');
// Initialize a technical objects
$object = new Mailing($db);
-$extrafields = new ExtraFields($db);
$hookmanager->initHooks(array('mailingcard', 'globalcard'));
// Fetch optionals attributes and labels
diff --git a/htdocs/comm/mailing/list.php b/htdocs/comm/mailing/list.php
index 9bc73290dac..6cfe5abf85a 100644
--- a/htdocs/comm/mailing/list.php
+++ b/htdocs/comm/mailing/list.php
@@ -3,8 +3,8 @@
* Copyright (C) 2005-2010 Regis Houssin
* Copyright (C) 2024 MDW
* Copyright (C) 2024 Alexandre Spangaro
- * Copyright (C) 2024 Frédéric France
- * Copyright (C) 2025 Jon Bendtsen
+ * Copyright (C) 2024-2026 Frédéric France
+ * Copyright (C) 2025 Jon Bendtsen
* Copyright (C) 2025 Josep Lluís Amador Teruel
*
* This program is free software; you can redistribute it and/or modify
@@ -32,6 +32,7 @@ require '../../main.inc.php';
/**
* @var Conf $conf
* @var DoliDB $db
+ * @var ExtraFields $extrafields
* @var HookManager $hookmanager
* @var Translate $langs
* @var User $user
@@ -82,7 +83,6 @@ $search_project = GETPOST('search_project', 'alpha');
// Initialize a technical objects
$object = new Mailing($db);
-$extrafields = new ExtraFields($db);
if ($projectid > 0) {
$hookmanager->initHooks(array('projectmailing', 'globalcard'));
} else {
diff --git a/htdocs/comm/mailing/note.php b/htdocs/comm/mailing/note.php
index b72bd4b87aa..ee87315edc3 100644
--- a/htdocs/comm/mailing/note.php
+++ b/htdocs/comm/mailing/note.php
@@ -1,6 +1,6 @@
- * Copyright (C) 2024-2025 Frédéric France
+ * Copyright (C) 2024-2026 Frédéric France
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,17 +24,16 @@
// Load Dolibarr environment
require '../../main.inc.php';
-
-require_once DOL_DOCUMENT_ROOT.'/comm/mailing/class/mailing.class.php';
-require_once DOL_DOCUMENT_ROOT.'/core/lib/emailing.lib.php';
-
/**
* @var Conf $conf
* @var DoliDB $db
+ * @var ExtraFields $extrafields
* @var HookManager $hookmanager
* @var Translate $langs
* @var User $user
*/
+require_once DOL_DOCUMENT_ROOT.'/comm/mailing/class/mailing.class.php';
+require_once DOL_DOCUMENT_ROOT.'/core/lib/emailing.lib.php';
// Load translation files required by the page
$langs->loadLangs(array("mails", "mailing", "companies"));
@@ -48,7 +47,6 @@ $backtopage = GETPOST('backtopage', 'alpha');
// Initialize a technical objects
$object = new Mailing($db);
-$extrafields = new ExtraFields($db);
$diroutputmassaction = $conf->mailing->dir_output.'/temp/massgeneration/'.$user->id;
$hookmanager->initHooks(array('mailingnote', 'globalcard')); // Note that conf->hooks_modules contains array
// Fetch optionals attributes and labels
diff --git a/htdocs/comm/propal/card.php b/htdocs/comm/propal/card.php
index 05f06514944..f98dcb8f0ec 100644
--- a/htdocs/comm/propal/card.php
+++ b/htdocs/comm/propal/card.php
@@ -45,6 +45,15 @@
// Load Dolibarr environment
require '../../main.inc.php';
+/**
+ * @var Conf $conf
+ * @var DoliDB $db
+ * @var ExtraFields $extrafields
+ * @var HookManager $hookmanager
+ * @var Societe $mysoc
+ * @var Translate $langs
+ * @var User $user
+ */
require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
require_once DOL_DOCUMENT_ROOT . '/core/class/html.formother.class.php';
require_once DOL_DOCUMENT_ROOT . '/core/class/html.formfile.class.php';
@@ -66,14 +75,6 @@ if (isModEnabled('variants')) {
require_once DOL_DOCUMENT_ROOT . '/variants/class/ProductCombination.class.php';
}
-/**
- * @var Conf $conf
- * @var DoliDB $db
- * @var HookManager $hookmanager
- * @var Societe $mysoc
- * @var Translate $langs
- * @var User $user
- */
// Load translation files required by the page
$langs->loadLangs(array('companies', 'propal', 'compta', 'bills', 'orders', 'products', 'sendings', 'other'));
@@ -109,7 +110,6 @@ $hidedesc = (GETPOSTINT('hidedesc') ? GETPOSTINT('hidedesc') : (getDolGlobalStri
$hideref = (GETPOSTINT('hideref') ? GETPOSTINT('hideref') : (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_REF') ? 1 : 0));
$object = new Propal($db);
-$extrafields = new ExtraFields($db);
// fetch optionals attributes and labels
$extrafields->fetch_name_optionals_label($object->table_element);
diff --git a/htdocs/commande/index.php b/htdocs/commande/index.php
index 036f898424d..cf33b2d22a5 100644
--- a/htdocs/commande/index.php
+++ b/htdocs/commande/index.php
@@ -3,7 +3,7 @@
* Copyright (C) 2004-2011 Laurent Destailleur
* Copyright (C) 2005-2012 Regis Houssin
* Copyright (C) 2019 Nicolas ZABOURI
- * Copyright (C) 2019-2024 Frédéric France
+ * Copyright (C) 2019-2026 Frédéric France
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -28,12 +28,6 @@
// Load Dolibarr environment
require '../main.inc.php';
-require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
-require_once DOL_DOCUMENT_ROOT.'/core/class/notify.class.php';
-require_once DOL_DOCUMENT_ROOT.'/societe/class/client.class.php';
-require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
-require_once DOL_DOCUMENT_ROOT.'/core/lib/order.lib.php';
-
/**
* @var Conf $conf
* @var DoliDB $db
@@ -41,6 +35,12 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/order.lib.php';
* @var Translate $langs
* @var User $user
*/
+require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
+require_once DOL_DOCUMENT_ROOT.'/core/class/notify.class.php';
+require_once DOL_DOCUMENT_ROOT.'/societe/class/client.class.php';
+require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
+require_once DOL_DOCUMENT_ROOT.'/core/lib/order.lib.php';
+
// Load translation files required by the page
$langs->loadLangs(array('orders', 'bills'));
@@ -50,8 +50,6 @@ if (!$user->hasRight('commande', 'lire')) {
accessforbidden();
}
-$hookmanager = new HookManager($db);
-
// Initialize a technical object to manage hooks. Note that conf->hooks_modules contains array
$hookmanager->initHooks(array('ordersindex'));
diff --git a/htdocs/compta/bank/class/paymentvarious.class.php b/htdocs/compta/bank/class/paymentvarious.class.php
index 5bdf7139c9d..e25edb535d7 100644
--- a/htdocs/compta/bank/class/paymentvarious.class.php
+++ b/htdocs/compta/bank/class/paymentvarious.class.php
@@ -1,7 +1,8 @@
- * Copyright (C) 2018-2025 Frédéric France
- * Copyright (C) 2024-2026 MDW
+/* Copyright (C) 2017-2021 Alexandre Spangaro
+ * Copyright (C) 2018-2025 Frédéric France
+ * Copyright (C) 2024-2026 MDW
+ * Copyright (C) 2026 Solution Libre SAS
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -272,7 +273,13 @@ class PaymentVarious extends CommonObject
return -1;
}
- if (!$notrigger) {
+ // Actions on extra fields
+ $result = $this->insertExtraFields();
+ if ($result < 0) {
+ $error++;
+ }
+
+ if (!$error && !$notrigger) {
// Call trigger
$result = $this->call_trigger('PAYMENT_VARIOUS_MODIFY', $user);
if ($result < 0) {
@@ -354,6 +361,10 @@ class PaymentVarious extends CommonObject
$this->rappro = $obj->rappro;
$this->bank_num_releve = $obj->bank_num_releve;
}
+
+ // Fetch extrafields
+ $this->fetch_optionals();
+
$this->db->free($resql);
return 1;
@@ -533,6 +544,12 @@ class PaymentVarious extends CommonObject
$this->ref = (string) $this->id;
if ($this->id > 0) {
+ // Insert extrafields
+ $result = $this->insertExtraFields();
+ if ($result < 0) {
+ $error++;
+ }
+
if (isModEnabled("bank") && !empty($this->amount)) {
// Insert into llx_bank
require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php';
diff --git a/htdocs/compta/bank/line.php b/htdocs/compta/bank/line.php
index 42eba27e714..332e4dbcffd 100644
--- a/htdocs/compta/bank/line.php
+++ b/htdocs/compta/bank/line.php
@@ -7,7 +7,7 @@
* Copyright (C) 2015-2026 Alexandre Spangaro
* Copyright (C) 2015 Jean-François Ferry
* Copyright (C) 2016 Marcos García
- * Copyright (C) 2018-2025 Frédéric France
+ * Copyright (C) 2018-2026 Frédéric France
* Copyright (C) 2021 Gauthier VERDOL
* Copyright (C) 2024-2026 MDW
*
@@ -36,6 +36,7 @@ require '../../main.inc.php';
/**
* @var Conf $conf
* @var DoliDB $db
+ * @var ExtraFields $extrafields
* @var HookManager $hookmanager
* @var Translate $langs
* @var User $user
@@ -90,7 +91,6 @@ if (!$user->hasRight('banque', 'lire') && !$user->hasRight('banque', 'consolidat
}
$object = new AccountLine($db);
-$extrafields = new ExtraFields($db);
$extrafields->fetch_name_optionals_label($object->element);
if ($id > 0) {
diff --git a/htdocs/compta/bank/various_payment/card.php b/htdocs/compta/bank/various_payment/card.php
index b1414c13568..7b86b7b6984 100644
--- a/htdocs/compta/bank/various_payment/card.php
+++ b/htdocs/compta/bank/various_payment/card.php
@@ -1,9 +1,10 @@
- * Copyright (C) 2018-2025 Frédéric France
- * Copyright (C) 2023 Laurent Destailleur
- * Copyright (C) 2023 Joachim Kueter
- * Copyright (C) 2024-2025 MDW
+/* Copyright (C) 2017-2026 Alexandre Spangaro
+ * Copyright (C) 2018-2025 Frédéric France
+ * Copyright (C) 2023 Laurent Destailleur
+ * Copyright (C) 2023 Joachim Kueter
+ * Copyright (C) 2024-2025 MDW
+ * Copyright (C) 2026 Solution Libre SAS
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -27,18 +28,6 @@
// Load Dolibarr environment
require '../../../main.inc.php';
-require_once DOL_DOCUMENT_ROOT.'/core/lib/bank.lib.php';
-require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
-require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php';
-require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/paymentvarious.class.php';
-require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php';
-require_once DOL_DOCUMENT_ROOT.'/core/class/html.formaccounting.class.php';
-require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingaccount.class.php';
-require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingjournal.class.php';
-if (isModEnabled('project')) {
- require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
- require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
-}
/**
* @var Conf $conf
@@ -48,6 +37,20 @@ if (isModEnabled('project')) {
* @var User $user
*/
+require_once DOL_DOCUMENT_ROOT.'/core/lib/bank.lib.php';
+require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
+require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php';
+require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/paymentvarious.class.php';
+require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php';
+require_once DOL_DOCUMENT_ROOT.'/core/class/html.formaccounting.class.php';
+require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingaccount.class.php';
+require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingjournal.class.php';
+require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
+if (isModEnabled('project')) {
+ require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
+ require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
+}
+
// Load translation files required by the page
$langs->loadLangs(array("accountancy", "banks", "bills", "categories", "compta", "users"));
@@ -84,6 +87,9 @@ $result = restrictedArea($user, 'banque', '', '', '');
$object = new PaymentVarious($db);
+$extrafields = new ExtraFields($db);
+$extrafields->fetch_name_optionals_label($object->table_element);
+
$permissiontoadd = $user->hasRight('banque', 'modifier');
$permissiontodelete = $user->hasRight('banque', 'modifier');
@@ -148,6 +154,12 @@ if (empty($reshook)) {
$object->sens = GETPOSTINT('sens');
$object->fk_project = GETPOSTINT('fk_project');
+ // Fill array 'array_options' with data from add form
+ $ret = $extrafields->setOptionalsFromPost(null, $object);
+ if ($ret < 0) {
+ $error++;
+ }
+
if (!checkGeneralAccountAllowsAuxiliary($db, $object->accountancy_code, $object->subledger_account)) {
setEventMessages($langs->trans("ErrorAccountNotCentralized"). ". " . $langs->trans("RemoveSubsidiaryAccountOrAdjustTheGeneralAccount"), null, 'errors');
$error++;
@@ -538,6 +550,8 @@ if ($action == 'create') {
}
// Other attributes
+ print $object->showOptionals($extrafields, 'create');
+
$parameters = array();
$reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
print $hookmanager->resPrint;
diff --git a/htdocs/compta/bank/various_payment/list.php b/htdocs/compta/bank/various_payment/list.php
index 492b35b55b1..23397c5ca4c 100644
--- a/htdocs/compta/bank/various_payment/list.php
+++ b/htdocs/compta/bank/various_payment/list.php
@@ -1,9 +1,10 @@
- * Copyright (C) 2017 Laurent Destailleur
- * Copyright (C) 2018-2024 Frédéric France
- * Copyright (C) 2020 Tobias Sekan
- * Copyright (C) 2024-2025 MDW
+/* Copyright (C) 2017-2026 Alexandre Spangaro
+ * Copyright (C) 2017 Laurent Destailleur
+ * Copyright (C) 2018-2024 Frédéric France
+ * Copyright (C) 2020 Tobias Sekan
+ * Copyright (C) 2024-2025 MDW
+ * Copyright (C) 2026 Solution Libre SAS
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -27,6 +28,15 @@
// Load Dolibarr environment
require '../../../main.inc.php';
+
+/**
+ * @var Conf $conf
+ * @var DoliDB $db
+ * @var HookManager $hookmanager
+ * @var Translate $langs
+ * @var User $user
+ */
+
require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/paymentvarious.class.php';
require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formaccounting.class.php';
@@ -37,14 +47,6 @@ if (isModEnabled('project')) {
require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
}
-/**
- * @var Conf $conf
- * @var DoliDB $db
- * @var HookManager $hookmanager
- * @var Translate $langs
- * @var User $user
- */
-
// Load translation files required by the page
$langs->loadLangs(array("compta", "banks", "bills", "accountancy"));
@@ -183,6 +185,9 @@ $arrayfields = array(
'credit' => array('label' => "Credit", 'checked' => '1', 'position' => 510),
);
+// Extra fields
+include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_array_fields.tpl.php';
+
$arrayfields = dol_sort_array($arrayfields, 'position');
// Security check
@@ -266,9 +271,19 @@ $sql = "SELECT v.rowid, v.sens, v.amount, v.label, v.datep as datep, v.datev as
$sql .= " ba.rowid as bid, ba.ref as bref, ba.number as bnumber, ba.account_number as bank_account_number, ba.fk_accountancy_journal as accountancy_journal, ba.label as blabel,";
$sql .= " pst.code as payment_code";
+// Add fields from extrafields
+if (!empty($extrafields->attributes[$object->table_element]['label'])) {
+ foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) {
+ $sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? ", ef.".$key." as options_".$key : '');
+ }
+}
+
$sqlfields = $sql; // $sql fields to remove for count total
$sql .= " FROM ".MAIN_DB_PREFIX."payment_various as v";
+if (!empty($extrafields->attributes[$object->table_element]['label']) && is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label'])) {
+ $sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$object->table_element."_extrafields as ef on (v.rowid = ef.fk_object)";
+}
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_paiement as pst ON v.fk_typepayment = pst.id";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."bank as b ON v.fk_bank = b.rowid";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."bank_account as ba ON b.fk_account = ba.rowid";
@@ -600,6 +615,9 @@ if ($arrayfields['credit']['checked']) {
print '';
}
+// Extra fields
+include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_input.tpl.php';
+
if (!$conf->main_checkbox_left_column) {
print '| ';
$searchpicto = $form->showFilterButtons();
@@ -893,6 +911,9 @@ while ($i < $imaxinloop) {
print ' | ';
}
+ // Extra fields
+ include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php';
+
if (!$conf->main_checkbox_left_column) {
print ' | ';
if (!$i) {
diff --git a/htdocs/compta/cashcontrol/cashcontrol_list.php b/htdocs/compta/cashcontrol/cashcontrol_list.php
index d2711e022b1..3429ccf7c4e 100644
--- a/htdocs/compta/cashcontrol/cashcontrol_list.php
+++ b/htdocs/compta/cashcontrol/cashcontrol_list.php
@@ -1,6 +1,6 @@
- * Copyright (C) 2024 Frédéric France
+ * Copyright (C) 2024-2026 Frédéric France
* Copyright (C) 2025-2026 MDW
*
* This program is free software; you can redistribute it and/or modify
@@ -28,6 +28,7 @@ require '../../main.inc.php';
/**
* @var Conf $conf
* @var DoliDB $db
+ * @var ExtraFields $extrafields
* @var HookManager $hookmanager
* @var Translate $langs
* @var User $user
@@ -73,7 +74,6 @@ $pagenext = $page + 1;
// Initialize a technical objects
$object = new CashControl($db);
-$extrafields = new ExtraFields($db);
//$diroutputmassaction = $conf->mymodule->dir_output.'/temp/massgeneration/'.$user->id;
$hookmanager->initHooks(array($contextpage)); // Note that conf->hooks_modules contains array
diff --git a/htdocs/compta/facture/card-rec.php b/htdocs/compta/facture/card-rec.php
index 9b57b35208e..85fcd2585db 100644
--- a/htdocs/compta/facture/card-rec.php
+++ b/htdocs/compta/facture/card-rec.php
@@ -52,7 +52,6 @@ if (isModEnabled('project')) {
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/invoice.lib.php';
-require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
// Load translation files required by the page
$langs->loadLangs(array('bills', 'companies', 'compta', 'admin', 'other', 'products', 'banks'));
diff --git a/htdocs/contact/agenda.php b/htdocs/contact/agenda.php
index 35e64572768..81660b7b294 100644
--- a/htdocs/contact/agenda.php
+++ b/htdocs/contact/agenda.php
@@ -8,7 +8,7 @@
* Copyright (C) 2013-2024 Alexandre Spangaro
* Copyright (C) 2014 Juanjo Menent
* Copyright (C) 2015 Jean-François Ferry
- * Copyright (C) 2024-2025 Frédéric France
+ * Copyright (C) 2024-2026 Frédéric France
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -35,6 +35,7 @@ require '../main.inc.php';
/**
* @var Conf $conf
* @var DoliDB $db
+ * @var ExtraFields $extrafields
* @var HookManager $hookmanager
* @var Translate $langs
* @var User $user
@@ -46,7 +47,6 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php';
-require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
@@ -61,8 +61,8 @@ $error = 0;
$errors = array();
// Get parameters
-$action = (GETPOST('action', 'alpha') ? GETPOST('action', 'alpha') : 'view');
-$confirm = GETPOST('confirm', 'alpha');
+$action = (GETPOST('action', 'alpha') ? GETPOST('action', 'alpha') : 'view');
+$confirm = GETPOST('confirm', 'alpha');
$backtopage = GETPOST('backtopage', 'alpha');
$contextpage = GETPOST('contextpage', 'aZ09');
@@ -71,7 +71,6 @@ $socid = GETPOSTINT('socid');
// Initialize objects
$object = new Contact($db);
-$extrafields = new ExtraFields($db);
// fetch optionals attributes and labels
$extrafields->fetch_name_optionals_label($object->table_element);
diff --git a/htdocs/contact/card.php b/htdocs/contact/card.php
index 9f30549754b..d45ffa78563 100644
--- a/htdocs/contact/card.php
+++ b/htdocs/contact/card.php
@@ -8,7 +8,7 @@
* Copyright (C) 2013-2024 Alexandre Spangaro
* Copyright (C) 2014 Juanjo Menent
* Copyright (C) 2015 Jean-François Ferry
- * Copyright (C) 2018-2025 Frédéric France
+ * Copyright (C) 2018-2026 Frédéric France
* Copyright (C) 2019 Josep Lluís Amador
* Copyright (C) 2020-2026 Open-Dsi
* Copyright (C) 2024-2026 MDW
@@ -36,6 +36,15 @@
// Load Dolibarr environment
require '../main.inc.php';
+/**
+ * @var Conf $conf
+ * @var DoliDB $db
+ * @var ExtraFields $extrafields
+ * @var HookManager $hookmanager
+ * @var Societe $mysoc
+ * @var Translate $langs
+ * @var User $user
+ */
require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/contact.lib.php';
@@ -44,21 +53,11 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formadmin.class.php';
-require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
-/**
- * @var Conf $conf
- * @var DoliDB $db
- * @var HookManager $hookmanager
- * @var Societe $mysoc
- * @var Translate $langs
- * @var User $user
- */
-
// Load translation files required by the page
$langs->loadLangs(array('companies', 'users', 'other', 'commercial'));
@@ -75,7 +74,6 @@ $socid = GETPOSTINT('socid');
// Initialize a technical object
$object = new Contact($db);
-$extrafields = new ExtraFields($db);
// fetch optionals attributes and labels
$extrafields->fetch_name_optionals_label($object->table_element);
diff --git a/htdocs/contrat/card.php b/htdocs/contrat/card.php
index 7c384facac1..6d7325eb85f 100644
--- a/htdocs/contrat/card.php
+++ b/htdocs/contrat/card.php
@@ -9,11 +9,11 @@
* Copyright (C) 2014-2020 Ferran Marcet
* Copyright (C) 2014-2016 Marcos García
* Copyright (C) 2015 Jean-François Ferry
- * Copyright (C) 2018-2026 Frédéric France
- * Copyright (C) 2023 Charlene Benke
+ * Copyright (C) 2018-2026 Frédéric France
+ * Copyright (C) 2023-2026 Charlene Benke
* Copyright (C) 2023 Nick Fragoulis
* Copyright (C) 2024-2025 MDW
- * Copyright (C) 2024 Alexandre Spangaro
+ * Copyright (C) 2024-2026 Alexandre Spangaro
* Copyright (C) 2025 William Mead
*
* This program is free software; you can redistribute it and/or modify
@@ -1138,6 +1138,7 @@ llxHeader('', $title, $help_url, '', 0, 0, '', '', '', 'mod-contrat page-card');
$form = new Form($db);
$formfile = new FormFile($db);
+$staticcontractline = new ContratLigne($db);
if (isModEnabled('project')) {
$formproject = new FormProjets($db);
}
@@ -1525,10 +1526,10 @@ if ($action == 'create') {
print '';
+ print '
';
print '
';
-
- print '
';
+ print '';
// Line info of thirdparty discounts
print '| '.$langs->trans('Discount').' | ';
@@ -1560,6 +1561,86 @@ if ($action == 'create') {
print " |
";
print '';
+ print '';
+
+ print ''."\n";
+ print '
';
+
+ print '
';
+
+ // Qty by service status
+ print '| '."".' | ';
+ print ''.$langs->trans('Total').' | ';
+ print ''.$staticcontractline->LibStatut(0, 5, 0).' | ';
+ print ''.$staticcontractline->LibStatut(4, 5, 0).' | ';
+ print ''.$staticcontractline->LibStatut(4, 5, 1).' | ';
+ print ''.$staticcontractline->LibStatut(5, 5, 0).' | ';
+ print '
';
+
+ $all= $object->getTotalizedLines(-1, 0);
+ $draft= $object->getTotalizedLines(0, 0);
+ $enabled= $object->getTotalizedLines(4, 0);
+ $expired= $object->getTotalizedLines(4, 1);
+ $close= $object->getTotalizedLines(5, 0);
+
+ print '| '.$langs->trans("Qty").' | ';
+ print ''.price2num($all['total_qty']).' | ';
+ print ''.price2num($draft['total_qty']).' | ';
+ print ''.price2num($enabled['total_qty']).' | ';
+ print ''.price2num($expired['total_qty']).' | ';
+ print ''.price2num($close['total_qty']).' | ';
+ print '
';
+
+ print '| '.$langs->trans("TotalHT").' | ';
+ print ''.price($all['total_ht']).' | ';
+ print ''.price($draft['total_ht']).' | ';
+ print ''.price($enabled['total_ht']).' | ';
+ print ''.price($expired['total_ht']).' | ';
+ print ''.price($close['total_ht']).' | ';
+ print '
';
+
+ print '| '.$langs->trans("TotalVAT").' | ';
+ print ''.price($all['total_tva']).' | ';
+ print ''.price($draft['total_tva']).' | ';
+ print ''.price($enabled['total_tva']).' | ';
+ print ''.price($expired['total_tva']).' | ';
+ print ''.price($close['total_tva']).' | ';
+ print '
';
+
+ if ($mysoc->localtax1_assuj == "1" || $all['total_localtax1'] != 0) {
+ print '| ' . $langs->trans("TotalLT1") . ' | ';
+ print '' . price($all['total_localtax1']) . ' | ';
+ print '' . price($draft['total_localtax1']) . ' | ';
+ print '' . price($enabled['total_localtax1']) . ' | ';
+ print '' . price($expired['total_localtax1']) . ' | ';
+ print '' . price($close['total_localtax1']) . ' | ';
+ print '
';
+ }
+
+ if ($mysoc->localtax2_assuj == "1" || $all['total_localtax2'] != 0) {
+ print '| ' . $langs->trans("TotalLT2") . ' | ';
+ print '' . price($all['total_localtax2']) . ' | ';
+ print '' . price($draft['total_localtax2']) . ' | ';
+ print '' . price($enabled['total_localtax2']) . ' | ';
+ print '' . price($expired['total_localtax2']) . ' | ';
+ print '' . price($close['total_localtax2']) . ' | ';
+ print '
';
+ }
+
+ print '| '.$langs->trans("TotalTTC").' | ';
+ print ''.price($all['total_ttc']).' | ';
+ print ''.price($draft['total_ttc']).' | ';
+ print ''.price($enabled['total_ttc']).' | ';
+ print ''.price($expired['total_ttc']).' | ';
+ print ''.price($close['total_ttc']).' | ';
+ print '
';
+
+ print "
";
+
+ print '
';
+ print '';
+
+ print '
';
if ($object->status == $object::STATUS_DRAFT && $user->hasRight('contrat', 'creer')) {
print '';
diff --git a/htdocs/contrat/class/contrat.class.php b/htdocs/contrat/class/contrat.class.php
index 814e223449c..82ae9b8635c 100644
--- a/htdocs/contrat/class/contrat.class.php
+++ b/htdocs/contrat/class/contrat.class.php
@@ -1,18 +1,20 @@
- * Copyright (C) 2004-2012 Destailleur Laurent
- * Copyright (C) 2005-2014 Regis Houssin
- * Copyright (C) 2006 Andre Cianfarani
- * Copyright (C) 2008 Raphael Bertrand
- * Copyright (C) 2010-2016 Juanjo Menent
- * Copyright (C) 2013 Christophe Battarel
- * Copyright (C) 2013 Florian Henry
- * Copyright (C) 2014-2015 Marcos García
- * Copyright (C) 2018 Nicolas ZABOURI
+/* Copyright (C) 2003 Rodolphe Quiedeville
+ * Copyright (C) 2004-2012 Destailleur Laurent
+ * Copyright (C) 2005-2014 Regis Houssin
+ * Copyright (C) 2006 Andre Cianfarani
+ * Copyright (C) 2008 Raphael Bertrand
+ * Copyright (C) 2010-2016 Juanjo Menent
+ * Copyright (C) 2013 Christophe Battarel
+ * Copyright (C) 2013 Florian Henry
+ * Copyright (C) 2014-2015 Marcos García
+ * Copyright (C) 2018 Nicolas ZABOURI
* Copyright (C) 2018-2025 Frédéric France
- * Copyright (C) 2015-2018 Ferran Marcet
- * Copyright (C) 2024 William Mead
- * Copyright (C) 2024-2026 MDW
+ * Copyright (C) 2015-2018 Ferran Marcet
+ * Copyright (C) 2024 William Mead
+ * Copyright (C) 2024-2026 MDW
+ * Copyright (C) 2026 Charlene Benke
+ * Copyright (C) 2026 Alexandre Spangaro |int Array of totalized lines or int if error
+ */
+ public function getTotalizedLines($statut, int $expired)
+ {
+ $sql = "SELECT SUM(cd.qty) as total_qty, SUM(cd.total_ht) as total_ht, SUM(cd.total_tva) as total_tva, SUM(cd.total_ttc) as total_ttc,";
+ $sql .= " SUM(cd.total_localtax1) as total_localtax1, SUM(cd.total_localtax2) as total_localtax2";
+ $sql .= " FROM ".MAIN_DB_PREFIX."contratdet as cd";
+ $sql .= " WHERE cd.fk_contrat =".((int) $this->id);
+ if ($statut >= 0) {
+ $sql .= " AND cd.statut = ".((int) $statut);
+ if ($expired > 0) {
+ $sql .= " AND cd.date_fin_validite < '".$this->db->idate(dol_now())."'";
+ } else {
+ $sql .= " AND cd.date_fin_validite >= '".$this->db->idate(dol_now())."'";
+ }
+ }
+ $ret = $this->db->query($sql);
+ $response = array();
+ if ($ret) {
+ $obj = $this->db->fetch_object($ret);
+ $response['total_qty'] = $obj->total_qty;
+ $response['total_ht'] = $obj->total_ht;
+ $response['total_tva'] = $obj->total_tva;
+ $response['total_localtax1'] = $obj->total_localtax1;
+ $response['total_localtax2'] = $obj->total_localtax2;
+ $response['total_ttc'] = $obj->total_ttc;
+ } else {
+ dol_print_error($this->db);
+ $this->error = $this->db->lasterror();
+ return -1;
+ }
+ return $response;
+ }
+
// @Todo getLibSignedStatus, LibSignedStatus
/**
diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php
index 62822cfae36..7b9084f71f4 100644
--- a/htdocs/core/class/html.form.class.php
+++ b/htdocs/core/class/html.form.class.php
@@ -1123,7 +1123,7 @@ class Form
/**
* Return a select list of country phone calling codes
*
- * @param string $selected Pre-selected phone code value (e.g. "+33")
+ * @param string $selected Preselected phone code value (e.g. "+33")
* @param string $htmlname Name of HTML select element
* @param string $morecss More CSS classes
* @param int $showempty Show empty option (1) or not (0)
diff --git a/htdocs/core/class/ldap.class.php b/htdocs/core/class/ldap.class.php
index 92f57ff1d31..054d05a469c 100644
--- a/htdocs/core/class/ldap.class.php
+++ b/htdocs/core/class/ldap.class.php
@@ -30,7 +30,7 @@
* Note:
* LDAP_ESCAPE_FILTER is to escape char array('\\', '*', '(', ')', "\x00")
* LDAP_ESCAPE_DN is to escape char array('\\', ',', '=', '+', '<', '>', ';', '"', '#')
- * @phan-file-suppress PhanTypeMismatchArgumentInternal (notifications concern 'resource)
+ * @phan-file-suppress PhanTypeMismatchArgumentInternal (notifications concern 'resource')
*/
/**
@@ -242,7 +242,8 @@ class Ldap
public $ldapcharset = 'UTF-8';
/**
- * @var bool|resource The internal LDAP connection handle. Was a resource before PHP 8.1 and is an object of class LDAP\Connection since PHP 8.1
+ * @var false|resource The internal LDAP connection handle. Was a resource before PHP 8.1 and is an object of class LDAP\Connection since PHP 8.1
+ * @phpstan-var LDAP\Connection
*/
public $connection;
@@ -346,7 +347,7 @@ class Ldap
if (empty($this->error)) {
// Loop on each ldap server
foreach ($this->server as $host) {
- if ($connected) {
+ if ($connected) { // @phpstan-ignore if.alwaysFalse
break;
}
if (empty($host)) {
@@ -384,7 +385,7 @@ class Ldap
}
}
- if (is_resource($this->connection) || is_object($this->connection)) {
+ if ($this->connection !== false) {
if ($ldapdebug) {
dol_syslog(get_class($this)."::connectBind this->connection is ok", LOG_DEBUG);
}
@@ -436,7 +437,7 @@ class Ldap
}
}
// Try in anonymous
- if (!$this->bind) {
+ if (!$this->bind) { // @phpstan-ignore booleanNot.alwaysTrue
dol_syslog(get_class($this)."::connectBind try bind anonymously on ".$host, LOG_DEBUG);
$result = $this->bind();
if ($result) {
@@ -451,7 +452,7 @@ class Ldap
}
}
- if (!$connected) {
+ if (!$connected) { // @phpstan-ignore booleanNot.alwaysTrue
$this->unbind();
}
} // End loop on each server
@@ -540,7 +541,7 @@ class Ldap
}
}
} else {
- if (is_resource($this->connection)) {
+ if ($this->connection !== false) {
// @phan-suppress-next-line PhanTypeMismatchArgumentInternalReal PhanTypeSuspiciousIndirectVariable
$this->result = @ldap_unbind($this->connection);
}
diff --git a/htdocs/core/db/pgsql.class.php b/htdocs/core/db/pgsql.class.php
index 361037e705f..0aff98276ab 100644
--- a/htdocs/core/db/pgsql.class.php
+++ b/htdocs/core/db/pgsql.class.php
@@ -62,7 +62,9 @@ class DoliDBPgsql extends DoliDB
public $standard_conforming_strings = false;
- /** @var resource|boolean Resultset of last query */
+ /**
+ * @var false|resource|PgSql\Result Resultset of last query
+ */
private $_results;
@@ -624,7 +626,8 @@ class DoliDBPgsql extends DoliDB
/**
* Return datas as an array
*
- * @param resource $resultset Resultset of request
+ * @param bool|resource $resultset Resultset of request
+ * @phpstan-param bool|resource|PgSql\Result $resultset
* @return array|null|int<0,0> Array or null if KO or end of cursor or 0 if resultset is bool
*/
public function fetch_row($resultset)
@@ -634,6 +637,9 @@ class DoliDBPgsql extends DoliDB
if (!is_resource($resultset) && !is_object($resultset)) {
$resultset = $this->_results;
}
+ if (is_bool($resultset)) {
+ return 0;
+ }
return pg_fetch_row($resultset); // @phan-suppress-current-line PhanTypeMismatchArgumentProbablyReal
}
diff --git a/htdocs/core/lib/bank.lib.php b/htdocs/core/lib/bank.lib.php
index cf11e59f5ff..d69f280395b 100644
--- a/htdocs/core/lib/bank.lib.php
+++ b/htdocs/core/lib/bank.lib.php
@@ -1,12 +1,13 @@
- * Copyright (C) 2012 Regis Houssin
- * Copyright (C) 2015 Alexandre Spangaro
- * Copyright (C) 2016 Juanjo Menent
- * Copyright (C) 2019 Nicolas ZABOURI
- * Copyright (C) 2021 Ferran Marcet
- * Copyright (C) 2024 MDW
+/* Copyright (C) 2006-2016 Laurent Destailleur
+ * Copyright (C) 2012 Regis Houssin
+ * Copyright (C) 2015 Alexandre Spangaro
+ * Copyright (C) 2016 Juanjo Menent
+ * Copyright (C) 2019 Nicolas ZABOURI
+ * Copyright (C) 2021 Ferran Marcet
+ * Copyright (C) 2024 MDW
* Copyright (C) 2024-2026 Frédéric France
+ * Copyright (C) 2026 Solution Libre SAS
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -207,6 +208,7 @@ function bank_admin_prepare_head($object)
$extrafields->fetch_name_optionals_label('bank_account');
$extrafields->fetch_name_optionals_label('bank');
$extrafields->fetch_name_optionals_label('paiement');
+ $extrafields->fetch_name_optionals_label('payment_various');
$h = 0;
$head = array();
@@ -255,6 +257,15 @@ function bank_admin_prepare_head($object)
$head[$h][2] = 'bank_payments_extrafields';
$h++;
+ $head[$h][0] = dolBuildUrl(DOL_URL_ROOT.'/admin/bank_various_payment_extrafields.php');
+ $head[$h][1] = $langs->trans("ExtraFields").' ('.$langs->trans("VariousPayments").')';
+ $nbExtrafields = $extrafields->attributes['payment_various']['count'];
+ if ($nbExtrafields > 0) {
+ $head[$h][1] .= ''.$nbExtrafields.'';
+ }
+ $head[$h][2] = 'bank_various_payment_extrafields';
+ $h++;
+
complete_head_from_modules($conf, $langs, $object, $head, $h, 'bank_admin', 'remove');
return $head;
diff --git a/htdocs/core/lib/security.lib.php b/htdocs/core/lib/security.lib.php
index 4c7ac5b137c..49d587073ca 100644
--- a/htdocs/core/lib/security.lib.php
+++ b/htdocs/core/lib/security.lib.php
@@ -546,13 +546,20 @@ function restrictedArea(User $user, $features, $object = 0, $tableandshare = '',
$feature2 = 'evaluation';
}
- // @todo check : project_task
- // @todo possible ?
- // elseif (substr($features, -3, 3) == 'det') {
- // $features = substr($features, 0, -3);
- // } elseif (substr($features, -4, 4) == '_det' || substr($features, -4, 4) == 'line') {
- // $features = substr($features, 0, -4);
- // }
+ // When the object is a task (element='project_task') and $feature2 is empty,
+ // $checkUserAccessToObject() falls into the $checkproject path and uses the task ID
+ // as project ID, which always fails. Setting $feature2='project_task' triggers the
+ // normalization at line 974 that redirects to the $checktask path, which correctly
+ // resolves $task->fk_project before calling getProjectsAuthorizedForUser().
+ if (is_object($object) && in_array($object->element, array('project_task', 'task'))
+ && (empty($features) || in_array($features, array('projet', 'project')))
+ && empty($feature2)) {
+ $features = 'projet';
+ $feature2 = 'project_task';
+ if (empty($tableandshare)) {
+ $tableandshare = 'projet_task';
+ }
+ }
// print $features.' - '.$tableandshare.' - '.$feature2.' - '.$dbt_select."\n";
diff --git a/htdocs/core/modules/modBanque.class.php b/htdocs/core/modules/modBanque.class.php
index fd0adfd32e0..354cedc0663 100644
--- a/htdocs/core/modules/modBanque.class.php
+++ b/htdocs/core/modules/modBanque.class.php
@@ -1,9 +1,10 @@
- * Copyright (C) 2004-2008 Laurent Destailleur
- * Copyright (C) 2004 Sebastien Di Cintio
- * Copyright (C) 2004 Benoit Mortier
- * Copyright (C) 2008-2011 Regis Houssin
+/* Copyright (C) 2003-2005 Rodolphe Quiedeville
+ * Copyright (C) 2004-2008 Laurent Destailleur
+ * Copyright (C) 2004 Sebastien Di Cintio
+ * Copyright (C) 2004 Benoit Mortier
+ * Copyright (C) 2008-2011 Regis Houssin
+ * Copyright (C) 2026 Solution Libre SAS
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -230,10 +231,16 @@ class modBanque extends DolibarrModules
'v.note'=>"payment", 'v.datec'=>"payment",
"p.ref"=>"project", "p.title"=>"project"
);
+ // Add extra fields
+ $keyforselect = 'payment_various';
+ $keyforelement = 'payment';
+ $keyforaliasextra = 'extra';
+ include DOL_DOCUMENT_ROOT.'/core/extrafieldsinexport.inc.php';
$this->export_sql_start[$r] = 'SELECT ';
$this->export_sql_end[$r] = ' FROM '.MAIN_DB_PREFIX.'payment_various as v';
$this->export_sql_end[$r] .= ' LEFT JOIN '.MAIN_DB_PREFIX."projet as p ON v.fk_projet = p.rowid";
$this->export_sql_end[$r] .= ' LEFT JOIN '.MAIN_DB_PREFIX."c_paiement as cp ON v.fk_typepayment = cp.id";
+ $this->export_sql_end[$r] .= ' LEFT JOIN '.MAIN_DB_PREFIX.'payment_various_extrafields as extra ON v.rowid = extra.fk_object';
$this->export_sql_end[$r] .= ' WHERE v.entity IN ('.getEntity('payment_various').')';
$this->export_sql_order[$r] = ' ORDER BY v.datep';
}
diff --git a/htdocs/core/modules/modSubtotals.class.php b/htdocs/core/modules/modSubtotals.class.php
index bcf6635bdec..45e5826eacd 100644
--- a/htdocs/core/modules/modSubtotals.class.php
+++ b/htdocs/core/modules/modSubtotals.class.php
@@ -33,6 +33,10 @@
include_once DOL_DOCUMENT_ROOT."/core/modules/DolibarrModules.class.php";
require_once DOL_DOCUMENT_ROOT.'/subtotals/class/commonsubtotal.class.php';
+if (!defined('SUBTOTALS_SPECIAL_CODE')) {
+ define('SUBTOTALS_SPECIAL_CODE', 81);
+}
+
/**
* Description and activation class for module subtotals
*/
diff --git a/htdocs/core/tpl/objectline_create.tpl.php b/htdocs/core/tpl/objectline_create.tpl.php
index 2997ad591de..80fa779b073 100644
--- a/htdocs/core/tpl/objectline_create.tpl.php
+++ b/htdocs/core/tpl/objectline_create.tpl.php
@@ -1304,7 +1304,8 @@ if (!empty($object->thirdparty)) {
}
// Deal with supplier ref price (idprodfournprice = int)
- if (jQuery('#idprodfournprice').val() > 0)
+ var supplierVal = jQuery('#idprodfournprice').val();
+ if (supplierVal && supplierVal !== '-1' && (supplierVal > 0 || supplierVal.indexOf('idprod_') === 0))
{
console.log("objectline_create.tpl #idprodfournprice is an ID > 0, so we set some properties into page");
diff --git a/htdocs/core/triggers/interface_50_modAgenda_ActionsAuto.class.php b/htdocs/core/triggers/interface_50_modAgenda_ActionsAuto.class.php
index caafde041c8..0a27e200bd4 100644
--- a/htdocs/core/triggers/interface_50_modAgenda_ActionsAuto.class.php
+++ b/htdocs/core/triggers/interface_50_modAgenda_ActionsAuto.class.php
@@ -8,7 +8,7 @@
* Copyright (C) 2022 Ferran Marcet
* Copyright (C) 2023-2024 William Mead
* Copyright (C) 2023 Christian Foellmann
- * Copyright (C) 2024-2025 MDW
+ * Copyright (C) 2024-2026 MDW
* Copyright (C) 2025 Frédéric France
*
* This program is free software; you can redistribute it and/or modify
@@ -209,13 +209,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("ContractValidatedInDolibarr", (string) ($object->newref ? $object->newref : $object->ref));
+ $object->actionmsg2 = $langs->transnoentities("ContractValidatedInDolibarr", (string) ($object->newref ? $object->newref : (string) $object->ref));
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("ContractValidatedInDolibarr", (string) ($object->newref ? $object->newref : $object->ref));
+ $object->actionmsg = $langs->transnoentities("ContractValidatedInDolibarr", (string) ($object->newref ? $object->newref : (string) $object->ref));
}
$object->sendtoid = array();
@@ -244,13 +244,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("PropalValidatedInDolibarr", (string) ($object->newref ? $object->newref : $object->ref));
+ $object->actionmsg2 = $langs->transnoentities("PropalValidatedInDolibarr", (string) ($object->newref ? $object->newref : (string) $object->ref));
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("PropalValidatedInDolibarr", (string) ($object->newref ? $object->newref : $object->ref));
+ $object->actionmsg = $langs->transnoentities("PropalValidatedInDolibarr", (string) ($object->newref ? $object->newref : (string) $object->ref));
}
$object->sendtoid = array();
@@ -261,13 +261,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("PropalBackToDraftInDolibarr", (string) ($object->newref ? $object->newref : $object->ref));
+ $object->actionmsg2 = $langs->transnoentities("PropalBackToDraftInDolibarr", (string) ($object->newref ? $object->newref : (string) $object->ref));
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("PropalBackToDraftInDolibarr", (string) ($object->newref ? $object->newref : $object->ref));
+ $object->actionmsg = $langs->transnoentities("PropalBackToDraftInDolibarr", (string) ($object->newref ? $object->newref : (string) $object->ref));
}
$object->sendtoid = array();
@@ -347,13 +347,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("OrderValidatedInDolibarr", (string) ($object->newref ? $object->newref : $object->ref));
+ $object->actionmsg2 = $langs->transnoentities("OrderValidatedInDolibarr", (string) ($object->newref ? $object->newref : (string) $object->ref));
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("OrderValidatedInDolibarr", (string) ($object->newref ? $object->newref : $object->ref));
+ $object->actionmsg = $langs->transnoentities("OrderValidatedInDolibarr", (string) ($object->newref ? $object->newref : (string) $object->ref));
}
$object->sendtoid = array();
@@ -433,13 +433,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) { // Label
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("InvoiceValidatedInDolibarr", ($object->newref ? $object->newref : $object->ref));
+ $object->actionmsg2 = $langs->transnoentities("InvoiceValidatedInDolibarr", ($object->newref ? $object->newref : (string) $object->ref));
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) { // Description
- $object->actionmsg = $langs->transnoentities("InvoiceValidatedInDolibarr", ($object->newref ? $object->newref : $object->ref));
+ $object->actionmsg = $langs->transnoentities("InvoiceValidatedInDolibarr", ($object->newref ? $object->newref : (string) $object->ref));
}
$object->sendtoid = array();
@@ -450,13 +450,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("InvoiceBackToDraftInDolibarr", $object->ref);
+ $object->actionmsg2 = $langs->transnoentities("InvoiceBackToDraftInDolibarr", (string) $object->ref);
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("InvoiceBackToDraftInDolibarr", $object->ref);
+ $object->actionmsg = $langs->transnoentities("InvoiceBackToDraftInDolibarr", (string) $object->ref);
}
$object->sendtoid = array();
@@ -467,13 +467,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("InvoiceSentByEMail", $object->ref);
+ $object->actionmsg2 = $langs->transnoentities("InvoiceSentByEMail", (string) $object->ref);
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("InvoiceSentByEMail", $object->ref);
+ $object->actionmsg = $langs->transnoentities("InvoiceSentByEMail", (string) $object->ref);
}
// Parameters $object->sendtoid defined by caller
@@ -486,13 +486,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
// Values for this action can't be defined by caller.
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("InvoicePaidInDolibarr", $object->ref);
+ $object->actionmsg2 = $langs->transnoentities("InvoicePaidInDolibarr", (string) $object->ref);
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("InvoicePaidInDolibarr", $object->ref);
+ $object->actionmsg = $langs->transnoentities("InvoicePaidInDolibarr", (string) $object->ref);
}
$object->sendtoid = array();
@@ -503,13 +503,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("InvoiceCanceledInDolibarr", $object->ref);
+ $object->actionmsg2 = $langs->transnoentities("InvoiceCanceledInDolibarr", (string) $object->ref);
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("InvoiceCanceledInDolibarr", $object->ref);
+ $object->actionmsg = $langs->transnoentities("InvoiceCanceledInDolibarr", (string) $object->ref);
}
$object->sendtoid = array();
@@ -520,13 +520,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("InterventionCreatedInDolibarr", $object->ref);
+ $object->actionmsg2 = $langs->transnoentities("InterventionCreatedInDolibarr", (string) $object->ref);
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("InterventionCreatedInDolibarr", $object->ref);
+ $object->actionmsg = $langs->transnoentities("InterventionCreatedInDolibarr", (string) $object->ref);
}
$object->sendtoid = array();
@@ -539,13 +539,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("InterventionValidatedInDolibarr", ($object->newref ? $object->newref : $object->ref));
+ $object->actionmsg2 = $langs->transnoentities("InterventionValidatedInDolibarr", ($object->newref ? $object->newref : (string) $object->ref));
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("InterventionValidatedInDolibarr", ($object->newref ? $object->newref : $object->ref));
+ $object->actionmsg = $langs->transnoentities("InterventionValidatedInDolibarr", ($object->newref ? $object->newref : (string) $object->ref));
}
$object->sendtoid = array();
@@ -558,13 +558,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("InterventionModifiedInDolibarr", $object->ref);
+ $object->actionmsg2 = $langs->transnoentities("InterventionModifiedInDolibarr", (string) $object->ref);
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("InterventionModifiedInDolibarr", $object->ref);
+ $object->actionmsg = $langs->transnoentities("InterventionModifiedInDolibarr", (string) $object->ref);
}
$object->sendtoid = array();
@@ -577,13 +577,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("InterventionSentByEMail", $object->ref);
+ $object->actionmsg2 = $langs->transnoentities("InterventionSentByEMail", (string) $object->ref);
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("InterventionSentByEMail", $object->ref);
+ $object->actionmsg = $langs->transnoentities("InterventionSentByEMail", (string) $object->ref);
}
// Parameters $object->sendtoid defined by caller
@@ -595,13 +595,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("InterventionClassifiedBilledInDolibarr", $object->ref);
+ $object->actionmsg2 = $langs->transnoentities("InterventionClassifiedBilledInDolibarr", (string) $object->ref);
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("InterventionClassifiedBilledInDolibarr", $object->ref);
+ $object->actionmsg = $langs->transnoentities("InterventionClassifiedBilledInDolibarr", (string) $object->ref);
}
$object->sendtoid = array();
@@ -612,13 +612,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("InterventionClassifiedUnbilledInDolibarr", $object->ref);
+ $object->actionmsg2 = $langs->transnoentities("InterventionClassifiedUnbilledInDolibarr", (string) $object->ref);
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("InterventionClassifiedUnbilledInDolibarr", $object->ref);
+ $object->actionmsg = $langs->transnoentities("InterventionClassifiedUnbilledInDolibarr", (string) $object->ref);
}
$object->sendtoid = array();
@@ -629,13 +629,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("InterventionClosedInDolibarr", $object->ref);
+ $object->actionmsg2 = $langs->transnoentities("InterventionClosedInDolibarr", (string) $object->ref);
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("InterventionClosedInDolibarr", $object->ref);
+ $object->actionmsg = $langs->transnoentities("InterventionClosedInDolibarr", (string) $object->ref);
}
$object->sendtoid = array();
@@ -648,13 +648,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("InterventionDeletedInDolibarr", $object->ref);
+ $object->actionmsg2 = $langs->transnoentities("InterventionDeletedInDolibarr", (string) $object->ref);
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("InterventionDeletedInDolibarr", $object->ref);
+ $object->actionmsg = $langs->transnoentities("InterventionDeletedInDolibarr", (string) $object->ref);
}
$object->sendtoid = array();
@@ -667,13 +667,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("ShippingValidated", ($object->newref ? $object->newref : $object->ref));
+ $object->actionmsg2 = $langs->transnoentities("ShippingValidated", ($object->newref ? $object->newref : (string) $object->ref));
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("ShippingValidated", ($object->newref ? $object->newref : $object->ref));
+ $object->actionmsg = $langs->transnoentities("ShippingValidated", ($object->newref ? $object->newref : (string) $object->ref));
}
// Parameters $object->sendtoid defined by caller
@@ -685,13 +685,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("ShippingSentByEMail", $object->ref);
+ $object->actionmsg2 = $langs->transnoentities("ShippingSentByEMail", (string) $object->ref);
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("ShippingSentByEMail", $object->ref);
+ $object->actionmsg = $langs->transnoentities("ShippingSentByEMail", (string) $object->ref);
}
// Parameters $object->sendtoid defined by caller
@@ -704,13 +704,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("ReceptionValidated", ($object->newref ? $object->newref : $object->ref));
+ $object->actionmsg2 = $langs->transnoentities("ReceptionValidated", ($object->newref ? $object->newref : (string) $object->ref));
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("ReceptionValidated", ($object->newref ? $object->newref : $object->ref));
+ $object->actionmsg = $langs->transnoentities("ReceptionValidated", ($object->newref ? $object->newref : (string) $object->ref));
}
// Parameters $object->sendtoid defined by caller
@@ -723,13 +723,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("ReceptionSentByEMail", $object->ref);
+ $object->actionmsg2 = $langs->transnoentities("ReceptionSentByEMail", (string) $object->ref);
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("ReceptionSentByEMail", $object->ref);
+ $object->actionmsg = $langs->transnoentities("ReceptionSentByEMail", (string) $object->ref);
}
// Parameters $object->sendtoid defined by caller
@@ -741,13 +741,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("PropalValidatedInDolibarr", ($object->newref ? $object->newref : $object->ref));
+ $object->actionmsg2 = $langs->transnoentities("PropalValidatedInDolibarr", ($object->newref ? $object->newref : (string) $object->ref));
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("PropalValidatedInDolibarr", ($object->newref ? $object->newref : $object->ref));
+ $object->actionmsg = $langs->transnoentities("PropalValidatedInDolibarr", ($object->newref ? $object->newref : (string) $object->ref));
}
$object->sendtoid = array();
@@ -758,13 +758,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("ProposalSentByEMail", $object->ref);
+ $object->actionmsg2 = $langs->transnoentities("ProposalSentByEMail", (string) $object->ref);
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("ProposalSentByEMail", $object->ref);
+ $object->actionmsg = $langs->transnoentities("ProposalSentByEMail", (string) $object->ref);
}
// Parameters $object->sendtoid defined by caller
@@ -776,13 +776,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("PropalClosedSignedInDolibarr", $object->ref);
+ $object->actionmsg2 = $langs->transnoentities("PropalClosedSignedInDolibarr", (string) $object->ref);
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("PropalClosedSignedInDolibarr", $object->ref);
+ $object->actionmsg = $langs->transnoentities("PropalClosedSignedInDolibarr", (string) $object->ref);
}
$object->sendtoid = array();
@@ -793,13 +793,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("PropalClosedRefusedInDolibarr", $object->ref);
+ $object->actionmsg2 = $langs->transnoentities("PropalClosedRefusedInDolibarr", (string) $object->ref);
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("PropalClosedRefusedInDolibarr", $object->ref);
+ $object->actionmsg = $langs->transnoentities("PropalClosedRefusedInDolibarr", (string) $object->ref);
}
$object->sendtoid = array();
@@ -810,13 +810,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("OrderCreatedInDolibarr", ($object->newref ? $object->newref : $object->ref));
+ $object->actionmsg2 = $langs->transnoentities("OrderCreatedInDolibarr", ($object->newref ? $object->newref : (string) $object->ref));
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("OrderCreatedInDolibarr", ($object->newref ? $object->newref : $object->ref));
+ $object->actionmsg = $langs->transnoentities("OrderCreatedInDolibarr", ($object->newref ? $object->newref : (string) $object->ref));
}
$object->sendtoid = array();
@@ -827,13 +827,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("OrderValidatedInDolibarr", ($object->newref ? $object->newref : $object->ref));
+ $object->actionmsg2 = $langs->transnoentities("OrderValidatedInDolibarr", ($object->newref ? $object->newref : (string) $object->ref));
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("OrderValidatedInDolibarr", ($object->newref ? $object->newref : $object->ref));
+ $object->actionmsg = $langs->transnoentities("OrderValidatedInDolibarr", ($object->newref ? $object->newref : (string) $object->ref));
}
$object->sendtoid = array();
@@ -844,13 +844,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("OrderApprovedInDolibarr", $object->ref);
+ $object->actionmsg2 = $langs->transnoentities("OrderApprovedInDolibarr", (string) $object->ref);
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("OrderApprovedInDolibarr", $object->ref);
+ $object->actionmsg = $langs->transnoentities("OrderApprovedInDolibarr", (string) $object->ref);
}
$object->sendtoid = array();
@@ -861,13 +861,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("OrderRefusedInDolibarr", $object->ref);
+ $object->actionmsg2 = $langs->transnoentities("OrderRefusedInDolibarr", (string) $object->ref);
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("OrderRefusedInDolibarr", $object->ref);
+ $object->actionmsg = $langs->transnoentities("OrderRefusedInDolibarr", (string) $object->ref);
}
if (!empty($object->refuse_note)) {
@@ -883,13 +883,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("OrderCanceledInDolibarr", $object->ref);
+ $object->actionmsg2 = $langs->transnoentities("OrderCanceledInDolibarr", (string) $object->ref);
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("OrderCanceledInDolibarr", $object->ref);
+ $object->actionmsg = $langs->transnoentities("OrderCanceledInDolibarr", (string) $object->ref);
}
if (!empty($object->cancel_note)) {
@@ -905,13 +905,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("SupplierOrderSubmitedInDolibarr", ($object->newref ?: $object->ref), $object->getInputMethod());
+ $object->actionmsg2 = $langs->transnoentities("SupplierOrderSubmitedInDolibarr", ($object->newref ?: (string) $object->ref), $object->getInputMethod());
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("SupplierOrderSubmitedInDolibarr", ($object->newref ? $object->newref : $object->ref));
+ $object->actionmsg = $langs->transnoentities("SupplierOrderSubmitedInDolibarr", ($object->newref ? $object->newref : (string) $object->ref));
}
if (!empty($object->context['comments'])) {
@@ -927,13 +927,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("SupplierOrderReceivedInDolibarr", ($object->newref ? $object->newref : $object->ref));
+ $object->actionmsg2 = $langs->transnoentities("SupplierOrderReceivedInDolibarr", ($object->newref ? $object->newref : (string) $object->ref));
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("SupplierOrderReceivedInDolibarr", ($object->newref ? $object->newref : $object->ref));
+ $object->actionmsg = $langs->transnoentities("SupplierOrderReceivedInDolibarr", ($object->newref ? $object->newref : (string) $object->ref));
}
$object->sendtoid = array();
@@ -944,13 +944,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("SupplierOrderSentByEMail", $object->ref);
+ $object->actionmsg2 = $langs->transnoentities("SupplierOrderSentByEMail", (string) $object->ref);
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("SupplierOrderSentByEMail", $object->ref);
+ $object->actionmsg = $langs->transnoentities("SupplierOrderSentByEMail", (string) $object->ref);
}
// Parameters $object->sendtoid defined by caller
@@ -962,13 +962,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("SupplierOrderClassifiedBilled", $object->ref);
+ $object->actionmsg2 = $langs->transnoentities("SupplierOrderClassifiedBilled", (string) $object->ref);
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("SupplierOrderClassifiedBilled", $object->ref);
+ $object->actionmsg = $langs->transnoentities("SupplierOrderClassifiedBilled", (string) $object->ref);
}
$object->sendtoid = array();
@@ -979,13 +979,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("InvoiceCreatedInDolibarr", ($object->newref ? $object->newref : $object->ref));
+ $object->actionmsg2 = $langs->transnoentities("InvoiceCreatedInDolibarr", ($object->newref ? $object->newref : (string) $object->ref));
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("InvoiceCreatedInDolibarr", ($object->newref ? $object->newref : $object->ref));
+ $object->actionmsg = $langs->transnoentities("InvoiceCreatedInDolibarr", ($object->newref ? $object->newref : (string) $object->ref));
}
$object->sendtoid = array();
@@ -996,13 +996,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("InvoiceValidatedInDolibarr", ($object->newref ? $object->newref : $object->ref));
+ $object->actionmsg2 = $langs->transnoentities("InvoiceValidatedInDolibarr", ($object->newref ? $object->newref : (string) $object->ref));
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("InvoiceValidatedInDolibarr", ($object->newref ? $object->newref : $object->ref));
+ $object->actionmsg = $langs->transnoentities("InvoiceValidatedInDolibarr", ($object->newref ? $object->newref : (string) $object->ref));
}
$object->sendtoid = array();
@@ -1013,13 +1013,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("InvoiceBackToDraftInDolibarr", $object->ref);
+ $object->actionmsg2 = $langs->transnoentities("InvoiceBackToDraftInDolibarr", (string) $object->ref);
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("InvoiceBackToDraftInDolibarr", $object->ref);
+ $object->actionmsg = $langs->transnoentities("InvoiceBackToDraftInDolibarr", (string) $object->ref);
}
$object->sendtoid = array();
@@ -1030,13 +1030,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("SupplierInvoiceSentByEMail", $object->ref);
+ $object->actionmsg2 = $langs->transnoentities("SupplierInvoiceSentByEMail", (string) $object->ref);
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("SupplierInvoiceSentByEMail", $object->ref);
+ $object->actionmsg = $langs->transnoentities("SupplierInvoiceSentByEMail", (string) $object->ref);
}
// Parameters $object->sendtoid defined by caller
@@ -1048,13 +1048,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("InvoicePaidInDolibarr", $object->ref);
+ $object->actionmsg2 = $langs->transnoentities("InvoicePaidInDolibarr", (string) $object->ref);
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("InvoicePaidInDolibarr", $object->ref);
+ $object->actionmsg = $langs->transnoentities("InvoicePaidInDolibarr", (string) $object->ref);
}
$object->sendtoid = array();
@@ -1064,13 +1064,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("InvoiceCanceledInDolibarr", $object->ref);
+ $object->actionmsg2 = $langs->transnoentities("InvoiceCanceledInDolibarr", (string) $object->ref);
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("InvoiceCanceledInDolibarr", $object->ref);
+ $object->actionmsg = $langs->transnoentities("InvoiceCanceledInDolibarr", (string) $object->ref);
}
$object->sendtoid = array();
@@ -1191,13 +1191,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("MemberSubscriptionDeletedInDolibarr", $object->ref, $member->getFullName($langs));
+ $object->actionmsg2 = $langs->transnoentities("MemberSubscriptionDeletedInDolibarr", (string) $object->ref, $member->getFullName($langs));
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("MemberSubscriptionDeletedInDolibarr", $object->ref, $member->getFullName($langs));
+ $object->actionmsg = $langs->transnoentities("MemberSubscriptionDeletedInDolibarr", (string) $object->ref, $member->getFullName($langs));
$object->actionmsg .= "\n".$langs->transnoentities("Member").': '.$member->getFullName($langs);
$object->actionmsg .= "\n".$langs->transnoentities("Type").': '.$object->fk_type;
$object->actionmsg .= "\n".$langs->transnoentities("Amount").': '.$object->amount;
@@ -1273,14 +1273,14 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("ProjectCreatedInDolibarr", $object->ref);
+ $object->actionmsg2 = $langs->transnoentities("ProjectCreatedInDolibarr", (string) $object->ref);
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("ProjectCreatedInDolibarr", $object->ref);
- $object->actionmsg .= "\n".$langs->transnoentities("Project").': '.$object->ref;
+ $object->actionmsg = $langs->transnoentities("ProjectCreatedInDolibarr", (string) $object->ref);
+ $object->actionmsg .= "\n".$langs->transnoentities("Project").': '.(string) $object->ref;
}
$object->sendtoid = array();
@@ -1291,14 +1291,14 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("ProjectValidatedInDolibarr", $object->ref);
+ $object->actionmsg2 = $langs->transnoentities("ProjectValidatedInDolibarr", (string) $object->ref);
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("ProjectValidatedInDolibarr", $object->ref);
- $object->actionmsg .= "\n".$langs->transnoentities("Project").': '.$object->ref;
+ $object->actionmsg = $langs->transnoentities("ProjectValidatedInDolibarr", (string) $object->ref);
+ $object->actionmsg .= "\n".$langs->transnoentities("Project").': '.(string) $object->ref;
}
$object->sendtoid = array();
@@ -1309,13 +1309,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("ProjectModifiedInDolibarr", $object->ref);
+ $object->actionmsg2 = $langs->transnoentities("ProjectModifiedInDolibarr", (string) $object->ref);
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("ProjectModifiedInDolibarr", $object->ref);
+ $object->actionmsg = $langs->transnoentities("ProjectModifiedInDolibarr", (string) $object->ref);
}
//$object->actionmsg .= "\n".$langs->transnoentities("Task").': ???';
@@ -1331,13 +1331,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("ProjectSentByEMail", $object->ref);
+ $object->actionmsg2 = $langs->transnoentities("ProjectSentByEMail", (string) $object->ref);
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("ProjectSentByEMail", $object->ref);
+ $object->actionmsg = $langs->transnoentities("ProjectSentByEMail", (string) $object->ref);
}
// Parameters $object->sendtoid defined by caller
@@ -1348,9 +1348,9 @@ class InterfaceActionsAuto extends DolibarrTriggers
$langs->loadLangs(array("agenda", "other", "projects"));
if (empty($object->actionmsg2)) {
- $object->actionmsg2 = $langs->transnoentities("ProjectDeletedInDolibarr", $object->ref);
+ $object->actionmsg2 = $langs->transnoentities("ProjectDeletedInDolibarr", (string) $object->ref);
}
- $object->actionmsg = $langs->transnoentities("ProjectDeletedInDolibarr", $object->ref);
+ $object->actionmsg = $langs->transnoentities("ProjectDeletedInDolibarr", (string) $object->ref);
$object->sendtoid = array();
} elseif ($action == 'PROJECT_CLOSE' && $object instanceof Project) {
@@ -1359,13 +1359,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("ProjectClosedInDolibarr", $object->ref);
+ $object->actionmsg2 = $langs->transnoentities("ProjectClosedInDolibarr", (string) $object->ref);
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("ProjectClosedInDolibarr", $object->ref);
+ $object->actionmsg = $langs->transnoentities("ProjectClosedInDolibarr", (string) $object->ref);
}
$object->sendtoid = array();
@@ -1377,14 +1377,14 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("TaskCreatedInDolibarr", $object->ref);
+ $object->actionmsg2 = $langs->transnoentities("TaskCreatedInDolibarr", (string) $object->ref);
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("TaskCreatedInDolibarr", $object->ref);
- $object->actionmsg .= "\n".$langs->transnoentities("Task").': '.$object->ref;
+ $object->actionmsg = $langs->transnoentities("TaskCreatedInDolibarr", (string) $object->ref);
+ $object->actionmsg .= "\n".$langs->transnoentities("Task").': '.(string) $object->ref;
}
$object->sendtoid = array();
@@ -1395,14 +1395,14 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("TaskModifiedInDolibarr", $object->ref);
+ $object->actionmsg2 = $langs->transnoentities("TaskModifiedInDolibarr", (string) $object->ref);
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("TaskModifiedInDolibarr", $object->ref);
- $object->actionmsg .= "\n".$langs->transnoentities("Task").': '.$object->ref;
+ $object->actionmsg = $langs->transnoentities("TaskModifiedInDolibarr", (string) $object->ref);
+ $object->actionmsg .= "\n".$langs->transnoentities("Task").': '.(string) $object->ref;
}
$object->sendtoid = array();
@@ -1413,14 +1413,14 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("TaskDeletedInDolibarr", $object->ref);
+ $object->actionmsg2 = $langs->transnoentities("TaskDeletedInDolibarr", (string) $object->ref);
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("TaskDeletedInDolibarr", $object->ref);
- $object->actionmsg .= "\n".$langs->transnoentities("Task").': '.$object->ref;
+ $object->actionmsg = $langs->transnoentities("TaskDeletedInDolibarr", (string) $object->ref);
+ $object->actionmsg .= "\n".$langs->transnoentities("Task").': '.(string) $object->ref;
}
$object->sendtoid = array();
@@ -1431,13 +1431,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
if (empty($object->context['actionmsg2'])) {
- $object->actionmsg2 = $langs->transnoentities("TICKET_ASSIGNEDInDolibarr", $object->ref);
+ $object->actionmsg2 = $langs->transnoentities("TICKET_ASSIGNEDInDolibarr", (string) $object->ref);
} else {
$object->actionmsg2 = $object->context['actionmsg2'];
}
}
if (empty($object->actionmsg)) {
- $object->actionmsg = $langs->transnoentities("TICKET_ASSIGNEDInDolibarr", $object->ref);
+ $object->actionmsg = $langs->transnoentities("TICKET_ASSIGNEDInDolibarr", (string) $object->ref);
}
if ($object->oldcopy->fk_user_assign > 0) {
@@ -1475,21 +1475,21 @@ class InterfaceActionsAuto extends DolibarrTriggers
if (empty($object->actionmsg2)) {
// Load translation files required by the page
$langs->loadLangs(array("agenda", "other"));
- if ($langs->transnoentities($action."InDolibarr", (empty($object->newref) ? $object->ref : $object->newref)) != $action."InDolibarr") { // specific translation key
- $object->actionmsg2 = $langs->transnoentities($action."InDolibarr", (empty($object->newref) ? $object->ref : $object->newref));
+ if ($langs->transnoentities($action."InDolibarr", (empty($object->newref) ? (string) $object->ref : $object->newref)) != $action."InDolibarr") { // specific translation key
+ $object->actionmsg2 = $langs->transnoentities($action."InDolibarr", (empty($object->newref) ? (string) $object->ref : $object->newref));
} else { // generic translation key
$tmp = explode('_', $action);
- $object->actionmsg2 = $langs->transnoentities($tmp[count($tmp) - 1]."InDolibarr", (empty($object->newref) ? $object->ref : $object->newref));
+ $object->actionmsg2 = $langs->transnoentities($tmp[count($tmp) - 1]."InDolibarr", (empty($object->newref) ? (string) $object->ref : $object->newref));
}
}
if (empty($object->actionmsg)) {
// Load translation files required by the page
$langs->loadLangs(array("agenda", "other"));
- if ($langs->transnoentities($action."InDolibarr", (empty($object->newref) ? $object->ref : $object->newref)) != $action."InDolibarr") { // specific translation key
- $object->actionmsg = $langs->transnoentities($action."InDolibarr", (empty($object->newref) ? $object->ref : $object->newref));
+ if ($langs->transnoentities($action."InDolibarr", (empty($object->newref) ? (string) $object->ref : $object->newref)) != $action."InDolibarr") { // specific translation key
+ $object->actionmsg = $langs->transnoentities($action."InDolibarr", (empty($object->newref) ? (string) $object->ref : $object->newref));
} else { // generic translation key
$tmp = explode('_', $action);
- $object->actionmsg = $langs->transnoentities($tmp[count($tmp) - 1]."InDolibarr", (empty($object->newref) ? $object->ref : $object->newref));
+ $object->actionmsg = $langs->transnoentities($tmp[count($tmp) - 1]."InDolibarr", (empty($object->newref) ? (string) $object->ref : $object->newref));
}
if (isModEnabled('multicompany') && property_exists($object, 'entity') && $object->entity > 1) {
$object->actionmsg .= ' ('.$langs->trans("Entity").' '.$object->entity.')';
diff --git a/htdocs/core/triggers/interface_50_modLdap_Ldapsynchro.class.php b/htdocs/core/triggers/interface_50_modLdap_Ldapsynchro.class.php
index 019a1f6428b..1637a176edc 100644
--- a/htdocs/core/triggers/interface_50_modLdap_Ldapsynchro.class.php
+++ b/htdocs/core/triggers/interface_50_modLdap_Ldapsynchro.class.php
@@ -2,7 +2,7 @@
/* Copyright (C) 2005-2012 Laurent Destailleur
* Copyright (C) 2005-2021 Regis Houssin
* Copyright (C) 2014 Marcos García
- * Copyright (C) 2024-2025 MDW
+ * Copyright (C) 2024-2026 MDW
* Copyright (C) 2025 Frédéric France
*
* This program is free software; you can redistribute it and/or modify
@@ -551,79 +551,83 @@ class InterfaceLdapsynchro extends DolibarrTriggers
$object->oldcopy = clone $object; // @phan-suppress-current-line PhanTypeMismatchProperty
}
- if (!method_exists($object->oldcopy, '_load_ldap_info')) {
- dol_syslog("Trigger ".$action." was called by a function that did not set previously the method ->_load_ldap_info onto object", LOG_WARNING);
- $object->oldcopy = clone $object; // @phan-suppress-current-line PhanTypeMismatchProperty
- }
+ $oldcopy = $object->oldcopy; // Copy for static analysis
- $oldinfo = $object->oldcopy->_load_ldap_info();
- $olddn = $object->oldcopy->_load_ldap_dn($oldinfo);
+ if (is_object($oldcopy)) {
+ if (!method_exists($oldcopy, '_load_ldap_info')) {
+ dol_syslog("Trigger ".$action." was called by a function that did not set previously the method ->_load_ldap_info onto object", LOG_WARNING);
+ $oldcopy = clone $object; // @phan-suppress-current-line PhanTypeMismatchProperty
+ }
- // Verify if entry exist
- $container = $object->oldcopy->_load_ldap_dn($oldinfo, 1);
- $search = "(".$object->oldcopy->_load_ldap_dn($oldinfo, 2).")";
- $records = $ldap->search($container, $search);
- if (count($records) && $records['count'] == 0) {
- $olddn = '';
- }
-
- $info = $object->_load_ldap_info();
- $dn = $object->_load_ldap_dn($info);
- $newrdn = $object->_load_ldap_dn($info, 2);
- $newparent = $object->_load_ldap_dn($info, 1);
-
- $result = $ldap->update($dn, $info, $user, $olddn, $newrdn, $newparent);
-
- // For member type
- if (getDolGlobalString('LDAP_MEMBER_TYPE_ACTIVE') && getDolGlobalInt('LDAP_MEMBER_TYPE_ACTIVE') === Ldap::SYNCHRO_DOLIBARR_TO_LDAP) {
- require_once DOL_DOCUMENT_ROOT."/adherents/class/adherent_type.class.php";
-
- /*
- * Change member info
- */
- $newmembertype = new AdherentType($this->db);
- $newmembertype->fetch($object->typeid);
- $newmembertype->listMembersForMemberType('', 1);
-
- $oldinfo = $newmembertype->_load_ldap_info();
- $olddn = $newmembertype->_load_ldap_dn($oldinfo);
+ $oldinfo = $oldcopy->_load_ldap_info();
+ $olddn = $oldcopy->_load_ldap_dn($oldinfo);
// Verify if entry exist
- $container = $newmembertype->_load_ldap_dn($oldinfo, 1);
- $search = "(".$newmembertype->_load_ldap_dn($oldinfo, 2).")";
+ $container = $oldcopy->_load_ldap_dn($oldinfo, 1);
+ $search = "(".$oldcopy->_load_ldap_dn($oldinfo, 2).")";
$records = $ldap->search($container, $search);
if (count($records) && $records['count'] == 0) {
$olddn = '';
}
- $info = $newmembertype->_load_ldap_info(); // Contains all members, included the new one (insert already done before trigger call)
- $dn = $newmembertype->_load_ldap_dn($info);
+ $info = $object->_load_ldap_info();
+ $dn = $object->_load_ldap_dn($info);
+ $newrdn = $object->_load_ldap_dn($info, 2);
+ $newparent = $object->_load_ldap_dn($info, 1);
- $result = $ldap->update($dn, $info, $user, $olddn);
+ $result = $ldap->update($dn, $info, $user, $olddn, $newrdn, $newparent);
+
+ // For member type
+ if (getDolGlobalString('LDAP_MEMBER_TYPE_ACTIVE') && getDolGlobalInt('LDAP_MEMBER_TYPE_ACTIVE') === Ldap::SYNCHRO_DOLIBARR_TO_LDAP) {
+ require_once DOL_DOCUMENT_ROOT."/adherents/class/adherent_type.class.php";
- if ($object->oldcopy->typeid != $object->typeid) {
/*
- * Remove member in old member type
+ * Change member info
*/
- $oldmembertype = new AdherentType($this->db);
- $oldmembertype->fetch($object->oldcopy->typeid);
- $oldmembertype->listMembersForMemberType('', 1);
+ $newmembertype = new AdherentType($this->db);
+ $newmembertype->fetch($object->typeid);
+ $newmembertype->listMembersForMemberType('', 1);
- $oldinfo = $oldmembertype->_load_ldap_info();
- $olddn = $oldmembertype->_load_ldap_dn($oldinfo);
+ $oldinfo = $newmembertype->_load_ldap_info();
+ $olddn = $newmembertype->_load_ldap_dn($oldinfo);
// Verify if entry exist
- $container = $oldmembertype->_load_ldap_dn($oldinfo, 1);
- $search = "(".$oldmembertype->_load_ldap_dn($oldinfo, 2).")";
+ $container = $newmembertype->_load_ldap_dn($oldinfo, 1);
+ $search = "(".$newmembertype->_load_ldap_dn($oldinfo, 2).")";
$records = $ldap->search($container, $search);
if (count($records) && $records['count'] == 0) {
$olddn = '';
}
- $info = $oldmembertype->_load_ldap_info(); // Contains all members, included the new one (insert already done before trigger call)
- $dn = $oldmembertype->_load_ldap_dn($info);
+ $info = $newmembertype->_load_ldap_info(); // Contains all members, included the new one (insert already done before trigger call)
+ $dn = $newmembertype->_load_ldap_dn($info);
$result = $ldap->update($dn, $info, $user, $olddn);
+
+ if ($oldcopy->typeid != $object->typeid) {
+ /*
+ * Remove member in old member type
+ */
+ $oldmembertype = new AdherentType($this->db);
+ $oldmembertype->fetch($oldcopy->typeid);
+ $oldmembertype->listMembersForMemberType('', 1);
+
+ $oldinfo = $oldmembertype->_load_ldap_info();
+ $olddn = $oldmembertype->_load_ldap_dn($oldinfo);
+
+ // Verify if entry exist
+ $container = $oldmembertype->_load_ldap_dn($oldinfo, 1);
+ $search = "(".$oldmembertype->_load_ldap_dn($oldinfo, 2).")";
+ $records = $ldap->search($container, $search);
+ if (count($records) && $records['count'] == 0) {
+ $olddn = '';
+ }
+
+ $info = $oldmembertype->_load_ldap_info(); // Contains all members, included the new one (insert already done before trigger call)
+ $dn = $oldmembertype->_load_ldap_dn($info);
+
+ $result = $ldap->update($dn, $info, $user, $olddn);
+ }
}
}
}
@@ -766,25 +770,29 @@ class InterfaceLdapsynchro extends DolibarrTriggers
$object->oldcopy = clone $object; // @phan-suppress-current-line PhanTypeMismatchProperty
}
- $object->oldcopy->listMembersForMemberType('', 1);
+ $oldcopy = $object->oldcopy; // Local copy to help static analysis.
- $oldinfo = $object->oldcopy->_load_ldap_info();
- $olddn = $object->oldcopy->_load_ldap_dn($oldinfo);
+ if (is_object($oldcopy)) {
+ $oldcopy->listMembersForMemberType('', 1);
- // Verify if entry exist
- $container = $object->oldcopy->_load_ldap_dn($oldinfo, 1);
- $search = "(".$object->oldcopy->_load_ldap_dn($oldinfo, 2).")";
- $records = $ldap->search($container, $search);
- if (count($records) && $records['count'] == 0) {
- $olddn = '';
+ $oldinfo = $oldcopy->_load_ldap_info();
+ $olddn = $oldcopy->_load_ldap_dn($oldinfo);
+
+ // Verify if entry exist
+ $container = $oldcopy->_load_ldap_dn($oldinfo, 1);
+ $search = "(".$oldcopy->_load_ldap_dn($oldinfo, 2).")";
+ $records = $ldap->search($container, $search);
+ if (count($records) && $records['count'] == 0) {
+ $olddn = '';
+ }
+
+ $object->listMembersForMemberType('', 1);
+
+ $info = $object->_load_ldap_info();
+ $dn = $object->_load_ldap_dn($info);
+
+ $result = $ldap->update($dn, $info, $user, $olddn);
}
-
- $object->listMembersForMemberType('', 1);
-
- $info = $object->_load_ldap_info();
- $dn = $object->_load_ldap_dn($info);
-
- $result = $ldap->update($dn, $info, $user, $olddn);
}
if ($result <= 0) {
diff --git a/htdocs/core/triggers/interface_50_modTicket_TicketEmail.class.php b/htdocs/core/triggers/interface_50_modTicket_TicketEmail.class.php
index 3dedad04378..ec68dc2300d 100644
--- a/htdocs/core/triggers/interface_50_modTicket_TicketEmail.class.php
+++ b/htdocs/core/triggers/interface_50_modTicket_TicketEmail.class.php
@@ -1,7 +1,7 @@
* Copyright (C) 2016 Christophe Battarel
- * Copyright (C) 2024-2025 MDW
+ * Copyright (C) 2024-2026 MDW
* Copyright (C) 2025 Frédéric France
* Copyright (C) 2023-2025 Benjamin Falière
*
@@ -378,8 +378,8 @@ class InterfaceTicketEmail extends DolibarrTriggers
$appli = $mysoc->name;
/* Send email to admin */
- $subject = '['.$appli.'] '.$langs->transnoentities($base_subject, $object->ref, $object->track_id);
- $message_admin = $langs->transnoentities($body, $object->track_id).'
';
+ $subject = '['.$appli.'] '.$langs->transnoentities($base_subject, (string) $object->ref, (string) $object->track_id);
+ $message_admin = $langs->transnoentities($body, (string) $object->track_id).'
';
$message_admin .= '- '.$langs->trans('Title').' : '.$object->subject.'
';
$message_admin .= '- '.$langs->trans('Type').' : '.$langs->getLabelFromKey($this->db, 'TicketTypeShort'.$object->type_code, 'c_ticket_type', 'code', 'label', $object->type_code).'
';
$message_admin .= '- '.$langs->trans('TicketCategory').' : '.$langs->getLabelFromKey($this->db, 'TicketCategoryShort'.$object->category_code, 'c_ticket_category', 'code', 'label', $object->category_code).'
';
@@ -449,7 +449,7 @@ class InterfaceTicketEmail extends DolibarrTriggers
$appli = $mysoc->name;
$subject = '['.$appli.'] '.$langs->transnoentities($base_subject);
- $message_customer = $langs->transnoentities($body, $object->track_id).'
';
+ $message_customer = $langs->transnoentities($body, (string) $object->track_id).'
';
$message_customer .= '- '.$langs->trans('Title').' : '.$object->subject.'
';
$message_customer .= '- '.$langs->trans('Type').' : '.$langs->getLabelFromKey($this->db, 'TicketTypeShort'.$object->type_code, 'c_ticket_type', 'code', 'label', $object->type_code).'
';
$message_customer .= '- '.$langs->trans('TicketCategory').' : '.$langs->getLabelFromKey($this->db, 'TicketCategoryShort'.$object->category_code, 'c_ticket_category', 'code', 'label', $object->category_code).'
';
@@ -490,7 +490,7 @@ class InterfaceTicketEmail extends DolibarrTriggers
$message_customer .= ''.$langs->trans('Message').' :
'.$message.'
';
if (getDolGlobalInt('TICKET_ENABLE_PUBLIC_INTERFACE')) {
- $url_public_ticket = getDolGlobalString('TICKET_URL_PUBLIC_INTERFACE', dol_buildpath('/public/ticket/', 2)).'view.php?track_id='.urlencode($object->track_id);
+ $url_public_ticket = getDolGlobalString('TICKET_URL_PUBLIC_INTERFACE', dol_buildpath('/public/ticket/', 2)).'view.php?track_id='.urlencode((string) $object->track_id);
$message_customer .= ''.$langs->trans($see_ticket).' : '.$url_public_ticket.'
';
$message_customer .= ''.$langs->trans('TicketEmailPleaseDoNotReplyToThisEmail').'
';
} else {
@@ -547,7 +547,7 @@ class InterfaceTicketEmail extends DolibarrTriggers
$appli = $mysoc->name;
$subject = '['.$appli.'] '.$langs->transnoentities($base_subject);
- $message = ''.$langs->transnoentities($body, $object->track_id, dolGetFirstLastname($user->firstname, $user->lastname))."
";
+ $message = ''.$langs->transnoentities($body, (string) $object->track_id, dolGetFirstLastname($user->firstname, $user->lastname))."
";
$message .= '- '.$langs->trans('Title').' : '.$object->subject.'
';
$message .= '- '.$langs->trans('Type').' : '.$object->type_label.'
';
$message .= '- '.$langs->trans('Category').' : '.$object->category_label.'
';
diff --git a/htdocs/dav/dav.class.php b/htdocs/dav/dav.class.php
index 1d528c9772b..906ead80db3 100644
--- a/htdocs/dav/dav.class.php
+++ b/htdocs/dav/dav.class.php
@@ -61,12 +61,12 @@ class CdavLib
/**
* Base sql request for calendar events
*
- * @param int $calid Calendar id
+ * @param int $calendarId Calendar id
* @param int|bool $oid Oid
* @param int|bool $ouri Ouri
* @return string
*/
- public function getSqlCalEvents($calid, $oid = false, $ouri = false)
+ public function getSqlCalEvents($calendarId, $oid = false, $ouri = false)
{
// TODO : replace GROUP_CONCAT by
$sql = 'SELECT
@@ -94,7 +94,7 @@ class CdavLib
FROM '.MAIN_DB_PREFIX.'actioncomm AS a';
$sql .= " LEFT JOIN '.MAIN_DB_PREFIX.'c_country as co ON co.rowid = sp.fk_pays
LEFT JOIN '.MAIN_DB_PREFIX.'c_country as cos ON cos.rowid = s.fk_pays
- WHERE a.id IN (SELECT ar.fk_actioncomm FROM '.MAIN_DB_PREFIX.'actioncomm_resources ar WHERE ar.element_type='user' AND ar.fk_element=".((int) $calid).")
+ WHERE a.id IN (SELECT ar.fk_actioncomm FROM '.MAIN_DB_PREFIX.'actioncomm_resources ar WHERE ar.element_type='user' AND ar.fk_element=".((int) $calendarId).")
AND a.code IN (SELECT cac.code FROM '.MAIN_DB_PREFIX.'c_actioncomm cac WHERE cac.type <> 'systemauto')
AND a.entity IN (".getEntity('societe', 1).")";
// TODO Restrict on external users
@@ -112,11 +112,11 @@ class CdavLib
/**
* Convert calendar row to VCalendar string
*
- * @param int $calid Calendar id
+ * @param int $calendarId Calendar id
* @param Object $obj Object id
* @return string
*/
- public function toVCalendar($calid, $obj)
+ public function toVCalendar($calendarId, $obj)
{
/*$categ = array();
if($obj->soc_client)
@@ -169,7 +169,7 @@ class CdavLib
$caldata .= "LAST-MODIFIED:".gmdate('Ymd\THis', strtotime($obj->lastupd))."Z\n";
$caldata .= "DTSTAMP:".gmdate('Ymd\THis', strtotime($obj->lastupd))."Z\n";
if ($obj->sourceuid == '') {
- $caldata .= "UID:".$obj->id.'-ev-'.$calid.'-cal-'.constant('CDAV_URI_KEY')."\n";
+ $caldata .= "UID:".$obj->id.'-ev-'.$calendarId.'-cal-'.constant('CDAV_URI_KEY')."\n";
} else {
$caldata .= "UID:".$obj->sourceuid."\n";
}
@@ -251,24 +251,24 @@ class CdavLib
*/
public function getFullCalendarObjects($calendarId, $bCalendarData)
{
- $calid = (int) $calendarId;
+ $calendarId = (int) $calendarId;
$calevents = array();
if (!$this->user->rights->agenda->myactions->read) {
return $calevents;
}
- if ($calid != $this->user->id && (!isset($this->user->rights->agenda->allactions->read) || !$this->user->rights->agenda->allactions->read)) {
+ if ($calendarId != $this->user->id && (!isset($this->user->rights->agenda->allactions->read) || !$this->user->rights->agenda->allactions->read)) {
return $calevents;
}
- $sql = $this->getSqlCalEvents($calid);
+ $sql = $this->getSqlCalEvents($calendarId);
$result = $this->db->query($sql);
if ($result) {
while ($obj = $this->db->fetch_object($result)) {
- $calendardata = $this->toVCalendar($calid, $obj);
+ $calendardata = $this->toVCalendar($calendarId, $obj);
if ($bCalendarData) {
$calevents[] = array(
diff --git a/htdocs/eventorganization/class/conferenceorboothattendee.class.php b/htdocs/eventorganization/class/conferenceorboothattendee.class.php
index dbec03466ae..a7c34d2243b 100644
--- a/htdocs/eventorganization/class/conferenceorboothattendee.class.php
+++ b/htdocs/eventorganization/class/conferenceorboothattendee.class.php
@@ -301,7 +301,7 @@ class ConferenceOrBoothAttendee extends CommonObject
$result = $this->createCommon($user, $notrigger);
if ($result > 0) {
$result = $this->fetch($result);
- if ($result > 0) {
+ if ($result > 0 && empty($this->ref)) {
$this->ref = (string) $this->id;
$result = $this->update($user);
}
diff --git a/htdocs/fichinter/card.php b/htdocs/fichinter/card.php
index 869d6b0371a..94ba5059594 100644
--- a/htdocs/fichinter/card.php
+++ b/htdocs/fichinter/card.php
@@ -967,12 +967,14 @@ $help_url = 'EN:Module_Interventions|FR:Module_Fiches_d\'interventions';
llxHeader('', $title, $help_url, '', 0, 0, '', '', '', 'mod-fichinter page-card');
+// Create new intervention
if ($action == 'create') {
- // Create new intervention
-
$soc = new Societe($db);
+ if ($socid > 0) {
+ $soc->fetch($socid);
+ }
- print load_fiche_titre($langs->trans("AddIntervention"), '', 'intervention');
+ print load_fiche_titre($langs->trans("NewIntervention"), '', 'intervention');
if ($error > 0) {
dol_htmloutput_errors($mesg);
@@ -980,10 +982,6 @@ if ($action == 'create') {
dol_htmloutput_mesg($mesg);
}
- if ($socid) {
- $res = $soc->fetch($socid);
- }
-
if (GETPOST('origin', 'alphanohtml') && GETPOSTINT('originid')) {
// Parse element/subelement (ex: project_task)
$regs = array();
@@ -1036,6 +1034,8 @@ if ($action == 'create') {
}
} else {
$projectid = GETPOSTINT('projectid');
+ $note_private = GETPOST("note_private", "alpha");
+ $note_public = GETPOST("note_public", "alpha");
}
if (!$conf->global->FICHEINTER_ADDON) {
@@ -1051,206 +1051,192 @@ if ($action == 'create') {
//$modFicheinter = new $obj;
//$numpr = $modFicheinter->getNextValue($soc, $object);
+ print '
';
} elseif ($id > 0 || !empty($ref)) {
// View mode
diff --git a/htdocs/fourn/card.php b/htdocs/fourn/card.php
index a4e410e1dbe..5bb362af0a8 100644
--- a/htdocs/fourn/card.php
+++ b/htdocs/fourn/card.php
@@ -7,7 +7,7 @@
* Copyright (C) 2014 Jean Heimburger
* Copyright (C) 2015 Marcos García
* Copyright (C) 2015 Raphaël Doursenaud
- * Copyright (C) 2021-2025 Frédéric France
+ * Copyright (C) 2021-2026 Frédéric France
* Copyright (C) 2024-2026 MDW
* Copyright (C) 2024 Alexandre Spangaro
*
@@ -33,6 +33,15 @@
// Load Dolibarr environment
require '../main.inc.php';
+/**
+ * @var Conf $conf
+ * @var DoliDB $db
+ * @var ExtraFields $extrafields
+ * @var HookManager $hookmanager
+ * @var Societe $mysoc
+ * @var Translate $langs
+ * @var User $user
+ */
require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.class.php';
require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture-rec.class.php';
@@ -40,7 +49,6 @@ require_once DOL_DOCUMENT_ROOT.'/supplier_proposal/class/supplier_proposal.class
require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
-require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
if (isModEnabled('member')) {
require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
}
@@ -49,15 +57,6 @@ if (isModEnabled('accounting')) {
require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingaccount.class.php';
}
-/**
- * @var Conf $conf
- * @var DoliDB $db
- * @var HookManager $hookmanager
- * @var Societe $mysoc
- * @var Translate $langs
- * @var User $user
- */
-
// Load translation files required by page
$langs->loadLangs(array('accountancy', 'companies', 'suppliers', 'products', 'bills', 'orders', 'commercial'));
@@ -75,7 +74,6 @@ $hookmanager->initHooks(array('thirdpartysupplier', 'globalcard'));
$result = restrictedArea($user, 'societe&fournisseur', $id, '&societe', '', 'rowid');
$object = new Fournisseur($db);
-$extrafields = new ExtraFields($db);
// fetch optionals attributes and labels
$extrafields->fetch_name_optionals_label($object->table_element);
diff --git a/htdocs/fourn/class/fournisseur.orderline.class.php b/htdocs/fourn/class/fournisseur.orderline.class.php
index 10b3449fd7b..9603c0f03a7 100644
--- a/htdocs/fourn/class/fournisseur.orderline.class.php
+++ b/htdocs/fourn/class/fournisseur.orderline.class.php
@@ -171,12 +171,12 @@ class CommandeFournisseurLigne extends CommonOrderLine
{
$sql = 'SELECT cd.rowid, cd.fk_commande, cd.fk_product, cd.product_type, cd.description, cd.qty, cd.tva_tx, cd.special_code,';
$sql .= ' cd.localtax1_tx, cd.localtax2_tx, cd.localtax1_type, cd.localtax2_type, cd.ref as ref_supplier,';
- $sql .= ' cd.remise, cd.remise_percent, cd.subprice,';
+ $sql .= ' cd.remise, cd.remise_percent, cd.subprice, cd.subprice_ttc,';
$sql .= ' cd.info_bits, cd.total_ht, cd.total_tva, cd.total_ttc,';
$sql .= ' cd.total_localtax1, cd.total_localtax2,';
$sql .= ' p.ref as product_ref, p.label as product_label, p.description as product_desc,';
$sql .= ' cd.date_start, cd.date_end, cd.fk_unit, cd.extraparams,';
- $sql .= ' cd.multicurrency_subprice, cd.multicurrency_total_ht, cd.multicurrency_total_tva, cd.multicurrency_total_ttc,';
+ $sql .= ' cd.multicurrency_subprice, cd.multicurrency_subprice_ttc, cd.multicurrency_total_ht, cd.multicurrency_total_tva, cd.multicurrency_total_ttc,';
$sql .= ' c.fk_soc as socid';
$sql .= ' FROM '.$this->db->prefix().'commande_fournisseur as c, '.$this->db->prefix().'commande_fournisseurdet as cd';
$sql .= ' LEFT JOIN '.$this->db->prefix().'product as p ON cd.fk_product = p.rowid';
diff --git a/htdocs/holiday/card.php b/htdocs/holiday/card.php
index b891673854b..7c6e3929aa5 100644
--- a/htdocs/holiday/card.php
+++ b/htdocs/holiday/card.php
@@ -538,14 +538,18 @@ if (empty($reshook)) {
}
// option to notify the validator if the balance is less than the request
+ // (only for leave types that actually use the balance counter)
if (!getDolGlobalString('HOLIDAY_HIDE_APPROVER_ABOUT_NEGATIVE_BALANCE')) {
- $tmpUser = new User($db);
- $tmpUser->fetch($object->fk_user);
+ $affectingtypes = $object->getTypes(1, 1);
+ if (!empty($affectingtypes[$object->fk_type])) {
+ $tmpUser = new User($db);
+ $tmpUser->fetch($object->fk_user);
- $nbopenedday = num_open_day($object->date_debut_gmt, $object->date_fin_gmt, 0, 1, $object->halfday, $tmpUser->country_id, $object->fk_user);
+ $nbopenedday = num_open_day($object->date_debut_gmt, $object->date_fin_gmt, 0, 1, $object->halfday, $tmpUser->country_id, $object->fk_user);
- if ($nbopenedday > $object->getCPforUser($object->fk_user, $object->fk_type)) {
- $message .= "".$langs->transnoentities("HolidaysToValidateAlertSolde")."
\n";
+ if ($nbopenedday > $object->getCPforUser($object->fk_user, $object->fk_type)) {
+ $message .= "".$langs->transnoentities("HolidaysToValidateAlertSolde")."
\n";
+ }
}
}
diff --git a/htdocs/holiday/card_group.php b/htdocs/holiday/card_group.php
index ca6e1c8af7d..c598a1d31ad 100644
--- a/htdocs/holiday/card_group.php
+++ b/htdocs/holiday/card_group.php
@@ -760,11 +760,15 @@ function sendMail($id, $cancreate, $now, $autoValidation)
}
// option to notify the validator if the balance is less than the request
+ // (only for leave types that actually use the balance counter)
if (!getDolGlobalString('HOLIDAY_HIDE_APPROVER_ABOUT_NEGATIVE_BALANCE')) {
- $nbopenedday = num_open_day($object->date_debut_gmt, $object->date_fin_gmt, 0, 1, $object->halfday, $expediteur->country_id, $object->fk_user);
+ $affectingtypes = $object->getTypes(1, 1);
+ if (!empty($affectingtypes[$object->fk_type])) {
+ $nbopenedday = num_open_day($object->date_debut_gmt, $object->date_fin_gmt, 0, 1, $object->halfday, $expediteur->country_id, $object->fk_user);
- if ($nbopenedday > $object->getCPforUser($object->fk_user, $object->fk_type)) {
- $message .= "".$langs->transnoentities("HolidaysToValidateAlertSolde")."
\n";
+ if ($nbopenedday > $object->getCPforUser($object->fk_user, $object->fk_type)) {
+ $message .= "".$langs->transnoentities("HolidaysToValidateAlertSolde")."
\n";
+ }
}
}
diff --git a/htdocs/install/mysql/data/llx_c_chargesociales.sql b/htdocs/install/mysql/data/llx_c_chargesociales.sql
index 95eb0daa3e6..f7ec00f70ba 100644
--- a/htdocs/install/mysql/data/llx_c_chargesociales.sql
+++ b/htdocs/install/mysql/data/llx_c_chargesociales.sql
@@ -59,6 +59,22 @@ insert into llx_c_chargesociales (fk_pays, id, libelle, deductible, active, code
insert into llx_c_chargesociales (fk_pays, id, libelle, deductible, active, code) values (2, 220, 'Prime existence', 1,1,'TAXBEPRIEXI');
insert into llx_c_chargesociales (fk_pays, id, libelle, deductible, active, code) values (2, 230, 'Precompte immobilier', 1,1,'TAXBEPREIMMO');
+--
+-- Switzerland
+--
+
+insert into llx_c_chargesociales (fk_pays, id, libelle, deductible, active, code) values (6, 600, 'AVS / AI / APG (Basic social contributions grouped)', 1, 1, 'TAXCHBASE');
+insert into llx_c_chargesociales (fk_pays, id, libelle, deductible, active, code) values (6, 601, 'Old-age insurance (AVS)', 1, 1, 'TAXCHAVS');
+insert into llx_c_chargesociales (fk_pays, id, libelle, deductible, active, code) values (6, 602, 'Disability insurance (AI)', 1, 1, 'TAXCHAI');
+insert into llx_c_chargesociales (fk_pays, id, libelle, deductible, active, code) values (6, 603, 'Income compensation allowance (APG)', 1, 1, 'TAXCHAPG');
+insert into llx_c_chargesociales (fk_pays, id, libelle, deductible, active, code) values (6, 604, 'Family allowances (CAF)', 1, 1, 'TAXCHAC');
+insert into llx_c_chargesociales (fk_pays, id, libelle, deductible, active, code) values (6, 605, 'Unemployment insurance (AC)', 1, 1, 'TAXCHACHO');
+insert into llx_c_chargesociales (fk_pays, id, libelle, deductible, active, code) values (6, 606, 'Occupational pension plan (LPP / 2nd pillar)', 1, 1, 'TAXCHLPP');
+insert into llx_c_chargesociales (fk_pays, id, libelle, deductible, active, code) values (6, 607, 'Occupational accident insurance (LAA - employer share)', 1, 1, 'TAXCHAA');
+insert into llx_c_chargesociales (fk_pays, id, libelle, deductible, active, code) values (6, 608, 'Non-occupational accident insurance (LAA - employer share)', 1, 1, 'TAXCHAA-NP');
+insert into llx_c_chargesociales (fk_pays, id, libelle, deductible, active, code) values (6, 609, 'Health insurance (LAMal - optional employer contribution)', 1, 1, 'TAXCHLAMAL');
+insert into llx_c_chargesociales (fk_pays, id, libelle, deductible, active, code) values (6, 610, 'Withholding tax (employees taxed at source)', 1, 1, 'TAXCHIS');
+
--
-- Austria
--
diff --git a/htdocs/install/mysql/migration/23.0.0-24.0.0.sql b/htdocs/install/mysql/migration/23.0.0-24.0.0.sql
index 1090814360f..349fda9fa96 100644
--- a/htdocs/install/mysql/migration/23.0.0-24.0.0.sql
+++ b/htdocs/install/mysql/migration/23.0.0-24.0.0.sql
@@ -530,4 +530,17 @@ ALTER TABLE llx_product_warehouse_properties ADD INDEX idx_product_warehouse_pro
ALTER TABLE llx_product_warehouse_properties ADD CONSTRAINT fk_product_warehouse_properties_fk_product FOREIGN KEY (fk_product) REFERENCES llx_product (rowid);
ALTER TABLE llx_product_warehouse_properties ADD CONSTRAINT fk_product_warehouse_properties_fk_entrepot FOREIGN KEY (fk_entrepot) REFERENCES llx_entrepot (rowid);
+-- Add extrafields on various payment
+CREATE TABLE llx_payment_various_extrafields
+(
+ rowid integer AUTO_INCREMENT PRIMARY KEY,
+ tms timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ fk_object integer NOT NULL,
+ import_key varchar(14) -- import key
+) ENGINE=innodb;
+
+ALTER TABLE llx_payment_various_extrafields ADD UNIQUE INDEX uk_payment_various_extrafields (fk_object);
+
+ALTER TABLE llx_actioncomm ADD COLUMN max_participants integer DEFAULT NULL AFTER status;
+ALTER TABLE llx_actioncomm ADD INDEX idx_actioncomm_max_participants (max_participants);
-- end of migration
diff --git a/htdocs/install/mysql/tables/llx_actioncomm.key.sql b/htdocs/install/mysql/tables/llx_actioncomm.key.sql
index 452a81dbf21..bee117d626d 100644
--- a/htdocs/install/mysql/tables/llx_actioncomm.key.sql
+++ b/htdocs/install/mysql/tables/llx_actioncomm.key.sql
@@ -30,5 +30,6 @@ ALTER TABLE llx_actioncomm ADD INDEX idx_actioncomm_ref_ext (ref_ext);
ALTER TABLE llx_actioncomm ADD INDEX idx_actioncomm_percent (percent);
ALTER TABLE llx_actioncomm ADD INDEX idx_actioncomm_ref (ref, entity);
+ALTER TABLE llx_actioncomm ADD INDEX idx_actioncomm_max_participants (max_participants);
-- To test performance to get fast next num on actioncomm
-- ALTER TABLE llx_actioncomm ADD INDEX idx_actioncomm_entity_id (entity, id);
diff --git a/htdocs/install/mysql/tables/llx_actioncomm.sql b/htdocs/install/mysql/tables/llx_actioncomm.sql
index aab0efb1090..dd220a17ec6 100644
--- a/htdocs/install/mysql/tables/llx_actioncomm.sql
+++ b/htdocs/install/mysql/tables/llx_actioncomm.sql
@@ -76,6 +76,7 @@ create table llx_actioncomm
num_vote integer DEFAULT NULL, -- use for Event Organization module
event_paid smallint NOT NULL DEFAULT 0, -- use for Event Organization module
status smallint NOT NULL DEFAULT 0, -- use for Event Organization module for now, but could be use after for event global status
+ max_participants integer DEFAULT NULL, -- Maximum number of participants allowed for this action (event, meeting, shift)
fk_element integer DEFAULT NULL, -- For link to an element (proposal, invoice, order, ...)
elementtype varchar(255) DEFAULT NULL, -- For link to an element (proposal, invoice, order, ...)
diff --git a/htdocs/install/mysql/tables/llx_payment_various_extrafields.key.sql b/htdocs/install/mysql/tables/llx_payment_various_extrafields.key.sql
new file mode 100644
index 00000000000..3760942ddce
--- /dev/null
+++ b/htdocs/install/mysql/tables/llx_payment_various_extrafields.key.sql
@@ -0,0 +1,21 @@
+-- ===================================================================
+-- Copyright (C) 2013 Jean-Francois FERRY
+-- Copyright (C) 2026 Solution Libre SAS
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see .
+--
+-- ===================================================================
+
+
+ALTER TABLE llx_payment_various_extrafields ADD UNIQUE INDEX uk_payment_various_extrafields (fk_object);
diff --git a/htdocs/install/mysql/tables/llx_payment_various_extrafields.sql b/htdocs/install/mysql/tables/llx_payment_various_extrafields.sql
new file mode 100644
index 00000000000..187ac399885
--- /dev/null
+++ b/htdocs/install/mysql/tables/llx_payment_various_extrafields.sql
@@ -0,0 +1,26 @@
+-- ===================================================================
+-- Copyright (C) 2013 Jean-Francois FERRY
+-- Copyright (C) 2026 Solution Libre SAS
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see .
+--
+-- ===================================================================
+
+CREATE TABLE llx_payment_various_extrafields
+(
+ rowid integer AUTO_INCREMENT PRIMARY KEY,
+ tms timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ fk_object integer NOT NULL,
+ import_key varchar(14) -- import key
+) ENGINE=innodb;
diff --git a/htdocs/install/mysql/tables/llx_product_warehouse_properties-stock.key.sql b/htdocs/install/mysql/tables/llx_product_warehouse_properties-stock.key.sql
index 0f60c355e8b..7f0f91e3f75 100644
--- a/htdocs/install/mysql/tables/llx_product_warehouse_properties-stock.key.sql
+++ b/htdocs/install/mysql/tables/llx_product_warehouse_properties-stock.key.sql
@@ -20,4 +20,4 @@ ALTER TABLE llx_product_warehouse_properties ADD INDEX idx_product_warehouse_pro
ALTER TABLE llx_product_warehouse_properties ADD INDEX idx_product_warehouse_properties_fk_entrepot (fk_entrepot);
ALTER TABLE llx_product_warehouse_properties ADD CONSTRAINT fk_product_warehouse_properties_fk_product FOREIGN KEY (fk_product) REFERENCES llx_product (rowid);
-ALTER TABLE llx_product_warehouse_properties ADD CONSTRAINT fk_product_warehouse_properties_fk_entrepot FOREIGN KEY (fk_entrepot) REFERENCES llx_entrepot (rowid);
\ No newline at end of file
+ALTER TABLE llx_product_warehouse_properties ADD CONSTRAINT fk_product_warehouse_properties_fk_entrepot FOREIGN KEY (fk_entrepot) REFERENCES llx_entrepot (rowid);
diff --git a/htdocs/install/repair.php b/htdocs/install/repair.php
index 89eab5a6bcc..bd4d30bd477 100644
--- a/htdocs/install/repair.php
+++ b/htdocs/install/repair.php
@@ -1,13 +1,14 @@
- * Copyright (C) 2004-2012 Laurent Destailleur
- * Copyright (C) 2005-2012 Regis Houssin
- * Copyright (C) 2015 Raphaël Doursenaud
- * Copyright (C) 2021-2025 Frédéric France
- * Copyright (C) 2023 Gauthier VERDOL
- * Copyright (C) 2024-2026 MDW
- * Copyright (C) 2024 Vincent de Grandpré
- * Copyright (C) 2025 Alexandre Spangaro
+/* Copyright (C) 2004 Rodolphe Quiedeville
+ * Copyright (C) 2004-2012 Laurent Destailleur
+ * Copyright (C) 2005-2012 Regis Houssin
+ * Copyright (C) 2015 Raphaël Doursenaud
+ * Copyright (C) 2021-2025 Frédéric France
+ * Copyright (C) 2023 Gauthier VERDOL
+ * Copyright (C) 2024-2026 MDW
+ * Copyright (C) 2024 Vincent de Grandpré
+ * Copyright (C) 2025 Alexandre Spangaro
+ * Copyright (C) 2026 Solution Libre SAS
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -414,7 +415,7 @@ if ($ok && GETPOST('standard', 'alpha')) {
'fichinter' => 'fichinter', 'fichinterdet' => 'fichinterdet',
'inventory' => 'inventory',
'actioncomm' => 'actioncomm', 'bom_bom' => 'bom_bom', 'mrp_mo' => 'mrp_mo',
- 'adherent_type' => 'adherent_type', 'user' => 'user', 'partnership' => 'partnership', 'projet' => 'projet', 'projet_task' => 'projet_task', 'ticket' => 'ticket');
+ 'adherent_type' => 'adherent_type', 'user' => 'user', 'partnership' => 'partnership', 'projet' => 'projet', 'projet_task' => 'projet_task', 'ticket' => 'ticket', 'payment_various' => 'payment_various');
//$listofmodulesextra = array('fichinter'=>'fichinter');
print ' *** Check that fields into the extra table structure match the table of definition. If not, add column into table |
';
diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang
index 9bfda85b1d9..607c2517949 100644
--- a/htdocs/langs/en_US/admin.lang
+++ b/htdocs/langs/en_US/admin.lang
@@ -2825,7 +2825,7 @@ ViewLogs=View Logs
DisableMCPAI=Turn off to completely disable AI access to MCP server
EnableMCPServer=Enable MCP Server
EnableLogging=Enable Request Logging
-ObfuscatePIIData=Obfuscate PII Data
+ObfuscatePIIData=Obfuscate Prompt Data
AIRequestLogs=AI Request Logs
ErrorTableNotExists=Table %s does not exist
PleaseRunSQLToEnableLogging=Please run the following SQL to enable logging
diff --git a/htdocs/langs/en_US/main.lang b/htdocs/langs/en_US/main.lang
index 319f95574bf..745792cd4af 100644
--- a/htdocs/langs/en_US/main.lang
+++ b/htdocs/langs/en_US/main.lang
@@ -1436,3 +1436,4 @@ Delay=Delay
RefOfOnCustomerSide=Reference of %s on customer side
RefOfOnVendorSide=Reference of %s on vendor side
SeeDocumentation=See documentation
+AIAssistant=AI Assistant
diff --git a/htdocs/langs/en_US/other.lang b/htdocs/langs/en_US/other.lang
index 966b980b345..fefc5b7c9af 100644
--- a/htdocs/langs/en_US/other.lang
+++ b/htdocs/langs/en_US/other.lang
@@ -419,7 +419,6 @@ AIWelcomeMessage=Hi! I'm your Dolibarr assistant. How can I help you today?
ErrorThirdPartyNotFound=Error ThirdParty Not Found
TotalValue=Total Value
Expenses=Expenses
-AIAssistant=AI Assistant
ClearChatHistoryTitle=Clear Chat History
Clear=Clear
OptionTextOnly=Text Only
diff --git a/htdocs/main.inc.php b/htdocs/main.inc.php
index e63b1517ff2..cd6dc55dc06 100644
--- a/htdocs/main.inc.php
+++ b/htdocs/main.inc.php
@@ -2261,14 +2261,17 @@ function top_menu($head, $title = '', $target = '', $disablejs = 0, $disablehead
$toprightmenu .= top_menu_search();
}
+ // Add AI picto
+ $toprightmenu .= top_menu_ai();
+
+ // Add bookmark dropdown
+ $toprightmenu .= top_menu_bookmark();
+
if (getDolGlobalString('MAIN_USE_TOP_MENU_QUICKADD_DROPDOWN')) {
// Add the quick add object dropdown
$toprightmenu .= top_menu_quickadd();
}
- // Add bookmark dropdown
- $toprightmenu .= top_menu_bookmark();
-
if (getDolGlobalString('MAIN_USE_TOP_MENU_IMPORT_FILE')) {
// Add the import file link
$toprightmenu .= top_menu_importfile();
@@ -2710,6 +2713,33 @@ function top_menu_user($hideloginname = 0, $urllogout = '')
return $btnUser;
}
+/**
+ * Build the tooltip on top menu quick add.
+ * Called when option MAIN_USE_TOP_MENU_QUICKADD_DROPDOWN is set
+ *
+ * @return string HTML content
+ */
+function top_menu_ai()
+{
+ global $conf, $langs;
+
+ // Button disabled on text browser
+ /*if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
+ return '';
+ }*/
+
+ $html = '';
+
+ if (isModEnabled('ai')) {
+ $html .= '
+ ';
+ }
+
+ return $html;
+}
+
/**
* Build the tooltip on top menu quick add.
* Called when option MAIN_USE_TOP_MENU_QUICKADD_DROPDOWN is set
@@ -2730,7 +2760,7 @@ function top_menu_quickadd()
if (!empty($conf->use_javascript_ajax)) {
$html .= '
';
if (!defined('JS_JQUERY_DISABLE_DROPDOWN')) { // This may be set by some pages that use different jquery version to avoid errors
diff --git a/htdocs/modulebuilder/template/stats/myobject_index.php b/htdocs/modulebuilder/template/stats/myobject_index.php
index 55d542a7895..bb673216be3 100644
--- a/htdocs/modulebuilder/template/stats/myobject_index.php
+++ b/htdocs/modulebuilder/template/stats/myobject_index.php
@@ -174,8 +174,10 @@ $fileurlnb = DOL_URL_ROOT.'/viewimage.php?modulepart=orderstats&file=ordersnbiny
$px1 = new DolGraph();
+$displaypx1 = false;
$mesg = $px1->isGraphKo();
if (!$mesg) {
+ $displaypx1 = true;
$px1->SetData($data);
$i = $startyear;
$legend = array();
@@ -225,8 +227,10 @@ if (!$user->hasRight('societe', 'client', 'voir')) {
}
$px2 = new DolGraph();
+$displaypx2 = false;
$mesg = $px2->isGraphKo();
if (!$mesg) {
+ $displaypx2 = true;
$px2->SetData($data);
$i = $startyear;
$legend = array();
@@ -273,8 +277,10 @@ if (!$user->hasRight('societe', 'client', 'voir')) {
}
$px3 = new DolGraph();
+$displaypx3 = false;
$mesg = $px3->isGraphKo();
if (!$mesg) {
+ $displaypx3 = true;
$px3->SetData($data);
$i = $startyear;
$legend = array();
@@ -435,16 +441,16 @@ print '\n";
}
/*
- if (isset($px2)) {
+ if ($displaypx2) {
print $px2->show();
print " \n";
}
- if (isset($px2)) {
+ if ($displaypx3) {
print $px3->show();
print " \n";
}
diff --git a/htdocs/projet/card.php b/htdocs/projet/card.php
index f39a27b6162..e9382424b51 100644
--- a/htdocs/projet/card.php
+++ b/htdocs/projet/card.php
@@ -503,6 +503,8 @@ if (empty($reshook)) {
if ($result <= 0) {
setEventMessages($object->error, $object->errors, 'errors');
$action = '';
+ } else {
+ setEventMessages($langs->trans("FileGenerated"), null, 'mesgs');
}
}
diff --git a/htdocs/reception/card.php b/htdocs/reception/card.php
index e023df29b7e..1d6e3cfef04 100644
--- a/htdocs/reception/card.php
+++ b/htdocs/reception/card.php
@@ -1612,7 +1612,27 @@ if ($action == 'create' && $permissiontoadd) {
if ($reshook < 0) {
setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
} elseif (empty($reshook)) {
- $dispatchLines = array_merge($dispatchLines, $hookmanager->resArray);
+ // Only merge if resArray is a valid, non-empty array
+ if (is_array($hookmanager->resArray) && !empty($hookmanager->resArray)) {
+ // Check if the merge would overwrite valid data with NULL
+ $tempMerged = array_merge($dispatchLines, $hookmanager->resArray);
+
+ // Sanity check: ensure our existing keys are still valid arrays
+ $corrupted = false;
+ foreach ($dispatchLines as $idx => $val) {
+ if (!is_array($tempMerged[$idx]) || !isset($tempMerged[$idx]['fk_commandefourndet'])) {
+ $corrupted = true;
+ break;
+ }
+ }
+
+ if (!$corrupted) {
+ $dispatchLines = $tempMerged;
+ } else {
+ // If merge corrupted data, ignore the hook result and keep original
+ error_log("WARNING: Hook dataProcessing returned invalid data, ignoring merge.");
+ }
+ }
} elseif ($reshook > 0) {
// $resArray starts from [0], we need $dispatchLines to start from [1], so we shift it
$dispatchLines = $hookmanager->resArray;
@@ -1622,7 +1642,7 @@ if ($action == 'create' && $permissiontoadd) {
}
print '';
+ });
+ ';
print ' ';
@@ -2526,7 +2546,7 @@ if ($action == 'create' && $permissiontoadd) {
// Get list of products already sent for same source object into $alreadysent
$alreadysent = array();
- if (empty($origin)) {
+ if (empty($origin) || $origin == 'order_supplier') {
$origin = 'supplier_order';
}
diff --git a/htdocs/societe/card.php b/htdocs/societe/card.php
index 4c28f86c02e..eee2f624182 100644
--- a/htdocs/societe/card.php
+++ b/htdocs/societe/card.php
@@ -3482,6 +3482,7 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($canvasdisplayactio
if ($result > 0) {
$adh->ref = $adh->getFullName($langs);
print $adh->getNomUrl(-1);
+ print ' — '.$adh->getLibStatut(0);
} else {
print ''.$langs->trans("ThirdpartyNotLinkedToMember").'';
}
diff --git a/htdocs/societe/class/societe.class.php b/htdocs/societe/class/societe.class.php
index 5a7aef0f4bc..75400fef6d7 100644
--- a/htdocs/societe/class/societe.class.php
+++ b/htdocs/societe/class/societe.class.php
@@ -1024,8 +1024,14 @@ class Societe extends CommonObject
$this->code_compta_client = trim($this->code_compta_client ?? '');
$this->accountancy_code_customer_general = trim($this->accountancy_code_customer_general ?? '');
+ if ($this->accountancy_code_customer_general === '-1') {
+ $this->accountancy_code_customer_general = '';
+ }
$this->accountancy_code_customer = trim((string) $this->code_compta_client);
$this->accountancy_code_supplier_general = trim($this->accountancy_code_supplier_general ?? '');
+ if ($this->accountancy_code_supplier_general === '-1') {
+ $this->accountancy_code_supplier_general = '';
+ }
$this->accountancy_code_supplier = trim((string) $this->code_compta_fournisseur);
$this->accountancy_code_buy = trim((string) $this->accountancy_code_buy);
$this->accountancy_code_sell = trim((string) $this->accountancy_code_sell);
@@ -1537,8 +1543,14 @@ class Societe extends CommonObject
}
$this->accountancy_code_customer_general = trim((string) $this->accountancy_code_customer_general);
+ if ($this->accountancy_code_customer_general === '-1') {
+ $this->accountancy_code_customer_general = '';
+ }
$this->code_compta_client = trim((string) $this->code_compta_client);
$this->accountancy_code_supplier_general = trim((string) $this->accountancy_code_supplier_general);
+ if ($this->accountancy_code_supplier_general === '-1') {
+ $this->accountancy_code_supplier_general = '';
+ }
$this->code_compta_fournisseur = trim((string) $this->code_compta_fournisseur);
// Check parameters. More tests are done later in the ->verify()
diff --git a/htdocs/takepos/invoice.php b/htdocs/takepos/invoice.php
index 11782ff9fc4..4663bc4d58a 100644
--- a/htdocs/takepos/invoice.php
+++ b/htdocs/takepos/invoice.php
@@ -351,7 +351,8 @@ if (empty($reshook)) {
// Add the payment
if (!$error && $res >= 0) {
$remaintopay = $invoice->getRemainToPay();
- if ($remaintopay > 0) {
+ // Credit notes have negative remaintopay; regular invoices have positive
+ if (($remaintopay > 0 && $invoice->type != Facture::TYPE_CREDIT_NOTE) || ($remaintopay < 0 && $invoice->type == Facture::TYPE_CREDIT_NOTE)) {
$payment = new Paiement($db);
$payment->datepaye = $now;
diff --git a/htdocs/theme/eldy/dropdown.inc.php b/htdocs/theme/eldy/dropdown.inc.php
index cdbc21f1acc..0022849ce7b 100644
--- a/htdocs/theme/eldy/dropdown.inc.php
+++ b/htdocs/theme/eldy/dropdown.inc.php
@@ -330,7 +330,7 @@ a.top-menu-dropdown-link {
border-radius: 0;
}
-
+#topmenu-tool,
#topmenu-global-search-dropdown,
#topmenu-quickadd-dropdown,
#topmenu-bookmark-dropdown,
diff --git a/htdocs/theme/md/dropdown.inc.php b/htdocs/theme/md/dropdown.inc.php
index 1d30b792077..8776970fd8d 100644
--- a/htdocs/theme/md/dropdown.inc.php
+++ b/htdocs/theme/md/dropdown.inc.php
@@ -51,7 +51,7 @@ button.dropdown-item.global-search-item {
display: block;
}
-
+#topmenu-tool a,
#topmenu-global-search-dropdown a.login-dropdown-a,
#topmenu-quickadd-dropdown a.login-dropdown-a,
#topmenu-bookmark-dropdown a.login-dropdown-a,
@@ -347,7 +347,7 @@ a.top-menu-dropdown-link {
border-radius: 0;
}
-
+#topmenu-tool,
#topmenu-login-dropdown,
#topmenu-quickadd-dropdown,
#topmenu-bookmark-dropdown,
diff --git a/htdocs/ticket/stats/index.php b/htdocs/ticket/stats/index.php
index 37dd4c898bf..e4af4203f23 100644
--- a/htdocs/ticket/stats/index.php
+++ b/htdocs/ticket/stats/index.php
@@ -1,7 +1,7 @@
- * Copyright (C) 2024-2025 MDW
- * Copyright (C) 2024-2025 Frédéric France
+/* Copyright (C) 2019 Laurent Destailleur
+ * Copyright (C) 2024-2025 MDW |