Passed
Branch develop (21edb4)
by
unknown
41:33
created

doc_generic_usergroup_odt   C

Complexity

Total Complexity 53

Size/Duplication

Total Lines 466
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 280
dl 0
loc 466
rs 6.96
c 1
b 0
f 0
wmc 53

3 Methods

Rating   Name   Duplication   Size   Complexity  
B info() 0 96 8
A __construct() 0 37 2
F write_file() 0 283 43

How to fix   Complexity   

Complex Class

Complex classes like doc_generic_usergroup_odt often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use doc_generic_usergroup_odt, and based on these observations, apply Extract Interface, too.

1
<?php
2
/* Copyright (C) 2010-2012 	Laurent Destailleur <[email protected]>
3
 * Copyright (C) 2012		Juanjo Menent		<[email protected]>
4
 * Copyright (C) 2018       Frédéric France     <[email protected]>
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
21
/**
22
 *	\file       htdocs/core/modules/user/doc/doc_generic_user_odt.modules.php
23
 *	\ingroup    societe
24
 *	\brief      File of class to build ODT documents for third parties
25
 */
26
27
require_once DOL_DOCUMENT_ROOT.'/core/modules/usergroup/modules_usergroup.class.php';
28
require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
29
require_once DOL_DOCUMENT_ROOT.'/user/class/usergroup.class.php';
30
require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
31
require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
32
require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
33
require_once DOL_DOCUMENT_ROOT.'/core/lib/doc.lib.php';
34
35
36
/**
37
 *	Class to build documents using ODF templates generator
38
 */
