From b8dc0d34ec5eb41ee416795c9b00fe033da0b06f Mon Sep 17 00:00:00 2001 From: Jam Balaya Date: Fri, 24 Jul 2026 00:38:42 +0900 Subject: [PATCH] FIX #33065 page hangs when displaying a very long html content (#39260) * FIX #39190 wrong unit price when invoicing time spent with one line per declaration (#39215) * FIX #39190 wrong unit price when invoicing time spent with one line per declaration In projet/tasks/time.php, the 'onelineperperiod' mode (invoice generation option "One line for each time spent declaration") computed the unit price as $pu_ht = price2num($value['totalvaluetodivideby3600'] / 3600, 'MU'); but totalvaluetodivideby3600 is timespent_duration (seconds) * timespent_thm (hourly rate), so dividing by 3600 yields "hours * hourly rate", which is the line total and not a unit price. The quantity passed to addline() is the number of hours, so the line was billed hours * (hours * rate) instead of hours * rate: the time is over-billed by a factor equal to the number of hours. The sibling modes are already correct: 'onelineperuser' and 'onelinepertask' divide by the recorded number of seconds. Up to 16.0 'onelineperuser' had the same /3600 expression; it was fixed there and 'onelineperperiod' was left behind. Align it with that reference implementation, including the same guard against a zero duration. Also reset $pu_ht for each generated line. $pu_ht is initialized once before the loops (with the price of the selected product/service, or 0) and this mode only had an "if (empty($pu_ht))" test, so once a price was computed for the first line every following line reused it, and lines of users with a different hourly rate got the rate of the first line. The base price is saved before the loop and restored on each iteration, so the product/service price path is preserved. * Rename variable for clarity in time.php --------- Co-authored-by: Laurent Destailleur * FIX isInt() does not detect sized integer types (tinyint, bigint) (#39236) CommonObject::isInt() decides whether a list-page column gets numeric search mode and is also used when resolving $this->id. The regex /(^int|int$)/ missed sized integer types such as tinyint(4) and bigint(20): they neither start nor end with "int". These types are not exotic: tinyint(4) is used in several core $fields definitions (societe, contact, entrepot, companypaymentmode, ...) and ModuleBuilder-generated tables use bigint(20) for rowid, so isInt() should recognise them rather than requiring callers to change the column type. The new regex /^(?:tiny|small|medium|big)?int|int$/ also handles smallint/mediumint with a size. Anchoring is preserved on purpose so that strings which merely contain "int" (e.g. sellist:Table:...) are still NOT matched, while the Dolibarr foreign-key syntax "integer:Class:path" keeps being detected. Signed-off-by: Jam Balaya * FIX #34667 checkUserAccessToObject: skip entity check for non-multientity objects (multicompany) (#39246) When the multicompany module is enabled, checkUserAccessToObject() (used by restrictedArea(), e.g. from an ajax tooltip) ran the entity check unconditionally in its default/custom-object branch, building "AND dbt.entity IN (...)". For a custom object whose table has no entity column (ismultientitymanaged = 0), that SQL fails, nb comes back 0 and access is wrongly denied. Guard the branch so the entity test only runs when the object is actually multi-entity managed. Keep the test for legacy classes that never define ismultientitymanaged (null/unset) and for a non-object $object, and skip it only when a class explicitly sets ismultientitymanaged = 0. Supersedes the stale #34667 (by @jyhere) and applies the condition requested by @eldy in its review. Co-authored-by: Claude Opus 4.8 * FIX mo_production: show very-short unit label instead of untranslated 'UnitPShort' (#39253) The "Unit" column of the consume/produce tables used measuringUnitString(..., 2), which translates a