Skip to content
Merged

1.6.2 #132

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
88d27c7
Fix specimen model
mapiolca Jan 2, 2026
12824e2
Update setup.php
mapiolca Jan 2, 2026
acb1730
Update ChangeLog.md
mapiolca Jan 2, 2026
1de8a05
Update timesheetweek.class.php
mapiolca Jan 2, 2026
e856a9b
Update timesheetweek.class.php
mapiolca Jan 2, 2026
3462346
Update timesheetweek.class.php
mapiolca Jan 2, 2026
d0c644c
Update timesheetweek.class.php
mapiolca Jan 2, 2026
900d9f2
Update timesheetweek.class.php
mapiolca Jan 2, 2026
43bb152
Update timesheetweek.class.php
mapiolca Jan 2, 2026
e15a271
Update timesheetweek.class.php
mapiolca Jan 3, 2026
ff8d3ee
Update timesheetweek.class.php
mapiolca Jan 3, 2026
e392d89
Update interface_99_modTimesheetWeek_TimesheetWeekTriggers.class.php
mapiolca Jan 3, 2026
5c861c3
Update interface_99_modTimesheetWeek_TimesheetWeekTriggers.class.php
mapiolca Jan 3, 2026
f7732de
Update interface_99_modTimesheetWeek_TimesheetWeekTriggers.class.php
mapiolca Jan 3, 2026
15bc953
Update interface_99_modTimesheetWeek_TimesheetWeekTriggers.class.php
mapiolca Jan 3, 2026
960d1da
Update interface_99_modTimesheetWeek_TimesheetWeekTriggers.class.php
mapiolca Jan 3, 2026
c002de4
Update interface_99_modTimesheetWeek_TimesheetWeekTriggers.class.php
mapiolca Jan 3, 2026
991e0d7
Update interface_99_modTimesheetWeek_TimesheetWeekTriggers.class.php
mapiolca Jan 3, 2026
dffaec8
Fix HTML email body and multipart handling
mapiolca Jan 3, 2026
074ab00
Normalize timesheet notification body newlines
mapiolca Jan 3, 2026
763ed8a
Merge pull request #130 from mapiolca/2026-01-03-fix-email-notificati…
mapiolca Jan 3, 2026
2a48c29
Merge pull request #131 from mapiolca/mapiolca-patch-1
mapiolca Jan 3, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion ChangeLog.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# CHANGELOG MODULE TIMESHEETWEEK FOR [DOLIBARR ERP CRM](https://www.dolibarr.org)

## 1.6.2 (14/12/2025)
## 1.6.2 (02/01/2026)
- Correctif : ajout de TimesheetWeek::initAsSpecimen() pour éviter une erreur fatale lors de l’aperçu du modèle de numérotation “advanced”. / Fix: add missing TimesheetWeek::initAsSpecimen() to prevent a fatal error when previewing the “advanced” numbering model.
- Correctif : prise en charge de action=updateMask dans la page de configuration pour enregistrer correctement le masque “advanced” (TIMESHEETWEEK_ADVANCED_MASK). / Fix: handle action=updateMask in setup page to correctly save the “advanced” mask (TIMESHEETWEEK_ADVANCED_MASK).
- Envoie les notifications de changement d'état avec des versions HTML pour conserver les actions et caractères spéciaux. / Sends status change notifications with HTML variants to preserve actions and special characters.
- Décode les entités HTML dans les objets générés pour afficher correctement les accents dans les courriels. / Decodes HTML entities in generated subjects to display accented characters correctly in emails.
- Calcule la signature des notifications en utilisant MAIN_APPLICATION_TITLE ou, à défaut, le nom de la société. / Builds notification signatures using MAIN_APPLICATION_TITLE or, if unavailable, the company name.
Expand Down
20 changes: 18 additions & 2 deletions admin/setup.php
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ function timesheetweekListDocumentModels(array $directories, Translate $langs, a
}

