From f4555c4413ed301ef1481c03f32af11c0d126f58 Mon Sep 17 00:00:00 2001 From: Florian Mortgat <50440633+atm-florianm@users.noreply.github.com> Date: Wed, 23 Jul 2025 11:26:49 +0200 Subject: [PATCH 1/4] FIX 17.0 SQL syntax error and/or constraint error when calling Facture::update() after a clone (e.g. in a trigger) (#34778) Co-authored-by: Laurent Destailleur --- htdocs/compta/facture/class/facture.class.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index 3f42160dfd1..b62b3bdfb48 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -1238,7 +1238,7 @@ class Facture extends CommonInvoice $object->socid = $objsoc->id; $object->cond_reglement_id = (!empty($objsoc->cond_reglement_id) ? $objsoc->cond_reglement_id : 0); $object->mode_reglement_id = (!empty($objsoc->mode_reglement_id) ? $objsoc->mode_reglement_id : 0); - $object->fk_project = ''; + $object->fk_project = null; $object->fk_delivery_address = ''; } @@ -1255,8 +1255,8 @@ class Facture extends CommonInvoice $object->user_valid = null; // deprecated $object->fk_user_author = $user->id; $object->fk_user_valid = null; - $object->fk_fac_rec_source = null; $object->fk_facture_source = 0; + $object->fk_fac_rec_source = null; $object->date_creation = ''; $object->date_modification = ''; $object->date_validation = ''; From 437a07ba3c09c1420dad23d5c4e53c42d8ae911e Mon Sep 17 00:00:00 2001 From: Sylvain Legrand Date: Wed, 23 Jul 2025 17:17:30 +0300 Subject: [PATCH 2/4] fix use of MAIN_CHECKBOX_LEFT_COLUMN on stockadate (#34783) --- htdocs/product/stock/stockatdate.php | 38 +++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/htdocs/product/stock/stockatdate.php b/htdocs/product/stock/stockatdate.php index 1503e439749..2794223694e 100644 --- a/htdocs/product/stock/stockatdate.php +++ b/htdocs/product/stock/stockatdate.php @@ -458,6 +458,13 @@ print ''; // Fields title search print ''; +// Action column +if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print ''; + $searchpicto = $form->showFilterButtons('left'); + print $searchpicto; + print ''; +} print ''; print ''; print ''; @@ -474,10 +481,13 @@ $parameters = array('param'=>$param, 'sortfield'=>$sortfield, 'sortorder'=>$sort $reshook = $hookmanager->executeHooks('printFieldListOption', $parameters); // Note that $action and $object may have been modified by hook print $hookmanager->resPrint; -print ''; -$searchpicto = $form->showFilterAndCheckAddButtons(0); -print $searchpicto; -print ''; +// Action column +if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print ''; + $searchpicto = $form->showFilterButtons(); + print $searchpicto; + print ''; +} print ''; $fieldtosortcurrentstock = 'stock'; @@ -487,6 +497,10 @@ if (!empty($search_fk_warehouse)) { // Lines of title print ''; +// Action column +if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print_liste_field_titre('', $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'left '); +} print_liste_field_titre('ProductRef', $_SERVER["PHP_SELF"], 'p.ref', $param, '', '', $sortfield, $sortorder); print_liste_field_titre('Label', $_SERVER["PHP_SELF"], 'p.label', $param, '', '', $sortfield, $sortorder); @@ -508,7 +522,10 @@ $parameters = array('param'=>$param, 'sortfield'=>$sortfield, 'sortorder'=>$sort $reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters); // Note that $action and $object may have been modified by hook print $hookmanager->resPrint; -print_liste_field_titre('', $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'right '); +// Action column +if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print_liste_field_titre('', $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'right '); +} print "\n"; @@ -583,6 +600,11 @@ while ($i < ($limit ? min($num, $limit) : $num)) { print ''; + // Action column + if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print ''; + } + // Product ref print ''.$prod->getNomUrl(1, '').''; @@ -649,8 +671,10 @@ while ($i < ($limit ? min($num, $limit) : $num)) { $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters); // Note that $action and $object may have been modified by hook print $hookmanager->resPrint; - // Action - print ''; + // Action column + if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print ''; + } print ''."\n"; } From 6a88d31675f2c40e01f6c779a7869a226b1652b1 Mon Sep 17 00:00:00 2001 From: Maxime Kohlhaas Date: Sat, 26 Jul 2025 14:57:23 +0200 Subject: [PATCH 3/4] Fix : missing langs load on comm card file (#34812) Co-authored-by: x --- htdocs/comm/card.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/comm/card.php b/htdocs/comm/card.php index 173ee8a6510..10be5a72f83 100644 --- a/htdocs/comm/card.php +++ b/htdocs/comm/card.php @@ -64,7 +64,7 @@ if (!empty($conf->ficheinter->enabled)) { } // Load translation files required by the page -$langs->loadLangs(array('companies', 'banks')); +$langs->loadLangs(array('companies', 'banks', 'commercial')); if (!empty($conf->contrat->enabled)) { $langs->load("contracts"); From 154a25f8cba06d72fa60014c9eb19c489c8172ca Mon Sep 17 00:00:00 2001 From: VIAL-GOUTEYRON Quentin Date: Thu, 31 Jul 2025 22:59:29 +0200 Subject: [PATCH 4/4] Enhance working days calculation to incorporate half-day adjustments and optimize public holiday checks (#34552) * "Enhance working days calculation to incorporate half-day adjustments and optimize public holiday checks" * "Add test cases for num_open_day() to validate half-day and weekend boundary scenarios" * "Update DateLibTest to include Saturday and Sunday as non-working days in test setup" --- htdocs/core/lib/date.lib.php | 33 ++++++++++++++++++++++++++------- test/phpunit/DateLibTest.php | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 7 deletions(-) diff --git a/htdocs/core/lib/date.lib.php b/htdocs/core/lib/date.lib.php index c412a03468e..da401cbbb0c 100644 --- a/htdocs/core/lib/date.lib.php +++ b/htdocs/core/lib/date.lib.php @@ -997,16 +997,35 @@ function num_open_day($timestampStart, $timestampEnd, $inhour = 0, $lastday = 0, return 'ErrorBadParameter_num_open_day'; } - //print 'num_open_day timestampStart='.$timestampStart.' timestampEnd='.$timestampEnd.' bit='.$lastday; if ($timestampStart < $timestampEnd) { - $numdays = num_between_day($timestampStart, $timestampEnd, $lastday); + // --- 1. Calculate Gross Working Days --- + // Gross working days = total days in range - non-working days (weekends & public holidays). + $nbOpenDay = num_between_day($timestampStart, $timestampEnd, $lastday) - num_public_holiday($timestampStart, $timestampEnd, $country_code, $lastday); - $numholidays = num_public_holiday($timestampStart, $timestampEnd, $country_code, $lastday); - $nbOpenDay = ($numdays - $numholidays); - if ($inhour == 1 && $nbOpenDay <= 3) { - $nbOpenDay = ($nbOpenDay * 24); + // --- 2. Apply Contextual Half-Day Deductions --- + $halfday = (int) $halfday; // Ensure $halfday is an integer for reliable comparisons. + + // Check if start/end days are working days just ONCE to optimize performance + // by avoiding redundant calls to the potentially slow num_public_holiday() function. + $isStartDayWorking = (num_public_holiday($timestampStart, $timestampStart, $country_code, 1) == 0); + $isEndDayWorking = (num_public_holiday($timestampEnd, $timestampEnd, $country_code, 1) == 0); + + // Deduct 0.5 if the leave starts in the afternoon of a working day. + if (($halfday == -1 || $halfday == 2) && $isStartDayWorking) { + $nbOpenDay -= 0.5; } - return $nbOpenDay - (($inhour == 1 ? 12 : 0.5) * abs($halfday)); + + // Deduct 0.5 if the leave ends in the morning of a different, working day. + if (($halfday == 1 || $halfday == 2) && date('Y-m-d', $timestampStart) != date('Y-m-d', $timestampEnd) && $isEndDayWorking) { + $nbOpenDay -= 0.5; + } + + // --- 3. Return Final Value --- + if ($inhour == 1) { + return $nbOpenDay * 24; + } + + return $nbOpenDay; } elseif ($timestampStart == $timestampEnd) { $numholidays = 0; if ($lastday) { diff --git a/test/phpunit/DateLibTest.php b/test/phpunit/DateLibTest.php index 983ad2af489..d5f13c7320e 100644 --- a/test/phpunit/DateLibTest.php +++ b/test/phpunit/DateLibTest.php @@ -303,6 +303,42 @@ class DateLibTest extends PHPUnit\Framework\TestCase $result=num_open_day($date1, $date2, 'XX', 1); print __METHOD__." result=".$result."\n"; $this->assertEquals(3, $result, 'NumOpenDay for XX when saturday + sunday are working days'); // 3 opened day, 0 closes (even if country unknown) + + // Define specific dates for these tests + $date_friday_4 = dol_mktime(0, 0, 0, 1, 4, 2013, 'gmt'); // Friday + $date_saturday_5 = dol_mktime(0, 0, 0, 1, 5, 2013, 'gmt'); // Saturday + $date_monday_7 = dol_mktime(0, 0, 0, 1, 7, 2013, 'gmt'); // Monday + $date_friday_11 = dol_mktime(0, 0, 0, 1, 11, 2013, 'gmt'); // Following Friday + + // Case 1: Weekend Boundary (Friday morning -> Saturday morning) + // Expected: 1 day. No half-day deduction for end date on a non-working day. + // $starthalfday = 'morning', $endhalfday = 'morning' -> $halfday = 1 + $conf->global->MAIN_NON_WORKING_DAYS_INCLUDE_SATURDAY = 1; + $conf->global->MAIN_NON_WORKING_DAYS_INCLUDE_SUNDAY = 1; + $result = num_open_day($date_friday_4, $date_saturday_5, 0, 1, 1, 'FR'); + print __METHOD__." result=".$result."\n"; + $this->assertEquals(1, $result, 'Case 1: Friday morning to Saturday morning should be 1 day'); + + // Case 2: Full week with half-day (Friday morning -> Following Friday morning) + // Expected: 5.5 days. + // $starthalfday = 'morning', $endhalfday = 'morning' -> $halfday = 1 + $result = num_open_day($date_friday_4, $date_friday_11, 0, 1, 1, 'FR'); + print __METHOD__." result=".$result."\n"; + $this->assertEquals(5.5, $result, 'Case 2: Friday morning to next Friday morning should be 5.5 days'); + + // Case 3: Single Half-Day (Monday afternoon) + // Expected: 0.5 days. + // $starthalfday = 'afternoon' -> $halfday = -1 + $result = num_open_day($date_monday_7, $date_monday_7, 0, 1, -1, 'FR'); + print __METHOD__." result=".$result."\n"; + $this->assertEquals(0.5, $result, 'Case 3: A single Monday afternoon should be 0.5 days'); + + // Case 4: Standard Leave (Monday morning -> Friday evening) + // Expected: 5 days. + // $starthalfday = 'morning', $endhalfday = 'evening' -> $halfday = 0 + $result = num_open_day($date_monday_7, $date_friday_11, 0, 1, 0, 'FR'); + print __METHOD__." result=".$result."\n"; + $this->assertEquals(5, $result, 'Case 4: Monday morning to Friday evening should be 5 days'); } /**