39
class doc_generic_usergroup_odt extends ModelePDFUserGroup
40
{
41
	/**
42
	 * Issuer
43
	 * @var Societe
44
	 */
45
	public $emetteur;
46
47
	/**
48
	 * @var array Minimum version of PHP required by module.
49
	 * e.g.: PHP ≥ 5.6 = array(5, 6)
50
	 */
51
	public $phpmin = array(5, 6);
52
53
	/**
54
	 * Dolibarr version of the loaded document
55
	 * @var string
56
	 */
57
	public $version = 'dolibarr';
58
59
60
	/**
61
	 *	Constructor
62
	 *
63
	 *  @param		DoliDB		$db      Database handler
64
	 */
65
	public function __construct($db)
66
	{
67
		global $conf, $langs, $mysoc;
68
69
		// Load translation files required by the page
70
		$langs->loadLangs(array("main", "companies"));
71
72
		$this->db = $db;
73
		$this->name = "ODT templates";
74
		$this->description = $langs->trans("DocumentModelOdt");
75
		$this->scandir = 'USERGROUP_ADDON_PDF_ODT_PATH'; // Name of constant that is used to save list of directories to scan
76
77
		// Page size for A4 format
78
		$this->type = 'odt';
79
		$this->page_largeur = 0;
80
		$this->page_hauteur = 0;
81
		$this->format = array($this->page_largeur, $this->page_hauteur);
82
		$this->marge_gauche = 0;
83
		$this->marge_droite = 0;
84
		$this->marge_haute = 0;
85
		$this->marge_basse = 0;
86
87
		$this->option_logo = 1; // Display logo
88
		$this->option_tva = 0; // Manage the vat option USERGROUP_TVAOPTION
89
		$this->option_modereg = 0; // Display payment mode
90
		$this->option_condreg = 0; // Display payment terms
91
		$this->option_codeproduitservice = 0; // Display product-service code
92
		$this->option_multilang = 1; // Available in several languages
93
		$this->option_escompte = 0; // Displays if there has been a discount
94
		$this->option_credit_note = 0; // Support credit notes
95
		$this->option_freetext = 1; // Support add of a personalised text
96
		$this->option_draft_watermark = 0; // Support add of a watermark on drafts
97
98
		// Get source company
99
		$this->emetteur = $mysoc;
100
		if (!$this->emetteur->country_code) {
101
			$this->emetteur->country_code = substr($langs->defaultlang, -2); // By default if not defined
102
		}
103
	}
104
105
106
	/**
107
	 *	Return description of a module
108
	 *
109
	 *	@param	Translate	$langs      Lang object to use for output
110
	 *	@return string       			Description
111
	 */
112
	public function info($langs)
113
	{
114
		global $conf, $langs;
115
116
		// Load translation files required by the page
117
		$langs->loadLangs(array("errors", "companies"));
118
119
		$form = new Form($this->db);
120
121
		$texte = $this->description.".<br>\n";
122
		$texte .= '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
123
		$texte .= '<input type="hidden" name="token" value="'.newToken().'">';
124
		$texte .= '<input type="hidden" name="action" value="setModuleOptions">';
125
		$texte .= '<input type="hidden" name="param1" value="USERGROUP_ADDON_PDF_ODT_PATH">';
126
		if ($conf->global->MAIN_PROPAL_CHOOSE_ODT_DOCUMENT > 0) {
127
			$texte .= '<input type="hidden" name="param2" value="USERGROUP_ADDON_PDF_ODT_DEFAULT">';
128
			$texte .= '<input type="hidden" name="param3" value="USERGROUP_ADDON_PDF_ODT_TOBILL">';
129
			$texte .= '<input type="hidden" name="param4" value="USERGROUP_ADDON_PDF_ODT_CLOSED">';
130
		}
131
		$texte .= '<table class="nobordernopadding" width="100%">';
132
133
		// List of directories area
134
		$texte .= '<tr><td>';
135
		$texttitle = $langs->trans("ListOfDirectories");
136
		$listofdir = explode(',', preg_replace('/[\r\n]+/', ',', trim($conf->global->USERGROUP_ADDON_PDF_ODT_PATH)));
137
		$listoffiles = array();
138
		foreach ($listofdir as $key => $tmpdir) {
139
			$tmpdir = trim($tmpdir);
140
			$tmpdir = preg_replace('/DOL_DATA_ROOT/', DOL_DATA_ROOT, $tmpdir);
141
			if (!$tmpdir) {
142
				unset($listofdir[$key]);
143
				continue;
144
			}
145
			if (!is_dir($tmpdir)) {
146
				$texttitle .= img_warning($langs->trans("ErrorDirNotFound", $tmpdir), 0);
147
			} else {
148
				$tmpfiles = dol_dir_list($tmpdir, 'files', 0, '\.(ods|odt)');
149
				if (count($tmpfiles)) {
150
					$listoffiles = array_merge($listoffiles, $tmpfiles);
151
				}
152
			}
153
		}
154
		$texthelp = $langs->trans("ListOfDirectoriesForModelGenODT");
155
		// Add list of substitution keys
156
		$texthelp .= '<br>'.$langs->trans("FollowingSubstitutionKeysCanBeUsed").'<br>';
157
		$texthelp .= $langs->transnoentitiesnoconv("FullListOnOnlineDocumentation"); // This contains an url, we don't modify it
158
159
		$texte .= $form->textwithpicto($texttitle, $texthelp, 1, 'help', '', 1);
160
		$texte .= '<div><div style="display: inline-block; min-width: 100px; vertical-align: middle;">';
161
		$texte .= '<textarea class="flat" cols="60" name="value1">';
162
		$texte .= $conf->global->USERGROUP_ADDON_PDF_ODT_PATH;
163
		$texte .= '</textarea>';
164
		$texte .= '</div><div style="display: inline-block; vertical-align: middle;">';
165
		$texte .= '<input type="submit" class="button small" value="'.$langs->trans("Modify").'" name="Button">';
166
		$texte .= '<br></div></div>';
167
168
		// Scan directories
169
		if (count($listofdir)) {
170
			$texte .= $langs->trans("NumberOfModelFilesFound").': <b>'.count($listoffiles).'</b>';
171
172
			if ($conf->global->MAIN_PROPAL_CHOOSE_ODT_DOCUMENT > 0) {
173
				// Model for creation
174
				$list = ModelePDFUserGroup::liste_modeles($this->db);
175
				$texte .= '<table width="50%;">';
176
				$texte .= '<tr>';
177
				$texte .= '<td width="60%;">'.$langs->trans("DefaultModelPropalCreate").'</td>';
178
				$texte .= '<td colspan="">';
179
				$texte .= $form->selectarray('value2', $list, $conf->global->USERGROUP_ADDON_PDF_ODT_DEFAULT);
180
				$texte .= "</td></tr>";
181
182
				$texte .= '<tr>';
183
				$texte .= '<td width="60%;">'.$langs->trans("DefaultModelPropalToBill").'</td>';
184
				$texte .= '<td colspan="">';
185
				$texte .= $form->selectarray('value3', $list, $conf->global->USERGROUP_ADDON_PDF_ODT_TOBILL);
186
				$texte .= "</td></tr>";
187
				$texte .= '<tr>';
188
189
				$texte .= '<td width="60%;">'.$langs->trans("DefaultModelPropalClosed").'</td>';
190
				$texte .= '<td colspan="">';
191
				$texte .= $form->selectarray('value4', $list, $conf->global->USERGROUP_ADDON_PDF_ODT_CLOSED);
192
				$texte .= "</td></tr>";
193
				$texte .= '</table>';
194
			}
195
		}
196
197
		$texte .= '</td>';
198
199
		$texte .= '<td rowspan="2" class="tdtop hideonsmartphone">';
200
		$texte .= $langs->trans("ExampleOfDirectoriesForModelGen");
201
		$texte .= '</td>';
202
		$texte .= '</tr>';
203
204
		$texte .= '</table>';
205
		$texte .= '</form>';
206
207
		return $texte;
208
	}
209
210
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
211
	/**
212
	 *	Function to build a document on disk using the generic odt module.
213
	 *
214
	 *	@param		UserGroup		$object				Object source to build document
215
	 *	@param		Translate	$outputlangs		Lang output object
216
	 * 	@param		string		$srctemplatepath	Full path of source filename for generator using a template file
217
	 *  @param		int			$hidedetails		Do not show line details
218
	 *  @param		int			$hidedesc			Do not show desc
219
	 *  @param		int			$hideref			Do not show ref
220
	 *	@return		int         					1 if OK, <=0 if KO
221
	 */
222
	public function write_file($object, $outputlangs, $srctemplatepath, $hidedetails = 0, $hidedesc = 0, $hideref = 0)
223
	{
224
		// phpcs:enable
225
		global $user, $langs, $conf, $mysoc, $hookmanager;
226
227
		if (empty($srctemplatepath)) {
228
			dol_syslog("doc_generic_odt::write_file parameter srctemplatepath empty", LOG_WARNING);
229
			return -1;
230
		}
231
232
		// Add odtgeneration hook
233
		if (!is_object($hookmanager)) {
234
			include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
235
			$hookmanager = new HookManager($this->db);
236
		}
237
		$hookmanager->initHooks(array('odtgeneration'));
238
		global $action;
239
240
		if (!is_object($outputlangs)) {
241
			$outputlangs = $langs;
242
		}
243
		$sav_charset_output = $outputlangs->charset_output;
244
		$outputlangs->charset_output = 'UTF-8';
245
246
		// Load translation files required by the page
247
		$outputlangs->loadLangs(array("main", "companies", "bills", "dict"));
248
249
		if ($conf->user->dir_output) {
250
			// If $object is id instead of object
251
			if (!is_object($object)) {
252
				$id = $object;
253
				$object = new UserGroup($this->db);
254
				$result = $object->fetch($id);
255
				if ($result < 0) {
256
					dol_print_error($this->db, $object->error);
257
					return -1;
258
				}
259
			}
260
261
			$dir = $conf->usergroup->dir_output;
262
			$objectref = dol_sanitizeFileName($object->ref);
263
			if (!preg_match('/specimen/i', $objectref)) {
264
				$dir .= "/".$objectref;
265
			}
266
			$file = $dir."/".$objectref.".odt";
267
268
			if (!file_exists($dir)) {
269
				if (dol_mkdir($dir) < 0) {
270
					$this->error = $langs->transnoentities("ErrorCanNotCreateDir", $dir);
271
					return -1;
272
				}
273
			}
274
275
			if (file_exists($dir)) {
276
				//print "srctemplatepath=".$srctemplatepath;	// Src filename
277
				$newfile = basename($srctemplatepath);
278
				$newfiletmp = preg_replace('/\.od(t|s)/i', '', $newfile);
279
				$newfiletmp = preg_replace('/template_/i', '', $newfiletmp);
280
				$newfiletmp = preg_replace('/modele_/i', '', $newfiletmp);
281
282
				$newfiletmp = $objectref.'_'.$newfiletmp;
283
284
				// Get extension (ods or odt)
285
				$newfileformat = substr($newfile, strrpos($newfile, '.') + 1);
286
				if (!empty($conf->global->MAIN_DOC_USE_TIMING)) {
287
					$format = $conf->global->MAIN_DOC_USE_TIMING;
288
					if ($format == '1') {
289
						$format = '%Y%m%d%H%M%S';
290
					}
291
					$filename = $newfiletmp.'-'.dol_print_date(dol_now(), $format).'.'.$newfileformat;
292
				} else {
293
					$filename = $newfiletmp.'.'.$newfileformat;
294
				}
295
				$file = $dir.'/'.$filename;
296
				//print "newdir=".$dir;
297
				//print "newfile=".$newfile;
298
				//print "file=".$file;
299
				//print "conf->user->dir_temp=".$conf->user->dir_temp;
300
301
				dol_mkdir($conf->user->dir_temp);
302
				if (!is_writable($conf->user->dir_temp)) {
303
					$this->error = "Failed to write in temp directory ".$conf->user->dir_temp;
304
					dol_syslog('Error in write_file: '.$this->error, LOG_ERR);
305
					return -1;
306
				}
307
308
				// If CUSTOMER contact defined on user, we use it
309
				$usecontact = false;
310
				$arrayidcontact = $object->getIdContact('external', 'CUSTOMER');
311
				if (count($arrayidcontact) > 0) {
312
					$usecontact = true;
313
					$result = $object->fetch_contact($arrayidcontact[0]);
314
				}
315
316
				// Recipient name
317
				if (!empty($usecontact)) {
318
					if ($usecontact && ($object->contact->fk_soc != $object->thirdparty->id && (!isset($conf->global->MAIN_USE_COMPANY_NAME_OF_CONTACT) || !empty($conf->global->MAIN_USE_COMPANY_NAME_OF_CONTACT)))) {
319
						$socobject = $object->contact;
320
					} else {
321
						$socobject = $object->thirdparty;
322
						// if we have a CUSTOMER contact and we dont use it as recipient we store the contact object for later use
323
						$contactobject = $object->contact;
324
					}
325
				} else {
326
					$socobject = $object->thirdparty;
327
				}
328
				// Make substitution
329
				$substitutionarray = array(
330
				'__FROM_NAME__' => $this->emetteur->name,
331
				'__FROM_EMAIL__' => $this->emetteur->email,
332
				'__TOTAL_TTC__' => $object->total_ttc,
333
				'__TOTAL_HT__' => $object->total_ht,
334
				'__TOTAL_VAT__' => $object->total_tva
335
				);
336
				complete_substitutions_array($substitutionarray, $langs, $object);
337
				// Call the ODTSubstitution hook
338
				$parameters = array('file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs, 'substitutionarray'=>&$substitutionarray);
339
				$reshook = $hookmanager->executeHooks('ODTSubstitution', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
340
341
				// Line of free text
342
				$newfreetext = '';
343
				$paramfreetext = 'user_FREE_TEXT';
344
				if (!empty($conf->global->$paramfreetext)) {
345
					$newfreetext = make_substitutions($conf->global->$paramfreetext, $substitutionarray);
346
				}
347
348
				// Open and load template
349
				require_once ODTPHP_PATH.'odf.php';
350
				try {
351
					$odfHandler = new odf(
352
						$srctemplatepath,
353
						array(
354
							'PATH_TO_TMP'	  => $conf->user->dir_temp,
355
							'ZIP_PROXY'		  => 'PclZipProxy', // PhpZipProxy or PclZipProxy. Got "bad compression method" error when using PhpZipProxy.
356
							'DELIMITER_LEFT'  => '{',
357
							'DELIMITER_RIGHT' => '}'
358
						)
359
					);
360
				} catch (Exception $e) {
361
					$this->error = $e->getMessage();
362
					dol_syslog($e->getMessage(), LOG_WARNING);
363
					return -1;
364
				}
365
				// After construction $odfHandler->contentXml contains content and
366
				// [!-- BEGIN row.lines --]*[!-- END row.lines --] has been replaced by
367
				// [!-- BEGIN lines --]*[!-- END lines --]
368
				//print html_entity_decode($odfHandler->__toString());
369
				//print exit;
370
371
372
				// Make substitutions into odt of freetext
373
				try {
374
					$odfHandler->setVars('free_text', $newfreetext, true, 'UTF-8');
375
				} catch (OdfException $e) {
376
					dol_syslog($e->getMessage(), LOG_WARNING);
377
				}
378
379
				// Make substitutions into odt
380
				$array_user = $this->get_substitutionarray_user($user, $outputlangs);
381
				$array_global = $this->get_substitutionarray_each_var_object($object, $outputlangs);
382
				$array_soc = $this->get_substitutionarray_mysoc($mysoc, $outputlangs);
383
				$array_thirdparty = $this->get_substitutionarray_thirdparty($socobject, $outputlangs);
384
				$array_objet = $this->get_substitutionarray_each_var_object($object, $outputlangs);
385
				$array_other = $this->get_substitutionarray_other($outputlangs);
386
				// retrieve contact information for use in object as contact_xxx tags
387
				$array_thirdparty_contact = array();
388
				if ($usecontact && is_object($contactobject)) {
389
					$array_thirdparty_contact = $this->get_substitutionarray_contact($contactobject, $outputlangs, 'contact');
390
				}
391
392
				$tmparray = array_merge($array_global, $array_user, $array_soc, $array_thirdparty, $array_objet, $array_other, $array_thirdparty_contact);
393
				complete_substitutions_array($tmparray, $outputlangs, $object);
394
				$object->fetch_optionals();
395
				// Call the ODTSubstitution hook
396
				$parameters = array('file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs, 'substitutionarray'=>&$tmparray);
397
				$reshook = $hookmanager->executeHooks('ODTSubstitution', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
398
				foreach ($tmparray as $key => $value) {
399
					try {
400
						if (preg_match('/logo$/', $key)) { // Image
401
							if (file_exists($value)) {
402
								$odfHandler->setImage($key, $value);
403
							} else {
404
								$odfHandler->setVars($key, 'ErrorFileNotFound', true, 'UTF-8');
405
							}
406
						} else // Text
407
						{
408
							$odfHandler->setVars($key, $value, true, 'UTF-8');
409
						}
410
					} catch (OdfException $e) {
411
						dol_syslog($e->getMessage(), LOG_WARNING);
412
					}
413
				}
414
				// Replace tags of lines
415
				try {
416
					$foundtagforlines = 1;
417
					try {
418
						$listlines = $odfHandler->setSegment('lines');
419
					} catch (OdfException $e) {
420
						// We may arrive here if tags for lines not present into template
421
						$foundtagforlines = 0;
422
						dol_syslog($e->getMessage(), LOG_INFO);
423
					}
424
					if ($foundtagforlines) {
425
						foreach ($object->members as $u) {
426
							$tmparray = $this->get_substitutionarray_each_var_object($u, $outputlangs);
427
							unset($tmparray['object_pass']);
428
							unset($tmparray['object_pass_indatabase']);
429
							complete_substitutions_array($tmparray, $outputlangs, $object, $user, "completesubstitutionarray_users");
430
							// Call the ODTSubstitutionLine hook
431
							$parameters = array('odfHandler'=>&$odfHandler, 'file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs, 'substitutionarray'=>&$tmparray, 'line'=>$u);
432
							$reshook = $hookmanager->executeHooks('ODTSubstitutionLine', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
433
							foreach ($tmparray as $key => $val) {
434
								try {
435
									if (!is_array($val)) {
436
										$listlines->setVars($key, $val, true, 'UTF-8');
437
									}
438
								} catch (OdfException $e) {
439
									dol_syslog($e->getMessage(), LOG_WARNING);
440
								} catch (SegmentException $e) {
441
									dol_syslog($e->getMessage(), LOG_WARNING);
442
								}
443
							}
444
							$listlines->merge();
445
						}
446
						$odfHandler->mergeSegment($listlines);
447
					}
448
				} catch (OdfException $e) {
449
					$this->error = $e->getMessage();
450
					dol_syslog($this->error, LOG_WARNING);
451
					return -1;
452
				}
453
454
				// Replace labels translated
455
				$tmparray = $outputlangs->get_translations_for_substitutions();
456
				foreach ($tmparray as $key => $value) {
457
					try {
458
						$odfHandler->setVars($key, $value, true, 'UTF-8');
459
					} catch (OdfException $e) {
460
						dol_syslog($e->getMessage(), LOG_WARNING);
461
					}
462
				}
463
464
				// Call the beforeODTSave hook
465
				$parameters = array('odfHandler'=>&$odfHandler, 'file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs);
466
				$reshook = $hookmanager->executeHooks('beforeODTSave', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
467
468
				// Write new file
469
				if (!empty($conf->global->MAIN_ODT_AS_PDF)) {
470
					try {
471
						$odfHandler->exportAsAttachedPDF($file);
472
					} catch (Exception $e) {
473
						$this->error = $e->getMessage();
474
						dol_syslog($e->getMessage(), LOG_WARNING);
475
						return -1;
476
					}
477
				} else {
478
					try {
479
						$odfHandler->saveToDisk($file);
480
					} catch (Exception $e) {
481
						$this->error = $e->getMessage();
482
						dol_syslog($e->getMessage(), LOG_WARNING);
483
						return -1;
484
					}
485
				}
486
487
				$reshook = $hookmanager->executeHooks('afterODTCreation', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
488
489
				if (!empty($conf->global->MAIN_UMASK)) {
490
					@chmod($file, octdec($conf->global->MAIN_UMASK));
491
				}
492
493
				$odfHandler = null; // Destroy object
494
495
				$this->result = array('fullpath'=>$file);
496
497
				return 1; // Success
498
			} else {
499
				$this->error = $langs->transnoentities("ErrorCanNotCreateDir", $dir);
500
				return -1;
501
			}
502
		}
503
504
		return -1;
505
	}
506
}
507