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