dolibarr  18.0.0-beta
project.class.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2002-2005 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3  * Copyright (C) 2005-2020 Laurent Destailleur <eldy@users.sourceforge.net>
4  * Copyright (C) 2005-2010 Regis Houssin <regis.houssin@inodbox.com>
5  * Copyright (C) 2013 Florian Henry <florian.henry@open-concept.pro>
6  * Copyright (C) 2014-2017 Marcos GarcĂ­a <marcosgdf@gmail.com>
7  * Copyright (C) 2017 Ferran Marcet <fmarcet@2byte.es>
8  * Copyright (C) 2019 Juanjo Menent <jmenent@2byte.es>
9  * Copyright (C) 2022 Charlene Benke <charlene@patas-monkey.com>
10  * Copyright (C) 2023 Gauthier VERDOL <gauthier.verdol@atm-consulting.fr>
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 3 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program. If not, see <https://www.gnu.org/licenses/>.
24  */
25 
31 require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
32 
36 class Project extends CommonObject
37 {
38 
42  public $element = 'project';
43 
47  public $table_element = 'projet';
48 
52  public $table_element_line = 'projet_task';
53 
57  public $table_element_date;
58 
62  public $fk_element = 'fk_projet';
63 
68  public $ismultientitymanaged = 1;
69 
73  public $isextrafieldmanaged = 1;
74 
78  public $picto = 'project';
79 
83  protected $table_ref_field = 'ref';
84 
88  public $description;
89 
93  public $title;
94 
100  public $dateo;
101 
105  public $date_start;
106 
112  public $datee;
113 
117  public $date_end;
118 
122  public $date_start_event;
123 
127  public $date_end_event;
128 
132  public $location;
133 
137  public $date_close;
138 
139  public $socid; // To store id of thirdparty
140  public $thirdparty_name; // To store name of thirdparty (defined only in some cases)
141 
143 
147  public $fk_user_close;
148 
152  public $user_close_id;
153  public $public;
154 
158  public $budget_amount;
159 
163  public $usage_opportunity;
164 
168  public $usage_task;
169 
173  public $usage_bill_time; // Is the time spent on project must be invoiced or not
174 
178  public $usage_organize_event;
179 
183  public $accept_conference_suggestions;
184 
188  public $accept_booth_suggestions;
189 
193  public $price_registration;
194 
198  public $price_booth;
199 
203  public $max_attendees;
204 
205  public $statuts_short;
206  public $statuts_long;
207 
208  public $statut; // 0=draft, 1=opened, 2=closed
209 
210  public $opp_status; // opportunity status, into table llx_c_lead_status
211  public $opp_status_code;
212  public $fk_opp_status; // opportunity status, into table llx_c_lead_status
213  public $opp_amount; // opportunity amount
214  public $opp_percent; // opportunity probability
215  public $opp_weighted_amount; // opportunity weighted amount
216 
217  public $email_msgid;
218 
219  public $oldcopy;
220 
221  public $weekWorkLoad; // Used to store workload details of a projet
222  public $weekWorkLoadPerTask; // Used to store workload details of tasks of a projet
223 
229  public $datec;
230 
234  public $date_c;
235 
241  public $datem;
242 
246  public $date_m;
247 
251  public $lines;
252 
277  // BEGIN MODULEBUILDER PROPERTIES
281  public $fields = array(
282  'rowid' =>array('type'=>'integer', 'label'=>'ID', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>10),
283  'ref' =>array('type'=>'varchar(50)', 'label'=>'Ref', 'enabled'=>1, 'visible'=>1, 'showoncombobox'=>1, 'position'=>15, 'searchall'=>1),
284  'title' =>array('type'=>'varchar(255)', 'label'=>'ProjectLabel', 'enabled'=>1, 'visible'=>1, 'notnull'=>1, 'position'=>17, 'showoncombobox'=>2, 'searchall'=>1),
285  'entity' =>array('type'=>'integer', 'label'=>'Entity', 'default'=>1, 'enabled'=>1, 'visible'=>3, 'notnull'=>1, 'position'=>19),
286  'fk_soc' =>array('type'=>'integer', 'label'=>'Thirdparty', 'enabled'=>1, 'visible'=>0, 'position'=>20),
287  'dateo' =>array('type'=>'date', 'label'=>'DateStart', 'enabled'=>1, 'visible'=>1, 'position'=>30),
288  'datee' =>array('type'=>'date', 'label'=>'DateEnd', 'enabled'=>1, 'visible'=>1, 'position'=>35),
289  'description' =>array('type'=>'text', 'label'=>'Description', 'enabled'=>1, 'visible'=>3, 'position'=>55, 'searchall'=>1),
290  'public' =>array('type'=>'integer', 'label'=>'Visibility', 'enabled'=>1, 'visible'=>1, 'position'=>65),
291  'fk_opp_status' =>array('type'=>'integer', 'label'=>'OpportunityStatusShort', 'enabled'=>'getDolGlobalString("PROJECT_USE_OPPORTUNITIES")', 'visible'=>1, 'position'=>75),
292  'opp_percent' =>array('type'=>'double(5,2)', 'label'=>'OpportunityProbabilityShort', 'enabled'=>'getDolGlobalString("PROJECT_USE_OPPORTUNITIES")', 'visible'=>1, 'position'=>80),
293  'note_private' =>array('type'=>'html', 'label'=>'NotePrivate', 'enabled'=>1, 'visible'=>0, 'position'=>85, 'searchall'=>1),
294  'note_public' =>array('type'=>'html', 'label'=>'NotePublic', 'enabled'=>1, 'visible'=>0, 'position'=>90, 'searchall'=>1),
295  'model_pdf' =>array('type'=>'varchar(255)', 'label'=>'ModelPdf', 'enabled'=>1, 'visible'=>0, 'position'=>95),
296  'date_close' =>array('type'=>'datetime', 'label'=>'DateClosing', 'enabled'=>1, 'visible'=>0, 'position'=>105),
297  'fk_user_close' =>array('type'=>'integer', 'label'=>'UserClosing', 'enabled'=>1, 'visible'=>0, 'position'=>110),
298  'opp_amount' =>array('type'=>'double(24,8)', 'label'=>'OpportunityAmountShort', 'enabled'=>1, 'visible'=>'getDolGlobalString("PROJECT_USE_OPPORTUNITIES")', 'position'=>115),
299  'budget_amount' =>array('type'=>'double(24,8)', 'label'=>'Budget', 'enabled'=>1, 'visible'=>-1, 'position'=>119),
300  'usage_opportunity' =>array('type'=>'integer', 'label'=>'UsageOpportunity', 'enabled'=>1, 'visible'=>-1, 'position'=>130),
301  'usage_task' =>array('type'=>'integer', 'label'=>'UsageTasks', 'enabled'=>1, 'visible'=>-1, 'position'=>135),
302  'usage_bill_time' =>array('type'=>'integer', 'label'=>'UsageBillTimeShort', 'enabled'=>1, 'visible'=>-1, 'position'=>140),
303  'usage_organize_event' =>array('type'=>'integer', 'label'=>'UsageOrganizeEvent', 'enabled'=>1, 'visible'=>-1, 'position'=>145),
304  // Properties for event organization
305  'date_start_event' =>array('type'=>'date', 'label'=>'DateStartEvent', 'enabled'=>"isModEnabled('eventorganization')", 'visible'=>1, 'position'=>200),
306  'date_end_event' =>array('type'=>'date', 'label'=>'DateEndEvent', 'enabled'=>"isModEnabled('eventorganization')", 'visible'=>1, 'position'=>201),
307  'location' =>array('type'=>'text', 'label'=>'Location', 'enabled'=>1, 'visible'=>3, 'position'=>55, 'searchall'=>202),
308  'accept_conference_suggestions' =>array('type'=>'integer', 'label'=>'AllowUnknownPeopleSuggestConf', 'enabled'=>1, 'visible'=>-1, 'position'=>210),
309  'accept_booth_suggestions' =>array('type'=>'integer', 'label'=>'AllowUnknownPeopleSuggestBooth', 'enabled'=>1, 'visible'=>-1, 'position'=>211),
310  'price_registration' =>array('type'=>'double(24,8)', 'label'=>'PriceOfRegistration', 'enabled'=>1, 'visible'=>-1, 'position'=>212),
311  'price_booth' =>array('type'=>'double(24,8)', 'label'=>'PriceOfBooth', 'enabled'=>1, 'visible'=>-1, 'position'=>215),
312  'max_attendees' =>array('type'=>'integer', 'label'=>'MaxNbOfAttendees', 'enabled'=>1, 'visible'=>-1, 'position'=>215),
313  // Generic
314  'datec' =>array('type'=>'datetime', 'label'=>'DateCreationShort', 'enabled'=>1, 'visible'=>-2, 'position'=>400),
315  'tms' =>array('type'=>'timestamp', 'label'=>'DateModificationShort', 'enabled'=>1, 'visible'=>-2, 'notnull'=>1, 'position'=>405),
316  'fk_user_creat' =>array('type'=>'integer', 'label'=>'UserCreation', 'enabled'=>1, 'visible'=>0, 'notnull'=>1, 'position'=>410),
317  'fk_user_modif' =>array('type'=>'integer', 'label'=>'UserModification', 'enabled'=>1, 'visible'=>0, 'position'=>415),
318  'import_key' =>array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-1, 'position'=>420),
319  'email_msgid'=>array('type'=>'varchar(255)', 'label'=>'EmailMsgID', 'enabled'=>1, 'visible'=>-1, 'position'=>450, 'help'=>'EmailMsgIDWhenSourceisEmail', 'csslist'=>'tdoverflowmax125'),
320  'fk_statut' =>array('type'=>'smallint(6)', 'label'=>'Status', 'enabled'=>1, 'visible'=>1, 'notnull'=>1, 'position'=>500),
321  );
322  // END MODULEBUILDER PROPERTIES
323 
327  const STATUS_DRAFT = 0;
328 
332  const STATUS_VALIDATED = 1;
333 
337  const STATUS_CLOSED = 2;
338 
344  public function __construct($db)
345  {
346  global $conf;
347 
348  $this->db = $db;
349 
350  $this->statuts_short = array(0 => 'Draft', 1 => 'Opened', 2 => 'Closed');
351  $this->statuts_long = array(0 => 'Draft', 1 => 'Opened', 2 => 'Closed');
352 
353  global $conf;
354 
355  if (empty($conf->global->MAIN_SHOW_TECHNICAL_ID)) {
356  $this->fields['rowid']['visible'] = 0;
357  }
358 
359  if (empty($conf->global->PROJECT_USE_OPPORTUNITIES)) {
360  $this->fields['fk_opp_status']['enabled'] = 0;
361  $this->fields['opp_percent']['enabled'] = 0;
362  $this->fields['opp_amount']['enabled'] = 0;
363  $this->fields['usage_opportunity']['enabled'] = 0;
364  }
365 
366  if (!empty($conf->global->PROJECT_HIDE_TASKS)) {
367  $this->fields['usage_bill_time']['visible'] = 0;
368  $this->fields['usage_task']['visible'] = 0;
369  }
370 
371  if (empty($conf->eventorganization->enabled)) {
372  $this->fields['usage_organize_event']['visible'] = 0;
373  $this->fields['accept_conference_suggestions']['enabled'] = 0;
374  $this->fields['accept_booth_suggestions']['enabled'] = 0;
375  $this->fields['price_registration']['enabled'] = 0;
376  $this->fields['price_booth']['enabled'] = 0;
377  $this->fields['max_attendees']['enabled'] = 0;
378  }
379  }
380 
388  public function create($user, $notrigger = 0)
389  {
390  global $conf, $langs;
391 
392  $error = 0;
393  $ret = 0;
394 
395  $now = dol_now();
396 
397  // Clean parameters
398  $this->note_private = dol_substr($this->note_private, 0, 65535);
399  $this->note_public = dol_substr($this->note_public, 0, 65535);
400 
401  // Check parameters
402  if (!trim($this->ref)) {
403  $this->error = 'ErrorFieldsRequired';
404  dol_syslog(get_class($this)."::create error -1 ref null", LOG_ERR);
405  return -1;
406  }
407  if (!empty($conf->global->PROJECT_THIRDPARTY_REQUIRED) && !($this->socid > 0)) {
408  $this->error = 'ErrorFieldsRequired';
409  dol_syslog(get_class($this)."::create error -1 thirdparty not defined and option PROJECT_THIRDPARTY_REQUIRED is set", LOG_ERR);
410  return -1;
411  }
412 
413  // Create project
414  $this->db->begin();
415 
416  $sql = "INSERT INTO ".MAIN_DB_PREFIX."projet (";
417  $sql .= "ref";
418  $sql .= ", title";
419  $sql .= ", description";
420  $sql .= ", fk_soc";
421  $sql .= ", fk_user_creat";
422  $sql .= ", fk_statut";
423  $sql .= ", fk_opp_status";
424  $sql .= ", opp_percent";
425  $sql .= ", public";
426  $sql .= ", datec";
427  $sql .= ", dateo";
428  $sql .= ", datee";
429  $sql .= ", opp_amount";
430  $sql .= ", budget_amount";
431  $sql .= ", usage_opportunity";
432  $sql .= ", usage_task";
433  $sql .= ", usage_bill_time";
434  $sql .= ", usage_organize_event";
435  $sql .= ", accept_conference_suggestions";
436  $sql .= ", accept_booth_suggestions";
437  $sql .= ", price_registration";
438  $sql .= ", price_booth";
439  $sql .= ", max_attendees";
440  $sql .= ", date_start_event";
441  $sql .= ", date_end_event";
442  $sql .= ", location";
443  $sql .= ", email_msgid";
444  $sql .= ", note_private";
445  $sql .= ", note_public";
446  $sql .= ", entity";
447  $sql .= ", ip";
448  $sql .= ") VALUES (";
449  $sql .= "'".$this->db->escape($this->ref)."'";
450  $sql .= ", '".$this->db->escape($this->title)."'";
451  $sql .= ", '".$this->db->escape($this->description)."'";
452  $sql .= ", ".($this->socid > 0 ? $this->socid : "null");
453  $sql .= ", ".((int) $user->id);
454  $sql .= ", ".(is_numeric($this->statut) ? ((int) $this->statut) : '0');
455  $sql .= ", ".((is_numeric($this->opp_status) && $this->opp_status > 0) ? ((int) $this->opp_status) : 'NULL');
456  $sql .= ", ".(is_numeric($this->opp_percent) ? ((int) $this->opp_percent) : 'NULL');
457  $sql .= ", ".($this->public ? 1 : 0);
458  $sql .= ", '".$this->db->idate($now)."'";
459  $sql .= ", ".($this->date_start != '' ? "'".$this->db->idate($this->date_start)."'" : 'null');
460  $sql .= ", ".($this->date_end != '' ? "'".$this->db->idate($this->date_end)."'" : 'null');
461  $sql .= ", ".(strcmp($this->opp_amount, '') ? price2num($this->opp_amount) : 'null');
462  $sql .= ", ".(strcmp($this->budget_amount, '') ? price2num($this->budget_amount) : 'null');
463  $sql .= ", ".($this->usage_opportunity ? 1 : 0);
464  $sql .= ", ".($this->usage_task ? 1 : 0);
465  $sql .= ", ".($this->usage_bill_time ? 1 : 0);
466  $sql .= ", ".($this->usage_organize_event ? 1 : 0);
467  $sql .= ", ".($this->accept_conference_suggestions ? 1 : 0);
468  $sql .= ", ".($this->accept_booth_suggestions ? 1 : 0);
469  $sql .= ", ".(strcmp($this->price_registration, '') ? price2num($this->price_registration) : 'null');
470  $sql .= ", ".(strcmp($this->price_booth, '') ? price2num($this->price_booth) : 'null');
471  $sql .= ", ".(strcmp($this->max_attendees, '') ? ((int) $this->max_attendees) : 'null');
472  $sql .= ", ".($this->date_start_event != '' ? "'".$this->db->idate($this->date_start_event)."'" : 'null');
473  $sql .= ", ".($this->date_end_event != '' ? "'".$this->db->idate($this->date_end_event)."'" : 'null');
474  $sql .= ", ".($this->location ? "'".$this->db->escape($this->location)."'" : 'null');
475  $sql .= ", ".($this->email_msgid ? "'".$this->db->escape($this->email_msgid)."'" : 'null');
476  $sql .= ", ".($this->note_private ? "'".$this->db->escape($this->note_private)."'" : 'null');
477  $sql .= ", ".($this->note_public ? "'".$this->db->escape($this->note_public)."'" : 'null');
478  $sql .= ", ".((int) $conf->entity);
479  $sql .= ", ".(!isset($this->ip) ? 'NULL' : "'".$this->db->escape($this->ip)."'");
480  $sql .= ")";
481 
482  dol_syslog(get_class($this)."::create", LOG_DEBUG);
483  $resql = $this->db->query($sql);
484  if ($resql) {
485  $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."projet");
486  $ret = $this->id;
487 
488  if (!$notrigger) {
489  // Call trigger
490  $result = $this->call_trigger('PROJECT_CREATE', $user);
491  if ($result < 0) {
492  $error++;
493  }
494  // End call triggers
495  }
496  } else {
497  $this->error = $this->db->lasterror();
498  $this->errno = $this->db->lasterrno();
499  $error++;
500  }
501 
502  // Update extrafield
503  if (!$error) {
504  $result = $this->insertExtraFields();
505  if ($result < 0) {
506  $error++;
507  }
508  }
509 
510  if (!$error && (getDolGlobalString('MAIN_DISABLEDRAFTSTATUS') || getDolGlobalString('MAIN_DISABLEDRAFTSTATUS_PROJECT'))) {
511  $res = $this->setValid($user);
512  if ($res < 0) {
513  $error++;
514  }
515  }
516 
517  if (!$error) {
518  $this->db->commit();
519  return $ret;
520  } else {
521  $this->db->rollback();
522  return -1;
523  }
524  }
525 
533  public function update($user, $notrigger = 0)
534  {
535  global $langs, $conf;
536 
537  $error = 0;
538 
539  // Clean parameters
540  $this->title = trim($this->title);
541  $this->description = trim($this->description);
542  if ($this->opp_amount < 0) {
543  $this->opp_amount = '';
544  }
545  if ($this->opp_percent < 0) {
546  $this->opp_percent = '';
547  }
548  if ($this->date_end && $this->date_end < $this->date_start) {
549  $this->error = $langs->trans("ErrorDateEndLowerThanDateStart");
550  $this->errors[] = $this->error;
551  $this->db->rollback();
552  dol_syslog(get_class($this)."::update error -3 ".$this->error, LOG_ERR);
553  return -3;
554  }
555 
556  $this->entity = ((isset($this->entity) && is_numeric($this->entity)) ? $this->entity : $conf->entity);
557 
558  if (dol_strlen(trim($this->ref)) > 0) {
559  $this->db->begin();
560 
561  $sql = "UPDATE ".MAIN_DB_PREFIX."projet SET";
562  $sql .= " ref='".$this->db->escape($this->ref)."'";
563  $sql .= ", title = '".$this->db->escape($this->title)."'";
564  $sql .= ", description = '".$this->db->escape($this->description)."'";
565  $sql .= ", fk_soc = ".($this->socid > 0 ? $this->socid : "null");
566  $sql .= ", fk_statut = ".((int) $this->statut);
567  $sql .= ", fk_opp_status = ".((is_numeric($this->opp_status) && $this->opp_status > 0) ? $this->opp_status : 'null');
568  $sql .= ", opp_percent = ".((is_numeric($this->opp_percent) && $this->opp_percent != '') ? $this->opp_percent : 'null');
569  $sql .= ", public = ".($this->public ? 1 : 0);
570  $sql .= ", datec = ".($this->date_c != '' ? "'".$this->db->idate($this->date_c)."'" : 'null');
571  $sql .= ", dateo = ".($this->date_start != '' ? "'".$this->db->idate($this->date_start)."'" : 'null');
572  $sql .= ", datee = ".($this->date_end != '' ? "'".$this->db->idate($this->date_end)."'" : 'null');
573  $sql .= ", date_close = ".($this->date_close != '' ? "'".$this->db->idate($this->date_close)."'" : 'null');
574  $sql .= ", fk_user_close = ".($this->fk_user_close > 0 ? $this->fk_user_close : "null");
575  $sql .= ", opp_amount = ".(strcmp($this->opp_amount, '') ? price2num($this->opp_amount) : "null");
576  $sql .= ", budget_amount = ".(strcmp($this->budget_amount, '') ? price2num($this->budget_amount) : "null");
577  $sql .= ", fk_user_modif = ".$user->id;
578  $sql .= ", usage_opportunity = ".($this->usage_opportunity ? 1 : 0);
579  $sql .= ", usage_task = ".($this->usage_task ? 1 : 0);
580  $sql .= ", usage_bill_time = ".($this->usage_bill_time ? 1 : 0);
581  $sql .= ", usage_organize_event = ".($this->usage_organize_event ? 1 : 0);
582  $sql .= ", accept_conference_suggestions = ".($this->accept_conference_suggestions ? 1 : 0);
583  $sql .= ", accept_booth_suggestions = ".($this->accept_booth_suggestions ? 1 : 0);
584  $sql .= ", price_registration = ".(strcmp($this->price_registration, '') ? price2num($this->price_registration) : "null");
585  $sql .= ", price_booth = ".(strcmp($this->price_booth, '') ? price2num($this->price_booth) : "null");
586  $sql .= ", max_attendees = ".(strcmp($this->max_attendees, '') ? price2num($this->max_attendees) : "null");
587  $sql .= ", date_start_event = ".($this->date_start_event != '' ? "'".$this->db->idate($this->date_start_event)."'" : 'null');
588  $sql .= ", date_end_event = ".($this->date_end_event != '' ? "'".$this->db->idate($this->date_end_event)."'" : 'null');
589  $sql .= ", location = '".$this->db->escape($this->location)."'";
590  $sql .= ", entity = ".((int) $this->entity);
591  $sql .= " WHERE rowid = ".((int) $this->id);
592 
593  dol_syslog(get_class($this)."::update", LOG_DEBUG);
594  $resql = $this->db->query($sql);
595  if ($resql) {
596  // Update extrafield
597  if (!$error) {
598  $result = $this->insertExtraFields();
599  if ($result < 0) {
600  $error++;
601  }
602  }
603 
604  if (!$error && !$notrigger) {
605  // Call trigger
606  $result = $this->call_trigger('PROJECT_MODIFY', $user);
607  if ($result < 0) {
608  $error++;
609  }
610  // End call triggers
611  }
612 
613  if (!$error && (is_object($this->oldcopy) && $this->oldcopy->ref !== $this->ref)) {
614  // We remove directory
615  if ($conf->project->dir_output) {
616  $olddir = $conf->project->dir_output."/".dol_sanitizeFileName($this->oldcopy->ref);
617  $newdir = $conf->project->dir_output."/".dol_sanitizeFileName($this->ref);
618  if (file_exists($olddir)) {
619  include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
620  $res = @rename($olddir, $newdir);
621  if (!$res) {
622  $langs->load("errors");
623  $this->error = $langs->trans('ErrorFailToRenameDir', $olddir, $newdir);
624  $error++;
625  }
626  }
627  }
628  }
629  if (!$error) {
630  $this->db->commit();
631  $result = 1;
632  } else {
633  $this->db->rollback();
634  $result = -1;
635  }
636  } else {
637  $this->error = $this->db->lasterror();
638  $this->errors[] = $this->error;
639  $this->db->rollback();
640  if ($this->db->lasterrno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
641  $result = -4;
642  } else {
643  $result = -2;
644  }
645  dol_syslog(get_class($this)."::update error ".$result." ".$this->error, LOG_ERR);
646  }
647  } else {
648  dol_syslog(get_class($this)."::update ref null");
649  $result = -1;
650  }
651 
652  return $result;
653  }
654 
664  public function fetch($id, $ref = '', $ref_ext = '', $email_msgid = '')
665  {
666  if (empty($id) && empty($ref) && empty($ref_ext) && empty($email_msgid)) {
667  dol_syslog(get_class($this)."::fetch Bad parameters", LOG_WARNING);
668  return -1;
669  }
670 
671  $sql = "SELECT rowid, entity, ref, title, description, public, datec, opp_amount, budget_amount,";
672  $sql .= " tms, dateo as date_start, datee as date_end, date_close, fk_soc, fk_user_creat, fk_user_modif, fk_user_close, fk_statut as status, fk_opp_status, opp_percent,";
673  $sql .= " note_private, note_public, model_pdf, usage_opportunity, usage_task, usage_bill_time, usage_organize_event, email_msgid,";
674  $sql .= " accept_conference_suggestions, accept_booth_suggestions, price_registration, price_booth, max_attendees, date_start_event, date_end_event, location";
675  $sql .= " FROM ".MAIN_DB_PREFIX."projet";
676  if (!empty($id)) {
677  $sql .= " WHERE rowid = ".((int) $id);
678  } else {
679  $sql .= " WHERE entity IN (".getEntity('project').")";
680  if (!empty($ref)) {
681  $sql .= " AND ref = '".$this->db->escape($ref)."'";
682  } elseif (!empty($ref_ext)) {
683  $sql .= " AND ref_ext = '".$this->db->escape($ref_ext)."'";
684  } else {
685  $sql .= " AND email_msgid = '".$this->db->escape($email_msgid)."'";
686  }
687  }
688 
689  dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
690  $resql = $this->db->query($sql);
691  if ($resql) {
692  $num_rows = $this->db->num_rows($resql);
693 
694  if ($num_rows) {
695  $obj = $this->db->fetch_object($resql);
696 
697  $this->id = $obj->rowid;
698  $this->entity = $obj->entity;
699  $this->ref = $obj->ref;
700  $this->title = $obj->title;
701  $this->description = $obj->description;
702  $this->date_c = $this->db->jdate($obj->datec);
703  $this->datec = $this->db->jdate($obj->datec); // TODO deprecated
704  $this->date_m = $this->db->jdate($obj->tms);
705  $this->datem = $this->db->jdate($obj->tms); // TODO deprecated
706  $this->date_start = $this->db->jdate($obj->date_start);
707  $this->date_end = $this->db->jdate($obj->date_end);
708  $this->date_close = $this->db->jdate($obj->date_close);
709  $this->note_private = $obj->note_private;
710  $this->note_public = $obj->note_public;
711  $this->socid = $obj->fk_soc;
712  $this->user_author_id = $obj->fk_user_creat;
713  $this->user_modification_id = $obj->fk_user_modif;
714  $this->user_close_id = $obj->fk_user_close;
715  $this->public = $obj->public;
716  $this->statut = $obj->status; // deprecated
717  $this->status = $obj->status;
718  $this->opp_status = $obj->fk_opp_status;
719  $this->opp_amount = $obj->opp_amount;
720  $this->opp_percent = $obj->opp_percent;
721  $this->budget_amount = $obj->budget_amount;
722  $this->model_pdf = $obj->model_pdf;
723  $this->modelpdf = $obj->model_pdf; // deprecated
724  $this->usage_opportunity = (int) $obj->usage_opportunity;
725  $this->usage_task = (int) $obj->usage_task;
726  $this->usage_bill_time = (int) $obj->usage_bill_time;
727  $this->usage_organize_event = (int) $obj->usage_organize_event;
728  $this->accept_conference_suggestions = (int) $obj->accept_conference_suggestions;
729  $this->accept_booth_suggestions = (int) $obj->accept_booth_suggestions;
730  $this->price_registration = $obj->price_registration;
731  $this->price_booth = $obj->price_booth;
732  $this->max_attendees = $obj->max_attendees;
733  $this->date_start_event = $this->db->jdate($obj->date_start_event);
734  $this->date_end_event = $this->db->jdate($obj->date_end_event);
735  $this->location = $obj->location;
736  $this->email_msgid = $obj->email_msgid;
737 
738  $this->db->free($resql);
739 
740  // Retrieve all extrafield
741  // fetch optionals attributes and labels
742  $this->fetch_optionals();
743 
744  return 1;
745  }
746 
747  $this->db->free($resql);
748 
749  return 0;
750  } else {
751  $this->error = $this->db->lasterror();
752  $this->errors[] = $this->db->lasterror();
753  return -1;
754  }
755  }
756 
757  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
769  public function get_element_list($type, $tablename, $datefieldname = '', $date_start = '', $date_end = '', $projectkey = 'fk_projet')
770  {
771  // phpcs:enable
772 
773  global $hookmanager;
774 
775  $elements = array();
776 
777  if ($this->id <= 0) {
778  return $elements;
779  }
780 
781  $ids = $this->id;
782 
783  if ($type == 'agenda') {
784  $sql = "SELECT id as rowid FROM ".MAIN_DB_PREFIX."actioncomm WHERE fk_project IN (".$this->db->sanitize($ids).") AND entity IN (".getEntity('agenda').")";
785  } elseif ($type == 'expensereport') {
786  $sql = "SELECT ed.rowid FROM ".MAIN_DB_PREFIX."expensereport as e, ".MAIN_DB_PREFIX."expensereport_det as ed WHERE e.rowid = ed.fk_expensereport AND e.entity IN (".getEntity('expensereport').") AND ed.fk_projet IN (".$this->db->sanitize($ids).")";
787  } elseif ($type == 'project_task') {
788  $sql = "SELECT DISTINCT pt.rowid FROM ".MAIN_DB_PREFIX."projet_task as pt WHERE pt.fk_projet IN (".$this->db->sanitize($ids).")";
789  } elseif ($type == 'element_time') { // Case we want to duplicate line foreach user
790  $sql = "SELECT DISTINCT pt.rowid, ptt.fk_user FROM ".MAIN_DB_PREFIX."projet_task as pt, ".MAIN_DB_PREFIX."element_time as ptt WHERE pt.rowid = ptt.fk_element AND ptt.elementtype = 'task' AND pt.fk_projet IN (".$this->db->sanitize($ids).")";
791  } elseif ($type == 'stock_mouvement') {
792  $sql = "SELECT ms.rowid, ms.fk_user_author as fk_user FROM ".MAIN_DB_PREFIX."stock_mouvement as ms, ".MAIN_DB_PREFIX."entrepot as e WHERE e.rowid = ms.fk_entrepot AND e.entity IN (".getEntity('stock').") AND ms.origintype = 'project' AND ms.fk_origin IN (".$this->db->sanitize($ids).") AND ms.type_mouvement = 1";
793  } elseif ($type == 'loan') {
794  $sql = "SELECT l.rowid, l.fk_user_author as fk_user FROM ".MAIN_DB_PREFIX."loan as l WHERE l.entity IN (".getEntity('loan').") AND l.fk_projet IN (".$this->db->sanitize($ids).")";
795  } else {
796  $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX.$tablename." WHERE ".$projectkey." IN (".$this->db->sanitize($ids).") AND entity IN (".getEntity($type).")";
797  }
798 
799  if ($date_start > 0 && $type == 'loan') {
800  $sql .= " AND (dateend > '".$this->db->idate($date_start)."' OR dateend IS NULL)";
801  } elseif ($date_start > 0 && ($type != 'project_task')) { // For table project_taks, we want the filter on date apply on project_time_spent table
802  if (empty($datefieldname) && !empty($this->table_element_date)) {
803  $datefieldname = $this->table_element_date;
804  }
805  if (empty($datefieldname)) {
806  return 'Error this object has no date field defined';
807  }
808  $sql .= " AND (".$datefieldname." >= '".$this->db->idate($date_start)."' OR ".$datefieldname." IS NULL)";
809  }
810 
811  if ($date_end > 0 && $type == 'loan') {
812  $sql .= " AND (datestart < '".$this->db->idate($date_end)."' OR datestart IS NULL)";
813  } elseif ($date_end > 0 && ($type != 'project_task')) { // For table project_taks, we want the filter on date apply on project_time_spent table
814  if (empty($datefieldname) && !empty($this->table_element_date)) {
815  $datefieldname = $this->table_element_date;
816  }
817  if (empty($datefieldname)) {
818  return 'Error this object has no date field defined';
819  }
820  $sql .= " AND (".$datefieldname." <= '".$this->db->idate($date_end)."' OR ".$datefieldname." IS NULL)";
821  }
822 
823  $parameters = array(
824  'sql'=>$sql,
825  'type' => $type,
826  'tablename' => $tablename,
827  'datefieldname' => $datefieldname,
828  'dates' => $date_start,
829  'datee' => $date_end,
830  'fk_projet' => $projectkey,
831  'ids' => $ids,
832  );
833  $reshook = $hookmanager->executeHooks('getElementList', $parameters);
834  if ($reshook > 0) {
835  $sql = $hookmanager->resPrint;
836  } else {
837  $sql .= $hookmanager->resPrint;
838  }
839 
840  if (!$sql) {
841  return -1;
842  }
843 
844  //print $sql;
845  dol_syslog(get_class($this)."::get_element_list", LOG_DEBUG);
846  $result = $this->db->query($sql);
847  if ($result) {
848  $nump = $this->db->num_rows($result);
849  if ($nump) {
850  $i = 0;
851  while ($i < $nump) {
852  $obj = $this->db->fetch_object($result);
853 
854  $elements[$i] = $obj->rowid.(empty($obj->fk_user) ? '' : '_'.$obj->fk_user);
855 
856  $i++;
857  }
858  $this->db->free($result);
859  }
860 
861  /* Return array even if empty*/
862  return $elements;
863  } else {
864  dol_print_error($this->db);
865  }
866  }
867 
875  public function delete($user, $notrigger = 0)
876  {
877  global $langs, $conf;
878  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
879 
880  $error = 0;
881 
882  $this->db->begin();
883 
884  if (!$error) {
885  // Delete linked contacts
886  $res = $this->delete_linked_contact();
887  if ($res < 0) {
888  $this->error = 'ErrorFailToDeleteLinkedContact';
889  //$error++;
890  $this->db->rollback();
891  return 0;
892  }
893  }
894 
895  // Set fk_projet into elements to null
896  $listoftables = array(
897  'propal'=>'fk_projet', 'commande'=>'fk_projet', 'facture'=>'fk_projet',
898  'supplier_proposal'=>'fk_projet', 'commande_fournisseur'=>'fk_projet', 'facture_fourn'=>'fk_projet',
899  'expensereport_det'=>'fk_projet', 'contrat'=>'fk_projet',
900  'fichinter'=>'fk_projet',
901  'don'=>array('field'=>'fk_projet', 'module'=>'don'),
902  'actioncomm'=>'fk_project',
903  'mrp_mo'=>'fk_project',
904  'entrepot'=>'fk_project'
905  );
906  foreach ($listoftables as $key => $value) {
907  if (is_array($value)) {
908  if (!isModEnabled($value['module'])) {
909  continue;
910  }
911  $fieldname = $value['field'];
912  } else {
913  $fieldname = $value;
914  }
915  $sql = "UPDATE ".MAIN_DB_PREFIX.$key." SET ".$fieldname." = NULL where ".$fieldname." = ".((int) $this->id);
916 
917  $resql = $this->db->query($sql);
918  if (!$resql) {
919  $this->errors[] = $this->db->lasterror();
920  $error++;
921  break;
922  }
923  }
924 
925  // Remove linked categories.
926  if (!$error) {
927  $sql = "DELETE FROM ".MAIN_DB_PREFIX."categorie_project";
928  $sql .= " WHERE fk_project = ".((int) $this->id);
929 
930  $result = $this->db->query($sql);
931  if (!$result) {
932  $error++;
933  $this->errors[] = $this->db->lasterror();
934  }
935  }
936 
937  // Fetch tasks
938  $this->getLinesArray($user, 0);
939 
940  // Delete tasks
941  $ret = $this->deleteTasks($user);
942  if ($ret < 0) {
943  $error++;
944  }
945 
946 
947  // Delete all child tables
948  if (!$error) {
949  $elements = array('categorie_project'); // elements to delete. TODO Make goodway to delete
950  foreach ($elements as $table) {
951  if (!$error) {
952  $sql = "DELETE FROM ".MAIN_DB_PREFIX.$table;
953  $sql .= " WHERE fk_project = ".((int) $this->id);
954 
955  $result = $this->db->query($sql);
956  if (!$result) {
957  $error++;
958  $this->errors[] = $this->db->lasterror();
959  }
960  }
961  }
962  }
963 
964  if (!$error) {
965  $sql = "DELETE FROM ".MAIN_DB_PREFIX."projet_extrafields";
966  $sql .= " WHERE fk_object = ".((int) $this->id);
967 
968  $resql = $this->db->query($sql);
969  if (!$resql) {
970  $this->errors[] = $this->db->lasterror();
971  $error++;
972  }
973  }
974 
975  // Delete project
976  if (!$error) {
977  $sql = "DELETE FROM ".MAIN_DB_PREFIX."projet";
978  $sql .= " WHERE rowid=".((int) $this->id);
979 
980  $resql = $this->db->query($sql);
981  if (!$resql) {
982  $this->errors[] = $langs->trans("CantRemoveProject", $langs->transnoentitiesnoconv("ProjectOverview"));
983  $error++;
984  }
985  }
986 
987 
988 
989  if (empty($error)) {
990  // We remove directory
991  $projectref = dol_sanitizeFileName($this->ref);
992  if ($conf->project->dir_output) {
993  $dir = $conf->project->dir_output."/".$projectref;
994  if (file_exists($dir)) {
995  $res = @dol_delete_dir_recursive($dir);
996  if (!$res) {
997  $this->errors[] = 'ErrorFailToDeleteDir';
998  $error++;
999  }
1000  }
1001  }
1002 
1003  if (!$notrigger) {
1004  // Call trigger
1005  $result = $this->call_trigger('PROJECT_DELETE', $user);
1006 
1007  if ($result < 0) {
1008  $error++;
1009  }
1010  // End call triggers
1011  }
1012  }
1013 
1014  if (empty($error)) {
1015  $this->db->commit();
1016  return 1;
1017  } else {
1018  foreach ($this->errors as $errmsg) {
1019  dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR);
1020  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
1021  }
1022  dol_syslog(get_class($this)."::delete ".$this->error, LOG_ERR);
1023  $this->db->rollback();
1024  return -1;
1025  }
1026  }
1027 
1036  public function getElementCount($type, $tablename, $projectkey = 'fk_projet')
1037  {
1038  if ($this->id <= 0) {
1039  return 0;
1040  }
1041 
1042  if ($type == 'agenda') {
1043  $sql = "SELECT COUNT(id) as nb FROM ".MAIN_DB_PREFIX."actioncomm WHERE fk_project = ".((int) $this->id)." AND entity IN (".getEntity('agenda').")";
1044  } elseif ($type == 'expensereport') {
1045  $sql = "SELECT COUNT(ed.rowid) as nb FROM ".MAIN_DB_PREFIX."expensereport as e, ".MAIN_DB_PREFIX."expensereport_det as ed WHERE e.rowid = ed.fk_expensereport AND e.entity IN (".getEntity('expensereport').") AND ed.fk_projet = ".((int) $this->id);
1046  } elseif ($type == 'project_task') {
1047  $sql = "SELECT DISTINCT COUNT(pt.rowid) as nb FROM ".MAIN_DB_PREFIX."projet_task as pt WHERE pt.fk_projet = ".((int) $this->id);
1048  } elseif ($type == 'element_time') { // Case we want to duplicate line foreach user
1049  $sql = "SELECT DISTINCT COUNT(pt.rowid) as nb FROM ".MAIN_DB_PREFIX."projet_task as pt, ".MAIN_DB_PREFIX."element_time as ptt WHERE pt.rowid = ptt.fk_element AND ptt.elementtype = 'task' AND pt.fk_projet = ".((int) $this->id);
1050  } elseif ($type == 'stock_mouvement') {
1051  $sql = "SELECT COUNT(ms.rowid) as nb FROM ".MAIN_DB_PREFIX."stock_mouvement as ms, ".MAIN_DB_PREFIX."entrepot as e WHERE e.rowid = ms.fk_entrepot AND e.entity IN (".getEntity('stock').") AND ms.origintype = 'project' AND ms.fk_origin = ".((int) $this->id)." AND ms.type_mouvement = 1";
1052  } elseif ($type == 'loan') {
1053  $sql = "SELECT COUNT(l.rowid) as nb FROM ".MAIN_DB_PREFIX."loan as l WHERE l.entity IN (".getEntity('loan').") AND l.fk_projet = ".((int) $this->id);
1054  } else {
1055  $sql = "SELECT COUNT(rowid) as nb FROM ".MAIN_DB_PREFIX.$tablename." WHERE ".$projectkey." = ".((int) $this->id)." AND entity IN (".getEntity($type).")";
1056  }
1057 
1058  $result = $this->db->query($sql);
1059 
1060  if (!$result) {
1061  return 0;
1062  }
1063 
1064  $obj = $this->db->fetch_object($result);
1065 
1066  $this->db->free($result);
1067 
1068  return $obj->nb;
1069  }
1070 
1077  public function deleteTasks($user)
1078  {
1079  $countTasks = count($this->lines);
1080  $deleted = false;
1081  if ($countTasks) {
1082  foreach ($this->lines as $task) {
1083  if ($task->hasChildren() <= 0) { // If there is no children (or error to detect them)
1084  $deleted = true;
1085  $ret = $task->delete($user);
1086  if ($ret <= 0) {
1087  $this->errors[] = $this->db->lasterror();
1088  return -1;
1089  }
1090  }
1091  }
1092  }
1093  $this->getLinesArray($user);
1094  if ($deleted && count($this->lines) < $countTasks) {
1095  if (count($this->lines)) {
1096  $this->deleteTasks($this->lines);
1097  }
1098  }
1099 
1100  return 1;
1101  }
1102 
1110  public function setValid($user, $notrigger = 0)
1111  {
1112  global $langs, $conf;
1113 
1114  $error = 0;
1115 
1116  // Protection
1117  if ($this->status == self::STATUS_VALIDATED) {
1118  dol_syslog(get_class($this)."::validate action abandonned: already validated", LOG_WARNING);
1119  return 0;
1120  }
1121 
1122  // Check parameters
1123  if (preg_match('/^'.preg_quote($langs->trans("CopyOf").' ').'/', $this->title)) {
1124  $this->error = $langs->trans("ErrorFieldFormat", $langs->transnoentities("Label")).'. '.$langs->trans('RemoveString', $langs->transnoentitiesnoconv("CopyOf"));
1125  return -1;
1126  }
1127 
1128  $this->db->begin();
1129 
1130  $sql = "UPDATE ".MAIN_DB_PREFIX."projet";
1131  $sql .= " SET fk_statut = ".self::STATUS_VALIDATED;
1132  $sql .= " WHERE rowid = ".((int) $this->id);
1133  //$sql .= " AND entity = ".((int) $conf->entity); // Disabled, when we use the ID for the where, we must not add any other search condition
1134 
1135  dol_syslog(get_class($this)."::setValid", LOG_DEBUG);
1136  $resql = $this->db->query($sql);
1137  if ($resql) {
1138  // Call trigger
1139  if (empty($notrigger)) {
1140  $result = $this->call_trigger('PROJECT_VALIDATE', $user);
1141  if ($result < 0) {
1142  $error++;
1143  }
1144  // End call triggers
1145  }
1146 
1147  if (!$error) {
1148  $this->statut = 1;
1149  $this->db->commit();
1150  return 1;
1151  } else {
1152  $this->db->rollback();
1153  $this->error = join(',', $this->errors);
1154  dol_syslog(get_class($this)."::setValid ".$this->error, LOG_ERR);
1155  return -1;
1156  }
1157  } else {
1158  $this->db->rollback();
1159  $this->error = $this->db->lasterror();
1160  return -1;
1161  }
1162  }
1163 
1170  public function setClose($user)
1171  {
1172  global $langs, $conf;
1173 
1174  $now = dol_now();
1175 
1176  $error = 0;
1177 
1178  if ($this->statut != self::STATUS_CLOSED) {
1179  $this->db->begin();
1180 
1181  $sql = "UPDATE ".MAIN_DB_PREFIX."projet";
1182  $sql .= " SET fk_statut = ".self::STATUS_CLOSED.", fk_user_close = ".((int) $user->id).", date_close = '".$this->db->idate($now)."'";
1183  $sql .= " WHERE rowid = ".((int) $this->id);
1184  $sql .= " AND fk_statut = ".self::STATUS_VALIDATED;
1185 
1186  if (!empty($conf->global->PROJECT_USE_OPPORTUNITIES)) {
1187  // TODO What to do if fk_opp_status is not code 'WON' or 'LOST'
1188  }
1189 
1190  dol_syslog(get_class($this)."::setClose", LOG_DEBUG);
1191  $resql = $this->db->query($sql);
1192  if ($resql) {
1193  // Call trigger
1194  $result = $this->call_trigger('PROJECT_CLOSE', $user);
1195  if ($result < 0) {
1196  $error++;
1197  }
1198  // End call triggers
1199 
1200  if (!$error) {
1201  $this->statut = 2;
1202  $this->db->commit();
1203  return 1;
1204  } else {
1205  $this->db->rollback();
1206  $this->error = join(',', $this->errors);
1207  dol_syslog(get_class($this)."::setClose ".$this->error, LOG_ERR);
1208  return -1;
1209  }
1210  } else {
1211  $this->db->rollback();
1212  $this->error = $this->db->lasterror();
1213  return -1;
1214  }
1215  }
1216 
1217  return 0;
1218  }
1219 
1226  public function getLibStatut($mode = 0)
1227  {
1228  return $this->LibStatut(isset($this->statut) ? $this->statut : $this->status, $mode);
1229  }
1230 
1231  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1239  public function LibStatut($status, $mode = 0)
1240  {
1241  // phpcs:enable
1242  global $langs;
1243 
1244  $statustrans = array(
1245  0 => 'status0',
1246  1 => 'status4',
1247  2 => 'status6',
1248  );
1249 
1250  $statusClass = 'status0';
1251  if (!empty($statustrans[$status])) {
1252  $statusClass = $statustrans[$status];
1253  }
1254 
1255  return dolGetStatus($langs->transnoentitiesnoconv($this->statuts_long[$status]), $langs->transnoentitiesnoconv($this->statuts_short[$status]), '', $statusClass, $mode);
1256  }
1257 
1265  public function getTooltipContentArray($params)
1266  {
1267  global $conf, $langs;
1268 
1269  $langs->load('projects');
1270  $option = $params['option'] ?? '';
1271  $moreinpopup = $params['morinpopup'] ?? '';
1272 
1273  $datas = [];
1274  if ($option != 'nolink') {
1275  $datas['picto'] = img_picto('', $this->picto, 'class="pictofixedwidth"').' <u class="paddingrightonly">'.$langs->trans("Project").'</u>';
1276  }
1277  if (isset($this->status)) {
1278  $datas['picto'] .= ' '.$this->getLibStatut(5);
1279  }
1280  $datas['ref'] = (isset($datas['picto']) ? '<br>' : '').'<b>'.$langs->trans('Ref').': </b>'.$this->ref; // The space must be after the : to not being explode when showing the title in img_picto
1281  $datas['label'] = '<br><b>'.$langs->trans('Label').': </b>'.$this->title; // The space must be after the : to not being explode when showing the title in img_picto
1282  if (isset($this->public)) {
1283  $datas['visibility'] = '<br><b>'.$langs->trans("Visibility").":</b> ";
1284  $datas['visibility'] .= ($this->public ? img_picto($langs->trans('SharedProject'), 'world', 'class="pictofixedwidth"').$langs->trans("SharedProject") : img_picto($langs->trans('PrivateProject'), 'private', 'class="pictofixedwidth"').$langs->trans("PrivateProject"));
1285  }
1286  if (!empty($this->thirdparty_name)) {
1287  $datas['thirdparty'] = '<br><b>'.$langs->trans('ThirdParty').': </b>'.$this->thirdparty_name; // The space must be after the : to not being explode when showing the title in img_picto
1288  }
1289  if (!empty($this->date_start)) {
1290  $datas['datestart'] = '<br><b>'.$langs->trans('DateStart').': </b>'.dol_print_date($this->date_start, 'day'); // The space must be after the : to not being explode when showing the title in img_picto
1291  }
1292  if (!empty($this->date_end)) {
1293  $datas['dateend'] = '<br><b>'.$langs->trans('DateEnd').': </b>'.dol_print_date($this->date_end, 'day'); // The space must be after the : to not being explode when showing the title in img_picto
1294  }
1295  if ($moreinpopup) {
1296  $datas['moreinpopup'] = '<br>'.$moreinpopup;
1297  }
1298 
1299  return $datas;
1300  }
1301 
1315  public function getNomUrl($withpicto = 0, $option = '', $addlabel = 0, $moreinpopup = '', $sep = ' - ', $notooltip = 0, $save_lastsearch_value = -1, $morecss = '')
1316  {
1317  global $conf, $langs, $user, $hookmanager;
1318 
1319  if (!empty($conf->dol_no_mouse_hover)) {
1320  $notooltip = 1; // Force disable tooltips
1321  }
1322 
1323  $result = '';
1324  if (!empty($conf->global->PROJECT_OPEN_ALWAYS_ON_TAB)) {
1325  $option = $conf->global->PROJECT_OPEN_ALWAYS_ON_TAB;
1326  }
1327  $params = [
1328  'id' => $this->id,
1329  'objecttype' => $this->element,
1330  'moreinpopup' => $moreinpopup,
1331  'option' => $option,
1332  ];
1333  $classfortooltip = 'classfortooltip';
1334  $dataparams = '';
1335  if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) {
1336  $classfortooltip = 'classforajaxtooltip';
1337  $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"';
1338  $label = '';
1339  } else {
1340  $label = implode($this->getTooltipContentArray($params));
1341  }
1342 
1343  $url = '';
1344  if ($option != 'nolink') {
1345  if (preg_match('/\.php$/', $option)) {
1346  $url = dol_buildpath($option, 1).'?id='.$this->id;
1347  } elseif ($option == 'task') {
1348  $url = DOL_URL_ROOT.'/projet/tasks.php?id='.$this->id;
1349  } elseif ($option == 'preview') {
1350  $url = DOL_URL_ROOT.'/projet/element.php?id='.$this->id;
1351  } elseif ($option == 'eventorganization') {
1352  $url = DOL_URL_ROOT.'/eventorganization/conferenceorbooth_list.php?projectid='.$this->id;
1353  } else {
1354  $url = DOL_URL_ROOT.'/projet/card.php?id='.$this->id;
1355  }
1356  // Add param to save lastsearch_values or not
1357  $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1358  if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
1359  $add_save_lastsearch_values = 1;
1360  }
1361  if ($add_save_lastsearch_values) {
1362  $url .= '&save_lastsearch_values=1';
1363  }
1364  }
1365 
1366  $linkclose = '';
1367  if (empty($notooltip) && $user->hasRight('projet', 'lire')) {
1368  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
1369  $label = $langs->trans("ShowProject");
1370  $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
1371  }
1372  $linkclose .= ($label ? ' title="'.dol_escape_htmltag($label, 1).'"' : ' title="tocomplete"');
1373  $linkclose .= $dataparams.' class="'.$classfortooltip.($morecss ? ' '.$morecss : '').'"';
1374  } else {
1375  $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
1376  }
1377 
1378  $picto = 'projectpub';
1379  if (!$this->public) {
1380  $picto = 'project';
1381  }
1382 
1383  $linkstart = '<a href="'.$url.'"';
1384  $linkstart .= $linkclose.'>';
1385  $linkend = '</a>';
1386 
1387  $result .= $linkstart;
1388  if ($withpicto) {
1389  $result .= img_object(($notooltip ? '' : $label), $picto, 'class="pictofixedwidth em088"', 0, 0, $notooltip ? 0 : 1);
1390  }
1391  if ($withpicto != 2) {
1392  $result .= $this->ref;
1393  }
1394  $result .= $linkend;
1395  if ($withpicto != 2) {
1396  $result .= (($addlabel && $this->title) ? '<span class="opacitymedium">'.$sep.dol_trunc($this->title, ($addlabel > 1 ? $addlabel : 0)).'</span>' : '');
1397  }
1398 
1399  global $action;
1400  $hookmanager->initHooks(array('projectdao'));
1401  $parameters = array('id'=>$this->id, 'getnomurl' => &$result);
1402  $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1403  if ($reshook > 0) {
1404  $result = $hookmanager->resPrint;
1405  } else {
1406  $result .= $hookmanager->resPrint;
1407  }
1408 
1409  return $result;
1410  }
1411 
1419  public function initAsSpecimen()
1420  {
1421  global $user, $langs, $conf;
1422 
1423  $now = dol_now();
1424 
1425  // Initialise parameters
1426  $this->id = 0;
1427  $this->ref = 'SPECIMEN';
1428  $this->entity = $conf->entity;
1429  $this->specimen = 1;
1430  $this->socid = 1;
1431  $this->date_c = $now;
1432  $this->date_m = $now;
1433  $this->date_start = $now;
1434  $this->date_end = $now + (3600 * 24 * 365);
1435  $this->note_public = 'SPECIMEN';
1436  $this->fk_ele = 20000;
1437  $this->opp_amount = 20000;
1438  $this->budget_amount = 10000;
1439 
1440  $this->usage_opportunity = 1;
1441  $this->usage_task = 1;
1442  $this->usage_bill_time = 1;
1443  $this->usage_organize_event = 1;
1444 
1445  /*
1446  $nbp = mt_rand(1, 9);
1447  $xnbp = 0;
1448  while ($xnbp < $nbp)
1449  {
1450  $line = new Task($this->db);
1451  $line->fk_project = 0;
1452  $line->label = $langs->trans("Label") . " " . $xnbp;
1453  $line->description = $langs->trans("Description") . " " . $xnbp;
1454 
1455  $this->lines[]=$line;
1456  $xnbp++;
1457  }
1458  */
1459  }
1460 
1468  public function restrictedProjectArea(User $user, $mode = 'read')
1469  {
1470  // To verify role of users
1471  $userAccess = 0;
1472  if (($mode == 'read' && !empty($user->rights->projet->all->lire)) || ($mode == 'write' && !empty($user->rights->projet->all->creer)) || ($mode == 'delete' && !empty($user->rights->projet->all->supprimer))) {
1473  $userAccess = 1;
1474  } elseif ($this->public && (($mode == 'read' && !empty($user->rights->projet->lire)) || ($mode == 'write' && !empty($user->rights->projet->creer)) || ($mode == 'delete' && !empty($user->rights->projet->supprimer)))) {
1475  $userAccess = 1;
1476  } else { // No access due to permission to read all projects, so we check if we are a contact of project
1477  foreach (array('internal', 'external') as $source) {
1478  $userRole = $this->liste_contact(4, $source);
1479  $num = count($userRole);
1480 
1481  $nblinks = 0;
1482  while ($nblinks < $num) {
1483  if ($source == 'internal' && $user->id == $userRole[$nblinks]['id']) { // $userRole[$nblinks]['id'] is id of user (llx_user) for internal contacts
1484  if ($mode == 'read' && $user->rights->projet->lire) {
1485  $userAccess++;
1486  }
1487  if ($mode == 'write' && $user->rights->projet->creer) {
1488  $userAccess++;
1489  }
1490  if ($mode == 'delete' && $user->rights->projet->supprimer) {
1491  $userAccess++;
1492  }
1493  }
1494  if ($source == 'external' && $user->socid > 0 && $user->socid == $userRole[$nblinks]['socid']) { // $userRole[$nblinks]['id'] is id of contact (llx_socpeople) or external contacts
1495  if ($mode == 'read' && $user->rights->projet->lire) {
1496  $userAccess++;
1497  }
1498  if ($mode == 'write' && $user->rights->projet->creer) {
1499  $userAccess++;
1500  }
1501  if ($mode == 'delete' && $user->rights->projet->supprimer) {
1502  $userAccess++;
1503  }
1504  }
1505  $nblinks++;
1506  }
1507  }
1508  //if (empty($nblinks)) // If nobody has permission, we grant creator
1509  //{
1510  // if ((!empty($this->user_author_id) && $this->user_author_id == $user->id))
1511  // {
1512  // $userAccess = 1;
1513  // }
1514  //}
1515  }
1516 
1517  return ($userAccess ? $userAccess : -1);
1518  }
1519 
1530  public function getProjectsAuthorizedForUser($user, $mode = 0, $list = 0, $socid = 0, $filter = '')
1531  {
1532  $projects = array();
1533  $temp = array();
1534 
1535  $sql = "SELECT ".(($mode == 0 || $mode == 1) ? "DISTINCT " : "")."p.rowid, p.ref";
1536  $sql .= " FROM ".MAIN_DB_PREFIX."projet as p";
1537  if ($mode == 0) {
1538  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."element_contact as ec ON ec.element_id = p.rowid";
1539  } elseif ($mode == 1) {
1540  $sql .= ", ".MAIN_DB_PREFIX."element_contact as ec";
1541  } elseif ($mode == 2) {
1542  // No filter. Use this if user has permission to see all project
1543  }
1544  $sql .= " WHERE p.entity IN (".getEntity('project').")";
1545  // Internal users must see project he is contact to even if project linked to a third party he can't see.
1546  //if ($socid || ! $user->rights->societe->client->voir) $sql.= " AND (p.fk_soc IS NULL OR p.fk_soc = 0 OR p.fk_soc = ".((int) $socid).")";
1547  if ($socid > 0) {
1548  $sql .= " AND (p.fk_soc IS NULL OR p.fk_soc = 0 OR p.fk_soc = ".((int) $socid).")";
1549  }
1550 
1551  // Get id of types of contacts for projects (This list never contains a lot of elements)
1552  $listofprojectcontacttype = array();
1553  $sql2 = "SELECT ctc.rowid, ctc.code FROM ".MAIN_DB_PREFIX."c_type_contact as ctc";
1554  $sql2 .= " WHERE ctc.element = '".$this->db->escape($this->element)."'";
1555  $sql2 .= " AND ctc.source = 'internal'";
1556  $resql = $this->db->query($sql2);
1557  if ($resql) {
1558  while ($obj = $this->db->fetch_object($resql)) {
1559  $listofprojectcontacttype[$obj->rowid] = $obj->code;
1560  }
1561  } else {
1562  dol_print_error($this->db);
1563  }
1564  if (count($listofprojectcontacttype) == 0) {
1565  $listofprojectcontacttype[0] = '0'; // To avoid syntax error if not found
1566  }
1567 
1568  if ($mode == 0) {
1569  $sql .= " AND ( p.public = 1";
1570  $sql .= " OR ( ec.fk_c_type_contact IN (".$this->db->sanitize(join(',', array_keys($listofprojectcontacttype))).")";
1571  $sql .= " AND ec.fk_socpeople = ".((int) $user->id).")";
1572  $sql .= " )";
1573  } elseif ($mode == 1) {
1574  $sql .= " AND ec.element_id = p.rowid";
1575  $sql .= " AND (";
1576  $sql .= " ( ec.fk_c_type_contact IN (".$this->db->sanitize(join(',', array_keys($listofprojectcontacttype))).")";
1577  $sql .= " AND ec.fk_socpeople = ".((int) $user->id).")";
1578  $sql .= " )";
1579  } elseif ($mode == 2) {
1580  // No filter. Use this if user has permission to see all project
1581  }
1582 
1583  $sql .= $filter;
1584  //print $sql;
1585 
1586  $resql = $this->db->query($sql);
1587  if ($resql) {
1588  $num = $this->db->num_rows($resql);
1589  $i = 0;
1590  while ($i < $num) {
1591  $row = $this->db->fetch_row($resql);
1592  $projects[$row[0]] = $row[1];
1593  $temp[] = $row[0];
1594  $i++;
1595  }
1596 
1597  $this->db->free($resql);
1598 
1599  if ($list) {
1600  if (empty($temp)) {
1601  return '0';
1602  }
1603  $result = implode(',', $temp);
1604  return $result;
1605  }
1606  } else {
1607  dol_print_error($this->db);
1608  }
1609 
1610  return $projects;
1611  }
1612 
1628  public function createFromClone(User $user, $fromid, $clone_contact = false, $clone_task = true, $clone_project_file = false, $clone_task_file = false, $clone_note = true, $move_date = true, $notrigger = 0, $newthirdpartyid = 0)
1629  {
1630  global $langs, $conf;
1631 
1632  $error = 0;
1633 
1634  dol_syslog("createFromClone clone_contact=".$clone_contact." clone_task=".$clone_task." clone_project_file=".$clone_project_file." clone_note=".$clone_note." move_date=".$move_date, LOG_DEBUG);
1635 
1636  $now = dol_mktime(0, 0, 0, idate('m', dol_now()), idate('d', dol_now()), idate('Y', dol_now()));
1637 
1638  $clone_project = new Project($this->db);
1639 
1640  $clone_project->context['createfromclone'] = 'createfromclone';
1641 
1642  $this->db->begin();
1643 
1644  // Load source object
1645  $clone_project->fetch($fromid);
1646  $clone_project->fetch_optionals();
1647  if ($newthirdpartyid > 0) {
1648  $clone_project->socid = $newthirdpartyid;
1649  }
1650  $clone_project->fetch_thirdparty();
1651 
1652  $orign_dt_start = $clone_project->date_start;
1653  $orign_project_ref = $clone_project->ref;
1654 
1655  $clone_project->id = 0;
1656  if ($move_date) {
1657  $clone_project->date_start = $now;
1658  if (!(empty($clone_project->date_end))) {
1659  $clone_project->date_end = $clone_project->date_end + ($now - $orign_dt_start);
1660  }
1661  }
1662 
1663  $clone_project->date_c = $now;
1664 
1665  if (!$clone_note) {
1666  $clone_project->note_private = '';
1667  $clone_project->note_public = '';
1668  }
1669 
1670  //Generate next ref
1671  $defaultref = '';
1672  $obj = empty($conf->global->PROJECT_ADDON) ? 'mod_project_simple' : $conf->global->PROJECT_ADDON;
1673  // Search template files
1674  $file = ''; $classname = ''; $filefound = 0;
1675  $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
1676  foreach ($dirmodels as $reldir) {
1677  $file = dol_buildpath($reldir."core/modules/project/".$obj.'.php', 0);
1678  if (file_exists($file)) {
1679  $filefound = 1;
1680  dol_include_once($reldir."core/modules/project/".$obj.'.php');
1681  $modProject = new $obj;
1682  $defaultref = $modProject->getNextValue(is_object($clone_project->thirdparty) ? $clone_project->thirdparty : null, $clone_project);
1683  break;
1684  }
1685  }
1686  if (is_numeric($defaultref) && $defaultref <= 0) {
1687  $defaultref = '';
1688  }
1689 
1690  $clone_project->ref = $defaultref;
1691  $clone_project->title = $langs->trans("CopyOf").' '.$clone_project->title;
1692 
1693  // Create clone
1694  $result = $clone_project->create($user, $notrigger);
1695 
1696  // Other options
1697  if ($result < 0) {
1698  $this->error .= $clone_project->error;
1699  $error++;
1700  }
1701 
1702  if (!$error) {
1703  //Get the new project id
1704  $clone_project_id = $clone_project->id;
1705 
1706  //Note Update
1707  if (!$clone_note) {
1708  $clone_project->note_private = '';
1709  $clone_project->note_public = '';
1710  } else {
1711  $this->db->begin();
1712  $res = $clone_project->update_note(dol_html_entity_decode($clone_project->note_public, ENT_QUOTES | ENT_HTML5), '_public');
1713  if ($res < 0) {
1714  $this->error .= $clone_project->error;
1715  $error++;
1716  $this->db->rollback();
1717  } else {
1718  $this->db->commit();
1719  }
1720 
1721  $this->db->begin();
1722  $res = $clone_project->update_note(dol_html_entity_decode($clone_project->note_private, ENT_QUOTES | ENT_HTML5), '_private');
1723  if ($res < 0) {
1724  $this->error .= $clone_project->error;
1725  $error++;
1726  $this->db->rollback();
1727  } else {
1728  $this->db->commit();
1729  }
1730  }
1731 
1732  //Duplicate contact
1733  if ($clone_contact) {
1734  $origin_project = new Project($this->db);
1735  $origin_project->fetch($fromid);
1736 
1737  foreach (array('internal', 'external') as $source) {
1738  $tab = $origin_project->liste_contact(-1, $source);
1739  if (is_array($tab) && count($tab)>0) {
1740  foreach ($tab as $contacttoadd) {
1741  $clone_project->add_contact($contacttoadd['id'], $contacttoadd['code'], $contacttoadd['source'], $notrigger);
1742  if ($clone_project->error == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
1743  $langs->load("errors");
1744  $this->error .= $langs->trans("ErrorThisContactIsAlreadyDefinedAsThisType");
1745  $error++;
1746  } else {
1747  if ($clone_project->error != '') {
1748  $this->error .= $clone_project->error;
1749  $error++;
1750  }
1751  }
1752  }
1753  } elseif ($tab < 0) {
1754  $this->error .= $origin_project->error;
1755  $error++;
1756  }
1757  }
1758  }
1759 
1760  //Duplicate file
1761  if ($clone_project_file) {
1762  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1763 
1764  $clone_project_dir = $conf->project->dir_output."/".dol_sanitizeFileName($defaultref);
1765  $ori_project_dir = $conf->project->dir_output."/".dol_sanitizeFileName($orign_project_ref);
1766 
1767  if (dol_mkdir($clone_project_dir) >= 0) {
1768  $filearray = dol_dir_list($ori_project_dir, "files", 0, '', '(\.meta|_preview.*\.png)$', '', SORT_ASC, 1);
1769  foreach ($filearray as $key => $file) {
1770  $rescopy = dol_copy($ori_project_dir.'/'.$file['name'], $clone_project_dir.'/'.$file['name'], 0, 1);
1771  if (is_numeric($rescopy) && $rescopy < 0) {
1772  $this->error .= $langs->trans("ErrorFailToCopyFile", $ori_project_dir.'/'.$file['name'], $clone_project_dir.'/'.$file['name']);
1773  $error++;
1774  }
1775  }
1776  } else {
1777  $this->error .= $langs->trans('ErrorInternalErrorDetected').':dol_mkdir';
1778  $error++;
1779  }
1780  }
1781 
1782  //Duplicate task
1783  if ($clone_task) {
1784  require_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php';
1785 
1786  $taskstatic = new Task($this->db);
1787 
1788  // Security check
1789  $socid = 0;
1790  if ($user->socid > 0) {
1791  $socid = $user->socid;
1792  }
1793 
1794  $tasksarray = $taskstatic->getTasksArray(0, 0, $fromid, $socid, 0);
1795 
1796  $tab_conv_child_parent = array();
1797 
1798  // Loop on each task, to clone it
1799  foreach ($tasksarray as $tasktoclone) {
1800  $result_clone = $taskstatic->createFromClone($user, $tasktoclone->id, $clone_project_id, $tasktoclone->fk_parent, $move_date, true, false, $clone_task_file, true, false);
1801  if ($result_clone <= 0) {
1802  $this->error .= $taskstatic->error;
1803  $error++;
1804  } else {
1805  $new_task_id = $result_clone;
1806  $taskstatic->fetch($tasktoclone->id);
1807 
1808  //manage new parent clone task id
1809  // if the current task has child we store the original task id and the equivalent clone task id
1810  if (($taskstatic->hasChildren()) && !array_key_exists($tasktoclone->id, $tab_conv_child_parent)) {
1811  $tab_conv_child_parent[$tasktoclone->id] = $new_task_id;
1812  }
1813  }
1814  }
1815 
1816  //Parse all clone node to be sure to update new parent
1817  $tasksarray = $taskstatic->getTasksArray(0, 0, $clone_project_id, $socid, 0);
1818  foreach ($tasksarray as $task_cloned) {
1819  $taskstatic->fetch($task_cloned->id);
1820  if ($taskstatic->fk_task_parent != 0) {
1821  $taskstatic->fk_task_parent = $tab_conv_child_parent[$taskstatic->fk_task_parent];
1822  }
1823  $res = $taskstatic->update($user, $notrigger);
1824  if ($result_clone <= 0) {
1825  $this->error .= $taskstatic->error;
1826  $error++;
1827  }
1828  }
1829  }
1830  }
1831 
1832  unset($clone_project->context['createfromclone']);
1833 
1834  if (!$error) {
1835  $this->db->commit();
1836  return $clone_project_id;
1837  } else {
1838  $this->db->rollback();
1839  dol_syslog(get_class($this)."::createFromClone nbError: ".$error." error : ".$this->error, LOG_ERR);
1840  return -1;
1841  }
1842  }
1843 
1844 
1851  public function shiftTaskDate($old_project_dt_start)
1852  {
1853  global $user, $langs, $conf;
1854 
1855  $error = 0;
1856  $result = 0;
1857 
1858  $taskstatic = new Task($this->db);
1859 
1860  // Security check
1861  $socid = 0;
1862  if ($user->socid > 0) {
1863  $socid = $user->socid;
1864  }
1865 
1866  $tasksarray = $taskstatic->getTasksArray(0, 0, $this->id, $socid, 0);
1867 
1868  foreach ($tasksarray as $tasktoshiftdate) {
1869  $to_update = false;
1870  // Fetch only if update of date will be made
1871  if ((!empty($tasktoshiftdate->date_start)) || (!empty($tasktoshiftdate->date_end))) {
1872  //dol_syslog(get_class($this)."::shiftTaskDate to_update", LOG_DEBUG);
1873  $to_update = true;
1874  $task = new Task($this->db);
1875  $result = $task->fetch($tasktoshiftdate->id);
1876  if (!$result) {
1877  $error++;
1878  $this->error .= $task->error;
1879  }
1880  }
1881  //print "$this->date_start + $tasktoshiftdate->date_start - $old_project_dt_start";exit;
1882 
1883  //Calcultate new task start date with difference between old proj start date and origin task start date
1884  if (!empty($tasktoshiftdate->date_start)) {
1885  $task->date_start = $this->date_start + ($tasktoshiftdate->date_start - $old_project_dt_start);
1886  }
1887 
1888  //Calcultate new task end date with difference between origin proj end date and origin task end date
1889  if (!empty($tasktoshiftdate->date_end)) {
1890  $task->date_end = $this->date_start + ($tasktoshiftdate->date_end - $old_project_dt_start);
1891  }
1892 
1893  if ($to_update) {
1894  $result = $task->update($user);
1895  if (!$result) {
1896  $error++;
1897  $this->error .= $task->error;
1898  }
1899  }
1900  }
1901  if ($error != 0) {
1902  return -1;
1903  }
1904  return $result;
1905  }
1906 
1907 
1908  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1916  public function update_element($tableName, $elementSelectId)
1917  {
1918  // phpcs:enable
1919  $sql = "UPDATE ".MAIN_DB_PREFIX.$tableName;
1920 
1921  if ($tableName == "actioncomm") {
1922  $sql .= " SET fk_project=".$this->id;
1923  $sql .= " WHERE id=".((int) $elementSelectId);
1924  } elseif ($tableName == "entrepot") {
1925  $sql .= " SET fk_project=".$this->id;
1926  $sql .= " WHERE rowid=".((int) $elementSelectId);
1927  } else {
1928  $sql .= " SET fk_projet=".$this->id;
1929  $sql .= " WHERE rowid=".((int) $elementSelectId);
1930  }
1931 
1932  dol_syslog(get_class($this)."::update_element", LOG_DEBUG);
1933  $resql = $this->db->query($sql);
1934  if (!$resql) {
1935  $this->error = $this->db->lasterror();
1936  return -1;
1937  } else {
1938  return 1;
1939  }
1940  }
1941 
1942  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1952  public function remove_element($tableName, $elementSelectId, $projectfield = 'fk_projet')
1953  {
1954  // phpcs:enable
1955  $sql = "UPDATE ".MAIN_DB_PREFIX.$tableName;
1956 
1957  if ($tableName == "actioncomm") {
1958  $sql .= " SET fk_project=NULL";
1959  $sql .= " WHERE id=".((int) $elementSelectId);
1960  } else {
1961  $sql .= " SET ".$projectfield."=NULL";
1962  $sql .= " WHERE rowid=".((int) $elementSelectId);
1963  }
1964 
1965  dol_syslog(get_class($this)."::remove_element", LOG_DEBUG);
1966  $resql = $this->db->query($sql);
1967  if (!$resql) {
1968  $this->error = $this->db->lasterror();
1969  return -1;
1970  } else {
1971  return 1;
1972  }
1973  }
1974 
1985  public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0)
1986  {
1987  global $conf, $langs;
1988 
1989  $langs->load("projects");
1990 
1991  if (!dol_strlen($modele)) {
1992  $modele = 'baleine';
1993 
1994  if ($this->model_pdf) {
1995  $modele = $this->model_pdf;
1996  } elseif (!empty($conf->global->PROJECT_ADDON_PDF)) {
1997  $modele = $conf->global->PROJECT_ADDON_PDF;
1998  }
1999  }
2000 
2001  $modelpath = "core/modules/project/doc/";
2002 
2003  return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref);
2004  }
2005 
2006 
2016  public function loadTimeSpent($datestart, $taskid = 0, $userid = 0)
2017  {
2018  $error = 0;
2019 
2020  $this->weekWorkLoad = array();
2021  $this->weekWorkLoadPerTask = array();
2022 
2023  if (empty($datestart)) {
2024  dol_print_error('', 'Error datestart parameter is empty');
2025  }
2026 
2027  $sql = "SELECT ptt.rowid as taskid, ptt.element_duration, ptt.element_date, ptt.element_datehour, ptt.fk_element";
2028  $sql .= " FROM ".MAIN_DB_PREFIX."element_time AS ptt, ".MAIN_DB_PREFIX."projet_task as pt";
2029  $sql .= " WHERE ptt.fk_element = pt.rowid";
2030  $sql .= " AND ptt.elementtype = 'task'";
2031  $sql .= " AND pt.fk_projet = ".((int) $this->id);
2032  $sql .= " AND (ptt.element_date >= '".$this->db->idate($datestart)."' ";
2033  $sql .= " AND ptt.element_date <= '".$this->db->idate(dol_time_plus_duree($datestart, 1, 'w') - 1)."')";
2034  if ($taskid) {
2035  $sql .= " AND ptt.fk_element=".((int) $taskid);
2036  }
2037  if (is_numeric($userid)) {
2038  $sql .= " AND ptt.fk_user=".((int) $userid);
2039  }
2040 
2041  //print $sql;
2042  $resql = $this->db->query($sql);
2043  if ($resql) {
2044  $daylareadyfound = array();
2045 
2046  $num = $this->db->num_rows($resql);
2047  $i = 0;
2048  // Loop on each record found, so each couple (project id, task id)
2049  while ($i < $num) {
2050  $obj = $this->db->fetch_object($resql);
2051  $day = $this->db->jdate($obj->element_date); // task_date is date without hours
2052  if (empty($daylareadyfound[$day])) {
2053  $this->weekWorkLoad[$day] = $obj->element_duration;
2054  $this->weekWorkLoadPerTask[$day][$obj->fk_element] = $obj->element_duration;
2055  } else {
2056  $this->weekWorkLoad[$day] += $obj->element_duration;
2057  $this->weekWorkLoadPerTask[$day][$obj->fk_element] += $obj->element_duration;
2058  }
2059  $daylareadyfound[$day] = 1;
2060  $i++;
2061  }
2062  $this->db->free($resql);
2063  return 1;
2064  } else {
2065  $this->error = "Error ".$this->db->lasterror();
2066  dol_syslog(get_class($this)."::fetch ".$this->error, LOG_ERR);
2067  return -1;
2068  }
2069  }
2070 
2080  public function loadTimeSpentMonth($datestart, $taskid = 0, $userid = 0)
2081  {
2082  $error = 0;
2083 
2084  $this->monthWorkLoad = array();
2085  $this->monthWorkLoadPerTask = array();
2086 
2087  if (empty($datestart)) {
2088  dol_print_error('', 'Error datestart parameter is empty');
2089  }
2090 
2091  $sql = "SELECT ptt.rowid as taskid, ptt.element_duration, ptt.element_date, ptt.element_datehour, ptt.fk_element";
2092  $sql .= " FROM ".MAIN_DB_PREFIX."element_time AS ptt, ".MAIN_DB_PREFIX."projet_task as pt";
2093  $sql .= " WHERE ptt.fk_element = pt.rowid";
2094  $sql .= " AND ptt.elementtype = 'task'";
2095  $sql .= " AND pt.fk_projet = ".((int) $this->id);
2096  $sql .= " AND (ptt.element_date >= '".$this->db->idate($datestart)."' ";
2097  $sql .= " AND ptt.element_date <= '".$this->db->idate(dol_time_plus_duree($datestart, 1, 'm') - 1)."')";
2098  if ($taskid) {
2099  $sql .= " AND ptt.fk_element=".((int) $taskid);
2100  }
2101  if (is_numeric($userid)) {
2102  $sql .= " AND ptt.fk_user=".((int) $userid);
2103  }
2104 
2105  //print $sql;
2106  $resql = $this->db->query($sql);
2107  if ($resql) {
2108  $weekalreadyfound = array();
2109 
2110  $num = $this->db->num_rows($resql);
2111  $i = 0;
2112  // Loop on each record found, so each couple (project id, task id)
2113  while ($i < $num) {
2114  $obj = $this->db->fetch_object($resql);
2115  if (!empty($obj->element_date)) {
2116  $date = explode('-', $obj->element_date);
2117  $week_number = getWeekNumber($date[2], $date[1], $date[0]);
2118  }
2119  if (empty($weekalreadyfound[$week_number])) {
2120  $this->monthWorkLoad[$week_number] = $obj->element_duration;
2121  $this->monthWorkLoadPerTask[$week_number][$obj->fk_element] = $obj->element_duration;
2122  } else {
2123  $this->monthWorkLoad[$week_number] += $obj->element_duration;
2124  $this->monthWorkLoadPerTask[$week_number][$obj->fk_element] += $obj->element_duration;
2125  }
2126  $weekalreadyfound[$week_number] = 1;
2127  $i++;
2128  }
2129  $this->db->free($resql);
2130  return 1;
2131  } else {
2132  $this->error = "Error ".$this->db->lasterror();
2133  dol_syslog(get_class($this)."::fetch ".$this->error, LOG_ERR);
2134  return -1;
2135  }
2136  }
2137 
2138  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2145  public function load_board($user)
2146  {
2147  // phpcs:enable
2148  global $conf, $langs;
2149 
2150  // For external user, no check is done on company because readability is managed by public status of project and assignement.
2151  //$socid=$user->socid;
2152 
2153  $response = new WorkboardResponse();
2154  $response->warning_delay = $conf->project->warning_delay / 60 / 60 / 24;
2155  $response->label = $langs->trans("OpenedProjects");
2156  $response->labelShort = $langs->trans("Opened");
2157  $response->url = DOL_URL_ROOT.'/projet/list.php?search_project_user=-1&search_status=1&mainmenu=project';
2158  $response->img = img_object('', "projectpub");
2159  $response->nbtodo = 0;
2160  $response->nbtodolate = 0;
2161 
2162  $sql = "SELECT p.rowid, p.fk_statut as status, p.fk_opp_status, p.datee as datee";
2163  $sql .= " FROM (".MAIN_DB_PREFIX."projet as p";
2164  $sql .= ")";
2165  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s on p.fk_soc = s.rowid";
2166  // For external user, no check is done on company permission because readability is managed by public status of project and assignement.
2167  //if (! $user->rights->societe->client->voir && ! $socid) $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON sc.fk_soc = s.rowid";
2168  $sql .= " WHERE p.fk_statut = 1";
2169  $sql .= " AND p.entity IN (".getEntity('project').')';
2170 
2171 
2172  $projectsListId = null;
2173  if (!$user->hasRight("projet", "all", "lire")) {
2174  $response->url = DOL_URL_ROOT.'/projet/list.php?search_status=1&mainmenu=project';
2175  $projectsListId = $this->getProjectsAuthorizedForUser($user, 0, 1);
2176  if (empty($projectsListId)) {
2177  return $response;
2178  }
2179 
2180  $sql .= " AND p.rowid IN (".$this->db->sanitize($projectsListId).")";
2181  }
2182 
2183  // No need to check company, as filtering of projects must be done by getProjectsAuthorizedForUser
2184  //if ($socid || ! $user->rights->societe->client->voir) $sql.= " AND (p.fk_soc IS NULL OR p.fk_soc = 0 OR p.fk_soc = ".((int) $socid).")";
2185  // For external user, no check is done on company permission because readability is managed by public status of project and assignement.
2186  //if (! $user->rights->societe->client->voir && ! $socid) $sql.= " AND ((s.rowid = sc.fk_soc AND sc.fk_user = ".((int) $user->id).") OR (s.rowid IS NULL))";
2187 
2188  //print $sql;
2189  $resql = $this->db->query($sql);
2190  if ($resql) {
2191  $project_static = new Project($this->db);
2192 
2193 
2194  // This assignment in condition is not a bug. It allows walking the results.
2195  while ($obj = $this->db->fetch_object($resql)) {
2196  $response->nbtodo++;
2197 
2198  $project_static->statut = $obj->status;
2199  $project_static->opp_status = $obj->fk_opp_status;
2200  $project_static->date_end = $this->db->jdate($obj->datee);
2201 
2202  if ($project_static->hasDelay()) {
2203  $response->nbtodolate++;
2204  }
2205  }
2206 
2207  return $response;
2208  }
2209 
2210  $this->error = $this->db->error();
2211  return -1;
2212  }
2213 
2222  public static function replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
2223  {
2224  $tables = array(
2225  'projet'
2226  );
2227 
2228  return CommonObject::commonReplaceThirdparty($dbs, $origin_id, $dest_id, $tables);
2229  }
2230 
2231 
2232  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2238  public function load_state_board()
2239  {
2240  // phpcs:enable
2241  global $user;
2242 
2243  $this->nb = array();
2244 
2245  $sql = "SELECT count(p.rowid) as nb";
2246  $sql .= " FROM ".MAIN_DB_PREFIX."projet as p";
2247  $sql .= " WHERE";
2248  $sql .= " p.entity IN (".getEntity('project').")";
2249  if (empty($user->rights->projet->all->lire)) {
2250  $projectsListId = $this->getProjectsAuthorizedForUser($user, 0, 1);
2251  $sql .= "AND p.rowid IN (".$this->db->sanitize($projectsListId).")";
2252  }
2253 
2254  $resql = $this->db->query($sql);
2255  if ($resql) {
2256  while ($obj = $this->db->fetch_object($resql)) {
2257  $this->nb["projects"] = $obj->nb;
2258  }
2259  $this->db->free($resql);
2260  return 1;
2261  } else {
2262  dol_print_error($this->db);
2263  $this->error = $this->db->error();
2264  return -1;
2265  }
2266  }
2267 
2268 
2274  public function hasDelay()
2275  {
2276  global $conf;
2277 
2278  if (!($this->statut == self::STATUS_VALIDATED)) {
2279  return false;
2280  }
2281  if (!$this->date_end) {
2282  return false;
2283  }
2284 
2285  $now = dol_now();
2286 
2287  return ($this->date_end) < ($now - $conf->project->warning_delay);
2288  }
2289 
2290 
2297  public function info($id)
2298  {
2299  $sql = 'SELECT c.rowid, datec as datec, tms as datem,';
2300  $sql .= ' date_close as datecloture,';
2301  $sql .= ' fk_user_creat as fk_user_author, fk_user_close as fk_use_cloture';
2302  $sql .= ' FROM '.MAIN_DB_PREFIX.'projet as c';
2303  $sql .= ' WHERE c.rowid = '.((int) $id);
2304  $result = $this->db->query($sql);
2305  if ($result) {
2306  if ($this->db->num_rows($result)) {
2307  $obj = $this->db->fetch_object($result);
2308  $this->id = $obj->rowid;
2309  if ($obj->fk_user_author) {
2310  $cuser = new User($this->db);
2311  $cuser->fetch($obj->fk_user_author);
2312  $this->user_creation = $cuser;
2313  }
2314 
2315  if (!empty($obj->fk_user_cloture)) {
2316  $cluser = new User($this->db);
2317  $cluser->fetch($obj->fk_user_cloture);
2318  $this->user_cloture = $cluser;
2319  }
2320 
2321  $this->date_creation = $this->db->jdate($obj->datec);
2322  $this->date_modification = $this->db->jdate($obj->datem);
2323  $this->date_cloture = $this->db->jdate($obj->datecloture);
2324  }
2325 
2326  $this->db->free($result);
2327  } else {
2328  dol_print_error($this->db);
2329  }
2330  }
2331 
2342  public function setCategories($categories)
2343  {
2344  require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
2345  return parent::setCategoriesCommon($categories, Categorie::TYPE_PROJECT);
2346  }
2347 
2348 
2356  public function getLinesArray($user, $loadRoleMode = 1)
2357  {
2358  require_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php';
2359  $taskstatic = new Task($this->db);
2360 
2361  $this->lines = $taskstatic->getTasksArray(0, $user, $this->id, 0, 0, '', '-1', '', 0, 0, array(), 0, array(), 0, $loadRoleMode);
2362  return 1;
2363  }
2364 
2382  public function sendEmail($text, $subject, $filename_list = array(), $mimetype_list = array(), $mimefilename_list = array(), $addr_cc = "", $addr_bcc = "", $deliveryreceipt = 0, $msgishtml = -1, $errors_to = '', $moreinheader = '')
2383  {
2384  global $conf, $langs;
2385  // TODO EMAIL
2386 
2387  return 1;
2388  }
2396  public function getKanbanView($option = '', $arraydata = null)
2397  {
2398  global $langs;
2399 
2400  $selected = (empty($arraydata['selected']) ? 0 : $arraydata['selected']);
2401 
2402  $return = '<div class="box-flex-item box-flex-grow-zero">';
2403  $return .= '<div class="info-box info-box-sm">';
2404  $return .= '<span class="info-box-icon bg-infobox-action">';
2405  $return .= img_picto('', $this->public ? 'projectpub' : $this->picto);
2406  //$return .= '<i class="fa fa-dol-action"></i>'; // Can be image
2407  $return .= '</span>';
2408  $return .= '<div class="info-box-content">';
2409  $return .= '<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">'.(method_exists($this, 'getNomUrl') ? $this->getNomUrl() : $this->ref);
2410  if ($this->hasDelay()) {
2411  $return .= img_warning($langs->trans('Late'));
2412  }
2413  $return .= '</span>';
2414  $return .= '<input id="cb'.$this->id.'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->id.'"'.($selected ? ' checked="checked"' : '').'>';
2415  // Date
2416  /*
2417  if (property_exists($this, 'date_start') && $this->date_start) {
2418  $return .= '<br><span class="info-box-label">'.dol_print_date($this->date_start, 'day').'</>';
2419  }
2420  if (property_exists($this, 'date_end') && $this->date_end) {
2421  if ($this->date_start) {
2422  $return .= ' - ';
2423  } else {
2424  $return .= '<br>';
2425  }
2426  $return .= '<span class="info-box-label">'.dol_print_date($this->date_end, 'day').'</span>';
2427  }*/
2428  if (!empty($arraydata['assignedusers'])) {
2429  $return .= '<br><span class="small">'.$arraydata['assignedusers'].'</span>';
2430  }
2431  /*if (property_exists($this, 'user_author_id')) {
2432  $return .= '<br><span class="info-box-label opacitymedium">'.$langs->trans("Author").'</span>';
2433  $return .= '<span> : '.$user->getNomUrl(1).'</span>';
2434  }*/
2435  if ($this->usage_opportunity && $this->opp_status_code) {
2436  //$return .= '<br><span class="info-bo-label opacitymedium">'.$langs->trans("OpportunityStatusShort").'</span>';
2437  $return .= '<br><span class="info-box-label small">'.$langs->trans("OppStatus".$this->opp_status_code).'</span>';
2438  $return .= ' <span class="opacitymedium small">('.round($this->opp_percent).'%)</span>';
2439  $return .= '<br><span class="amount small">'.price($this->opp_amount).'</span>';
2440  }
2441  if (method_exists($this, 'getLibStatut')) {
2442  $return .= '<br><div class="info-box-status small">'.$this->getLibStatut(3).'</div>';
2443  }
2444  $return .= '</div>';
2445  $return .= '</div>';
2446  $return .= '</div>';
2447  return $return;
2448  }
2449 }
Project\getNomUrl
getNomUrl($withpicto=0, $option='', $addlabel=0, $moreinpopup='', $sep=' - ', $notooltip=0, $save_lastsearch_value=-1, $morecss='')
Return clickable name (with picto eventually)
Definition: project.class.php:1315
Project\createFromClone
createFromClone(User $user, $fromid, $clone_contact=false, $clone_task=true, $clone_project_file=false, $clone_task_file=false, $clone_note=true, $move_date=true, $notrigger=0, $newthirdpartyid=0)
Load an object from its id and create a new one in database.
Definition: project.class.php:1628
Project\loadTimeSpentMonth
loadTimeSpentMonth($datestart, $taskid=0, $userid=0)
Load time spent into this->weekWorkLoad and this->weekWorkLoadPerTask for all day of a week of projec...
Definition: project.class.php:2080
dol_sanitizeFileName
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
Definition: functions.lib.php:1322
description
print *****$script_file(".$version.") pid cd cd cd description as description
Definition: email_expire_services_to_customers.php:83
Project
Class to manage projects.
Definition: project.class.php:36
Project\getProjectsAuthorizedForUser
getProjectsAuthorizedForUser($user, $mode=0, $list=0, $socid=0, $filter='')
Return array of projects a user has permission on, is affected to, or all projects.
Definition: project.class.php:1530
Project\__construct
__construct($db)
Constructor.
Definition: project.class.php:344
Project\getLinesArray
getLinesArray($user, $loadRoleMode=1)
Create an array of tasks of current project.
Definition: project.class.php:2356
Project\$user_author_id
$user_author_id
Id of project creator. Not defined if shared project.
Definition: project.class.php:142
getWeekNumber
getWeekNumber($day, $month, $year)
Return week number.
Definition: date.lib.php:1167
dol_delete_dir_recursive
dol_delete_dir_recursive($dir, $count=0, $nophperrors=0, $onlysub=0, &$countdeleted=0, $indexdatabase=1, $nolog=0)
Remove a directory $dir and its subdirectories (or only files and subdirectories)
Definition: files.lib.php:1483
DoliDB
Class to manage Dolibarr database access.
Definition: DoliDB.class.php:30
Project\hasDelay
hasDelay()
Is the project delayed?
Definition: project.class.php:2274
Project\getElementCount
getElementCount($type, $tablename, $projectkey='fk_projet')
Return the count of a type of linked elements of this project.
Definition: project.class.php:1036
dol_print_error
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
Definition: functions.lib.php:5096
Project\loadTimeSpent
loadTimeSpent($datestart, $taskid=0, $userid=0)
Load time spent into this->weekWorkLoad and this->weekWorkLoadPerTask for all day of a week of projec...
Definition: project.class.php:2016
dol_include_once
if(!function_exists('dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
Definition: functions.lib.php:1128
dol_buildpath
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
Definition: functions.lib.php:1157
Project\getLibStatut
getLibStatut($mode=0)
Return status label of object.
Definition: project.class.php:1226
dol_dir_list
dol_dir_list($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:62
Project\remove_element
remove_element($tableName, $elementSelectId, $projectfield='fk_projet')
Associate element to a project.
Definition: project.class.php:1952
img_warning
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
Definition: functions.lib.php:4773
Task
Class to manage tasks.
Definition: task.class.php:39
Project\LibStatut
LibStatut($status, $mode=0)
Renvoi status label for a status.
Definition: project.class.php:1239
CommonObject
Parent class of all other business classes (invoices, contracts, proposals, orders,...
Definition: commonobject.class.php:45
CommonObject\liste_contact
liste_contact($statusoflink=-1, $source='external', $list=0, $code='', $status=-1, $arrayoftcids=array())
Get array of all contacts for an object.
Definition: commonobject.class.php:1234
Project\$public
$public
Tell if this is a public or private project.
Definition: project.class.php:153
dol_copy
dol_copy($srcfile, $destfile, $newmask=0, $overwriteifexists=1, $testvirus=0, $indexdatabase=0)
Copy a file to another file.
Definition: files.lib.php:716
Project\info
info($id)
Charge les informations d'ordre info dans l'objet commande.
Definition: project.class.php:2297
price2num
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
Definition: functions.lib.php:5943
Project\getTooltipContentArray
getTooltipContentArray($params)
getTooltipContentArray
Definition: project.class.php:1265
dol_print_date
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
Definition: functions.lib.php:2665
WorkboardResponse
Definition: workboardresponse.class.php:24
img_picto
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
Definition: functions.lib.php:4125
CommonObject\commonGenerateDocument
commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams=null)
Common function for all objects extending CommonObject for generating documents.
Definition: commonobject.class.php:5334
Project\update
update($user, $notrigger=0)
Update a project.
Definition: project.class.php:533
Project\load_state_board
load_state_board()
Charge indicateurs this->nb pour le tableau de bord.
Definition: project.class.php:2238
getEntity
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
Definition: functions.lib.php:265
Project\initAsSpecimen
initAsSpecimen()
Initialise an instance with random values.
Definition: project.class.php:1419
CommonObject\insertExtraFields
insertExtraFields($trigger='', $userused=null)
Add/Update all extra fields values for the current object.
Definition: commonobject.class.php:6110
Project\replaceThirdparty
static replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
Function used to replace a thirdparty id with another one.
Definition: project.class.php:2222
$sql
if(isModEnabled('facture') &&!empty($user->rights->facture->lire)) if((isModEnabled('fournisseur') &&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->hasRight("fournisseur", "facture", "lire"))||(isModEnabled('supplier_invoice') && $user->hasRight("supplier_invoice", "lire"))) if(isModEnabled('don') && $user->hasRight('don', 'lire')) if(isModEnabled('tax') &&!empty($user->rights->tax->charges->lire)) if(isModEnabled('facture') &&isModEnabled('commande') && $user->hasRight("commande", "lire") &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $sql
Social contributions to pay.
Definition: index.php:746
CommonObject\delete_linked_contact
delete_linked_contact($source='', $code='')
Delete all links between an object $this and all its contacts in llx_element_contact.
Definition: commonobject.class.php:1189
Project\sendEmail
sendEmail($text, $subject, $filename_list=array(), $mimetype_list=array(), $mimefilename_list=array(), $addr_cc="", $addr_bcc="", $deliveryreceipt=0, $msgishtml=-1, $errors_to='', $moreinheader='')
Function sending an email to the current member with the text supplied in parameter.
Definition: project.class.php:2382
Project\setValid
setValid($user, $notrigger=0)
Validate a project.
Definition: project.class.php:1110
Project\generateDocument
generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0)
Create an intervention document on disk using template defined into PROJECT_ADDON_PDF.
Definition: project.class.php:1985
dol_syslog
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
Definition: functions.lib.php:1732
CommonObject\fetch_optionals
fetch_optionals($rowid=null, $optionsArray=null)
Function to get extra fields of an object into $this->array_options This method is in most cases call...
Definition: commonobject.class.php:5959
dol_substr
dol_substr($string, $start, $length=null, $stringencoding='', $trunconbytes=0)
Make a substring.
Definition: functions.lib.php:4010
dol_strlen
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
Definition: functions.lib.php:3987
Project\get_element_list
get_element_list($type, $tablename, $datefieldname='', $date_start='', $date_end='', $projectkey='fk_projet')
Return list of elements for type, linked to a project.
Definition: project.class.php:769
Project\shiftTaskDate
shiftTaskDate($old_project_dt_start)
Shift project task date from current date to delta.
Definition: project.class.php:1851
Project\create
create($user, $notrigger=0)
Create a project into database.
Definition: project.class.php:388
isModEnabled
isModEnabled($module)
Is Dolibarr module enabled.
Definition: functions.lib.php:207
ref
$object ref
Definition: info.php:78
getDolGlobalString
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
Definition: functions.lib.php:142
Project\deleteTasks
deleteTasks($user)
Delete tasks with no children first, then task with children recursively.
Definition: project.class.php:1077
dol_time_plus_duree
dol_time_plus_duree($time, $duration_value, $duration_unit, $ruleforendofmonth=0)
Add a delay to a date.
Definition: date.lib.php:122
User
Class to manage Dolibarr users.
Definition: user.class.php:47
Project\STATUS_VALIDATED
const STATUS_VALIDATED
Open/Validated status.
Definition: project.class.php:332
dol_html_entity_decode
dol_html_entity_decode($a, $b, $c='UTF-8', $keepsomeentities=0)
Replace html_entity_decode functions to manage errors.
Definition: functions.lib.php:7505
Project\update_element
update_element($tableName, $elementSelectId)
Associate element to a project.
Definition: project.class.php:1916
dolGetStatus
dolGetStatus($statusLabel='', $statusLabelShort='', $html='', $statusType='status0', $displayMode=0, $url='', $params=array())
Output the badge of a status.
Definition: functions.lib.php:10932
img_object
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
Definition: functions.lib.php:4462
Project\setCategories
setCategories($categories)
Sets object to supplied categories.
Definition: project.class.php:2342
dol_now
dol_now($mode='auto')
Return date for now.
Definition: functions.lib.php:3046
Project\STATUS_CLOSED
const STATUS_CLOSED
Closed status.
Definition: project.class.php:337
CommonObject\call_trigger
call_trigger($triggerName, $user)
Call trigger based on this instance.
Definition: commonobject.class.php:5743
Project\$table_ref_field
$table_ref_field
{}
Definition: project.class.php:83
Project\fetch
fetch($id, $ref='', $ref_ext='', $email_msgid='')
Get object from database.
Definition: project.class.php:664
dol_mkdir
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
Definition: functions.lib.php:6924
dol_mktime
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed informations (by default a local PHP server timestamp) Re...
Definition: functions.lib.php:2958
getDolGlobalInt
getDolGlobalInt($key, $default=0)
Return dolibarr global constant int value.
Definition: functions.lib.php:156
Project\STATUS_DRAFT
const STATUS_DRAFT
Draft status.
Definition: project.class.php:327
Project\setClose
setClose($user)
Close a project.
Definition: project.class.php:1170
CommonObject\commonReplaceThirdparty
static commonReplaceThirdparty(DoliDB $dbs, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a thirdparty id with another one.
Definition: commonobject.class.php:8469
Project\getKanbanView
getKanbanView($option='', $arraydata=null)
Return clicable link of object (with eventually picto)
Definition: project.class.php:2396
Project\load_board
load_board($user)
Load indicators for dashboard (this->nbtodo and this->nbtodolate)
Definition: project.class.php:2145
Project\restrictedProjectArea
restrictedProjectArea(User $user, $mode='read')
Check if user has permission on current project.
Definition: project.class.php:1468