dolibarr 24.0.0-beta
doc_generic_task_odt.modules.php
Go to the documentation of this file.
1<?php
2
3/* Copyright (C) 2010-2012 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2012 Juanjo Menent <jmenent@2byte.es>
5 * Copyright (C) 2013 Florian Henry <florian.henry@ope-concept.pro>
6 * Copyright (C) 2016 Charlie Benke <charlie@patas-monkey.com>
7 * Copyright (C) 2018-2026 Frédéric France <frederic.france@free.fr>
8 * Copyright (C) 2023 Gauthier VERDOL <gauthier.verdol@atm-consulting.fr>
9 * Copyright (C) 2024-2026 MDW <mdeweerd@users.noreply.github.com>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program. If not, see <https://www.gnu.org/licenses/>.
23 * or see https://www.gnu.org/
24 */
25
32require_once DOL_DOCUMENT_ROOT.'/core/modules/project/modules_project.php';
33require_once DOL_DOCUMENT_ROOT.'/core/modules/project/task/modules_task.php';
34require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
35require_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php';
36require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
37require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
38require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
39require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
40require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
41require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
42require_once DOL_DOCUMENT_ROOT.'/core/lib/doc.lib.php';
43require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
44if (isModEnabled("propal")) {
45 require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
46}
47if (isModEnabled('invoice')) {
48 require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
49}
50if (isModEnabled('invoice')) {
51 require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture-rec.class.php';
52}
53if (isModEnabled('order')) {
54 require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
55}
56if (isModEnabled("supplier_invoice")) {
57 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
58}
59if (isModEnabled("supplier_order")) {
60 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
61}
62if (isModEnabled('contract')) {
63 require_once DOL_DOCUMENT_ROOT.'/contrat/class/contrat.class.php';
64}
65if (isModEnabled('intervention')) {
66 require_once DOL_DOCUMENT_ROOT.'/fichinter/class/fichinter.class.php';
67}
68if (isModEnabled('agenda')) {
69 require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
70}
71
72
77{
82 public $version = 'dolibarr';
83
84
90 public function __construct($db)
91 {
92 global $langs, $mysoc;
93
94 // Load translation files required by the page
95 $langs->loadLangs(array("main", "companies"));
96
97 $this->db = $db;
98 $this->name = "ODT templates";
99 $this->description = $langs->trans("DocumentModelOdt");
100 $this->scandir = 'PROJECT_TASK_ADDON_PDF_ODT_PATH'; // Name of constant that is used to save list of directories to scan
101
102 // Page size for A4 format
103 $this->type = 'odt';
104 $this->page_largeur = 0;
105 $this->page_hauteur = 0;
106 $this->format = array($this->page_largeur, $this->page_hauteur);
107 $this->marge_gauche = 0;
108 $this->marge_droite = 0;
109 $this->marge_haute = 0;
110 $this->marge_basse = 0;
111
112 $this->option_logo = 1; // Display logo
113 $this->option_tva = 0; // Manage the vat option COMMANDE_TVAOPTION
114 $this->option_modereg = 0; // Display payment mode
115 $this->option_condreg = 0; // Display payment terms
116 $this->option_multilang = 0; // Available in several languages
117 $this->option_escompte = 0; // Displays if there has been a discount
118 $this->option_credit_note = 0; // Support credit notes
119 $this->option_freetext = 1; // Support add of a personalised text
120 $this->option_draft_watermark = 0; // Support add of a watermark on drafts
121
122 if ($mysoc === null) {
123 dol_syslog(get_class($this).'::__construct() Global $mysoc should not be null.'. getCallerInfoString(), LOG_ERR);
124 return;
125 }
126
127 // Get source company
128 $this->emetteur = $mysoc;
129 if (!$this->emetteur->country_code) {
130 $this->emetteur->country_code = substr($langs->defaultlang, -2); // By default, if was not defined
131 }
132 }
133
134
135 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
144 public function get_substitutionarray_object($object, $outputlangs, $array_key = 'object')
145 {
146 // phpcs:enable
147 global $extrafields;
148
149 if (!$object instanceof Project) {
150 dol_syslog("Expected Project object, got ".gettype($object), LOG_ERR);
151 return array();
152 }
153
154 $resarray = array(
155 $array_key.'_id' => $object->id,
156 $array_key.'_ref' => $object->ref,
157 $array_key.'_title' => $object->title,
158 $array_key.'_description' => $object->description,
159 $array_key.'_date_creation' => dol_print_date($object->date_c, 'day'),
160 $array_key.'_date_modification' => dol_print_date($object->date_m, 'day'),
161 $array_key.'_date_start' => dol_print_date($object->date_start, 'day'),
162 $array_key.'_date_end' => dol_print_date($object->date_end, 'day'),
163 $array_key.'_note_private' => $object->note_private,
164 $array_key.'_note_public' => $object->note_public,
165 $array_key.'_public' => $object->public,
166 $array_key.'_statut' => $object->getLibStatut()
167 );
168
169 // Retrieve extrafields
170 if (is_array($object->array_options) && count($object->array_options)) {
171 $object->fetch_optionals();
172
173 $resarray = $this->fill_substitutionarray_with_extrafields($object, $resarray, $extrafields, $array_key, $outputlangs);
174 }
175
176 return $resarray;
177 }
178
179 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
188 public function get_substitutionarray_tasks($task, $outputlangs, $array_key = 'task')
189 {
190 // phpcs:enable
191 global $extrafields;
192
193 $resarray = array(
194 'task_ref' => $task->ref,
195 'task_fk_project' => $task->fk_project,
196 'task_projectref' => $task->projectref,
197 'task_projectlabel' => $task->projectlabel,
198 'task_label' => $task->label,
199 'task_description' => $task->description,
200 'task_fk_parent' => $task->fk_task_parent,
201 'task_duration' => $task->duration_effective,
202 'task_duration_formated' => convertSecondToTime($task->duration_effective, 'allhourmin'),
203 'task_planned_workload' => $task->planned_workload,
204 'task_planned_workload_formated' => convertSecondToTime($task->planned_workload, 'allhourmin'),
205 'task_progress' => $task->progress,
206 'task_public' => $task->public,
207 'task_date_start' => dol_print_date($task->date_start, 'day'),
208 'task_date_end' => dol_print_date($task->date_end, 'day'),
209 'task_note_private' => (string) $task->note_private,
210 'task_note_public' => (string) $task->note_public
211 );
212
213 // Retrieve extrafields
214 if (is_array($task->array_options) && count($task->array_options)) {
215 $task->fetch_optionals();
216
217 $resarray = $this->fill_substitutionarray_with_extrafields($task, $resarray, $extrafields, $array_key, $outputlangs);
218 }
219
220 return $resarray;
221 }
222
223 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
231 public function get_substitutionarray_project_contacts($contact, $outputlangs)
232 {
233 // phpcs:enable
234 return array(
235 'projcontacts_id' => $contact['id'],
236 'projcontacts_rowid' => $contact['rowid'],
237 'projcontacts_role' => $contact['libelle'],
238 'projcontacts_lastname' => $contact['lastname'],
239 'projcontacts_firstname' => $contact['firstname'],
240 'projcontacts_fullcivname' => $contact['fullname'],
241 'projcontacts_socname' => $contact['socname'],
242 'projcontacts_email' => $contact['email']
243 );
244 }
245
246 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
254 public function get_substitutionarray_project_file($file, $outputlangs)
255 {
256 // phpcs:enable
257 return array(
258 'projfile_name' => $file['name'],
259 'projfile_date' => dol_print_date($file['date'], 'day'),
260 'projfile_size' => $file['size']
261 );
262 }
263
264 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
272 public function get_substitutionarray_project_reference($refdetail, $outputlangs)
273 {
274 // phpcs:enable
275 return array(
276 'projref_type' => (string) $refdetail['type'],
277 'projref_ref' => (string) $refdetail['ref'],
278 'projref_date' => dol_print_date($refdetail['date'], 'day'),
279 'projref_socname' => (string) $refdetail['socname'],
280 'projref_amountht' => price($refdetail['amountht'], 0, $outputlangs),
281 'projref_amountttc' => price($refdetail['amountttc'], 0, $outputlangs),
282 'projref_status' => (int) $refdetail['status']
283 );
284 }
285
286 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
294 public function get_substitutionarray_tasksressource($taskresource, $outputlangs)
295 {
296 // phpcs:enable
297
298 //dol_syslog(get_class($this).'::get_substitutionarray_tasksressource taskressource='.var_export($taskressource,true),LOG_DEBUG);
299 return array(
300 'taskressource_rowid' => $taskresource['rowid'],
301 'taskressource_role' => $taskresource['libelle'],
302 'taskressource_lastname' => $taskresource['lastname'],
303 'taskressource_firstname' => $taskresource['firstname'],
304 'taskressource_fullcivname' => $taskresource['fullname'],
305 'taskressource_socname' => $taskresource['socname'],
306 'taskressource_email' => $taskresource['email']
307 );
308 }
309
310 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
318 public function get_substitutionarray_taskstime($tasktime, $outputlangs)
319 {
320 // phpcs:enable
321 global $conf;
322
323 return array(
324 'tasktime_rowid' => $tasktime['rowid'],
325 'tasktime_task_date' => dol_print_date($tasktime['task_date'], 'day'),
326 'tasktime_task_duration' => convertSecondToTime($tasktime['task_duration'], 'all'),
327 'tasktime_note' => $tasktime['note'],
328 'tasktime_fk_user' => $tasktime['fk_user'],
329 'tasktime_user_name' => $tasktime['lastname'],
330 'tasktime_user_first' => $tasktime['firstname'],
331 'tasktime_fullcivname' => $tasktime['fullcivname']
332 );
333 }
334
335 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
343 public function get_substitutionarray_task_file($file, $outputlangs)
344 {
345 // phpcs:enable
346 return array(
347 'tasksfile_name' => $file['name'],
348 'tasksfile_date' => dol_print_date($file['date'], 'day'),
349 'tasksfile_size' => $file['size']
350 );
351 }
352
353
360 public function info($langs)
361 {
362 global $conf, $langs;
363
364 // Load translation files required by the page
365 $langs->loadLangs(array("errors", "companies"));
366
367 $form = new Form($this->db);
368
369 $texte = $this->description.".<br>\n";
370 $texte .= '<form action="'.$_SERVER["PHP_SELF"].'" method="POST" enctype="multipart/form-data">';
371 $texte .= '<input type="hidden" name="token" value="'.newToken().'">';
372 $texte .= '<input type="hidden" name="page_y" value="">';
373 $texte .= '<input type="hidden" name="action" value="setModuleOptions">';
374 $texte .= '<input type="hidden" name="param1" value="PROJECT_TASK_ADDON_PDF_ODT_PATH">';
375 $texte .= '<table class="nobordernopadding centpercent">';
376
377 // List of directories area
378 $texte .= '<tr><td>';
379 $texttitle = $langs->trans("ListOfDirectories");
380 $listofdir = explode(',', preg_replace('/[\r\n]+/', ',', trim($conf->global->PROJECT_TASK_ADDON_PDF_ODT_PATH)));
381 $listoffiles = array();
382 foreach ($listofdir as $key => $tmpdir) {
383 $tmpdir = trim($tmpdir);
384 $tmpdir = preg_replace('/DOL_DATA_ROOT/', DOL_DATA_ROOT, $tmpdir);
385 if (!$tmpdir) {
386 unset($listofdir[$key]);
387 continue;
388 }
389 if (!is_dir($tmpdir)) {
390 $texttitle .= img_warning($langs->trans("ErrorDirNotFound", $tmpdir), '');
391 } else {
392 $tmpfiles = dol_dir_list($tmpdir, 'files', 0, '\.(ods|odt)');
393 if (count($tmpfiles)) {
394 $listoffiles = array_merge($listoffiles, $tmpfiles);
395 }
396 }
397 }
398 $texthelp = $langs->trans("ListOfDirectoriesForModelGenODT");
399 $texthelp .= '<br><br><span class="opacitymedium">'.$langs->trans("ExampleOfDirectoriesForModelGen").'</span>';
400 // Add list of substitution keys
401 $texthelp .= '<br>'.$langs->trans("FollowingSubstitutionKeysCanBeUsed").'<br>';
402 $texthelp .= $langs->transnoentitiesnoconv("FullListOnOnlineDocumentation"); // This contains an url, we don't modify it
403
404 $texte .= $form->textwithpicto($texttitle, $texthelp, 1, 'help', '', 1, 3, $this->name);
405 $texte .= '<div><div style="display: inline-block; min-width: 100px; vertical-align: middle;">';
406 $texte .= '<textarea class="flat textareafordir" spellcheck="false" cols="60" name="value1">';
407 $texte .= getDolGlobalString('PROJECT_TASK_ADDON_PDF_ODT_PATH');
408 $texte .= '</textarea>';
409 $texte .= '</div><div style="display: inline-block; vertical-align: middle;">';
410 $texte .= '<input type="submit" class="button button-edit reposition smallpaddingimp" name="modify" value="'.dol_escape_htmltag($langs->trans("Modify")).'">';
411 $texte .= '<br></div></div>';
412
413 // Scan directories
414 $nbofiles = count($listoffiles);
415 if (getDolGlobalString('PROJECT_TASK_ADDON_PDF_ODT_PATH')) {
416 $texte .= $langs->trans("NumberOfModelFilesFound").': <b>';
417 //$texte.=$nbofiles?'<a id="a_'.get_class($this).'" href="#">':'';
418 $texte .= $nbofiles;
419 //$texte.=$nbofiles?'</a>':'';
420 $texte .= '</b>';
421 }
422
423 if ($nbofiles) {
424 $texte .= '<div id="div_'.get_class($this).'" class="hiddenx">';
425 // Show list of found files
426 foreach ($listoffiles as $file) {
427 $texte .= '- '.$file['name'].' <a href="'.DOL_URL_ROOT.'/document.php?modulepart=doctemplates&file=tasks/'.urlencode(basename($file['name'])).'">'.img_picto('', 'listlight').'</a>';
428 $texte .= ' &nbsp; <a class="reposition" href="'.$_SERVER["PHP_SELF"].'?modulepart=doctemplates&keyforuploaddir=PROJECT_TASK_ADDON_PDF_ODT_PATH&action=deletefile&token='.newToken().'&file='.urlencode(basename($file['name'])).'">'.img_picto('', 'delete').'</a>';
429 $texte .= '<br>';
430 }
431 $texte .= '</div>';
432 }
433 // Add input to upload a new template file.
434 $texte .= '<div>'.$langs->trans("UploadNewTemplate");
435 $maxfilesizearray = getMaxFileSizeArray();
436 $maxmin = $maxfilesizearray['maxmin'];
437 if ($maxmin > 0) {
438 $texte .= '<input type="hidden" name="MAX_FILE_SIZE" value="'.($maxmin * 1024).'">'; // MAX_FILE_SIZE must precede the field type=file
439 }
440 $texte .= ' <input type="file" name="uploadfile">';
441 $texte .= '<input type="hidden" value="PROJECT_TASK_ADDON_PDF_ODT_PATH" name="keyforuploaddir">';
442 $texte .= '<input type="submit" class="button smallpaddingimp reposition" value="'.dol_escape_htmltag($langs->trans("Upload")).'" name="upload">';
443 $texte .= '</div>';
444 $texte .= '</td>';
445
446 $texte .= '</tr>';
447
448 $texte .= '</table>';
449 $texte .= '</form>';
450
451 return $texte;
452 }
453
454 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
466 public function write_file($object, $outputlangs, $srctemplatepath = '', $hidedetails = 0, $hidedesc = 0, $hideref = 0)
467 {
468 // phpcs:enable
469 global $user, $langs, $conf, $mysoc, $hookmanager;
470
471 if (empty($srctemplatepath)) {
472 dol_syslog("doc_generic_odt::write_file parameter srctemplatepath empty", LOG_WARNING);
473 return -1;
474 }
475
476 // Add odtgeneration hook
477 if (!is_object($hookmanager)) {
478 include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
479 $hookmanager = new HookManager($this->db);
480 }
481 $hookmanager->initHooks(array('odtgeneration'));
482 global $action;
483
484 if (!is_object($outputlangs)) {
485 $outputlangs = $langs;
486 }
487 $sav_charset_output = $outputlangs->charset_output;
488 $outputlangs->charset_output = 'UTF-8';
489
490 // Load translation files required by the page
491 $outputlangs->loadLangs(array("main", "dict", "companies", "projects"));
492
493 if ($conf->project->dir_output) {
494 // If $object is id instead of object
495 if (!is_object($object)) {
496 $id = $object;
497 $object = new Task($this->db);
498 $result = $object->fetch($id);
499 if ($result < 0) {
500 dol_print_error($this->db, $object->error);
501 return -1;
502 }
503 }
504 $project = new Project($this->db);
505 $project->fetch((int) $object->fk_project);
506 $project->fetch_thirdparty();
507
508 $dir = $conf->project->dir_output."/".$project->ref."/";
509 $objectref = dol_sanitizeFileName($object->ref);
510 if (!preg_match('/specimen/i', $objectref)) {
511 $dir .= "/".$objectref;
512 }
513 $file = $dir."/".$objectref.".odt";
514
515 if (!file_exists($dir)) {
516 if (dol_mkdir($dir) < 0) {
517 $this->error = $langs->transnoentities("ErrorCanNotCreateDir", $dir);
518 return -1;
519 }
520 }
521
522
523 if (file_exists($dir)) {
524 //print "srctemplatepath=".$srctemplatepath; // Src filename
525 $newfile = basename($srctemplatepath);
526 $newfiletmp = preg_replace('/\.(ods|odt)/i', '', $newfile);
527 $newfiletmp = preg_replace('/template_/i', '', $newfiletmp);
528 $newfiletmp = preg_replace('/modele_/i', '', $newfiletmp);
529 $newfiletmp = $objectref . '_' . $newfiletmp;
530 //$file=$dir.'/'.$newfiletmp.'.'.dol_print_date(dol_now(),'%Y%m%d%H%M%S').'.odt';
531 $file = $dir . '/' . $newfiletmp . '.odt';
532 //print "newdir=".$dir;
533 //print "newfile=".$newfile;
534 //print "file=".$file;
535 //print "conf->societe->dir_temp=".$conf->societe->dir_temp;
536
537 dol_mkdir($conf->project->dir_temp);
538 if (!is_writable($conf->project->dir_temp)) {
539 $this->error = $langs->transnoentities("ErrorFailedToWriteInTempDirectory", $conf->project->dir_temp);
540 dol_syslog('Error in write_file: ' . $this->error, LOG_ERR);
541 return -1;
542 }
543
544 $socobject = $project->thirdparty;
545
546 // Make substitution
547 $substitutionarray = array(
548 '__FROM_NAME__' => $this->emetteur->name,
549 '__FROM_EMAIL__' => $this->emetteur->email,
550 );
551 complete_substitutions_array($substitutionarray, $langs, $object);
552 // Call the ODTSubstitution hook
553 $tmparray = array();
554 $action = '';
555 $parameters = array('file' => $file, 'object' => $object, 'outputlangs' => $outputlangs, 'substitutionarray' => &$tmparray);
556 $reshook = $hookmanager->executeHooks('ODTSubstitution', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
557
558 // Open and load template
559 require_once ODTPHP_PATH.'odf.php';
560 try {
561 $odfHandler = new Odf(
562 $srctemplatepath,
563 array(
564 'PATH_TO_TMP' => $conf->project->dir_temp,
565 'ZIP_PROXY' => getDolGlobalString('MAIN_ODF_ZIP_PROXY', 'PclZipProxy'), // PhpZipProxy or PclZipProxy. Got "bad compression method" error when using PhpZipProxy.
566 'DELIMITER_LEFT' => '{',
567 'DELIMITER_RIGHT' => '}'
568 )
569 );
570 } catch (Exception $e) {
571 $this->error = $e->getMessage();
572 return -1;
573 }
574 // After construction $odfHandler->contentXml contains content and
575 // [!-- BEGIN row.lines --]*[!-- END row.lines --] has been replaced by
576 // [!-- BEGIN lines --]*[!-- END lines --]
577 //print html_entity_decode($odfHandler->__toString());
578 //print exit;
579
580
581 // Define substitution array
582 $substitutionarray = getCommonSubstitutionArray($outputlangs, 0, null, $object);
583 $array_object_from_properties = $this->get_substitutionarray_each_var_object($object, $outputlangs);
584 $array_objet = $this->get_substitutionarray_object($project, $outputlangs);
585 $array_user = $this->get_substitutionarray_user($user, $outputlangs);
586 $array_soc = $this->get_substitutionarray_mysoc($mysoc, $outputlangs);
587 $array_thirdparty = $this->get_substitutionarray_thirdparty($socobject, $outputlangs);
588 $array_other = $this->get_substitutionarray_other($outputlangs);
589
590 $tmparray = array_merge($substitutionarray, $array_object_from_properties, $array_user, $array_soc, $array_thirdparty, $array_objet, $array_other);
591 complete_substitutions_array($tmparray, $outputlangs, $object);
592
593 // retrieve the constant to apply a ratio for image size or set the ratio to 1
594 if (getDolGlobalString('MAIN_DOC_ODT_IMAGE_RATIO')) {
595 $ratio = (float) getDolGlobalString('MAIN_DOC_ODT_IMAGE_RATIO');
596 } else {
597 $ratio = 1;
598 }
599
600 foreach ($tmparray as $key => $value) {
601 try {
602 if (preg_match('/logo$/', $key)) { // Image
603 if (file_exists($value)) {
604 $odfHandler->setImage($key, $value, $ratio);
605 } else {
606 $odfHandler->setVars($key, 'ErrorFileNotFound', true, 'UTF-8');
607 }
608 } else { // Text
609 $odfHandler->setVars($key, $value, true, 'UTF-8');
610 }
611 } catch (OdfException $e) {
612 dol_syslog($e->getMessage(), LOG_INFO);
613 }
614 }
615
618 // Replace tags of lines for tasks
619 try {
620 // Security check
621 $socid = 0;
622 if (!empty($project->fk_soc)) {
623 $socid = $project->fk_soc;
624 }
625
626 $tmparray = $this->get_substitutionarray_tasks($object, $outputlangs);
627 complete_substitutions_array($tmparray, $outputlangs, $object);
628 foreach ($tmparray as $key => $val) {
629 try {
630 $odfHandler->setVars($key, $val, true, 'UTF-8');
631 } catch (OdfException $e) {
632 dol_syslog($e->getMessage(), LOG_INFO);
633 }
634 }
635
636 // Replace tags of lines for contacts task
637 $sourcearray = array('internal', 'external');
638 $contact_array = array();
639 foreach ($sourcearray as $source) {
640 $contact_temp = $object->liste_contact(-1, $source);
641 if ((is_array($contact_temp) && count($contact_temp) > 0)) {
642 $contact_array = array_merge($contact_array, $contact_temp);
643 }
644 }
645 // Check for segment
646 $listlinestaskres = null;
647 try {
648 $listlinestaskres = $odfHandler->setSegment('tasksressources');
649 } catch (OdfExceptionSegmentNotFound $e) {
650 // We may arrive here if tags for lines not present into template
651 $listlinestaskres = null;
652 dol_syslog($e->getMessage(), LOG_INFO);
653 }
654 if ($listlinestaskres && (is_array($contact_array) && count($contact_array) > 0)) {
655 foreach ($contact_array as $contact) {
656 if ($contact['source'] == 'internal') {
657 $objectdetail = new User($this->db);
658 $objectdetail->fetch($contact['id']);
659 $contact['socname'] = $mysoc->name;
660 } elseif ($contact['source'] == 'external') {
661 $objectdetail = new Contact($this->db);
662 $objectdetail->fetch($contact['id']);
663
664 $soc = new Societe($this->db);
665 $soc->fetch($contact['socid']);
666 $contact['socname'] = $soc->name;
667 } else {
668 dol_syslog(get_class().'::'.__METHOD__.' Unexpected contact source:'.$contact['source'], LOG_WARNING);
669 $objectdetail = null;
670 }
671 $contact['fullname'] = is_object($objectdetail) ? $objectdetail->getFullName($outputlangs, 1) : null;
672
673 $tmparray = $this->get_substitutionarray_tasksressource($contact, $outputlangs);
674
675 foreach ($tmparray as $key => $val) {
676 try {
677 $listlinestaskres->setVars($key, $val, true, 'UTF-8');
678 } catch (SegmentException $e) {
679 dol_syslog($e->getMessage(), LOG_INFO);
680 }
681 }
682 $listlinestaskres->merge();
683 }
684 $odfHandler->mergeSegment($listlinestaskres);
685 }
686
687 // Check for segment
688 $listlinestasktime = null;
689 try {
690 $listlinestasktime = $odfHandler->setSegment('taskstimes');
691 } catch (OdfExceptionSegmentNotFound $e) {
692 // We may arrive here if tags for lines not present into template
693 $listlinestasktime = null;
694 dol_syslog($e->getMessage(), LOG_INFO);
695 }
696
697 // Time resources
698 $sql = "SELECT t.rowid, t.element_date as task_date, t.element_duration as task_duration, t.fk_user, t.note";
699 $sql .= ", u.lastname, u.firstname";
700 $sql .= " FROM ".MAIN_DB_PREFIX."element_time as t";
701 $sql .= " , ".MAIN_DB_PREFIX."user as u";
702 $sql .= " WHERE t.fk_element =".((int) $object->id);
703 $sql .= " AND t.elementtype = 'task'";
704 $sql .= " AND t.fk_user = u.rowid";
705 $sql .= " ORDER BY t.element_date DESC";
706
707 $resql = $this->db->query($sql);
708 if ($listlinestasktime !== null && $resql) {
709 $num = $this->db->num_rows($resql);
710 $i = 0;
711 $tasks = array();
712
713 while ($i < $num) {
714 $row = $this->db->fetch_array($resql);
715 if (!empty($row['fk_user'])) {
716 $objectdetail = new User($this->db);
717 $objectdetail->fetch($row['fk_user']);
718 // TODO Use a cache to avoid fetch for same user
719 $row['fullcivname'] = $objectdetail->getFullName($outputlangs, 1);
720 } else {
721 $row['fullcivname'] = '';
722 }
723
724 $tmparray = $this->get_substitutionarray_taskstime($row, $outputlangs);
725
726 foreach ($tmparray as $key => $val) {
727 try {
728 $listlinestasktime->setVars($key, $val, true, 'UTF-8');
729 } catch (SegmentException $e) {
730 dol_syslog($e->getMessage(), LOG_INFO);
731 }
732 }
733 $listlinestasktime->merge();
734 $i++;
735 }
736 $this->db->free($resql);
737
738 $odfHandler->mergeSegment($listlinestasktime);
739 }
740
741
742 // Replace tags of project files
743 // Check for segment
744 $listtasksfiles = null;
745 try {
746 $listtasksfiles = $odfHandler->setSegment('tasksfiles');
747 } catch (OdfExceptionSegmentNotFound $e) {
748 // We may arrive here if tags for lines not present into template
749 $listtasksfiles = null;
750 dol_syslog($e->getMessage(), LOG_INFO);
751 }
752 if ($listtasksfiles !== null) {
753 $upload_dir = $conf->project->dir_output.'/'.dol_sanitizeFileName($project->ref).'/'.dol_sanitizeFileName($object->ref);
754 $filearray = dol_dir_list($upload_dir, "files", 0, '', '(\.meta|_preview.*\.png)$', 'name', SORT_ASC, 1);
755
756 foreach ($filearray as $filedetail) {
757 $tmparray = $this->get_substitutionarray_task_file($filedetail, $outputlangs);
758 //dol_syslog(get_class($this).'::main $tmparray'.var_export($tmparray,true));
759 foreach ($tmparray as $key => $val) {
760 try {
761 $listtasksfiles->setVars($key, $val, true, 'UTF-8');
762 } catch (SegmentException $e) {
763 dol_syslog($e->getMessage(), LOG_INFO);
764 }
765 }
766 $listtasksfiles->merge();
767 }
768 //$listlines->merge();
769
770 $odfHandler->mergeSegment($listtasksfiles);
771 }
772 } catch (OdfException $e) {
773 $this->error = $e->getMessage();
774 dol_syslog($this->error, LOG_WARNING);
775 return -1;
776 }
777
778
779 // Replace tags of project files
780 // Check for segment
781 $listlines = null;
782 try {
783 $listlines = $odfHandler->setSegment('projectfiles');
784 } catch (OdfExceptionSegmentNotFound $e) {
785 // We may arrive here if tags for lines not present into template
786 $listlines = null;
787 dol_syslog($e->getMessage(), LOG_INFO);
788 }
789 if ($listlines !== null) {
790 try {
791 $upload_dir = $conf->project->dir_output.'/'.dol_sanitizeFileName($object->ref);
792 $filearray = dol_dir_list($upload_dir, "files", 0, '', '(\.meta|_preview.*\.png)$', 'name', SORT_ASC, 1);
793
794 foreach ($filearray as $filedetail) {
795 //dol_syslog(get_class($this).'::main $filedetail'.var_export($filedetail,true));
796 $tmparray = $this->get_substitutionarray_project_file($filedetail, $outputlangs);
797
798 foreach ($tmparray as $key => $val) {
799 try {
800 $listlines->setVars($key, $val, true, 'UTF-8');
801 } catch (SegmentException $e) {
802 dol_syslog($e->getMessage(), LOG_INFO);
803 }
804 }
805 $listlines->merge();
806 }
807 $odfHandler->mergeSegment($listlines);
808 } catch (OdfException $e) {
809 $this->error = $e->getMessage();
810 dol_syslog($this->error, LOG_WARNING);
811 return -1;
812 }
813 }
814
815 // Replace tags of lines for contacts
816 $sourcearray = array('internal', 'external');
817 $contact_array = array();
818 foreach ($sourcearray as $source) {
819 $contact_temp = $project->liste_contact(-1, $source);
820 if ((is_array($contact_temp) && count($contact_temp) > 0)) {
821 $contact_array = array_merge($contact_array, $contact_temp);
822 }
823 }
824 // Check for segment
825 $listlines = null;
826 try {
827 $listlines = $odfHandler->setSegment('projectcontacts');
828 } catch (OdfExceptionSegmentNotFound $e) {
829 // We may arrive here if tags for lines not present into template
830 $listlines = null;
831 dol_syslog($e->getMessage(), LOG_INFO);
832 }
833 if ($listlines !== null && (is_array($contact_array) && count($contact_array) > 0)) {
834 try {
835 foreach ($contact_array as $contact) {
836 if ($contact['source'] == 'internal') {
837 $objectdetail = new User($this->db);
838 $objectdetail->fetch($contact['id']);
839 $contact['socname'] = $mysoc->name;
840 } elseif ($contact['source'] == 'external') {
841 $objectdetail = new Contact($this->db);
842 $objectdetail->fetch($contact['id']);
843
844 $soc = new Societe($this->db);
845 $soc->fetch($contact['socid']);
846 $contact['socname'] = $soc->name;
847 } else {
848 dol_syslog(get_class().'::'.__METHOD__.' Unexpected contact source:'.$contact['source'], LOG_ERR);
849 continue;
850 }
851 $contact['fullname'] = $objectdetail->getFullName($outputlangs, 1);
852
853 $tmparray = $this->get_substitutionarray_project_contacts($contact, $outputlangs);
854
855 foreach ($tmparray as $key => $val) {
856 try {
857 $listlines->setVars($key, $val, true, 'UTF-8');
858 } catch (SegmentException $e) {
859 dol_syslog($e->getMessage(), LOG_INFO);
860 }
861 }
862 $listlines->merge();
863 }
864 $odfHandler->mergeSegment($listlines);
865 } catch (OdfException $e) {
866 $this->error = $e->getMessage();
867 dol_syslog($this->error, LOG_WARNING);
868 return -1;
869 }
870 }
871
872
873 // Call the beforeODTSave hook
874 $parameters = array('odfHandler' => &$odfHandler, 'file' => $file, 'object' => $object, 'outputlangs' => $outputlangs, 'substitutionarray' => &$tmparray);
875 $reshook = $hookmanager->executeHooks('beforeODTSave', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
876
877
878 // Write new file
879 if (getDolGlobalString('MAIN_ODT_AS_PDF')) {
880 try {
881 $odfHandler->exportAsAttachedPDF($file);
882 } catch (Exception $e) {
883 $this->error = $e->getMessage();
884 dol_syslog($e->getMessage(), LOG_INFO);
885 return -1;
886 }
887 } else {
888 try {
889 $odfHandler->saveToDisk($file);
890 } catch (Exception $e) {
891 $this->error = $e->getMessage();
892 dol_syslog($e->getMessage(), LOG_INFO);
893 return -1;
894 }
895 }
896 $parameters = array('odfHandler' => &$odfHandler, 'file' => $file, 'object' => $object, 'outputlangs' => $outputlangs, 'substitutionarray' => &$tmparray);
897 $reshook = $hookmanager->executeHooks('afterODTCreation', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
898
899 dolChmod($file);
900
901 $odfHandler = null; // Destroy object
902
903 $this->result = array('fullpath' => $file);
904
905 return 1; // Success
906 } else {
907 $this->error = $langs->transnoentities("ErrorCanNotCreateDir", $dir);
908 return -1;
909 }
910 }
911
912 return -1;
913 }
914}
$id
Support class for third parties, contacts, members, users or resources.
Definition account.php:47
if(! $sortfield) if(! $sortorder) $object
Definition account.php:100
get_substitutionarray_each_var_object(&$object, $outputlangs, $recursive=1)
Define array with couple substitution key => substitution value @phpstan-template T.
get_substitutionarray_mysoc($mysoc, $outputlangs)
Define array with couple substitution key => substitution value.
get_substitutionarray_other($outputlangs)
Define array with couple substitution key => substitution value.
fill_substitutionarray_with_extrafields($object, $array_to_fill, $extrafields, $array_key, $outputlangs)
Fill array with couple extrafield key => extrafield value Note that vars into substitutions array are...
get_substitutionarray_thirdparty($object, $outputlangs, $array_key='company')
Define array with couple substitution key => substitution value For example {company_name}...
get_substitutionarray_user($user, $outputlangs)
Define array with couple substitution key => substitution value.
Class to manage contact/addresses.
Class to manage generation of HTML components Only common components must be here.
Class to manage hooks.
Parent class for task models.
write_file($object, $outputlangs, $srctemplatepath='', $hidedetails=0, $hidedesc=0, $hideref=0)
Function to build a document on disk using the generic odt module.
Class to manage projects.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage tasks.
Class to manage Dolibarr users.
Class to build documents using ODF templates generator.
get_substitutionarray_task_file($file, $outputlangs)
Define array with couple substitution key => substitution value.
get_substitutionarray_taskstime($tasktime, $outputlangs)
Define array with couple substitution key => substitution value.
get_substitutionarray_tasks($task, $outputlangs, $array_key='task')
Define array with couple substitution key => substitution value.
get_substitutionarray_object($object, $outputlangs, $array_key='object')
Define array with couple substitution key => substitution value.
get_substitutionarray_project_contacts($contact, $outputlangs)
Define array with couple substitution key => substitution value.
get_substitutionarray_project_file($file, $outputlangs)
Define array with couple substitution key => substitution value.
info($langs)
Return description of a module.
get_substitutionarray_project_reference($refdetail, $outputlangs)
Define array with couple substitution key => substitution value.
get_substitutionarray_tasksressource($taskresource, $outputlangs)
Define array with couple substitution key => substitution value.
global $mysoc
convertSecondToTime($iSecond, $format='all', $lengthOfDay=86400, $lengthOfWeek=7)
Return, in clear text, value of a number of seconds in days, hours and minutes.
Definition date.lib.php:248
print $script_file $mode $langs defaultlang(is_numeric($duration_value) ? " delay=". $duration_value :"").(is_numeric($duration_value2) ? " after cd cd cd description as description
Only used if Module[ID]Desc translation string is not found.
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
dol_dir_list($utf8_path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0, $nbsecondsold=0)
Scan a directory and return a list of files/directories.
Definition files.lib.php:64
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2, $allowothertags=array())
Show picto whatever it's its name (generic function)
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
getCallerInfoString()
Get caller info as a string that can be appended to a log message.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1, $includequotes=0, $allowdash=0)
Clean a string to use it as a file name.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
dolChmod($filepath, $newmask='')
Change mod of a file.
complete_substitutions_array(&$substitutionarray, $outputlangs, $object=null, $parameters=null, $callfunc="completesubstitutionarray")
Complete the $substitutionarray with more entries coming from external module that had set the "subst...
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false, $decorate=0)
Output date in a string format according to outputlangs (or langs if not defined).
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
if(preg_match('/(crypted|dolcrypt):/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
'integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter[:Sortfield]]]',...
Definition repair.php:130
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition repair.php:133
getMaxFileSizeArray()
Return the max allowed for file upload.