dolibarr  17.0.4
doc_generic_odt.modules.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2010-2011 Laurent Destailleur <ely@users.sourceforge.net>
3  * Copyright (C) 2016 Charlie Benke <charlie@patas-monkey.com>
4  * Copyright (C) 2018-2019 Frédéric France <frederic.france@netlogic.fr>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program. If not, see <https://www.gnu.org/licenses/>.
18  * or see https://www.gnu.org/
19  */
20 
27 require_once DOL_DOCUMENT_ROOT.'/core/modules/societe/modules_societe.class.php';
28 require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
29 require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
30 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
31 require_once DOL_DOCUMENT_ROOT.'/core/lib/doc.lib.php';
32 
33 
38 {
43  public $emetteur;
44 
49  public $phpmin = array(7, 0);
50 
51 
57  public function __construct($db)
58  {
59  global $conf, $langs, $mysoc;
60 
61  // Load translation files required by the page
62  $langs->loadLangs(array("main", "companies"));
63 
64  $this->db = $db;
65  $this->name = "ODT templates";
66  $this->description = $langs->trans("DocumentModelOdt");
67  $this->scandir = 'COMPANY_ADDON_PDF_ODT_PATH'; // Name of constant that is used to save list of directories to scan
68 
69  // Page size for A4 format
70  $this->type = 'odt';
71  $this->page_largeur = 0;
72  $this->page_hauteur = 0;
73  $this->format = array($this->page_largeur, $this->page_hauteur);
74  $this->marge_gauche = 0;
75  $this->marge_droite = 0;
76  $this->marge_haute = 0;
77  $this->marge_basse = 0;
78 
79  $this->option_logo = 1; // Display logo
80 
81  // Retrieves transmitter
82  $this->emetteur = $mysoc;
83  if (!$this->emetteur->country_code) {
84  $this->emetteur->country_code = substr($langs->defaultlang, -2); // By default, if was not defined
85  }
86  }
87 
88 
95  public function info($langs)
96  {
97  global $conf, $langs;
98 
99  // Load traductions files required by page
100  $langs->loadLangs(array("companies", "errors"));
101 
102  $form = new Form($this->db);
103 
104  $texte = $this->description.".<br>\n";
105  $texte .= '<!-- form for option of ODT templates -->';
106  $texte .= '<form action="'.$_SERVER["PHP_SELF"].'" method="POST" enctype="multipart/form-data">';
107  $texte .= '<input type="hidden" name="token" value="'.newToken().'">';
108  $texte .= '<input type="hidden" name="page_y" value="">';
109  $texte .= '<input type="hidden" name="action" value="setModuleOptions">';
110  $texte .= '<input type="hidden" name="param1" value="COMPANY_ADDON_PDF_ODT_PATH">';
111  $texte .= '<table class="nobordernopadding centpercent">';
112 
113  // List of directories area
114  $texte .= '<tr><td>';
115  $texttitle = $langs->trans("ListOfDirectories");
116  $listofdir = explode(',', preg_replace('/[\r\n]+/', ',', trim($conf->global->COMPANY_ADDON_PDF_ODT_PATH)));
117  $listoffiles = array();
118  foreach ($listofdir as $key => $tmpdir) {
119  $tmpdir = trim($tmpdir);
120  $tmpdir = preg_replace('/DOL_DATA_ROOT/', DOL_DATA_ROOT, $tmpdir);
121  if (!$tmpdir) {
122  unset($listofdir[$key]);
123  continue;
124  }
125  if (!is_dir($tmpdir)) {
126  $texttitle .= img_warning($langs->trans("ErrorDirNotFound", $tmpdir), 0);
127  } else {
128  $tmpfiles = dol_dir_list($tmpdir, 'files', 0, '\.od(s|t)$', '', 'name', SORT_ASC, 0, true); // Disable hook for the moment
129  if (count($tmpfiles)) {
130  $listoffiles = array_merge($listoffiles, $tmpfiles);
131  }
132  }
133  }
134  $texthelp = $langs->trans("ListOfDirectoriesForModelGenODT");
135  // Add list of substitution keys
136  $texthelp .= '<br>'.$langs->trans("FollowingSubstitutionKeysCanBeUsed").'<br>';
137  $texthelp .= $langs->transnoentitiesnoconv("FullListOnOnlineDocumentation"); // This contains an url, we don't modify it
138 
139  $texte .= $form->textwithpicto($texttitle, $texthelp, 1, 'help', '', 1);
140  $texte .= '<table><tr><td>';
141  $texte .= '<textarea class="flat" cols="60" name="value1">';
142  $texte .= $conf->global->COMPANY_ADDON_PDF_ODT_PATH;
143  $texte .= '</textarea>';
144  $texte .= '</td>';
145  $texte .= '<td class="center">&nbsp; ';
146  $texte .= '<input type="submit" class="button small reposition" name="modify" value="'.$langs->trans("Modify").'">';
147  $texte .= '</td>';
148  $texte .= '</tr>';
149  $texte .= '</table>';
150 
151  // Scan directories
152  $nbofiles = count($listoffiles);
153  if (!empty($conf->global->COMPANY_ADDON_PDF_ODT_PATH)) {
154  $texte .= $langs->trans("NumberOfModelFilesFound").': <b>';
155  //$texte.=$nbofiles?'<a id="a_'.get_class($this).'" href="#">':'';
156  $texte .= $nbofiles;
157  //$texte.=$nbofiles?'</a>':'';
158  $texte .= '</b>';
159  }
160 
161  if ($nbofiles) {
162  $texte .= '<div id="div_'.get_class($this).'" class="hiddenx">';
163  // Show list of found files
164  foreach ($listoffiles as $file) {
165  $texte .= '- '.$file['name'].' &nbsp; <a class="reposition" href="'.DOL_URL_ROOT.'/document.php?modulepart=doctemplates&file=thirdparties/'.urlencode(basename($file['name'])).'">'.img_picto('', 'listlight').'</a>';
166  $texte .= ' &nbsp; <a class="reposition" href="'.$_SERVER["PHP_SELF"].'?modulepart=doctemplates&keyforuploaddir=COMPANY_ADDON_PDF_ODT_PATH&action=deletefile&token='.newToken().'&file='.urlencode(basename($file['name'])).'">'.img_picto('', 'delete').'</a>';
167  $texte .= '<br>';
168  }
169  $texte .= '</div>';
170  }
171  // Add input to upload a new template file.
172  $texte .= '<div>'.$langs->trans("UploadNewTemplate");
173  $maxfilesizearray = getMaxFileSizeArray();
174  $maxmin = $maxfilesizearray['maxmin'];
175  if ($maxmin > 0) {
176  $texte .= '<input type="hidden" name="MAX_FILE_SIZE" value="'.($maxmin * 1024).'">'; // MAX_FILE_SIZE must precede the field type=file
177  }
178  $texte .= ' <input type="file" name="uploadfile">';
179  $texte .= '<input type="hidden" value="COMPANY_ADDON_PDF_ODT_PATH" name="keyforuploaddir">';
180  $texte .= '<input type="submit" class="button small reposition" value="'.dol_escape_htmltag($langs->trans("Upload")).'" name="upload">';
181  $texte .= '</div>';
182  $texte .= '</td>';
183 
184  $texte .= '<td rowspan="2" class="tdtop hideonsmartphone">';
185  $texte .= '<span class="opacitymedium">';
186  $texte .= $langs->trans("ExampleOfDirectoriesForModelGen");
187  $texte .= '</span>';
188  $texte .= '</td>';
189  $texte .= '</tr>';
190 
191  $texte .= '</table>';
192  $texte .= '</form>';
193 
194  return $texte;
195  }
196 
197  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
209  public function write_file($object, $outputlangs, $srctemplatepath, $hidedetails = 0, $hidedesc = 0, $hideref = 0)
210  {
211  // phpcs:enable
212  global $user, $langs, $conf, $mysoc, $hookmanager;
213 
214  if (empty($srctemplatepath)) {
215  dol_syslog("doc_generic_odt::write_file parameter srctemplatepath empty", LOG_WARNING);
216  return -1;
217  }
218 
219  // Add odtgeneration hook
220  if (!is_object($hookmanager)) {
221  include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
222  $hookmanager = new HookManager($this->db);
223  }
224  $hookmanager->initHooks(array('odtgeneration'));
225  global $action;
226 
227  if (!is_object($outputlangs)) {
228  $outputlangs = $langs;
229  }
230  $sav_charset_output = $outputlangs->charset_output;
231  $outputlangs->charset_output = 'UTF-8';
232 
233  // Load translation files required by the page
234  $outputlangs->loadLangs(array("main", "dict", "companies", "projects"));
235 
236  if ($conf->societe->multidir_output[$object->entity]) {
237  $dir = $conf->societe->multidir_output[$object->entity];
238  $objectref = dol_sanitizeFileName($object->id);
239  if (!preg_match('/specimen/i', $objectref)) {
240  $dir .= "/".$objectref;
241  }
242 
243  if (!file_exists($dir)) {
244  if (dol_mkdir($dir) < 0) {
245  $this->error = $langs->transnoentities("ErrorCanNotCreateDir", $dir);
246  return -1;
247  }
248  }
249 
250  if (file_exists($dir)) {
251  //print "srctemplatepath=".$srctemplatepath; // Src filename
252  $newfile = basename($srctemplatepath);
253  $newfiletmp = preg_replace('/\.od(s|t)/i', '', $newfile);
254  $newfiletmp = preg_replace('/template_/i', '', $newfiletmp);
255  $newfiletmp = preg_replace('/modele_/i', '', $newfiletmp);
256  // Get extension (ods or odt)
257  $newfileformat = substr($newfile, strrpos($newfile, '.') + 1);
258  if (!empty($conf->global->MAIN_DOC_USE_OBJECT_THIRDPARTY_NAME)) {
259  $newfiletmp = dol_sanitizeFileName(dol_string_nospecial($object->name)) . '-' . $newfiletmp;
260  $newfiletmp = preg_replace('/__+/', '_', $newfiletmp); // Replace repeated _ into one _ (to avoid string with substitution syntax)
261  }
262  if (!empty($conf->global->MAIN_DOC_USE_TIMING)) {
263  $format = $conf->global->MAIN_DOC_USE_TIMING;
264  if ($format == '1') {
265  $format = '%Y%m%d%H%M%S';
266  }
267  $filename = $newfiletmp . '-' . dol_print_date(dol_now(), $format) . '.' . $newfileformat;
268  } else {
269  $filename = $newfiletmp . '.' . $newfileformat;
270  }
271  $file = $dir . '/' . $filename;
272  $object->builddoc_filename = $filename; // For triggers
273  //print "newfileformat=".$newfileformat;
274  //print "newdir=".$dir;
275  //print "newfile=".$newfile;
276  //print "file=".$file;
277  //print "conf->societe->dir_temp=".$conf->societe->dir_temp;
278  //exit;
279 
280  dol_mkdir($conf->societe->multidir_temp[$object->entity]);
281  if (!is_writable($conf->societe->multidir_temp[$object->entity])) {
282  $this->error = $langs->transnoentities("ErrorFailedToWriteInTempDirectory", $conf->societe->multidir_temp[$object->entity]);
283  dol_syslog('Error in write_file: ' . $this->error, LOG_ERR);
284  return -1;
285  }
286 
287  // Open and load template
288  require_once ODTPHP_PATH.'odf.php';
289  try {
290  $odfHandler = new odf(
291  $srctemplatepath,
292  array(
293  'PATH_TO_TMP' => $conf->societe->multidir_temp[$object->entity],
294  'ZIP_PROXY' => 'PclZipProxy', // PhpZipProxy or PclZipProxy. Got "bad compression method" error when using PhpZipProxy.
295  'DELIMITER_LEFT' => '{',
296  'DELIMITER_RIGHT' => '}'
297  )
298  );
299  } catch (Exception $e) {
300  $this->error = $e->getMessage();
301  dol_syslog($e->getMessage(), LOG_INFO);
302  return -1;
303  }
304  //print $odfHandler->__toString()."\n";
305 
306  // Replace tags of lines for contacts
307  $contact_arrray = array();
308 
309  $sql = "SELECT p.rowid";
310  $sql .= " FROM ".MAIN_DB_PREFIX."socpeople as p";
311  $sql .= " WHERE p.fk_soc = ".((int) $object->id);
312 
313  $result = $this->db->query($sql);
314  $num = $this->db->num_rows($result);
315 
316  if ($num) {
317  require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
318 
319  $i = 0;
320  $contactstatic = new Contact($this->db);
321 
322  while ($i < $num) {
323  $obj = $this->db->fetch_object($result);
324 
325  $contact_arrray[$i] = $obj->rowid;
326  $i++;
327  }
328  }
329  if ((is_array($contact_arrray) && count($contact_arrray) > 0)) {
330  try {
331  $listlines = $odfHandler->setSegment('companycontacts');
332 
333  foreach ($contact_arrray as $array_key => $contact_id) {
334  $res_contact = $contactstatic->fetch($contact_id);
335  if ((int) $res_contact > 0) {
336  $tmparray = $this->get_substitutionarray_contact($contactstatic, $outputlangs, 'contact');
337  foreach ($tmparray as $key => $val) {
338  try {
339  $listlines->setVars($key, $val, true, 'UTF-8');
340  } catch (OdfException $e) {
341  dol_syslog($e->getMessage(), LOG_INFO);
342  } catch (SegmentException $e) {
343  dol_syslog($e->getMessage(), LOG_INFO);
344  }
345  }
346  $listlines->merge();
347  } else {
348  $this->error = $contactstatic->error;
349  dol_syslog($this->error, LOG_WARNING);
350  }
351  }
352  $odfHandler->mergeSegment($listlines);
353  } catch (OdfException $e) {
354  $this->error = $e->getMessage();
355  dol_syslog($this->error, LOG_WARNING);
356  //return -1;
357  }
358  }
359 
360  // Make substitutions into odt
361  $array_user = $this->get_substitutionarray_user($user, $outputlangs);
362  $array_soc = $this->get_substitutionarray_mysoc($mysoc, $outputlangs);
363  $array_thirdparty = $this->get_substitutionarray_thirdparty($object, $outputlangs);
364  $array_other = $this->get_substitutionarray_other($outputlangs);
365 
366  $tmparray = array_merge($array_user, $array_soc, $array_thirdparty, $array_other);
367  complete_substitutions_array($tmparray, $outputlangs, $object);
368 
369  // Call the ODTSubstitution hook
370  $parameters = array('odfHandler'=>&$odfHandler, 'file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs, 'substitutionarray'=>&$tmparray);
371  $reshook = $hookmanager->executeHooks('ODTSubstitution', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
372 
373  // Replace variables into document
374  foreach ($tmparray as $key => $value) {
375  try {
376  if (preg_match('/logo$/', $key)) { // Image
377  if (file_exists($value)) {
378  $odfHandler->setImage($key, $value);
379  } else {
380  $odfHandler->setVars($key, 'ErrorFileNotFound', true, 'UTF-8');
381  }
382  } else // Text
383  {
384  $odfHandler->setVars($key, $value, true, 'UTF-8');
385  }
386  } catch (OdfException $e) {
387  // setVars failed, probably because key not found
388  dol_syslog($e->getMessage(), LOG_INFO);
389  }
390  }
391 
392  // Replace labels translated
393  $tmparray = $outputlangs->get_translations_for_substitutions();
394  foreach ($tmparray as $key => $value) {
395  try {
396  $odfHandler->setVars($key, $value, true, 'UTF-8');
397  } catch (OdfException $e) {
398  dol_syslog($e->getMessage(), LOG_INFO);
399  }
400  }
401 
402  // Call the beforeODTSave hook
403  $parameters = array('odfHandler'=>&$odfHandler, 'file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs, 'substitutionarray'=>&$tmparray);
404  $reshook = $hookmanager->executeHooks('beforeODTSave', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
405 
406  // Write new file
407  if (!empty($conf->global->MAIN_ODT_AS_PDF)) {
408  try {
409  $odfHandler->exportAsAttachedPDF($file);
410  } catch (Exception $e) {
411  $this->error = $e->getMessage();
412  dol_syslog($e->getMessage(), LOG_INFO);
413  return -1;
414  }
415  } else {
416  try {
417  $odfHandler->creator = $user->getFullName($outputlangs);
418  $odfHandler->title = $object->builddoc_filename;
419  $odfHandler->subject = $object->builddoc_filename;
420 
421  if (!empty($conf->global->ODT_ADD_DOLIBARR_ID)) {
422  $odfHandler->userdefined['dol_id'] = $object->id;
423  $odfHandler->userdefined['dol_element'] = $object->element;
424  }
425 
426  $odfHandler->saveToDisk($file);
427  } catch (Exception $e) {
428  $this->error = $e->getMessage();
429  dol_syslog($e->getMessage(), LOG_INFO);
430  return -1;
431  }
432  }
433  $parameters = array('odfHandler'=>&$odfHandler, 'file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs, 'substitutionarray'=>&$tmparray);
434  $reshook = $hookmanager->executeHooks('afterODTCreation', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
435 
436  if (!empty($conf->global->MAIN_UMASK)) {
437  @chmod($file, octdec($conf->global->MAIN_UMASK));
438  }
439 
440  $odfHandler = null; // Destroy object
441 
442  $this->result = array('fullpath'=>$file);
443 
444  return 1; // Success
445  } else {
446  $this->error = $langs->transnoentities("ErrorCanNotCreateDir", $dir);
447  return -1;
448  }
449  }
450 
451  $this->error = 'UnknownError';
452  return -1;
453  }
454 }
get_substitutionarray_mysoc($mysoc, $outputlangs)
Define array with couple substitution key => substitution value.
get_substitutionarray_contact($object, $outputlangs, $array_key='object')
Define array with couple substitution key => substitution value.
get_substitutionarray_other($outputlangs)
Define array with couple substitution key => substitution value.
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 third parties models of doc generators.
Class to build documents using ODF templates generator.
__construct($db)
Constructor.
write_file($object, $outputlangs, $srctemplatepath, $hidedetails=0, $hidedesc=0, $hideref=0)
Function to build a document on disk using the generic odt module.
info($langs)
Return description of a module.
if($cancel &&! $id) if($action=='add' &&! $cancel) if($action=='delete') if($id) $form
Actions.
Definition: card.php:143
print *****$script_file(".$version.") pid cd cd cd description as description
Only used if Module[ID]Desc translation string is not found.
dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0, $nbsecondsold=0)
Scan a directory and return a list of files/directories.
Definition: files.lib.php:61
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
dol_now($mode='auto')
Return date for now.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
newToken()
Return the value of token currently saved into session with name 'newtoken'.
dol_string_nospecial($str, $newstr='_', $badcharstoreplace='', $badcharstoremove='')
Clean a string from all punctuation characters to use it as a ref or login.
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_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
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:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition: repair.php:119
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition: repair.php:122
getMaxFileSizeArray()
Return the max allowed for file upload.
$conf db
API class for accounts.
Definition: inc.php:41