// EN: Verify CSRF token when the request changes the configuration.
if (in_array($action, array('setmodule', 'setdoc', 'setdocmodel', 'delmodel', 'setquarterday', 'savereminder', 'testreminder'), true)) {
if (in_array($action, array('setmodule', 'updateMask', 'setdoc', 'setdocmodel', 'delmodel', 'setquarterday', 'savereminder', 'testreminder'), true)) {
if (function_exists('dol_verify_token')) {
if (empty($token) || dol_verify_token($token) <= 0) {
accessforbidden();
Expand All @@ -304,6 +304,22 @@ function timesheetweekListDocumentModels(array $directories, Translate $langs, a
}
}

// EN: Persist mask configuration for numbering models (action=updateMask).
if ($action === 'updateMask') {
$maskconst = GETPOST('maskconst', 'alphanohtml');
$maskconst = preg_replace('/[^a-zA-Z0-9_]/', '', (string) $maskconst);
$maskvalue = GETPOST('maskvalue', 'nohtml'); // Allow mask tokens like {yy}{mm}...
if (!empty($maskconst)) {
$result = dolibarr_set_const($db, $maskconst, $maskvalue, 'chaine', 0, '', $conf->entity);
if ($result > 0) {
setEventMessages($langs->trans('SetupSaved'), null, 'mesgs');
} else {
setEventMessages($langs->trans('Error'), null, 'errors');
}
}
}


// EN: Set the default PDF model while ensuring the model is enabled.
if ($action === 'setdoc' && !empty($value)) {
$res = timesheetweekEnableDocumentModel($value, $docLabel, $scanDir);
Expand Down Expand Up @@ -737,4 +753,4 @@ function timesheetweekListDocumentModels(array $directories, Translate $langs, a
print dol_get_fiche_end();

llxFooter();
$db->close();
$db->close();
48 changes: 47 additions & 1 deletion class/timesheetweek.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,36 @@ public function __construct($db)
$this->dir_output = DOL_DATA_ROOT.'/timesheetweek';
}
}
/**
* Initialise un objet specimen (prévisualisation / exemple de numérotation).
*
* @return int 1 si OK, <0 si KO
*/
public function initAsSpecimen()
{
$ret = 1;

// CommonObject (Dolibarr) fournit généralement initAsSpecimenCommon()
if (method_exists($this, 'initAsSpecimenCommon')) {
$ret = $this->initAsSpecimenCommon();
if ($ret < 0) return $ret;
}

$now = dol_now();

$this->id = 0;
$this->ref = 'TSW-SPECIMEN';
$this->status = self::STATUS_DRAFT;

// Utilisé par le modèle de numérotation (get_next_value) via $object->date_creation
$this->date_creation = $now;

// Valeurs cohérentes si le masque exploite l'année / semaine
$this->year = (int) dol_print_date($now, '%Y');
$this->week = (int) dol_print_date($now, '%V');

return 1;
}

/**
* EN: Detect lazily if the database schema already stores the PDF model.
Expand Down Expand Up @@ -1596,6 +1626,11 @@ protected function sendAutomaticNotification($triggerCode, User $actionUser)
// EN: Build the direct link to the card so it can be injected inside the e-mail template.
$url = dol_buildpath('/timesheetweek/timesheetweek_card.php', 2).'?id='.(int) $this->id;

// FR: Conserve aussi une version HTML cliquable du lien.
// EN: Keep a clickable HTML version of the link as well.
$urlRaw = $url;
$urlHtml = '<a href="'.dol_escape_htmltag($urlRaw).'">'.dol_escape_htmltag($urlRaw).'</a>';

$employeeName = $employee ? $employee->getFullName($langs) : '';
$validatorName = $validator ? $validator->getFullName($langs) : '';
$actionUserName = $actionUser->getFullName($langs);
Expand All @@ -1606,7 +1641,8 @@ protected function sendAutomaticNotification($triggerCode, User $actionUser)
'__TIMESHEETWEEK_REF__' => $this->ref,
'__TIMESHEETWEEK_WEEK__' => $this->week,
'__TIMESHEETWEEK_YEAR__' => $this->year,
'__TIMESHEETWEEK_URL__' => $url,
'__TIMESHEETWEEK_URL__' => $urlHtml,
'__TIMESHEETWEEK_URL_RAW__' => $urlRaw,
'__TIMESHEETWEEK_EMPLOYEE_FULLNAME__' => $employeeName,
'__TIMESHEETWEEK_VALIDATOR_FULLNAME__' => $validatorName,
'__ACTION_USER_FULLNAME__' => $actionUserName,
Expand Down Expand Up @@ -1828,6 +1864,16 @@ public function sendNativeMailNotification($triggerCode, User $actionUser, $reci
$htmlMessage = isset($options['message_html']) ? (string) $options['message_html'] : $message;
$isHtml = !empty($options['ishtml']) ? 1 : 0;

if (empty($options['message_html'])) {
$htmlMessage = dol_nl2br(dol_escape_htmltag($message));
} else {
$htmlMessage = (string) $options['message_html'];
}

if (!empty($conf->global->MAIN_MAIL_USE_MULTI_PART) || $isHtml) {
$isHtml = 1;
}

$payload = array(
'trigger' => $triggerCode,
'action' => $triggerCode,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,48 @@ protected function sendNotification($action, TimesheetWeek $timesheet, User $act
$sendto = implode(',', array_unique(array_filter($sendtoList)));
$cc = implode(',', array_unique(array_filter($ccList)));
$bcc = implode(',', array_unique(array_filter($bccList)));
$messageHtml = !empty($template) ? $message : dol_nl2br($message);
// Normalize escaped newlines coming from lang/templates ("\\n" -> "\n")
$normalizeNewlines = function ($str) {
if ($str === null) return $str;

// Handle double-escaped sequences first
$str = str_replace(array('\\\\r\\\\n', '\\\\n', '\\\\r'), array("\r\n", "\n", "\r"), $str);
$str = preg_replace('/\\\\+r\\\\+n/', "\r\n", $str);
$str = preg_replace('/\\\\+n/', "\n", $str);
$str = preg_replace('/\\\\+r/', "\r", $str);

// Then handle standard escaped sequences
return str_replace(array('\\r\\n', '\\n', '\\r'), array("\r\n", "\n", "\r"), $str);
};

$messageText = $normalizeNewlines($message);
$messageText = str_replace(array("\\r\\n", "\\n", "\\r"), array("\r\n", "\n", "\r"), $messageText);

// Build HTML part from message (keep existing HTML if message already contains tags)
if (function_exists('dol_textishtml') && dol_textishtml($messageText)) {
$messageHtml = $messageText;
} else {
$messageHtml = dol_nl2br(dol_escape_htmltag($messageText));
}

// Make URL clickable in HTML part using Dolibarr helper (no regex linkify).
if (!empty($url) && function_exists('dol_print_url') && strpos($messageHtml, '<a ') === false) {
$escapedUrl = dol_escape_htmltag($url);
$clickableUrl = dol_print_url($url, '_blank', 255, 0, '');
if (!empty($clickableUrl)) {
$messageHtml = str_replace($escapedUrl, $clickableUrl, $messageHtml);
}
}
$messageHtml = str_replace(array("\\r\\n", "\\n", "\\r"), array('<br>', '<br>', ''), $messageHtml);

dol_syslog(
__METHOD__.
': prepare mail action='.$action.
' msgishtml=1 textlen='.(function_exists('dol_strlen') ? dol_strlen($messageText) : strlen($messageText)).
' htmllen='.(function_exists('dol_strlen') ? dol_strlen($messageHtml) : strlen($messageHtml)).
' haslink='.((strpos($messageHtml, '<a ') !== false) ? 'yes' : 'no'),
LOG_DEBUG
);
$trackId = 'timesheetweek-'.$timesheet->id.'-'.$action.'-'.($recipient ? (int) $recipient->id : 0);
$isHtml = 1;

Expand All @@ -430,7 +471,7 @@ protected function sendNotification($action, TimesheetWeek $timesheet, User $act
$substitutions,
array(
'subject' => $subject,
'message' => $message,
'message' => $messageText,
'message_html' => $messageHtml,
'sendto' => $sendto,
'cc' => $cc,
Expand Down