PageRenderTime 45ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/htdocs/core/modules/facture/doc/doc_generic_invoice_odt.modules.php

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