diff --git a/htdocs/admin/holiday.php b/htdocs/admin/holiday.php
index 3f32848b594..b907a94cb65 100644
--- a/htdocs/admin/holiday.php
+++ b/htdocs/admin/holiday.php
@@ -536,6 +536,22 @@ if ($conf->use_javascript_ajax) {
print "";
print "";
+// Set holiday decrease at the end of month
+print '
';
+print "| ".$langs->trans("ConsumeHolidaysAtTheEndOfTheMonthTheyAreTakenAt")." | ";
+print '';
+if ($conf->use_javascript_ajax) {
+ print ajax_constantonoff('HOLIDAY_DECREASE_AT_END_OF_MONTH', array(), null, 0, 0, 0, 2, 0, 1);
+} else {
+ if (getDolGlobalString('HOLIDAY_DECREASE_AT_END_OF_MONTH')) {
+ print ''.img_picto($langs->trans("Enabled"), 'on').'';
+ } else {
+ print ''.img_picto($langs->trans("Disabled"), 'off').'';
+ }
+}
+print " | ";
+print "
";
+
if (getDolGlobalInt('MAIN_FEATURES_LEVEL') >= 2) {
$substitutionarray = pdf_getSubstitutionArray($langs, array('objectamount'), null, 2);
$substitutionarray['__(AnyTranslationKey)__'] = $langs->trans("Translation");
diff --git a/htdocs/holiday/card.php b/htdocs/holiday/card.php
index 4abddc738c7..50a3cbb6467 100644
--- a/htdocs/holiday/card.php
+++ b/htdocs/holiday/card.php
@@ -603,6 +603,8 @@ if (empty($reshook)) {
$object->statut = Holiday::STATUS_APPROVED;
$object->status = Holiday::STATUS_APPROVED;
+ $decrease = getDolGlobalInt('HOLIDAY_DECREASE_AT_END_OF_MONTH');
+
$db->begin();
$verif = $object->approve($user);
@@ -612,12 +614,12 @@ if (empty($reshook)) {
}
// If no SQL error, we redirect to the request form
- if (!$error) {
+ if (!$error && empty($decrease)) {
// Calculate number of days consumed
$nbopenedday = num_open_day($object->date_debut_gmt, $object->date_fin_gmt, 0, 1, $object->halfday);
$soldeActuel = $object->getCpforUser($object->fk_user, $object->fk_type);
$newSolde = ($soldeActuel - $nbopenedday);
- $label = $langs->transnoentitiesnoconv("Holidays").' - '.$object->ref;
+ $label = $object->ref.' - '.$langs->transnoentitiesnoconv("HolidayConsumption");
// The modification is added to the LOG
$result = $object->addLogCP($user->id, $object->fk_user, $label, $newSolde, $object->fk_type);
@@ -832,6 +834,8 @@ if (empty($reshook)) {
$object->statut = Holiday::STATUS_CANCELED;
$object->status = Holiday::STATUS_CANCELED;
+ $decrease = getDolGlobalInt('HOLIDAY_DECREASE_AT_END_OF_MONTH');
+
$result = $object->update($user);
if ($result >= 0 && $oldstatus == Holiday::STATUS_APPROVED) { // holiday was already validated, status 3, so we must increase back the balance
@@ -841,14 +845,28 @@ if (empty($reshook)) {
$error++;
}
+ $startDate = $object->date_debut_gmt;
+ $endDate = $object->date_fin_gmt;
+
+ if (!empty($decrease)) {
+ $lastUpdate = strtotime($object->getConfCP('lastUpdate', dol_print_date(dol_now(), '%Y%m%d%H%M%S')));
+ $date = strtotime('-1 month', $lastUpdate);
+ $endOfMonthBeforeLastUpdate = dol_mktime(0, 0, 0, (int) date('m', $date), (int) date('t', $date), (int) date('Y', $date), 1);
+ if ($object->date_debut_gmt < $endOfMonthBeforeLastUpdate && $object->date_fin_gmt > $endOfMonthBeforeLastUpdate) {
+ $endDate = $endOfMonthBeforeLastUpdate;
+ } elseif ($object->date_debut_gmt > $endOfMonthBeforeLastUpdate) {
+ $endDate = $startDate;
+ }
+ }
+
// Calculate number of days consumed
- $nbopenedday = num_open_day($object->date_debut_gmt, $object->date_fin_gmt, 0, 1, $object->halfday);
+ $nbopenedday = num_open_day($startDate, $endDate, 0, 1, $object->halfday);
$soldeActuel = $object->getCpforUser($object->fk_user, $object->fk_type);
$newSolde = ($soldeActuel + $nbopenedday);
// The modification is added to the LOG
- $result1 = $object->addLogCP($user->id, $object->fk_user, $langs->transnoentitiesnoconv("HolidaysCancelation"), $newSolde, $object->fk_type);
+ $result1 = $object->addLogCP($user->id, $object->fk_user, $object->ref.' - '.$langs->transnoentitiesnoconv("HolidayCreditAfterCancellation"), $newSolde, $object->fk_type);
// Update of the balance
$result2 = $object->updateSoldeCP($object->fk_user, $newSolde, $object->fk_type);
diff --git a/htdocs/holiday/class/holiday.class.php b/htdocs/holiday/class/holiday.class.php
index 1086bf64a75..bb1a02dc179 100644
--- a/htdocs/holiday/class/holiday.class.php
+++ b/htdocs/holiday/class/holiday.class.php
@@ -505,6 +505,7 @@ class Holiday extends CommonObject
*/
public function fetchByUser($user_id, $order = '', $filter = '')
{
+ $this->holiday = [];
$sql = "SELECT";
$sql .= " cp.rowid,";
$sql .= " cp.ref,";
@@ -1657,36 +1658,36 @@ class Holiday extends CommonObject
*/
public function updateSoldeCP($userID = 0, $nbHoliday = 0, $fk_type = 0)
{
- global $user, $langs;
+ global $user, $langs, $conf;
$error = 0;
if (empty($userID) && empty($nbHoliday) && empty($fk_type)) {
$langs->load("holiday");
+ $decrease = getDolGlobalInt('HOLIDAY_DECREASE_AT_END_OF_MONTH');
+
// Si mise à jour pour tout le monde en début de mois
$now = dol_now();
- $month = date('m', $now);
- $newdateforlastupdate = dol_print_date($now, '%Y%m%d%H%M%S');
-
// Get month of last update
- $lastUpdate = $this->getConfCP('lastUpdate', $newdateforlastupdate);
- $monthLastUpdate = $lastUpdate[4].$lastUpdate[5];
+ $lastUpdate = dol_stringtotime($this->getConfCP('lastUpdate', dol_print_date($now, '%Y%m%d%H%M%S')));
//print 'month: '.$month.' lastUpdate:'.$lastUpdate.' monthLastUpdate:'.$monthLastUpdate;exit;
- // If month date is not same than the one of last update (the one we saved in database), then we update the timestamp and balance of each open user.
- if ($month != $monthLastUpdate) {
+ $yearMonthLastUpdate = dol_print_date($lastUpdate, '%Y%m');
+ $yearMonthNow = dol_print_date($now, '%Y%m');
+
+ // If month date is not same than the one of last update (the one we saved in database), then we update the timestamp and balance of each open user,
+ // catching up to the current month if a gap is detected
+ while ($yearMonthLastUpdate < $yearMonthNow) {
$this->db->begin();
+ $year = dol_print_date($lastUpdate, '%Y');
+ $month = dol_print_date($lastUpdate, '%m');
+
$users = $this->fetchUsers(false, false, ' AND u.statut > 0');
$nbUser = count($users);
- $sql = "UPDATE ".MAIN_DB_PREFIX."holiday_config SET";
- $sql .= " value = '".$this->db->escape($newdateforlastupdate)."'";
- $sql .= " WHERE name = 'lastUpdate'";
- $result = $this->db->query($sql);
-
$typeleaves = $this->getTypes(1, 1);
// Update each user counter
@@ -1701,27 +1702,89 @@ class Holiday extends CommonObject
$nowHoliday = (float) $userCounter['nb_holiday'];
$newSolde = $nowHoliday + $nbDaysToAdd;
- // We add a log for each user
- $this->addLogCP($user->id, $userCounter['rowid'], $langs->trans('HolidaysMonthlyUpdate'), $newSolde, $userCounter['type']);
+ // We add a log for each user when its balance gets increased
+ $this->addLogCP($user->id, $userCounter['rowid'], $langs->trans('HolidayMonthlyCredit'), $newSolde, $userCounter['type']);
$result = $this->updateSoldeCP($userCounter['rowid'], $newSolde, $userCounter['type']);
if ($result < 0) {
- $error++;
- break;
+ $this->db->rollback();
+ return -1;
+ }
+
+ if (empty($decrease)) {
+ continue;
+ }
+
+ // We fetch a user's holiday in the current month and then calculate the number of days to deduct if he has at least one registered
+ $filter = " AND cp.statut = ".((int) self::STATUS_APPROVED);
+ $filter .= " AND cp.date_fin >= '".$this->db->idate(dol_stringtotime(dol_print_date($lastUpdate, '%Y-%m-01')))."'";
+ $filter .= " AND cp.date_debut <= '".$this->db->idate(dol_stringtotime(dol_print_date($lastUpdate, '%Y-%m-t')))."'";
+ $filter .= " AND cp.fk_type = ".((int) $userCounter['type']);
+ $this->fetchByUser($userCounter['id'], '', $filter);
+
+ if (empty($this->holiday)) {
+ continue;
+ }
+
+ $startOfMonth = dol_mktime(0, 0, 0, (int) $month, 1, (int) $year, 1);
+ $endOfMonth = dol_mktime(0, 0, 0, (int) $month, (int) dol_print_date($lastUpdate, 't'), (int) $year, 1);
+
+ foreach ($this->holiday as $obj) {
+ $startDate = $obj['date_debut_gmt'];
+ $endDate = $obj['date_fin_gmt'];
+
+ if ($startDate <= $endOfMonth && $startDate < $startOfMonth) {
+ $startDate = $startOfMonth;
+ }
+
+ if ($startOfMonth <= $endDate && $endDate > $endOfMonth) {
+ $endDate = $endOfMonth;
+ }
+
+ $nbDaysToDeduct = (int) num_open_day($startDate, $endDate, 0, 1, $obj['halfday']);
+
+ if ($nbDaysToDeduct <= 0) {
+ continue;
+ }
+
+ $newSolde -= $nbDaysToDeduct;
+
+ // We add a log for each user when its balance gets decreased
+ $this->addLogCP($user->id, $userCounter['rowid'], $obj['ref'].' - '.$langs->trans('HolidayConsumption'), $newSolde, $userCounter['type']);
+
+ $result = $this->updateSoldeCP($userCounter['rowid'], $newSolde, $userCounter['type']);
+
+ if ($result < 0) {
+ $this->db->rollback();
+ return -1;
+ }
}
}
- if (!$error) {
- $this->db->commit();
- return 1;
- } else {
+ //updating the date of the last monthly balance update
+ $newMonth = dol_get_next_month((int) dol_print_date($lastUpdate, '%m'), (int) dol_print_date($lastUpdate, '%Y'));
+ $lastUpdate = dol_mktime(0, 0, 0, (int) $newMonth['month'], 1, (int) $newMonth['year']);
+ $sql = "UPDATE ".MAIN_DB_PREFIX."holiday_config SET";
+ $sql .= " value = '".$this->db->escape(dol_print_date($lastUpdate, '%Y%m%d%H%M%S'))."'";
+ $sql .= " WHERE name = 'lastUpdate'";
+ $result = $this->db->query($sql);
+
+ if (!$result) {
$this->db->rollback();
return -1;
}
+
+ $this->db->commit();
+
+ $yearMonthLastUpdate = dol_print_date($lastUpdate, '%Y%m');
}
- return 0;
+ if (!$error) {
+ return 1;
+ } else {
+ return 0;
+ }
} else {
// Mise à jour pour un utilisateur
$nbHoliday = price2num($nbHoliday, 5);
diff --git a/htdocs/langs/en_US/holiday.lang b/htdocs/langs/en_US/holiday.lang
index ec723e88812..03cc8e23d21 100644
--- a/htdocs/langs/en_US/holiday.lang
+++ b/htdocs/langs/en_US/holiday.lang
@@ -101,6 +101,9 @@ AutoValidationOnCreate=Automatic validation
FirstDayOfHoliday=Beginning day of leave request
LastDayOfHoliday=Ending day of leave request
HolidaysMonthlyUpdate=Monthly update
+HolidayMonthlyCredit=Monthly credit
+HolidayConsumption=Consumption
+HolidayCreditAfterCancellation=Credit after cancellation
ManualUpdate=Manual update
HolidaysCancelation=Leave request cancellation
EmployeeLastname=Employee last name
@@ -154,3 +157,4 @@ ConfirmMassIncreaseHoliday=Bulk leave balance increase
NumberDayAddMass=Number of day to add to the selection
ConfirmMassIncreaseHolidayQuestion=Are you sure you want to increase holiday of the %s selected record(s)?
HolidayQtyNotModified=Balance of remaining days for %s has not been changed
+ConsumeHolidaysAtTheEndOfTheMonthTheyAreTakenAt=Consume holidays at the end of the month they are taken at
diff --git a/htdocs/langs/fr_FR/holiday.lang b/htdocs/langs/fr_FR/holiday.lang
index 82e08b6ab15..859f6d0d00a 100644
--- a/htdocs/langs/fr_FR/holiday.lang
+++ b/htdocs/langs/fr_FR/holiday.lang
@@ -101,6 +101,9 @@ AutoValidationOnCreate=Validation automatique
FirstDayOfHoliday=Premier jour de congés
LastDayOfHoliday=Dernier jour de congés
HolidaysMonthlyUpdate=Mise à jour mensuelle
+HolidayMonthlyCredit=Crédit mensuel
+HolidayConsumption=Consommation
+HolidayCreditAfterCancellation=Crédit après annulation
ManualUpdate=Mise à jour manuelle
HolidaysCancelation=Annulation de la demande de congés
EmployeeLastname=Nom du salarié
@@ -155,3 +158,4 @@ ConfirmMassIncreaseHoliday=Augmentation massive du solde des congés
NumberDayAddMass=Nombre de jours à ajouter à la sélection
ConfirmMassIncreaseHolidayQuestion=Êtes-vous sûr de vouloir augmenter les vacances du ou des enregistrement(s) sélectionnés %s ?
HolidayQtyNotModified=Le solde des jours restants pour %s n'a pas été modifié
+ConsumeHolidaysAtTheEndOfTheMonthTheyAreTakenAt=Consommer les jours de congés à la fin du mois où ils sont pris