dolibarr 24.0.0-beta
recruitmentjobposition.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2020 Laurent Destailleur <eldy@users.sourceforge.net>
3/* Copyright (C) 2022 Alexandre Spangaro <aspangaro@open-dsi.fr>
4 * Copyright (C) 2024-2025 Frédéric France <frederic.france@free.fr>
5 * Copyright (C) 2024-2026 MDW <mdeweerd@users.noreply.github.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
27// Put here all includes required by your class file
28require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
29//require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
30//require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
31
36{
40 public $module = 'recruitment';
41
45 public $element = 'recruitmentjobposition';
46
50 public $table_element = 'recruitment_recruitmentjobposition';
51
55 public $picto = 'recruitmentjobposition';
56
60 const STATUS_DRAFT = 0;
61
66
71
75 const STATUS_CANCELED = 9;
76
77
103 // BEGIN MODULEBUILDER PROPERTIES
107 public $fields = array(
108 'rowid' => array('type' => 'integer', 'label' => 'TechnicalID', 'enabled' => 1, 'position' => 1, 'notnull' => 1, 'visible' => 0, 'noteditable' => 1, 'index' => 1, 'comment' => "Id"),
109 'entity' => array('type' => 'integer', 'label' => 'Entity', 'enabled' => 1, 'visible' => 0, 'position' => 5, 'notnull' => 1, 'default' => '1', 'index' => 1),
110 'ref' => array('type' => 'varchar(128)', 'label' => 'Ref', 'enabled' => 1, 'position' => 10, 'notnull' => 1, 'visible' => 4, 'noteditable' => 1, 'default' => '(PROV)', 'index' => 1, 'searchall' => 1, 'showoncombobox' => 1, 'comment' => "Reference of object", 'css' => 'nowraponall'),
111 'label' => array('type' => 'varchar(255)', 'label' => 'JobLabel', 'enabled' => 1, 'position' => 30, 'notnull' => 1, 'visible' => 1, 'searchall' => 1, 'css' => 'minwidth500', 'csslist' => 'tdoverflowmax300', 'showoncombobox' => 2, 'autofocusoncreate' => 1),
112 'qty' => array('type' => 'integer', 'label' => 'NbOfEmployeesExpected', 'enabled' => 1, 'position' => 45, 'notnull' => 1, 'visible' => 1, 'default' => '1', 'isameasure' => 1, 'css' => 'maxwidth75imp'),
113 'fk_project' => array('type' => 'integer:Project:projet/class/project.class.php:1', 'label' => 'Project', 'enabled' => 'isModProject("project")', 'position' => 52, 'notnull' => -1, 'visible' => -1, 'index' => 1, 'css' => 'maxwidth500', 'picto' => 'project'),
114 'fk_user_recruiter' => array('type' => 'integer:User:user/class/user.class.php:1:(statut:=:1)', 'label' => 'ResponsibleOfRecruitement', 'enabled' => 1, 'position' => 54, 'notnull' => 1, 'visible' => 1, 'foreignkey' => 'user.rowid', 'css' => 'maxwidth500', 'csslist' => 'tdoverflowmax150', 'picto' => 'user'),
115 'email_recruiter' => array('type' => 'varchar(255)', 'label' => 'EmailRecruiter', 'enabled' => 1, 'position' => 54, 'notnull' => 0, 'visible' => -1, 'help' => 'ToUseAGenericEmail', 'picto' => 'email'),
116 'fk_user_supervisor' => array('type' => 'integer:User:user/class/user.class.php:1:(statut:=:1)', 'label' => 'FutureManager', 'enabled' => 1, 'position' => 55, 'notnull' => 0, 'visible' => -1, 'foreignkey' => 'user.rowid', 'css' => 'maxwidth500', 'csslist' => 'tdoverflowmax150', 'picto' => 'user'),
117 'fk_establishment' => array('type' => 'integer:Establishment:hrm/class/establishment.class.php', 'label' => 'Establishment', 'enabled' => 'isModEnabled("hrm")', 'position' => 56, 'notnull' => 0, 'visible' => -1, 'foreignkey' => 'establishment.rowid',),
118 'fk_soc' => array('type' => 'integer:Societe:societe/class/societe.class.php:1:((status:=:1) AND (entity:IN:__SHARED_ENTITIES__))', 'label' => 'WorkPlace', 'enabled' => 'isModEnabled("societe")', 'position' => 57, 'notnull' => -1, 'visible' => -1, 'css' => 'maxwidth500', 'index' => 1, 'help' => "IfJobIsLocatedAtAPartner", 'picto' => 'company'),
119 'date_planned' => array('type' => 'date', 'label' => 'DateExpected', 'enabled' => 1, 'position' => 60, 'notnull' => 0, 'visible' => 1,),
120 'remuneration_suggested' => array('type' => 'varchar(255)', 'label' => 'Remuneration', 'enabled' => 1, 'position' => 62, 'notnull' => 0, 'visible' => 1,),
121 'description' => array('type' => 'html', 'label' => 'Description', 'enabled' => 1, 'position' => 65, 'notnull' => 0, 'visible' => 3,),
122 'note_public' => array('type' => 'html', 'label' => 'NotePublic', 'enabled' => 1, 'position' => 101, 'notnull' => 0, 'visible' => 0,),
123 'note_private' => array('type' => 'html', 'label' => 'NotePrivate', 'enabled' => 1, 'position' => 102, 'notnull' => 0, 'visible' => 0,),
124 'date_creation' => array('type' => 'datetime', 'label' => 'DateCreation', 'enabled' => 1, 'position' => 500, 'notnull' => 1, 'visible' => -4,),
125 'tms' => array('type' => 'timestamp', 'label' => 'DateModification', 'enabled' => 1, 'position' => 501, 'notnull' => 0, 'visible' => -2,),
126 'fk_user_creat' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserAuthor', 'enabled' => 1, 'position' => 510, 'notnull' => 1, 'visible' => -2, 'foreignkey' => 'user.rowid',),
127 'fk_user_modif' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserModif', 'enabled' => 1, 'position' => 511, 'notnull' => -1, 'visible' => -2,),
128 'last_main_doc' => array('type' => 'varchar(255)', 'label' => 'LastMainDoc', 'enabled' => 1, 'position' => 900, 'notnull' => 0, 'visible' => 0,),
129 'import_key' => array('type' => 'varchar(14)', 'label' => 'ImportId', 'enabled' => 1, 'position' => 1000, 'notnull' => -1, 'visible' => -2,),
130 'model_pdf' => array('type' => 'varchar(255)', 'label' => 'Model pdf', 'enabled' => 1, 'position' => 1010, 'notnull' => -1, 'visible' => 0,),
131 'status' => array('type' => 'smallint', 'label' => 'Status', 'enabled' => 1, 'position' => 1000, 'notnull' => 1, 'visible' => 5, 'default' => '0', 'index' => 1, 'arrayofkeyval' => array(0 => 'Draft', 1 => 'Validated', 3 => 'Recruited', 9 => 'Canceled'),),
132 );
136 public $rowid;
137
141 public $ref;
142
146 public $label;
147
151 public $qty;
152
156 public $fk_soc;
157
161 public $fk_project;
165 public $fk_user_recruiter;
166
170 public $email_recruiter;
171
175 public $remuneration_suggested;
176
180 public $fk_user_supervisor;
184 public $fk_establishment;
188 public $date_planned;
192 public $description;
196 public $note_public;
200 public $note_private;
204 public $fk_user_creat;
208 public $fk_user_modif;
212 public $last_main_doc;
216 public $import_key;
220 public $model_pdf;
224 public $status;
225 // END MODULEBUILDER PROPERTIES
226
227
233 public function __construct(DoliDB $db)
234 {
235 global $conf, $langs;
236
237 $this->db = $db;
238
239 $this->ismultientitymanaged = 1;
240 $this->isextrafieldmanaged = 1;
241
242 if (!getDolGlobalString('MAIN_SHOW_TECHNICAL_ID') && isset($this->fields['rowid'])) {
243 $this->fields['rowid']['visible'] = 0;
244 }
245 if (!isModEnabled('multicompany') && isset($this->fields['entity'])) {
246 $this->fields['entity']['enabled'] = 0;
247 }
248
249 // Example to show how to set values of fields definition dynamically
250 /*if ($user->hasRight('recruitment', 'recruitmentjobposition', 'read')) {
251 $this->fields['myfield']['visible'] = 1;
252 $this->fields['myfield']['noteditable'] = 0;
253 }*/
254
255 // Unset fields that are disabled
256 foreach ($this->fields as $key => $val) {
257 if (isset($val['enabled']) && empty($val['enabled'])) {
258 unset($this->fields[$key]);
259 }
260 }
261
262 // Translate some data of arrayofkeyval
263 if (is_object($langs)) {
264 foreach ($this->fields as $key => $val) {
265 if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
266 foreach ($val['arrayofkeyval'] as $key2 => $val2) {
267 $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2);
268 }
269 }
270 }
271 }
272 }
273
281 public function create(User $user, $notrigger = 0)
282 {
283 return $this->createCommon($user, $notrigger);
284 }
285
293 public function createFromClone(User $user, $fromid)
294 {
295 global $langs, $extrafields;
296 $error = 0;
297
298 dol_syslog(__METHOD__, LOG_DEBUG);
299
300 $object = new self($this->db);
301
302 $this->db->begin();
303
304 // Load source object
305 $result = $object->fetchCommon($fromid);
306 if ($result > 0 && !empty($object->table_element_line)) {
307 $object->fetchLines();
308 }
309
310 // get lines so they will be clone
311 //foreach($this->lines as $line)
312 // $line->fetch_optionals();
313
314 // Reset some properties
315 unset($object->id);
316 unset($object->fk_user_creat);
317 unset($object->import_key);
318
319 // Clear fields
320 if (property_exists($object, 'ref')) {
321 // @phan-suppress-next-line PhanTypeMismatchProperty
322 $object->ref = empty($this->fields['ref']['default']) ? "Copy_Of_".$object->ref : $this->fields['ref']['default'];
323 }
324 if (property_exists($object, 'label')) {
325 // @phan-suppress-next-line PhanTypeInvalidDimOffset
326 $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf")." ".$object->label : $this->fields['label']['default'];
327 }
328 if (property_exists($object, 'status')) {
329 $object->status = self::STATUS_DRAFT;
330 }
331 if (property_exists($object, 'date_creation')) {
332 $object->date_creation = dol_now();
333 }
334 if (property_exists($object, 'date_modification')) {
335 $object->date_modification = null;
336 }
337 // ...
338 // Clear extrafields that are unique
339 if (is_array($object->array_options) && count($object->array_options) > 0) {
340 $extrafields->fetch_name_optionals_label($this->table_element);
341 foreach ($object->array_options as $key => $option) {
342 $shortkey = preg_replace('/options_/', '', $key);
343 if (!empty($extrafields->attributes[$this->element]['unique'][$shortkey])) {
344 //var_dump($key);
345 //var_dump($clonedObj->array_options[$key]); exit;
346 unset($object->array_options[$key]);
347 }
348 }
349 }
350
351 // Create clone
352 $object->context['createfromclone'] = 'createfromclone';
353 $result = $object->createCommon($user);
354 if ($result < 0) {
355 $error++;
357 }
358
359 if (!$error) {
360 // copy internal contacts
361 if ($this->copy_linked_contact($object, 'internal') < 0) {
362 $error++;
363 }
364 }
365
366 if (!$error) {
367 // copy external contacts if same company
368 if (property_exists($this, 'socid') && $this->socid == $object->socid) {
369 if ($this->copy_linked_contact($object, 'external') < 0) {
370 $error++;
371 }
372 }
373 }
374
375 unset($object->context['createfromclone']);
376
377 // End
378 if (!$error) {
379 $this->db->commit();
380 return $object;
381 } else {
382 $this->db->rollback();
383 return -1;
384 }
385 }
386
394 public function fetch($id, $ref = null)
395 {
396 $result = $this->fetchCommon($id, $ref);
397 if ($result > 0 && !empty($this->table_element_line)) {
398 $this->fetchLines();
399 }
400 return $result;
401 }
402
408 public function fetchLines()
409 {
410 $this->lines = array();
411
412 $result = $this->fetchLinesCommon();
413 return $result;
414 }
415
416
429 public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, $filter = '', $filtermode = 'AND')
430 {
431 dol_syslog(__METHOD__, LOG_DEBUG);
432
433 $records = array();
434
435 $sql = 'SELECT ';
436 $sql .= $this->getFieldList();
437 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
438 if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
439 $sql .= ' WHERE t.entity IN ('.getEntity($this->element).')';
440 } else {
441 $sql .= ' WHERE 1 = 1';
442 }
443
444 // Manage filter
445 $errormessage = '';
446 $sql .= forgeSQLFromUniversalSearchCriteria($filter, $errormessage);
447 if ($errormessage) {
448 $this->errors[] = $errormessage;
449 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
450 return -1;
451 }
452
453 if (!empty($sortfield)) {
454 $sql .= $this->db->order($sortfield, $sortorder);
455 }
456 if (!empty($limit)) {
457 $sql .= $this->db->plimit($limit, $offset);
458 }
459
460 $resql = $this->db->query($sql);
461 if ($resql) {
462 $num = $this->db->num_rows($resql);
463 $i = 0;
464 while ($i < ($limit ? min($limit, $num) : $num)) {
465 $obj = $this->db->fetch_object($resql);
466
467 $record = new self($this->db);
468 $record->setVarsFromFetchObj($obj);
469
470 $records[$record->id] = $record;
471
472 $i++;
473 }
474 $this->db->free($resql);
475
476 return $records;
477 } else {
478 $this->errors[] = 'Error '.$this->db->lasterror();
479 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
480
481 return -1;
482 }
483 }
484
492 public function update(User $user, $notrigger = 0)
493 {
494 return $this->updateCommon($user, $notrigger);
495 }
496
504 public function delete(User $user, $notrigger = 0)
505 {
506 return $this->deleteCommon($user, $notrigger);
507 }
508
517 public function deleteLine(User $user, $idline, $notrigger = 0)
518 {
519 if ($this->status < 0) {
520 $this->error = 'ErrorDeleteLineNotAllowedByObjectStatus';
521 return -2;
522 }
523
524 return $this->deleteLineCommon($user, $idline, $notrigger);
525 }
526
527
535 public function validate($user, $notrigger = 0)
536 {
537 global $conf;
538
539 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
540
541 $error = 0;
542
543 // Protection
544 if ($this->status == self::STATUS_VALIDATED) {
545 dol_syslog(get_class($this)."::validate action abandoned: already validated", LOG_WARNING);
546 return 0;
547 }
548
549 $now = dol_now();
550
551 $this->db->begin();
552
553 // Define new ref
554 if (/* !$error && */ (preg_match('/^[\‍(]?PROV/i', $this->ref) || empty($this->ref))) { // empty should not happened, but when it occurs, the test save life
555 $num = $this->getNextNumRef();
556 } else {
557 $num = (string) $this->ref;
558 }
559 $this->newref = $num;
560
561 if (!empty($num)) {
562 // Validate
563 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
564 $sql .= " SET ref = '".$this->db->escape($num)."',";
565 $sql .= " status = ".self::STATUS_VALIDATED;
566 if (!empty($this->fields['date_validation'])) {
567 $sql .= ", date_validation = '".$this->db->idate($now)."',";
568 }
569 if (!empty($this->fields['fk_user_valid'])) { // @phan-suppress-current-line PhanTypeMismatchProperty
570 $sql .= ", fk_user_valid = ".((int) $user->id);
571 }
572 $sql .= " WHERE rowid = ".((int) $this->id);
573
574 dol_syslog(get_class($this)."::validate()", LOG_DEBUG);
575 $resql = $this->db->query($sql);
576 if (!$resql) {
577 dol_print_error($this->db);
578 $this->error = $this->db->lasterror();
579 $error++;
580 }
581
582 if (!$error && !$notrigger) {
583 // Call trigger
584 $result = $this->call_trigger('RECRUITMENTJOBPOSITION_VALIDATE', $user);
585 if ($result < 0) {
586 $error++;
587 }
588 // End call triggers
589 }
590 }
591
592 if (!$error) {
593 $this->oldref = $this->ref;
594
595 // Rename directory if dir was a temporary ref
596 if (preg_match('/^[\‍(]?PROV/i', $this->ref)) {
597 // Now we rename also files into index
598 $sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filename = CONCAT('".$this->db->escape($this->newref)."', SUBSTR(filename, ".(strlen($this->ref) + 1).")), filepath = 'recruitmentjobposition/".$this->db->escape($this->newref)."'";
599 $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'recruitmentjobposition/".$this->db->escape($this->ref)."' and entity = ".$conf->entity;
600 $resql = $this->db->query($sql);
601 if (!$resql) {
602 $error++;
603 $this->error = $this->db->lasterror();
604 }
605 $sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filepath = 'recruitmentjobposition/".$this->db->escape($this->newref)."'";
606 $sql .= " WHERE filepath = 'recruitmentjobposition/".$this->db->escape($this->ref)."' and entity = ".$conf->entity;
607 $resql = $this->db->query($sql);
608 if (!$resql) {
609 $error++;
610 $this->error = $this->db->lasterror();
611 }
612
613 // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
614 $oldref = dol_sanitizeFileName($this->ref);
615 $newref = dol_sanitizeFileName($num);
616 $dirsource = $conf->recruitment->dir_output.'/recruitmentjobposition/'.$oldref;
617 $dirdest = $conf->recruitment->dir_output.'/recruitmentjobposition/'.$newref;
618 if (!$error && file_exists($dirsource)) {
619 dol_syslog(get_class($this)."::validate() rename dir ".$dirsource." into ".$dirdest);
620
621 if (@rename($dirsource, $dirdest)) {
622 dol_syslog("Rename ok");
623 // Rename docs starting with $oldref with $newref
624 $listoffiles = dol_dir_list($conf->recruitment->dir_output.'/recruitmentjobposition/'.$newref, 'files', 1, '^'.preg_quote($oldref, '/'));
625 foreach ($listoffiles as $fileentry) {
626 $dirsource = $fileentry['name'];
627 $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource);
628 $dirsource = $fileentry['path'].'/'.$dirsource;
629 $dirdest = $fileentry['path'].'/'.$dirdest;
630 @rename($dirsource, $dirdest);
631 }
632 }
633 }
634 }
635 }
636
637 // Set new ref and current status
638 if (!$error) {
639 $this->ref = $num;
641 }
642
643 if (!$error) {
644 $this->db->commit();
645 return 1;
646 } else {
647 $this->db->rollback();
648 return -1;
649 }
650 }
651
652
660 public function setDraft($user, $notrigger = 0)
661 {
662 // Protection
663 if ($this->status <= self::STATUS_DRAFT) {
664 return 0;
665 }
666
667 /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->recruitment->write))
668 || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->recruitment->recruitment_advance->validate))))
669 {
670 $this->error='Permission denied';
671 return -1;
672 }*/
673
674 return $this->setStatusCommon($user, self::STATUS_DRAFT, $notrigger, 'RECRUITMENTJOBPOSITION_UNVALIDATE');
675 }
676
684 public function cancel($user, $notrigger = 0)
685 {
686 // Protection
687 if ($this->status != self::STATUS_VALIDATED) {
688 return 0;
689 }
690
691 /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->recruitment->write))
692 || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->recruitment->recruitment_advance->validate))))
693 {
694 $this->error='Permission denied';
695 return -1;
696 }*/
697
698 return $this->setStatusCommon($user, self::STATUS_CANCELED, $notrigger, 'RECRUITMENTJOBPOSITION_CLOSE');
699 }
700
710 public function cloture($user, $status, $note = "", $notrigger = 0)
711 {
712 global $langs, $conf;
713
714 $error = 0;
715 $now = dol_now();
716
717 $this->db->begin();
718
719 $newprivatenote = dol_concatdesc($this->note_private, $note);
720
721 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
722 $sql .= " SET status = ".((int) $status).", note_private = '".$this->db->escape($newprivatenote)."'";
723 //$sql .= ", date_cloture='".$this->db->idate($now)."', fk_user_cloture=".$user->id;
724 $sql .= " WHERE rowid = ".((int) $this->id);
725
726 $resql = $this->db->query($sql);
727 if ($resql) {
728 $modelpdf = $this->model_pdf;
729 $triggerName = 'RECRUITMENTJOB_CLOSE_REFUSED';
730
731 if ($status == self::STATUS_RECRUITED) {
732 $triggerName = 'RECRUITMENTJOB_CLOSE_RECRUITED';
733 $modelpdf = $this->model_pdf;
734 }
735
736 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
737 // Define output language
738 $outputlangs = $langs;
739 if (getDolGlobalInt('MAIN_MULTILANGS')) {
740 $outputlangs = new Translate("", $conf);
741 $newlang = (GETPOST('lang_id', 'aZ09') ? GETPOST('lang_id', 'aZ09') : $this->thirdparty->default_lang);
742 $outputlangs->setDefaultLang($newlang);
743 }
744
745 // PDF
746 $hidedetails = (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_DETAILS') ? 1 : 0);
747 $hidedesc = (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_DESC') ? 1 : 0);
748 $hideref = (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_REF') ? 1 : 0);
749
750 //$ret=$object->fetch($id); // Reload to get new records
751 $this->generateDocument($modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
752 }
753
754 $this->oldcopy = clone $this;
755 $this->status = $status;
756 $this->date_cloture = $now;
757 $this->note_private = $newprivatenote;
758
759 if (!$notrigger /* && empty($error) */) {
760 // Call trigger
761 $result = $this->call_trigger($triggerName, $user);
762 if ($result < 0) {
763 $error++;
764 }
765 // End call triggers
766 }
767
768 if (!$error) {
769 $this->db->commit();
770 return 1;
771 } else {
772 $this->status = $this->oldcopy->status;
773 $this->date_cloture = $this->oldcopy->date_cloture;
774 $this->note_private = $this->oldcopy->note_private;
775
776 $this->db->rollback();
777 return -1;
778 }
779 } else {
780 $this->error = $this->db->lasterror();
781 $this->db->rollback();
782 return -1;
783 }
784 }
785
793 public function reopen($user, $notrigger = 0)
794 {
795 // Protection
796 if ($this->status != self::STATUS_CANCELED) {
797 return 0;
798 }
799
800 /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->recruitment->write))
801 || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->recruitment->recruitment_advance->validate))))
802 {
803 $this->error='Permission denied';
804 return -1;
805 }*/
806
807 return $this->setStatusCommon($user, self::STATUS_VALIDATED, $notrigger, 'RECRUITMENTJOBPOSITION_REOPEN');
808 }
809
817 public function getTooltipContentArray($params)
818 {
819 global $langs;
820
821 $langs->load('recruitment');
822
823 $datas = [];
824
825 if (getDolGlobalInt('MAIN_OPTIMIZEFORTEXTBROWSER')) {
826 return ['optimize' => $langs->trans("ShowPositionToBeFilled")];
827 }
828 $datas['picto'] = img_picto('', $this->picto) . ' <u class="paddingrightonly">' . $langs->trans("PositionToBeFilled") . '</u>';
829 if (isset($this->status)) {
830 $datas['picto'] .= ' ' . $this->getLibStatut(5);
831 }
832 if (!empty($this->ref)) {
833 $datas['ref'] = '<br><b>' . $langs->trans('Ref') . ':</b> ' . $this->ref;
834 }
835 if (!empty($this->label)) {
836 $datas['ref'] = '<br>' . $langs->trans('Label') . ':</b> ' . $this->label;
837 }
838
839 return $datas;
840 }
841
852 public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
853 {
854 global $conf, $langs, $hookmanager;
855
856 if (!empty($conf->dol_no_mouse_hover)) {
857 $notooltip = 1; // Force disable tooltips
858 }
859
860 $result = '';
861 $params = [
862 'id' => (string) $this->id,
863 'objecttype' => $this->element.($this->module ? '@'.$this->module : ''),
864 'option' => $option,
865 ];
866 $classfortooltip = 'classfortooltip';
867 $dataparams = '';
868 if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) {
869 $classfortooltip = 'classforajaxtooltip';
870 $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"';
871 $label = '';
872 } else {
873 $label = implode($this->getTooltipContentArray($params));
874 }
875
876 $baseurl = DOL_URL_ROOT . '/recruitment/recruitmentjobposition_card.php';
877 $query = ['id' => $this->id];
878 if ($option !== 'nolink') {
879 // Add param to save lastsearch_values or not
880 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
881 if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
882 $add_save_lastsearch_values = 1;
883 }
884 if ($add_save_lastsearch_values) {
885 $query += ['save_lastsearch_values' => 1];
886 }
887 }
888 $url = dolBuildUrl($baseurl, $query);
889
890 $linkclose = '';
891 if (empty($notooltip)) {
892 if (getDolGlobalInt('MAIN_OPTIMIZEFORTEXTBROWSER')) {
893 $label = $langs->trans("ShowPositionToBeFilled");
894 $linkclose .= ' alt="'.dolPrintHTMLForAttribute($label).'"';
895 }
896 $linkclose .= ($label ? ' title="'.dolPrintHTMLForAttribute($label).'"' : ' title="tocomplete"');
897 $linkclose .= $dataparams.' class="'.$classfortooltip.($morecss ? ' '.$morecss : '').'"';
898 } else {
899 $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
900 }
901
902 $linkstart = '<a href="'.$url.'"';
903 $linkstart .= $linkclose.'>';
904 $linkend = '</a>';
905
906 $result .= $linkstart;
907
908 if (empty($this->showphoto_on_popup)) {
909 if ($withpicto) {
910 $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip ? 0 : 1);
911 }
912 } else {
913 if ($withpicto) {
914 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
915
916 list($class, $module) = explode('@', $this->picto);
917 $upload_dir = $conf->$module->multidir_output[$conf->entity]."/$class/".dol_sanitizeFileName($this->ref);
918 $filearray = dol_dir_list($upload_dir, "files");
919 $filename = $filearray[0]['name'];
920 if (!empty($filename)) {
921 $pospoint = strpos($filearray[0]['name'], '.');
922
923 $pathtophoto = $class.'/'.$this->ref.'/thumbs/'.substr($filename, 0, $pospoint).'_mini'.substr($filename, $pospoint);
924 if (!getDolGlobalString(strtoupper($module.'_'.$class).'_FORMATLISTPHOTOSASUSERS')) {
925 $result .= '<div class="floatleft inline-block valignmiddle divphotoref"><div class="photoref"><img class="photo'.$module.'" alt="No photo" border="0" src="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$module.'&entity='.$conf->entity.'&file='.urlencode($pathtophoto).'"></div></div>';
926 } else {
927 $result .= '<div class="floatleft inline-block valignmiddle divphotoref"><img class="photouserphoto userphoto" alt="No photo" border="0" src="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$module.'&entity='.$conf->entity.'&file='.urlencode($pathtophoto).'"></div>';
928 }
929
930 $result .= '</div>';
931 } else {
932 $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip ? 0 : 1);
933 }
934 }
935 }
936
937 if ($withpicto != 2) {
938 $result .= $this->ref;
939 }
940
941 $result .= $linkend;
942 //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
943
944 global $action, $hookmanager;
945 $hookmanager->initHooks(array('recruitmentjobpositiondao'));
946 $parameters = array('id' => $this->id, 'getnomurl' => &$result);
947 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
948 if ($reshook > 0) {
949 $result = $hookmanager->resPrint;
950 } else {
951 $result .= $hookmanager->resPrint;
952 }
953
954 return $result;
955 }
956
963 public function getLibStatut($mode = 0)
964 {
965 return $this->LibStatut($this->status, $mode);
966 }
967
968 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
976 public function LibStatut($status, $mode = 0)
977 {
978 // phpcs:enable
979 if (empty($this->labelStatus) || empty($this->labelStatusShort)) {
980 global $langs;
981 //$langs->load("recruitment");
982 $this->labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Draft');
983 $this->labelStatus[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('Validated');
984 $this->labelStatus[self::STATUS_RECRUITED] = $langs->transnoentitiesnoconv('Recruited');
985 $this->labelStatus[self::STATUS_CANCELED] = $langs->transnoentitiesnoconv('Canceled');
986 $this->labelStatusShort[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Draft');
987 $this->labelStatusShort[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('Validated');
988 $this->labelStatusShort[self::STATUS_RECRUITED] = $langs->transnoentitiesnoconv('Recruited');
989 $this->labelStatusShort[self::STATUS_CANCELED] = $langs->transnoentitiesnoconv('Canceled');
990 }
991
992 $statusType = 'status'.$status;
993 if ($status == self::STATUS_VALIDATED) {
994 $statusType = 'status4';
995 }
996 if ($status == self::STATUS_RECRUITED) {
997 $statusType = 'status6';
998 }
999 if ($status == self::STATUS_CANCELED) {
1000 $statusType = 'status9';
1001 }
1002
1003 return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode);
1004 }
1005
1012 public function info($id)
1013 {
1014 $sql = 'SELECT rowid, date_creation as datec, tms as datem,';
1015 $sql .= ' fk_user_creat, fk_user_modif';
1016 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
1017 $sql .= ' WHERE t.rowid = '.((int) $id);
1018 $result = $this->db->query($sql);
1019 if ($result) {
1020 if ($this->db->num_rows($result)) {
1021 $obj = $this->db->fetch_object($result);
1022
1023 $this->id = $obj->rowid;
1024
1025 $this->user_creation_id = $obj->fk_user_creat;
1026 $this->user_modification_id = $obj->fk_user_modif;
1027 $this->date_creation = $this->db->jdate($obj->datec);
1028 $this->date_modification = empty($obj->datem) ? '' : $this->db->jdate($obj->datem);
1029 }
1030
1031 $this->db->free($result);
1032 } else {
1033 dol_print_error($this->db);
1034 }
1035 }
1036
1043 public function initAsSpecimen()
1044 {
1045 return $this->initAsSpecimenCommon();
1046 }
1047
1053 public function getLinesArray()
1054 {
1055 $this->lines = array();
1056
1057 return $this->lines;
1058 }
1059
1065 public function getNextNumRef()
1066 {
1067 global $langs, $conf;
1068 $langs->load("recruitment");
1069
1070 if (!getDolGlobalString('RECRUITMENT_RECRUITMENTJOBPOSITION_ADDON')) {
1071 $conf->global->RECRUITMENT_RECRUITMENTJOBPOSITION_ADDON = 'mod_recruitmentjobposition_standard';
1072 }
1073
1074 if (getDolGlobalString('RECRUITMENT_RECRUITMENTJOBPOSITION_ADDON')) {
1075 $mybool = false;
1076
1077 $file = getDolGlobalString('RECRUITMENT_RECRUITMENTJOBPOSITION_ADDON') . ".php";
1078 $classname = getDolGlobalString('RECRUITMENT_RECRUITMENTJOBPOSITION_ADDON');
1079
1080 // Include file with class
1081 $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
1082 foreach ($dirmodels as $reldir) {
1083 $dir = dol_buildpath($reldir."core/modules/recruitment/");
1084
1085 // Load file with numbering class (if found)
1086 $mybool = ((bool) @include_once $dir.$file) || $mybool;
1087 }
1088
1089 if (!$mybool) {
1090 dol_print_error(null, "Failed to include file ".$file);
1091 return '';
1092 }
1093
1094 if (class_exists($classname)) {
1095 $obj = new $classname();
1096 '@phan-var-force ModeleNumRefRecruitmentJobPosition $obj';
1097 $numref = $obj->getNextValue($this);
1098
1099 if ($numref != '' && $numref != '-1') {
1100 return $numref;
1101 } else {
1102 $this->error = $obj->error;
1103 //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error);
1104 return "";
1105 }
1106 } else {
1107 print $langs->trans("Error")." ".$langs->trans("ClassNotFound").' '.$classname;
1108 return "";
1109 }
1110 } else {
1111 print $langs->trans("ErrorNumberingModuleNotSetup", $this->element);
1112 return "";
1113 }
1114 }
1115
1127 public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
1128 {
1129 global $conf, $langs;
1130
1131 $result = 0;
1132 $includedocgeneration = 1;
1133
1134 $langs->load("recruitment");
1135
1136 if (!dol_strlen($modele)) {
1137 if (getDolGlobalString('RECRUITMENTJOBPOSITION_ADDON_PDF')) {
1138 $modele = getDolGlobalString('RECRUITMENTJOBPOSITION_ADDON_PDF');
1139 } else {
1140 $modele = ''; // No default value. For job position, we allow to disable all PDF generation
1141 }
1142 }
1143
1144 $modelpath = "core/modules/recruitment/doc/";
1145
1146 if ($includedocgeneration && !empty($modele)) {
1147 $result = $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
1148 }
1149
1150 return $result;
1151 }
1152
1160 public function doScheduledJob()
1161 {
1162 //global $conf, $langs;
1163
1164 //$conf->global->SYSLOG_FILE = 'DOL_DATA_ROOT/dolibarr_mydedicatedlofile.log';
1165
1166 $error = 0;
1167 $this->output = '';
1168 $this->error = '';
1169
1170 dol_syslog(__METHOD__, LOG_DEBUG);
1171
1172 $now = dol_now();
1173
1174 $this->db->begin();
1175
1176 // ...
1177
1178 $this->db->commit();
1179
1180 return $error;
1181 }
1182
1183
1191 public function getKanbanView($option = '', $arraydata = null)
1192 {
1193 global $langs;
1194
1195 $selected = (empty($arraydata['selected']) ? 0 : $arraydata['selected']);
1196
1197 $return = '<div class="box-flex-item box-flex-grow-zero">';
1198 $return .= '<div class="info-box info-box-sm">';
1199 $return .= '<span class="info-box-icon bg-infobox-action">';
1200 $return .= img_picto('', $this->picto);
1201 $return .= '</span>';
1202 $return .= '<div class="info-box-content">';
1203 $return .= '<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">'.(method_exists($this, 'getNomUrl') ? $this->getNomUrl(1) : $this->ref).($this->qty > 1 ? ' <span title="'.$langs->trans("NbOfEmployeesExpected").'">('.$this->qty.')</span>' : '').'</span>';
1204 if ($selected >= 0) {
1205 $return .= '<input id="cb'.$this->id.'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->id.'"'.($selected ? ' checked="checked"' : '').'>';
1206 }
1207 /*
1208 if (property_exists($this, 'date_planned')) {
1209 $return .= '<br><span class="opacitymedium">'.$langs->trans("Date").'</span> : <span class="info-box-label">'.dol_print_date($this->db->jdate($this->date_planned), 'day').'</span>';
1210 }*/
1211 if (property_exists($this, 'remuneration_suggested')) {
1212 $return .= '<br><span class="opacitymedium">'.$langs->trans("Remuneration").'</span> : <span class="info-box-label">'.$this->remuneration_suggested.'</span>';
1213 }
1214 if (method_exists($this, 'getLibStatut')) {
1215 $return .= '<br><div class="info-box-status">'.$this->getLibStatut(3).' &nbsp; <span class="opacitymedium" title="'.$langs->trans("RecruitmentCandidatures").'">'.$langs->trans("RecruitmentCandidatures", '', '', '', '', 5).'</span> : <span>';
1216 $return .= $arraydata['nbapplications'];
1217 $return .= '</span></div>';
1218 }
1219 $return .= '</div>';
1220 $return .= '</div>';
1221 $return .= '</div>';
1222 return $return;
1223 }
1224}
if(! $sortfield) if(! $sortorder) $object
Definition account.php:100
$object ref
Definition info.php:90
Parent class of all other business classes (invoices, contracts, proposals, orders,...
deleteLineCommon(User $user, $idline, $notrigger=0)
Delete a line of object in database.
commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams=null)
Common function for all objects extending CommonObject for generating documents.
setErrorsFromObject($object)
setErrorsFromObject
createCommon(User $user, $notrigger=0)
Create object in the database.
getFieldList($alias='', $excludefields=array())
Function to concat keys of fields.
updateCommon(User $user, $notrigger=0)
Update object into database.
setStatusCommon($user, $status, $notrigger=0, $triggercode='')
Set to a status.
initAsSpecimenCommon()
Initialise object with example values Id must be 0 if object instance is a specimen.
copy_linked_contact($objFrom, $source='internal')
Copy contact from one element to current.
fetchLinesCommon($morewhere='', $noextrafields=0)
Load object in memory from the database.
fetchCommon($id, $ref=null, $morewhere='', $noextrafields=0)
Load object in memory from the database.
deleteCommon(User $user, $notrigger=0, $forcechilddeletion=0)
Delete object in database.
Class to manage Dolibarr database access.
Class for RecruitmentJobPosition.
validate($user, $notrigger=0)
Validate object.
deleteLine(User $user, $idline, $notrigger=0)
Delete a line of object in database.
generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0, $moreparams=null)
Create a document onto disk according to template module.
info($id)
Load the info information in the object.
getTooltipContentArray($params)
getTooltipContentArray
cloture($user, $status, $note="", $notrigger=0)
Close the recruitment.
getNomUrl($withpicto=0, $option='', $notooltip=0, $morecss='', $save_lastsearch_value=-1)
Return a link to the object card (with optionally the picto)
doScheduledJob()
Action executed by scheduler CAN BE A CRON TASK.
setDraft($user, $notrigger=0)
Set draft status.
getLibStatut($mode=0)
Return label of the status.
create(User $user, $notrigger=0)
Create object into database.
LibStatut($status, $mode=0)
Return the status.
getLinesArray()
Create an array of lines.
reopen($user, $notrigger=0)
Set back to validated status.
getKanbanView($option='', $arraydata=null)
Return clickable link of object (with eventually picto)
fetchAll($sortorder='', $sortfield='', $limit=0, $offset=0, $filter='', $filtermode='AND')
Load list of objects in memory from the database.
update(User $user, $notrigger=0)
Update object into database.
fetch($id, $ref=null)
Load object in memory from the database.
cancel($user, $notrigger=0)
Set cancel status.
createFromClone(User $user, $fromid)
Clone an object into another one.
initAsSpecimen()
Initialise object with example values Id must be 0 if object instance is a specimen.
getNextNumRef()
Returns the reference to the following non used object depending on the active numbering module.
fetchLines()
Load object lines in memory from the database.
Class to manage translations.
Class to manage Dolibarr users.
print $langs trans("Ref").' m titre as m m statut as status
Or an array listing all the potential status of the object: array: int of the status => translated la...
Definition index.php:168
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $db
API class for accounts.
dol_dir_list($utf8_path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0, $nbsecondsold=0)
Scan a directory and return a list of files/directories.
Definition files.lib.php:64
dol_now($mode='gmt')
Return date for now.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2, $allowothertags=array())
Show picto whatever it's its name (generic function)
dolBuildUrl($url, $params=[], $addtoken=false, $anchor='')
Return path of url.
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $allowothertags=array())
Show a picto called object_picto (generic function)
dol_sanitizeFileName($str, $newstr='_', $unaccent=1, $includequotes=0, $allowdash=0)
Clean a string to use it as a file name.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_concatdesc($text1, $text2, $forxml=false, $invert=false)
Concat 2 descriptions with a new line between them (second operand after first one with appropriate n...
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
print $langs trans("Show") . '< td style="' . $timeColor . '" align="center"> s</td > badge status0 badge status4 badge status3 Error badge status8< td align="center">< span class="badge ' . $badge . '"></span ></td >< td align="center">< a href="#" class="button button-small" onclick="openLogModal(this)" data-req="' . dol_escape_htmltag($reqSafe) . '" data-res="' . dol_escape_htmltag($resSafe) . '" data-err="' . dol_escape_htmltag($errSafe) . '">< span class="fa fa-search-plus"></span ></a ></td ></tr >< tr >< td colspan="' . $colspan . '" class="opacitymedium"></td ></tr ></table ></div ></form > logModal none logModal none s a JSON string
buildzip.php