pdf_beluga.modules.php 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899
  1. <?php
  2. /* Copyright (C) 2010-2012 Regis Houssin <regis.houssin@inodbox.com>
  3. * Copyright (C) 2015-2018 Charlene Benke <charlie@patas-monkey.com>
  4. * Copyright (C) 2018 Laurent Destailleur <eldy@users.sourceforge.net>
  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. * \file htdocs/core/modules/project/doc/pdf_beluga.modules.php
  22. * \ingroup project
  23. * \brief File of class to generate project document beluga
  24. */
  25. require_once DOL_DOCUMENT_ROOT.'/core/modules/project/modules_project.php';
  26. require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
  27. require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
  28. require_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php';
  29. require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
  30. require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php';
  31. require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
  32. require_once DOL_DOCUMENT_ROOT.'/core/lib/project.lib.php';
  33. require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
  34. require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
  35. require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
  36. require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture-rec.class.php';
  37. require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
  38. require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
  39. require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
  40. require_once DOL_DOCUMENT_ROOT.'/contrat/class/contrat.class.php';
  41. require_once DOL_DOCUMENT_ROOT.'/fichinter/class/fichinter.class.php';
  42. require_once DOL_DOCUMENT_ROOT.'/compta/deplacement/class/deplacement.class.php';
  43. require_once DOL_DOCUMENT_ROOT.'/expensereport/class/expensereport.class.php';
  44. require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
  45. /**
  46. * Class to manage generation of project document Beluga
  47. */
  48. class pdf_beluga extends ModelePDFProjects
  49. {
  50. /**
  51. * @var DoliDb Database handler
  52. */
  53. public $db;
  54. /**
  55. * @var string model name
  56. */
  57. public $name;
  58. /**
  59. * @var string model description (short text)
  60. */
  61. public $description;
  62. /**
  63. * @var int Save the name of generated file as the main doc when generating a doc with this template
  64. */
  65. public $update_main_doc_field;
  66. /**
  67. * @var string document type
  68. */
  69. public $type;
  70. /**
  71. * @var array Minimum version of PHP required by module.
  72. * e.g.: PHP ≥ 5.6 = array(5, 6)
  73. */
  74. public $phpmin = array(5, 6);
  75. /**
  76. * Dolibarr version of the loaded document
  77. * @var string
  78. */
  79. public $version = 'dolibarr';
  80. /**
  81. * @var int page_largeur
  82. */
  83. public $page_largeur;
  84. /**
  85. * @var int page_hauteur
  86. */
  87. public $page_hauteur;
  88. /**
  89. * @var array format
  90. */
  91. public $format;
  92. /**
  93. * @var int marge_gauche
  94. */
  95. public $marge_gauche;
  96. /**
  97. * @var int marge_droite
  98. */
  99. public $marge_droite;
  100. /**
  101. * @var int marge_haute
  102. */
  103. public $marge_haute;
  104. /**
  105. * @var int marge_basse
  106. */
  107. public $marge_basse;
  108. /**
  109. * Page orientation
  110. * @var string 'P' or 'Portait' (default), 'L' or 'Landscape'
  111. */
  112. private $orientation = '';
  113. /**
  114. * Issuer
  115. * @var Societe
  116. */
  117. public $emetteur;
  118. public $posxref;
  119. public $posxdate;
  120. public $posxsociete;
  121. public $posxamountht;
  122. public $posxamountttc;
  123. public $posstatut;
  124. /**
  125. * Constructor
  126. *
  127. * @param DoliDB $db Database handler
  128. */
  129. public function __construct($db)
  130. {
  131. global $conf, $langs, $mysoc;
  132. // Translations
  133. $langs->loadLangs(array("main", "projects", "companies"));
  134. $this->db = $db;
  135. $this->name = "beluga";
  136. $this->description = $langs->trans("DocumentModelBeluga");
  137. $this->update_main_doc_field = 1; // Save the name of generated file as the main doc when generating a doc with this template
  138. // Page size for A4 format
  139. $this->type = 'pdf';
  140. $formatarray = pdf_getFormat();
  141. $this->orientation = 'L';
  142. if ($this->orientation == 'L' || $this->orientation == 'Landscape') {
  143. $this->page_largeur = $formatarray['height'];
  144. $this->page_hauteur = $formatarray['width'];
  145. } else {
  146. $this->page_largeur = $formatarray['width'];
  147. $this->page_hauteur = $formatarray['height'];
  148. }
  149. $this->format = array($this->page_largeur, $this->page_hauteur);
  150. $this->marge_gauche = isset($conf->global->MAIN_PDF_MARGIN_LEFT) ? $conf->global->MAIN_PDF_MARGIN_LEFT : 10;
  151. $this->marge_droite = isset($conf->global->MAIN_PDF_MARGIN_RIGHT) ? $conf->global->MAIN_PDF_MARGIN_RIGHT : 10;
  152. $this->marge_haute = isset($conf->global->MAIN_PDF_MARGIN_TOP) ? $conf->global->MAIN_PDF_MARGIN_TOP : 10;
  153. $this->marge_basse = isset($conf->global->MAIN_PDF_MARGIN_BOTTOM) ? $conf->global->MAIN_PDF_MARGIN_BOTTOM : 10;
  154. $this->option_logo = 1; // Display logo FAC_PDF_LOGO
  155. $this->option_tva = 1; // Manage the vat option FACTURE_TVAOPTION
  156. // Get source company
  157. $this->emetteur = $mysoc;
  158. if (!$this->emetteur->country_code) {
  159. $this->emetteur->country_code = substr($langs->defaultlang, -2); // By default if not defined
  160. }
  161. // Define position of columns
  162. if ($this->orientation == 'L' || $this->orientation == 'Landscape') {
  163. $this->posxref = $this->marge_gauche + 1;
  164. $this->posxdate = $this->marge_gauche + 105;
  165. $this->posxsociety = $this->marge_gauche + 126;
  166. $this->posxamountht = $this->marge_gauche + 190;
  167. $this->posxamountttc = $this->marge_gauche + 215;
  168. $this->posxstatut = $this->marge_gauche + 245;
  169. } else {
  170. $this->posxref = $this->marge_gauche + 1;
  171. $this->posxdate = $this->marge_gauche + 25;
  172. $this->posxsociety = $this->marge_gauche + 46;
  173. $this->posxamountht = $this->marge_gauche + 110;
  174. $this->posxamountttc = $this->marge_gauche + 135;
  175. $this->posxstatut = $this->marge_gauche + 165;
  176. }
  177. if ($this->page_largeur < 210) { // To work with US executive format
  178. $this->posxref -= 20;
  179. $this->posxdate -= 20;
  180. $this->posxsociete -= 20;
  181. $this->posxamountht -= 20;
  182. $this->posxamountttc -= 20;
  183. $this->posstatut -= 20;
  184. }
  185. }
  186. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
  187. /**
  188. * Fonction generant le projet sur le disque
  189. *
  190. * @param Project $object Object project a generer
  191. * @param Translate $outputlangs Lang output object
  192. * @return int 1 if OK, <=0 if KO
  193. */
  194. public function write_file($object, $outputlangs)
  195. {
  196. // phpcs:enable
  197. global $conf, $hookmanager, $langs, $user;
  198. $formproject = new FormProjets($this->db);
  199. if (!is_object($outputlangs)) {
  200. $outputlangs = $langs;
  201. }
  202. // For backward compatibility with FPDF, force output charset to ISO, because FPDF expect text to be encoded in ISO
  203. if (!empty($conf->global->MAIN_USE_FPDF)) {
  204. $outputlangs->charset_output = 'ISO-8859-1';
  205. }
  206. // Load traductions files required by page
  207. $outputlangs->loadLangs(array("main", "dict", "companies", "projects"));
  208. if ($conf->projet->dir_output) {
  209. //$nblines = count($object->lines); // This is set later with array of tasks
  210. $objectref = dol_sanitizeFileName($object->ref);
  211. $dir = $conf->projet->dir_output;
  212. if (!preg_match('/specimen/i', $objectref)) {
  213. $dir .= "/".$objectref;
  214. }
  215. $file = $dir."/".$objectref.".pdf";
  216. if (!file_exists($dir)) {
  217. if (dol_mkdir($dir) < 0) {
  218. $this->error = $langs->transnoentities("ErrorCanNotCreateDir", $dir);
  219. return 0;
  220. }
  221. }
  222. if (file_exists($dir)) {
  223. // Add pdfgeneration hook
  224. if (!is_object($hookmanager)) {
  225. include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
  226. $hookmanager = new HookManager($this->db);
  227. }
  228. $hookmanager->initHooks(array('pdfgeneration'));
  229. $parameters = array('file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs);
  230. global $action;
  231. $reshook = $hookmanager->executeHooks('beforePDFCreation', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
  232. // Create pdf instance
  233. $pdf = pdf_getInstance($this->format);
  234. $default_font_size = pdf_getPDFFontSize($outputlangs); // Must be after pdf_getInstance
  235. $pdf->SetAutoPageBreak(1, 0);
  236. $heightforinfotot = 40; // Height reserved to output the info and total part
  237. $heightforfreetext = (isset($conf->global->MAIN_PDF_FREETEXT_HEIGHT) ? $conf->global->MAIN_PDF_FREETEXT_HEIGHT : 5); // Height reserved to output the free text on last page
  238. $heightforfooter = $this->marge_basse + 8; // Height reserved to output the footer (value include bottom margin)
  239. if (!empty($conf->global->MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS)) {
  240. $heightforfooter += 6;
  241. }
  242. if (class_exists('TCPDF')) {
  243. $pdf->setPrintHeader(false);
  244. $pdf->setPrintFooter(false);
  245. }
  246. $pdf->SetFont(pdf_getPDFFont($outputlangs));
  247. // Set path to the background PDF File
  248. if (!empty($conf->global->MAIN_ADD_PDF_BACKGROUND)) {
  249. $pagecount = $pdf->setSourceFile($conf->mycompany->dir_output.'/'.$conf->global->MAIN_ADD_PDF_BACKGROUND);
  250. $tplidx = $pdf->importPage(1);
  251. }
  252. // Complete object by loading several other informations
  253. $task = new Task($this->db);
  254. $tasksarray = array();
  255. $tasksarray = $task->getTasksArray(0, 0, $object->id);
  256. // Special case when used with object = specimen, we may return all lines
  257. if (!$object->id > 0) {
  258. $tasksarray = array_slice($tasksarray, 0, min(5, count($tasksarray)));
  259. }
  260. $object->lines = $tasksarray;
  261. $nblines = count($object->lines);
  262. $pdf->Open();
  263. $pagenb = 0;
  264. $pdf->SetDrawColor(128, 128, 128);
  265. $pdf->SetTitle($outputlangs->convToOutputCharset($object->ref));
  266. $pdf->SetSubject($outputlangs->transnoentities("Project"));
  267. $pdf->SetCreator("Dolibarr ".DOL_VERSION);
  268. $pdf->SetAuthor($outputlangs->convToOutputCharset($user->getFullName($outputlangs)));
  269. $pdf->SetKeyWords($outputlangs->convToOutputCharset($object->ref)." ".$outputlangs->transnoentities("Project"));
  270. if (!empty($conf->global->MAIN_DISABLE_PDF_COMPRESSION)) {
  271. $pdf->SetCompression(false);
  272. }
  273. $pdf->SetMargins($this->marge_gauche, $this->marge_haute, $this->marge_droite); // Left, Top, Right
  274. // New page
  275. $pdf->AddPage($this->orientation);
  276. if (!empty($tplidx)) {
  277. $pdf->useTemplate($tplidx);
  278. }
  279. $pagenb++;
  280. $this->_pagehead($pdf, $object, 1, $outputlangs);
  281. $pdf->SetFont('', '', $default_font_size - 1);
  282. $pdf->MultiCell(0, 3, ''); // Set interline to 3
  283. $pdf->SetTextColor(0, 0, 0);
  284. $tab_top = 50;
  285. $tab_top_newpage = (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD) ? 42 : 10);
  286. $tab_height = $this->page_hauteur - $tab_top - $heightforfooter - $heightforfreetext;
  287. // Show public note
  288. $notetoshow = empty($object->note_public) ? '' : $object->note_public;
  289. if ($notetoshow) {
  290. $substitutionarray = pdf_getSubstitutionArray($outputlangs, null, $object);
  291. complete_substitutions_array($substitutionarray, $outputlangs, $object);
  292. $notetoshow = make_substitutions($notetoshow, $substitutionarray, $outputlangs);
  293. $notetoshow = convertBackOfficeMediasLinksToPublicLinks($notetoshow);
  294. $tab_top -= 2;
  295. $pdf->SetFont('', '', $default_font_size - 1);
  296. $pdf->writeHTMLCell(190, 3, $this->posxref - 1, $tab_top - 2, dol_htmlentitiesbr($notetoshow), 0, 1);
  297. $nexY = $pdf->GetY();
  298. $height_note = $nexY - $tab_top;
  299. // Rect takes a length in 3rd parameter
  300. $pdf->SetDrawColor(192, 192, 192);
  301. $pdf->Rect($this->marge_gauche, $tab_top - 2, $this->page_largeur - $this->marge_gauche - $this->marge_droite, $height_note + 2);
  302. $tab_height = $tab_height - $height_note;
  303. $tab_top = $nexY + 6;
  304. } else {
  305. $height_note = 0;
  306. }
  307. $heightoftitleline = 10;
  308. $iniY = $tab_top + $heightoftitleline + 1;
  309. $curY = $tab_top + $heightoftitleline + 1;
  310. $nexY = $tab_top + $heightoftitleline + 1;
  311. $listofreferent = array(
  312. 'propal'=>array(
  313. 'name'=>"Proposals",
  314. 'title'=>"ListProposalsAssociatedProject",
  315. 'class'=>'Propal',
  316. 'table'=>'propal',
  317. 'datefieldname'=>'datep',
  318. 'test'=>$conf->propal->enabled && $user->rights->propale->lire,
  319. 'lang'=>'propal'),
  320. 'order'=>array(
  321. 'name'=>"CustomersOrders",
  322. 'title'=>"ListOrdersAssociatedProject",
  323. 'class'=>'Commande',
  324. 'table'=>'commande',
  325. 'datefieldname'=>'date_commande',
  326. 'test'=>$conf->commande->enabled && $user->rights->commande->lire,
  327. 'lang'=>'orders'),
  328. 'invoice'=>array(
  329. 'name'=>"CustomersInvoices",
  330. 'title'=>"ListInvoicesAssociatedProject",
  331. 'class'=>'Facture',
  332. 'margin'=>'add',
  333. 'table'=>'facture',
  334. 'datefieldname'=>'datef',
  335. 'test'=>$conf->facture->enabled && $user->rights->facture->lire,
  336. 'lang'=>'bills'),
  337. 'invoice_predefined'=>array(
  338. 'name'=>"PredefinedInvoices",
  339. 'title'=>"ListPredefinedInvoicesAssociatedProject",
  340. 'class'=>'FactureRec',
  341. 'table'=>'facture_rec',
  342. 'datefieldname'=>'datec',
  343. 'test'=>$conf->facture->enabled && $user->rights->facture->lire,
  344. 'lang'=>'bills'),
  345. 'order_supplier'=>array(
  346. 'name'=>"SuppliersOrders",
  347. 'title'=>"ListSupplierOrdersAssociatedProject",
  348. 'class'=>'CommandeFournisseur',
  349. 'table'=>'commande_fournisseur',
  350. 'datefieldname'=>'date_commande',
  351. 'test'=>(!empty($conf->fournisseur->enabled) && empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->rights->fournisseur->commande->lire) || (!empty($conf->supplier_order->enabled) && $user->rights->supplier_order->lire),
  352. 'lang'=>'orders'),
  353. 'invoice_supplier'=>array(
  354. 'name'=>"BillsSuppliers",
  355. 'title'=>"ListSupplierInvoicesAssociatedProject",
  356. 'class'=>'FactureFournisseur',
  357. 'margin'=>'minus',
  358. 'table'=>'facture_fourn',
  359. 'datefieldname'=>'datef',
  360. 'test'=>(!empty($conf->fournisseur->enabled) && empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->rights->fournisseur->facture->lire) || (!empty($conf->supplier_invoice->enabled) && $user->rights->supplier_invoice->lire),
  361. 'lang'=>'bills'),
  362. 'contract'=>array(
  363. 'name'=>"Contracts",
  364. 'title'=>"ListContractAssociatedProject",
  365. 'class'=>'Contrat',
  366. 'table'=>'contrat',
  367. 'datefieldname'=>'date_contrat',
  368. 'test'=>$conf->contrat->enabled && $user->rights->contrat->lire,
  369. 'lang'=>'contract'),
  370. 'intervention'=>array(
  371. 'name'=>"Interventions",
  372. 'title'=>"ListFichinterAssociatedProject",
  373. 'class'=>'Fichinter',
  374. 'table'=>'fichinter',
  375. 'datefieldname'=>'date_valid',
  376. 'disableamount'=>1,
  377. 'test'=>$conf->ficheinter->enabled && $user->rights->ficheinter->lire,
  378. 'lang'=>'interventions'),
  379. 'trip'=>array(
  380. 'name'=>"TripsAndExpenses",
  381. 'title'=>"ListExpenseReportsAssociatedProject",
  382. 'class'=>'Deplacement',
  383. 'table'=>'deplacement',
  384. 'datefieldname'=>'dated',
  385. 'margin'=>'minus',
  386. 'disableamount'=>1,
  387. 'test'=>$conf->deplacement->enabled && $user->rights->deplacement->lire,
  388. 'lang'=>'trip'),
  389. 'expensereport'=>array(
  390. 'name'=>"ExpensesReports",
  391. 'title'=>"ListExpenseReportsAssociatedProject",
  392. 'class'=>'ExpenseReport',
  393. 'table'=>'expensereport',
  394. 'datefieldname'=>'dated',
  395. 'margin'=>'minus',
  396. 'disableamount'=>1,
  397. 'test'=>$conf->expensereport->enabled && $user->rights->expensereport->lire,
  398. 'lang'=>'trip'),
  399. 'agenda'=>array(
  400. 'name'=>"Agenda",
  401. 'title'=>"ListActionsAssociatedProject",
  402. 'class'=>'ActionComm',
  403. 'table'=>'actioncomm',
  404. 'datefieldname'=>'datep',
  405. 'disableamount'=>1,
  406. 'test'=>$conf->agenda->enabled && $user->rights->agenda->allactions->read,
  407. 'lang'=>'agenda')
  408. );
  409. $hookmanager->initHooks(array('completeListOfReferent'));
  410. $hookmanager->executeHooks('completeListOfReferent', ['listofreferent'=>$listofreferent], $object, $action);
  411. if (!empty($hookmanager->resArray)) {
  412. $listofreferent = array_merge($listofreferent, $hookmanager->resArray);
  413. }
  414. foreach ($listofreferent as $key => $value) {
  415. $title = $value['title'];
  416. $classname = $value['class'];
  417. $tablename = $value['table'];
  418. $datefieldname = $value['datefieldname'];
  419. $qualified = $value['test'];
  420. $langstoload = $value['lang'];
  421. $projectField = isset($value['project_field']) ? $value['project_field'] : 'fk_projet';
  422. $langs->load($langstoload);
  423. if (!$qualified) {
  424. continue;
  425. }
  426. //var_dump("$key, $tablename, $datefieldname, $dates, $datee");
  427. $elementarray = $object->get_element_list($key, $tablename, $datefieldname, '', '', $projectField);
  428. $num = count($elementarray);
  429. if ($num >= 0) {
  430. $nexY = $pdf->GetY() + 5;
  431. $curY = $nexY;
  432. $pdf->SetFont('', '', $default_font_size - 1); // Into loop to work with multipage
  433. $pdf->SetTextColor(0, 0, 0);
  434. $pdf->SetXY($this->posxref, $curY);
  435. $pdf->MultiCell($this->posxstatut - $this->posxref, 3, $outputlangs->transnoentities($title), 0, 'L');
  436. $selectList = $formproject->select_element($tablename, $object->thirdparty->id, '', -2, $projectField);
  437. $nexY = $pdf->GetY() + 1;
  438. $curY = $nexY;
  439. $pdf->SetXY($this->posxref, $curY);
  440. $pdf->MultiCell($this->posxdate - $this->posxref, 3, $outputlangs->transnoentities("Ref"), 1, 'L');
  441. $pdf->SetXY($this->posxdate, $curY);
  442. $pdf->MultiCell($this->posxsociety - $this->posxdate, 3, $outputlangs->transnoentities("Date"), 1, 'C');
  443. $pdf->SetXY($this->posxsociety, $curY);
  444. $titlethirdparty = $outputlangs->transnoentities("ThirdParty");
  445. if ($classname == 'ExpenseReport') {
  446. $titlethirdparty = $langs->trans("User");
  447. }
  448. $pdf->MultiCell($this->posxamountht - $this->posxsociety, 3, $titlethirdparty, 1, 'L');
  449. if (empty($value['disableamount'])) {
  450. $pdf->SetXY($this->posxamountht, $curY);
  451. $pdf->MultiCell($this->posxamountttc - $this->posxamountht, 3, $outputlangs->transnoentities("AmountHTShort"), 1, 'R');
  452. $pdf->SetXY($this->posxamountttc, $curY);
  453. $pdf->MultiCell($this->posxstatut - $this->posxamountttc, 3, $outputlangs->transnoentities("AmountTTCShort"), 1, 'R');
  454. } else {
  455. $pdf->SetXY($this->posxamountht, $curY);
  456. $pdf->MultiCell($this->posxstatut - $this->posxamountht, 3, "", 1, 'R');
  457. }
  458. $pdf->SetXY($this->posxstatut, $curY);
  459. $pdf->MultiCell($this->page_largeur - $this->marge_droite - $this->posxstatut, 3, $outputlangs->transnoentities("Status"), 1, 'R');
  460. if (is_array($elementarray) && count($elementarray) > 0) {
  461. $nexY = $pdf->GetY();
  462. $total_ht = 0;
  463. $total_ttc = 0;
  464. $num = count($elementarray);
  465. // Loop on each lines
  466. for ($i = 0; $i < $num; $i++) {
  467. $curY = $nexY;
  468. $pdf->SetFont('', '', $default_font_size - 1); // Into loop to work with multipage
  469. $pdf->SetTextColor(0, 0, 0);
  470. $pdf->setTopMargin($tab_top_newpage);
  471. $pdf->setPageOrientation($this->orientation, 1, $heightforfooter + $heightforfreetext + $heightforinfotot); // The only function to edit the bottom margin of current page to set it.
  472. $pageposbefore = $pdf->getPage();
  473. // Description of line
  474. $idofelement = $elementarray[$i];
  475. if ($classname == 'ExpenseReport') {
  476. // We get id of expense report
  477. $expensereportline = new ExpenseReportLine($this->db);
  478. $expensereportline->fetch($idofelement);
  479. $idofelement = $expensereportline->fk_expensereport;
  480. }
  481. $element = new $classname($this->db);
  482. $element->fetch($idofelement);
  483. $element->fetch_thirdparty();
  484. // print $classname;
  485. $qualifiedfortotal = true;
  486. if ($key == 'invoice') {
  487. if ($element->close_code == 'replaced') {
  488. $qualifiedfortotal = false; // Replacement invoice
  489. }
  490. }
  491. $showpricebeforepagebreak = 1;
  492. $pdf->startTransaction();
  493. // Label
  494. $pdf->SetXY($this->posxref, $curY);
  495. $pdf->MultiCell($this->posxdate - $this->posxref, 3, $element->ref, 1, 'L');
  496. $pageposafter = $pdf->getPage();
  497. if ($pageposafter > $pageposbefore) { // There is a pagebreak
  498. $pdf->rollbackTransaction(true);
  499. $pageposafter = $pageposbefore;
  500. //print $pageposafter.'-'.$pageposbefore;exit;
  501. $pdf->setPageOrientation($this->orientation, 1, $heightforfooter); // The only function to edit the bottom margin of current page to set it.
  502. // Label
  503. $pdf->SetXY($this->posxref, $curY);
  504. $posybefore = $pdf->GetY();
  505. $pdf->MultiCell($this->posxdate - $this->posxref, 3, $element->ref, 1, 'L');
  506. $pageposafter = $pdf->getPage();
  507. $posyafter = $pdf->GetY();
  508. if ($posyafter > ($this->page_hauteur - ($heightforfooter + $heightforfreetext + $heightforinfotot))) { // There is no space left for total+free text
  509. if ($i == ($num - 1)) { // No more lines, and no space left to show total, so we create a new page
  510. $pdf->AddPage($this->orientation, '', true);
  511. if (!empty($tplidx)) {
  512. $pdf->useTemplate($tplidx);
  513. }
  514. if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) {
  515. $this->_pagehead($pdf, $object, 0, $outputlangs);
  516. }
  517. $pdf->setPage($pageposafter + 1);
  518. }
  519. } else {
  520. // We found a page break
  521. // Allows data in the first page if description is long enough to break in multiples pages
  522. if (!empty($conf->global->MAIN_PDF_DATA_ON_FIRST_PAGE)) {
  523. $showpricebeforepagebreak = 1;
  524. } else {
  525. $showpricebeforepagebreak = 0;
  526. }
  527. $forcedesconsamepage = 1;
  528. if ($forcedesconsamepage) {
  529. $pdf->rollbackTransaction(true);
  530. $pageposafter = $pageposbefore;
  531. $pdf->setPageOrientation($this->orientation, 1, $heightforfooter); // The only function to edit the bottom margin of current page to set it.
  532. $pdf->AddPage($this->orientation, '', true);
  533. if (!empty($tplidx)) {
  534. $pdf->useTemplate($tplidx);
  535. }
  536. if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) {
  537. $this->_pagehead($pdf, $object, 0, $outputlangs);
  538. }
  539. $pdf->setPage($pageposafter + 1);
  540. $pdf->SetFont('', '', $default_font_size - 1); // On repositionne la police par defaut
  541. $pdf->MultiCell(0, 3, ''); // Set interline to 3
  542. $pdf->SetTextColor(0, 0, 0);
  543. $pdf->setPageOrientation($this->orientation, 1, $heightforfooter); // The only function to edit the bottom margin of current page to set it.
  544. $curY = $tab_top_newpage + $heightoftitleline + 1;
  545. // Label
  546. $pdf->SetXY($this->posxref, $curY);
  547. $posybefore = $pdf->GetY();
  548. $pdf->MultiCell($this->posxdate - $this->posxref, 3, $element->ref, 1, 'L');
  549. $pageposafter = $pdf->getPage();
  550. $posyafter = $pdf->GetY();
  551. }
  552. }
  553. //var_dump($i.' '.$posybefore.' '.$posyafter.' '.($this->page_hauteur - ($heightforfooter + $heightforfreetext + $heightforinfotot)).' '.$showpricebeforepagebreak);
  554. } else // No pagebreak
  555. {
  556. $pdf->commitTransaction();
  557. }
  558. $posYAfterDescription = $pdf->GetY();
  559. $nexY = $pdf->GetY();
  560. $pageposafter = $pdf->getPage();
  561. $pdf->setPage($pageposbefore);
  562. $pdf->setTopMargin($this->marge_haute);
  563. $pdf->setPageOrientation($this->orientation, 1, 0); // The only function to edit the bottom margin of current page to set it.
  564. // We suppose that a too long description is moved completely on next page
  565. if ($pageposafter > $pageposbefore && empty($showpricebeforepagebreak)) {
  566. //var_dump($pageposbefore.'-'.$pageposafter.'-'.$showpricebeforepagebreak);
  567. $pdf->setPage($pageposafter);
  568. $curY = $tab_top_newpage + $heightoftitleline + 1;
  569. }
  570. $pdf->SetFont('', '', $default_font_size - 1); // On repositionne la police par defaut
  571. // Date
  572. if ($tablename == 'commande_fournisseur' || $tablename == 'supplier_order') {
  573. $date = $element->date_commande;
  574. } else {
  575. $date = $element->date;
  576. if (empty($date)) {
  577. $date = $element->datep;
  578. }
  579. if (empty($date)) {
  580. $date = $element->date_contrat;
  581. }
  582. if (empty($date)) {
  583. $date = $element->datev; // Fiche inter
  584. }
  585. }
  586. $pdf->SetXY($this->posxdate, $curY);
  587. $pdf->MultiCell($this->posxsociety - $this->posxdate, 3, dol_print_date($date, 'day'), 1, 'C');
  588. $pdf->SetXY($this->posxsociety, $curY);
  589. if ($classname == 'ExpenseReport') {
  590. $fuser = new User($this->db);
  591. $fuser->fetch($element->fk_user_author);
  592. $pdf->MultiCell($this->posxamountht - $this->posxsociety, 3, $fuser->getFullName($outputlangs), 1, 'L');
  593. } else {
  594. $pdf->MultiCell($this->posxamountht - $this->posxsociety, 3, (is_object($element->thirdparty) ? $element->thirdparty->name : ''), 1, 'L');
  595. }
  596. // Amount without tax
  597. if (empty($value['disableamount'])) {
  598. $pdf->SetXY($this->posxamountht, $curY);
  599. $pdf->MultiCell($this->posxamountttc - $this->posxamountht, 3, (isset($element->total_ht) ? price($element->total_ht) : ''), 1, 'R');
  600. $pdf->SetXY($this->posxamountttc, $curY);
  601. $pdf->MultiCell($this->posxstatut - $this->posxamountttc, 3, (isset($element->total_ttc) ? price($element->total_ttc) : ''), 1, 'R');
  602. } else {
  603. $pdf->SetXY($this->posxamountht, $curY);
  604. if ($key == 'agenda') {
  605. $textforamount = dol_trunc($element->label, 26);
  606. $pdf->MultiCell($this->posxstatut - $this->posxamountht, 3, $textforamount, 1, 'L');
  607. } else {
  608. $pdf->MultiCell($this->posxstatut - $this->posxamountht, 3, "", 1, 'R');
  609. }
  610. }
  611. // Status
  612. if ($element instanceof CommonInvoice) {
  613. // This applies for Facture and FactureFournisseur
  614. $outputstatut = $element->getLibStatut(1, $element->getSommePaiement());
  615. } else {
  616. $outputstatut = $element->getLibStatut(1);
  617. }
  618. $pdf->SetXY($this->posxstatut, $curY);
  619. $pdf->MultiCell($this->page_largeur - $this->marge_droite - $this->posxstatut, 3, $outputstatut, 1, 'R', false, 1, '', '', true, 0, true);
  620. if ($qualifiedfortotal) {
  621. $total_ht = $total_ht + $element->total_ht;
  622. $total_ttc = $total_ttc + $element->total_ttc;
  623. }
  624. $nexY = $pdf->GetY();
  625. $curY = $nexY;
  626. }
  627. if (empty($value['disableamount'])) {
  628. $curY = $nexY;
  629. $pdf->SetXY($this->posxref, $curY);
  630. $pdf->MultiCell($this->posxamountttc - $this->posxref, 3, "TOTAL", 1, 'L');
  631. $pdf->SetXY($this->posxamountht, $curY);
  632. $pdf->MultiCell($this->posxamountttc - $this->posxamountht, 3, (isset($element->total_ht) ? price($total_ht) : ''), 1, 'R');
  633. $pdf->SetXY($this->posxamountttc, $curY);
  634. $pdf->MultiCell($this->posxstatut - $this->posxamountttc, 3, (isset($element->total_ttc) ? price($total_ttc) : ''), 1, 'R');
  635. $pdf->SetXY($this->posxstatut, $curY);
  636. $pdf->MultiCell($this->page_largeur - $this->marge_droite - $this->posxstatut, 3, $outputlangs->transnoentities("Nb")." ".$num, 1, 'L');
  637. }
  638. $nexY = $pdf->GetY() + 5;
  639. $curY = $nexY;
  640. }
  641. }
  642. $nexY += 2; // Add space between lines
  643. // Detect if some page were added automatically and output _tableau for past pages
  644. while ($pagenb < $pageposafter) {
  645. $pdf->setPage($pagenb);
  646. $this->_pagefoot($pdf, $object, $outputlangs, 1);
  647. $pagenb++;
  648. $pdf->setPage($pagenb);
  649. $pdf->setPageOrientation($this->orientation, 1, 0); // The only function to edit the bottom margin of current page to set it.
  650. if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) {
  651. $this->_pagehead($pdf, $object, 0, $outputlangs);
  652. }
  653. }
  654. }
  655. // Pied de page
  656. $this->_pagefoot($pdf, $object, $outputlangs);
  657. if (method_exists($pdf, 'AliasNbPages')) {
  658. $pdf->AliasNbPages();
  659. }
  660. $pdf->Close();
  661. $pdf->Output($file, 'F');
  662. // Add pdfgeneration hook
  663. $hookmanager->initHooks(array('pdfgeneration'));
  664. $parameters = array('file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs);
  665. global $action;
  666. $reshook = $hookmanager->executeHooks('afterPDFCreation', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
  667. if ($reshook < 0) {
  668. $this->error = $hookmanager->error;
  669. $this->errors = $hookmanager->errors;
  670. }
  671. if (!empty($conf->global->MAIN_UMASK)) {
  672. @chmod($file, octdec($conf->global->MAIN_UMASK));
  673. }
  674. $this->result = array('fullpath'=>$file);
  675. return 1; // No error
  676. } else {
  677. $this->error = $langs->transnoentities("ErrorCanNotCreateDir", $dir);
  678. return 0;
  679. }
  680. } else {
  681. $this->error = $langs->transnoentities("ErrorConstantNotDefined", "PROJECT_OUTPUTDIR");
  682. return 0;
  683. }
  684. }
  685. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
  686. /**
  687. * Show table for lines
  688. *
  689. * @param TCPDF $pdf Object PDF
  690. * @param string $tab_top Top position of table
  691. * @param string $tab_height Height of table (rectangle)
  692. * @param int $nexY Y
  693. * @param Translate $outputlangs Langs object
  694. * @param int $hidetop Hide top bar of array
  695. * @param int $hidebottom Hide bottom bar of array
  696. * @return void
  697. */
  698. protected function _tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop = 0, $hidebottom = 0)
  699. {
  700. $heightoftitleline = 10;
  701. $default_font_size = pdf_getPDFFontSize($outputlangs);
  702. $pdf->SetDrawColor(128, 128, 128);
  703. // Draw rect of all tab (title + lines). Rect takes a length in 3rd parameter
  704. $pdf->Rect($this->marge_gauche, $tab_top, $this->page_largeur - $this->marge_gauche - $this->marge_droite, $tab_height);
  705. // line prend une position y en 3eme param
  706. $pdf->line($this->marge_gauche, $tab_top + $heightoftitleline, $this->page_largeur - $this->marge_droite, $tab_top + $heightoftitleline);
  707. $pdf->SetTextColor(0, 0, 0);
  708. $pdf->SetFont('', '', $default_font_size);
  709. }
  710. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
  711. /**
  712. * Show top header of page.
  713. *
  714. * @param TCPDF $pdf Object PDF
  715. * @param Project $object Object to show
  716. * @param int $showaddress 0=no, 1=yes
  717. * @param Translate $outputlangs Object lang for output
  718. * @return void
  719. */
  720. protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs)
  721. {
  722. global $langs, $conf, $mysoc;
  723. $default_font_size = pdf_getPDFFontSize($outputlangs);
  724. pdf_pagehead($pdf, $outputlangs, $this->page_hauteur);
  725. $pdf->SetTextColor(0, 0, 60);
  726. $pdf->SetFont('', 'B', $default_font_size + 3);
  727. $posx = $this->page_largeur - $this->marge_droite - 100;
  728. $posy = $this->marge_haute;
  729. $pdf->SetXY($this->marge_gauche, $posy);
  730. // Logo
  731. $logo = $conf->mycompany->dir_output.'/logos/'.$mysoc->logo;
  732. if ($mysoc->logo) {
  733. if (is_readable($logo)) {
  734. $height = pdf_getHeightForLogo($logo);
  735. $pdf->Image($logo, $this->marge_gauche, $posy, 0, $height); // width=0 (auto)
  736. } else {
  737. $pdf->SetTextColor(200, 0, 0);
  738. $pdf->SetFont('', 'B', $default_font_size - 2);
  739. $pdf->MultiCell(100, 3, $langs->transnoentities("ErrorLogoFileNotFound", $logo), 0, 'L');
  740. $pdf->MultiCell(100, 3, $langs->transnoentities("ErrorGoToModuleSetup"), 0, 'L');
  741. }
  742. } else {
  743. $pdf->MultiCell(100, 4, $outputlangs->transnoentities($this->emetteur->name), 0, 'L');
  744. }
  745. $pdf->SetFont('', 'B', $default_font_size + 3);
  746. $pdf->SetXY($posx, $posy);
  747. $pdf->SetTextColor(0, 0, 60);
  748. $pdf->MultiCell(100, 4, $outputlangs->transnoentities("Project")." ".$outputlangs->convToOutputCharset($object->ref), '', 'R');
  749. $pdf->SetFont('', '', $default_font_size + 2);
  750. $posy += 6;
  751. $pdf->SetXY($posx, $posy);
  752. $pdf->SetTextColor(0, 0, 60);
  753. $pdf->MultiCell(100, 4, $outputlangs->transnoentities("DateStart")." : ".dol_print_date($object->date_start, 'day', false, $outputlangs, true), '', 'R');
  754. $posy += 6;
  755. $pdf->SetXY($posx, $posy);
  756. $pdf->MultiCell(100, 4, $outputlangs->transnoentities("DateEnd")." : ".dol_print_date($object->date_end, 'day', false, $outputlangs, true), '', 'R');
  757. if (is_object($object->thirdparty)) {
  758. $posy += 6;
  759. $pdf->SetXY($posx, $posy);
  760. $pdf->MultiCell(100, 4, $outputlangs->transnoentities("ThirdParty")." : ".$object->thirdparty->getFullName($outputlangs), '', 'R');
  761. }
  762. $pdf->SetTextColor(0, 0, 60);
  763. }
  764. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
  765. /**
  766. * Show footer of page. Need this->emetteur object
  767. *
  768. * @param TCPDF $pdf PDF
  769. * @param Project $object Object to show
  770. * @param Translate $outputlangs Object lang for output
  771. * @param int $hidefreetext 1=Hide free text
  772. * @return integer
  773. */
  774. protected function _pagefoot(&$pdf, $object, $outputlangs, $hidefreetext = 0)
  775. {
  776. global $conf;
  777. $showdetails = empty($conf->global->MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS) ? 0 : $conf->global->MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS;
  778. return pdf_pagefoot($pdf, $outputlangs, 'PROJECT_FREE_TEXT', $this->emetteur, $this->marge_basse, $this->marge_gauche, $this->page_hauteur, $object, $showdetails, $hidefreetext);
  779. }
  780. }