diff --git a/admin/setup.php b/admin/setup.php index 61edbf6..3c8a46e 100644 --- a/admin/setup.php +++ b/admin/setup.php @@ -127,6 +127,11 @@ dolibarr_set_const($db, 'DOLIMEET_TRAININGSESSION_LOCATION', $trainingSessionLocation, 'chaine', 0, '', $conf->entity); } + $trainingSessionAbsenceRate = GETPOST('training_session_absence_rate', 'int'); + if ($trainingSessionAbsenceRate != getDolGlobalInt('DOLIMEET_TRAININGSESSION_ABSENCE_RATE')) { + dolibarr_set_const($db, 'DOLIMEET_TRAININGSESSION_ABSENCE_RATE', $trainingSessionAbsenceRate, 'integer', 0, '', $conf->entity); + } + setEventMessage('SavedConfig'); header('Location: ' . $_SERVER['PHP_SELF']); exit; @@ -246,6 +251,12 @@ print ''; print ''; + // Training session absence rate + print '' . $langs->transnoentities('TrainingSessionAbsenceRate') . ''; + print img_picto('', 'sort-numeric-down', 'class="pictofixedwidth"'); + print ''; + print ''; + print ''; print '
'; print ''; diff --git a/class/actions_dolimeet.class.php b/class/actions_dolimeet.class.php index af131f8..3118828 100644 --- a/class/actions_dolimeet.class.php +++ b/class/actions_dolimeet.class.php @@ -154,9 +154,6 @@ public function formObjectOptions(array $parameters, $object, $action): int $extrafields->attributes['contrat']['label']['label'] = $picto . $langs->transnoentities($extrafields->attributes['contrat']['label']['label']); $extrafields->attributes['contrat']['label']['trainingsession_type'] = $picto . $langs->transnoentities($extrafields->attributes['contrat']['label']['trainingsession_type']); $extrafields->attributes['contrat']['label']['trainingsession_location'] = $picto . $langs->transnoentities($extrafields->attributes['contrat']['label']['trainingsession_location']); - $extrafields->attributes['contrat']['label']['trainingsession_start'] = $picto . $langs->transnoentities($extrafields->attributes['contrat']['label']['trainingsession_start']); - $extrafields->attributes['contrat']['label']['trainingsession_end'] = $picto . $langs->transnoentities($extrafields->attributes['contrat']['label']['trainingsession_end']); - $extrafields->attributes['contrat']['label']['trainingsession_durations'] = $picto . $langs->transnoentities($extrafields->attributes['contrat']['label']['trainingsession_durations']); $extrafields->attributes['contrat']['label']['trainingsession_opco_financing'] = $picto . $langs->transnoentities($extrafields->attributes['contrat']['label']['trainingsession_opco_financing']); // Initialize the param attribute for trainingsession_service @@ -363,9 +360,6 @@ public function printFieldListOption(array $parameters): int $extrafields->attributes['contrat']['label']['label'] = $picto . $langs->transnoentities($extrafields->attributes['contrat']['label']['label']); $extrafields->attributes['contrat']['label']['trainingsession_type'] = $picto . $langs->transnoentities($extrafields->attributes['contrat']['label']['trainingsession_type']); $extrafields->attributes['contrat']['label']['trainingsession_location'] = $picto . $langs->transnoentities($extrafields->attributes['contrat']['label']['trainingsession_location']); - $extrafields->attributes['contrat']['label']['trainingsession_start'] = $picto . $langs->transnoentities($extrafields->attributes['contrat']['label']['trainingsession_start']); - $extrafields->attributes['contrat']['label']['trainingsession_end'] = $picto . $langs->transnoentities($extrafields->attributes['contrat']['label']['trainingsession_end']); - $extrafields->attributes['contrat']['label']['trainingsession_durations'] = $picto . $langs->transnoentities($extrafields->attributes['contrat']['label']['trainingsession_durations']); $extrafields->attributes['contrat']['label']['trainingsession_opco_financing'] = $picto . $langs->transnoentities($extrafields->attributes['contrat']['label']['trainingsession_opco_financing']); } @@ -664,87 +658,21 @@ function fillTable(data) { require_once __DIR__ . '/../../saturne/lib/saturne_functions.lib.php'; require_once __DIR__ . '/../../saturne/core/modules/saturne/modules_saturne.php'; - // Load DoliMeet libraries - require_once __DIR__ . '/session.class.php'; - saturne_load_langs(); - // Handle consistency of contract trainingsession dates - $session = new Session($this->db); - - $filter = ' AND t.status >= 0 AND t.type = "trainingsession" AND t.fk_contrat = ' . $object->id . ' ORDER BY t.date_start ASC'; - $session->fetch('', '', $filter); - - $out = img_picto('', 'check', 'class="marginleftonly"'); - if ($session->date_start != $object->array_options['options_trainingsession_start']) { - $out = $form->textwithpicto('', $langs->trans('TrainingSessionStartErrorMatchingDate', $session->ref), 1, 'warning'); - } ?> - - dolimeet->multidir_output[$object->entity ?? 1]; + $objRef = dol_sanitizeFileName($object->ref); + $dirFiles = 'completioncertificatedocument/' . $objRef; + $fileDir = $upload_dir . '/' . $dirFiles; + $urlSource = $_SERVER['PHP_SELF'] . '?id=' . $object->id; - $filter = ' AND t.status >= 0 AND t.type = "trainingsession" AND t.fk_contrat = ' . $object->id . ' ORDER BY t.date_end DESC'; - $session->fetch('', '', $filter); + $html = saturne_show_documents('dolimeet:CompletioncertificateDocument', $dirFiles, $fileDir, $urlSource, $user->rights->contrat->creer, $user->rights->contrat->supprimer, '', 1, 0, 0, 0, 0, '', 0, $langs->defaultlang, '', $object, 0, 'remove_file', (($object->statut > Contrat::STATUS_DRAFT && getDolGlobalInt('DOLIMEET_SESSION_TRAINER_RESPONSIBLE') > 0) ? 1 : 0), $langs->trans('DefineSessionTrainerResponsible') . '
' . $langs->trans('ObjectMustBeValidatedToGenerate', ucfirst($langs->transnoentities(ucfirst($object->element))))); ?> - $out = img_picto('', 'check', 'class="marginleftonly"'); - if ($session->date_end != $object->array_options['options_trainingsession_end']) { - $out = $form->textwithpicto('', $langs->trans('TrainingSessionEndErrorMatchingDate', $session->ref), 1, 'warning'); - } ?> = 0 AND t.type = "trainingsession" AND t.fk_contrat = ' . $object->id; - $sessions = $session->fetchAll('', '', 0, 0, ['customsql' => $filter]); - if (is_array($sessions) && !empty($sessions)) { - foreach ($sessions as $sessionSingle) { - $sessionDurations += $sessionSingle->duration; - } - } - if (GETPOST('action') == 'edit_extras' && GETPOST('attribute') == 'trainingsession_durations') { - $out = ''; - $out .= '
'; - $out .= ''; - $out .= ''; - $out .= ''; - $out .= ''; - $out .= $form->select_duration('duration', $object->array_options['options_trainingsession_durations'], 0, 'text', 0, 1); - $out .= '' . ''; - } else { - $out = '' . ($object->array_options['options_trainingsession_durations'] > 0 ? convertSecondToTime($object->array_options['options_trainingsession_durations'], 'allhourmin') : '00:00') . ' - '; - $out .= $langs->trans('CalculatedTotalSessionDuration') . ' ' . ($sessionDurations > 0 ? convertSecondToTime($sessionDurations, 'allhourmin') : '00:00'); - if ($sessionDurations != $object->array_options['options_trainingsession_durations']) { - $out .= $form->textwithpicto('', $langs->trans('TrainingSessionDurationErrorMatching', $session->ref), 1, 'warning'); - } - $out .= ''; - } ?> - - id > 0) { - print ''; - - $upload_dir = $conf->dolimeet->multidir_output[$object->entity ?? 1]; - $objRef = dol_sanitizeFileName($object->ref); - $dirFiles = 'completioncertificatedocument/' . $objRef; - $fileDir = $upload_dir . '/' . $dirFiles; - $urlSource = $_SERVER['PHP_SELF'] . '?id=' . $object->id; - - $html = saturne_show_documents('dolimeet:CompletioncertificateDocument', $dirFiles, $fileDir, $urlSource, $user->rights->contrat->creer, $user->rights->contrat->supprimer, '', 1, 0, 0, 0, 0, '', 0, $langs->defaultlang, '', $object, 0, 'remove_file', (($object->statut > Contrat::STATUS_DRAFT && getDolGlobalInt('DOLIMEET_SESSION_TRAINER_RESPONSIBLE') > 0) ? 1 : 0), $langs->trans('DefineSessionTrainerResponsible') . '
' . $langs->trans('ObjectMustBeValidatedToGenerate', ucfirst($langs->transnoentities(ucfirst($object->element))))); ?> - - - - id); exit; } + } + if (strpos($parameters['context'], 'contractcard') !== false) { if ($action == 'builddoc' && strstr(GETPOST('model'), 'completioncertificatedocument_odt')) { require_once __DIR__ . '/dolimeetdocuments/completioncertificatedocument.class.php'; @@ -960,43 +890,47 @@ public function moreHtmlStatus(array $parameters, CommonObject $object): int if (strpos($parameters['context'], 'contractcard') !== false) { if (!empty($object->array_options['options_trainingsession_type'])) { - $contacts = []; - $contactRoleBySources = [ - 'internal' => [ - 'warning' => ['trainee', 'sessiontrainer'] - ], - 'external' => [ - 'info' => ['billing', 'customer'], - 'warning' => ['trainee', 'sessiontrainer', 'opco'] - ] + $contactRoles = [ + 'trainee' => ['source' => 'both', 'notice' => 'warning'], + 'sessiontrainer' => ['source' => 'both', 'notice' => 'warning'], + 'billing' => ['source' => 'external', 'notice' => 'info'], + 'customer' => ['source' => 'external', 'notice' => 'info'], + 'opco' => ['source' => 'external', 'notice' => 'info'], ]; - foreach ($contactRoleBySources as $contactSource => $contactNoticeTypes) { - foreach ($contactNoticeTypes as $contactNoticeType => $contactRoles) { - foreach ($contactRoles as $contactRole) { - if (empty($object->liste_contact(-1, $contactSource, 0, dol_strtoupper($contactRole)))) { - $contacts[$contactNoticeType][$contactRole]++; - if ($object->array_options['options_trainingsession_opco_financing'] == 0 && $contactRole == 'opco') { - $contacts['info']['opco']++; - unset($contacts['warning']['opco']); - } - } + foreach ($contactRoles as $contactRole => $contactInfos) { + $contacts = []; + if ($contactInfos['source'] == 'both') { + $internalContacts = $object->liste_contact(-1, 'internal', 0, dol_strtoupper($contactRole)); + $externalContacts = $object->liste_contact(-1, 'external', 0, dol_strtoupper($contactRole)); + if ((is_array($internalContacts) && !empty($internalContacts)) || (is_array($externalContacts) && !empty($externalContacts))) { + $contacts = array_merge($internalContacts, $externalContacts); } + } else { + $contacts = $object->liste_contact(-1, $contactInfos['source'], 0, dol_strtoupper($contactRole)); + } + if (is_array($contacts) && empty($contacts)) { + if ($object->array_options['options_trainingsession_opco_financing'] == 1 && $contactRole == 'opco') { + $contactInfos['notice'] = 'warning'; + } + $contactsNoticeByRoles[$contactInfos['notice']][$contactRole] = $contactInfos; } } $moreHtmlStatus = ''; - foreach ($contacts as $contactNoticeType => $contactRoles) { - $moreHtmlStatus .= '
'; - $moreHtmlStatus .= '
'; - $moreHtmlStatus .= '
'; - foreach ($contactRoles as $contactRole => $role) { - if ($object->array_options['options_trainingsession_opco_financing'] == 0 && $contactRole == 'opco') { - $moreHtmlStatus .= $langs->transnoentities('OpcoInfo', $langs->transnoentities(ucfirst($contactRole))) . '
'; - continue; + if (!empty($contactsNoticeByRoles)) { + foreach ($contactsNoticeByRoles as $contactNoticeType => $contactRoles) { + $moreHtmlStatus .= '
'; + $moreHtmlStatus .= '
'; + $moreHtmlStatus .= '
'; + foreach ($contactRoles as $contactRole => $role) { + if ($object->array_options['options_trainingsession_opco_financing'] == 0 && $contactRole == 'opco') { + $moreHtmlStatus .= $langs->transnoentities('OpcoInfo', $langs->transnoentities(ucfirst($contactRole))) . '
'; + continue; + } + $moreHtmlStatus .= $langs->transnoentities('ObjectNotFound', $langs->transnoentities(ucfirst($contactRole))) . '
'; } - $moreHtmlStatus .= $langs->transnoentities('ObjectNotFound', $langs->transnoentities(ucfirst($contactRole))) . '
'; + $moreHtmlStatus .= '
'; } - $moreHtmlStatus .= '
'; } $this->resprints = $moreHtmlStatus; @@ -1097,7 +1031,7 @@ public function completeTabsHead(array $parameters): int $nbSessions = 0; require_once __DIR__ . '/session.class.php'; $session = new Session($db); - switch ($parameters['object']->element) { + switch ($parameters['object']->element ?? '') { case 'societe' : $objectElement = 'soc'; break; @@ -1109,10 +1043,10 @@ public function completeTabsHead(array $parameters): int $filter = 't.status >= 0 AND t.model = 1 AND t.element_type = "service" AND t.fk_element = ' . $parameters['object']->id; break; default : - $objectElement = $parameters['object']->element; + $objectElement = $parameters['object']->element ?? ''; break; } - $filter = $filter ?? 't.status >= 0 AND t.fk_' . $objectElement . ' = ' . $parameters['object']->id; + $filter = $filter ?? 't.status >= 0 AND t.fk_' . $objectElement . ' = ' . ($parameters['object']->id ?? 0); $filter .= GETPOST('object_type') ? " AND t.type = '" . GETPOST('object_type') . "'" : ''; $sessions = $session->fetchAll('', '', 0, 0, ['customsql' => $filter]); if (is_array($sessions) && !empty($sessions)) { @@ -1132,8 +1066,6 @@ public function completeTabsHead(array $parameters): int } } } - - $this->results = $parameters; } return 0; // or return 1 to replace standard code @@ -1349,97 +1281,90 @@ public function saturneBuildDoc(array $parameters, CommonObject $object, string if (strpos((!empty($parameters['models']) ? $parameters['models'][1] : $parameters['model']), 'completioncertificate') !== false) { require_once __DIR__ . '/session.class.php'; - $session = new Session($this->db); - $document = new CompletioncertificateDocument($this->db); - $signatory = new SaturneSignature($this->db, 'dolimeet', $object->element); + $session = new Session($this->db); - $contactList = []; - $signedTrainee = []; - $sessions = $session->fetchAll('', '', 0, 0, ['customsql' => 't.fk_contrat = ' . $object->id . ' AND t.status >= 0']); - // We retrieve internal & external user linked to the contract foreach (['internal', 'external'] as $source) { $contactList[$source] = $object->liste_contact(-1, $source, 0, 'TRAINEE'); - // We need our array keys to start with 1 for further logic - array_unshift($contactList[$source],''); - unset($contactList[$source][0]); } - // Because of the structure of $contactList we need a second array where we will remove someone if he is present for ONE session - $absentTrainee = $contactList; + $sessions = $session->fetchAll('', '', 0, 0, ['customsql' => 't.fk_contrat = ' . $object->id . ' AND t.status >= 1']); if (is_array($sessions) && !empty($sessions)) { + $signatory = new SaturneSignature($this->db, 'dolimeet', $object->element); + + $durations = 0; + $nbSessions = count($sessions); + $contactIds = []; foreach ($sessions as $session) { - $signatories = $signatory->fetchSignatories($session->id, 'trainingsession', 'role = "Trainee"'); - foreach ($signatories as $signatory) { - $type = ($signatory->element_type == 'user' ? 'internal' : 'external'); - $absentId = array_column($absentTrainee[$type], 'id'); - - // We search for the key in $contactList corresponding to the current $signatory->element_id - array_unshift($absentId,''); - unset($absentId[0]); - // array_search return false (0) if it doesn't find, that's why we need our $absentTrainee array to start by 1 - $key = array_search($signatory->element_id, $absentId); - - if ($signatory->attendance != SaturneSignature::ATTENDANCE_ABSENT) { - // If the $signatory is present then we will remove it from the $absentTrainee array - if ($key > 0) { - unset($absentTrainee[$type][$key]); + $absentSignatories = $signatory->fetchSignatories($session->id, 'trainingsession', 't.role = "Trainee"' . ' AND t.attendance = ' . SaturneSignature::ATTENDANCE_ABSENT); + if (is_array($absentSignatories) && !empty($absentSignatories)) { + foreach ($absentSignatories as $signatory) { + $type = ($signatory->element_type == 'user' ? 'internal' : 'external'); + $contactIds = array_column($contactList[$type], 'id'); + if (in_array($signatory->element_id, $contactIds)) { + $absentTrainees[$signatory->element_id]['lastname'] = $signatory->lastname; + $absentTrainees[$signatory->element_id]['firstname'] = $signatory->firstname; + $absentTrainees[$signatory->element_id]['type'] = $type; + $absentTrainees[$signatory->element_id]['nbAbsence']++; } - $signedTrainee[$type][$signatory->element_id] += $session->duration; } } + $durations += $session->duration; } - $lastSession = end($sessions); - $dateEnd = $lastSession->date_end; - if ($dateEnd != $object->array_options['options_trainingsession_end']) { - setEventMessages($langs->trans('TrainingSessionEndErrorMatchingDate', $lastSession->ref), [], 'warnings'); - } - } - if (!empty($absentTrainee)) { - foreach ($absentTrainee as $absentType) { - foreach($absentType as $contact) { - setEventMessages($langs->trans('NoCertificateBecauseAbsent', $contact['lastname'], $contact['firstname']), [], 'warnings'); + if (!empty($absentTrainees)) { + foreach ($absentTrainees as $absentId => $absentTrainee) { + if (($absentTrainee['nbAbsence'] / $nbSessions * 100) > getDolGlobalInt('DOLIMEET_TRAININGSESSION_ABSENCE_RATE')) { + $key = array_search($absentId, $contactIds); + unset($contactList[$absentTrainee['type']][$key]); + setEventMessages($langs->trans('NoCertificateBecauseAbsent', $absentTrainee['lastname'], $absentTrainee['firstname']), [], 'warnings'); + } } } - } - $parameters['moreparams']['object'] = $object; - $parameters['moreparams']['object']->element = 'trainingsession'; - $parameters['moreparams']['object']->date_start = $object->array_options['options_trainingsession_start']; - $parameters['moreparams']['object']->date_end = $object->array_options['options_trainingsession_end']; - $parameters['moreparams']['object']->fk_contrat = $object->id; - - if (!empty($contactList) && !empty($signedTrainee)) { - foreach ($contactList as $contactType) { - foreach($contactType as $contact) { - if (is_array($signedTrainee[$contact['source']]) && array_key_exists($contact['id'], $signedTrainee[$contact['source']])) { - $parameters['moreparams']['attendant'] = $signatory; + if (!empty($contactList)) { + $document = new CompletioncertificateDocument($this->db); + $parameters['moreparams']['attendant'] = new stdClass(); + + $parameters['moreparams']['object'] = $object; + $parameters['moreparams']['object']->element = 'trainingsession'; + $parameters['moreparams']['object']->fk_contrat = $object->id; + $parameters['moreparams']['object']->date_start = current($sessions)->date_start; + $parameters['moreparams']['object']->date_end = end($sessions)->date_end; + $parameters['moreparams']['object']->duration = $durations; + foreach ($contactList as $contactType) { + foreach($contactType as $contact) { $parameters['moreparams']['attendant']->firstname = $contact['firstname']; $parameters['moreparams']['attendant']->lastname = $contact['lastname']; $parameters['moreparams']['attendant']->element_type = ($contact['source'] == 'external' ? 'socpeople' : 'user'); $parameters['moreparams']['attendant']->element_id = $contact['id']; - $parameters['moreparams']['object']->duration = $signedTrainee[$contact['source']][$contact['id']]; $document->element = 'trainingsessiondocument'; + $result = $document->generateDocument((!empty($parameters['models']) ? $parameters['models'][1] : $parameters['model']), $parameters['outputlangs'], $parameters['hidedetails'], $parameters['hidedesc'], $parameters['hideref'], $parameters['moreparams']); + // Need to reset $document->error because commonGenerateDocument call unwanted function dol_delete_preview + if ($document->error == 'ErrorObjectNoSupportedByFunction') { + $document->error = ''; + } if ($result <= 0) { setEventMessages($document->error, $document->errors, 'errors'); } + + $documentType = explode('_odt', (!empty($parameters['models']) ? $parameters['models'][1] : $parameters['model'])); + if ($document->element != $documentType[0]) { + $document->element = $documentType[0]; + } + + setEventMessages($langs->trans('FileGenerated') . ' - ' . 'element . '/' . $object->ref . '/' . $document->last_main_doc) . '&entity=' . $conf->entity . '"' . '>' . $document->last_main_doc, []); } } - } - $documentType = explode('_odt', (!empty($parameters['models']) ? $parameters['models'][1] : $parameters['model'])); - if ($document->element != $documentType[0]) { - $document->element = $documentType[0]; - } - setEventMessages($langs->trans('FileGenerated') . ' - ' . 'element . '/' . $object->ref . '/' . $document->last_main_doc) . '&entity=' . $conf->entity . '"' . '>' . $document->last_main_doc, []); - $urlToRedirect = $_SERVER['REQUEST_URI']; - $urlToRedirect = preg_replace('/#builddoc$/', '', $urlToRedirect); - $urlToRedirect = preg_replace('/action=builddoc&?/', '', $urlToRedirect); // To avoid infinite loop - if (!GETPOST('forcebuilddoc')){ - header('Location: ' . $urlToRedirect . '#builddoc'); - exit; + $urlToRedirect = $_SERVER['REQUEST_URI']; + $urlToRedirect = preg_replace('/#builddoc$/', '', $urlToRedirect); + $urlToRedirect = preg_replace('/action=builddoc&?/', '', $urlToRedirect); // To avoid infinite loop + if (!GETPOST('forcebuilddoc')){ + header('Location: ' . $urlToRedirect . '#builddoc'); + exit; + } } } } diff --git a/class/session.class.php b/class/session.class.php index 5343ffc..2274f10 100644 --- a/class/session.class.php +++ b/class/session.class.php @@ -119,8 +119,8 @@ class Session extends SaturneObject 'import_key' => ['type' => 'varchar(14)', 'label' => 'ImportId', 'enabled' => 1, 'position' => 60, 'notnull' => 0, 'visible' => 0, 'index' => 0], 'status' => ['type' => 'smallint', 'label' => 'Status', 'enabled' => 1, 'position' => 190, 'notnull' => 1, 'visible' => 2, 'default' => 0, 'index' => 1, 'validate' => 1, 'arrayofkeyval' => [0 => 'StatusDraft', 1 => 'ValidatePendingSignature', 2 => 'Locked', 3 => 'Archived']], 'label' => ['type' => 'varchar(255)', 'label' => 'Label', 'enabled' => 1, 'position' => 70, 'notnull' => 1, 'visible' => 1, 'searchall' => 1, 'css' => 'minwidth300', 'cssview' => 'wordbreak', 'showoncombobox' => 2, 'validate' => 1, 'autofocusoncreate' => 1], - 'date_start' => ['type' => 'datetime', 'label' => 'DateStart', 'enabled' => 1, 'position' => 110, 'notnull' => 0, 'visible' => 1], - 'date_end' => ['type' => 'datetime', 'label' => 'DateEnd', 'enabled' => 1, 'position' => 120, 'notnull' => 0, 'visible' => 1], + 'date_start' => ['type' => 'datetime', 'label' => 'DateStart', 'enabled' => 1, 'position' => 41, 'notnull' => 0, 'visible' => 1], + 'date_end' => ['type' => 'datetime', 'label' => 'DateEnd', 'enabled' => 1, 'position' => 42, 'notnull' => 0, 'visible' => 1], 'content' => ['type' => 'html', 'label' => 'Content', 'enabled' => 1, 'position' => 140, 'notnull' => 0, 'visible' => 3, 'validate' => 1], 'type' => ['type' => 'varchar(128)', 'label' => 'Type', 'enabled' => 1, 'position' => 120, 'notnull' => 1, 'visible' => 0], 'element_type' => ['type' => 'select', 'label' => 'ElementType', 'enabled' => 1, 'position' => 91, 'notnull' => 0, 'visible' => 3, 'css' => 'maxwidth150 widthcentpercentminusxx'], diff --git a/core/modules/modDoliMeet.class.php b/core/modules/modDoliMeet.class.php index 7c32936..1f6a97b 100644 --- a/core/modules/modDoliMeet.class.php +++ b/core/modules/modDoliMeet.class.php @@ -230,6 +230,7 @@ public function __construct($db) $i++ => ['DOLIMEET_TRAININGSESSION_AFTERNOON_START_HOUR', 'chaine', '14:00', '', 0, 'current'], $i++ => ['DOLIMEET_TRAININGSESSION_AFTERNOON_END_HOUR', 'chaine', '18:00', '', 0, 'current'], $i++ => ['DOLIMEET_TRAININGSESSION_LOCATION', 'chaine', 'TrainingSessionLocationOther', '', 0, 'current'], + $i++ => ['DOLIMEET_TRAININGSESSION_ABSENCE_RATE', 'integer', 20, '', 0, 'current'], // CONST GENERAL CONST. $i++ => ['CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST', 'integer', 1, '', 0, 'current'], @@ -629,7 +630,9 @@ public function init($options = ''): int $saturneMail->joinfiles = 0; $saturneMail->content = $langs->transnoentities('CompletionCertificateDocumentContent'); - dolibarr_set_const($this->db, 'DOLIMEET_EMAIL_TEMPLATE_COMPLETION_CERTIFICATE', $saturneMail->create($user), 'chaine', 0, '', $conf->entity); + $emailTemplateID = $saturneMail->create($user); + + dolibarr_set_const($this->db, 'DOLIMEET_EMAIL_TEMPLATE_COMPLETION_CERTIFICATE', $emailTemplateID, 'chaine', 0, '', $conf->entity); dolibarr_set_const($this->db, 'DOLIMEET_EMAIL_TEMPLATE_SET', 2, 'integer', 0, '', $conf->entity); } @@ -673,17 +676,29 @@ public function init($options = ''): int 'trainingsession_type' => ['Label' => 'TrainingSessionType', 'type' => 'sellist', 'length' => '', 'elementtype' => ['contrat', 'propal', 'projet'], 'position' => 10, 'params' => 'a:1:{s:7:"options";a:1:{s:34:"c_trainingsession_type:label:rowid";N;}}', 'list' => 1, 'help' => ['contrat' => '', 'propal' => '', 'projet' => 'TrainingSessionTypeHelp'], 'entity' => 0, 'langfile' => 'dolimeet@dolimeet', 'enabled' => "isModEnabled('dolimeet')", ['css' => 'minwidth100 maxwidth300 widthcentpercentminusxx']], 'trainingsession_service' => ['Label' => 'TrainingSessionService', 'type' => 'chkbxlst', 'length' => '', 'elementtype' => ['propal', 'projet'], 'position' => 10, 'params' => '', 'list' => 1, 'help' => 'TrainingSessionServiceHelp', 'entity' => 0, 'langfile' => 'dolimeet@dolimeet', 'enabled' => "isModEnabled('dolimeet')", ['css' => 'minwidth100 maxwidth300 widthcentpercentminusxx']], 'trainingsession_location' => ['Label' => 'TrainingSessionLocation', 'type' => 'varchar', 'length' => 255, 'elementtype' => ['contrat', 'propal', 'projet'], 'position' => 20, 'params' => '', 'list' => 1, 'help' => 'TrainingSessionLocationHelp', 'entity' => 0, 'langfile' => 'dolimeet@dolimeet', 'enabled' => "isModEnabled('dolimeet')", ['css' => 'minwidth100 maxwidth300 widthcentpercentminusxx']], - 'trainingsession_start' => ['Label' => 'TrainingSessionStart', 'type' => 'datetime', 'length' => '', 'elementtype' => ['contrat'], 'position' => 30, 'params' => '', 'list' => 1, 'help' => 'TrainingSessionStartHelp', 'entity' => 0, 'langfile' => 'dolimeet@dolimeet', 'enabled' => "isModEnabled('dolimeet')"], - 'trainingsession_end' => ['Label' => 'TrainingSessionEnd', 'type' => 'datetime', 'length' => '', 'elementtype' => ['contrat'], 'position' => 40, 'params' => '', 'list' => 1, 'help' => 'TrainingSessionEndHelp', 'entity' => 0, 'langfile' => 'dolimeet@dolimeet', 'enabled' => "isModEnabled('dolimeet')"], - 'trainingsession_durations' => ['Label' => 'TrainingSessionDurations', 'type' => 'int', 'length' => '', 'elementtype' => ['contrat'], 'position' => 50, 'params' => '', 'list' => 5, 'help' => 'TrainingSessionDurationHelp', 'entity' => 0, 'langfile' => 'dolimeet@dolimeet', 'enabled' => "isModEnabled('dolimeet')"], - 'trainingsession_opco_financing' => ['Label' => 'TrainingSessionOpcoFinancing', 'type' => 'boolean', 'length' => '', 'elementtype' => ['contrat'], 'position' => 60, 'params' => '', 'list' => 5, 'help' => 'TrainingSessionOpcoFinancingHelp', 'entity' => 0, 'langfile' => 'dolimeet@dolimeet', 'enabled' => "isModEnabled('dolimeet')"] + 'trainingsession_opco_financing' => ['Label' => 'TrainingSessionOpcoFinancing', 'type' => 'boolean', 'length' => '', 'elementtype' => ['contrat'], 'position' => 60, 'params' => '', 'alwayseditable' => 1, 'list' => 5, 'help' => 'TrainingSessionOpcoFinancingHelp', 'entity' => 0, 'langfile' => 'dolimeet@dolimeet', 'enabled' => "isModEnabled('dolimeet')"] ]; foreach ($extraFieldsArrays as $key => $extraField) { foreach ($extraField['elementtype'] as $extraFieldElementType) { $extraFields->update($key, $extraField['Label'], $extraField['type'], $extraField['length'], $extraFieldElementType, 0, 0, $this->numero . $extraField['position'], $extraField['params'], '', '', $extraField['list'], ($extraField['help'][$extraFieldElementType] ?? $extraField['help']), '', '', $extraField['entity'], $extraField['langfile'], $extraField['enabled'] . ' && isModEnabled("' . $extraFieldElementType . '")', 0, 0, $extraField['css']); - $extraFields->addExtraField($key, $extraField['Label'], $extraField['type'], $this->numero . $extraField['position'], $extraField['length'], $extraFieldElementType, 0, 0, '', $extraField['params'], '', '', $extraField['list'], $extraField['help'], '', $extraField['entity'], $extraField['langfile'], $extraField['enabled'] . ' && isModEnabled("' . $extraFieldElementType . '")', 0, 0, $extraField['css']); + $extraFields->addExtraField($key, $extraField['Label'], $extraField['type'], $this->numero . $extraField['position'], $extraField['length'], $extraFieldElementType, 0, 0, '', $extraField['params'], $extraField['alwayseditable'], '', $extraField['list'], $extraField['help'], '', $extraField['entity'], $extraField['langfile'], $extraField['enabled'] . ' && isModEnabled("' . $extraFieldElementType . '")', 0, 0, $extraField['css']); + } + } + + if (getDolGlobalInt('DOLIMEET_EXTRAFIELDS_BACKWARD_COMPATIBILITY') == 0) { + $extraFieldsArrays = [ + 'trainingsession_start' => ['elementtype' => ['contrat']], + 'trainingsession_end' => ['elementtype' => ['contrat']], + 'trainingsession_durations' => ['elementtype' => ['contrat']] + ]; + + foreach ($extraFieldsArrays as $key => $extraField) { + foreach ($extraField['elementtype'] as $extraFieldElementType) { + $extraFields->delete($key, $extraFieldElementType); + } } + dolibarr_set_const($this->db, 'DOLIMEET_EXTRAFIELDS_BACKWARD_COMPATIBILITY', 1, 'integer', 0, '', $conf->entity); } return $this->_init($sql, $options); diff --git a/core/substitutions/functions_dolimeet.lib.php b/core/substitutions/functions_dolimeet.lib.php index e6ff000..a3fc4eb 100644 --- a/core/substitutions/functions_dolimeet.lib.php +++ b/core/substitutions/functions_dolimeet.lib.php @@ -36,7 +36,7 @@ function dolimeet_completesubstitutionarray(array &$substitutionarray, Translate { global $conf, $db, $user; - if ($object->element == 'contrat') { + if ($object && $object->element == 'contrat') { // Load Saturne libraries require_once __DIR__ . '/../../../saturne/class/saturnesignature.class.php'; require_once __DIR__ . '/../../../saturne/lib/saturne_functions.lib.php'; @@ -76,8 +76,6 @@ function dolimeet_completesubstitutionarray(array &$substitutionarray, Translate } $substitutionarray['__DOLIMEET_CONTRACT_LABEL__'] = $object->array_options['options_label']; - $substitutionarray['__DOLIMEET_CONTRACT_TRAININGSESSION_START__'] = $object->array_options['options_trainingsession_start']; - $substitutionarray['__DOLIMEET_CONTRACT_TRAININGSESSION_END__'] = $object->array_options['options_trainingsession_end']; $substitutionarray['__DOLIMEET_CONTRACT_TRAININGSESSION_TYPE__'] = $object->array_options['options_trainingsession_type']; $substitutionarray['__DOLIMEET_CONTRACT_TRAININGSESSION_LOCATION__'] = $object->array_options['options_trainingsession_location']; diff --git a/langs/en_US/dolimeet.lang b/langs/en_US/dolimeet.lang index 1bf8623..ba67a17 100644 --- a/langs/en_US/dolimeet.lang +++ b/langs/en_US/dolimeet.lang @@ -122,7 +122,7 @@ TrainingSessionLocationHelp = Place where the training session linked TrainingSessionDurationHelp = Total duration of the sessions HH:MM (ex: 60:30)
The duration shown on the certificate corresponds to the total number of hours of sessions attended by a trainee. CalculatedTotalSessionDuration = Total calculated duration time: TrainingSessionDurationErrorMatching = Error: consistency of training session duration.
The total duration of the sessions indicated in the contract is different from the calculated duration of all the sessions linked to the contract. -NoCertificateBecauseAbsent = No certificate was generated for %s %s because it was absent from all sessions. +NoCertificateBecauseAbsent = No certificate was generated for %s %s because it was absent from at least one session. # Attendant role diff --git a/langs/fr_FR/dolimeet.lang b/langs/fr_FR/dolimeet.lang index fc6150a..c23fca3 100644 --- a/langs/fr_FR/dolimeet.lang +++ b/langs/fr_FR/dolimeet.lang @@ -53,6 +53,7 @@ AfternoonEndHour = Heure de fin d'après-midi TrainingSessionLocationCompany = Lieu de formation (société) TrainingSessionLocationThirdParty = Lieu de formation (tiers) TrainingSessionLocationOther = Autre lieu de formation par défaut +TrainingSessionAbsenceRate = Taux d'absence acceptable aux sessions de formation @@ -139,7 +140,7 @@ TrainingSessionStartErrorMatchingDate = Erreur : cohérence des dates d TrainingSessionEndErrorMatchingDate = Erreur : cohérence des dates de fin de la formation.
La date de fin de la formation du contrat n'est pas égale à la date fin de la dernière session de formation %s. CalculatedTotalSessionDuration = Durée totale calculée : TrainingSessionDurationErrorMatching = Erreur : cohérence de la durée des sessions de formation.
La durée totale des sessions indiqué dans le contrat est différente de la durée calculé de l'ensemble des sessions liées au contrat. -NoCertificateBecauseAbsent = Aucun certificat n'a été généré pour %s %s parcequ'il a été absent à toute les sessions. +NoCertificateBecauseAbsent = Aucun certificat n'a été généré pour %s %s parcequ'il a été absent à au moins une session. ErrorMissingTrainingSessionProjectInfo = Attention : information du projet de formation manquante # Extrafields - Attributs supplémentaires diff --git a/view/session/session_list.php b/view/session/session_list.php index 442ee22..480fcb0 100644 --- a/view/session/session_list.php +++ b/view/session/session_list.php @@ -109,7 +109,7 @@ // Default sort order (if not yet defined by previous GETPOST) if (!$sortfield) { reset($object->fields); // Reset is required to avoid key() to return null - $sortfield = 't.date_creation'; + $sortfield = 't.date_start'; } if (!$sortorder) { $sortorder = 'DESC';