diff --git a/admin/setup.php b/admin/setup.php
index afa4118..5835354 100644
--- a/admin/setup.php
+++ b/admin/setup.php
@@ -33,18 +33,19 @@
$res = require_once __DIR__.'/../../../main.inc.php';
}
if (!$res) {
- die('Include of main fails');
+die('Include of main fails');
}
require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
-// EN: Load email template class with backward compatibility for older Dolibarr versions.
+require_once DOL_DOCUMENT_ROOT.'/cron/class/cronjob.class.php';
+// EN: Load email template class with version-aware fallback.
-if (floatval(DOL_VERSION) < 23) {
- dol_include_once('/timesheetweek/core/class/cemailtemplate.class.php');
+if (version_compare(DOL_VERSION, '23.0.0', '>=') || file_exists(DOL_DOCUMENT_ROOT.'/core/class/cemailtemplate.class.php')) {
+require_once DOL_DOCUMENT_ROOT.'/core/class/cemailtemplate.class.php';
} else {
- require_once DOL_DOCUMENT_ROOT.'/core/class/cemailtemplate.class.php';
+require_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
}
require_once DOL_DOCUMENT_ROOT.'/core/lib/doc.lib.php';
@@ -354,30 +355,41 @@ function timesheetweekListDocumentModels(array $directories, Translate $langs, a
}
if ($action === 'savereminder') {
-$reminderEnabledValue = (int) GETPOST('TIMESHEETWEEK_REMINDER_ENABLED', 'int');
-$reminderWeekdayValue = (int) GETPOST('TIMESHEETWEEK_REMINDER_WEEKDAY', 'int');
-$reminderHourValue = trim(GETPOST('TIMESHEETWEEK_REMINDER_HOUR', 'alphanohtml'));
-$reminderTemplateValue = (int) GETPOST('TIMESHEETWEEK_REMINDER_EMAIL_TEMPLATE', 'int');
-
- $error = 0;
-
- if ($reminderWeekdayValue < 1 || $reminderWeekdayValue > 7) {
- setEventMessages($langs->trans('TimesheetWeekReminderWeekdayInvalid'), null, 'errors');
- $error++;
+ $reminderEnabledValue = (int) GETPOST('TIMESHEETWEEK_REMINDER_ENABLED', 'int');
+ $reminderStartYear = (int) GETPOST('TIMESHEETWEEK_REMINDER_STARTTIMEyear', 'int');
+ $reminderStartMonth = (int) GETPOST('TIMESHEETWEEK_REMINDER_STARTTIMEmonth', 'int');
+ $reminderStartDay = (int) GETPOST('TIMESHEETWEEK_REMINDER_STARTTIMEday', 'int');
+ $reminderStartHour = (int) GETPOST('TIMESHEETWEEK_REMINDER_STARTTIMEhour', 'int');
+ $reminderStartMinute = (int) GETPOST('TIMESHEETWEEK_REMINDER_STARTTIMEmin', 'int');
+ $reminderTemplateValue = (int) GETPOST('TIMESHEETWEEK_REMINDER_EMAIL_TEMPLATE', 'int');
+ $reminderExcludedUsersValue = GETPOST('TIMESHEETWEEK_REMINDER_EXCLUDED_USERS', 'array');
+ $reminderExcludedUsersList = array();
+ if (is_array($reminderExcludedUsersValue)) {
+ foreach ($reminderExcludedUsersValue as $reminderExcludedUserId) {
+ $reminderExcludedUserId = (int) $reminderExcludedUserId;
+ if ($reminderExcludedUserId > 0) {
+ $reminderExcludedUsersList[] = $reminderExcludedUserId;
+ }
+ }
}
-
- if (!preg_match('/^(?:[01]\\d|2[0-3]):[0-5]\\d$/', $reminderHourValue)) {
- setEventMessages($langs->trans('TimesheetWeekReminderHourInvalid'), null, 'errors');
+
+
+
+ $error = 0;
+
+ $reminderStartTimestamp = dol_mktime($reminderStartHour, $reminderStartMinute, 0, $reminderStartMonth, $reminderStartDay, $reminderStartYear);
+ if (empty($reminderStartTimestamp)) {
+ setEventMessages($langs->trans('TimesheetWeekReminderStartTimeInvalid'), null, 'errors');
$error++;
}
-
+
if (!$error) {
$results = array();
$results[] = dolibarr_set_const($db, 'TIMESHEETWEEK_REMINDER_ENABLED', ($reminderEnabledValue ? 1 : 0), 'chaine', 0, '', $conf->entity);
- $results[] = dolibarr_set_const($db, 'TIMESHEETWEEK_REMINDER_WEEKDAY', $reminderWeekdayValue, 'chaine', 0, '', $conf->entity);
- $results[] = dolibarr_set_const($db, 'TIMESHEETWEEK_REMINDER_HOUR', $reminderHourValue, 'chaine', 0, '', $conf->entity);
+ $results[] = dolibarr_set_const($db, 'TIMESHEETWEEK_REMINDER_STARTTIME', (string) $reminderStartTimestamp, 'chaine', 0, '', $conf->entity);
$results[] = dolibarr_set_const($db, 'TIMESHEETWEEK_REMINDER_EMAIL_TEMPLATE', $reminderTemplateValue, 'chaine', 0, '', $conf->entity);
-
+ $results[] = dolibarr_set_const($db, 'TIMESHEETWEEK_REMINDER_EXCLUDED_USERS', implode(',', $reminderExcludedUsersList), 'chaine', 0, '', $conf->entity);
+
$hasError = false;
foreach ($results as $resultValue) {
if ($resultValue <= 0) {
@@ -385,23 +397,28 @@ function timesheetweekListDocumentModels(array $directories, Translate $langs, a
break;
}
}
-
+
if ($hasError) {
setEventMessages($langs->trans('Error'), null, 'errors');
} else {
+ $cronUpdate = TimesheetweekReminder::updateCronStartTime($db, $reminderStartTimestamp, $user);
+ if ($cronUpdate < 0) {
+ setEventMessages($langs->trans('TimesheetWeekReminderCronUpdateFailed'), null, 'errors');
+ } elseif ($cronUpdate === 0) {
+ setEventMessages($langs->trans('TimesheetWeekReminderCronMissing'), null, 'warnings');
+ }
setEventMessages($langs->trans('SetupSaved'), null, 'mesgs');
}
}
}
- if ($action === 'testreminder') {
+if ($action === 'testreminder') {
$reminder = new TimesheetweekReminder($db);
- $resultTest = $reminder->sendTest($db, $user); //$resultTest = TimesheetweekReminder::sendTest($db, $user);
- //var_dump($resultTest);
- if ($resultTest == 0) {
- setEventMessages($langs->trans('TimesheetWeekReminderTestSuccess'), null, 'mesgs');
+ $resultTest = $reminder->sendTest($user);
+ if ($resultTest >= 0) {
+ setEventMessages($langs->trans('TimesheetWeekReminderTestSuccess'), null, 'mesgs');
} else {
- setEventMessages($langs->trans('TimesheetWeekReminderTestError'), null, 'errors');
+ setEventMessages($langs->trans('TimesheetWeekReminderTestError'), null, 'errors');
}
}
@@ -410,9 +427,43 @@ function timesheetweekListDocumentModels(array $directories, Translate $langs, a
$defaultPdf = getDolGlobalString('TIMESHEETWEEK_ADDON_PDF', 'standard_timesheetweek');
$useQuarterDaySelector = getDolGlobalInt('TIMESHEETWEEK_QUARTERDAYFORDAILYCONTRACT', 0);
$reminderEnabled = getDolGlobalInt('TIMESHEETWEEK_REMINDER_ENABLED', 0);
-$reminderWeekday = getDolGlobalInt('TIMESHEETWEEK_REMINDER_WEEKDAY', 1);
-$reminderHour = getDolGlobalString('TIMESHEETWEEK_REMINDER_HOUR', '18:00');
+$reminderStartValue = getDolGlobalString('TIMESHEETWEEK_REMINDER_STARTTIME', '');
+$reminderStartTimestamp = '';
+if ($reminderStartValue !== '') {
+ if (is_numeric($reminderStartValue)) {
+ $reminderStartTimestamp = (int) $reminderStartValue;
+ } else {
+ $reminderStartTimestamp = dol_stringtotime($reminderStartValue, 0);
+ }
+}
+if (empty($reminderStartTimestamp)) {
+ $reminderStartTimestamp = dol_now();
+}
+$reminderCurrentHour = (int) dol_print_date($reminderStartTimestamp, '%H');
+$reminderCurrentMinute = (int) dol_print_date($reminderStartTimestamp, '%M');
+$reminderWeekday = (int) dol_print_date($reminderStartTimestamp, '%w');
+$now = dol_now();
+$currentWeekday = (int) dol_print_date($now, '%w');
+$daysAhead = ($reminderWeekday - $currentWeekday + 7) % 7;
+$referenceDate = dol_time_plus_duree($now, $daysAhead, 'd');
+$referenceYear = (int) dol_print_date($referenceDate, '%Y');
+$referenceMonth = (int) dol_print_date($referenceDate, '%m');
+$referenceDay = (int) dol_print_date($referenceDate, '%d');
+$nextReminderTimestamp = dol_mktime($reminderCurrentHour, $reminderCurrentMinute, 0, $referenceMonth, $referenceDay, $referenceYear);
+if ($nextReminderTimestamp <= $now) {
+ $nextReminderTimestamp = dol_time_plus_duree($nextReminderTimestamp, 7, 'd');
+}
+if ($nextReminderTimestamp !== $reminderStartTimestamp) {
+ dolibarr_set_const($db, 'TIMESHEETWEEK_REMINDER_STARTTIME', (string) $nextReminderTimestamp, 'chaine', 0, '', $conf->entity);
+ TimesheetweekReminder::updateCronStartTime($db, $nextReminderTimestamp, $user);
+}
+$reminderStartTimestamp = $nextReminderTimestamp;
$reminderTemplateId = getDolGlobalInt('TIMESHEETWEEK_REMINDER_EMAIL_TEMPLATE', 0);
+$reminderExcludedUsersString = getDolGlobalString('TIMESHEETWEEK_REMINDER_EXCLUDED_USERS', '');
+$reminderExcludedUsers = array();
+if ($reminderExcludedUsersString !== '') {
+ $reminderExcludedUsers = array_filter(array_map('intval', explode(',', $reminderExcludedUsersString)));
+}
$directories = array_merge(array('/'), (array) $conf->modules_parts['models']);
// EN: Prepare a lightweight object to test numbering module activation.
@@ -582,32 +633,44 @@ function timesheetweekListDocumentModels(array $directories, Translate $langs, a
print '';
print '';
-$weekdayOptions = array(
-1 => $langs->trans('Monday'),
-2 => $langs->trans('Tuesday'),
-3 => $langs->trans('Wednesday'),
-4 => $langs->trans('Thursday'),
-5 => $langs->trans('Friday'),
-6 => $langs->trans('Saturday'),
-7 => $langs->trans('Sunday'),
-);
+$selectStartTime = $form->select_date($reminderStartTimestamp, 'TIMESHEETWEEK_REMINDER_STARTTIME', 1, 1, 0, '', 1, 0, 1, '', 0, 0, '', '', '', '');
print '
';
-print '| '.$langs->trans('TimesheetWeekReminderWeekday').' | ';
-print ''.$langs->trans('TimesheetWeekReminderWeekdayHelp').' | ';
-print ''.$form->selectarray('TIMESHEETWEEK_REMINDER_WEEKDAY', $weekdayOptions, $reminderWeekday, 0, 0, 0, '', 0, 0, 0, '', '', 1).' | ';
+print ''.$langs->trans('TimesheetWeekReminderStartTime').' | ';
+print ''.$langs->trans('TimesheetWeekReminderStartTimeHelp').' | ';
+print ''.$selectStartTime.' | ';
print '
';
print '';
-print '| '.$langs->trans('TimesheetWeekReminderHour').' | ';
-print ''.$langs->trans('TimesheetWeekReminderHourHelp').' | ';
-print ' | ';
+print ''.$langs->trans('TimesheetWeekReminderEmailTemplate').' | ';
+print ''.$langs->trans('TimesheetWeekReminderEmailTemplateHelp').' | ';
+print ''.$form->selectarray('TIMESHEETWEEK_REMINDER_EMAIL_TEMPLATE', $templateOptions, $reminderTemplateId, 0, 0, 0, '', 0, 0, 0, '', '', $conf->entity).' | ';
print '
';
+$selectExcludedUsers = $form->select_dolusers(
+$reminderExcludedUsers,
+'TIMESHEETWEEK_REMINDER_EXCLUDED_USERS',
+0,
+'',
+0,
+'',
+'',
+0,
+0,
+0,
+'',
+0,
+'',
+'minwidth300',
+0,
+0,
+1
+);
+
print '';
-print '| '.$langs->trans('TimesheetWeekReminderEmailTemplate').' | ';
-print ''.$langs->trans('TimesheetWeekReminderEmailTemplateHelp').' | ';
-print ''.$form->selectarray('TIMESHEETWEEK_REMINDER_EMAIL_TEMPLATE', $templateOptions, $reminderTemplateId, 0, 0, 0, '', 0, 0, 0, '', '', 1).' | ';
+print ''.$langs->trans('TimesheetWeekReminderExcludedUsers').' | ';
+print ''.$langs->trans('TimesheetWeekReminderExcludedUsersHelp').' | ';
+print ''.$selectExcludedUsers.' | ';
print '
';
print '';
diff --git a/class/timesheetweek_reminder.class.php b/class/timesheetweek_reminder.class.php
index 9c9d47e..7f3e984 100644
--- a/class/timesheetweek_reminder.class.php
+++ b/class/timesheetweek_reminder.class.php
@@ -37,8 +37,10 @@
require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/functions.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
+require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php';
require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
+require_once DOL_DOCUMENT_ROOT.'/cron/class/cronjob.class.php';
dol_include_once('/timesheetweek/class/timesheetweek.class.php');
@@ -49,43 +51,47 @@
class TimesheetweekReminder extends CommonObject
{
public $db;
- public $error;
- public $errors = array();
- public $output;
-
- public function __construct(DoliDB $db)
- {
- $this->db = $db;
- }
+ public $error;
+ public $errors = array();
+ public $output;
+
+ public function __construct(DoliDB $db)
+ {
+ $this->db = $db;
+ }
/**
- * Run cron job to send weekly reminder emails.
- *
- * @param DoliDB $db Database handler
- * @param int $limit Optional limit for recipients
- * @param int $forcerun Force execution (1) or use normal scheduling (0)
- * @param array $targetUserIds Limit execution to specific user ids when provided
- * @return int <0 if KO, >=0 if OK (number of emails sent)
- */
- public function run($dbInstance = null, $limit = 0, $forcerun = 0, array $targetUserIds = array()) //$dbInstance = null,
+ * Run cron job to send weekly reminder emails.
+ *
+ * @param DoliDB|null $dbInstance Optional database handler override
+ * @param int $limit Optional limit for recipients
+ * @param int $forcerun Force execution (1) or use normal scheduling (0)
+ * @param array $targetUserIds Limit execution to specific user ids when provided
+ * @return int <0 if KO, >=0 if OK (number of emails sent)
+ */
+ public function run($dbInstance = null, $limit = 0, $forcerun = 0, array $targetUserIds = array())
{
global $db, $conf, $user, $langs;
- /*
- $db = $dbInstance;
- if (empty($db) && !empty($GLOBALS['db'])) {
- $db = $GLOBALS['db'];
- }
- */
- if (empty($db)) {
- dol_syslog($langs->transnoentitiesnoconv('ErrorNoDatabase'), LOG_ERR);
- return -1;
+ if ($dbInstance instanceof DoliDB) {
+ $this->db = $dbInstance;
+ } elseif (!empty($db) && $db instanceof DoliDB) {
+ $this->db = $db;
}
-
+
+ if (empty($this->db)) {
+ $this->error = $langs->trans('ErrorNoDatabase');
+ $this->output = $this->error;
+ dol_syslog($this->error, LOG_ERR);
+ return 0;
+ }
+
+ $db = $this->db;
+
$langs->loadLangs(array('timesheetweek@timesheetweek'));
$forceExecution = !empty($forcerun);
if (!$forceExecution) {
- $forceExecution = ((int) GETPOST('forcerun', 'int') > 0);
+ $forceExecution = ((int) GETPOST('forcerun', 'int') > 0);
}
if (!$forceExecution) {
$action = GETPOST('action', 'aZ09');
@@ -95,88 +101,71 @@ public function run($dbInstance = null, $limit = 0, $forcerun = 0, array $target
}
}
- if (floatval(DOL_VERSION) < 23) {
- dol_include_once('/timesheetweek/core/class/cemailtemplate.class.php');
- } else {
+ $useCoreTemplateClass = (version_compare(DOL_VERSION, '23.0.0', '>=') || file_exists(DOL_DOCUMENT_ROOT.'/core/class/cemailtemplate.class.php')) ? true : false;
+ if ($useCoreTemplateClass) {
require_once DOL_DOCUMENT_ROOT.'/core/class/cemailtemplate.class.php';
+ dol_syslog(__METHOD__.' use core CEmailTemplate', LOG_DEBUG);
+ } else {
+ require_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
+ dol_syslog(__METHOD__.' use ModelMail', LOG_DEBUG);
}
- if (!class_exists('CEmailTemplate') && !class_exists('EmailTemplate')) {
- dol_syslog($langs->trans('ErrorFailedToLoadEmailTemplateClass'), LOG_ERR);
- return -1;
- }
-
- dol_syslog(__METHOD__, LOG_DEBUG);
-
$reminderEnabled = getDolGlobalInt('TIMESHEETWEEK_REMINDER_ENABLED', 0, $conf->entity);
if (empty($reminderEnabled) && empty($forceExecution)) {
dol_syslog('TimesheetweekReminder: reminder disabled', LOG_INFO);
+ $this->output = $langs->trans('TimesheetWeekReminderDisabled');
return 0;
}
- $reminderWeekday = getDolGlobalInt('TIMESHEETWEEK_REMINDER_WEEKDAY', 1, $conf->entity);
- if ($reminderWeekday < 1 || $reminderWeekday > 7) {
- dol_syslog($langs->trans('TimesheetWeekReminderWeekdayInvalid'), LOG_ERR);
- return -1;
+ $reminderStartValue = getDolGlobalString('TIMESHEETWEEK_REMINDER_STARTTIME', '', $conf->entity);
+ $reminderStartTimestamp = 0;
+ if ($reminderStartValue !== '') {
+ if (is_numeric($reminderStartValue)) {
+ $reminderStartTimestamp = (int) $reminderStartValue;
+ } else {
+ $reminderStartTimestamp = dol_stringtotime($reminderStartValue, 0);
+ }
}
-
- $reminderHour = getDolGlobalString('TIMESHEETWEEK_REMINDER_HOUR', '18:00', $conf->entity);
- if (!preg_match('/^(?:[01]\\d|2[0-3]):[0-5]\\d$/', $reminderHour)) {
- dol_syslog($langs->trans('TimesheetWeekReminderHourInvalid'), LOG_ERR);
- return -1;
+ if (empty($reminderStartTimestamp)) {
+ $this->error = $langs->trans('TimesheetWeekReminderStartTimeInvalid');
+ $this->output = $this->error;
+ dol_syslog($this->error, LOG_ERR);
+ return 0;
}
$templateId = getDolGlobalInt('TIMESHEETWEEK_REMINDER_EMAIL_TEMPLATE', 0, $conf->entity);
if (empty($templateId)) {
- dol_syslog($langs->trans('TimesheetWeekReminderTemplateMissing'), LOG_WARNING);
+ $this->error = $langs->trans('TimesheetWeekReminderTemplateMissing');
+ $this->output = $this->error;
+ dol_syslog($this->error, LOG_WARNING);
return 0;
}
- $timezoneCode = !empty($conf->timezone) ? $conf->timezone : 'UTC';
- $now = dol_now();
- $nowArray = dol_getdate($now, true, $timezoneCode);
- $currentWeekday = (int) $nowArray['wday'];
- $currentWeekdayIso = ($currentWeekday === 0) ? 7 : $currentWeekday;
- $currentMinutes = ((int) $nowArray['hours'] * 60) + (int) $nowArray['minutes'];
-
- list($targetHour, $targetMinute) = explode(':', $reminderHour);
- $targetMinutes = ((int) $targetHour * 60) + (int) $targetMinute;
- $windowMinutes = 5;
- $lowerBound = max(0, $targetMinutes - $windowMinutes);
- $upperBound = min(120, $targetMinutes + $windowMinutes);
-
- if (empty($forceExecution)) {
- if ($currentWeekdayIso !== $reminderWeekday) {
- dol_syslog('TimesheetweekReminder: not the configured day, skipping execution', LOG_DEBUG);
- return 0;
- }
- if ($currentMinutes < $lowerBound || $currentMinutes > $upperBound) {
- dol_syslog('TimesheetweekReminder: outside configured time window, skipping execution', LOG_DEBUG);
- return 0;
- }
- }
-
$emailTemplate = null;
$templateFetch = 0;
- if (class_exists('CEmailTemplate')) {
+ if ($useCoreTemplateClass && class_exists('CEmailTemplate')) {
$emailTemplate = new CEmailTemplate($db);
if (method_exists($emailTemplate, 'apifetch')) {
$templateFetch = $emailTemplate->apifetch($templateId);
} else {
$templateFetch = $emailTemplate->fetch($templateId);
}
- } elseif (class_exists('EmailTemplate')) {
- $emailTemplate = new EmailTemplate($db);
- $templateFetch = $emailTemplate->fetch($templateId);
- }
-
- if (empty($emailTemplate)) {
- dol_syslog($langs->trans('TimesheetWeekReminderTemplateMissing'), LOG_ERR);
- return -1;
+ if ($templateFetch > 0) {
+ dol_syslog(__METHOD__.' template fetched via CEmailTemplate id='.$templateId, LOG_DEBUG);
+ }
+ } elseif (!$useCoreTemplateClass && class_exists('FormMail')) {
+ $formMail = new FormMail($db);
+ $emailTemplate = $formMail->getEMailTemplate($db, 'actioncomm_send', $user, $langs, $templateId, 1);
+ if ($emailTemplate instanceof ModelMail && $emailTemplate->id > 0) {
+ $templateFetch = 1;
+ dol_syslog(__METHOD__.' template fetched via ModelMail id='.$templateId, LOG_DEBUG);
+ }
}
- if ($templateFetch <= 0) {
- dol_syslog($langs->trans('TimesheetWeekReminderTemplateMissing'), LOG_WARNING);
+ if (empty($emailTemplate) || $templateFetch <= 0) {
+ $this->error = $langs->trans('TimesheetWeekReminderTemplateMissing');
+ $this->output = $this->error;
+ dol_syslog($this->error, LOG_ERR);
return 0;
}
@@ -184,11 +173,16 @@ public function run($dbInstance = null, $limit = 0, $forcerun = 0, array $target
$body = !empty($emailTemplate->content) ? $emailTemplate->content : '';
if (empty($subject) || empty($body)) {
- dol_syslog($langs->trans('TimesheetWeekReminderTemplateMissing'), LOG_WARNING);
+ $this->error = $langs->trans('TimesheetWeekReminderTemplateMissing');
+ $this->output = $this->error;
+ dol_syslog($this->error, LOG_WARNING);
return 0;
}
- $from = getDolGlobalString('MAIN_MAIL_EMAIL_FROM', '');
+ $from = (!empty($emailTemplate->email_from) ? $emailTemplate->email_from : '');
+ if (empty($from)) {
+ $from = getDolGlobalString('MAIN_MAIL_EMAIL_FROM', '');
+ }
if (empty($from)) {
$from = getDolGlobalString('MAIN_INFO_SOCIETE_MAIL', '');
}
@@ -196,28 +190,27 @@ public function run($dbInstance = null, $limit = 0, $forcerun = 0, array $target
$substitutions = getCommonSubstitutionArray($langs, 0, null, null, null);
complete_substitutions_array($substitutions, $langs, null);
- $eligibleRights = array(
- 45000301, // read own
- 45000302, // read child
- 45000303, // read all
- 45000304, // write own
- 45000305, // write child
- 45000306, // write all
- 45000310, // validate generic
- 45000311, // validate own
- 45000312, // validate child
- 45000313, // validate all
- 45000314, // seal
- 45000315, // unseal
- );
-
- $entityFilter = getEntity('user');
+ $excludedUsersString = getDolGlobalString('TIMESHEETWEEK_REMINDER_EXCLUDED_USERS', '', $conf->entity);
+ $excludedUsers = array();
+ if ($excludedUsersString !== '') {
+ $excludedUsers = array_filter(array_map('intval', explode(',', $excludedUsersString)));
+ }
+
$sql = 'SELECT DISTINCT u.rowid, u.lastname, u.firstname, u.email';
$sql .= ' FROM '.MAIN_DB_PREFIX."user AS u";
- $sql .= ' INNER JOIN '.MAIN_DB_PREFIX."user_rights AS ur ON ur.fk_user = u.rowid AND ur.entity IN (".$entityFilter.')';
+ if (isModEnabled('multicompany') && getDolGlobalString('MULTICOMPANY_TRANSVERSE_MODE')) {
+ $sql .= " INNER JOIN ".MAIN_DB_PREFIX."usergroup_user as ug";
+ $sql .= " ON ((ug.fk_user = u.rowid";
+ $sql .= " AND ug.entity IN (".getEntity('usergroup')."))";
+ $sql .= " OR u.entity = 0)";
+ }
$sql .= " WHERE u.statut = 1 AND u.email IS NOT NULL AND u.email <> ''";
- $sql .= ' AND u.entity IN ('.$entityFilter.')';
- $sql .= ' AND ur.fk_id IN ('.implode(',', array_map('intval', $eligibleRights)).')';
+ if (isModEnabled('multicompany') && !getDolGlobalString('MULTICOMPANY_TRANSVERSE_MODE')) {
+ $sql .= ' AND u.entity IN ('.getEntity("user").')';
+ }
+ if (!empty($excludedUsers)) {
+ $sql .= ' AND u.rowid NOT IN ('.implode(',', $excludedUsers).')';
+ }
if (!empty($targetUserIds)) {
$sql .= ' AND u.rowid IN ('.implode(',', array_map('intval', $targetUserIds)).')';
}
@@ -228,8 +221,10 @@ public function run($dbInstance = null, $limit = 0, $forcerun = 0, array $target
$resql = $db->query($sql);
if (!$resql) {
- dol_syslog($db->lasterror(), LOG_ERR);
- return -1;
+ $this->error = $db->lasterror();
+ $this->output = $langs->trans('TimesheetWeekReminderSendFailed', $this->error);
+ dol_syslog($this->error, LOG_ERR);
+ return 0;
}
$emailsSent = 0;
@@ -277,32 +272,72 @@ public function run($dbInstance = null, $limit = 0, $forcerun = 0, array $target
$db->free($resql);
-/* if ($errors > 0) {
+ if ($errors > 0) {
+ $this->error = $langs->trans('TimesheetWeekReminderSendFailed', $errors);
+ $this->output = $this->error;
+ dol_syslog(__METHOD__.' errors='.$errors, LOG_ERR);
return -$errors;
- }*/
+ }
-// return $emailsSent;
-
- if ($errors) {
- $this->error = $langs->trans('TimesheetWeekReminderSendFailed', $errors);
- dol_syslog(__METHOD__." end - ".$this->error, LOG_ERR);
- return 1;
- }else{
- $this->output = $langs->trans('TimesheetWeekReminderSendSuccess', $emailsSent);
- dol_syslog(__METHOD__." end - ".$this->output, LOG_INFO);
- return 0;
- }
- }
+ $this->output = $langs->trans('TimesheetWeekReminderSendSuccess', $emailsSent);
+ dol_syslog(__METHOD__.' sent='.$emailsSent, LOG_DEBUG);
- /**
- * Send a reminder test email to the current user using the configured template.
- *
- * @param DoliDB $db Database handler
- * @param User $user Current user
- * @return int <0 if KO, >=0 if OK (number of emails sent)
- */
- public function sendTest($db, User $user)
- {
- return self::run($db, 1, 1, array((int) $user->id));
+ return $emailsSent;
+ }
+ /**
+ * Send a reminder test email to the current user using the configured template.
+ *
+ * @param User $user Current user
+ * @return int <0 if KO, >=0 if OK (number of emails sent)
+ */
+ public function sendTest(User $user)
+ {
+ return $this->run($this->db, 1, 1, array((int) $user->id));
+ }
+
+ /**
+ * Update the cron job start date using the provided timestamp.
+ *
+ * @param DoliDB $db Database handler
+ * @param int $startTimestamp Next launch timestamp
+ * @param User|null $currentUser User performing the update
+ * @return int >0 if updated, 0 if cron missing, <0 on error
+ */
+ public static function updateCronStartTime(DoliDB $db, int $startTimestamp, $currentUser = null)
+ {
+ global $user;
+
+ $cronJob = new Cronjob($db);
+ $fetchResult = $cronJob->fetch(0, 'TimesheetweekReminder', 'run');
+ if ($fetchResult <= 0 || empty($cronJob->id)) {
+ return 0;
+ }
+
+ $cronJob->datestart = $startTimestamp;
+ $cronJob->datenextrun = $startTimestamp;
+
+ $userForUpdate = $currentUser;
+ if (empty($userForUpdate) && !empty($user) && $user instanceof User) {
+ $userForUpdate = $user;
+ }
+
+ return $cronJob->update($userForUpdate);
+ }
+
+ /**
+ * Store the next reminder start date based on the provided timestamp.
+ *
+ * @param int $currentStartTimestamp Current start timestamp
+ * @return int Next start timestamp
+ */
+ private function scheduleNextStart($currentStartTimestamp)
+ {
+ global $db, $conf;
+
+ $nextStartTimestamp = dol_time_plus_duree($currentStartTimestamp, 1, 'w');
+ dolibarr_set_const($db, 'TIMESHEETWEEK_REMINDER_STARTTIME', (string) $nextStartTimestamp, 'chaine', 0, '', $conf->entity);
+ self::updateCronStartTime($db, $nextStartTimestamp);
+
+ return $nextStartTimestamp;
+ }
}
-}
diff --git a/core/modules/timesheetweek/mod_timesheetweek_advanced.php b/core/modules/timesheetweek/mod_timesheetweek_advanced.php
index dd0deaa..8af2fe7 100644
--- a/core/modules/timesheetweek/mod_timesheetweek_advanced.php
+++ b/core/modules/timesheetweek/mod_timesheetweek_advanced.php
@@ -146,7 +146,7 @@ public function getNextValue($object)
$date = $object->date_creation;
- $numFinal = get_next_value($db, $mask, 'timesheetweek_timesheetweek', 'ref', '', '', $date);
+ $numFinal = get_next_value($db, $mask, 'timesheet_week', 'ref', '', '', $date);
return $numFinal;
}
diff --git a/core/modules/timesheetweek/mod_timesheetweek_standard.php b/core/modules/timesheetweek/mod_timesheetweek_standard.php
index 04e9bfb..baaf0a7 100644
--- a/core/modules/timesheetweek/mod_timesheetweek_standard.php
+++ b/core/modules/timesheetweek/mod_timesheetweek_standard.php
@@ -93,7 +93,7 @@ public function canBeActivated($object)
$posindice = strlen($this->prefix) + 6;
$sql = "SELECT MAX(CAST(SUBSTRING(ref FROM ".$posindice.") AS SIGNED)) as max";
- $sql .= " FROM ".$db->prefix()."timesheetweek_timesheetweek";
+ $sql .= " FROM ".$db->prefix()."timesheet_week";
$sql .= " WHERE ref LIKE '".$db->escape($this->prefix)."____-%'";
$resql = $db->query($sql);
@@ -126,7 +126,7 @@ public function getNextValue($object)
// first we get the max value
$posindice = strlen($this->prefix) + 6;
$sql = "SELECT MAX(CAST(SUBSTRING(ref FROM ".$posindice.") AS SIGNED)) as max";
- $sql .= " FROM ".$db->prefix()."timesheetweek_timesheetweek";
+ $sql .= " FROM ".$db->prefix()."timesheet_week";
$sql .= " WHERE ref LIKE '".$db->escape($this->prefix)."____-%'";
$resql = $db->query($sql);
diff --git a/langs/en_US/timesheetweek.lang b/langs/en_US/timesheetweek.lang
index 7c0ea4b..90c399f 100644
--- a/langs/en_US/timesheetweek.lang
+++ b/langs/en_US/timesheetweek.lang
@@ -31,14 +31,15 @@ TimesheetWeekReminderSectionTitle = Weekly email reminder
TimesheetWeekReminderSectionHelp = Configure the automatic reminder asking users to fill, validate or send their weekly timesheets.
TimesheetWeekReminderEnabled = Enable automatic reminder
TimesheetWeekReminderEnabledHelp = Turn the weekly reminder on or off.
-TimesheetWeekReminderWeekday = Reminder day of week
-TimesheetWeekReminderWeekdayHelp = Select which day of the week the reminder should be sent.
-TimesheetWeekReminderHour = Reminder time (HH:MM)
-TimesheetWeekReminderHourHelp = Time of day when the reminder should be sent.
-TimesheetWeekReminderHourInvalid = Please enter a valid time formatted as HH:MM.
-TimesheetWeekReminderWeekdayInvalid = Please choose a valid day of the week for the reminder.
+TimesheetWeekReminderStartTime = Reminder start date and time
+TimesheetWeekReminderStartTimeHelp = Choose the exact date and time when the next reminder must start running.
+TimesheetWeekReminderStartTimeInvalid = Please select a valid date and time for the reminder start.
+TimesheetWeekReminderCronUpdateFailed = Unable to update the cron start date for the reminder task.
+TimesheetWeekReminderCronMissing = Reminder cron task not found; please reactivate the module to recreate it.
TimesheetWeekReminderEmailTemplate = Email template for reminder
TimesheetWeekReminderEmailTemplateHelp = Choose the Dolibarr email template used to send the reminder.
+TimesheetWeekReminderExcludedUsers = Users excluded from the reminder
+TimesheetWeekReminderExcludedUsersHelp = Select users who must not receive the weekly reminder email.
TimesheetWeekReminderCronLabel = Weekly timesheet reminder
TimesheetWeekReminderCronComment = Send weekly reminder emails prompting users to complete their timesheets.
TimesheetWeekReminderTemplateMissing = Reminder email template is not configured.
diff --git a/langs/fr_FR/timesheetweek.lang b/langs/fr_FR/timesheetweek.lang
index d5aa9f3..ed38a7d 100644
--- a/langs/fr_FR/timesheetweek.lang
+++ b/langs/fr_FR/timesheetweek.lang
@@ -31,14 +31,15 @@ TimesheetWeekReminderSectionTitle = Rappel hebdomadaire par email
TimesheetWeekReminderSectionHelp = Configure le rappel automatique invitant les utilisateurs à saisir, valider ou envoyer leurs feuilles hebdomadaires.
TimesheetWeekReminderEnabled = Activer le rappel automatique
TimesheetWeekReminderEnabledHelp = Active ou désactive l'envoi hebdomadaire du rappel.
-TimesheetWeekReminderWeekday = Jour d'envoi du rappel
-TimesheetWeekReminderWeekdayHelp = Choisissez le jour de la semaine pour envoyer le rappel.
-TimesheetWeekReminderHour = Heure d'envoi (HH:MM)
-TimesheetWeekReminderHourHelp = Heure d'envoi du rappel, au format 24 h.
-TimesheetWeekReminderHourInvalid = Merci de saisir une heure valide au format HH:MM.
-TimesheetWeekReminderWeekdayInvalid = Merci de choisir un jour de semaine valide pour le rappel.
+TimesheetWeekReminderStartTime = Date et heure de départ du rappel
+TimesheetWeekReminderStartTimeHelp = Choisissez la date et l'heure exactes du prochain lancement du rappel.
+TimesheetWeekReminderStartTimeInvalid = Merci de sélectionner une date et une heure de départ valides pour le rappel.
+TimesheetWeekReminderCronUpdateFailed = Impossible de mettre à jour la date de départ de la tâche CRON du rappel.
+TimesheetWeekReminderCronMissing = Tâche CRON de rappel introuvable ; merci de réactiver le module pour la recréer.
TimesheetWeekReminderEmailTemplate = Modèle d'email pour le rappel
TimesheetWeekReminderEmailTemplateHelp = Sélectionnez le modèle d'email Dolibarr utilisé pour envoyer le rappel.
+TimesheetWeekReminderExcludedUsers = Utilisateurs exclus du rappel
+TimesheetWeekReminderExcludedUsersHelp = Sélectionnez les utilisateurs qui ne doivent pas recevoir le rappel hebdomadaire.
TimesheetWeekReminderCronLabel = Rappel hebdomadaire des feuilles d'heures
TimesheetWeekReminderCronComment = Envoie un rappel hebdomadaire par email pour inviter les utilisateurs à compléter leurs feuilles d'heures.
TimesheetWeekReminderTemplateMissing = Le modèle d'email de rappel n'est pas configuré.