dolibarr 19.0.3
doc_generic_member_odt.class.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-2021 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/member/modules_member.class.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 $conf, $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 = 'MEMBER_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 FACTURE_TVAOPTION
75 $this->option_modereg = 0; // Display payment mode
76 $this->option_condreg = 0; // Display payment terms
77 $this->option_multilang = 1; // Available in several languages
78 $this->option_escompte = 0; // Displays if there has been a discount
79 $this->option_credit_note = 0; // Support credit notes
80 $this->option_freetext = 1; // Support add of a personalised text
81 $this->option_draft_watermark = 0; // Support add of a watermark on drafts
82
83 // Recupere emetteur
84 $this->emetteur = $mysoc;
85 if (!$this->emetteur->country_code) {
86 $this->emetteur->country_code = substr($langs->defaultlang, -2); // By default if not defined
87 }
88 }
89
90
97 public function info($langs)
98 {
99 global $langs;
100
101 // Load translation files required by the page
102 $langs->loadLangs(array('companies', 'errors'));
103
104 $form = new Form($this->db);
105
106 $texte = $this->description.".<br>\n";
107 $texte .= '<form action="'.$_SERVER["PHP_SELF"].'" method="POST" enctype="multipart/form-data">';
108 $texte .= '<input type="hidden" name="token" value="'.newToken().'">';
109 $texte .= '<input type="hidden" name="page_y" value="">';
110 $texte .= '<input type="hidden" name="action" value="setModuleOptions">';
111 $texte .= '<input type="hidden" name="param1" value="MEMBER_ADDON_PDF_ODT_PATH">';
112 $texte .= '<table class="nobordernopadding" width="100%">';
113
114 // List of directories area
115 $texte .= '<tr><td>';
116 $texttitle = $langs->trans("ListOfDirectories");
117 $listofdir = explode(',', preg_replace('/[\r\n]+/', ',', trim(getDolGlobalString('MEMBER_ADDON_PDF_ODT_PATH'))));
118 $listoffiles = array();
119 foreach ($listofdir as $key => $tmpdir) {
120 $tmpdir = trim($tmpdir);
121 $tmpdir = preg_replace('/DOL_DATA_ROOT/', DOL_DATA_ROOT, $tmpdir);
122 if (!$tmpdir) {
123 unset($listofdir[$key]);
124 continue;
125 }
126 if (!is_dir($tmpdir)) {
127 $texttitle .= img_warning($langs->trans("ErrorDirNotFound", $tmpdir), 0);
128 } else {
129 $tmpfiles = dol_dir_list($tmpdir, 'files', 0, '\.(ods|odt)');
130 if (count($tmpfiles)) {
131 $listoffiles = array_merge($listoffiles, $tmpfiles);
132 }
133 }
134 }
135 $texthelp = $langs->trans("ListOfDirectoriesForModelGenODT");
136 $texthelp .= '<br><br><span class="opacitymedium">'.$langs->trans("ExampleOfDirectoriesForModelGen").'</span>';
137 // Add list of substitution keys
138 $texthelp .= '<br>'.$langs->trans("FollowingSubstitutionKeysCanBeUsed").'<br>';
139 $texthelp .= $langs->transnoentitiesnoconv("FullListOnOnlineDocumentation"); // This contains an url, we don't modify it
140
141 $texte .= $form->textwithpicto($texttitle, $texthelp, 1, 'help', '', 1, 3, $this->name);
142 $texte .= '<div><div style="display: inline-block; min-width: 100px; vertical-align: middle;">';
143 $texte .= '<textarea class="flat" cols="60" name="value1">';
144 $texte .= getDolGlobalString('MEMBER_ADDON_PDF_ODT_PATH');
145 $texte .= '</textarea>';
146 $texte .= '</div><div style="display: inline-block; vertical-align: middle;">';
147 $texte .= '<input type="submit" class="button button-edit reposition smallpaddingimp" name="modify" value="'.dol_escape_htmltag($langs->trans("Modify")).'">';
148 $texte .= '<br></div></div>';
149
150 // Scan directories
151 if (count($listofdir)) {
152 $texte .= $langs->trans("NumberOfModelFilesFound").': <b>'.count($listoffiles).'</b>';
153
154 $texte .= '<div id="div_'.get_class($this).'" class="hiddenx">';
155 // Show list of found files
156 foreach ($listoffiles as $file) {
157 $texte .= '- '.$file['name'].' <a href="'.DOL_URL_ROOT.'/document.php?modulepart=doctemplates&file=members/'.urlencode(basename($file['name'])).'">'.img_picto('', 'listlight').'</a>';
158 $texte .= ' &nbsp; <a class="reposition" href="'.$_SERVER["PHP_SELF"].'?modulepart=doctemplates&keyforuploaddir=MEMBER_ADDON_PDF_ODT_PATH&action=deletefile&token='.newToken().'&file='.urlencode(basename($file['name'])).'">'.img_picto('', 'delete').'</a>';
159 $texte .= '<br>';
160 }
161 $texte .= '</div>';
162 }
163 // Add input to upload a new template file.
164 $texte .= '<div>'.$langs->trans("UploadNewTemplate");
165 $maxfilesizearray = getMaxFileSizeArray();
166 $maxmin = $maxfilesizearray['maxmin'];
167 if ($maxmin > 0) {
168 $texte .= '<input type="hidden" name="MAX_FILE_SIZE" value="'.($maxmin * 1024).'">'; // MAX_FILE_SIZE must precede the field type=file
169 }
170 $texte .= ' <input type="file" name="uploadfile">';
171 $texte .= '<input type="hidden" value="MEMBER_ADDON_PDF_ODT_PATH" name="keyforuploaddir">';
172 $texte .= '<input type="submit" class="button smallpaddingimp reposition" value="'.dol_escape_htmltag($langs->trans("Upload")).'" name="upload">';
173 $texte .= '</div>';
174 $texte .= '</td>';
175
176 $texte .= '</tr>';
177
178 $texte .= '</table>';
179 $texte .= '</form>';
180
181 return $texte;
182 }
183
184 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
196 public function write_file($object, $outputlangs, $srctemplatepath, $mode = 'member', $nooutput = 0, $filename = 'tmp_cards')
197 {
198 // phpcs:enable
199 global $user, $langs, $conf, $mysoc, $hookmanager;
200
201 if (empty($srctemplatepath)) {
202 dol_syslog("doc_generic_odt::write_file parameter srctemplatepath empty", LOG_WARNING);
203 return -1;
204 }
205
206 // Add odtgeneration hook
207 if (!is_object($hookmanager)) {
208 include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
209 $hookmanager = new HookManager($this->db);
210 }
211 $hookmanager->initHooks(array('odtgeneration'));
212 global $action;
213
214 if (!is_object($outputlangs)) {
215 $outputlangs = $langs;
216 }
217 $sav_charset_output = $outputlangs->charset_output;
218 $outputlangs->charset_output = 'UTF-8';
219
220 // Load translation files required by the page
221 $outputlangs->loadLangs(array("main", "companies", "bills", "dict"));
222
223 if ($conf->adherent->dir_output) {
224 // If $object is id instead of object
225 if (!is_object($object)) {
226 $id = $object;
227 $object = new User($this->db);
228 $result = $object->fetch($id);
229 if ($result < 0) {
230 dol_print_error($this->db, $object->error);
231 return -1;
232 }
233 }
234
235 $object->fetch_thirdparty();
236
237 $dir = $conf->adherent->dir_output;
238 $objectref = dol_sanitizeFileName($object->ref);
239 if (!preg_match('/specimen/i', $objectref)) {
240 $dir .= "/".$objectref;
241 }
242 $file = $dir."/".$objectref.".odt";
243
244 if (!file_exists($dir)) {
245 if (dol_mkdir($dir) < 0) {
246 $this->error = $langs->transnoentities("ErrorCanNotCreateDir", $dir);
247 return -1;
248 }
249 }
250
251 if (file_exists($dir)) {
252 //print "srctemplatepath=".$srctemplatepath; // Src filename
253 $newfile = basename($srctemplatepath);
254 $newfiletmp = preg_replace('/\.od[ts]/i', '', $newfile);
255 $newfiletmp = preg_replace('/template_/i', '', $newfiletmp);
256 $newfiletmp = preg_replace('/modele_/i', '', $newfiletmp);
257
258 $newfiletmp = $objectref . '_' . $newfiletmp;
259
260 // Get extension (ods or odt)
261 $newfileformat = substr($newfile, strrpos($newfile, '.') + 1);
262 if (getDolGlobalString('MAIN_DOC_USE_TIMING')) {
263 $format = getDolGlobalString('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 //print "newdir=".$dir;
273 //print "newfile=".$newfile;
274 //print "file=".$file;
275 //print "conf->adherent->dir_temp=".$conf->adherent->dir_temp;
276
277 dol_mkdir($conf->adherent->dir_temp);
278 if (!is_writable($conf->adherent->dir_temp)) {
279 $this->error = $langs->transnoentities("ErrorFailedToWriteInTempDirectory", $conf->adherent->dir_temp);
280 dol_syslog('Error in write_file: ' . $this->error, LOG_ERR);
281 return -1;
282 }
283
284 // If CUSTOMER contact defined on member, we use it
285 $usecontact = false;
286 $arrayidcontact = $object->getIdContact('external', 'CUSTOMER');
287 if (count($arrayidcontact) > 0) {
288 $usecontact = true;
289 $result = $object->fetch_contact($arrayidcontact[0]);
290 }
291
292 // Recipient name
293 if (!empty($usecontact)) {
294 // We can use the company of contact instead of thirdparty company
295 if ($object->contact->socid != $object->thirdparty->id && (!isset($conf->global->MAIN_USE_COMPANY_NAME_OF_CONTACT) || getDolGlobalString('MAIN_USE_COMPANY_NAME_OF_CONTACT'))) {
296 $object->contact->fetch_thirdparty();
297 $socobject = $object->contact->thirdparty;
298 $contactobject = $object->contact;
299 } else {
300 $socobject = $object->thirdparty;
301 // if we have a CUSTOMER contact and we dont use it as thirdparty recipient we store the contact object for later use
302 $contactobject = $object->contact;
303 }
304 } else {
305 $socobject = $object->thirdparty;
306 }
307
308 // Open and load template
309 require_once ODTPHP_PATH.'odf.php';
310 try {
311 $odfHandler = new Odf(
312 $srctemplatepath,
313 array(
314 'PATH_TO_TMP' => $conf->adherent->dir_temp,
315 'ZIP_PROXY' => getDolGlobalString('MAIN_ODF_ZIP_PROXY', 'PclZipProxy'), // PhpZipProxy or PclZipProxy. Got "bad compression method" error when using PhpZipProxy.
316 'DELIMITER_LEFT' => '{',
317 'DELIMITER_RIGHT' => '}'
318 )
319 );
320 } catch (Exception $e) {
321 $this->error = $e->getMessage();
322 dol_syslog($e->getMessage(), LOG_WARNING);
323 return -1;
324 }
325
326 // Make substitutions into odt
327 $array_member = $this->getSubstitutionarrayMember($object, $outputlangs);
328 $array_soc = $this->get_substitutionarray_mysoc($mysoc, $outputlangs);
329 $array_thirdparty = $this->get_substitutionarray_thirdparty($socobject, $outputlangs);
330 $array_other = $this->get_substitutionarray_other($outputlangs);
331 // retrieve contact information for use in object as contact_xxx tags
332 $array_thirdparty_contact = array();
333 if ($usecontact && is_object($contactobject)) {
334 $array_thirdparty_contact = $this->get_substitutionarray_contact($contactobject, $outputlangs, 'contact');
335 }
336
337 $tmparray = array_merge($array_member, $array_soc, $array_thirdparty, $array_other, $array_thirdparty_contact);
338 complete_substitutions_array($tmparray, $outputlangs, $object);
339 // Call the ODTSubstitution hook
340 $parameters = array(
341 'file'=>$file,
342 'object'=>$object,
343 'outputlangs'=>$outputlangs,
344 'substitutionarray'=>&$tmparray
345 );
346 $reshook = $hookmanager->executeHooks('ODTSubstitution', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
347 foreach ($tmparray as $key => $value) {
348 try {
349 if (preg_match('/logo$/', $key)) {
350 // Image
351 if (file_exists($value)) {
352 $odfHandler->setImage($key, $value);
353 } else {
354 $odfHandler->setVars($key, 'ErrorFileNotFound', true, 'UTF-8');
355 }
356 } else {
357 // Text
358 $odfHandler->setVars($key, $value, true, 'UTF-8');
359 }
360 } catch (OdfException $e) {
361 dol_syslog($e->getMessage(), LOG_WARNING);
362 }
363 }
364
365 // Replace labels translated
366 $tmparray = $outputlangs->get_translations_for_substitutions();
367 foreach ($tmparray as $key => $value) {
368 try {
369 $odfHandler->setVars($key, $value, true, 'UTF-8');
370 } catch (OdfException $e) {
371 dol_syslog($e->getMessage(), LOG_WARNING);
372 }
373 }
374
375 // Call the beforeODTSave hook
376 $parameters = array('odfHandler'=>&$odfHandler, 'file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs);
377 $reshook = $hookmanager->executeHooks('beforeODTSave', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
378
379 // Write new file
380 if (getDolGlobalString('MAIN_ODT_AS_PDF')) {
381 try {
382 $odfHandler->exportAsAttachedPDF($file);
383 } catch (Exception $e) {
384 $this->error = $e->getMessage();
385 dol_syslog($e->getMessage(), LOG_WARNING);
386 return -1;
387 }
388 } else {
389 try {
390 $odfHandler->saveToDisk($file);
391 } catch (Exception $e) {
392 $this->error = $e->getMessage();
393 dol_syslog($e->getMessage(), LOG_WARNING);
394 return -1;
395 }
396 }
397
398 $reshook = $hookmanager->executeHooks('afterODTCreation', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
399
400 dolChmod($file);
401
402 $odfHandler = null; // Destroy object
403
404 $this->result = array('fullpath'=>$file);
405
406 return 1; // Success
407 } else {
408 $this->error = $langs->transnoentities("ErrorCanNotCreateDir", $dir);
409 return -1;
410 }
411 }
412
413 return -1;
414 }
415
416 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
425 public function get_substitutionarray_object($object, $outputlangs, $array_key = 'object')
426 {
427 // phpcs:enable
428 $array_other = array();
429 foreach ($object as $key => $value) {
430 if (!is_array($value) && !is_object($value)) {
431 $array_other[$array_key.'_'.$key] = $value;
432 }
433 }
434 return $array_other;
435 }
436}
getSubstitutionarrayMember($member, $outputlangs)
Define array with couple substitution key => substitution value.
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}...
Class to manage generation of HTML components Only common components must be here.
Class to manage hooks.
Parent class to manage intervention document templates.
Class to manage Dolibarr users.
Class to build documents using ODF templates generator.
info($langs)
Return description of a module.
get_substitutionarray_object($object, $outputlangs, $array_key='object')
get substitution array for object
write_file($object, $outputlangs, $srctemplatepath, $mode='member', $nooutput=0, $filename='tmp_cards')
Function to build a document on disk using the generic odt module.
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.