diff --git a/ChangeLog.md b/ChangeLog.md
index fd6f372..4c79d5c 100644
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,9 @@
# CHANGELOG MODULE TIMESHEETWEEK FOR [DOLIBARR ERP CRM](https://www.dolibarr.org)
+## 1.4.0
+- Ajoute un interrupteur d'administration pour activer le sélecteur quart de jour des salariés au forfait jour. / Adds an admin switch to enable the quarter-day selector for daily-rate employees.
+- Affiche les durées forfait jour (0.25, 0.5 et 1 jour) dans les PDF standard et de synthèse lorsque le quart de jour est actif. / Displays the daily-rate durations (0.25, 0.5 and 1 day) inside the standard and summary PDFs whenever quarter-day mode is enabled.
+
## 1.3.0
- Active la génération de PDF depuis la fiche hebdomadaire avec le widget Documents Dolibarr et respecte les modèles configurés dans la page de setup. / Enables PDF generation from the weekly sheet using Dolibarr's Documents widget and honours the templates configured in the setup page.
- Introduit le modèle PDF « standard_timesheetweek » basé sur la synthèse partagée afin de produire les fichiers dans le répertoire documentaire Dolibarr. / Introduces the "standard_timesheetweek" PDF model powered by the shared summary engine so files land into Dolibarr's document directory.
diff --git a/admin/setup.php b/admin/setup.php
index 3624524..1394de5 100644
--- a/admin/setup.php
+++ b/admin/setup.php
@@ -276,12 +276,12 @@ function timesheetweekListDocumentModels(array $directories, Translate $langs, a
// EN: Verify CSRF token when the request changes the configuration.
// FR: Vérifie le jeton CSRF lorsque la requête modifie la configuration.
-if (in_array($action, array('setmodule', 'setdoc', 'setdocmodel', 'delmodel'), true)) {
- if (function_exists('dol_verify_token')) {
- if (empty($token) || dol_verify_token($token) <= 0) {
- accessforbidden();
- }
+if (in_array($action, array('setmodule', 'setdoc', 'setdocmodel', 'delmodel', 'setquarterday'), true)) {
+ if (function_exists('dol_verify_token')) {
+ if (empty($token) || dol_verify_token($token) <= 0) {
+ accessforbidden();
}
+ }
}
// EN: Persist the chosen numbering module.
@@ -323,21 +323,37 @@ function timesheetweekListDocumentModels(array $directories, Translate $langs, a
// EN: Disable a PDF model and remove the default flag if needed.
// FR: Désactive un modèle PDF et supprime le statut par défaut si nécessaire.
if ($action === 'delmodel' && !empty($value)) {
- $res = timesheetweekDisableDocumentModel($value);
- if ($res > 0) {
- if ($value === getDolGlobalString('TIMESHEETWEEK_ADDON_PDF')) {
- dolibarr_del_const($db, 'TIMESHEETWEEK_ADDON_PDF', $conf->entity);
- }
- setEventMessages($langs->trans('ModelDisabled', $value), null, 'mesgs');
- } else {
- setEventMessages($langs->trans('Error'), null, 'errors');
+ $res = timesheetweekDisableDocumentModel($value);
+ if ($res > 0) {
+ if ($value === getDolGlobalString('TIMESHEETWEEK_ADDON_PDF')) {
+ dolibarr_del_const($db, 'TIMESHEETWEEK_ADDON_PDF', $conf->entity);
}
+ setEventMessages($langs->trans('ModelDisabled', $value), null, 'mesgs');
+ } else {
+ setEventMessages($langs->trans('Error'), null, 'errors');
+ }
+}
+
+// EN: Enable or disable the quarter-day selector for daily rate contracts.
+// FR: Active ou désactive le sélecteur quart de jour pour les contrats au forfait jour.
+if ($action === 'setquarterday') {
+ $targetValue = (int) GETPOST('value', 'int');
+ if ($targetValue !== 0) {
+ $targetValue = 1;
+ }
+ $res = dolibarr_set_const($db, 'TIMESHEETWEEK_QUARTERDAYFORDAILYCONTRACT', $targetValue, 'chaine', 0, '', $conf->entity);
+ if ($res > 0) {
+ setEventMessages($langs->trans('SetupSaved'), null, 'mesgs');
+ } else {
+ setEventMessages($langs->trans('Error'), null, 'errors');
+ }
}
// EN: Read the selected options so we can highlight them in the UI.
// FR: Lit les options sélectionnées pour les mettre en avant dans l'interface.
$selectedNumbering = getDolGlobalString('TIMESHEETWEEK_ADDON', 'mod_timesheetweek_standard');
$defaultPdf = getDolGlobalString('TIMESHEETWEEK_ADDON_PDF', 'standard_timesheetweek');
+$useQuarterDaySelector = getDolGlobalInt('TIMESHEETWEEK_QUARTERDAYFORDAILYCONTRACT', 0);
$directories = array_merge(array('/'), (array) $conf->modules_parts['models']);
// EN: Prepare a lightweight object to test numbering module activation.
@@ -438,6 +454,40 @@ function timesheetweekListDocumentModels(array $directories, Translate $langs, a
print '
';
+// EN: Display the helper switches dedicated to the daily-rate contract workflows.
+// FR: Affiche les commutateurs dédiés aux workflows des contrats au forfait jour.
+print load_fiche_titre($langs->trans('TimesheetWeekDailyRateOptions'), '', 'setup');
+print '
| '.$langs->trans('Name').' | '; +print ''.$langs->trans('Description').' | '; +print ''.$langs->trans('Status').' | '; +print '
|---|---|---|
| '.$langs->trans('TimesheetWeekQuarterDayForDailyContract').' | '; +print ''.$langs->trans('TimesheetWeekQuarterDayForDailyContractHelp').' | '; +print ''; + if (!empty($useQuarterDaySelector)) { + $url = $_SERVER['PHP_SELF'].'?action=setquarterday&value=0&token='.$pageToken; + print ''.img_picto($langs->trans('Disable'), 'switch_on').''; + } else { + $url = $_SERVER['PHP_SELF'].'?action=setquarterday&value=1&token='.$pageToken; + print ''.img_picto($langs->trans('Activate'), 'switch_off').''; + } + print ' | '; +print '
'.tw_pdf_format_cell_html($dailyRateLegendText).'
'; + } if (empty($tasksByProject)) { $htmlGrid .= ''.tw_pdf_format_cell_html($outputlangs->trans('NoTasksAssigned')).'
'; } else { @@ -848,10 +876,16 @@ protected function formatDays($value, $langs) */ protected function getDailyRateHoursMap() { - return array( + $map = array( 1 => 8.0, 2 => 4.0, 3 => 4.0 ); + if (getDolGlobalInt('TIMESHEETWEEK_QUARTERDAYFORDAILYCONTRACT', 0)) { + // EN: Register the quarter-day equivalence when the selector is enabled in configuration. + // FR: Enregistre l'équivalence du quart de jour lorsque le sélecteur est activé en configuration. + $map[4] = 2.0; + } + return $map; } } diff --git a/langs/en_US/timesheetweek.lang b/langs/en_US/timesheetweek.lang index 9afbe82..1762c7b 100644 --- a/langs/en_US/timesheetweek.lang +++ b/langs/en_US/timesheetweek.lang @@ -23,6 +23,10 @@ TimesheetWeekPDFModelsEmpty = No PDF template is available. PDFStandardTimesheetWeekDescription = Standard PDF model for weekly timesheets TimesheetWeekPdfReferenceLabel = Timesheet reference: %s TimesheetWeekPdfApprovedDetails = Approved on %s by %s +TimesheetWeekDailyRateOptions = Daily-rate options +TimesheetWeekDailyRateOptionsHelp = Configure the helpers available for daily-rate contracts. +TimesheetWeekQuarterDayForDailyContract = Quarter-day selector for daily-rate contracts +TimesheetWeekQuarterDayForDailyContractHelp = Allow daily-rate employees to declare quarter days instead of half-days only. NewSection=New section TIMESHEETWEEK_MYPARAM1 = My param 1 TIMESHEETWEEK_MYPARAM1Tooltip = My param 1 tooltip @@ -173,6 +177,10 @@ TimesheetWeekDailyRateLabel = Daily rate contract TimesheetWeekDailyRateFullDay = Full day TimesheetWeekDailyRateMorning = Morning TimesheetWeekDailyRateAfternoon = Afternoon +TimesheetWeekDailyRateOneDay = 1 day +TimesheetWeekDailyRateHalfDay = 0.5 day +TimesheetWeekDailyRateQuarterDay = 0.25 day +TimesheetWeekDailyRateDurationsLegend = Available daily-rate durations: %1$s / %2$s / %3$s LastModification = Last modification TotalDays = Total days TimesheetWeekTotalDays = Total days diff --git a/langs/fr_FR/timesheetweek.lang b/langs/fr_FR/timesheetweek.lang index acbcb95..c9bd0f9 100644 --- a/langs/fr_FR/timesheetweek.lang +++ b/langs/fr_FR/timesheetweek.lang @@ -23,6 +23,10 @@ TimesheetWeekPDFModelsEmpty = Aucun modèle PDF disponible. PDFStandardTimesheetWeekDescription = Modèle PDF standard pour les feuilles hebdomadaires TimesheetWeekPdfReferenceLabel = Référence de la feuille : %s TimesheetWeekPdfApprovedDetails = Approuvée le %s par %s +TimesheetWeekDailyRateOptions = Options forfait jour +TimesheetWeekDailyRateOptionsHelp = Configure les assistants disponibles pour les contrats au forfait jour. +TimesheetWeekQuarterDayForDailyContract = Sélecteur quart de jour pour forfait jour +TimesheetWeekQuarterDayForDailyContractHelp = Autorise les salariés au forfait jour à déclarer des quarts de jour au lieu des seules demi-journées. NewSection=Nouvelle section TIMESHEETWEEK_MYPARAM1 = Mon paramètre 1 TIMESHEETWEEK_MYPARAM1Tooltip = Info-bulle de mon paramètre 1 @@ -241,6 +245,10 @@ TimesheetWeekDailyRateLabel = Contrat forfait jour TimesheetWeekDailyRateFullDay = Journée TimesheetWeekDailyRateMorning = Matin TimesheetWeekDailyRateAfternoon = Après-midi +TimesheetWeekDailyRateOneDay = 1 jour +TimesheetWeekDailyRateHalfDay = 0.5 jour +TimesheetWeekDailyRateQuarterDay = 0.25 jour +TimesheetWeekDailyRateDurationsLegend = Durées forfait jour disponibles : %1$s / %2$s / %3$s LastModification = Dernière modification TotalDays = Total jours TimesheetWeekTotalDays = Total jours diff --git a/lib/timesheetweek_pdf.lib.php b/lib/timesheetweek_pdf.lib.php index 825b4fd..5ab7196 100644 --- a/lib/timesheetweek_pdf.lib.php +++ b/lib/timesheetweek_pdf.lib.php @@ -984,6 +984,20 @@ function tw_generate_summary_pdf($db, $conf, $langs, User $user, array $timeshee }); $sortedUsers = array_values($dataset); + // EN: Detect whether at least one daily-rate employee is included to display duration hints later on. + // FR: Détecte si au moins un salarié au forfait jour est inclus afin d'afficher les repères de durée ensuite. + $hasDailyRateEmployee = false; + foreach ($sortedUsers as $sortedUserSummary) { + if (!empty($sortedUserSummary['is_daily_rate'])) { + $hasDailyRateEmployee = true; + break; + } + } + + // EN: Remember if the quarter-day selector is enabled to conditionally show the duration legend in PDFs. + // FR: Mémorise si le sélecteur quart de jour est actif pour afficher conditionnellement la légende de durée dans les PDF. + $useQuarterDayDailyContract = (bool) getDolGlobalInt('TIMESHEETWEEK_QUARTERDAYFORDAILYCONTRACT', 0); + // EN: Track the lowest and highest ISO weeks among the selected records for filename generation. // FR: Suit les semaines ISO minimale et maximale parmi les enregistrements sélectionnés pour le nom du fichier. $earliestWeek = null; @@ -1133,6 +1147,27 @@ function tw_generate_summary_pdf($db, $conf, $langs, User $user, array $timeshee $usableWidth = $pdf->getPageWidth() - $margeGauche - $margeDroite; + // EN: Describe the legend reminding daily-rate durations whenever the quarter-day selector is active. + // FR: Décrit la légende rappelant les durées forfait jour lorsque le sélecteur quart de jour est actif. + $dailyRateLegendText = ''; + if ($useQuarterDayDailyContract && $hasDailyRateEmployee) { + $dailyRateLegendText = $langs->trans( + 'TimesheetWeekDailyRateDurationsLegend', + $langs->trans('TimesheetWeekDailyRateQuarterDay'), + $langs->trans('TimesheetWeekDailyRateHalfDay'), + $langs->trans('TimesheetWeekDailyRateOneDay') + ); + } + if ($dailyRateLegendText !== '') { + // EN: Print the legend in italics to highlight the duration equivalences without overpowering the tables. + // FR: Affiche la légende en italique pour mettre en avant les équivalences de durée sans dominer les tableaux. + $pdf->SetFont('', 'I', max($defaultFontSize - 1, 6)); + $pdf->SetX($margeGauche); + $pdf->MultiCell($usableWidth, 0, tw_pdf_normalize_string($dailyRateLegendText), 0, 'L', false); + $pdf->Ln(2); + $pdf->SetFont('', '', $defaultFontSize); + } + // EN: Describe the standard hour-based layout used for classic employees. // FR: Décrit la mise en page standard en heures utilisée pour les salariés classiques. $hoursColumnConfig = array( diff --git a/timesheetweek_card.php b/timesheetweek_card.php index 33acaac..6941e30 100644 --- a/timesheetweek_card.php +++ b/timesheetweek_card.php @@ -65,6 +65,9 @@ // EN: Default daily rate flag to avoid undefined notices before data loading. // FR: Définit le flag forfait jour par défaut pour éviter les notices avant chargement des données. +// EN: Default the quarter-day flag and daily rate usage before evaluating the employee profile. +// FR: Définit par défaut le drapeau quart de jour et l'utilisation du forfait avant d'évaluer le profil du salarié. +$useQuarterDayDailyContract = !empty($conf->global->TIMESHEETWEEK_QUARTERDAYFORDAILYCONTRACT); $isDailyRateEmployee = false; // ---- Fetch (set $object if id) ---- @@ -199,6 +202,28 @@ function tw_get_enabled_pdf_models(DoliDB $db) return $models; } +/** + * EN: Return the hour equivalents for each daily rate code (adds quarter-day when enabled). + * FR: Retourne les équivalences en heures pour chaque code forfait (ajoute le quart de jour si activé). + * + * @param bool $useQuarterDayDailyContract Flag for quarter-day support / Drapeau d'activation du quart de jour + * @return array