Commit graph

152470 commits

Author SHA1 Message Date
Frédéric FRANCE
592128018b
Update ci-checkfilesetlock.yml (#39525) 2026-08-14 20:31:46 +02:00
Laurent Destailleur
53a7f8eff4 Merge branch '22.0' of git@github.com:Dolibarr/dolibarr.git into 23.0 2026-08-14 15:52:54 +02:00
Laurent Destailleur
f506d5459a Merge branch '21.0' of git@github.com:Dolibarr/dolibarr.git into 22.0 2026-08-14 15:52:11 +02:00
MDW
f092c9b7f6
Qual(ci): Fix phan notices (typing) (#39510) 2026-08-14 15:49:33 +02:00
MDW
a053ecf7d3
Qual(ci): Fix phan notices (typing) (#39509) 2026-08-14 15:48:28 +02:00
Laurent Destailleur
cf4c308022 Fix escape js string - reported by Vulncheck 2026-08-14 15:43:43 +02:00
Laurent Destailleur
ab4b522d69 Fi regression, restore type string 2026-08-14 15:40:51 +02:00
MDW
9e215be47c
Qual(ci): Fix phan notices (typing) (#39511)
* Qual(ci): Fix phan notices (typing)

* Qual: Fix deposit_percent type (escaping)

# Qual: Fix deposit_percent type (escaping)

deposit_percent is a float but was escaped to string resulting in argument mismatch.
Fixed by casting to float.
2026-08-14 15:35:17 +02:00
Laurent Destailleur
48958ae565 Automated merge from 22.0 to 23.0 by tool pullmerge.sh 2026-08-13 17:38:17 +02:00
Laurent Destailleur
d119dd688e Automated merge from 21.0 to 22.0 by tool pullmerge.sh 2026-08-13 17:18:40 +02:00
Laurent Destailleur
5316cb7632 Fix subtotal when detail of line disabled
(SUBTOTAL_HIDE_LINES_UNDER_TITLE)
2026-08-13 17:04:11 +02:00
Laurent Destailleur
8133095ae1 Merge branch '21.0' of git@github.com:Dolibarr/dolibarr.git into 21.0 2026-08-13 15:53:04 +02:00
Laurent Destailleur
61ef9d017a Automated merge from 20.0 to 21.0 by tool pullmerge.sh 2026-08-13 15:52:37 +02:00
w3houde
050a776b0e
Fix #39020 use universal-search filter for MoLine lookup on V21+ (#39489)
Follow-up to the 18.0 fix. On 21.0 and later, MoLine::fetchAll no longer
handles fk_mo/origin_id/origin_type as exact matches in the array-filter
path; every non-rowid key falls back to LIKE '%value%'. So the array
filter added for 18.0 turned into origin_id LIKE '%..%' here, which can
match an unrelated MO line and reintroduce the duplicate MO the fix was
meant to prevent.

Build the lookup with the universal-search string filter
(fk_mo:=:.. AND origin_id:=:.. AND origin_type:=:'bomline') so the class
turns it into exact equality, as requested during review of #39163.

Signed-off-by: Dolicraft <contact@dolicraft.com>
Co-authored-by: Dolicraft <contact@dolicraft.com>
2026-08-13 14:25:01 +02:00
Laurent Destailleur
4cea4f8c71 Automated merge from 19.0 to 20.0 by tool pullmerge.sh 2026-08-13 14:23:57 +02:00
Laurent Destailleur
7ea87bb303 Automated merge from 18.0 to 19.0 by tool pullmerge.sh 2026-08-13 14:23:54 +02:00
w3houde
53085395c2
Fix #39494 keep decimals on asset disposal amount (#39495)
The asset disposal amount was read with GETPOSTINT, casting it to int
and dropping the decimals, so a disposal at 1500.50 was stored as 1500.
disposal_amount_ht is a 'price' field, so use GETPOSTFLOAT to keep the
decimal amount, both when storing it and when re-displaying it in the
disposal confirmation form.

Signed-off-by: Dolicraft <contact@dolicraft.com>
Co-authored-by: Dolicraft <contact@dolicraft.com>
2026-08-13 14:22:04 +02:00
w3houde
7a82187acd
Fix #39245 set TRIGGER_PREFIX to BILL on Facture (#39497)
On 23.0 the generic CommonObject methods (setPaymentMethods,
setBankAccount, ...) build the trigger name from
$this->TRIGGER_PREFIX, falling back to get_class() when it is empty.
Facture does not declare it, so it fires FACTURE_MODIFY instead of the
BILL_* events the class uses everywhere else (BILL_CREATE, BILL_MODIFY,
...). Modules listening on BILL_MODIFY miss those changes.

Declare public $TRIGGER_PREFIX = 'BILL', like the other objects do
(Holiday='HOLIDAY', Workstation='WORKSTATION', BOM='BOM').

Signed-off-by: Dolicraft <contact@dolicraft.com>
Co-authored-by: Dolicraft <contact@dolicraft.com>
2026-08-13 14:21:43 +02:00
HENRY Florian
af6c24c0ce
fix: remove bug in last PR 39407 merged (JS allowoverconsumption not delcared) (#39414) 2026-08-13 04:00:48 +02:00
support-accellier
bfbc4db36d
Fix currency rate lost (comes as 1) when creating Supplier Invoice from Supplier Order (#39424)
The origin multicurrency exchange rate was read with GETPOSTINT('originmulticurrency_tx'), which truncates any fractional rate (e.g. 0.83, 1.27) down to an integer. As a result, creating a Supplier Invoice from a Supplier Order (or other origin) always produced an exchange rate of 0 or 1 instead of the real rate, even when the multi-currency setting to keep the source object's original rate was enabled.

This was already fixed for one of the four occurrences in this file (the credit-note/replacement-invoice path) but the other three were never backported to this branch. This commit switches all three remaining occurrences from GETPOSTINT() to GETPOSTFLOAT(), matching develop/23.0.

Fixes #39423
2026-08-13 03:23:59 +02:00
Maxime Kohlhaas
cc31d40638
Fix : thirdparty birth was emptied on country change (#39440) 2026-08-13 03:05:13 +02:00
VIAL-GOUTEYRON Quentin
3ad376dc01
FIX Holiday shown one day off in agenda for users in another timezone (#39465)
Columns llx_holiday.date_debut and date_fin are pure DATE columns: they hold a
calendar fact, not an absolute instant, so they carry no time and no timezone.

The agenda read them with jdate() defaulting to 'tzserver', then projected them
back with dol_print_date(..., 'tzuserrel') to pick the calendar day box. The
resulting shift equals TZ_user - TZ_server, so any user whose timezone differs
from the server got leaves rendered on the wrong day. Users aligned with the
server saw nothing wrong, which is why this went unnoticed. It also triggers with
no user timezone set at all, since 'tzuserrel' falls back to UTC when
$_SESSION['dol_tz_string'] is empty, shifting leaves on any server east of UTC.

Read and project those dates in GMT instead. This follows the documented core
convention for dates without time ("We suppose dates without time are always gmt
(storage of course + output)", commonobject.class.php; "For date without hour,
date is always GMT for storage and output", extrafields.class.php) and honors the
$daykey contract of $eventarray, which must be midnight GMT of the displayed
calendar day. It also makes the half-day comparison consistent, since
dol_get_first_hour() is already called with 'gmt' a few lines below and only
supports gmt/tzserver anyway.

Two further defects disappear as a side effect: the loop condition
"while ($daykey <= $event->date_end_in_calendar)" compared a user-shifted $daykey
against a server-anchored $datef and rendered one extra day box, and halfday=-1
happened to be correct while halfday=0/1 were not, because the +12h offset
accidentally compensated the timezone shift.

Regular events are untouched: llx_actioncomm.datep is a DATETIME holding a real
instant, and its block still uses 'tzuserrel', so a 9am meeting stays correctly
shifted for a viewer in another timezone. Every other render path already
excludes type_code 'HOLIDAY', so there is no display change elsewhere.

peruser.php carries a copy of the same block and is fixed identically, otherwise
the two views of the same page would contradict each other.

Tested with a real browser (Playwright) against a server running in UTC, driving
the month view as Europe/Paris, America/Cayenne and Pacific/Auckland users on
three existing leaves: 3 failures before, none after, with identical day boxes in
every timezone. A single-day leave of 2026-07-28 was rendered on both 2026-07-27
and 2026-07-28 for the America/Cayenne user before the fix.
2026-08-13 02:45:02 +02:00
w3houde
e7ab87886e
Fix #39395 remove duplicate fk_user_modif in chargesociales update (#39474)
ChargeSociales::update() set fk_user_modif twice in the same UPDATE
statement. PostgreSQL rejects this with "multiple assignments to the
same column", so editing a social contribution failed. Remove the
duplicate assignment. Backport of the develop fix #39389 to the 22.0
and 23.0 maintenance branches, where the duplicate is still present.

Signed-off-by: Dolicraft <contact@dolicraft.com>
Co-authored-by: Dolicraft <contact@dolicraft.com>
2026-08-12 23:37:36 +02:00
w3houde
79128945ff
Fix #39400 unaccent Hungarian double acute letters (#39476)
dol_string_unaccent() did not map the Hungarian letters o-double-acute
and u-double-acute (U+0150/U+0151/U+0170/U+0171), so they were left
untouched in sanitized filenames. Add the four missing entries so they
transliterate to O/o/U/u like the other accented variants.

Signed-off-by: Dolicraft <contact@dolicraft.com>
Co-authored-by: Dolicraft <contact@dolicraft.com>
2026-08-12 23:37:10 +02:00
HENRY Florian
a1bfd5d9fb
fix: module builder rebuild class mistype foreignkey so delete them (#39480)
* fix: module builder rebuild class mistype foreignkey so delete them

* fix: module builder rebuild class mistype foreignkey so delete them
2026-08-12 23:07:45 +02:00
Laurent Destailleur
15c9ca58dc Automated merge from 19.0 to 20.0 by tool pullmerge.sh 2026-08-12 22:43:32 +02:00
Laurent Destailleur
5028dae981 Fix file access with hasp parameter - reported by tremor hunter 2026-08-12 22:16:43 +02:00
Laurent Destailleur
6dbaef2fd4 Automated merge from 18.0 to 19.0 by tool pullmerge.sh 2026-08-12 22:13:16 +02:00
Zakaria Boushaba
d0810e11e3
FIX: Fix mandatory field validation for select (empty '-1') and textarea (CKEDITOR not defined) (#39458)
Co-authored-by: Zakaria Boushaba <z.boushaba@vold.africa>
2026-08-11 19:46:22 +02:00
w3houde
6a647097bd
Fix #39355 load images.lib.php before image_format_supported in API (#39462)
The POST /documents endpoint with generateThumbs=1 called
image_format_supported() after requiring only files.lib.php, but that
function is defined in images.lib.php, which was never included on this
path. The call raised a fatal error and the request returned a bare
HTTP 500 with no JSON body. Add the missing require_once.

Signed-off-by: Dolicraft <contact@dolicraft.com>
Co-authored-by: Dolicraft <contact@dolicraft.com>
2026-08-11 19:41:49 +02:00
atm-lucas
eec0a49a87
Renaming a product's attached file fails when PRODUCT_USE_OLD_PATH_FOR_PHOTO is enabled (#39417) 2026-08-11 02:25:58 +02:00
Frédéric FRANCE
7f39b0cced
fix CI in v23 (#39439)
* fix CI

* Update mod_holiday_madonna.php

* Update lettering.class.php

* Update modExpenseReport.class.php

* Update modFacture.class.php

* Update modFicheinter.class.php

* Update modFournisseur.class.php

* Update modHoliday.class.php

* Update modMailing.class.php

* Update modPrelevement.class.php

* Update modPropale.class.php

* Update modReception.class.php

* Update modSociete.class.php

* Update modStock.class.php

* Update modSupplierProposal.class.php

* Update myobject_agenda.php
2026-08-11 02:13:43 +02:00
Frédéric FRANCE
61b3bc52b8
fix stock_alerte may be empty (null) (#38484)
* fix stock_alerte may be empty (null)

* Update product.php
2026-08-11 02:00:55 +02:00
Frédéric FRANCE
c86264053e
avoid to delete directory if ref is empty (#38877)
* avoid to delete directory

* Update contrat.class.php

* Update expedition.class.php

* Update fournisseur.commande.class.php

* Update fournisseur.facture.class.php

* Update project.class.php
2026-08-11 01:25:46 +02:00
Laurent Destailleur
a80eadb356 Backport sanitization from v24 2026-08-10 11:40:49 +02:00
Laurent Destailleur
2b90d1f14f Restore ability to add all lines under subtotal title 2026-08-07 15:56:16 +02:00
tcesar
322e41b81a
Fix: API auth fails in multicompany transverse mode when user has several groups (#39409) 2026-08-06 17:58:33 +02:00
TowyTowy
11a736d69e
FIX phone formatting dropping and duplicating digits for JO and PE (#39398)
The substr offsets in dol_print_phone did not line up with the segment
lengths, so formatted numbers repeated one digit and lost another.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 17:54:08 +02:00
HENRY Florian
ea1443e09e
fix: in MO split line broken on qty of component less than 1 (#39407)
* fix: in MO split line broken on qty less than 1 and over consumption

* fix: in MO split line broken on qty less than 1
2026-08-06 17:52:42 +02:00
Frédéric FRANCE
658c35a8af
fix phpstan in v23 (#39399)
* fix phpstan

* Update agenda.php

* Update agenda.php

* Update agenda.php
2026-08-06 17:51:51 +02:00
HENRY Florian
664e401166
fix: add missing translation file in mo_mouvement (#39406) 2026-08-06 17:51:14 +02:00
Laurent Destailleur
cad7be6dcb Merge branch '22.0' of git@github.com:Dolibarr/dolibarr.git into 23.0 2026-08-05 23:41:10 +02:00
Laurent Destailleur
d5dde5a7b2 Merge branch '21.0' of git@github.com:Dolibarr/dolibarr.git into 22.0 2026-08-05 23:24:47 +02:00
Maxime Kohlhaas
de75d4bbdb
Merge commit from fork
A PaymentIntent already used to record a payment on one invoice/order
could be resubmitted with a different fulltag/ref to fraudulently
record and validate a payment on a different object, since only its
Stripe status was checked, never whether it had already been consumed.
2026-08-05 15:13:44 +02:00
Eric - CAP-REL
ccc2701529
fix donator identity in case of fk_soc is set and empty fields (option in setup) (#39390) 2026-08-05 11:09:01 +02:00
Florian Hödl
f5907fe212
FIX Missing bottom margin on dropdown action buttons in md theme (#39388)
In theme md, the rule in btn.inc.php that gives action buttons their
bottom margin only lists direct children of div.tabsAction and children
of div.divButAction. Dropdown action buttons are not in that list.

dolGetButtonAction() renders a dropdown button as
<div class="dropdown inline-block dropdown-holder"><a class="dropdown-toggle ... butAction">,
so the anchor is a grandchild of div.tabsAction and matches none of the
existing selectors. It therefore gets no bottom margin.

When the action bar wraps onto more than one line and a line is made of
dropdown buttons, the rows have no vertical spacing at all and the
buttons visually touch each other.

Theme eldy already fixes this with the same selector
(div.tabsAction > .dropdown > .dropdown-toggle in theme/eldy/btn.inc.php);
theme md was never aligned. This adds the identical selector to md.

Measured with the compiled md stylesheet, six dropdown buttons wrapping
onto two rows: gap between rows 0px before, 22px after, which matches
the 1.4em the plain buttons already get. Layout of rows that mix plain
and dropdown buttons is unchanged.

Signed-off-by: Florian Hödl <florian@hoedl.co>
Co-authored-by: Florian Hödl <florian@hoedl.co>
2026-08-05 10:27:59 +02:00
Florian Hödl
72ecff38e4
FIX Missing include of ActionComm in doAutoRenewContracts (#39387)
Contrat::doAutoRenewContracts() instantiates ActionComm to log the
RENEW_CONTRACT event, but contrat.class.php never loads
comm/action/class/actioncomm.class.php.

From a web request the class is usually already loaded by some other
include, so the problem stays hidden. When the method is run as a
scheduled job it is not: scripts/cron/cron_run_jobs.php loads only
master.inc.php, functionscli.lib.php, cronjob.class.php and
user.class.php, and cronjob.class.php then loads only the job class
itself via dol_include_once($this->classesname). ActionComm is not part
of that include closure, so the method fails with
"Class ActionComm not found".

The fatal error happens after the UPDATE on llx_contratdet has been
issued but before $this->db->commit(), so the transaction is never
committed and the renewal is lost. The job also aborts, so every
remaining contract line in the loop is left unprocessed and the failure
is only visible as a fatal error in the log.

Verified on 23.0.3: after the cron bootstrap, class_exists('Contrat')
is true while class_exists('ActionComm') is false. Adding the include
next to the existing html.formmail.class.php include makes it true.

Signed-off-by: Florian Hödl <florian@hoedl.co>
Co-authored-by: Florian Hödl <florian@hoedl.co>
2026-08-05 10:18:26 +02:00
TowyTowy
9d10392d66
FIX isValidTinForES() rejects almost every Spanish NIE starting with T (#39384)
The "Check NIE T" branch compared the control character of the TIN to the
return value of preg_match() instead of using preg_match() as the condition:

    if ($num[8] == preg_match('/^[T]{1}[A-Z0-9]{8}$/', $str)) {

Since execution only reaches that branch when the string already matched the
format, preg_match() always returns 1, so the test collapsed to
$num[8] == 1. A NIE of type T therefore validated only when its last
character was literally "1", and every other one was reported as -3
(invalid control key). Out of the 36 possible control characters, 35 were
wrongly rejected.

A NIE starting with T has no control key algorithm, so matching the
documented syntax is the only check to perform.

Also fill in and enable the testIsValidTinForES() unit test that was left
commented out with empty input strings.

Co-authored-by: Claude <noreply@anthropic.com>
2026-08-04 22:48:15 +02:00
kkhelifa-opendsi
6dfc8de4b5
FIX: Show error when clone order fail (#39382)
* FIX: Show error when clone order fail

* Fix missing variable

* Fix foreach loop to reference correct object

Updated foreach loop to use the correct object reference for lines.

---------

Co-authored-by: Laurent Destailleur <eldy@destailleur.fr>
2026-08-04 22:35:21 +02:00
Grégory Aliot
f45d71a4b1
FIX MySQL DB_ERROR_1055 on treasury journal (#39359)
With the MySQL 8 default sql_mode (which includes ONLY_FULL_GROUP_BY),
the supplier invoices query of the treasury journal fails with
DB_ERROR_1055 ("Expression #5 of SELECT list is not in GROUP BY clause
and contains nonaggregated column 'pff.amount' which is not
functionally dependent on columns in GROUP BY clause"). Supplier
payments are then missing from the journal view and from the transfer
into the ledger, while customer invoices still pass, so a treasury
ledger is produced with revenues only and no supplier expense, with no
other signal than one error line in the transfer report.

This is the MySQL counterpart of PostgreSQL error 42803 fixed on
develop by #38910, then simplified by commit 42840b47a which removed
the GROUP BY of the three queries entirely: they contain no aggregate
function, and the fetch loops already deduplicate rows (isset() guards
on the object/payment keys and the already_sum check on the detail
line id), so the GROUP BY is useless. This backports that resolution,
with lines identical to develop so the upward merge stays clean.

Verified on a 23.0.2 instance on MySQL 8 with factory sql_mode: the
vanilla supplier query returns error 1055, the same query without
GROUP BY succeeds and returns the same rows, row for row, as the
exhaustive GROUP BY variant of #38910; the full year transfer produces
balanced pieces and a re-transfer creates no duplicate.

Signed-off-by: Gregory Aliot <greg.aliot@gmail.com>
Co-authored-by: Gregory Aliot <greg.aliot@gmail.com>
2026-08-04 18:39:19 +02:00