Total Complexity | 328 |
Total Lines | 2018 |
Duplicated Lines | 0 % |
Changes | 0 |
Complex classes like Project often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Project, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
33 | class Project extends CommonObject |
||
34 | { |
||
35 | |||
36 | /** |
||
37 | * @var string ID to identify managed object |
||
38 | */ |
||
39 | public $element = 'project'; |
||
40 | |||
41 | /** |
||
42 | * @var string Name of table without prefix where object is stored |
||
43 | */ |
||
44 | public $table_element = 'projet'; |
||
45 | |||
46 | /** |
||
47 | * @var int Name of subtable line |
||
48 | */ |
||
49 | public $table_element_line = 'projet_task'; |
||
50 | |||
51 | /** |
||
52 | * @var int Field with ID of parent key if this field has a parent |
||
53 | */ |
||
54 | public $fk_element = 'fk_projet'; |
||
55 | |||
56 | /** |
||
57 | * 0=No test on entity, 1=Test with field entity, 2=Test with link by societe |
||
58 | * @var int |
||
59 | */ |
||
60 | public $ismultientitymanaged = 1; |
||
61 | |||
62 | public $picto = 'projectpub'; |
||
63 | |||
64 | /** |
||
65 | * {@inheritdoc} |
||
66 | */ |
||
67 | protected $table_ref_field = 'ref'; |
||
68 | |||
69 | /** |
||
70 | * @var string description |
||
71 | */ |
||
72 | public $description; |
||
73 | |||
74 | /** |
||
75 | * @var string |
||
76 | * @deprecated |
||
77 | * @see title |
||
78 | */ |
||
79 | public $titre; |
||
80 | |||
81 | public $title; |
||
82 | public $date_start; |
||
83 | public $date_end; |
||
84 | public $date_close; |
||
85 | |||
86 | public $socid; // To store id of thirdparty |
||
87 | public $thirdparty_name; // To store name of thirdparty (defined only in some cases) |
||
88 | |||
89 | public $user_author_id; //!< Id of project creator. Not defined if shared project. |
||
90 | public $user_close_id; |
||
91 | public $public; //!< Tell if this is a public or private project |
||
92 | public $budget_amount; |
||
93 | public $bill_time; // Is the time spent on project must be invoiced or not |
||
94 | |||
95 | public $statuts_short; |
||
96 | public $statuts_long; |
||
97 | |||
98 | public $statut; // 0=draft, 1=opened, 2=closed |
||
99 | public $opp_status; // opportunity status, into table llx_c_lead_status |
||
100 | public $opp_percent; // opportunity probability |
||
101 | |||
102 | public $oldcopy; |
||
103 | |||
104 | public $weekWorkLoad; // Used to store workload details of a projet |
||
105 | public $weekWorkLoadPerTask; // Used to store workload details of tasks of a projet |
||
106 | |||
107 | /** |
||
108 | * @var int Creation date |
||
109 | * @deprecated |
||
110 | * @see date_c |
||
111 | */ |
||
112 | public $datec; |
||
113 | |||
114 | /** |
||
115 | * @var int Creation date |
||
116 | */ |
||
117 | public $date_c; |
||
118 | |||
119 | /** |
||
120 | * @var int Modification date |
||
121 | * @deprecated |
||
122 | * @see date_m |
||
123 | */ |
||
124 | public $datem; |
||
125 | |||
126 | /** |
||
127 | * @var int Modification date |
||
128 | */ |
||
129 | public $date_m; |
||
130 | |||
131 | /** |
||
132 | * @var Task[] |
||
133 | */ |
||
134 | public $lines; |
||
135 | |||
136 | /** |
||
137 | * Draft status |
||
138 | */ |
||
139 | const STATUS_DRAFT = 0; |
||
140 | |||
141 | /** |
||
142 | * Open/Validated status |
||
143 | */ |
||
144 | const STATUS_VALIDATED = 1; |
||
145 | |||
146 | /** |
||
147 | * Closed status |
||
148 | */ |
||
149 | const STATUS_CLOSED = 2; |
||
150 | |||
151 | |||
152 | |||
153 | /** |
||
154 | * Constructor |
||
155 | * |
||
156 | * @param DoliDB $db Database handler |
||
157 | */ |
||
158 | function __construct($db) |
||
159 | { |
||
160 | $this->db = $db; |
||
161 | |||
162 | $this->statuts_short = array(0 => 'Draft', 1 => 'Opened', 2 => 'Closed'); |
||
163 | $this->statuts_long = array(0 => 'Draft', 1 => 'Opened', 2 => 'Closed'); |
||
164 | } |
||
165 | |||
166 | /** |
||
167 | * Create a project into database |
||
168 | * |
||
169 | * @param User $user User making creation |
||
170 | * @param int $notrigger Disable triggers |
||
171 | * @return int <0 if KO, id of created project if OK |
||
172 | */ |
||
173 | function create($user, $notrigger=0) |
||
174 | { |
||
175 | global $conf, $langs; |
||
176 | |||
177 | $error = 0; |
||
178 | $ret = 0; |
||
179 | |||
180 | $now=dol_now(); |
||
181 | |||
182 | // Clean parameters |
||
183 | $this->note_private = dol_substr($this->note_private, 0, 65535); |
||
184 | $this->note_public = dol_substr($this->note_public, 0, 65535); |
||
185 | |||
186 | // Check parameters |
||
187 | if (!trim($this->ref)) |
||
188 | { |
||
189 | $this->error = 'ErrorFieldsRequired'; |
||
190 | dol_syslog(get_class($this)."::create error -1 ref null", LOG_ERR); |
||
191 | return -1; |
||
192 | } |
||
193 | if (! empty($conf->global->PROJECT_THIRDPARTY_REQUIRED) && ! $this->socid > 0) |
||
194 | { |
||
195 | $this->error = 'ErrorFieldsRequired'; |
||
196 | dol_syslog(get_class($this)."::create error -1 ref null", LOG_ERR); |
||
197 | return -1; |
||
198 | } |
||
199 | |||
200 | // Create project |
||
201 | $this->db->begin(); |
||
202 | |||
203 | $sql = "INSERT INTO " . MAIN_DB_PREFIX . "projet ("; |
||
204 | $sql.= "ref"; |
||
205 | $sql.= ", title"; |
||
206 | $sql.= ", description"; |
||
207 | $sql.= ", fk_soc"; |
||
208 | $sql.= ", fk_user_creat"; |
||
209 | $sql.= ", fk_statut"; |
||
210 | $sql.= ", fk_opp_status"; |
||
211 | $sql.= ", opp_percent"; |
||
212 | $sql.= ", public"; |
||
213 | $sql.= ", datec"; |
||
214 | $sql.= ", dateo"; |
||
215 | $sql.= ", datee"; |
||
216 | $sql.= ", opp_amount"; |
||
217 | $sql.= ", budget_amount"; |
||
218 | $sql.= ", bill_time"; |
||
219 | $sql.= ", note_private"; |
||
220 | $sql.= ", note_public"; |
||
221 | $sql.= ", entity"; |
||
222 | $sql.= ") VALUES ("; |
||
223 | $sql.= "'" . $this->db->escape($this->ref) . "'"; |
||
224 | $sql.= ", '" . $this->db->escape($this->title) . "'"; |
||
225 | $sql.= ", '" . $this->db->escape($this->description) . "'"; |
||
226 | $sql.= ", " . ($this->socid > 0 ? $this->socid : "null"); |
||
227 | $sql.= ", " . $user->id; |
||
228 | $sql.= ", ".(is_numeric($this->statut) ? $this->statut : '0'); |
||
229 | $sql.= ", ".(is_numeric($this->opp_status) ? $this->opp_status : 'NULL'); |
||
230 | $sql.= ", ".(is_numeric($this->opp_percent) ? $this->opp_percent : 'NULL'); |
||
231 | $sql.= ", " . ($this->public ? 1 : 0); |
||
232 | $sql.= ", '".$this->db->idate($now)."'"; |
||
233 | $sql.= ", " . ($this->date_start != '' ? "'".$this->db->idate($this->date_start)."'" : 'null'); |
||
234 | $sql.= ", " . ($this->date_end != '' ? "'".$this->db->idate($this->date_end)."'" : 'null'); |
||
235 | $sql.= ", " . (strcmp($this->opp_amount,'') ? price2num($this->opp_amount) : 'null'); |
||
236 | $sql.= ", " . (strcmp($this->budget_amount,'') ? price2num($this->budget_amount) : 'null'); |
||
237 | $sql.= ", " . ($this->bill_time ? 1 : 0); |
||
238 | $sql.= ", ".($this->note_private ? "'".$this->db->escape($this->note_private)."'" : 'null'); |
||
239 | $sql.= ", ".($this->note_public ? "'".$this->db->escape($this->note_public)."'" : 'null'); |
||
240 | $sql.= ", ".$conf->entity; |
||
241 | $sql.= ")"; |
||
242 | |||
243 | dol_syslog(get_class($this)."::create", LOG_DEBUG); |
||
244 | $resql = $this->db->query($sql); |
||
245 | if ($resql) |
||
246 | { |
||
247 | $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX . "projet"); |
||
248 | $ret = $this->id; |
||
249 | |||
250 | if (!$notrigger) |
||
251 | { |
||
252 | // Call trigger |
||
253 | $result=$this->call_trigger('PROJECT_CREATE',$user); |
||
254 | if ($result < 0) { $error++; } |
||
255 | // End call triggers |
||
256 | } |
||
257 | } |
||
258 | else |
||
259 | { |
||
260 | $this->error = $this->db->lasterror(); |
||
261 | $this->errno = $this->db->lasterrno(); |
||
262 | $error++; |
||
263 | } |
||
264 | |||
265 | // Update extrafield |
||
266 | if (! $error) { |
||
267 | if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used |
||
268 | { |
||
269 | $result=$this->insertExtraFields(); |
||
270 | if ($result < 0) |
||
271 | { |
||
272 | $error++; |
||
273 | } |
||
274 | } |
||
275 | } |
||
276 | |||
277 | if (! $error && !empty($conf->global->MAIN_DISABLEDRAFTSTATUS)) |
||
278 | { |
||
279 | $res = $this->setValid($user); |
||
280 | if ($res < 0) $error++; |
||
281 | } |
||
282 | |||
283 | if (! $error) |
||
284 | { |
||
285 | $this->db->commit(); |
||
286 | return $ret; |
||
287 | } |
||
288 | else |
||
289 | { |
||
290 | $this->db->rollback(); |
||
291 | return -1; |
||
292 | } |
||
293 | } |
||
294 | |||
295 | /** |
||
296 | * Update a project |
||
297 | * |
||
298 | * @param User $user User object of making update |
||
299 | * @param int $notrigger 1=Disable all triggers |
||
300 | * @return int <=0 if KO, >0 if OK |
||
301 | */ |
||
302 | function update($user, $notrigger=0) |
||
303 | { |
||
304 | global $langs, $conf; |
||
305 | |||
306 | $error=0; |
||
307 | |||
308 | // Clean parameters |
||
309 | $this->title = trim($this->title); |
||
310 | $this->description = trim($this->description); |
||
311 | if ($this->opp_amount < 0) $this->opp_amount=''; |
||
312 | if ($this->opp_percent < 0) $this->opp_percent=''; |
||
313 | if ($this->date_end && $this->date_end < $this->date_start) |
||
314 | { |
||
315 | $this->error = $langs->trans("ErrorDateEndLowerThanDateStart"); |
||
316 | $this->errors[] = $this->error; |
||
317 | $this->db->rollback(); |
||
318 | dol_syslog(get_class($this)."::update error -3 " . $this->error, LOG_ERR); |
||
319 | return -3; |
||
320 | } |
||
321 | |||
322 | if (dol_strlen(trim($this->ref)) > 0) |
||
323 | { |
||
324 | $this->db->begin(); |
||
325 | |||
326 | $sql = "UPDATE " . MAIN_DB_PREFIX . "projet SET"; |
||
327 | $sql.= " ref='" . $this->db->escape($this->ref) . "'"; |
||
328 | $sql.= ", title = '" . $this->db->escape($this->title) . "'"; |
||
329 | $sql.= ", description = '" . $this->db->escape($this->description) . "'"; |
||
330 | $sql.= ", fk_soc = " . ($this->socid > 0 ? $this->socid : "null"); |
||
331 | $sql.= ", fk_statut = " . $this->statut; |
||
332 | $sql.= ", fk_opp_status = " . ((is_numeric($this->opp_status) && $this->opp_status > 0) ? $this->opp_status : 'null'); |
||
333 | $sql.= ", opp_percent = " . ((is_numeric($this->opp_percent) && $this->opp_percent != '') ? $this->opp_percent : 'null'); |
||
334 | $sql.= ", public = " . ($this->public ? 1 : 0); |
||
335 | $sql.= ", datec=" . ($this->date_c != '' ? "'".$this->db->idate($this->date_c)."'" : 'null'); |
||
336 | $sql.= ", dateo=" . ($this->date_start != '' ? "'".$this->db->idate($this->date_start)."'" : 'null'); |
||
337 | $sql.= ", datee=" . ($this->date_end != '' ? "'".$this->db->idate($this->date_end)."'" : 'null'); |
||
338 | $sql.= ", date_close=" . ($this->date_close != '' ? "'".$this->db->idate($this->date_close)."'" : 'null'); |
||
339 | $sql.= ", fk_user_close=" . ($this->fk_user_close > 0 ? $this->fk_user_close : "null"); |
||
|
|||
340 | $sql.= ", opp_amount = " . (strcmp($this->opp_amount, '') ? price2num($this->opp_amount) : "null"); |
||
341 | $sql.= ", budget_amount = " . (strcmp($this->budget_amount, '') ? price2num($this->budget_amount) : "null"); |
||
342 | $sql.= ", fk_user_modif = " . $user->id; |
||
343 | $sql.= ", bill_time = " . ($this->bill_time ? 1 : 0); |
||
344 | $sql.= " WHERE rowid = " . $this->id; |
||
345 | |||
346 | dol_syslog(get_class($this)."::update", LOG_DEBUG); |
||
347 | $resql=$this->db->query($sql); |
||
348 | if ($resql) |
||
349 | { |
||
350 | // Update extrafield |
||
351 | if (! $error) |
||
352 | { |
||
353 | if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used |
||
354 | { |
||
355 | $result=$this->insertExtraFields(); |
||
356 | if ($result < 0) |
||
357 | { |
||
358 | $error++; |
||
359 | } |
||
360 | } |
||
361 | } |
||
362 | |||
363 | if (! $error && ! $notrigger) |
||
364 | { |
||
365 | // Call trigger |
||
366 | $result=$this->call_trigger('PROJECT_MODIFY',$user); |
||
367 | if ($result < 0) { $error++; } |
||
368 | // End call triggers |
||
369 | } |
||
370 | |||
371 | if (! $error && (is_object($this->oldcopy) && $this->oldcopy->ref !== $this->ref)) |
||
372 | { |
||
373 | // We remove directory |
||
374 | if ($conf->projet->dir_output) |
||
375 | { |
||
376 | $olddir = $conf->projet->dir_output . "/" . dol_sanitizeFileName($this->oldcopy->ref); |
||
377 | $newdir = $conf->projet->dir_output . "/" . dol_sanitizeFileName($this->ref); |
||
378 | if (file_exists($olddir)) |
||
379 | { |
||
380 | include_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php'; |
||
381 | $res=dol_move($olddir, $newdir); |
||
382 | if (! $res) |
||
383 | { |
||
384 | $langs->load("errors"); |
||
385 | $this->error=$langs->trans('ErrorFailToRenameDir',$olddir,$newdir); |
||
386 | $error++; |
||
387 | } |
||
388 | } |
||
389 | } |
||
390 | } |
||
391 | if (! $error ) |
||
392 | { |
||
393 | $this->db->commit(); |
||
394 | $result = 1; |
||
395 | } |
||
396 | else |
||
397 | { |
||
398 | $this->db->rollback(); |
||
399 | $result = -1; |
||
400 | } |
||
401 | } |
||
402 | else |
||
403 | { |
||
404 | $this->error = $this->db->lasterror(); |
||
405 | $this->errors[] = $this->error; |
||
406 | $this->db->rollback(); |
||
407 | if ($this->db->lasterrno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') |
||
408 | { |
||
409 | $result = -4; |
||
410 | } |
||
411 | else |
||
412 | { |
||
413 | $result = -2; |
||
414 | } |
||
415 | dol_syslog(get_class($this)."::update error " . $result . " " . $this->error, LOG_ERR); |
||
416 | } |
||
417 | } |
||
418 | else |
||
419 | { |
||
420 | dol_syslog(get_class($this)."::update ref null"); |
||
421 | $result = -1; |
||
422 | } |
||
423 | |||
424 | return $result; |
||
425 | } |
||
426 | |||
427 | /** |
||
428 | * Get object from database |
||
429 | * |
||
430 | * @param int $id Id of object to load |
||
431 | * @param string $ref Ref of project |
||
432 | * @return int >0 if OK, 0 if not found, <0 if KO |
||
433 | */ |
||
434 | function fetch($id, $ref='') |
||
435 | { |
||
436 | global $conf; |
||
437 | |||
438 | if (empty($id) && empty($ref)) return -1; |
||
439 | |||
440 | $sql = "SELECT rowid, ref, title, description, public, datec, opp_amount, budget_amount,"; |
||
441 | $sql.= " tms, dateo, datee, date_close, fk_soc, fk_user_creat, fk_user_modif, fk_user_close, fk_statut, fk_opp_status, opp_percent,"; |
||
442 | $sql.= " note_private, note_public, model_pdf, bill_time"; |
||
443 | $sql.= " FROM " . MAIN_DB_PREFIX . "projet"; |
||
444 | if (! empty($id)) |
||
445 | { |
||
446 | $sql.= " WHERE rowid=".$id; |
||
447 | } |
||
448 | else if (! empty($ref)) |
||
449 | { |
||
450 | $sql.= " WHERE ref='".$this->db->escape($ref)."'"; |
||
451 | $sql.= " AND entity IN (".getEntity('project').")"; |
||
452 | } |
||
453 | |||
454 | dol_syslog(get_class($this)."::fetch", LOG_DEBUG); |
||
455 | $resql = $this->db->query($sql); |
||
456 | if ($resql) |
||
457 | { |
||
458 | $num_rows = $this->db->num_rows($resql); |
||
459 | |||
460 | if ($num_rows) |
||
461 | { |
||
462 | $obj = $this->db->fetch_object($resql); |
||
463 | |||
464 | $this->id = $obj->rowid; |
||
465 | $this->ref = $obj->ref; |
||
466 | $this->title = $obj->title; |
||
467 | $this->titre = $obj->title; // TODO deprecated |
||
468 | $this->description = $obj->description; |
||
469 | $this->date_c = $this->db->jdate($obj->datec); |
||
470 | $this->datec = $this->db->jdate($obj->datec); // TODO deprecated |
||
471 | $this->date_m = $this->db->jdate($obj->tms); |
||
472 | $this->datem = $this->db->jdate($obj->tms); // TODO deprecated |
||
473 | $this->date_start = $this->db->jdate($obj->dateo); |
||
474 | $this->date_end = $this->db->jdate($obj->datee); |
||
475 | $this->date_close = $this->db->jdate($obj->date_close); |
||
476 | $this->note_private = $obj->note_private; |
||
477 | $this->note_public = $obj->note_public; |
||
478 | $this->socid = $obj->fk_soc; |
||
479 | $this->user_author_id = $obj->fk_user_creat; |
||
480 | $this->user_modification_id = $obj->fk_user_modif; |
||
481 | $this->user_close_id = $obj->fk_user_close; |
||
482 | $this->public = $obj->public; |
||
483 | $this->statut = $obj->fk_statut; |
||
484 | $this->opp_status = $obj->fk_opp_status; |
||
485 | $this->opp_amount = $obj->opp_amount; |
||
486 | $this->opp_percent = $obj->opp_percent; |
||
487 | $this->budget_amount = $obj->budget_amount; |
||
488 | $this->modelpdf = $obj->model_pdf; |
||
489 | $this->bill_time = (int) $obj->bill_time; |
||
490 | |||
491 | $this->db->free($resql); |
||
492 | |||
493 | // Retreive all extrafield |
||
494 | // fetch optionals attributes and labels |
||
495 | $this->fetch_optionals(); |
||
496 | |||
497 | return 1; |
||
498 | } |
||
499 | |||
500 | $this->db->free($resql); |
||
501 | |||
502 | return 0; |
||
503 | } |
||
504 | else |
||
505 | { |
||
506 | $this->error = $this->db->lasterror(); |
||
507 | return -1; |
||
508 | } |
||
509 | } |
||
510 | |||
511 | // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps |
||
512 | /** |
||
513 | * Return list of projects |
||
514 | * |
||
515 | * @param int $socid To filter on a particular third party |
||
516 | * @return array List of projects |
||
517 | */ |
||
518 | function liste_array($socid='') |
||
519 | { |
||
520 | // phpcs:enable |
||
521 | global $conf; |
||
522 | |||
523 | $projects = array(); |
||
524 | |||
525 | $sql = "SELECT rowid, title"; |
||
526 | $sql.= " FROM " . MAIN_DB_PREFIX . "projet"; |
||
527 | $sql.= " WHERE entity = " . $conf->entity; |
||
528 | if (! empty($socid)) $sql.= " AND fk_soc = " . $socid; |
||
529 | |||
530 | $resql = $this->db->query($sql); |
||
531 | if ($resql) |
||
532 | { |
||
533 | $nump = $this->db->num_rows($resql); |
||
534 | |||
535 | if ($nump) |
||
536 | { |
||
537 | $i = 0; |
||
538 | while ($i < $nump) |
||
539 | { |
||
540 | $obj = $this->db->fetch_object($resql); |
||
541 | |||
542 | $projects[$obj->rowid] = $obj->title; |
||
543 | $i++; |
||
544 | } |
||
545 | } |
||
546 | return $projects; |
||
547 | } |
||
548 | else |
||
549 | { |
||
550 | print $this->db->lasterror(); |
||
551 | } |
||
552 | } |
||
553 | |||
554 | // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps |
||
555 | /** |
||
556 | * Return list of elements for type, linked to a project |
||
557 | * |
||
558 | * @param string $type 'propal','order','invoice','order_supplier','invoice_supplier',... |
||
559 | * @param string $tablename name of table associated of the type |
||
560 | * @param string $datefieldname name of date field for filter |
||
561 | * @param int $dates Start date |
||
562 | * @param int $datee End date |
||
563 | * @param string $projectkey Equivalent key to fk_projet for actual type |
||
564 | * @return mixed Array list of object ids linked to project, < 0 or string if error |
||
565 | */ |
||
566 | function get_element_list($type, $tablename, $datefieldname='', $dates='', $datee='', $projectkey='fk_projet') |
||
567 | { |
||
568 | // phpcs:enable |
||
569 | $elements = array(); |
||
570 | |||
571 | if ($this->id <= 0) return $elements; |
||
572 | |||
573 | $ids = $this->id; |
||
574 | |||
575 | if ($type == 'agenda') |
||
576 | { |
||
577 | $sql = "SELECT id as rowid FROM " . MAIN_DB_PREFIX . "actioncomm WHERE fk_project IN (". $ids .") AND entity IN (".getEntity('agenda').")"; |
||
578 | } |
||
579 | elseif ($type == 'expensereport') |
||
580 | { |
||
581 | $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 (". $ids .")"; |
||
582 | } |
||
583 | elseif ($type == 'project_task') |
||
584 | { |
||
585 | $sql = "SELECT DISTINCT pt.rowid FROM " . MAIN_DB_PREFIX . "projet_task as pt, " . MAIN_DB_PREFIX . "projet_task_time as ptt WHERE pt.rowid = ptt.fk_task AND pt.fk_projet IN (". $ids .")"; |
||
586 | } |
||
587 | elseif ($type == 'project_task_time') // Case we want to duplicate line foreach user |
||
588 | { |
||
589 | $sql = "SELECT DISTINCT pt.rowid, ptt.fk_user FROM " . MAIN_DB_PREFIX . "projet_task as pt, " . MAIN_DB_PREFIX . "projet_task_time as ptt WHERE pt.rowid = ptt.fk_task AND pt.fk_projet IN (". $ids .")"; |
||
590 | } |
||
591 | elseif ($type == 'stock_mouvement') |
||
592 | { |
||
593 | $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 (". $ids .") AND ms.type_mouvement = 1"; |
||
594 | } |
||
595 | else |
||
596 | { |
||
597 | $sql = "SELECT rowid FROM " . MAIN_DB_PREFIX . $tablename." WHERE ".$projectkey." IN (". $ids .") AND entity IN (".getEntity($type).")"; |
||
598 | } |
||
599 | |||
600 | if ($dates > 0) |
||
601 | { |
||
602 | if (empty($datefieldname) && ! empty($this->table_element_date)) $datefieldname=$this->table_element_date; |
||
603 | if (empty($datefieldname)) return 'Error this object has no date field defined'; |
||
604 | $sql.=" AND (".$datefieldname." >= '".$this->db->idate($dates)."' OR ".$datefieldname." IS NULL)"; |
||
605 | } |
||
606 | if ($datee > 0) |
||
607 | { |
||
608 | if (empty($datefieldname) && ! empty($this->table_element_date)) $datefieldname=$this->table_element_date; |
||
609 | if (empty($datefieldname)) return 'Error this object has no date field defined'; |
||
610 | $sql.=" AND (".$datefieldname." <= '".$this->db->idate($datee)."' OR ".$datefieldname." IS NULL)"; |
||
611 | } |
||
612 | if (! $sql) return -1; |
||
613 | |||
614 | //print $sql; |
||
615 | dol_syslog(get_class($this)."::get_element_list", LOG_DEBUG); |
||
616 | $result = $this->db->query($sql); |
||
617 | if ($result) |
||
618 | { |
||
619 | $nump = $this->db->num_rows($result); |
||
620 | if ($nump) |
||
621 | { |
||
622 | $i = 0; |
||
623 | while ($i < $nump) |
||
624 | { |
||
625 | $obj = $this->db->fetch_object($result); |
||
626 | |||
627 | $elements[$i] = $obj->rowid.(empty($obj->fk_user)?'':'_'.$obj->fk_user); |
||
628 | |||
629 | $i++; |
||
630 | } |
||
631 | $this->db->free($result); |
||
632 | } |
||
633 | |||
634 | /* Return array even if empty*/ |
||
635 | return $elements; |
||
636 | } |
||
637 | else |
||
638 | { |
||
639 | dol_print_error($this->db); |
||
640 | } |
||
641 | } |
||
642 | |||
643 | /** |
||
644 | * Delete a project from database |
||
645 | * |
||
646 | * @param User $user User |
||
647 | * @param int $notrigger Disable triggers |
||
648 | * @return int <0 if KO, 0 if not possible, >0 if OK |
||
649 | */ |
||
650 | function delete($user, $notrigger=0) |
||
651 | { |
||
652 | global $langs, $conf; |
||
653 | require_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php'; |
||
654 | |||
655 | $error = 0; |
||
656 | |||
657 | $this->db->begin(); |
||
658 | |||
659 | if (!$error) |
||
660 | { |
||
661 | // Delete linked contacts |
||
662 | $res = $this->delete_linked_contact(); |
||
663 | if ($res < 0) |
||
664 | { |
||
665 | $this->error = 'ErrorFailToDeleteLinkedContact'; |
||
666 | //$error++; |
||
667 | $this->db->rollback(); |
||
668 | return 0; |
||
669 | } |
||
670 | } |
||
671 | |||
672 | // Set fk_projet into elements to null |
||
673 | $listoftables=array( |
||
674 | 'propal'=>'fk_projet', 'commande'=>'fk_projet', 'facture'=>'fk_projet', |
||
675 | 'supplier_proposal'=>'fk_projet', 'commande_fournisseur'=>'fk_projet', 'facture_fourn'=>'fk_projet', |
||
676 | 'expensereport_det'=>'fk_projet', 'contrat'=>'fk_projet', 'fichinter'=>'fk_projet', 'don'=>'fk_projet', |
||
677 | 'actioncomm'=>'fk_project' |
||
678 | ); |
||
679 | foreach($listoftables as $key => $value) |
||
680 | { |
||
681 | $sql = "UPDATE " . MAIN_DB_PREFIX . $key . " SET ".$value." = NULL where ".$value." = ". $this->id; |
||
682 | $resql = $this->db->query($sql); |
||
683 | if (!$resql) |
||
684 | { |
||
685 | $this->errors[] = $this->db->lasterror(); |
||
686 | $error++; |
||
687 | break; |
||
688 | } |
||
689 | } |
||
690 | |||
691 | // Fetch tasks |
||
692 | $this->getLinesArray($user); |
||
693 | |||
694 | // Delete tasks |
||
695 | $ret = $this->deleteTasks($user); |
||
696 | if ($ret < 0) $error++; |
||
697 | |||
698 | // Delete project |
||
699 | if (! $error) |
||
700 | { |
||
701 | $sql = "DELETE FROM " . MAIN_DB_PREFIX . "projet"; |
||
702 | $sql.= " WHERE rowid=" . $this->id; |
||
703 | |||
704 | $resql = $this->db->query($sql); |
||
705 | if (!$resql) |
||
706 | { |
||
707 | $this->errors[] = $langs->trans("CantRemoveProject"); |
||
708 | $error++; |
||
709 | } |
||
710 | } |
||
711 | |||
712 | if (! $error) |
||
713 | { |
||
714 | $sql = "DELETE FROM " . MAIN_DB_PREFIX . "projet_extrafields"; |
||
715 | $sql.= " WHERE fk_object=" . $this->id; |
||
716 | |||
717 | $resql = $this->db->query($sql); |
||
718 | if (! $resql) |
||
719 | { |
||
720 | $this->errors[] = $this->db->lasterror(); |
||
721 | $error++; |
||
722 | } |
||
723 | } |
||
724 | |||
725 | if (empty($error)) |
||
726 | { |
||
727 | // We remove directory |
||
728 | $projectref = dol_sanitizeFileName($this->ref); |
||
729 | if ($conf->projet->dir_output) |
||
730 | { |
||
731 | $dir = $conf->projet->dir_output . "/" . $projectref; |
||
732 | if (file_exists($dir)) |
||
733 | { |
||
734 | $res = @dol_delete_dir_recursive($dir); |
||
735 | if (!$res) |
||
736 | { |
||
737 | $this->errors[] = 'ErrorFailToDeleteDir'; |
||
738 | $error++; |
||
739 | } |
||
740 | } |
||
741 | } |
||
742 | |||
743 | if (!$notrigger) |
||
744 | { |
||
745 | // Call trigger |
||
746 | $result=$this->call_trigger('PROJECT_DELETE',$user); |
||
747 | |||
748 | if ($result < 0) { |
||
749 | $error++; |
||
750 | } |
||
751 | // End call triggers |
||
752 | } |
||
753 | } |
||
754 | |||
755 | if (empty($error)) |
||
756 | { |
||
757 | $this->db->commit(); |
||
758 | return 1; |
||
759 | } |
||
760 | else |
||
761 | { |
||
762 | foreach ( $this->errors as $errmsg ) |
||
763 | { |
||
764 | dol_syslog(get_class($this) . "::delete " . $errmsg, LOG_ERR); |
||
765 | $this->error .= ($this->error ? ', ' . $errmsg : $errmsg); |
||
766 | } |
||
767 | dol_syslog(get_class($this) . "::delete " . $this->error, LOG_ERR); |
||
768 | $this->db->rollback(); |
||
769 | return -1; |
||
770 | } |
||
771 | } |
||
772 | |||
773 | /** |
||
774 | * Delete tasks with no children first, then task with children recursively |
||
775 | * |
||
776 | * @param User $user User |
||
777 | * @return int <0 if KO, 1 if OK |
||
778 | */ |
||
779 | function deleteTasks($user) |
||
780 | { |
||
781 | $countTasks = count($this->lines); |
||
782 | $deleted = false; |
||
783 | if ($countTasks) |
||
784 | { |
||
785 | foreach($this->lines as $task) |
||
786 | { |
||
787 | if ($task->hasChildren() <= 0) { // If there is no children (or error to detect them) |
||
788 | $deleted = true; |
||
789 | $ret = $task->delete($user); |
||
790 | if ($ret <= 0) |
||
791 | { |
||
792 | $this->errors[] = $this->db->lasterror(); |
||
793 | return -1; |
||
794 | } |
||
795 | } |
||
796 | } |
||
797 | } |
||
798 | $this->getLinesArray($user); |
||
799 | if ($deleted && count($this->lines) < $countTasks) |
||
800 | { |
||
801 | if (count($this->lines)) $this->deleteTasks($this->lines); |
||
802 | } |
||
803 | |||
804 | return 1; |
||
805 | } |
||
806 | |||
807 | /** |
||
808 | * Validate a project |
||
809 | * |
||
810 | * @param User $user User that validate |
||
811 | * @param int $notrigger 1=Disable triggers |
||
812 | * @return int <0 if KO, >0 if OK |
||
813 | */ |
||
814 | function setValid($user, $notrigger=0) |
||
815 | { |
||
816 | global $langs, $conf; |
||
817 | |||
818 | $error=0; |
||
819 | |||
820 | if ($this->statut != 1) |
||
821 | { |
||
822 | // Check parameters |
||
823 | if (preg_match('/^'.preg_quote($langs->trans("CopyOf").' ').'/', $this->title)) |
||
824 | { |
||
825 | $this->error=$langs->trans("ErrorFieldFormat",$langs->transnoentities("Label")).'. '.$langs->trans('RemoveString',$langs->transnoentitiesnoconv("CopyOf")); |
||
826 | return -1; |
||
827 | } |
||
828 | |||
829 | $this->db->begin(); |
||
830 | |||
831 | $sql = "UPDATE " . MAIN_DB_PREFIX . "projet"; |
||
832 | $sql.= " SET fk_statut = 1"; |
||
833 | $sql.= " WHERE rowid = " . $this->id; |
||
834 | $sql.= " AND entity = " . $conf->entity; |
||
835 | |||
836 | dol_syslog(get_class($this)."::setValid", LOG_DEBUG); |
||
837 | $resql = $this->db->query($sql); |
||
838 | if ($resql) |
||
839 | { |
||
840 | // Call trigger |
||
841 | if (empty($notrigger)) |
||
842 | { |
||
843 | $result=$this->call_trigger('PROJECT_VALIDATE',$user); |
||
844 | if ($result < 0) { $error++; } |
||
845 | // End call triggers |
||
846 | } |
||
847 | |||
848 | if (!$error) |
||
849 | { |
||
850 | $this->statut=1; |
||
851 | $this->db->commit(); |
||
852 | return 1; |
||
853 | } |
||
854 | else |
||
855 | { |
||
856 | $this->db->rollback(); |
||
857 | $this->error = join(',', $this->errors); |
||
858 | dol_syslog(get_class($this)."::setValid " . $this->error, LOG_ERR); |
||
859 | return -1; |
||
860 | } |
||
861 | } |
||
862 | else |
||
863 | { |
||
864 | $this->db->rollback(); |
||
865 | $this->error = $this->db->lasterror(); |
||
866 | return -1; |
||
867 | } |
||
868 | } |
||
869 | } |
||
870 | |||
871 | /** |
||
872 | * Close a project |
||
873 | * |
||
874 | * @param User $user User that close project |
||
875 | * @return int <0 if KO, 0 if already closed, >0 if OK |
||
876 | */ |
||
877 | function setClose($user) |
||
878 | { |
||
879 | global $langs, $conf; |
||
880 | |||
881 | $now = dol_now(); |
||
882 | |||
883 | $error=0; |
||
884 | |||
885 | if ($this->statut != 2) |
||
886 | { |
||
887 | $this->db->begin(); |
||
888 | |||
889 | $sql = "UPDATE " . MAIN_DB_PREFIX . "projet"; |
||
890 | $sql.= " SET fk_statut = 2, fk_user_close = ".$user->id.", date_close = '".$this->db->idate($now)."'"; |
||
891 | $sql.= " WHERE rowid = " . $this->id; |
||
892 | $sql.= " AND entity = " . $conf->entity; |
||
893 | $sql.= " AND fk_statut = 1"; |
||
894 | |||
895 | if (! empty($conf->global->PROJECT_USE_OPPORTUNITIES)) |
||
896 | { |
||
897 | // TODO What to do if fk_opp_status is not code 'WON' or 'LOST' |
||
898 | } |
||
899 | |||
900 | dol_syslog(get_class($this)."::setClose", LOG_DEBUG); |
||
901 | $resql = $this->db->query($sql); |
||
902 | if ($resql) |
||
903 | { |
||
904 | // Call trigger |
||
905 | $result=$this->call_trigger('PROJECT_CLOSE',$user); |
||
906 | if ($result < 0) { $error++; } |
||
907 | // End call triggers |
||
908 | |||
909 | if (!$error) |
||
910 | { |
||
911 | $this->statut = 2; |
||
912 | $this->db->commit(); |
||
913 | return 1; |
||
914 | } |
||
915 | else |
||
916 | { |
||
917 | $this->db->rollback(); |
||
918 | $this->error = join(',', $this->errors); |
||
919 | dol_syslog(get_class($this)."::setClose " . $this->error, LOG_ERR); |
||
920 | return -1; |
||
921 | } |
||
922 | } |
||
923 | else |
||
924 | { |
||
925 | $this->db->rollback(); |
||
926 | $this->error = $this->db->lasterror(); |
||
927 | return -1; |
||
928 | } |
||
929 | } |
||
930 | |||
931 | return 0; |
||
932 | } |
||
933 | |||
934 | /** |
||
935 | * Return status label of object |
||
936 | * |
||
937 | * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto |
||
938 | * @return string Label |
||
939 | */ |
||
940 | function getLibStatut($mode=0) |
||
941 | { |
||
942 | return $this->LibStatut($this->statut, $mode); |
||
943 | } |
||
944 | |||
945 | // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps |
||
946 | /** |
||
947 | * Renvoi status label for a status |
||
948 | * |
||
949 | * @param int $statut id statut |
||
950 | * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto |
||
951 | * @return string Label |
||
952 | */ |
||
953 | function LibStatut($statut, $mode=0) |
||
954 | { |
||
955 | // phpcs:enable |
||
956 | global $langs; |
||
957 | |||
958 | if ($mode == 0) |
||
959 | { |
||
960 | return $langs->trans($this->statuts_long[$statut]); |
||
961 | } |
||
962 | if ($mode == 1) |
||
963 | { |
||
964 | return $langs->trans($this->statuts_short[$statut]); |
||
965 | } |
||
966 | if ($mode == 2) |
||
967 | { |
||
968 | if ($statut == 0) |
||
969 | return img_picto($langs->trans($this->statuts_long[$statut]), 'statut0') . ' ' . $langs->trans($this->statuts_short[$statut]); |
||
970 | if ($statut == 1) |
||
971 | return img_picto($langs->trans($this->statuts_long[$statut]), 'statut4') . ' ' . $langs->trans($this->statuts_short[$statut]); |
||
972 | if ($statut == 2) |
||
973 | return img_picto($langs->trans($this->statuts_long[$statut]), 'statut6') . ' ' . $langs->trans($this->statuts_short[$statut]); |
||
974 | } |
||
975 | if ($mode == 3) |
||
976 | { |
||
977 | if ($statut == 0) |
||
978 | return img_picto($langs->trans($this->statuts_long[$statut]), 'statut0'); |
||
979 | if ($statut == 1) |
||
980 | return img_picto($langs->trans($this->statuts_long[$statut]), 'statut4'); |
||
981 | if ($statut == 2) |
||
982 | return img_picto($langs->trans($this->statuts_long[$statut]), 'statut6'); |
||
983 | } |
||
984 | if ($mode == 4) |
||
985 | { |
||
986 | if ($statut == 0) |
||
987 | return img_picto($langs->trans($this->statuts_long[$statut]), 'statut0') . ' ' . $langs->trans($this->statuts_long[$statut]); |
||
988 | if ($statut == 1) |
||
989 | return img_picto($langs->trans($this->statuts_long[$statut]), 'statut4') . ' ' . $langs->trans($this->statuts_long[$statut]); |
||
990 | if ($statut == 2) |
||
991 | return img_picto($langs->trans($this->statuts_long[$statut]), 'statut6') . ' ' . $langs->trans($this->statuts_long[$statut]); |
||
992 | } |
||
993 | if ($mode == 5) |
||
994 | { |
||
995 | if ($statut == 0) |
||
996 | return $langs->trans($this->statuts_short[$statut]) . ' ' . img_picto($langs->trans($this->statuts_long[$statut]), 'statut0'); |
||
997 | if ($statut == 1) |
||
998 | return $langs->trans($this->statuts_short[$statut]) . ' ' . img_picto($langs->trans($this->statuts_long[$statut]), 'statut4'); |
||
999 | if ($statut == 2) |
||
1000 | return $langs->trans($this->statuts_short[$statut]) . ' ' . img_picto($langs->trans($this->statuts_long[$statut]), 'statut6'); |
||
1001 | } |
||
1002 | } |
||
1003 | |||
1004 | /** |
||
1005 | * Return clicable name (with picto eventually) |
||
1006 | * |
||
1007 | * @param int $withpicto 0=No picto, 1=Include picto into link, 2=Only picto |
||
1008 | * @param string $option Variant ('', 'nolink') |
||
1009 | * @param int $addlabel 0=Default, 1=Add label into string, >1=Add first chars into string |
||
1010 | * @param string $moreinpopup Text to add into popup |
||
1011 | * @param string $sep Separator between ref and label if option addlabel is set |
||
1012 | * @param int $notooltip 1=Disable tooltip |
||
1013 | * @param int $save_lastsearch_value -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking |
||
1014 | * @return string String with URL |
||
1015 | */ |
||
1016 | function getNomUrl($withpicto=0, $option='', $addlabel=0, $moreinpopup='', $sep=' - ', $notooltip=0, $save_lastsearch_value=-1) |
||
1017 | { |
||
1018 | global $conf, $langs, $user, $hookmanager; |
||
1019 | |||
1020 | if (! empty($conf->dol_no_mouse_hover)) $notooltip=1; // Force disable tooltips |
||
1021 | |||
1022 | $result = ''; |
||
1023 | |||
1024 | $label=''; |
||
1025 | if ($option != 'nolink') $label = '<u>' . $langs->trans("ShowProject") . '</u>'; |
||
1026 | $label .= ($label?'<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 |
||
1027 | $label .= ($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 |
||
1028 | if (! empty($this->thirdparty_name)) |
||
1029 | $label .= ($label?'<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 |
||
1030 | if (! empty($this->dateo)) |
||
1031 | $label .= ($label?'<br>':'').'<b>' . $langs->trans('DateStart') . ': </b>' . dol_print_date($this->dateo, 'day'); // The space must be after the : to not being explode when showing the title in img_picto |
||
1032 | if (! empty($this->datee)) |
||
1033 | $label .= ($label?'<br>':'').'<b>' . $langs->trans('DateEnd') . ': </b>' . dol_print_date($this->datee, 'day'); // The space must be after the : to not being explode when showing the title in img_picto |
||
1034 | if ($moreinpopup) $label.='<br>'.$moreinpopup; |
||
1035 | |||
1036 | $url=''; |
||
1037 | if ($option != 'nolink') |
||
1038 | { |
||
1039 | if (preg_match('/\.php$/',$option)) { |
||
1040 | $url = dol_buildpath($option,1) . '?id=' . $this->id; |
||
1041 | } |
||
1042 | else if ($option == 'task') |
||
1043 | { |
||
1044 | $url = DOL_URL_ROOT . '/projet/tasks.php?id=' . $this->id; |
||
1045 | } |
||
1046 | else |
||
1047 | { |
||
1048 | $url = DOL_URL_ROOT . '/projet/card.php?id=' . $this->id; |
||
1049 | } |
||
1050 | // Add param to save lastsearch_values or not |
||
1051 | $add_save_lastsearch_values=($save_lastsearch_value == 1 ? 1 : 0); |
||
1052 | if ($save_lastsearch_value == -1 && preg_match('/list\.php/',$_SERVER["PHP_SELF"])) $add_save_lastsearch_values=1; |
||
1053 | if ($add_save_lastsearch_values) $url.='&save_lastsearch_values=1'; |
||
1054 | } |
||
1055 | |||
1056 | $linkclose=''; |
||
1057 | if (empty($notooltip) && $user->rights->projet->lire) |
||
1058 | { |
||
1059 | if (! empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) |
||
1060 | { |
||
1061 | $label=$langs->trans("ShowProject"); |
||
1062 | $linkclose.=' alt="'.dol_escape_htmltag($label, 1).'"'; |
||
1063 | } |
||
1064 | $linkclose.=' title="'.dol_escape_htmltag($label, 1).'"'; |
||
1065 | $linkclose.=' class="classfortooltip"'; |
||
1066 | |||
1067 | /* |
||
1068 | $hookmanager->initHooks(array('projectdao')); |
||
1069 | $parameters=array('id'=>$this->id); |
||
1070 | // Note that $action and $object may have been modified by some hooks |
||
1071 | $reshook=$hookmanager->executeHooks('getnomurltooltip',$parameters,$this,$action); |
||
1072 | if ($reshook > 0) |
||
1073 | $linkclose = $hookmanager->resPrint; |
||
1074 | */ |
||
1075 | } |
||
1076 | |||
1077 | $picto = 'projectpub'; |
||
1078 | if (! $this->public) $picto = 'project'; |
||
1079 | |||
1080 | $linkstart = '<a href="'.$url.'"'; |
||
1081 | $linkstart.=$linkclose.'>'; |
||
1082 | $linkend='</a>'; |
||
1083 | |||
1084 | $result .= $linkstart; |
||
1085 | if ($withpicto) $result.=img_object(($notooltip?'':$label), $picto, ($notooltip?(($withpicto != 2) ? 'class="paddingright"' : ''):'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip?0:1); |
||
1086 | if ($withpicto != 2) $result.= $this->ref; |
||
1087 | $result .= $linkend; |
||
1088 | if ($withpicto != 2) $result.=(($addlabel && $this->title) ? $sep . dol_trunc($this->title, ($addlabel > 1 ? $addlabel : 0)) : ''); |
||
1089 | |||
1090 | global $action; |
||
1091 | $hookmanager->initHooks(array('projectdao')); |
||
1092 | $parameters=array('id'=>$this->id, 'getnomurl'=>$result); |
||
1093 | $reshook=$hookmanager->executeHooks('getNomUrl',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks |
||
1094 | if ($reshook > 0) $result = $hookmanager->resPrint; |
||
1095 | else $result .= $hookmanager->resPrint; |
||
1096 | |||
1097 | return $result; |
||
1098 | } |
||
1099 | |||
1100 | /** |
||
1101 | * Initialise an instance with random values. |
||
1102 | * Used to build previews or test instances. |
||
1103 | * id must be 0 if object instance is a specimen. |
||
1104 | * |
||
1105 | * @return void |
||
1106 | */ |
||
1107 | function initAsSpecimen() |
||
1108 | { |
||
1109 | global $user, $langs, $conf; |
||
1110 | |||
1111 | $now=dol_now(); |
||
1112 | |||
1113 | // Initialise parameters |
||
1114 | $this->id = 0; |
||
1115 | $this->ref = 'SPECIMEN'; |
||
1116 | $this->specimen = 1; |
||
1117 | $this->socid = 1; |
||
1118 | $this->date_c = $now; |
||
1119 | $this->date_m = $now; |
||
1120 | $this->date_start = $now; |
||
1121 | $this->date_end = $now + (3600 * 24 * 365); |
||
1122 | $this->note_public = 'SPECIMEN'; |
||
1123 | $this->fk_ele = 20000; |
||
1124 | $this->opp_amount = 20000; |
||
1125 | $this->budget_amount = 10000; |
||
1126 | |||
1127 | /* |
||
1128 | $nbp = mt_rand(1, 9); |
||
1129 | $xnbp = 0; |
||
1130 | while ($xnbp < $nbp) |
||
1131 | { |
||
1132 | $line = new Task($this->db); |
||
1133 | $line->fk_project = 0; |
||
1134 | $line->label = $langs->trans("Label") . " " . $xnbp; |
||
1135 | $line->description = $langs->trans("Description") . " " . $xnbp; |
||
1136 | |||
1137 | $this->lines[]=$line; |
||
1138 | $xnbp++; |
||
1139 | } |
||
1140 | */ |
||
1141 | } |
||
1142 | |||
1143 | /** |
||
1144 | * Check if user has permission on current project |
||
1145 | * |
||
1146 | * @param User $user Object user to evaluate |
||
1147 | * @param string $mode Type of permission we want to know: 'read', 'write' |
||
1148 | * @return int >0 if user has permission, <0 if user has no permission |
||
1149 | */ |
||
1150 | function restrictedProjectArea($user, $mode='read') |
||
1151 | { |
||
1152 | // To verify role of users |
||
1153 | $userAccess = 0; |
||
1154 | 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))) |
||
1155 | { |
||
1156 | $userAccess = 1; |
||
1157 | } |
||
1158 | else if ($this->public && (($mode == 'read' && ! empty($user->rights->projet->lire)) || ($mode == 'write' && ! empty($user->rights->projet->creer)) || ($mode == 'delete' && ! empty($user->rights->projet->supprimer)))) |
||
1159 | { |
||
1160 | $userAccess = 1; |
||
1161 | } |
||
1162 | else |
||
1163 | { |
||
1164 | foreach (array('internal', 'external') as $source) |
||
1165 | { |
||
1166 | $userRole = $this->liste_contact(4, $source); |
||
1167 | $num = count($userRole); |
||
1168 | |||
1169 | $nblinks = 0; |
||
1170 | while ($nblinks < $num) |
||
1171 | { |
||
1172 | if ($source == 'internal' && preg_match('/^PROJECT/', $userRole[$nblinks]['code']) && $user->id == $userRole[$nblinks]['id']) |
||
1173 | { |
||
1174 | if ($mode == 'read' && $user->rights->projet->lire) $userAccess++; |
||
1175 | if ($mode == 'write' && $user->rights->projet->creer) $userAccess++; |
||
1176 | if ($mode == 'delete' && $user->rights->projet->supprimer) $userAccess++; |
||
1177 | } |
||
1178 | $nblinks++; |
||
1179 | } |
||
1180 | } |
||
1181 | //if (empty($nblinks)) // If nobody has permission, we grant creator |
||
1182 | //{ |
||
1183 | // if ((!empty($this->user_author_id) && $this->user_author_id == $user->id)) |
||
1184 | // { |
||
1185 | // $userAccess = 1; |
||
1186 | // } |
||
1187 | //} |
||
1188 | } |
||
1189 | |||
1190 | return ($userAccess?$userAccess:-1); |
||
1191 | } |
||
1192 | |||
1193 | /** |
||
1194 | * Return array of projects a user has permission on, is affected to, or all projects |
||
1195 | * |
||
1196 | * @param User $user User object |
||
1197 | * @param int $mode 0=All project I have permission on (assigned to me and public), 1=Projects assigned to me only, 2=Will return list of all projects with no test on contacts |
||
1198 | * @param int $list 0=Return array, 1=Return string list |
||
1199 | * @param int $socid 0=No filter on third party, id of third party |
||
1200 | * @param string $filter additionnal filter on project (statut, ref, ...) |
||
1201 | * @return array or string Array of projects id, or string with projects id separated with "," if list is 1 |
||
1202 | */ |
||
1203 | function getProjectsAuthorizedForUser($user, $mode=0, $list=0, $socid=0, $filter='') |
||
1204 | { |
||
1205 | $projects = array(); |
||
1206 | $temp = array(); |
||
1207 | |||
1208 | $sql = "SELECT ".(($mode == 0 || $mode == 1) ? "DISTINCT " : "")."p.rowid, p.ref"; |
||
1209 | $sql.= " FROM " . MAIN_DB_PREFIX . "projet as p"; |
||
1210 | if ($mode == 0 || $mode == 1) |
||
1211 | { |
||
1212 | $sql.= ", " . MAIN_DB_PREFIX . "element_contact as ec"; |
||
1213 | } |
||
1214 | $sql.= " WHERE p.entity IN (".getEntity('project').")"; |
||
1215 | // Internal users must see project he is contact to even if project linked to a third party he can't see. |
||
1216 | //if ($socid || ! $user->rights->societe->client->voir) $sql.= " AND (p.fk_soc IS NULL OR p.fk_soc = 0 OR p.fk_soc = ".$socid.")"; |
||
1217 | if ($socid > 0) $sql.= " AND (p.fk_soc IS NULL OR p.fk_soc = 0 OR p.fk_soc = " . $socid . ")"; |
||
1218 | |||
1219 | // Get id of types of contacts for projects (This list never contains a lot of elements) |
||
1220 | $listofprojectcontacttype=array(); |
||
1221 | $sql2 = "SELECT ctc.rowid, ctc.code FROM ".MAIN_DB_PREFIX."c_type_contact as ctc"; |
||
1222 | $sql2.= " WHERE ctc.element = '" . $this->db->escape($this->element) . "'"; |
||
1223 | $sql2.= " AND ctc.source = 'internal'"; |
||
1224 | $resql = $this->db->query($sql2); |
||
1225 | if ($resql) |
||
1226 | { |
||
1227 | while($obj = $this->db->fetch_object($resql)) |
||
1228 | { |
||
1229 | $listofprojectcontacttype[$obj->rowid]=$obj->code; |
||
1230 | } |
||
1231 | } |
||
1232 | else dol_print_error($this->db); |
||
1233 | if (count($listofprojectcontacttype) == 0) $listofprojectcontacttype[0]='0'; // To avoid syntax error if not found |
||
1234 | |||
1235 | if ($mode == 0) |
||
1236 | { |
||
1237 | $sql.= " AND ec.element_id = p.rowid"; |
||
1238 | $sql.= " AND ( p.public = 1"; |
||
1239 | $sql.= " OR ( ec.fk_c_type_contact IN (".join(',', array_keys($listofprojectcontacttype)).")"; |
||
1240 | $sql.= " AND ec.fk_socpeople = ".$user->id.")"; |
||
1241 | $sql.= " )"; |
||
1242 | } |
||
1243 | if ($mode == 1) |
||
1244 | { |
||
1245 | $sql.= " AND ec.element_id = p.rowid"; |
||
1246 | $sql.= " AND ("; |
||
1247 | $sql.= " ( ec.fk_c_type_contact IN (".join(',', array_keys($listofprojectcontacttype)).")"; |
||
1248 | $sql.= " AND ec.fk_socpeople = ".$user->id.")"; |
||
1249 | $sql.= " )"; |
||
1250 | } |
||
1251 | if ($mode == 2) |
||
1252 | { |
||
1253 | // No filter. Use this if user has permission to see all project |
||
1254 | } |
||
1255 | |||
1256 | $sql.= $filter; |
||
1257 | //print $sql; |
||
1258 | |||
1259 | $resql = $this->db->query($sql); |
||
1260 | if ($resql) |
||
1261 | { |
||
1262 | $num = $this->db->num_rows($resql); |
||
1263 | $i = 0; |
||
1264 | while ($i < $num) |
||
1265 | { |
||
1266 | $row = $this->db->fetch_row($resql); |
||
1267 | $projects[$row[0]] = $row[1]; |
||
1268 | $temp[] = $row[0]; |
||
1269 | $i++; |
||
1270 | } |
||
1271 | |||
1272 | $this->db->free($resql); |
||
1273 | |||
1274 | if ($list) |
||
1275 | { |
||
1276 | if (empty($temp)) return '0'; |
||
1277 | $result = implode(',', $temp); |
||
1278 | return $result; |
||
1279 | } |
||
1280 | } |
||
1281 | else |
||
1282 | { |
||
1283 | dol_print_error($this->db); |
||
1284 | } |
||
1285 | |||
1286 | return $projects; |
||
1287 | } |
||
1288 | |||
1289 | /** |
||
1290 | * Load an object from its id and create a new one in database |
||
1291 | * |
||
1292 | * @param int $fromid Id of object to clone |
||
1293 | * @param bool $clone_contact Clone contact of project |
||
1294 | * @param bool $clone_task Clone task of project |
||
1295 | * @param bool $clone_project_file Clone file of project |
||
1296 | * @param bool $clone_task_file Clone file of task (if task are copied) |
||
1297 | * @param bool $clone_note Clone note of project |
||
1298 | * @param bool $move_date Move task date on clone |
||
1299 | * @param integer $notrigger No trigger flag |
||
1300 | * @param int $newthirdpartyid New thirdparty id |
||
1301 | * @return int New id of clone |
||
1302 | */ |
||
1303 | function createFromClone($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) |
||
1304 | { |
||
1305 | global $user,$langs,$conf; |
||
1306 | |||
1307 | $error=0; |
||
1308 | |||
1309 | 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); |
||
1310 | |||
1311 | $now = dol_mktime(0,0,0,idate('m',dol_now()),idate('d',dol_now()),idate('Y',dol_now())); |
||
1312 | |||
1313 | $clone_project=new Project($this->db); |
||
1314 | |||
1315 | $clone_project->context['createfromclone']='createfromclone'; |
||
1316 | |||
1317 | $this->db->begin(); |
||
1318 | |||
1319 | // Load source object |
||
1320 | $clone_project->fetch($fromid); |
||
1321 | $clone_project->fetch_optionals(); |
||
1322 | if ($newthirdpartyid > 0) $clone_project->socid = $newthirdpartyid; |
||
1323 | $clone_project->fetch_thirdparty(); |
||
1324 | |||
1325 | $orign_dt_start=$clone_project->date_start; |
||
1326 | $orign_project_ref=$clone_project->ref; |
||
1327 | |||
1328 | $clone_project->id=0; |
||
1329 | if ($move_date) { |
||
1330 | $clone_project->date_start = $now; |
||
1331 | if (!(empty($clone_project->date_end))) |
||
1332 | { |
||
1333 | $clone_project->date_end = $clone_project->date_end + ($now - $orign_dt_start); |
||
1334 | } |
||
1335 | } |
||
1336 | |||
1337 | $clone_project->datec = $now; |
||
1338 | |||
1339 | if (! $clone_note) |
||
1340 | { |
||
1341 | $clone_project->note_private=''; |
||
1342 | $clone_project->note_public=''; |
||
1343 | } |
||
1344 | |||
1345 | //Generate next ref |
||
1346 | $defaultref=''; |
||
1347 | $obj = empty($conf->global->PROJECT_ADDON)?'mod_project_simple':$conf->global->PROJECT_ADDON; |
||
1348 | // Search template files |
||
1349 | $file=''; $classname=''; $filefound=0; |
||
1350 | $dirmodels=array_merge(array('/'),(array) $conf->modules_parts['models']); |
||
1351 | foreach($dirmodels as $reldir) |
||
1352 | { |
||
1353 | $file=dol_buildpath($reldir."core/modules/project/".$obj.'.php',0); |
||
1354 | if (file_exists($file)) |
||
1355 | { |
||
1356 | $filefound=1; |
||
1357 | dol_include_once($reldir."core/modules/project/".$obj.'.php'); |
||
1358 | $modProject = new $obj; |
||
1359 | $defaultref = $modProject->getNextValue(is_object($clone_project->thirdparty)?$clone_project->thirdparty:null, $clone_project); |
||
1360 | break; |
||
1361 | } |
||
1362 | } |
||
1363 | if (is_numeric($defaultref) && $defaultref <= 0) $defaultref=''; |
||
1364 | |||
1365 | $clone_project->ref=$defaultref; |
||
1366 | $clone_project->title=$langs->trans("CopyOf").' '.$clone_project->title; |
||
1367 | |||
1368 | // Create clone |
||
1369 | $result=$clone_project->create($user,$notrigger); |
||
1370 | |||
1371 | // Other options |
||
1372 | if ($result < 0) |
||
1373 | { |
||
1374 | $this->error.=$clone_project->error; |
||
1375 | $error++; |
||
1376 | } |
||
1377 | |||
1378 | if (! $error) |
||
1379 | { |
||
1380 | //Get the new project id |
||
1381 | $clone_project_id=$clone_project->id; |
||
1382 | |||
1383 | //Note Update |
||
1384 | if (!$clone_note) |
||
1385 | { |
||
1386 | $clone_project->note_private=''; |
||
1387 | $clone_project->note_public=''; |
||
1388 | } |
||
1389 | else |
||
1390 | { |
||
1391 | $this->db->begin(); |
||
1392 | $res=$clone_project->update_note(dol_html_entity_decode($clone_project->note_public, ENT_QUOTES),'_public'); |
||
1393 | if ($res < 0) |
||
1394 | { |
||
1395 | $this->error.=$clone_project->error; |
||
1396 | $error++; |
||
1397 | $this->db->rollback(); |
||
1398 | } |
||
1399 | else |
||
1400 | { |
||
1401 | $this->db->commit(); |
||
1402 | } |
||
1403 | |||
1404 | $this->db->begin(); |
||
1405 | $res=$clone_project->update_note(dol_html_entity_decode($clone_project->note_private, ENT_QUOTES), '_private'); |
||
1406 | if ($res < 0) |
||
1407 | { |
||
1408 | $this->error.=$clone_project->error; |
||
1409 | $error++; |
||
1410 | $this->db->rollback(); |
||
1411 | } |
||
1412 | else |
||
1413 | { |
||
1414 | $this->db->commit(); |
||
1415 | } |
||
1416 | } |
||
1417 | |||
1418 | //Duplicate contact |
||
1419 | if ($clone_contact) |
||
1420 | { |
||
1421 | $origin_project = new Project($this->db); |
||
1422 | $origin_project->fetch($fromid); |
||
1423 | |||
1424 | foreach(array('internal','external') as $source) |
||
1425 | { |
||
1426 | $tab = $origin_project->liste_contact(-1,$source); |
||
1427 | |||
1428 | foreach ($tab as $contacttoadd) |
||
1429 | { |
||
1430 | $clone_project->add_contact($contacttoadd['id'], $contacttoadd['code'], $contacttoadd['source'],$notrigger); |
||
1431 | if ($clone_project->error == 'DB_ERROR_RECORD_ALREADY_EXISTS') |
||
1432 | { |
||
1433 | $langs->load("errors"); |
||
1434 | $this->error.=$langs->trans("ErrorThisContactIsAlreadyDefinedAsThisType"); |
||
1435 | $error++; |
||
1436 | } |
||
1437 | else |
||
1438 | { |
||
1439 | if ($clone_project->error!='') |
||
1440 | { |
||
1441 | $this->error.=$clone_project->error; |
||
1442 | $error++; |
||
1443 | } |
||
1444 | } |
||
1445 | } |
||
1446 | } |
||
1447 | } |
||
1448 | |||
1449 | //Duplicate file |
||
1450 | if ($clone_project_file) |
||
1451 | { |
||
1452 | require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; |
||
1453 | |||
1454 | $clone_project_dir = $conf->projet->dir_output . "/" . dol_sanitizeFileName($defaultref); |
||
1455 | $ori_project_dir = $conf->projet->dir_output . "/" . dol_sanitizeFileName($orign_project_ref); |
||
1456 | |||
1457 | if (dol_mkdir($clone_project_dir) >= 0) |
||
1458 | { |
||
1459 | $filearray=dol_dir_list($ori_project_dir,"files",0,'','(\.meta|_preview.*\.png)$','',SORT_ASC,1); |
||
1460 | foreach($filearray as $key => $file) |
||
1461 | { |
||
1462 | $rescopy = dol_copy($ori_project_dir . '/' . $file['name'], $clone_project_dir . '/' . $file['name'],0,1); |
||
1463 | if (is_numeric($rescopy) && $rescopy < 0) |
||
1464 | { |
||
1465 | $this->error.=$langs->trans("ErrorFailToCopyFile",$ori_project_dir . '/' . $file['name'],$clone_project_dir . '/' . $file['name']); |
||
1466 | $error++; |
||
1467 | } |
||
1468 | } |
||
1469 | } |
||
1470 | else |
||
1471 | { |
||
1472 | $this->error.=$langs->trans('ErrorInternalErrorDetected').':dol_mkdir'; |
||
1473 | $error++; |
||
1474 | } |
||
1475 | } |
||
1476 | |||
1477 | //Duplicate task |
||
1478 | if ($clone_task) |
||
1479 | { |
||
1480 | require_once DOL_DOCUMENT_ROOT . '/projet/class/task.class.php'; |
||
1481 | |||
1482 | $taskstatic = new Task($this->db); |
||
1483 | |||
1484 | // Security check |
||
1485 | $socid=0; |
||
1486 | if ($user->societe_id > 0) $socid = $user->societe_id; |
||
1487 | |||
1488 | $tasksarray=$taskstatic->getTasksArray(0, 0, $fromid, $socid, 0); |
||
1489 | |||
1490 | $tab_conv_child_parent=array(); |
||
1491 | |||
1492 | // Loop on each task, to clone it |
||
1493 | foreach ($tasksarray as $tasktoclone) |
||
1494 | { |
||
1495 | $result_clone = $taskstatic->createFromClone($tasktoclone->id,$clone_project_id,$tasktoclone->fk_parent,$move_date,true,false,$clone_task_file,true,false); |
||
1496 | if ($result_clone <= 0) |
||
1497 | { |
||
1498 | $this->error.=$result_clone->error; |
||
1499 | $error++; |
||
1500 | } |
||
1501 | else |
||
1502 | { |
||
1503 | $new_task_id=$result_clone; |
||
1504 | $taskstatic->fetch($tasktoclone->id); |
||
1505 | |||
1506 | //manage new parent clone task id |
||
1507 | // if the current task has child we store the original task id and the equivalent clone task id |
||
1508 | if (($taskstatic->hasChildren()) && !array_key_exists($tasktoclone->id,$tab_conv_child_parent)) |
||
1509 | { |
||
1510 | $tab_conv_child_parent[$tasktoclone->id] = $new_task_id; |
||
1511 | } |
||
1512 | } |
||
1513 | } |
||
1514 | |||
1515 | //Parse all clone node to be sure to update new parent |
||
1516 | $tasksarray=$taskstatic->getTasksArray(0, 0, $clone_project_id, $socid, 0); |
||
1517 | foreach ($tasksarray as $task_cloned) |
||
1518 | { |
||
1519 | $taskstatic->fetch($task_cloned->id); |
||
1520 | if ($taskstatic->fk_task_parent!=0) |
||
1521 | { |
||
1522 | $taskstatic->fk_task_parent=$tab_conv_child_parent[$taskstatic->fk_task_parent]; |
||
1523 | } |
||
1524 | $res=$taskstatic->update($user,$notrigger); |
||
1525 | if ($result_clone <= 0) |
||
1526 | { |
||
1527 | $this->error.=$taskstatic->error; |
||
1528 | $error++; |
||
1529 | } |
||
1530 | } |
||
1531 | } |
||
1532 | } |
||
1533 | |||
1534 | unset($clone_project->context['createfromclone']); |
||
1535 | |||
1536 | if (! $error) |
||
1537 | { |
||
1538 | $this->db->commit(); |
||
1539 | return $clone_project_id; |
||
1540 | } |
||
1541 | else |
||
1542 | { |
||
1543 | $this->db->rollback(); |
||
1544 | dol_syslog(get_class($this)."::createFromClone nbError: ".$error." error : " . $this->error, LOG_ERR); |
||
1545 | return -1; |
||
1546 | } |
||
1547 | } |
||
1548 | |||
1549 | |||
1550 | /** |
||
1551 | * Shift project task date from current date to delta |
||
1552 | * |
||
1553 | * @param timestamp $old_project_dt_start old project start date |
||
1554 | * @return int 1 if OK or < 0 if KO |
||
1555 | */ |
||
1556 | function shiftTaskDate($old_project_dt_start) |
||
1557 | { |
||
1558 | global $user,$langs,$conf; |
||
1559 | |||
1560 | $error=0; |
||
1561 | |||
1562 | $taskstatic = new Task($this->db); |
||
1563 | |||
1564 | // Security check |
||
1565 | $socid=0; |
||
1566 | if ($user->societe_id > 0) $socid = $user->societe_id; |
||
1567 | |||
1568 | $tasksarray=$taskstatic->getTasksArray(0, 0, $this->id, $socid, 0); |
||
1569 | |||
1570 | foreach ($tasksarray as $tasktoshiftdate) |
||
1571 | { |
||
1572 | $to_update=false; |
||
1573 | // Fetch only if update of date will be made |
||
1574 | if ((!empty($tasktoshiftdate->date_start)) || (!empty($tasktoshiftdate->date_end))) |
||
1575 | { |
||
1576 | //dol_syslog(get_class($this)."::shiftTaskDate to_update", LOG_DEBUG); |
||
1577 | $to_update=true; |
||
1578 | $task = new Task($this->db); |
||
1579 | $result = $task->fetch($tasktoshiftdate->id); |
||
1580 | if (!$result) |
||
1581 | { |
||
1582 | $error++; |
||
1583 | $this->error.=$task->error; |
||
1584 | } |
||
1585 | } |
||
1586 | //print "$this->date_start + $tasktoshiftdate->date_start - $old_project_dt_start";exit; |
||
1587 | |||
1588 | //Calcultate new task start date with difference between old proj start date and origin task start date |
||
1589 | if (!empty($tasktoshiftdate->date_start)) |
||
1590 | { |
||
1591 | $task->date_start = $this->date_start + ($tasktoshiftdate->date_start - $old_project_dt_start); |
||
1592 | } |
||
1593 | |||
1594 | //Calcultate new task end date with difference between origin proj end date and origin task end date |
||
1595 | if (!empty($tasktoshiftdate->date_end)) |
||
1596 | { |
||
1597 | $task->date_end = $this->date_start + ($tasktoshiftdate->date_end - $old_project_dt_start); |
||
1598 | } |
||
1599 | |||
1600 | if ($to_update) |
||
1601 | { |
||
1602 | $result = $task->update($user); |
||
1603 | if (!$result) |
||
1604 | { |
||
1605 | $error++; |
||
1606 | $this->error.=$task->error; |
||
1607 | } |
||
1608 | } |
||
1609 | } |
||
1610 | if ($error!=0) |
||
1611 | { |
||
1612 | return -1; |
||
1613 | } |
||
1614 | return $result; |
||
1615 | } |
||
1616 | |||
1617 | |||
1618 | // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps |
||
1619 | /** |
||
1620 | * Associate element to a project |
||
1621 | * |
||
1622 | * @param string $tableName Table of the element to update |
||
1623 | * @param int $elementSelectId Key-rowid of the line of the element to update |
||
1624 | * @return int 1 if OK or < 0 if KO |
||
1625 | */ |
||
1626 | function update_element($tableName, $elementSelectId) |
||
1627 | { |
||
1628 | // phpcs:enable |
||
1629 | $sql="UPDATE ".MAIN_DB_PREFIX.$tableName; |
||
1630 | |||
1631 | if ($tableName == "actioncomm") |
||
1632 | { |
||
1633 | $sql.= " SET fk_project=".$this->id; |
||
1634 | $sql.= " WHERE id=".$elementSelectId; |
||
1635 | } |
||
1636 | else |
||
1637 | { |
||
1638 | $sql.= " SET fk_projet=".$this->id; |
||
1639 | $sql.= " WHERE rowid=".$elementSelectId; |
||
1640 | } |
||
1641 | |||
1642 | dol_syslog(get_class($this)."::update_element", LOG_DEBUG); |
||
1643 | $resql=$this->db->query($sql); |
||
1644 | if (!$resql) { |
||
1645 | $this->error=$this->db->lasterror(); |
||
1646 | return -1; |
||
1647 | }else { |
||
1648 | return 1; |
||
1649 | } |
||
1650 | } |
||
1651 | |||
1652 | // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps |
||
1653 | /** |
||
1654 | * Associate element to a project |
||
1655 | * |
||
1656 | * @param string $tableName Table of the element to update |
||
1657 | * @param int $elementSelectId Key-rowid of the line of the element to update |
||
1658 | * @return int 1 if OK or < 0 if KO |
||
1659 | */ |
||
1660 | function remove_element($tableName, $elementSelectId) |
||
1661 | { |
||
1662 | // phpcs:enable |
||
1663 | $sql="UPDATE ".MAIN_DB_PREFIX.$tableName; |
||
1664 | |||
1665 | if ($TableName=="actioncomm") |
||
1666 | { |
||
1667 | $sql.= " SET fk_project=NULL"; |
||
1668 | $sql.= " WHERE id=".$elementSelectId; |
||
1669 | } |
||
1670 | else |
||
1671 | { |
||
1672 | $sql.= " SET fk_projet=NULL"; |
||
1673 | $sql.= " WHERE rowid=".$elementSelectId; |
||
1674 | } |
||
1675 | |||
1676 | dol_syslog(get_class($this)."::remove_element", LOG_DEBUG); |
||
1677 | $resql=$this->db->query($sql); |
||
1678 | if (!$resql) { |
||
1679 | $this->error=$this->db->lasterror(); |
||
1680 | return -1; |
||
1681 | }else { |
||
1682 | return 1; |
||
1683 | } |
||
1684 | } |
||
1685 | |||
1686 | /** |
||
1687 | * Create an intervention document on disk using template defined into PROJECT_ADDON_PDF |
||
1688 | * |
||
1689 | * @param string $modele Force template to use ('' by default) |
||
1690 | * @param Translate $outputlangs Objet lang to use for translation |
||
1691 | * @param int $hidedetails Hide details of lines |
||
1692 | * @param int $hidedesc Hide description |
||
1693 | * @param int $hideref Hide ref |
||
1694 | * @return int 0 if KO, 1 if OK |
||
1695 | */ |
||
1696 | public function generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0) |
||
1697 | { |
||
1698 | global $conf,$langs; |
||
1699 | |||
1700 | $langs->load("projects"); |
||
1701 | |||
1702 | if (! dol_strlen($modele)) { |
||
1703 | |||
1704 | $modele = 'baleine'; |
||
1705 | |||
1706 | if ($this->modelpdf) { |
||
1707 | $modele = $this->modelpdf; |
||
1708 | } elseif (! empty($conf->global->PROJECT_ADDON_PDF)) { |
||
1709 | $modele = $conf->global->PROJECT_ADDON_PDF; |
||
1710 | } |
||
1711 | } |
||
1712 | |||
1713 | $modelpath = "core/modules/project/doc/"; |
||
1714 | |||
1715 | return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref); |
||
1716 | } |
||
1717 | |||
1718 | |||
1719 | /** |
||
1720 | * Load time spent into this->weekWorkLoad and this->weekWorkLoadPerTask for all day of a week of project. |
||
1721 | * Note: array weekWorkLoad and weekWorkLoadPerTask are reset and filled at each call. |
||
1722 | * |
||
1723 | * @param int $datestart First day of week (use dol_get_first_day to find this date) |
||
1724 | * @param int $taskid Filter on a task id |
||
1725 | * @param int $userid Time spent by a particular user |
||
1726 | * @return int <0 if OK, >0 if KO |
||
1727 | */ |
||
1728 | public function loadTimeSpent($datestart, $taskid=0, $userid=0) |
||
1729 | { |
||
1730 | $error=0; |
||
1731 | |||
1732 | $this->weekWorkLoad=array(); |
||
1733 | $this->weekWorkLoadPerTask=array(); |
||
1734 | |||
1735 | if (empty($datestart)) dol_print_error('','Error datestart parameter is empty'); |
||
1736 | |||
1737 | $sql = "SELECT ptt.rowid as taskid, ptt.task_duration, ptt.task_date, ptt.task_datehour, ptt.fk_task"; |
||
1738 | $sql.= " FROM ".MAIN_DB_PREFIX."projet_task_time AS ptt, ".MAIN_DB_PREFIX."projet_task as pt"; |
||
1739 | $sql.= " WHERE ptt.fk_task = pt.rowid"; |
||
1740 | $sql.= " AND pt.fk_projet = ".$this->id; |
||
1741 | $sql.= " AND (ptt.task_date >= '".$this->db->idate($datestart)."' "; |
||
1742 | $sql.= " AND ptt.task_date <= '".$this->db->idate(dol_time_plus_duree($datestart, 1, 'w') - 1)."')"; |
||
1743 | if ($task_id) $sql.= " AND ptt.fk_task=".$taskid; |
||
1744 | if (is_numeric($userid)) $sql.= " AND ptt.fk_user=".$userid; |
||
1745 | |||
1746 | //print $sql; |
||
1747 | $resql=$this->db->query($sql); |
||
1748 | if ($resql) |
||
1749 | { |
||
1750 | $daylareadyfound=array(); |
||
1751 | |||
1752 | $num = $this->db->num_rows($resql); |
||
1753 | $i = 0; |
||
1754 | // Loop on each record found, so each couple (project id, task id) |
||
1755 | while ($i < $num) |
||
1756 | { |
||
1757 | $obj=$this->db->fetch_object($resql); |
||
1758 | $day=$this->db->jdate($obj->task_date); // task_date is date without hours |
||
1759 | if (empty($daylareadyfound[$day])) |
||
1760 | { |
||
1761 | $this->weekWorkLoad[$day] = $obj->task_duration; |
||
1762 | $this->weekWorkLoadPerTask[$day][$obj->fk_task] = $obj->task_duration; |
||
1763 | } |
||
1764 | else |
||
1765 | { |
||
1766 | $this->weekWorkLoad[$day] += $obj->task_duration; |
||
1767 | $this->weekWorkLoadPerTask[$day][$obj->fk_task] += $obj->task_duration; |
||
1768 | } |
||
1769 | $daylareadyfound[$day]=1; |
||
1770 | $i++; |
||
1771 | } |
||
1772 | $this->db->free($resql); |
||
1773 | return 1; |
||
1774 | } |
||
1775 | else |
||
1776 | { |
||
1777 | $this->error="Error ".$this->db->lasterror(); |
||
1778 | dol_syslog(get_class($this)."::fetch ".$this->error, LOG_ERR); |
||
1779 | return -1; |
||
1780 | } |
||
1781 | } |
||
1782 | |||
1783 | |||
1784 | // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps |
||
1785 | /** |
||
1786 | * Load indicators for dashboard (this->nbtodo and this->nbtodolate) |
||
1787 | * |
||
1788 | * @param User $user Objet user |
||
1789 | * @return WorkboardResponse|int <0 if KO, WorkboardResponse if OK |
||
1790 | */ |
||
1791 | function load_board($user) |
||
1848 | } |
||
1849 | } |
||
1850 | |||
1851 | |||
1852 | /** |
||
1853 | * Function used to replace a thirdparty id with another one. |
||
1854 | * |
||
1855 | * @param DoliDB $db Database handler |
||
1856 | * @param int $origin_id Old thirdparty id |
||
1857 | * @param int $dest_id New thirdparty id |
||
1858 | * @return bool |
||
1859 | */ |
||
1860 | public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id) |
||
1861 | { |
||
1862 | $tables = array( |
||
1863 | 'projet' |
||
1864 | ); |
||
1865 | |||
1866 | return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); |
||
1867 | } |
||
1868 | |||
1869 | |||
1870 | // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps |
||
1871 | /** |
||
1872 | * Charge indicateurs this->nb pour le tableau de bord |
||
1873 | * |
||
1874 | * @return int <0 if KO, >0 if OK |
||
1875 | */ |
||
1876 | function load_state_board() |
||
1877 | { |
||
1878 | // phpcs:enable |
||
1879 | global $user; |
||
1880 | |||
1881 | $this->nb=array(); |
||
1882 | |||
1883 | $sql = "SELECT count(p.rowid) as nb"; |
||
1884 | $sql.= " FROM ".MAIN_DB_PREFIX."projet as p"; |
||
1885 | $sql.= " WHERE"; |
||
1886 | $sql.= " p.entity IN (".getEntity('project').")"; |
||
1887 | if (! $user->rights->projet->all->lire) |
||
1888 | { |
||
1889 | $projectsListId = $this->getProjectsAuthorizedForUser($user,0,1); |
||
1890 | $sql .= "AND p.rowid IN (".$projectsListId.")"; |
||
1891 | } |
||
1892 | |||
1893 | $resql=$this->db->query($sql); |
||
1894 | if ($resql) |
||
1895 | { |
||
1896 | while ($obj=$this->db->fetch_object($resql)) |
||
1897 | { |
||
1898 | $this->nb["projects"]=$obj->nb; |
||
1899 | } |
||
1900 | $this->db->free($resql); |
||
1901 | return 1; |
||
1902 | } |
||
1903 | else |
||
1904 | { |
||
1905 | dol_print_error($this->db); |
||
1906 | $this->error=$this->db->error(); |
||
1907 | return -1; |
||
1908 | } |
||
1909 | } |
||
1910 | |||
1911 | |||
1912 | /** |
||
1913 | * Is the project delayed? |
||
1914 | * |
||
1915 | * @return bool |
||
1916 | */ |
||
1917 | public function hasDelay() |
||
1918 | { |
||
1919 | global $conf; |
||
1920 | |||
1921 | if (! ($this->statut == 1)) return false; |
||
1922 | if (! $this->datee && ! $this->date_end) return false; |
||
1923 | |||
1924 | $now = dol_now(); |
||
1925 | |||
1926 | return ($this->datee ? $this->datee : $this->date_end) < ($now - $conf->projet->warning_delay); |
||
1927 | } |
||
1928 | |||
1929 | |||
1930 | /** |
||
1931 | * Charge les informations d'ordre info dans l'objet commande |
||
1932 | * |
||
1933 | * @param int $id Id of order |
||
1934 | * @return void |
||
1935 | */ |
||
1936 | function info($id) |
||
1974 | } |
||
1975 | } |
||
1976 | |||
1977 | /** |
||
1978 | * Sets object to supplied categories. |
||
1979 | * |
||
1980 | * Deletes object from existing categories not supplied. |
||
1981 | * Adds it to non existing supplied categories. |
||
1982 | * Existing categories are left untouch. |
||
1983 | * |
||
1984 | * @param int[]|int $categories Category or categories IDs |
||
1985 | * @return void |
||
1986 | */ |
||
1987 | public function setCategories($categories) |
||
1988 | { |
||
1989 | // Decode type |
||
1990 | $type_id = Categorie::TYPE_PROJECT; |
||
2036 | } |
||
2037 | |||
2038 | |||
2039 | /** |
||
2040 | * Create an array of tasks of current project |
||
2041 | * |
||
2042 | * @param User $user Object user we want project allowed to |
||
2043 | * @return int >0 if OK, <0 if KO |
||
2044 | */ |
||
2045 | function getLinesArray($user) |
||
2051 | } |
||
2052 | } |
||
2053 |