PageRenderTime 55ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/htdocs/propal/core/modules/propale/doc/doc_generic_proposal_odt.modules.php

https://bitbucket.org/speedealing/speedealing
PHP | 506 lines | 353 code | 55 blank | 98 comment | 34 complexity | 7a3c9d6661d84066dc6cd0a7f99f163a MD5 | raw file
Possible License(s): LGPL-3.0, LGPL-2.1, GPL-3.0, MIT
  1. <?php
  2. /* Copyright (C) 2010-2012 Laurent Destailleur <eldy@users.sourceforge.net>
  3. * Copyright (C) 2012 Juanjo Menent <jmenent@2byte.es>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. * or see http://www.gnu.org/
  18. */
  19. /**
  20. * \file htdocs/core/modules/propale/doc/doc_generic_proposal_odt.modules.php
  21. * \ingroup societe
  22. * \brief File of class to build ODT documents for third parties
  23. */
  24. require_once DOL_DOCUMENT_ROOT.'/core/modules/propale/modules_propale.php';
  25. require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
  26. require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
  27. require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
  28. require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
  29. require_once DOL_DOCUMENT_ROOT.'/core/lib/doc.lib.php';
  30. /**
  31. * Class to build documents using ODF templates generator
  32. */
  33. class doc_generic_proposal_odt extends ModelePDFPropales
  34. {
  35. var $emetteur; // Objet societe qui emet
  36. var $phpmin = array(5,2,0); // Minimum version of PHP required by module
  37. var $version = 'dolibarr';
  38. /**
  39. * Constructor
  40. *
  41. * @param DoliDB $db Database handler
  42. */
  43. function __construct($db = '')
  44. {
  45. global $conf,$langs,$mysoc;
  46. $langs->load("main");
  47. $langs->load("companies");
  48. $this->db = $db;
  49. $this->name = "ODT templates";
  50. $this->description = $langs->trans("DocumentModelOdt");
  51. $this->scandir = 'PROPALE_ADDON_PDF_ODT_PATH'; // Name of constant that is used to save list of directories to scan
  52. // Dimension page pour format A4
  53. $this->type = 'odt';
  54. $this->page_largeur = 0;
  55. $this->page_hauteur = 0;
  56. $this->format = array($this->page_largeur,$this->page_hauteur);
  57. $this->marge_gauche=0;
  58. $this->marge_droite=0;
  59. $this->marge_haute=0;
  60. $this->marge_basse=0;
  61. $this->option_logo = 1; // Affiche logo
  62. $this->option_tva = 0; // Gere option tva PROPALE_TVAOPTION
  63. $this->option_modereg = 0; // Affiche mode reglement
  64. $this->option_condreg = 0; // Affiche conditions reglement
  65. $this->option_codeproduitservice = 0; // Affiche code produit-service
  66. $this->option_multilang = 0; // Dispo en plusieurs langues
  67. $this->option_escompte = 0; // Affiche si il y a eu escompte
  68. $this->option_credit_note = 0; // Support credit notes
  69. $this->option_freetext = 1; // Support add of a personalised text
  70. $this->option_draft_watermark = 0; // Support add of a watermark on drafts
  71. // Recupere emetteur
  72. $this->emetteur=$mysoc;
  73. if (! $this->emetteur->pays_code) $this->emetteur->pays_code=substr($langs->defaultlang,-2); // Par defaut, si n'etait pas defini
  74. }
  75. /**
  76. * Define array with couple substitution key => substitution value
  77. *
  78. * @param Object $object Main object to use as data source
  79. * @param Translate $outputlangs Lang object to use for output
  80. * @return array Array of substitution
  81. */
  82. function get_substitutionarray_object($object,$outputlangs)
  83. {
  84. global $conf;
  85. return array(
  86. 'object_id'=>$object->id,
  87. 'object_ref'=>$object->ref,
  88. 'object_ref_ext'=>$object->ref_ext,
  89. 'object_ref_customer'=>$object->ref_client,
  90. 'object_date'=>dol_print_date($object->date,'day'),
  91. 'object_date_end'=>dol_print_date($object->fin_validite,'day'),
  92. 'object_date_creation'=>dol_print_date($object->date_creation,'day'),
  93. 'object_date_modification'=>dol_print_date($object->date_modification,'day'),
  94. 'object_date_validation'=>dol_print_date($object->date_validation,'dayhour'),
  95. 'object_payment_mode_code'=>$object->mode_reglement_code,
  96. 'object_payment_mode'=>($outputlangs->transnoentitiesnoconv('PaymentType'.$object->mode_reglement_code)!='PaymentType'.$object->mode_reglement_code?$outputlangs->transnoentitiesnoconv('PaymentType'.$object->mode_reglement_code):$object->mode_reglement),
  97. 'object_payment_term_code'=>$object->cond_reglement_code,
  98. 'object_payment_term'=>($outputlangs->transnoentitiesnoconv('PaymentCondition'.$object->cond_reglement_code)!='PaymentCondition'.$object->cond_reglement_code?$outputlangs->transnoentitiesnoconv('PaymentCondition'.$object->cond_reglement_code):$object->cond_reglement),
  99. 'object_total_ht'=>price($object->total_ht,0,$outputlangs),
  100. 'object_total_vat'=>price($object->total_tva,0,$outputlangs),
  101. 'object_total_ttc'=>price($object->total_ttc,0,$outputlangs),
  102. 'object_total_discount' => price($object->getTotalDiscount(), 0, $outputlangs),
  103. 'object_vatrate'=>vatrate($object->tva),
  104. 'object_note_private'=>$object->note,
  105. 'object_note'=>$object->note_public,
  106. );
  107. }
  108. /**
  109. * Define array with couple substitution key => substitution value
  110. *
  111. * @param array $line Array of lines
  112. * @param Translate $outputlangs Lang object to use for output
  113. * @return array Substitution array
  114. */
  115. function get_substitutionarray_lines($line,$outputlangs)
  116. {
  117. global $conf;
  118. return array(
  119. 'line_fulldesc'=>doc_getlinedesc($line,$outputlangs),
  120. 'line_product_ref'=>$line->product_ref,
  121. 'line_product_label'=>$line->product_label,
  122. 'line_desc'=>$line->desc,
  123. 'line_vatrate'=>vatrate($line->tva_tx,true,$line->info_bits),
  124. 'line_up'=>price($line->subprice, 0, $outputlangs),
  125. 'line_qty'=>$line->qty,
  126. 'line_discount_percent'=>($line->remise_percent?$line->remise_percent.'%':''),
  127. 'line_price_ht'=>price($line->total_ht, 0, $outputlangs),
  128. 'line_price_ttc'=>price($line->total_ttc, 0, $outputlangs),
  129. 'line_price_vat'=>price($line->total_tva, 0, $outputlangs),
  130. 'line_date_start'=>$line->date_start,
  131. 'line_date_end'=>$line->date_end
  132. );
  133. }
  134. /**
  135. * Return description of a module
  136. *
  137. * @param Translate $langs Lang object to use for output
  138. * @return string Description
  139. */
  140. function info($langs)
  141. {
  142. global $conf,$langs;
  143. $langs->load("companies");
  144. $langs->load("errors");
  145. $form = new Form($this->db);
  146. $texte = $this->description.".<br>\n";
  147. $texte.= '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
  148. $texte.= '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
  149. $texte.= '<input type="hidden" name="action" value="setModuleOptions">';
  150. $texte.= '<input type="hidden" name="param1" value="PROPALE_ADDON_PDF_ODT_PATH">';
  151. $texte.= '<table class="nobordernopadding" width="100%">';
  152. // List of directories area
  153. $texte.= '<tr><td>';
  154. $texttitle=$langs->trans("ListOfDirectories");
  155. $listofdir=explode(',',preg_replace('/[\r\n]+/',',',trim($conf->global->PROPALE_ADDON_PDF_ODT_PATH)));
  156. $listoffiles=array();
  157. foreach($listofdir as $key=>$tmpdir)
  158. {
  159. $tmpdir=trim($tmpdir);
  160. $tmpdir=preg_replace('/DOL_DATA_ROOT/',DOL_DATA_ROOT,$tmpdir);
  161. if (! $tmpdir) { unset($listofdir[$key]); continue; }
  162. if (! is_dir($tmpdir)) $texttitle.=img_warning($langs->trans("ErrorDirNotFound",$tmpdir),0);
  163. else
  164. {
  165. $tmpfiles=dol_dir_list($tmpdir,'files',0,'\.odt');
  166. if (count($tmpfiles)) $listoffiles=array_merge($listoffiles,$tmpfiles);
  167. }
  168. }
  169. $texthelp=$langs->trans("ListOfDirectoriesForModelGenODT");
  170. // Add list of substitution keys
  171. $texthelp.='<br>'.$langs->trans("FollowingSubstitutionKeysCanBeUsed").'<br>';
  172. $texthelp.=$langs->transnoentitiesnoconv("FullListOnOnlineDocumentation"); // This contains an url, we don't modify it
  173. $texte.= $form->textwithpicto($texttitle,$texthelp,1,'help','',1);
  174. $texte.= '<table><tr><td>';
  175. $texte.= '<textarea class="flat" cols="60" name="value1">';
  176. $texte.=$conf->global->PROPALE_ADDON_PDF_ODT_PATH;
  177. $texte.= '</textarea>';
  178. $texte.= '</td>';
  179. $texte.= '<td align="center">&nbsp; ';
  180. $texte.= '<input type="submit" class="button" value="'.$langs->trans("Modify").'" name="Button">';
  181. $texte.= '</td>';
  182. $texte.= '</tr>';
  183. $texte.= '</table>';
  184. // Scan directories
  185. if (count($listofdir)) $texte.=$langs->trans("NumberOfModelFilesFound").': <b>'.count($listoffiles).'</b>';
  186. $texte.= '</td>';
  187. $texte.= '<td valign="top" rowspan="2">';
  188. $texte.= $langs->trans("ExampleOfDirectoriesForModelGen");
  189. $texte.= '</td>';
  190. $texte.= '</tr>';
  191. /*$texte.= '<tr>';
  192. $texte.= '<td align="center">';
  193. $texte.= '<input type="submit" class="button" value="'.$langs->trans("Modify").'" name="Button">';
  194. $texte.= '</td>';
  195. $texte.= '</tr>';*/
  196. $texte.= '</table>';
  197. $texte.= '</form>';
  198. return $texte;
  199. }
  200. /**
  201. * Function to build a document on disk using the generic odt module.
  202. *
  203. * @param Propale $object Object source to build document
  204. * @param Translate $outputlangs Lang output object
  205. * @param string $srctemplatepath Full path of source filename for generator using a template file
  206. * @return int 1 if OK, <=0 if KO
  207. */
  208. function write_file($object,$outputlangs,$srctemplatepath)
  209. {
  210. global $user,$langs,$conf,$mysoc;
  211. if (empty($srctemplatepath))
  212. {
  213. dol_syslog("doc_generic_odt::write_file parameter srctemplatepath empty", LOG_WARNING);
  214. return -1;
  215. }
  216. if (! is_object($outputlangs)) $outputlangs=$langs;
  217. $sav_charset_output=$outputlangs->charset_output;
  218. $outputlangs->charset_output='UTF-8';
  219. $outputlangs->load("main");
  220. $outputlangs->load("dict");
  221. $outputlangs->load("companies");
  222. $outputlangs->load("bills");
  223. if ($conf->propal->dir_output)
  224. {
  225. // If $object is id instead of object
  226. if (! is_object($object))
  227. {
  228. $id = $object;
  229. $object = new Propale($this->db);
  230. $result=$object->fetch($id);
  231. if ($result < 0)
  232. {
  233. dol_print_error($this->db,$object->error);
  234. return -1;
  235. }
  236. }
  237. $dir = $conf->propal->dir_output;
  238. $objectref = dol_sanitizeFileName($object->ref);
  239. if (! preg_match('/specimen/i',$objectref)) $dir.= "/" . $objectref;
  240. $file = $dir . "/" . $objectref . ".odt";
  241. if (! file_exists($dir))
  242. {
  243. if (dol_mkdir($dir) < 0)
  244. {
  245. $this->error=$langs->transnoentities("ErrorCanNotCreateDir",$dir);
  246. return -1;
  247. }
  248. }
  249. if (file_exists($dir))
  250. {
  251. //print "srctemplatepath=".$srctemplatepath; // Src filename
  252. $newfile=basename($srctemplatepath);
  253. $newfiletmp=preg_replace('/\.odt/i','',$newfile);
  254. $newfiletmp=preg_replace('/template_/i','',$newfiletmp);
  255. $newfiletmp=preg_replace('/modele_/i','',$newfiletmp);
  256. $newfiletmp=$objectref.'_'.$newfiletmp;
  257. //$file=$dir.'/'.$newfiletmp.'.'.dol_print_date(dol_now(),'%Y%m%d%H%M%S').'.odt';
  258. $file=$dir.'/'.$newfiletmp.'.odt';
  259. //print "newdir=".$dir;
  260. //print "newfile=".$newfile;
  261. //print "file=".$file;
  262. //print "conf->societe->dir_temp=".$conf->societe->dir_temp;
  263. dol_mkdir($conf->propal->dir_temp);
  264. // If BILLING contact defined on invoice, we use it
  265. $usecontact=false;
  266. $arrayidcontact=$object->getIdContact('external','BILLING');
  267. if (count($arrayidcontact) > 0)
  268. {
  269. $usecontact=true;
  270. $result=$object->fetch_contact($arrayidcontact[0]);
  271. }
  272. // Recipient name
  273. if (! empty($usecontact))
  274. {
  275. // On peut utiliser le nom de la societe du contact
  276. if (! empty($conf->global->MAIN_USE_COMPANY_NAME_OF_CONTACT)) $socobject = $object->contact;
  277. else $socobject = $object->client;
  278. }
  279. else
  280. {
  281. $socobject=$object->client;
  282. }
  283. // Make substitution
  284. $substitutionarray=array(
  285. '__FROM_NAME__' => $this->emetteur->nom,
  286. '__FROM_EMAIL__' => $this->emetteur->email,
  287. '__TOTAL_TTC__' => $object->total_ttc,
  288. '__TOTAL_HT__' => $object->total_ht,
  289. '__TOTAL_VAT__' => $object->total_vat
  290. );
  291. complete_substitutions_array($substitutionarray, $langs, $object);
  292. // Line of free text
  293. $newfreetext='';
  294. $paramfreetext='PROPALE_FREE_TEXT';
  295. if (! empty($conf->global->$paramfreetext))
  296. {
  297. $newfreetext=make_substitutions($conf->global->$paramfreetext,$substitutionarray);
  298. }
  299. // Open and load template
  300. require_once ODTPHP_PATH.'odf.php';
  301. $odfHandler = new odf(
  302. $srctemplatepath,
  303. array(
  304. 'PATH_TO_TMP' => $conf->propal->dir_temp,
  305. 'ZIP_PROXY' => 'PclZipProxy', // PhpZipProxy or PclZipProxy. Got "bad compression method" error when using PhpZipProxy.
  306. 'DELIMITER_LEFT' => '{',
  307. 'DELIMITER_RIGHT' => '}'
  308. )
  309. );
  310. // After construction $odfHandler->contentXml contains content and
  311. // [!-- BEGIN row.lines --]*[!-- END row.lines --] has been replaced by
  312. // [!-- BEGIN lines --]*[!-- END lines --]
  313. //print html_entity_decode($odfHandler->__toString());
  314. //print exit;
  315. // Make substitutions into odt of freetext
  316. try {
  317. $odfHandler->setVars('free_text', $newfreetext, true, 'UTF-8');
  318. }
  319. catch(OdfException $e)
  320. {
  321. }
  322. // Make substitutions into odt of user info
  323. $tmparray=$this->get_substitutionarray_user($user,$outputlangs);
  324. //var_dump($tmparray); exit;
  325. foreach($tmparray as $key=>$value)
  326. {
  327. try {
  328. if (preg_match('/logo$/',$key)) // Image
  329. {
  330. //var_dump($value);exit;
  331. if (file_exists($value)) $odfHandler->setImage($key, $value);
  332. else $odfHandler->setVars($key, 'ErrorFileNotFound', true, 'UTF-8');
  333. }
  334. else // Text
  335. {
  336. $odfHandler->setVars($key, $value, true, 'UTF-8');
  337. }
  338. }
  339. catch(OdfException $e)
  340. {
  341. }
  342. }
  343. // Make substitutions into odt of mysoc
  344. $tmparray=$this->get_substitutionarray_mysoc($mysoc,$outputlangs);
  345. //var_dump($tmparray); exit;
  346. foreach($tmparray as $key=>$value)
  347. {
  348. try {
  349. if (preg_match('/logo$/',$key)) // Image
  350. {
  351. //var_dump($value);exit;
  352. if (file_exists($value)) $odfHandler->setImage($key, $value);
  353. else $odfHandler->setVars($key, 'ErrorFileNotFound', true, 'UTF-8');
  354. }
  355. else // Text
  356. {
  357. $odfHandler->setVars($key, $value, true, 'UTF-8');
  358. }
  359. }
  360. catch(OdfException $e)
  361. {
  362. }
  363. }
  364. // Make substitutions into odt of thirdparty
  365. $tmparray=$this->get_substitutionarray_thirdparty($socobject,$outputlangs);
  366. foreach($tmparray as $key=>$value)
  367. {
  368. try {
  369. if (preg_match('/logo$/',$key)) // Image
  370. {
  371. if (file_exists($value)) $odfHandler->setImage($key, $value);
  372. else $odfHandler->setVars($key, 'ErrorFileNotFound', true, 'UTF-8');
  373. }
  374. else // Text
  375. {
  376. $odfHandler->setVars($key, $value, true, 'UTF-8');
  377. }
  378. }
  379. catch(OdfException $e)
  380. {
  381. }
  382. }
  383. // Replace tags of object + external modules
  384. $tmparray=$this->get_substitutionarray_object($object,$outputlangs);
  385. complete_substitutions_array($tmparray, $outputlangs, $object);
  386. foreach($tmparray as $key=>$value)
  387. {
  388. try {
  389. if (preg_match('/logo$/',$key)) // Image
  390. {
  391. if (file_exists($value)) $odfHandler->setImage($key, $value);
  392. else $odfHandler->setVars($key, 'ErrorFileNotFound', true, 'UTF-8');
  393. }
  394. else // Text
  395. {
  396. $odfHandler->setVars($key, $value, true, 'UTF-8');
  397. }
  398. }
  399. catch(OdfException $e)
  400. {
  401. }
  402. }
  403. // Replace tags of lines
  404. try
  405. {
  406. $listlines = $odfHandler->setSegment('lines');
  407. foreach ($object->lines as $line)
  408. {
  409. $tmparray=$this->get_substitutionarray_lines($line,$outputlangs);
  410. complete_substitutions_array($tmparray, $outputlangs, $object, $line, "completesubstitutionarray_lines");
  411. foreach($tmparray as $key => $val)
  412. {
  413. try
  414. {
  415. $listlines->setVars($key, $val, true, 'UTF-8');
  416. }
  417. catch(OdfException $e)
  418. {
  419. }
  420. catch(SegmentException $e)
  421. {
  422. }
  423. }
  424. $listlines->merge();
  425. }
  426. $odfHandler->mergeSegment($listlines);
  427. }
  428. catch(OdfException $e)
  429. {
  430. $this->error=$e->getMessage();
  431. dol_syslog($this->error, LOG_WARNING);
  432. return -1;
  433. }
  434. // Write new file
  435. //$result=$odfHandler->exportAsAttachedFile('toto');
  436. $odfHandler->saveToDisk($file);
  437. if (! empty($conf->global->MAIN_UMASK))
  438. @chmod($file, octdec($conf->global->MAIN_UMASK));
  439. $odfHandler=null; // Destroy object
  440. return 1; // Success
  441. }
  442. else
  443. {
  444. $this->error=$langs->transnoentities("ErrorCanNotCreateDir",$dir);
  445. return -1;
  446. }
  447. }
  448. return -1;
  449. }
  450. }
  451. ?>