dolibarr 19.0.3
doc_generic_ticket_odt.modules.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2010-2012 Laurent Destailleur <eldy@users.sourceforge.net>
3 * Copyright (C) 2012 Juanjo Menent <jmenent@2byte.es>
4 * Copyright (C) 2018-2020 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
27require_once DOL_DOCUMENT_ROOT.'/core/modules/ticket/modules_ticket.php';
28require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
29require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
30require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
31require_once DOL_DOCUMENT_ROOT.'/core/lib/doc.lib.php';
32
33
38{
43 public $version = 'dolibarr';
44
45
51 public function __construct($db)
52 {
53 global $langs, $mysoc;
54
55 // Load translation files required by the page
56 $langs->loadLangs(array("main", "companies"));
57
58 $this->db = $db;
59 $this->name = "ODT templates";
60 $this->description = $langs->trans("DocumentModelOdt");
61 $this->scandir = 'TICKET_ADDON_PDF_ODT_PATH'; // Name of constant that is used to save list of directories to scan
62
63 // Page size for A4 format
64 $this->type = 'odt';
65 $this->page_largeur = 0;
66 $this->page_hauteur = 0;
67 $this->format = array($this->page_largeur, $this->page_hauteur);
68 $this->marge_gauche = 0;
69 $this->marge_droite = 0;
70 $this->marge_haute = 0;
71 $this->marge_basse = 0;
72
73 $this->option_logo = 1; // Display logo
74 $this->option_tva = 0; // Manage the vat option USER_TVAOPTION
75 $this->option_multilang = 1; // Available in several languages
76 $this->option_freetext = 0; // Support add of a personalised text
77 $this->option_draft_watermark = 0; // Support add of a watermark on drafts
78
79 // Get source company
80 $this->emetteur = $mysoc;
81 if (!$this->emetteur->country_code) {
82 $this->emetteur->country_code = substr($langs->defaultlang, -2); // By default if not defined
83 }
84 }
85
86
93 public function info($langs)
94 {
95 global $langs;
96
97 // Load translation files required by the page
98 $langs->loadLangs(array('companies', 'errors'));
99
100 $form = new Form($this->db);
101
102 $texte = $this->description.".<br>\n";
103 $texte .= '<form action="'.$_SERVER["PHP_SELF"].'" method="POST" enctype="multipart/form-data">';
104 $texte .= '<input type="hidden" name="token" value="'.newToken().'">';
105 $texte .= '<input type="hidden" name="page_y" value="">';
106 $texte .= '<input type="hidden" name="action" value="setModuleOptions">';
107 $texte .= '<input type="hidden" name="param1" value="TICKET_ADDON_PDF_ODT_PATH">';
108
109 $texte .= '<table class="nobordernopadding" width="100%">';
110
111 // List of directories area
112 $texte .= '<tr><td>';
113 $texttitle = $langs->trans("ListOfDirectories");
114 $listofdir = explode(',', preg_replace('/[\r\n]+/', ',', trim(getDolGlobalString('TICKET_ADDON_PDF_ODT_PATH'))));
115 $listoffiles = array();
116 foreach ($listofdir as $key => $tmpdir) {
117 $tmpdir = trim($tmpdir);
118 $tmpdir = preg_replace('/DOL_DATA_ROOT/', DOL_DATA_ROOT, $tmpdir);
119 if (!$tmpdir) {
120 unset($listofdir[$key]);
121 continue;
122 }
123 if (!is_dir($tmpdir)) {
124 $texttitle .= img_warning($langs->trans("ErrorDirNotFound", $tmpdir), 0);
125 } else {
126 $tmpfiles = dol_dir_list($tmpdir, 'files', 0, '\.(ods|odt)');
127 if (count($tmpfiles)) {
128 $listoffiles = array_merge($listoffiles, $tmpfiles);
129 }
130 }
131 }
132 $texthelp = $langs->trans("ListOfDirectoriesForModelGenODT");
133 $texthelp .= '<br><br><span class="opacitymedium">'.$langs->trans("ExampleOfDirectoriesForModelGen").'</span>';
134 // Add list of substitution keys
135 $texthelp .= '<br>'.$langs->trans("FollowingSubstitutionKeysCanBeUsed").'<br>';
136 $texthelp .= $langs->transnoentitiesnoconv("FullListOnOnlineDocumentation"); // This contains an url, we don't modify it
137
138 $texte .= $form->textwithpicto($texttitle, $texthelp, 1, 'help', '', 1, 3, $this->name);
139 $texte .= '<div><div style="display: inline-block; min-width: 100px; vertical-align: middle;">';
140 $texte .= '<textarea class="flat" cols="60" name="value1">';
141 $texte .= getDolGlobalString('TICKET_ADDON_PDF_ODT_PATH');
142 $texte .= '</textarea>';
143 $texte .= '</div><div style="display: inline-block; vertical-align: middle;">';
144 $texte .= '<input type="submit" class="button button-edit reposition smallpaddingimp" name="modify" value="'.dol_escape_htmltag($langs->trans("Modify")).'">';
145 $texte .= '<br></div></div>';
146
147 // Scan directories
148 if (count($listofdir)) {
149 $texte .= $langs->trans("NumberOfModelFilesFound").': <b>'.count($listoffiles).'</b>';
150
151 $texte .= '<div id="div_'.get_class($this).'" class="hiddenx">';
152 // Show list of found files
153 foreach ($listoffiles as $file) {
154 $texte .= '- '.$file['name'].' <a href="'.DOL_URL_ROOT.'/document.php?modulepart=doctemplates&file=tickets/'.urlencode(basename($file['name'])).'">'.img_picto('', 'listlight').'</a>';
155 $texte .= ' &nbsp; <a class="reposition" href="'.$_SERVER["PHP_SELF"].'?modulepart=doctemplates&keyforuploaddir=TICKET_ADDON_PDF_ODT_PATH&action=deletefile&token='.newToken().'&file='.urlencode(basename($file['name'])).'">'.img_picto('', 'delete').'</a>';
156 $texte .= '<br>';
157 }
158 $texte .= '</div>';
159 }
160 // Add input to upload a new template file.
161 $texte .= '<div>'.$langs->trans("UploadNewTemplate");
162 $maxfilesizearray = getMaxFileSizeArray();
163 $maxmin = $maxfilesizearray['maxmin'];
164 if ($maxmin > 0) {
165 $texte .= '<input type="hidden" name="MAX_FILE_SIZE" value="'.($maxmin * 1024).'">'; // MAX_FILE_SIZE must precede the field type=file
166 }
167 $texte .= ' <input type="file" name="uploadfile">';
168 $texte .= '<input type="hidden" value="TICKET_ADDON_PDF_ODT_PATH" name="keyforuploaddir">';
169 $texte .= '<input type="submit" class="button smallpaddingimp reposition" value="'.dol_escape_htmltag($langs->trans("Upload")).'" name="upload">';
170 $texte .= '</div>';
171
172 $texte .= '</td>';
173
174 $texte .= '</tr>';
175
176 $texte .= '</table>';
177 $texte .= '</form>';
178
179 return $texte;
180 }
181
182 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
194 public function write_file($object, $outputlangs, $srctemplatepath, $hidedetails = 0, $hidedesc = 0, $hideref = 0)
195 {
196 // phpcs:enable
197 global $user, $langs, $conf, $mysoc, $hookmanager;
198
199 if (empty($srctemplatepath)) {
200 dol_syslog("doc_generic_odt::write_file parameter srctemplatepath empty", LOG_WARNING);
201 return -1;
202 }
203
204 // Add odtgeneration hook
205 if (!is_object($hookmanager)) {
206 include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
207 $hookmanager = new HookManager($this->db);
208 }
209 $hookmanager->initHooks(array('odtgeneration'));
210 global $action;
211
212 if (!is_object($outputlangs)) {
213 $outputlangs = $langs;
214 }
215 $sav_charset_output = $outputlangs->charset_output;
216 $outputlangs->charset_output = 'UTF-8';
217
218 // Load translation files required by the page
219 $outputlangs->loadLangs(array("main", "companies", "bills", "dict"));
220
221 if ($conf->ticket->dir_output) {
222 // If $object is id instead of object
223 if (!is_object($object)) {
224 $id = $object;
225 $object = new User($this->db);
226 $result = $object->fetch($id);
227 if ($result < 0) {
228 dol_print_error($this->db, $object->error);
229 return -1;
230 }
231 }
232
233 $object->fetch_thirdparty();
234
235 $dir = $conf->ticket->dir_output;
236 $objectref = dol_sanitizeFileName($object->ref);
237 if (!preg_match('/specimen/i', $objectref)) {
238 $dir .= "/".$objectref;
239 }
240 $file = $dir."/".$objectref.".odt";
241
242 if (!file_exists($dir)) {
243 if (dol_mkdir($dir) < 0) {
244 $this->error = $langs->transnoentities("ErrorCanNotCreateDir", $dir);
245 return -1;
246 }
247 }
248
249 if (file_exists($dir)) {
250 //print "srctemplatepath=".$srctemplatepath; // Src filename
251 $newfile = basename($srctemplatepath);
252 $newfiletmp = preg_replace('/\.od[ts]/i', '', $newfile);
253 $newfiletmp = preg_replace('/template_/i', '', $newfiletmp);
254 $newfiletmp = preg_replace('/modele_/i', '', $newfiletmp);
255
256 $newfiletmp = $objectref . '_' . $newfiletmp;
257
258 // Get extension (ods or odt)
259 $newfileformat = substr($newfile, strrpos($newfile, '.') + 1);
260 if (getDolGlobalString('MAIN_DOC_USE_TIMING')) {
261 $format = getDolGlobalString('MAIN_DOC_USE_TIMING');
262 if ($format == '1') {
263 $format = '%Y%m%d%H%M%S';
264 }
265 $filename = $newfiletmp . '-' . dol_print_date(dol_now(), $format) . '.' . $newfileformat;
266 } else {
267 $filename = $newfiletmp . '.' . $newfileformat;
268 }
269 $file = $dir . '/' . $filename;
270 //print "newdir=".$dir;
271 //print "newfile=".$newfile;
272 //print "file=".$file;
273 //print "conf->ticket->dir_temp=".$conf->ticket->dir_temp;
274
275 dol_mkdir($conf->ticket->dir_temp);
276 if (!is_writable($conf->ticket->dir_temp)) {
277 $this->error = $langs->transnoentities("ErrorFailedToWriteInTempDirectory", $conf->ticket->dir_temp);
278 dol_syslog('Error in write_file: ' . $this->error, LOG_ERR);
279 return -1;
280 }
281
282 // If CUSTOMER contact defined on user, we use it
283 $usecontact = false;
284 $arrayidcontact = $object->getIdContact('external', 'CUSTOMER');
285 if (count($arrayidcontact) > 0) {
286 $usecontact = true;
287 $result = $object->fetch_contact($arrayidcontact[0]);
288 }
289
290 // Recipient name
291 if (!empty($usecontact)) {
292 // We can use the company of contact instead of thirdparty company
293 if ($object->contact->socid != $object->thirdparty->id && (!isset($conf->global->MAIN_USE_COMPANY_NAME_OF_CONTACT) || getDolGlobalString('MAIN_USE_COMPANY_NAME_OF_CONTACT'))) {
294 $object->contact->fetch_thirdparty();
295 $socobject = $object->contact->thirdparty;
296 $contactobject = $object->contact;
297 } else {
298 $socobject = $object->thirdparty;
299 // if we have a CUSTOMER contact and we dont use it as thirdparty recipient we store the contact object for later use
300 $contactobject = $object->contact;
301 }
302 } else {
303 $socobject = $object->thirdparty;
304 }
305
306 // Open and load template
307 require_once ODTPHP_PATH.'odf.php';
308 try {
309 $odfHandler = new Odf(
310 $srctemplatepath,
311 array(
312 'PATH_TO_TMP' => $conf->ticket->dir_temp,
313 'ZIP_PROXY' => getDolGlobalString('MAIN_ODF_ZIP_PROXY', 'PclZipProxy'), // PhpZipProxy or PclZipProxy. Got "bad compression method" error when using PhpZipProxy.
314 'DELIMITER_LEFT' => '{',
315 'DELIMITER_RIGHT' => '}'
316 )
317 );
318 } catch (Exception $e) {
319 $this->error = $e->getMessage();
320 dol_syslog($e->getMessage(), LOG_WARNING);
321 return -1;
322 }
323
324 // Make substitutions into odt
325 $array_user = $this->get_substitutionarray_user($object, $outputlangs);
326 $array_soc = $this->get_substitutionarray_mysoc($mysoc, $outputlangs);
327 $array_thirdparty = $this->get_substitutionarray_thirdparty($socobject, $outputlangs);
328 $array_other = $this->get_substitutionarray_other($outputlangs);
329 // retrieve contact information for use in object as contact_xxx tags
330 $array_thirdparty_contact = array();
331 if ($usecontact && is_object($contactobject)) {
332 $array_thirdparty_contact = $this->get_substitutionarray_contact($contactobject, $outputlangs, 'contact');
333 }
334
335 $tmparray = array_merge($array_user, $array_soc, $array_thirdparty, $array_other, $array_thirdparty_contact);
336 complete_substitutions_array($tmparray, $outputlangs, $object);
337 $object->fetch_optionals();
338 // Call the ODTSubstitution hook
339 $parameters = array('file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs, 'substitutionarray'=>&$tmparray);
340 $reshook = $hookmanager->executeHooks('ODTSubstitution', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
341 foreach ($tmparray as $key => $value) {
342 try {
343 if (preg_match('/logo$/', $key)) { // Image
344 if (file_exists($value)) {
345 $odfHandler->setImage($key, $value);
346 } else {
347 $odfHandler->setVars($key, 'ErrorFileNotFound', true, 'UTF-8');
348 }
349 } else { // Text
350 $odfHandler->setVars($key, $value, true, 'UTF-8');
351 }
352 } catch (OdfException $e) {
353 dol_syslog($e->getMessage(), LOG_WARNING);
354 }
355 }
356
357 // Replace labels translated
358 $tmparray = $outputlangs->get_translations_for_substitutions();
359 foreach ($tmparray as $key => $value) {
360 try {
361 $odfHandler->setVars($key, $value, true, 'UTF-8');
362 } catch (OdfException $e) {
363 dol_syslog($e->getMessage(), LOG_WARNING);
364 }
365 }
366
367 // Call the beforeODTSave hook
368 $parameters = array('odfHandler'=>&$odfHandler, 'file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs);
369 $reshook = $hookmanager->executeHooks('beforeODTSave', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
370
371 // Write new file
372 if (getDolGlobalString('MAIN_ODT_AS_PDF')) {
373 try {
374 $odfHandler->exportAsAttachedPDF($file);
375 } catch (Exception $e) {
376 $this->error = $e->getMessage();
377 dol_syslog($e->getMessage(), LOG_WARNING);
378 return -1;
379 }
380 } else {
381 try {
382 $odfHandler->saveToDisk($file);
383 } catch (Exception $e) {
384 $this->error = $e->getMessage();
385 dol_syslog($e->getMessage(), LOG_WARNING);
386 return -1;
387 }
388 }
389
390 $reshook = $hookmanager->executeHooks('afterODTCreation', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
391
392 dolChmod($file);
393
394 $odfHandler = null; // Destroy object
395
396 $this->result = array('fullpath'=>$file);
397
398 return 1; // Success
399 } else {
400 $this->error = $langs->transnoentities("ErrorCanNotCreateDir", $dir);
401 return -1;
402 }
403 }
404
405 return -1;
406 }
407
408 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
417 public function get_substitutionarray_object($object, $outputlangs, $array_key = 'object')
418 {
419 // phpcs:enable
420 $array_other = array();
421 foreach ($object as $key => $value) {
422 if (!is_array($value) && !is_object($value)) {
423 $array_other[$array_key.'_'.$key] = $value;
424 }
425 }
426 return $array_other;
427 }
428}
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 generation of HTML components Only common components must be here.
Class to manage hooks.
Parent class for documents models.
Class to manage Dolibarr users.
Class to build documents using ODF templates generator.
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.
get_substitutionarray_object($object, $outputlangs, $array_key='object')
get substitution array for object
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.
dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0, $nbsecondsold=0)
Scan a directory and return a list of files/directories.
Definition files.lib.php:62
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
dolChmod($filepath, $newmask='')
Change mod of a file.
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)
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.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
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:121
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition repair.php:124
getMaxFileSizeArray()
Return the max allowed for file upload.