diff --git a/ChangeLog.md b/ChangeLog.md index a005123..431b0a3 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -8,6 +8,7 @@ - Affichage du libellé "Zone" devant chaque sélecteur quotidien. - Ajout de la traduction "Meals" en "Repas". - Ajout du script de mise à jour SQL (`sql/update_all.sql`) pour créer les compteurs hebdomadaires sur les données existantes. +- Redirection automatique vers la feuille existante en cas de création en doublon / Automatic redirect to the existing sheet when attempting a duplicate creation. - Ajout d'un accès rapide à la création de feuille d'heures via le menu supérieur. ## 1.0 diff --git a/README.md b/README.md index 832712b..62db4c5 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ ## Features - Statut "Scellée" / "Sealed" pour verrouiller les feuilles approuvées. +- Redirection automatique vers la feuille existante en cas de doublon / Automatic redirect to the existing sheet when a duplicate is requested. Description of the module... diff --git a/class/timesheetweek.class.php b/class/timesheetweek.class.php index 096a5b0..97ef6f2 100644 --- a/class/timesheetweek.class.php +++ b/class/timesheetweek.class.php @@ -149,11 +149,55 @@ public function create($user) return $this->id; } - /** - * Fetch by id or ref - * @param int|null $id - * @param string|null $ref - * @return int + /** + * EN: Fetch the existing timesheet for a user/week within an entity. + * FR: Récupère la feuille existante pour un utilisateur/semaine au sein d'une entité. + * + * @param int $userId Target user id + * @param int $year Target ISO year + * @param int $week Target ISO week number + * @param int|null $entity Optional entity identifier + * @return int >0 if found (id), 0 if not found, <0 on error + */ + public function fetchByUserWeek($userId, $year, $week, $entity = null) + { + global $conf; + + $this->error = ''; + $this->errors = array(); + + // EN: Determine the entity used for the lookup. + // FR: Détermine l'entité utilisée pour la recherche. + $entityId = ($entity !== null) ? (int) $entity : (int) $conf->entity; + + $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX.$this->table_element; + $sql .= " WHERE entity=".(int) $entityId; + $sql .= " AND fk_user=".(int) $userId; + $sql .= " AND year=".(int) $year; + $sql .= " AND week=".(int) $week; + $sql .= " LIMIT 1"; + + // EN: Execute the lookup to detect an existing record. + // FR: Exécute la recherche pour détecter un enregistrement existant. + $resql = $this->db->query($sql); + if (!$resql) { + $this->error = $this->db->lasterror(); + return -1; + } + + $obj = $this->db->fetch_object($resql); + if (!$obj) { + return 0; + } + + return $this->fetch((int) $obj->rowid); + } + + /** + * Fetch by id or ref + * @param int|null $id + * @param string|null $ref + * @return int */ public function fetch($id = null, $ref = null) { diff --git a/langs/en_US/timesheetweek.lang b/langs/en_US/timesheetweek.lang index 1e934ef..ddd8670 100644 --- a/langs/en_US/timesheetweek.lang +++ b/langs/en_US/timesheetweek.lang @@ -72,6 +72,7 @@ TimesheetUnsealed = Timesheet unsealed. StatusSetToDraft = Timesheet set back to draft status. ActionNotAllowedOnThisStatus = This action is not allowed on the current status. CannotSetDraftWhenSealed = A sealed timesheet must be unsealed before returning to draft status. +TimesheetWeekRedirectExisting = A timesheet already exists for this week. Redirecting to the existing sheet. Draft = Draft Submitted = Submitted Approved = Approved diff --git a/langs/fr_FR/timesheetweek.lang b/langs/fr_FR/timesheetweek.lang index 8ba7cd5..8b38dda 100644 --- a/langs/fr_FR/timesheetweek.lang +++ b/langs/fr_FR/timesheetweek.lang @@ -72,6 +72,7 @@ TimesheetUnsealed = Feuille de temps descellée. StatusSetToDraft = Feuille de temps repassée en brouillon. ActionNotAllowedOnThisStatus = Cette action n'est pas autorisée pour le statut actuel. CannotSetDraftWhenSealed = Une feuille scellée doit être descellée avant de repasser en brouillon. +TimesheetWeekRedirectExisting = Une feuille de temps existe déjà pour cette semaine. Redirection vers la feuille existante. Draft = Brouillon Submitted = Soumise Approved = Approuvée diff --git a/timesheetweek_card.php b/timesheetweek_card.php index 36664a2..4017ad4 100644 --- a/timesheetweek_card.php +++ b/timesheetweek_card.php @@ -327,13 +327,33 @@ function tw_can_validate_timesheet( } if ($action === 'add') { - $res = $object->create($user); - if ($res > 0) { - header("Location: ".$_SERVER["PHP_SELF"]."?id=".$object->id); - exit; - } else { - setEventMessages($object->error, $object->errors, 'errors'); - $action = 'create'; + $shouldCreate = true; // EN: Flag to know if creation must proceed. FR: Indicateur pour savoir si la création doit continuer. + if ($object->year > 0 && $object->week > 0) { + $existing = new TimesheetWeek($db); + // EN: Look for an existing timesheet for the same user and week. + // FR: Recherche une feuille existante pour le même utilisateur et la même semaine. + $existingRes = $existing->fetchByUserWeek($object->fk_user, $object->year, $object->week); + if ($existingRes > 0) { + setEventMessages($langs->trans('TimesheetWeekRedirectExisting'), null, 'warnings'); + header("Location: ".$_SERVER["PHP_SELF"]."?id=".$existing->id); + exit; + } + if ($existingRes < 0) { + setEventMessages($existing->error, $existing->errors, 'errors'); + $action = 'create'; + $shouldCreate = false; + } + } + + if ($shouldCreate) { + $res = $object->create($user); + if ($res > 0) { + header("Location: ".$_SERVER["PHP_SELF"]."?id=".$object->id); + exit; + } else { + setEventMessages($object->error, $object->errors, 'errors'); + $action = 'create'; + } } } }