Commit graph

154040 commits

Author SHA1 Message Date
MDW
18b7fa0fd4
FIX: Add Ghostscript installation and caching for Windows CI (#38325)
* Exclude doctemplates as DB dependencies

* FIX: Add Ghostscript installation and caching for Windows CI

# FIX: Add Ghostscript installation and caching for Windows CI

Ghostscript is necessary for one of the tests that converts an image into a PDF.
This commit adds the necessary steps to install Ghostscript and cache it for the Windows CI workflow.
2026-05-18 19:44:48 +02:00
VIAL-GOUTEYRON Quentin
110b35cba6
NEW Specify If the Object Manages Lines for Module Builder (#32664)
* Specify If the Object Manages Lines for Module Builder

* Update htdocs/modulebuilder/index.php

* Update myobject.class.php

* Update myobject.class.php

* Update myobject.class.php

* Update myobject.class.php

* Update myobject.class.php

* Update myobject.class.php

* Update myobject.class.php

* Update myobject.class.php

* Fix modulebuilder CI issues

* Fix Phan PhanUndeclaredProperty errors on PR #32664

- pdf_standard_myobject: add @phan-suppress-current-line on situation_percent,
  localtax2_tx, localtax1_type, localtax2_type, vat_src_code, pagebreak
  (MyObjectLine template class does not declare these inherited properties)
- doc_generic_project_odt: replace fk_soc with socid (correct PHP property;
  fk_soc is the DB column name, Project::fetch() maps it to $this->socid)

---------

Co-authored-by: Laurent Destailleur <eldy@destailleur.fr>
2026-05-18 16:13:35 +02:00
Laurent Destailleur
7b1a93b1c2 Clean code 2026-05-18 14:03:44 +02:00
Laurent Destailleur
629c460a3a Fix duplicate css when duplicate events 2026-05-18 13:43:53 +02:00
Laurent Destailleur
1f021efaed Merge branch 'develop' of git@github.com:Dolibarr/dolibarr.git into develop 2026-05-18 13:05:54 +02:00
Laurent Destailleur
6be5bac0ed Clean code 2026-05-18 13:05:07 +02:00
Jon Bendtsen
40b4e8744f
Fix #37675 API Post eventattendee sets ref to same as id (#38274)
* Fix #37675 API Post eventattendee sets ref to same as id

* Move empty ref check after fetch #38274

---------

Co-authored-by: Jon Bendtsen <jonbendtsen@jonb.dk>
2026-05-18 12:07:50 +02:00
MDW
1b94023550
Qual: Better error message for missing translation (#38313)
# Qual: Better error message for missing translation

Update error message to include 'error - ' after the line:offset: text
to correspond to an emacs like error message recognized by logToCs
which allows it to appear as a github annotation
2026-05-18 03:52:53 +02:00
Alexandre SPANGARO
e452584659
NEW - Various payments - Add extrafield (#38260)
* NEW - Various payments - Add extrafield

* Fix wrong path

---------

Co-authored-by: Laurent Destailleur <eldy@destailleur.fr>
2026-05-18 03:27:35 +02:00
Alexandre SPANGARO
ffae6a7de4
NEW Contract - Add consolidated total (#38249)
* NEW Contract - Add consolidated total

* CI

* CI

* CI

* English
2026-05-18 03:16:32 +02:00
MDW
b4c025712c
Qual: Fix Phan notices observed in #38164 (#38231)
# Qual: Fix Phan notices observed in #38164

Notices appear in #38164 in unchanged files, probably because the analysis is more selective in PRs.
This fixes notices in the observed files
2026-05-18 03:08:39 +02:00
MDW
4b191b12b4
Qual: Upgrade tool versions in pre-commit setup (#38233)
* Qual: Upgrade tool versions in pre-commit

* Qual: avoid codespell notice

* Qual: Fix spelling

* Qual: Fix spelling

* Qual: Add spelling exceptions

* Qual: whitespace/line-ending
2026-05-18 03:05:44 +02:00
Alexandre SPANGARO
4932d5781f
NEW #35052 Add social contributions for Switzerland (#38236) 2026-05-18 03:03:59 +02:00
SINONIDRISSA
621f7394a1
FIX install crash when loading subtotals module (#38244)
Co-authored-by: Layidu System <layidu@srv1003773.hstgr.cloud>
2026-05-18 03:03:11 +02:00
MDW
24bba6caa9
Qual: Fix PHPStan for ldap, pgsql, odtphp (#38246)
# Qual: Fix PHPStan for ldap, pgsql, odtphp

- Adjust typing in ldap and pgsql class to fix PHPStan notices;
- Exclude all files for odtphp from analysis (external lib);
- Update PHPStan baseline.
2026-05-18 03:01:50 +02:00
Jon Bendtsen
a74de0be97
fix(action): map eventorganization permissions to projet for linked actions (#38253)
When creating or updating an action linked to an event organization element
(e.g., conferenceorboothattendee), the permission check was failing because
the module 'eventorganization' does not have its own 'read' right in the
standard permission matrix; it relies on the 'projet' (Project) module.

This change maps 'eventorganization' to 'projet' during the permission check,
aligning with how restrictedArea() handles this module.

Also refactors the existing 'productbatch' mapping to use a switch statement
for better readability and consistency across the three action blocks.

Co-authored-by: Jon Bendtsen <jonbendtsen@jonb.dk>
2026-05-18 02:59:42 +02:00
Jon Bendtsen
fe85114b37
FIX #37453 AJAX tooltip for project tasks always shows "Access Forbidden" for restricted users (#38262)
Co-authored-by: Jon Bendtsen <jonbendtsen@jonb.dk>
2026-05-18 02:55:36 +02:00
Jon Bendtsen
3e2830a5d8
feat(eventorganization): Add database schema for participant capacity (#38248)
- Add 'max_participants' column to llx_actioncomm table (nullable)
- Add index 'idx_actioncomm_max_participants' for performance optimization
- Update table definition and key files for fresh installs
- Update migration script for existing installations

This column defines the maximum number of participants allowed for a session.
NULL means unlimited. This is used for events, meetings, and volunteer shifts.

This commit only contains database structure changes (SQL files).
PHP logic and UI implementation will follow in subsequent PRs.

Fixes #38247

Co-authored-by: Jon Bendtsen <jonbendtsen@jonb.dk>
2026-05-18 02:46:49 +02:00
Frédéric FRANCE
33c7c1d0ad
clean code (#38265)
* clean code

* clean code

* clean code

* clean code

* clean code

* clean code
2026-05-18 02:43:24 +02:00
Jon Bendtsen
ad545b323c
Fix #38168 reception card supplier order errors (#38272)
* Fix reception card supplierorder errors

* Include subprice_ttc & multicurrency_subprice_ttc in the SQL because we assign them later, and that would give a PHP warning Undefined property

* Refactor origin handling in card.php

* Update card.php

---------

Co-authored-by: Jon Bendtsen <jonbendtsen@jonb.dk>
Co-authored-by: Laurent Destailleur <eldy@destailleur.fr>
2026-05-18 02:40:27 +02:00
Laurent Destailleur
4e01c0d163 CI 2026-05-18 02:39:13 +02:00
Laurent Destailleur
ca3f1be55a Merge branch 'develop' of git@github.com:Dolibarr/dolibarr.git into develop 2026-05-18 02:36:55 +02:00
Laurent Destailleur
a573a9c521 Merge branch '23.0' of git@github.com:Dolibarr/dolibarr.git into develop 2026-05-18 02:31:38 +02:00
Laurent Destailleur
f0234fa318 Merge branch '23.0' of git@github.com:Dolibarr/dolibarr.git into 23.0 2026-05-18 02:26:54 +02:00
Laurent Destailleur
76821f3c1d Merge branch '22.0' of git@github.com:Dolibarr/dolibarr.git into 23.0 2026-05-18 02:26:17 +02:00
Jon Bendtsen
6f5bf5c935
FIX #37327 There is no product description displayed in version 22 (#38267)
Co-authored-by: Jon Bendtsen <jonbendtsen@jonb.dk>
2026-05-18 02:22:16 +02:00
Yoan Mollard
8754884a24
fix: Inverted logical condition for showing TVAIsNotUsed only in crabe template (#38271)
Fixes bug introduced in #8e005b19c02435817ecf8207064fd8340245dcd5
2026-05-18 01:55:24 +02:00
Jon Bendtsen
29aa7648e8
Fix api post member subscription returns negative one (#38280)
* Fix #38278 POST to API /members/{id}/subscriptions returns -1

* return the id of the new subscription

---------

Co-authored-by: Jon Bendtsen <jonbendtsen@jonb.dk>
2026-05-18 01:41:32 +02:00
Joachim Kueter
6c342ef754
Fix accountancy_code_*_general stores '-1' from empty dropdown option (#38282)
The empty option in the supplier/customer general account dropdown gets
value='-1' from Form::selectarray. When the form is submitted, GETPOST
returns '-1' and Societe::create()/update() stores it as a string because
the SQL builder's !empty() check accepts '-1' as truthy.

The bookkeeping export in purchasesjournal.php and sellsjournal.php then
uses '-1' as the account code (only bankjournal.php has a != '-1' guard)
and the transfer fails.

Normalize '-1' to '' next to the existing trim() in create() and update()
for both accountancy_code_customer_general and accountancy_code_supplier_general.
The existing SQL !empty() checks then write NULL as intended, and rows
that already contain '-1' self-heal on the next update.
2026-05-18 01:34:28 +02:00
Jon Bendtsen
f0b6c2cc33
NEW Add label column to a members subscription list (#38289)
Co-authored-by: Jon Bendtsen <jonbendtsen@jonb.dk>
2026-05-18 01:25:13 +02:00
Jon Bendtsen
0d5225d9c8
NEW add label textline on massaction member subscription (#38288)
Co-authored-by: Jon Bendtsen <jonbendtsen@jonb.dk>
2026-05-18 01:20:02 +02:00
Jon Bendtsen
8dfeb69148
NEW Member subscription tooltip includes label (#38291)
* NEW Add label column to a members subscription list

* NEW add label to member subscription mouseover tooltip

* pre-commit fix by loading the correct language

---------

Co-authored-by: Jon Bendtsen <jonbendtsen@jonb.dk>
2026-05-18 01:19:29 +02:00
Jon Bendtsen
af300a9467
New add notrigger to member->validate() function (#38293)
Co-authored-by: Jon Bendtsen <jonbendtsen@jonb.dk>
2026-05-18 01:19:12 +02:00
Pichinov-Jose
a9fbc88b84
Qual: enrich UniversalLLMAdapter::curl error diagnostics (#38304)
Rebased on top of upstream commit 95b57550d3 ("Fix curl direct use
is forbidden. Must use getUrlContent()") which replaced the raw
curl_* calls in this method with getURLContent(). The diagnostics
this patch adds are re-implemented on top of the new array shape
returned by getURLContent().

When the LLM API returns a non-JSON body, the previous code surfaced
only the generic message:

    "Error: Invalid JSON response from API."

with no clue about what really happened. Common real-world causes
are: HTTP 4xx/5xx with empty body, HTML error page from a proxy,
gateway timeout, model not found, etc. None of these are
distinguishable from each other in the admin Log Viewer, so admins
had to re-run with curl by hand to diagnose.

This patch:

- Reads $result['http_code'] and $result['url'] (both populated by
  getURLContent() via curl_getinfo()) and stores an enriched payload
  in $this->lastResponse so the admin Log Viewer shows HTTP code +
  effective URL + body length + body contents.
- Returns a descriptive error message when the body is not valid
  JSON: includes the HTTP code, body length, and a 500-char body
  snippet (with the '<empty>' placeholder for zero-length bodies).
- Adds the cURL error number ($result['curl_error_no']) alongside
  the cURL error message in the network-level error message, with
  the effective URL for context.
- Restores the LLM-specific response timeout that was lost in the
  getURLContent() refactor: $this->timeout is now passed as the
  10th argument ($timeoutresponse) so the configured value is
  honored instead of falling back to MAIN_USE_RESPONSE_TIMEOUT
  (default 30s). This also fixes the phpstan warning
  "Property UniversalLLMAdapter::$timeout is never read, only
  written." that the upstream refactor introduced.

No behavioral change for successful calls. Strictly improves the
error-path diagnostics surfaced to administrators, and restores
the per-LLM configurable timeout.

Tested with: a misconfigured Google Gemini URL that returns HTTP
404 with an empty body now produces:

    Error: Invalid JSON response from API (HTTP 404, 0 bytes).
    Body snippet: <empty>

instead of the previous opaque message.
2026-05-18 01:18:27 +02:00
Pichinov-Jose
5d851934d5
Fix: Ai::generateContent uses Google Gemini native API for google provider (#38296)
The Ai class currently builds every outbound request in OpenAI's
chat/completions shape, regardless of the configured provider.
This works for OpenAI-compatible backends (chatgpt, mistral, groq,
custom) but breaks the 'google' provider, whose native API differs
on all four key dimensions:

- URL path: /v1beta/models/<model>:generateContent
  (not /v1beta/chat/completions)
- Payload root: 'contents' / 'parts' / optional 'system_instruction'
  (not 'messages')
- Auth header: x-goog-api-key
  (not Authorization: Bearer)
- Response shape: candidates[0].content.parts[*].text
  (not choices[0].message.content)

As a result, every call to Gemini via Ai::generateContent() ended
with HTTP 404 (wrong path) or unparsed response data.

This patch makes Ai::generateContent() emit the native Gemini shape
when $this->apiService === 'google':

1. URL: after $model is resolved, suffix
   /models/<urlencoded model>:generateContent
   (and skip the /chat/completions suffix entirely for google)

2. Payload:
     {
       "contents": [
         {"role": "user", "parts": [{"text": <full prompt>}]}
       ],
       "system_instruction": {"parts": [{"text": <pre-prompt>}]}
     }

3. Header: x-goog-api-key: <key> (no Bearer)

4. Response parsing: concatenate
   candidates[0].content.parts[*].text

All other providers go through the existing OpenAI-compat branches
unchanged. No behavioral change for chatgpt, mistral, groq,
anthropic-compat, or custom endpoints.

Tested with: gemini-2.5-flash end-to-end via the AI Assistant web
UI (textgeneration). HTTP 200 with valid JSON output.
2026-05-18 01:17:39 +02:00
Pichinov-Jose
cdaff51147
Fix: FactureFournisseur::addline parameter order in ToolCrudObjects (#38295)
Unlike Facture::addline() which takes ($desc, $pu, $qty, $txtva, ...),
FactureFournisseur::addline() uses a different parameter order:

  ($desc, $pu, $txtva, $txlocaltax1, $txlocaltax2, $qty,
   $fk_product, $remise_percent, ...)

i.e. $qty is in position 6, not 3.

ToolCrudObjects::processAddLine() was calling
FactureFournisseur::addline() with the Facture order, which produced:

- our $qty (1) passed as $txtva  -> effective VAT rate 1%
- our $vat (20) passed as $txlocaltax1 -> wrong local tax
- a hardcoded 0 passed as $qty -> the line was inserted with
  qty=0 and silently dropped from the visible totals

The result: every supplier invoice created via create_other_document
ended up with the header correctly created but a 0.00 EUR total,
with no error returned (lines_added was reported as success).

This patch reorders the parameters to match the actual
FactureFournisseur::addline() signature and adds an inline comment
to warn future maintainers about this Dolibarr API quirk.

Other addline calls in the same switch (invoice/order/proposal,
supplier_order/supplier_proposal) use their respective correct
signatures already and are unaffected.

Tested with: create_other_document object_type=supplier_invoice
with one line (qty=1, unit_price=10, vat_rate=20) -> line now
appears with Total HT 10.00 EUR.
2026-05-18 01:16:32 +02:00
Pichinov-Jose
0e591afe34
Fix: allow free-text invoice/order/proposal lines when no product matches (#38298)
ToolCrudObjects::processAddLine() uses the line's 'description' as a
fallback product identifier when 'product' is not explicitly provided.
It then calls findProduct() to look up an existing Dolibarr product
by ref/barcode/label.

When no product matches (the common case for AI-generated lines that
describe a one-off service or a custom item), findProduct() returns
an error array and the function aborts WITHOUT ever calling addline().
The resulting document gets its header created but ends up with zero
lines and a 0.00 total.

This is contrary to standard Dolibarr behavior: free-text line items
(no product link, just a description and a price) are a first-class
feature of invoices, orders, and proposals.

This patch distinguishes between the two cases:

- Caller explicitly passed 'product': they wanted a specific product
  -> still abort with the original error if not found (unchanged).

- Caller only passed 'description': it's a free-text line ->
  silently fall through with $prod = null. Dolibarr then creates a
  free-text line with the user-provided description, qty, unit_price
  and vat_rate.

Tested with: create_other_document object_type=proposal containing
11 line items, none of which match existing product references ->
all 11 lines are now created with their correct totals (previously
the document was created with 0 lines and a 0.00 total).
2026-05-18 01:16:01 +02:00
Pichinov-Jose
6ee5130f24
Fix: parse_intent.php model resolution (array default and wrong constant) (#38300)
Two bugs combined to make UniversalLLMAdapter::__construct() crash with:

  TypeError: Argument #4 ($model) must be of type string, array given

at parse_intent.php line 301 when the user-configured model wasn't
properly read.

(1) Wrong shape assumption -- getListOfAIServices() declares model
defaults as a NESTED array of the form:

    $servicesList[$key]['textgeneration'] = ['default' => 'model-name']

The previous code read $servicesList[$key]['textgeneration'] (without
['default']) and got the inner array back. That array was then passed
as the $defModel fallback to a (string)-typed constructor argument.

(2) Wrong constant -- the admin UI ("Prompt and custom AI models" tab
in setup.php) stores the per-function model under
AI_API_<SERVICE>_MODEL_TEXT, matching the convention already used by
Ai::generateContent() for the same data. The previous code read
AI_API_<SERVICE>_MODEL (no _TEXT suffix), which is never written by
that form. So the user-configured model was silently ignored and we
fell back to the (array) default from bug #1.

Together these two bugs reliably reproduced the TypeError on any
default install of the AI module where the user had set a custom
text model via the admin UI.

This patch:

- Walks $servicesList[$key]['textgeneration'] correctly (extracting
  ['default'] when it's an array, accepting strings for backward
  compat).
- Tries AI_API_<SERVICE>_MODEL_TEXT first (the constant the admin
  UI writes), and falls back to the legacy AI_API_<SERVICE>_MODEL
  for compatibility with anyone who might have set it manually.
- Defensively coerces the final value to a string and falls back to
  the default if for any reason it's still not a string.

Tested with google (gemini-2.5-flash) and chatgpt configured via
the admin UI -> UniversalLLMAdapter receives a string and the
AI request goes through.
2026-05-18 01:15:23 +02:00
Pichinov-Jose
dbae20fb5e
Fix: ToolCrudObjects header inputSchema JSON Schema compliance (#38299)
create_customer_invoice and create_other_document declare a 'header'
object whose schema has 'required: [socid]' but no 'properties'
entry. This is technically allowed by JSON Schema but stricter
validators flag it as suspicious: the 'required' array references a
property that is not declared in 'properties'.

Beyond compliance, the omission means LLMs (and human reviewers) have
no machine-readable description of which fields are actually accepted
in the 'header' object. The Dolibarr backend already accepts socid,
date, duree_validite, note_public, note_private and others -- this
patch documents the most useful ones explicitly so consumer tools
can produce richer payloads.

Tested with: create_other_document object_type=proposal accepting
a 'header' that contains all of socid + date + duree_validite +
note_public -> all four fields are correctly mapped to the Propal
object (Dolibarr already accepts unknown properties via dynamic
property assignment, so this is purely a schema-documentation change).
2026-05-18 01:14:03 +02:00
Laurent Destailleur
e735bed124 Add AI assistant in top menu #38307 2026-05-18 01:09:26 +02:00
Laurent Destailleur
034647c653 NEW Add picto "AI assistant" 2026-05-18 01:00:27 +02:00
Laurent Destailleur
2cf81fe636 Debug v24 2026-05-18 00:37:43 +02:00
Laurent Destailleur
586b26a153 Merge branch 'develop' of git@github.com:Dolibarr/dolibarr.git into develop 2026-05-18 00:18:20 +02:00
Laurent Destailleur
5ae36d72bd Trans 2026-05-18 00:14:00 +02:00
Pichinov-Jose
d0df12ab81
Qual: preserve full tool descriptions for modern LLMs (#38301)
cleanToolSchemaForLLM() truncates each tool description to 3 words
whenever the schema has more than 20 tools. This heuristic likely
made sense for GPT-3.5 (4K context window) but is harmful with the
current crop of LLMs:

- Gemini 2.5 Flash: 1M token context
- GPT-4o: 128K
- Claude Sonnet: 1M

Three words per description is far too aggressive and actively
breaks tool selection. For example:

- create_other_document  -> "Create documents other"
- create_sales_order     -> "Create a CUSTOMER"
- add_line_item          -> "Add a single"

The LLM then has no way to know that create_other_document is what
should be used for supplier_invoice, or that add_line_item modifies
an EXISTING draft. We've observed Gemini concluding that
"supplier_invoice creation is not available" because the truncated
description didn't mention it.

Two complementary changes:

1. Raise the threshold from 20 to 100 -- this effectively disables
   compression for normal installs (~30 tools) while leaving a
   safety net for very large custom installs that register dozens
   of additional tools via the addMcpTools hook.

2. Even when compression IS active, never touch the tool-level
   description. Parameter-level compression (stripping defaults,
   descriptions of optional fields, collapsing complex objects)
   still applies and continues to save tokens. The right answer
   for truly oversized schemas is to filter the toolset upstream
   (which filterToolsProfessional() already does), not to mutilate
   each tool's description.

Tested with: a 30-tool schema sent in full now allows the LLM to
correctly select create_other_document with object_type
'supplier_invoice', 'proposal' and 'supplier_proposal' --
previously it returned a "feature not available" message.
2026-05-18 00:08:47 +02:00
Pichinov-Jose
fd8d0e3646
New: log MCP tools/call invocations to llx_ai_request_log (#38302)
The AI Assistant web UI (parse_intent.php) persists every request to
llx_ai_request_log via ai_log_request() in ai.lib.php. Administrators
can browse the resulting log via the existing Log Viewer
(htdocs/ai/admin/log_viewer.php).

The MCP HTTP server (mcp_server.php) does NOT call this helper. As a
result, external MCP client activity (Claude Desktop, Claude Code CLI,
MCP Inspector, custom scripts, etc.) is invisible to administrators
-- only dol_syslog() entries land in documents/dolibarr.log, which
is much harder to filter and audit.

This patch adds an mcp_log_request() helper alongside the existing
auth/dispatch logic in mcp_server.php. The helper:

- Persists every tools/call invocation to llx_ai_request_log
- Filters out lifecycle methods (initialize, ping,
  notifications/initialized, tools/list, ...) to avoid log spam
- Logs with provider='mcp' so administrators can filter MCP traffic
  in the Log Viewer
- Captures the tool name + arguments, success/error status, raw
  request payload and raw response payload
- Charges the elapsed time per-call (also per-call inside batches)

The helper is gated by the same AI_LOG_REQUESTS toggle that already
controls the web UI logging -- no new admin setting introduced.

Tested with: search_products, create_other_document, search_invoice,
get_sales_report from Claude Desktop and Claude Code CLI -- each
call appears as a new row in the Log Viewer with the right tool name,
status, payloads, and elapsed time.
2026-05-18 00:06:22 +02:00
Pichinov-Jose
325000c398
Fix: get_sales_report respects the group_by parameter (#38303)
The get_sales_report tool declares a group_by parameter with enum
values [thirdparty, product, month] in its inputSchema, but the
implementation ignored $args['group_by'] entirely and always
returned a flat list of invoices.

Meanwhile getPurchaseReport() in the same class already implemented
the correct grouped pattern (s.nom or DATE_FORMAT date) -- this
patch ports that pattern to getSalesReport(), with three modes:

- With a socid: detailed invoice list for that customer (unchanged
  behavior, kept for backward compatibility).

- Without socid, group_by=thirdparty (default): aggregate by
  customer with COUNT and SUM(total_ttc) -> Top-customers report.

- Without socid, group_by=month: aggregate by DATE_FORMAT(datef,
  '%Y-%m') -> monthly revenue report.

- Without socid, group_by=product: aggregate by product reference
  via INNER JOIN on facturedet, with COALESCE(p.ref, fd.description)
  so free-text lines without a product link still appear under
  their description. SUM(fd.total_ttc) gives per-product revenue,
  COUNT(DISTINCT f.rowid) gives the number of invoices that
  contained the product.

Tested:
- group_by=thirdparty: top customers correctly ranked by total.
- group_by=month: 2026-04 and 2026-05 buckets correctly populated.
- group_by=product: top product (SAM-BIK3-CAS-1430-24-N) correctly
  ranked at 1 276 EUR over 5 invoices.
- With socid: unchanged detailed listing.

Note: the 'product' grouping is also missing from getPurchaseReport()
in the current code. That can be addressed in a follow-up patch on
the same pattern.
2026-05-18 00:04:14 +02:00
Jon Bendtsen
f9e3058145
NEW add text field to search for label (#38306)
* NEW add text field to search for label

* PHAN fix #16134 - remove unused variable

---------

Co-authored-by: Jon Bendtsen <jonbendtsen@jonb.dk>
2026-05-18 00:02:31 +02:00
Jon Bendtsen
8edded0e14
New show linked member status on Thirdparty card (#38308)
Co-authored-by: Jon Bendtsen <jonbendtsen@jonb.dk>
2026-05-17 23:59:35 +02:00
Laurent Destailleur
4108a164ee Merge branch 'develop' of git@github.com:Dolibarr/dolibarr.git into develop 2026-05-17 23:58:14 +02:00