diff --git a/htdocs/comm/card.php b/htdocs/comm/card.php
index bbfa4dd649a..362a5f2aeb7 100644
--- a/htdocs/comm/card.php
+++ b/htdocs/comm/card.php
@@ -66,7 +66,7 @@ if (isModEnabled('ficheinter')) {
}
// Load translation files required by the page
-$langs->loadLangs(array('companies', 'banks'));
+$langs->loadLangs(array('companies', 'banks', 'commercial'));
if (isModEnabled('contrat')) {
$langs->load("contracts");
diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php
index 16321910c19..44c69bc996c 100644
--- a/htdocs/compta/facture/class/facture.class.php
+++ b/htdocs/compta/facture/class/facture.class.php
@@ -1248,7 +1248,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 = '';
}
@@ -1265,8 +1265,8 @@ class Facture extends CommonInvoice
$object->user_validation_id = null;
$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 = '';
diff --git a/htdocs/core/lib/date.lib.php b/htdocs/core/lib/date.lib.php
index e6d89b73c95..5f504d694ff 100644
--- a/htdocs/core/lib/date.lib.php
+++ b/htdocs/core/lib/date.lib.php
@@ -1051,16 +1051,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/htdocs/product/stock/stockatdate.php b/htdocs/product/stock/stockatdate.php
index ef614d1e40e..e8537223481 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";
@@ -584,6 +601,11 @@ while ($i < ($limit ? min($num, $limit) : $num)) {
print '';
+ // Action column
+ if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
+ print ' ';
+ }
+
// Product ref
print ''.$prod->getNomUrl(1, '').' ';
@@ -656,8 +678,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";
}
diff --git a/test/phpunit/DateLibTest.php b/test/phpunit/DateLibTest.php
index c9be8ac347a..da52355f253 100644
--- a/test/phpunit/DateLibTest.php
+++ b/test/phpunit/DateLibTest.php
@@ -305,6 +305,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');
}
/**