commondocgenerator.class.php 63 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634
  1. <?php
  2. /* Copyright (C) 2003-2005 Rodolphe Quiedeville <rodolphe@quiedeville.org>
  3. * Copyright (C) 2004-2010 Laurent Destailleur <eldy@users.sourceforge.net>
  4. * Copyright (C) 2004 Eric Seigne <eric.seigne@ryxeo.com>
  5. * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@inodbox.com>
  6. * Copyright (C) 2015 Marcos García <marcosgdf@gmail.com>
  7. * Copyright (C) 2016 Charlie Benke <charlie@patas-monkey.com>
  8. * Copyright (C) 2018-2020 Frédéric France <frederic.france@netlogic.fr>
  9. * Copyright (C) 2020 Josep Lluís Amador <joseplluis@lliuretic.cat>
  10. *
  11. * This program is free software; you can redistribute it and/or modify
  12. * it under the terms of the GNU General Public License as published by
  13. * the Free Software Foundation; either version 3 of the License, or
  14. * (at your option) any later version.
  15. *
  16. * This program is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. * GNU General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU General Public License
  22. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  23. * or see https://www.gnu.org/
  24. */
  25. /**
  26. * \file htdocs/core/class/commondocgenerator.class.php
  27. * \ingroup core
  28. * \brief File of parent class for documents generators
  29. */
  30. /**
  31. * Parent class for documents generators
  32. */
  33. abstract class CommonDocGenerator
  34. {
  35. /**
  36. * @var string Error code (or message)
  37. */
  38. public $error = '';
  39. /**
  40. * @var string[] Array of error strings
  41. */
  42. public $errors = array();
  43. /**
  44. * @var DoliDB Database handler.
  45. */
  46. protected $db;
  47. /**
  48. * @var Extrafields object
  49. */
  50. public $extrafieldsCache;
  51. /**
  52. * @var int If set to 1, save the fullname of generated file with path as the main doc when generating a doc with this template.
  53. */
  54. public $update_main_doc_field;
  55. /**
  56. * @var string The name of constant to use to scan ODT files (Exemple: 'COMMANDE_ADDON_PDF_ODT_PATH')
  57. */
  58. public $scandir;
  59. /**
  60. * Constructor
  61. *
  62. * @param DoliDB $db Database handler
  63. */
  64. public function __construct($db)
  65. {
  66. $this->db = $db;
  67. }
  68. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
  69. /**
  70. * Define array with couple substitution key => substitution value
  71. *
  72. * @param User $user User
  73. * @param Translate $outputlangs Language object for output
  74. * @return array Array of substitution key->code
  75. */
  76. public function get_substitutionarray_user($user, $outputlangs)
  77. {
  78. // phpcs:enable
  79. global $conf, $extrafields;
  80. $logotouse = $conf->user->dir_output.'/'.get_exdir($user->id, 2, 0, 1, $user, 'user').'/'.$user->photo;
  81. $array_user = array(
  82. 'myuser_lastname'=>$user->lastname,
  83. 'myuser_firstname'=>$user->firstname,
  84. 'myuser_fullname'=>$user->getFullName($outputlangs, 1),
  85. 'myuser_login'=>$user->login,
  86. 'myuser_phone'=>$user->office_phone,
  87. 'myuser_address'=>$user->address,
  88. 'myuser_zip'=>$user->zip,
  89. 'myuser_town'=>$user->town,
  90. 'myuser_country'=>$user->country,
  91. 'myuser_country_code'=>$user->country_code,
  92. 'myuser_state'=>$user->state,
  93. 'myuser_state_code'=>$user->state_code,
  94. 'myuser_fax'=>$user->office_fax,
  95. 'myuser_mobile'=>$user->user_mobile,
  96. 'myuser_email'=>$user->email,
  97. 'myuser_logo'=>$logotouse,
  98. 'myuser_job'=>$user->job,
  99. 'myuser_web'=>'' // url not exist in $user object
  100. );
  101. // Retrieve extrafields
  102. if (is_array($user->array_options) && count($user->array_options)) {
  103. $array_user = $this->fill_substitutionarray_with_extrafields($user, $array_user, $extrafields, 'myuser', $outputlangs);
  104. }
  105. return $array_user;
  106. }
  107. /**
  108. * Define array with couple substitution key => substitution value
  109. *
  110. * @param Adherent $member Member
  111. * @param Translate $outputlangs Language object for output
  112. * @return array Array of substitution key->code
  113. */
  114. public function getSubstitutionarrayMember($member, $outputlangs)
  115. {
  116. global $conf, $extrafields;
  117. if ($member->photo) {
  118. $logotouse = $conf->adherent->dir_output.'/'.get_exdir(0, 0, 0, 1, $member, 'user').'/photos/'.$member->photo;
  119. } else {
  120. $logotouse = DOL_DOCUMENT_ROOT.'/public/theme/common/nophoto.png';
  121. }
  122. $array_member = array(
  123. 'mymember_lastname' => $member->lastname,
  124. 'mymember_firstname' => $member->firstname,
  125. 'mymember_fullname' => $member->getFullName($outputlangs, 1),
  126. 'mymember_login' => $member->login,
  127. 'mymember_address' => $member->address,
  128. 'mymember_zip' => $member->zip,
  129. 'mymember_town' => $member->town,
  130. 'mymember_country_code' => $member->country_code,
  131. 'mymember_country' => $member->country,
  132. 'mymember_state_code' => $member->state_code,
  133. 'mymember_state' => $member->state,
  134. 'mymember_phone_perso' => $member->phone_perso,
  135. 'mymember_phone_pro' => $member->phone,
  136. 'mymember_phone_mobile' => $member->phone_mobile,
  137. 'mymember_email' => $member->email,
  138. 'mymember_logo' => $logotouse,
  139. 'mymember_gender' => $member->gender,
  140. 'mymember_birth_locale' => dol_print_date($member->birth, 'day', 'tzuser', $outputlangs),
  141. 'mymember_birth' => dol_print_date($member->birth, 'day', 'tzuser'),
  142. );
  143. // Retrieve extrafields
  144. if (is_array($member->array_options) && count($member->array_options)) {
  145. $array_member = $this->fill_substitutionarray_with_extrafields($member, $array_member, $extrafields, 'mymember', $outputlangs);
  146. }
  147. return $array_member;
  148. }
  149. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
  150. /**
  151. * Define array with couple substitution key => substitution value
  152. *
  153. * @param Societe $mysoc Object thirdparty
  154. * @param Translate $outputlangs Language object for output
  155. * @return array Array of substitution key->code
  156. */
  157. public function get_substitutionarray_mysoc($mysoc, $outputlangs)
  158. {
  159. // phpcs:enable
  160. global $conf;
  161. if (empty($mysoc->forme_juridique) && !empty($mysoc->forme_juridique_code)) {
  162. $mysoc->forme_juridique = getFormeJuridiqueLabel($mysoc->forme_juridique_code);
  163. }
  164. if (empty($mysoc->country) && !empty($mysoc->country_code)) {
  165. $mysoc->country = $outputlangs->transnoentitiesnoconv("Country".$mysoc->country_code);
  166. }
  167. if (empty($mysoc->state) && !empty($mysoc->state_code)) {
  168. $mysoc->state = getState($mysoc->state_code, 0);
  169. }
  170. $logotouse = $conf->mycompany->dir_output.'/logos/thumbs/'.$mysoc->logo_small;
  171. return array(
  172. 'mycompany_logo'=>$logotouse,
  173. 'mycompany_name'=>$mysoc->name,
  174. 'mycompany_email'=>$mysoc->email,
  175. 'mycompany_phone'=>$mysoc->phone,
  176. 'mycompany_fax'=>$mysoc->fax,
  177. 'mycompany_address'=>$mysoc->address,
  178. 'mycompany_zip'=>$mysoc->zip,
  179. 'mycompany_town'=>$mysoc->town,
  180. 'mycompany_country'=>$mysoc->country,
  181. 'mycompany_country_code'=>$mysoc->country_code,
  182. 'mycompany_state'=>$mysoc->state,
  183. 'mycompany_state_code'=>$mysoc->state_code,
  184. 'mycompany_web'=>$mysoc->url,
  185. 'mycompany_juridicalstatus'=>$mysoc->forme_juridique,
  186. 'mycompany_managers'=>$mysoc->managers,
  187. 'mycompany_capital'=>$mysoc->capital,
  188. 'mycompany_barcode'=>$mysoc->barcode,
  189. 'mycompany_idprof1'=>$mysoc->idprof1,
  190. 'mycompany_idprof2'=>$mysoc->idprof2,
  191. 'mycompany_idprof3'=>$mysoc->idprof3,
  192. 'mycompany_idprof4'=>$mysoc->idprof4,
  193. 'mycompany_idprof5'=>$mysoc->idprof5,
  194. 'mycompany_idprof6'=>$mysoc->idprof6,
  195. 'mycompany_vatnumber'=>$mysoc->tva_intra,
  196. 'mycompany_object'=>$mysoc->object,
  197. 'mycompany_note_private'=>$mysoc->note_private,
  198. //'mycompany_note_public'=>$mysoc->note_public, // Only private not exists for "mysoc" but both for thirdparties
  199. );
  200. }
  201. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
  202. /**
  203. * Define array with couple substitution key => substitution value
  204. * For example {company_name}, {company_name_alias}
  205. *
  206. * @param Societe $object Object
  207. * @param Translate $outputlangs Language object for output
  208. * @param string $array_key Name of the key for return array
  209. * @return array Array of substitution key->code
  210. */
  211. public function get_substitutionarray_thirdparty($object, $outputlangs, $array_key = 'company')
  212. {
  213. // phpcs:enable
  214. global $conf, $extrafields;
  215. if (empty($object->country) && !empty($object->country_code)) {
  216. $object->country = $outputlangs->transnoentitiesnoconv("Country".$object->country_code);
  217. }
  218. if (empty($object->state) && !empty($object->state_code)) {
  219. $object->state = getState($object->state_code, 0);
  220. }
  221. $array_thirdparty = array(
  222. 'company_name'=>$object->name,
  223. 'company_name_alias' => $object->name_alias,
  224. 'company_email'=>$object->email,
  225. 'company_phone'=>$object->phone,
  226. 'company_fax'=>$object->fax,
  227. 'company_address'=>$object->address,
  228. 'company_zip'=>$object->zip,
  229. 'company_town'=>$object->town,
  230. 'company_country'=>$object->country,
  231. 'company_country_code'=>$object->country_code,
  232. 'company_state'=>$object->state,
  233. 'company_state_code'=>$object->state_code,
  234. 'company_web'=>$object->url,
  235. 'company_barcode'=>$object->barcode,
  236. 'company_vatnumber'=>$object->tva_intra,
  237. 'company_customercode'=>$object->code_client,
  238. 'company_suppliercode'=>$object->code_fournisseur,
  239. 'company_customeraccountancycode'=>$object->code_compta,
  240. 'company_supplieraccountancycode'=>$object->code_compta_fournisseur,
  241. 'company_juridicalstatus'=>$object->forme_juridique,
  242. 'company_outstanding_limit'=>$object->outstanding_limit,
  243. 'company_capital'=>$object->capital,
  244. 'company_idprof1'=>$object->idprof1,
  245. 'company_idprof2'=>$object->idprof2,
  246. 'company_idprof3'=>$object->idprof3,
  247. 'company_idprof4'=>$object->idprof4,
  248. 'company_idprof5'=>$object->idprof5,
  249. 'company_idprof6'=>$object->idprof6,
  250. 'company_note_public'=>$object->note_public,
  251. 'company_note_private'=>$object->note_private,
  252. 'company_default_bank_iban'=>(is_object($object->bank_account) ? $object->bank_account->iban : ''),
  253. 'company_default_bank_bic'=>(is_object($object->bank_account) ? $object->bank_account->bic : '')
  254. );
  255. // Retrieve extrafields
  256. if (is_array($object->array_options) && count($object->array_options)) {
  257. $object->fetch_optionals();
  258. $array_thirdparty = $this->fill_substitutionarray_with_extrafields($object, $array_thirdparty, $extrafields, $array_key, $outputlangs);
  259. }
  260. return $array_thirdparty;
  261. }
  262. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
  263. /**
  264. * Define array with couple substitution key => substitution value
  265. *
  266. * @param Contact $object contact
  267. * @param Translate $outputlangs object for output
  268. * @param string $array_key Name of the key for return array
  269. * @return array Array of substitution key->code
  270. */
  271. public function get_substitutionarray_contact($object, $outputlangs, $array_key = 'object')
  272. {
  273. // phpcs:enable
  274. global $conf, $extrafields;
  275. if (empty($object->country) && !empty($object->country_code)) {
  276. $object->country = $outputlangs->transnoentitiesnoconv("Country".$object->country_code);
  277. }
  278. if (empty($object->state) && !empty($object->state_code)) {
  279. $object->state = getState($object->state_code, 0);
  280. }
  281. $array_contact = array(
  282. $array_key.'_fullname' => $object->getFullName($outputlangs, 1),
  283. $array_key.'_lastname' => $object->lastname,
  284. $array_key.'_firstname' => $object->firstname,
  285. $array_key.'_address' => $object->address,
  286. $array_key.'_zip' => $object->zip,
  287. $array_key.'_town' => $object->town,
  288. $array_key.'_state_id' => $object->state_id,
  289. $array_key.'_state_code' => $object->state_code,
  290. $array_key.'_state' => $object->state,
  291. $array_key.'_country_id' => $object->country_id,
  292. $array_key.'_country_code' => $object->country_code,
  293. $array_key.'_country' => $object->country,
  294. $array_key.'_poste' => $object->poste,
  295. $array_key.'_socid' => $object->socid,
  296. $array_key.'_statut' => $object->statut,
  297. $array_key.'_code' => $object->code,
  298. $array_key.'_email' => $object->email,
  299. $array_key.'_phone_pro' => $object->phone_pro,
  300. $array_key.'_phone_perso' => $object->phone_perso,
  301. $array_key.'_phone_mobile' => $object->phone_mobile,
  302. $array_key.'_fax' => $object->fax,
  303. $array_key.'_birthday' => $object->birthday,
  304. $array_key.'_default_lang' => $object->default_lang,
  305. $array_key.'_note_public' => $object->note_public,
  306. $array_key.'_note_private' => $object->note_private,
  307. $array_key.'_civility' => $object->civility,
  308. );
  309. // Retrieve extrafields
  310. if (is_array($object->array_options) && count($object->array_options)) {
  311. $object->fetch_optionals();
  312. $array_contact = $this->fill_substitutionarray_with_extrafields($object, $array_contact, $extrafields, $array_key, $outputlangs);
  313. }
  314. return $array_contact;
  315. }
  316. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
  317. /**
  318. * Define array with couple substitution key => substitution value
  319. *
  320. * @param Translate $outputlangs Language object for output
  321. * @return array Array of substitution key->code
  322. */
  323. public function get_substitutionarray_other($outputlangs)
  324. {
  325. // phpcs:enable
  326. global $conf;
  327. $now = dol_now('gmt'); // gmt
  328. $array_other = array(
  329. // Date in default language
  330. 'current_date'=>dol_print_date($now, 'day', 'tzuser'),
  331. 'current_datehour'=>dol_print_date($now, 'dayhour', 'tzuser'),
  332. 'current_server_date'=>dol_print_date($now, 'day', 'tzserver'),
  333. 'current_server_datehour'=>dol_print_date($now, 'dayhour', 'tzserver'),
  334. // Date in requested output language
  335. 'current_date_locale'=>dol_print_date($now, 'day', 'tzuser', $outputlangs),
  336. 'current_datehour_locale'=>dol_print_date($now, 'dayhour', 'tzuser', $outputlangs),
  337. 'current_server_date_locale'=>dol_print_date($now, 'day', 'tzserver', $outputlangs),
  338. 'current_server_datehour_locale'=>dol_print_date($now, 'dayhour', 'tzserver', $outputlangs),
  339. );
  340. foreach ($conf->global as $key => $val) {
  341. if (isASecretKey($key)) {
  342. $newval = '*****forbidden*****';
  343. } else {
  344. $newval = $val;
  345. }
  346. $array_other['__['.$key.']__'] = $newval;
  347. }
  348. return $array_other;
  349. }
  350. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
  351. /**
  352. * Define array with couple substitution key => substitution value
  353. *
  354. * @param Object $object Main object to use as data source
  355. * @param Translate $outputlangs Lang object to use for output
  356. * @param string $array_key Name of the key for return array
  357. * @return array Array of substitution
  358. */
  359. public function get_substitutionarray_object($object, $outputlangs, $array_key = 'object')
  360. {
  361. // phpcs:enable
  362. global $conf, $extrafields;
  363. $sumpayed = $sumdeposit = $sumcreditnote = '';
  364. $already_payed_all = 0;
  365. if ($object->element == 'facture') {
  366. $invoice_source = new Facture($this->db);
  367. if ($object->fk_facture_source > 0) {
  368. $invoice_source->fetch($object->fk_facture_source);
  369. }
  370. $sumpayed = $object->getSommePaiement();
  371. $sumdeposit = $object->getSumDepositsUsed();
  372. $sumcreditnote = $object->getSumCreditNotesUsed();
  373. $already_payed_all = $sumpayed + $sumdeposit + $sumcreditnote;
  374. if ($object->fk_account > 0) {
  375. require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php';
  376. $bank_account = new Account($this->db);
  377. $bank_account->fetch($object->fk_account);
  378. }
  379. }
  380. $date = ($object->element == 'contrat' ? $object->date_contrat : $object->date);
  381. $resarray = array(
  382. $array_key.'_id'=>$object->id,
  383. $array_key.'_ref'=>$object->ref,
  384. $array_key.'_ref_ext'=>$object->ref_ext,
  385. $array_key.'_ref_customer'=>(!empty($object->ref_client) ? $object->ref_client : (empty($object->ref_customer) ? '' : $object->ref_customer)),
  386. $array_key.'_ref_supplier'=>(!empty($object->ref_fournisseur) ? $object->ref_fournisseur : (empty($object->ref_supplier) ? '' : $object->ref_supplier)),
  387. $array_key.'_source_invoice_ref'=>$invoice_source->ref,
  388. // Dates
  389. $array_key.'_hour'=>dol_print_date($date, 'hour'),
  390. $array_key.'_date'=>dol_print_date($date, 'day'),
  391. $array_key.'_date_rfc'=>dol_print_date($date, 'dayrfc'),
  392. $array_key.'_date_limit'=>(!empty($object->date_lim_reglement) ?dol_print_date($object->date_lim_reglement, 'day') : ''),
  393. $array_key.'_date_end'=>(!empty($object->fin_validite) ?dol_print_date($object->fin_validite, 'day') : ''),
  394. $array_key.'_date_creation'=>dol_print_date($object->date_creation, 'day'),
  395. $array_key.'_date_modification'=>(!empty($object->date_modification) ?dol_print_date($object->date_modification, 'day') : ''),
  396. $array_key.'_date_validation'=>(!empty($object->date_validation) ?dol_print_date($object->date_validation, 'dayhour') : ''),
  397. $array_key.'_date_delivery_planed'=>(!empty($object->date_livraison) ?dol_print_date($object->date_livraison, 'day') : ''),
  398. $array_key.'_date_close'=>(!empty($object->date_cloture) ?dol_print_date($object->date_cloture, 'dayhour') : ''),
  399. $array_key.'_payment_mode_code'=>$object->mode_reglement_code,
  400. $array_key.'_payment_mode'=>($outputlangs->transnoentitiesnoconv('PaymentType'.$object->mode_reglement_code) != 'PaymentType'.$object->mode_reglement_code ? $outputlangs->transnoentitiesnoconv('PaymentType'.$object->mode_reglement_code) : $object->mode_reglement),
  401. $array_key.'_payment_term_code'=>$object->cond_reglement_code,
  402. $array_key.'_payment_term'=>($outputlangs->transnoentitiesnoconv('PaymentCondition'.$object->cond_reglement_code) != 'PaymentCondition'.$object->cond_reglement_code ? $outputlangs->transnoentitiesnoconv('PaymentCondition'.$object->cond_reglement_code) : ($object->cond_reglement_doc ? $object->cond_reglement_doc : $object->cond_reglement)),
  403. $array_key.'_incoterms'=>(method_exists($object, 'display_incoterms') ? $object->display_incoterms() : ''),
  404. $array_key.'_bank_iban'=>$bank_account->iban,
  405. $array_key.'_bank_bic'=>$bank_account->bic,
  406. $array_key.'_bank_label'=>$bank_account->label,
  407. $array_key.'_bank_number'=>$bank_account->number,
  408. $array_key.'_bank_proprio'=>$bank_account->proprio,
  409. $array_key.'_total_ht_locale'=>price($object->total_ht, 0, $outputlangs),
  410. $array_key.'_total_vat_locale'=>(!empty($object->total_vat) ?price($object->total_vat, 0, $outputlangs) : price($object->total_tva, 0, $outputlangs)),
  411. $array_key.'_total_localtax1_locale'=>price($object->total_localtax1, 0, $outputlangs),
  412. $array_key.'_total_localtax2_locale'=>price($object->total_localtax2, 0, $outputlangs),
  413. $array_key.'_total_ttc_locale'=>price($object->total_ttc, 0, $outputlangs),
  414. $array_key.'_total_ht'=>price2num($object->total_ht),
  415. $array_key.'_total_vat'=>(!empty($object->total_vat) ?price2num($object->total_vat) : price2num($object->total_tva)),
  416. $array_key.'_total_localtax1'=>price2num($object->total_localtax1),
  417. $array_key.'_total_localtax2'=>price2num($object->total_localtax2),
  418. $array_key.'_total_ttc'=>price2num($object->total_ttc),
  419. $array_key.'_multicurrency_code' => $object->multicurrency_code,
  420. $array_key.'_multicurrency_tx' => price2num($object->multicurrency_tx),
  421. $array_key.'_multicurrency_total_ht' => price2num($object->multicurrency_total_ht),
  422. $array_key.'_multicurrency_total_tva' => price2num($object->multicurrency_total_tva),
  423. $array_key.'_multicurrency_total_ttc' => price2num($object->multicurrency_total_ttc),
  424. $array_key.'_multicurrency_total_ht_locale' => price($object->multicurrency_total_ht, 0, $outputlangs),
  425. $array_key.'_multicurrency_total_tva_locale' => price($object->multicurrency_total_tva, 0, $outputlangs),
  426. $array_key.'_multicurrency_total_ttc_locale' => price($object->multicurrency_total_ttc, 0, $outputlangs),
  427. $array_key.'_note_private'=>$object->note,
  428. $array_key.'_note_public'=>$object->note_public,
  429. $array_key.'_note'=>$object->note_public, // For backward compatibility
  430. // Payments
  431. $array_key.'_already_payed_locale'=>price($sumpayed, 0, $outputlangs),
  432. $array_key.'_already_payed'=>price2num($sumpayed),
  433. $array_key.'_already_deposit_locale'=>price($sumdeposit, 0, $outputlangs),
  434. $array_key.'_already_deposit'=>price2num($sumdeposit),
  435. $array_key.'_already_creditnote_locale'=>price($sumcreditnote, 0, $outputlangs),
  436. $array_key.'_already_creditnote'=>price2num($sumcreditnote),
  437. $array_key.'_already_payed_all_locale'=>price(price2num($already_payed_all, 'MT'), 0, $outputlangs),
  438. $array_key.'_already_payed_all'=> price2num($already_payed_all, 'MT'),
  439. // Remain to pay with all known information (except open direct debit requests)
  440. $array_key.'_remain_to_pay_locale'=>price(price2num($object->total_ttc - $already_payed_all, 'MT'), 0, $outputlangs),
  441. $array_key.'_remain_to_pay'=>price2num($object->total_ttc - $already_payed_all, 'MT')
  442. );
  443. if (method_exists($object, 'getTotalDiscount') && in_array(get_class($object), array('Propal', 'Proposal', 'Commande', 'Facture', 'SupplierProposal', 'CommandeFournisseur', 'FactureFournisseur'))) {
  444. $resarray[$array_key.'_total_discount_ht_locale'] = price($object->getTotalDiscount(), 0, $outputlangs);
  445. $resarray[$array_key.'_total_discount_ht'] = price2num($object->getTotalDiscount());
  446. } else {
  447. $resarray[$array_key.'_total_discount_ht_locale'] = '';
  448. $resarray[$array_key.'_total_discount_ht'] = '';
  449. }
  450. // Fetch project information if there is a project assigned to this object
  451. if ($object->element != "project" && !empty($object->fk_project) && $object->fk_project > 0) {
  452. if (!is_object($object->project)) {
  453. $object->fetch_projet();
  454. }
  455. $resarray[$array_key.'_project_ref'] = $object->project->ref;
  456. $resarray[$array_key.'_project_title'] = $object->project->title;
  457. $resarray[$array_key.'_project_description'] = $object->project->description;
  458. $resarray[$array_key.'_project_date_start'] = dol_print_date($object->project->date_start, 'day');
  459. $resarray[$array_key.'_project_date_end'] = dol_print_date($object->project->date_end, 'day');
  460. }
  461. // Add vat by rates
  462. if (is_array($object->lines) && count($object->lines) > 0) {
  463. $totalUp = 0;
  464. // Set substitution keys for different VAT rates
  465. foreach ($object->lines as $line) {
  466. // $line->tva_tx format depends on database field accuracy, no reliable. This is kept for backward compatibility
  467. if (empty($resarray[$array_key.'_total_vat_'.$line->tva_tx])) {
  468. $resarray[$array_key.'_total_vat_'.$line->tva_tx] = 0;
  469. }
  470. $resarray[$array_key.'_total_vat_'.$line->tva_tx] += $line->total_tva;
  471. $resarray[$array_key.'_total_vat_locale_'.$line->tva_tx] = price($resarray[$array_key.'_total_vat_'.$line->tva_tx]);
  472. // $vatformated is vat without not expected chars (so 20, or 8.5 or 5.99 for example)
  473. $vatformated = vatrate($line->tva_tx);
  474. if (empty($resarray[$array_key.'_total_vat_'.$vatformated])) {
  475. $resarray[$array_key.'_total_vat_'.$vatformated] = 0;
  476. }
  477. $resarray[$array_key.'_total_vat_'.$vatformated] += $line->total_tva;
  478. $resarray[$array_key.'_total_vat_locale_'.$vatformated] = price($resarray[$array_key.'_total_vat_'.$vatformated]);
  479. $totalUp += $line->subprice * $line->qty;
  480. }
  481. // Calculate total up and total discount percentage
  482. // Note that this added fields does not match a field into database in Dolibarr (Dolibarr manage discount on lines not as a global property of object)
  483. $resarray['object_total_up'] = $totalUp;
  484. $resarray['object_total_up_locale'] = price($resarray['object_total_up'], 0, $outputlangs);
  485. if (method_exists($object, 'getTotalDiscount') && in_array(get_class($object), array('Propal', 'Proposal', 'Commande', 'Facture', 'SupplierProposal', 'CommandeFournisseur', 'FactureFournisseur'))) {
  486. $totalDiscount = $object->getTotalDiscount();
  487. } else {
  488. $totalDiscount = 0;
  489. }
  490. if (!empty($totalUp) && !empty($totalDiscount)) {
  491. $resarray['object_total_discount'] = round(100 / $totalUp * $totalDiscount, 2);
  492. $resarray['object_total_discount_locale'] = price($resarray['object_total_discount'], 0, $outputlangs);
  493. } else {
  494. $resarray['object_total_discount'] = '';
  495. $resarray['object_total_discount_locale'] = '';
  496. }
  497. }
  498. // Retrieve extrafields
  499. if (is_array($object->array_options) && count($object->array_options)) {
  500. $object->fetch_optionals();
  501. $resarray = $this->fill_substitutionarray_with_extrafields($object, $resarray, $extrafields, $array_key, $outputlangs);
  502. }
  503. return $resarray;
  504. }
  505. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
  506. /**
  507. * Define array with couple substitution key => substitution value
  508. *
  509. * @param Object $line Object line
  510. * @param Translate $outputlangs Lang object to use for output
  511. * @param int $linenumber The number of the line for the substitution of "object_line_pos"
  512. * @return array Return a substitution array
  513. */
  514. public function get_substitutionarray_lines($line, $outputlangs, $linenumber = 0)
  515. {
  516. // phpcs:enable
  517. global $conf;
  518. $resarray = array(
  519. 'line_pos' => $linenumber,
  520. 'line_fulldesc'=>doc_getlinedesc($line, $outputlangs),
  521. 'line_product_ref'=>(empty($line->product_ref) ? '' : $line->product_ref),
  522. 'line_product_ref_fourn'=>(empty($line->ref_fourn) ? '' : $line->ref_fourn), // for supplier doc lines
  523. 'line_product_label'=>(empty($line->product_label) ? '' : $line->product_label),
  524. 'line_product_type'=>(empty($line->product_type) ? '' : $line->product_type),
  525. 'line_product_barcode'=>(empty($line->product_barcode) ? '' : $line->product_barcode),
  526. 'line_desc'=>$line->desc,
  527. 'line_vatrate'=>vatrate($line->tva_tx, true, $line->info_bits),
  528. 'line_localtax1_rate'=>vatrate($line->localtax1_tx),
  529. 'line_localtax2_rate'=>vatrate($line->localtax1_tx),
  530. 'line_up'=>price2num($line->subprice),
  531. 'line_up_locale'=>price($line->subprice, 0, $outputlangs),
  532. 'line_total_up'=>price2num($line->subprice * $line->qty),
  533. 'line_total_up_locale'=>price($line->subprice * $line->qty, 0, $outputlangs),
  534. 'line_qty'=>$line->qty,
  535. 'line_discount_percent'=>($line->remise_percent ? $line->remise_percent.'%' : ''),
  536. 'line_price_ht'=>price2num($line->total_ht),
  537. 'line_price_ttc'=>price2num($line->total_ttc),
  538. 'line_price_vat'=>price2num($line->total_tva),
  539. 'line_price_ht_locale'=>price($line->total_ht, 0, $outputlangs),
  540. 'line_price_ttc_locale'=>price($line->total_ttc, 0, $outputlangs),
  541. 'line_price_vat_locale'=>price($line->total_tva, 0, $outputlangs),
  542. // Dates
  543. 'line_date_start'=>dol_print_date($line->date_start, 'day'),
  544. 'line_date_start_locale'=>dol_print_date($line->date_start, 'day', 'tzserver', $outputlangs),
  545. 'line_date_start_rfc'=>dol_print_date($line->date_start, 'dayrfc'),
  546. 'line_date_end'=>dol_print_date($line->date_end, 'day'),
  547. 'line_date_end_locale'=>dol_print_date($line->date_end, 'day', 'tzserver', $outputlangs),
  548. 'line_date_end_rfc'=>dol_print_date($line->date_end, 'dayrfc'),
  549. 'line_multicurrency_code' => price2num($line->multicurrency_code),
  550. 'line_multicurrency_subprice' => price2num($line->multicurrency_subprice),
  551. 'line_multicurrency_total_ht' => price2num($line->multicurrency_total_ht),
  552. 'line_multicurrency_total_tva' => price2num($line->multicurrency_total_tva),
  553. 'line_multicurrency_total_ttc' => price2num($line->multicurrency_total_ttc),
  554. 'line_multicurrency_subprice_locale' => price($line->multicurrency_subprice, 0, $outputlangs),
  555. 'line_multicurrency_total_ht_locale' => price($line->multicurrency_total_ht, 0, $outputlangs),
  556. 'line_multicurrency_total_tva_locale' => price($line->multicurrency_total_tva, 0, $outputlangs),
  557. 'line_multicurrency_total_ttc_locale' => price($line->multicurrency_total_ttc, 0, $outputlangs),
  558. );
  559. // Units
  560. if (!empty($conf->global->PRODUCT_USE_UNITS)) {
  561. $resarray['line_unit'] = $outputlangs->trans($line->getLabelOfUnit('long'));
  562. $resarray['line_unit_short'] = $outputlangs->trans($line->getLabelOfUnit('short'));
  563. }
  564. // Retrieve extrafields
  565. $extrafieldkey = $line->table_element;
  566. $array_key = "line";
  567. require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
  568. $extrafields = new ExtraFields($this->db);
  569. $extrafields->fetch_name_optionals_label($extrafieldkey, true);
  570. $line->fetch_optionals();
  571. $resarray = $this->fill_substitutionarray_with_extrafields($line, $resarray, $extrafields, $array_key, $outputlangs);
  572. // Check if the current line belongs to a supplier order
  573. if (get_class($line) == 'CommandeFournisseurLigne') {
  574. // Add the product supplier extrafields to the substitutions
  575. $extrafields->fetch_name_optionals_label("product_fournisseur_price");
  576. $extralabels = $extrafields->attributes["product_fournisseur_price"]['label'];
  577. if (!empty($extralabels) && is_array($extralabels)) {
  578. $columns = "";
  579. foreach ($extralabels as $key => $label) {
  580. $columns .= "$key, ";
  581. }
  582. if ($columns != "") {
  583. $columns = substr($columns, 0, strlen($columns) - 2);
  584. $resql = $this->db->query("SELECT ".$columns." FROM ".$this->db->prefix()."product_fournisseur_price_extrafields AS ex INNER JOIN ".$this->db->prefix()."product_fournisseur_price AS f ON ex.fk_object = f.rowid WHERE f.ref_fourn = '".$this->db->escape($line->ref_supplier)."'");
  585. if ($this->db->num_rows($resql) > 0) {
  586. $resql = $this->db->fetch_object($resql);
  587. foreach ($extralabels as $key => $label) {
  588. $resarray['line_product_supplier_'.$key] = $resql->{$key};
  589. }
  590. }
  591. }
  592. }
  593. }
  594. // Load product data optional fields to the line -> enables to use "line_options_{extrafield}"
  595. if (isset($line->fk_product) && $line->fk_product > 0) {
  596. $tmpproduct = new Product($this->db);
  597. $result = $tmpproduct->fetch($line->fk_product);
  598. foreach ($tmpproduct->array_options as $key => $label) {
  599. $resarray["line_product_".$key] = $label;
  600. }
  601. }
  602. return $resarray;
  603. }
  604. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
  605. /**
  606. * Define array with couple substitution key => substitution value
  607. *
  608. * @param Expedition $object Main object to use as data source
  609. * @param Translate $outputlangs Lang object to use for output
  610. * @param array $array_key Name of the key for return array
  611. * @return array Array of substitution
  612. */
  613. public function get_substitutionarray_shipment($object, $outputlangs, $array_key = 'object')
  614. {
  615. // phpcs:enable
  616. global $conf, $extrafields;
  617. dol_include_once('/core/lib/product.lib.php');
  618. $object->list_delivery_methods($object->shipping_method_id);
  619. $calculatedVolume = ($object->trueWidth * $object->trueHeight * $object->trueDepth);
  620. $array_shipment = array(
  621. $array_key.'_id'=>$object->id,
  622. $array_key.'_ref'=>$object->ref,
  623. $array_key.'_ref_ext'=>$object->ref_ext,
  624. $array_key.'_ref_customer'=>$object->ref_customer,
  625. $array_key.'_date_delivery'=>dol_print_date($object->date_delivery, 'day'),
  626. $array_key.'_hour_delivery'=>dol_print_date($object->date_delivery, 'hour'),
  627. $array_key.'_date_creation'=>dol_print_date($object->date_creation, 'day'),
  628. $array_key.'_total_ht'=>price($object->total_ht),
  629. $array_key.'_total_vat'=>price($object->total_tva),
  630. $array_key.'_total_ttc'=>price($object->total_ttc),
  631. $array_key.'_total_discount_ht' => price($object->getTotalDiscount()),
  632. $array_key.'_note_private'=>$object->note_private,
  633. $array_key.'_note'=>$object->note_public,
  634. $array_key.'_tracking_number'=>$object->tracking_number,
  635. $array_key.'_tracking_url'=>$object->tracking_url,
  636. $array_key.'_shipping_method'=>$object->listmeths[0]['libelle'],
  637. $array_key.'_weight'=>$object->trueWeight.' '.measuringUnitString(0, 'weight', $object->weight_units),
  638. $array_key.'_width'=>$object->trueWidth.' '.measuringUnitString(0, 'size', $object->width_units),
  639. $array_key.'_height'=>$object->trueHeight.' '.measuringUnitString(0, 'size', $object->height_units),
  640. $array_key.'_depth'=>$object->trueDepth.' '.measuringUnitString(0, 'size', $object->depth_units),
  641. $array_key.'_size'=>$calculatedVolume.' '.measuringUnitString(0, 'volume'),
  642. );
  643. // Add vat by rates
  644. foreach ($object->lines as $line) {
  645. if (empty($array_shipment[$array_key.'_total_vat_'.$line->tva_tx])) {
  646. $array_shipment[$array_key.'_total_vat_'.$line->tva_tx] = 0;
  647. }
  648. $array_shipment[$array_key.'_total_vat_'.$line->tva_tx] += $line->total_tva;
  649. }
  650. // Retrieve extrafields
  651. if (is_array($object->array_options) && count($object->array_options)) {
  652. $object->fetch_optionals();
  653. $array_shipment = $this->fill_substitutionarray_with_extrafields($object, $array_shipment, $extrafields, $array_key, $outputlangs);
  654. }
  655. // Add infor from $object->xxx where xxx has been loaded by fetch_origin() of shipment
  656. if (!empty($object->commande) && is_object($object->commande)) {
  657. $array_shipment['order_ref'] = $object->commande->ref;
  658. $array_shipment['order_ref_customer'] = $object->commande->ref_customer;
  659. }
  660. return $array_shipment;
  661. }
  662. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
  663. /**
  664. * Define array with couple substitution key => substitution value
  665. *
  666. * @param ExpeditionLigne $line Object line
  667. * @param Translate $outputlangs Lang object to use for output
  668. * @return array Substitution array
  669. */
  670. public function get_substitutionarray_shipment_lines($line, $outputlangs)
  671. {
  672. // phpcs:enable
  673. global $conf;
  674. dol_include_once('/core/lib/product.lib.php');
  675. $resarray = array(
  676. 'line_fulldesc'=>doc_getlinedesc($line, $outputlangs),
  677. 'line_product_ref'=>$line->product_ref,
  678. 'line_product_label'=>$line->product_label,
  679. 'line_desc'=>$line->desc,
  680. 'line_vatrate'=>vatrate($line->tva_tx, true, $line->info_bits),
  681. 'line_up'=>price($line->subprice),
  682. 'line_total_up'=>price($line->subprice * $line->qty),
  683. 'line_qty'=>$line->qty,
  684. 'line_qty_shipped'=>$line->qty_shipped,
  685. 'line_qty_asked'=>$line->qty_asked,
  686. 'line_discount_percent'=>($line->remise_percent ? $line->remise_percent.'%' : ''),
  687. 'line_price_ht'=>price($line->total_ht),
  688. 'line_price_ttc'=>price($line->total_ttc),
  689. 'line_price_vat'=>price($line->total_tva),
  690. 'line_weight'=>empty($line->weight) ? '' : $line->weight * $line->qty_shipped.' '.measuringUnitString(0, 'weight', $line->weight_units),
  691. 'line_length'=>empty($line->length) ? '' : $line->length * $line->qty_shipped.' '.measuringUnitString(0, 'size', $line->length_units),
  692. 'line_surface'=>empty($line->surface) ? '' : $line->surface * $line->qty_shipped.' '.measuringUnitString(0, 'surface', $line->surface_units),
  693. 'line_volume'=>empty($line->volume) ? '' : $line->volume * $line->qty_shipped.' '.measuringUnitString(0, 'volume', $line->volume_units),
  694. );
  695. // Retrieve extrafields
  696. $extrafieldkey = $line->element;
  697. $array_key = "line";
  698. require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
  699. $extrafields = new ExtraFields($this->db);
  700. $extrafields->fetch_name_optionals_label($extrafieldkey, true);
  701. $line->fetch_optionals();
  702. $resarray = $this->fill_substitutionarray_with_extrafields($line, $resarray, $extrafields, $array_key, $outputlangs);
  703. // Load product data optional fields to the line -> enables to use "line_product_options_{extrafield}"
  704. if (isset($line->fk_product) && $line->fk_product > 0) {
  705. $tmpproduct = new Product($this->db);
  706. $tmpproduct->fetch($line->fk_product);
  707. foreach ($tmpproduct->array_options as $key=>$label)
  708. $resarray["line_product_".$key] = $label;
  709. }
  710. return $resarray;
  711. }
  712. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
  713. /**
  714. * Define array with couple substitution key => substitution value
  715. *
  716. * @param Object $object Dolibarr Object
  717. * @param Translate $outputlangs Language object for output
  718. * @param boolean $recursive Want to fetch child array or child object
  719. * @return array Array of substitution key->code
  720. */
  721. public function get_substitutionarray_each_var_object(&$object, $outputlangs, $recursive = true)
  722. {
  723. // phpcs:enable
  724. $array_other = array();
  725. if (!empty($object)) {
  726. foreach ($object as $key => $value) {
  727. if (!empty($value)) {
  728. if (!is_array($value) && !is_object($value)) {
  729. $array_other['object_'.$key] = $value;
  730. }
  731. if (is_array($value) && $recursive) {
  732. $array_other['object_'.$key] = $this->get_substitutionarray_each_var_object($value, $outputlangs, false);
  733. }
  734. }
  735. }
  736. }
  737. return $array_other;
  738. }
  739. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
  740. /**
  741. * Fill array with couple extrafield key => extrafield value
  742. *
  743. * @param Object $object Object with extrafields (must have $object->array_options filled)
  744. * @param array $array_to_fill Substitution array
  745. * @param Extrafields $extrafields Extrafields object
  746. * @param string $array_key Prefix for name of the keys into returned array
  747. * @param Translate $outputlangs Lang object to use for output
  748. * @return array Substitution array
  749. */
  750. public function fill_substitutionarray_with_extrafields($object, $array_to_fill, $extrafields, $array_key, $outputlangs)
  751. {
  752. // phpcs:enable
  753. global $conf;
  754. if (is_array($extrafields->attributes[$object->table_element]['label'])) {
  755. foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $label) {
  756. if ($extrafields->attributes[$object->table_element]['type'][$key] == 'price') {
  757. $object->array_options['options_'.$key] = price2num($object->array_options['options_'.$key]);
  758. $object->array_options['options_'.$key.'_currency'] = price($object->array_options['options_'.$key], 0, $outputlangs, 0, 0, -1, $conf->currency);
  759. //Add value to store price with currency
  760. $array_to_fill = array_merge($array_to_fill, array($array_key.'_options_'.$key.'_currency' => $object->array_options['options_'.$key.'_currency']));
  761. } elseif ($extrafields->attributes[$object->table_element]['type'][$key] == 'select') {
  762. $object->array_options['options_'.$key] = $extrafields->attributes[$object->table_element]['param'][$key]['options'][$object->array_options['options_'.$key]];
  763. } elseif ($extrafields->attributes[$object->table_element]['type'][$key] == 'checkbox') {
  764. $valArray = explode(',', $object->array_options['options_'.$key]);
  765. $output = array();
  766. foreach ($extrafields->attributes[$object->table_element]['param'][$key]['options'] as $keyopt => $valopt) {
  767. if (in_array($keyopt, $valArray)) {
  768. $output[] = $valopt;
  769. }
  770. }
  771. $object->array_options['options_'.$key] = implode(', ', $output);
  772. } elseif ($extrafields->attributes[$object->table_element]['type'][$key] == 'date') {
  773. if (strlen($object->array_options['options_'.$key]) > 0) {
  774. $date = $object->array_options['options_'.$key];
  775. $object->array_options['options_'.$key] = dol_print_date($date, 'day'); // using company output language
  776. $object->array_options['options_'.$key.'_locale'] = dol_print_date($date, 'day', 'tzserver', $outputlangs); // using output language format
  777. $object->array_options['options_'.$key.'_rfc'] = dol_print_date($date, 'dayrfc'); // international format
  778. } else {
  779. $object->array_options['options_'.$key] = '';
  780. $object->array_options['options_'.$key.'_locale'] = '';
  781. $object->array_options['options_'.$key.'_rfc'] = '';
  782. }
  783. $array_to_fill = array_merge($array_to_fill, array($array_key.'_options_'.$key.'_locale' => $object->array_options['options_'.$key.'_locale']));
  784. $array_to_fill = array_merge($array_to_fill, array($array_key.'_options_'.$key.'_rfc' => $object->array_options['options_'.$key.'_rfc']));
  785. } elseif ($extrafields->attributes[$object->table_element]['label'][$key] == 'datetime') {
  786. $datetime = $object->array_options['options_'.$key];
  787. $object->array_options['options_'.$key] = ($datetime != "0000-00-00 00:00:00" ?dol_print_date($object->array_options['options_'.$key], 'dayhour') : ''); // using company output language
  788. $object->array_options['options_'.$key.'_locale'] = ($datetime != "0000-00-00 00:00:00" ?dol_print_date($object->array_options['options_'.$key], 'dayhour', 'tzserver', $outputlangs) : ''); // using output language format
  789. $object->array_options['options_'.$key.'_rfc'] = ($datetime != "0000-00-00 00:00:00" ?dol_print_date($object->array_options['options_'.$key], 'dayhourrfc') : ''); // international format
  790. $array_to_fill = array_merge($array_to_fill, array($array_key.'_options_'.$key.'_locale' => $object->array_options['options_'.$key.'_locale']));
  791. $array_to_fill = array_merge($array_to_fill, array($array_key.'_options_'.$key.'_rfc' => $object->array_options['options_'.$key.'_rfc']));
  792. } elseif ($extrafields->attributes[$object->table_element]['type'][$key] == 'link') {
  793. $id = $object->array_options['options_'.$key];
  794. if ($id != "") {
  795. $param = $extrafields->attributes[$object->table_element]['param'][$key];
  796. $param_list = array_keys($param['options']); // $param_list='ObjectName:classPath'
  797. $InfoFieldList = explode(":", $param_list[0]);
  798. $classname = $InfoFieldList[0];
  799. $classpath = $InfoFieldList[1];
  800. if (!empty($classpath)) {
  801. dol_include_once($InfoFieldList[1]);
  802. if ($classname && class_exists($classname)) {
  803. $tmpobject = new $classname($this->db);
  804. $tmpobject->fetch($id);
  805. // completely replace the id with the linked object name
  806. $object->array_options['options_'.$key] = $tmpobject->name;
  807. }
  808. }
  809. }
  810. }
  811. $array_to_fill = array_merge($array_to_fill, array($array_key.'_options_'.$key => $object->array_options['options_'.$key]));
  812. }
  813. }
  814. return $array_to_fill;
  815. }
  816. /**
  817. * Rect pdf
  818. *
  819. * @param TCPDF $pdf Object PDF
  820. * @param float $x Abscissa of first point
  821. * @param float $y Ordinate of first point
  822. * @param float $l ??
  823. * @param float $h ??
  824. * @param int $hidetop 1=Hide top bar of array and title, 0=Hide nothing, -1=Hide only title
  825. * @param int $hidebottom Hide bottom
  826. * @return void
  827. */
  828. public function printRect($pdf, $x, $y, $l, $h, $hidetop = 0, $hidebottom = 0)
  829. {
  830. if (empty($hidetop) || $hidetop == -1) {
  831. $pdf->line($x, $y, $x + $l, $y);
  832. }
  833. $pdf->line($x + $l, $y, $x + $l, $y + $h);
  834. if (empty($hidebottom)) {
  835. $pdf->line($x + $l, $y + $h, $x, $y + $h);
  836. }
  837. $pdf->line($x, $y + $h, $x, $y);
  838. }
  839. /**
  840. * uasort callback function to Sort columns fields
  841. *
  842. * @param array $a PDF lines array fields configs
  843. * @param array $b PDF lines array fields configs
  844. * @return int Return compare result
  845. */
  846. public function columnSort($a, $b)
  847. {
  848. if (empty($a['rank'])) {
  849. $a['rank'] = 0;
  850. }
  851. if (empty($b['rank'])) {
  852. $b['rank'] = 0;
  853. }
  854. if ($a['rank'] == $b['rank']) {
  855. return 0;
  856. }
  857. return ($a['rank'] > $b['rank']) ? -1 : 1;
  858. }
  859. /**
  860. * Prepare Array Column Field
  861. *
  862. * @param object $object common object
  863. * @param Translate $outputlangs langs
  864. * @param int $hidedetails Do not show line details
  865. * @param int $hidedesc Do not show desc
  866. * @param int $hideref Do not show ref
  867. * @return null
  868. */
  869. public function prepareArrayColumnField($object, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0)
  870. {
  871. global $conf;
  872. $this->defineColumnField($object, $outputlangs, $hidedetails, $hidedesc, $hideref);
  873. // Sorting
  874. uasort($this->cols, array($this, 'columnSort'));
  875. // Positionning
  876. $curX = $this->page_largeur - $this->marge_droite; // start from right
  877. // Array width
  878. $arrayWidth = $this->page_largeur - $this->marge_droite - $this->marge_gauche;
  879. // Count flexible column
  880. $totalDefinedColWidth = 0;
  881. $countFlexCol = 0;
  882. foreach ($this->cols as $colKey => & $colDef) {
  883. if (!$this->getColumnStatus($colKey)) {
  884. continue; // continue if disabled
  885. }
  886. if (!empty($colDef['scale'])) {
  887. // In case of column width is defined by percentage
  888. $colDef['width'] = abs($arrayWidth * $colDef['scale'] / 100);
  889. }
  890. if (empty($colDef['width'])) {
  891. $countFlexCol++;
  892. } else {
  893. $totalDefinedColWidth += $colDef['width'];
  894. }
  895. }
  896. foreach ($this->cols as $colKey => & $colDef) {
  897. // setting empty conf with default
  898. if (!empty($colDef['title'])) {
  899. $colDef['title'] = array_replace($this->defaultTitlesFieldsStyle, $colDef['title']);
  900. } else {
  901. $colDef['title'] = $this->defaultTitlesFieldsStyle;
  902. }
  903. // setting empty conf with default
  904. if (!empty($colDef['content'])) {
  905. $colDef['content'] = array_replace($this->defaultContentsFieldsStyle, $colDef['content']);
  906. } else {
  907. $colDef['content'] = $this->defaultContentsFieldsStyle;
  908. }
  909. if ($this->getColumnStatus($colKey)) {
  910. // In case of flexible column
  911. if (empty($colDef['width'])) {
  912. $colDef['width'] = abs(($arrayWidth - $totalDefinedColWidth)) / $countFlexCol;
  913. }
  914. // Set positions
  915. $lastX = $curX;
  916. $curX = $lastX - $colDef['width'];
  917. $colDef['xStartPos'] = $curX;
  918. $colDef['xEndPos'] = $lastX;
  919. }
  920. }
  921. }
  922. /**
  923. * get column content width from column key
  924. *
  925. * @param string $colKey the column key
  926. * @return float width in mm
  927. */
  928. public function getColumnContentWidth($colKey)
  929. {
  930. $colDef = $this->cols[$colKey];
  931. return $colDef['width'] - $colDef['content']['padding'][3] - $colDef['content']['padding'][1];
  932. }
  933. /**
  934. * get column content X (abscissa) left position from column key
  935. *
  936. * @param string $colKey the column key
  937. * @return float X position in mm
  938. */
  939. public function getColumnContentXStart($colKey)
  940. {
  941. $colDef = $this->cols[$colKey];
  942. return $colDef['xStartPos'] + $colDef['content']['padding'][3];
  943. }
  944. /**
  945. * get column position rank from column key
  946. *
  947. * @param string $colKey the column key
  948. * @return int rank on success and -1 on error
  949. */
  950. public function getColumnRank($colKey)
  951. {
  952. if (!isset($this->cols[$colKey]['rank'])) {
  953. return -1;
  954. }
  955. return $this->cols[$colKey]['rank'];
  956. }
  957. /**
  958. * get column position rank from column key
  959. *
  960. * @param string $newColKey the new column key
  961. * @param array $defArray a single column definition array
  962. * @param string $targetCol target column used to place the new column beside
  963. * @param bool $insertAfterTarget insert before or after target column ?
  964. * @return int new rank on success and -1 on error
  965. */
  966. public function insertNewColumnDef($newColKey, $defArray, $targetCol = false, $insertAfterTarget = false)
  967. {
  968. // prepare wanted rank
  969. $rank = -1;
  970. // try to get rank from target column
  971. if (!empty($targetCol)) {
  972. $rank = $this->getColumnRank($targetCol);
  973. if ($rank >= 0 && $insertAfterTarget) {
  974. $rank++;
  975. }
  976. }
  977. // get rank from new column definition
  978. if ($rank < 0 && !empty($defArray['rank'])) {
  979. $rank = $defArray['rank'];
  980. }
  981. // error: no rank
  982. if ($rank < 0) {
  983. return -1;
  984. }
  985. foreach ($this->cols as $colKey => & $colDef) {
  986. if ($rank <= $colDef['rank']) {
  987. $colDef['rank'] = $colDef['rank'] + 1;
  988. }
  989. }
  990. $defArray['rank'] = $rank;
  991. $this->cols[$newColKey] = $defArray; // array_replace is used to preserve keys
  992. return $rank;
  993. }
  994. /**
  995. * print standard column content
  996. *
  997. * @param TCPDF $pdf pdf object
  998. * @param float $curY curent Y position
  999. * @param string $colKey the column key
  1000. * @param string $columnText column text
  1001. * @return null
  1002. */
  1003. public function printStdColumnContent($pdf, &$curY, $colKey, $columnText = '')
  1004. {
  1005. global $hookmanager;
  1006. $parameters = array(
  1007. 'curY' => &$curY,
  1008. 'columnText' => $columnText,
  1009. 'colKey' => $colKey,
  1010. 'pdf' => &$pdf,
  1011. );
  1012. $reshook = $hookmanager->executeHooks('printStdColumnContent', $parameters, $this); // Note that $action and $object may have been modified by hook
  1013. if ($reshook < 0) {
  1014. setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  1015. }
  1016. if (!$reshook) {
  1017. if (empty($columnText)) {
  1018. return;
  1019. }
  1020. $pdf->SetXY($this->getColumnContentXStart($colKey), $curY); // Set curent position
  1021. $colDef = $this->cols[$colKey];
  1022. // save curent cell padding
  1023. $curentCellPaddinds = $pdf->getCellPaddings();
  1024. // set cell padding with column content definition
  1025. $pdf->setCellPaddings($colDef['content']['padding'][3], $colDef['content']['padding'][0], $colDef['content']['padding'][1], $colDef['content']['padding'][2]);
  1026. $pdf->writeHTMLCell($colDef['width'], 2, $colDef['xStartPos'], $curY, $columnText, 0, 1, 0, true, $colDef['content']['align']);
  1027. // restore cell padding
  1028. $pdf->setCellPaddings($curentCellPaddinds['L'], $curentCellPaddinds['T'], $curentCellPaddinds['R'], $curentCellPaddinds['B']);
  1029. }
  1030. }
  1031. /**
  1032. * print description column content
  1033. *
  1034. * @param TCPDF $pdf pdf object
  1035. * @param float $curY curent Y position
  1036. * @param string $colKey the column key
  1037. * @param object $object CommonObject
  1038. * @param int $i the $object->lines array key
  1039. * @param Translate $outputlangs Output language
  1040. * @param int $hideref hide ref
  1041. * @param int $hidedesc hide desc
  1042. * @param int $issupplierline if object need supplier product
  1043. * @return null
  1044. */
  1045. public function printColDescContent($pdf, &$curY, $colKey, $object, $i, $outputlangs, $hideref = 0, $hidedesc = 0, $issupplierline = 0)
  1046. {
  1047. // load desc col params
  1048. $colDef = $this->cols[$colKey];
  1049. // save curent cell padding
  1050. $curentCellPaddinds = $pdf->getCellPaddings();
  1051. // set cell padding with column content definition
  1052. $pdf->setCellPaddings($colDef['content']['padding'][3], $colDef['content']['padding'][0], $colDef['content']['padding'][1], $colDef['content']['padding'][2]);
  1053. // line description
  1054. pdf_writelinedesc($pdf, $object, $i, $outputlangs, $colDef['width'], 3, $colDef['xStartPos'], $curY, $hideref, $hidedesc, $issupplierline);
  1055. $posYAfterDescription = $pdf->GetY() - $colDef['content']['padding'][0];
  1056. // restore cell padding
  1057. $pdf->setCellPaddings($curentCellPaddinds['L'], $curentCellPaddinds['T'], $curentCellPaddinds['R'], $curentCellPaddinds['B']);
  1058. // Display extrafield if needed
  1059. $params = array(
  1060. 'display' => 'list',
  1061. 'printableEnable' => array(3),
  1062. 'printableEnableNotEmpty' => array(4)
  1063. );
  1064. $extrafieldDesc = $this->getExtrafieldsInHtml($object->lines[$i], $outputlangs, $params);
  1065. if (!empty($extrafieldDesc)) {
  1066. $this->printStdColumnContent($pdf, $posYAfterDescription, $colKey, $extrafieldDesc);
  1067. }
  1068. }
  1069. /**
  1070. * get extrafield content for pdf writeHtmlCell compatibility
  1071. * usage for PDF line columns and object note block
  1072. *
  1073. * @param object $object Common object
  1074. * @param string $extrafieldKey The extrafield key
  1075. * @param Translate $outputlangs The output langs (if value is __(XXX)__ we use it to translate it).
  1076. * @return string
  1077. */
  1078. public function getExtrafieldContent($object, $extrafieldKey, $outputlangs = null)
  1079. {
  1080. global $hookmanager;
  1081. if (empty($object->table_element)) {
  1082. return;
  1083. }
  1084. $extrafieldsKeyPrefix = "options_";
  1085. // Cleanup extrafield key to remove prefix if present
  1086. $pos = strpos($extrafieldKey, $extrafieldsKeyPrefix);
  1087. if ($pos === 0) {
  1088. $extrafieldKey = substr($extrafieldKey, strlen($extrafieldsKeyPrefix));
  1089. }
  1090. $extrafieldOptionsKey = $extrafieldsKeyPrefix.$extrafieldKey;
  1091. // Load extrafiels if not allready does
  1092. if (empty($this->extrafieldsCache)) {
  1093. $this->extrafieldsCache = new ExtraFields($this->db);
  1094. }
  1095. if (empty($this->extrafieldsCache->attributes[$object->table_element])) {
  1096. $this->extrafieldsCache->fetch_name_optionals_label($object->table_element);
  1097. }
  1098. $extrafields = $this->extrafieldsCache;
  1099. $extrafieldOutputContent = $extrafields->showOutputField($extrafieldKey, $object->array_options[$extrafieldOptionsKey], '', $object->table_element);
  1100. // TODO : allow showOutputField to be pdf public friendly, ex: in a link to object, clean getNomUrl to remove link and images... like a getName methode ...
  1101. if ($extrafields->attributes[$object->table_element]['type'][$extrafieldKey] == 'link') {
  1102. // for lack of anything better we cleanup all html tags
  1103. $extrafieldOutputContent = dol_string_nohtmltag($extrafieldOutputContent);
  1104. }
  1105. $parameters = array(
  1106. 'object' => $object,
  1107. 'extrafields' => $extrafields,
  1108. 'extrafieldKey' => $extrafieldKey,
  1109. 'extrafieldOutputContent' =>& $extrafieldOutputContent
  1110. );
  1111. $reshook = $hookmanager->executeHooks('getPDFExtrafieldContent', $parameters, $this); // Note that $action and $object may have been modified by hook
  1112. if ($reshook < 0) {
  1113. setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  1114. }
  1115. if ($reshook) {
  1116. $extrafieldOutputContent = $hookmanager->resPrint;
  1117. }
  1118. return $extrafieldOutputContent;
  1119. }
  1120. /**
  1121. * display extrafields columns content
  1122. *
  1123. * @param object $object line of common object
  1124. * @param Translate $outputlangs Output language
  1125. * @param array $params array of additionals parameters
  1126. * @return double max y value
  1127. */
  1128. public function getExtrafieldsInHtml($object, $outputlangs, $params = array())
  1129. {
  1130. global $hookmanager;
  1131. if (empty($object->table_element)) {
  1132. return;
  1133. }
  1134. // Load extrafiels if not allready does
  1135. if (empty($this->extrafieldsCache)) {
  1136. $this->extrafieldsCache = new ExtraFields($this->db);
  1137. }
  1138. if (empty($this->extrafieldsCache->attributes[$object->table_element])) {
  1139. $this->extrafieldsCache->fetch_name_optionals_label($object->table_element);
  1140. }
  1141. $extrafields = $this->extrafieldsCache;
  1142. $defaultParams = array(
  1143. 'style' => '',
  1144. 'display' => 'auto', // auto, table, list
  1145. 'printableEnable' => array(1),
  1146. 'printableEnableNotEmpty' => array(2),
  1147. 'table' => array(
  1148. 'maxItemsInRow' => 2,
  1149. 'cellspacing' => 0,
  1150. 'cellpadding' => 0,
  1151. 'border' => 0,
  1152. 'labelcolwidth' => '25%',
  1153. 'arrayOfLineBreakType' => array('text', 'html')
  1154. ),
  1155. 'list' => array(
  1156. 'separator' => '<br>'
  1157. ),
  1158. 'auto' => array(
  1159. 'list' => 0, // 0 for default
  1160. 'table' => 4 // if there more than x extrafield to display
  1161. ),
  1162. );
  1163. $params = $params + $defaultParams;
  1164. /**
  1165. * @var $extrafields ExtraFields
  1166. */
  1167. $html = '';
  1168. $fields = array();
  1169. if (!empty($extrafields->attributes[$object->table_element]['label']) && is_array($extrafields->attributes[$object->table_element]['label'])) {
  1170. foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $label) {
  1171. // Enable extrafield ?
  1172. $enabled = 0;
  1173. $disableOnEmpty = 0;
  1174. if (!empty($extrafields->attributes[$object->table_element]['printable'][$key])) {
  1175. $printable = intval($extrafields->attributes[$object->table_element]['printable'][$key]);
  1176. if (in_array($printable, $params['printableEnable']) || in_array($printable, $params['printableEnableNotEmpty'])) {
  1177. $enabled = 1;
  1178. }
  1179. if (in_array($printable, $params['printableEnableNotEmpty'])) {
  1180. $disableOnEmpty = 1;
  1181. }
  1182. }
  1183. if (empty($enabled)) {
  1184. continue;
  1185. }
  1186. $field = new stdClass();
  1187. $field->rank = intval($extrafields->attributes[$object->table_element]['pos'][$key]);
  1188. $field->content = $this->getExtrafieldContent($object, $key, $outputlangs);
  1189. $field->label = $outputlangs->transnoentities($label);
  1190. $field->type = $extrafields->attributes[$object->table_element]['type'][$key];
  1191. // dont display if empty
  1192. if ($disableOnEmpty && empty($field->content)) {
  1193. continue;
  1194. }
  1195. $fields[] = $field;
  1196. }
  1197. }
  1198. if (!empty($fields)) {
  1199. // Sort extrafields by rank
  1200. uasort($fields, function ($a, $b) {
  1201. return ($a->rank > $b->rank) ? 1 : -1;
  1202. });
  1203. // define some HTML content with style
  1204. $html .= !empty($params['style']) ? '<style>'.$params['style'].'</style>' : '';
  1205. // auto select display format
  1206. if ($params['display'] == 'auto') {
  1207. $lastNnumbItems = 0;
  1208. foreach ($params['auto'] as $display => $numbItems) {
  1209. if ($lastNnumbItems <= $numbItems && count($fields) > $numbItems) {
  1210. $lastNnumbItems = $numbItems;
  1211. $params['display'] = $display;
  1212. }
  1213. }
  1214. }
  1215. if ($params['display'] == 'list') {
  1216. // Display in list format
  1217. $i = 0;
  1218. foreach ($fields as $field) {
  1219. $html .= !empty($i) ? $params['list']['separator'] : '';
  1220. $html .= '<strong>'.$field->label.' : </strong>';
  1221. $html .= $field->content;
  1222. $i++;
  1223. }
  1224. } elseif ($params['display'] == 'table') {
  1225. // Display in table format
  1226. $html .= '<table class="extrafield-table" cellspacing="'.$params['table']['cellspacing'].'" cellpadding="'.$params['table']['cellpadding'].'" border="'.$params['table']['border'].'">';
  1227. $html .= "<tr>";
  1228. $itemsInRow = 0;
  1229. $maxItemsInRow = $params['table']['maxItemsInRow'];
  1230. foreach ($fields as $field) {
  1231. //$html.= !empty($html)?'<br>':'';
  1232. if ($itemsInRow >= $maxItemsInRow) {
  1233. // start a new line
  1234. $html .= "</tr><tr>";
  1235. $itemsInRow = 0;
  1236. }
  1237. // for some type we need line break
  1238. if (in_array($field->type, $params['table']['arrayOfLineBreakType'])) {
  1239. if ($itemsInRow > 0) {
  1240. // close table row and empty cols
  1241. for ($i = $itemsInRow; $i <= $maxItemsInRow; $i++) {
  1242. $html .= "<td></td><td></td>";
  1243. }
  1244. $html .= "</tr>";
  1245. // start a new line
  1246. $html .= "<tr>";
  1247. }
  1248. $itemsInRow = $maxItemsInRow;
  1249. $html .= '<td colspan="'.($maxItemsInRow * 2 - 1).'">';
  1250. $html .= '<strong>'.$field->label.' :</strong> ';
  1251. $html .= $field->content;
  1252. $html .= "</td>";
  1253. } else {
  1254. $itemsInRow++;
  1255. $html .= '<td width="'.$params['table']['labelcolwidth'].'" class="extrafield-label">';
  1256. $html .= '<strong>'.$field->label.' :</strong>';
  1257. $html .= "</td>";
  1258. $html .= '<td class="extrafield-content">';
  1259. $html .= $field->content;
  1260. $html .= "</td>";
  1261. }
  1262. }
  1263. $html .= "</tr>";
  1264. $html .= '</table>';
  1265. }
  1266. }
  1267. return $html;
  1268. }
  1269. /**
  1270. * get column status from column key
  1271. *
  1272. * @param string $colKey the column key
  1273. * @return float width in mm
  1274. */
  1275. public function getColumnStatus($colKey)
  1276. {
  1277. if (!empty($this->cols[$colKey]['status'])) {
  1278. return true;
  1279. } else {
  1280. return false;
  1281. }
  1282. }
  1283. /**
  1284. * Print standard column content
  1285. *
  1286. * @param TCPDI $pdf Pdf object
  1287. * @param float $tab_top Tab top position
  1288. * @param float $tab_height Default tab height
  1289. * @param Translate $outputlangs Output language
  1290. * @param int $hidetop Hide top
  1291. * @return float Height of col tab titles
  1292. */
  1293. public function pdfTabTitles(&$pdf, $tab_top, $tab_height, $outputlangs, $hidetop = 0)
  1294. {
  1295. global $hookmanager, $conf;
  1296. foreach ($this->cols as $colKey => $colDef) {
  1297. $parameters = array(
  1298. 'colKey' => $colKey,
  1299. 'pdf' => $pdf,
  1300. 'outputlangs' => $outputlangs,
  1301. 'tab_top' => $tab_top,
  1302. 'tab_height' => $tab_height,
  1303. 'hidetop' => $hidetop
  1304. );
  1305. $reshook = $hookmanager->executeHooks('pdfTabTitles', $parameters, $this); // Note that $object may have been modified by hook
  1306. if ($reshook < 0) {
  1307. setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  1308. } elseif (empty($reshook)) {
  1309. if (!$this->getColumnStatus($colKey)) {
  1310. continue;
  1311. }
  1312. // get title label
  1313. $colDef['title']['label'] = !empty($colDef['title']['label']) ? $colDef['title']['label'] : $outputlangs->transnoentities($colDef['title']['textkey']);
  1314. // Add column separator
  1315. if (!empty($colDef['border-left'])) {
  1316. $pdf->line($colDef['xStartPos'], $tab_top, $colDef['xStartPos'], $tab_top + $tab_height);
  1317. }
  1318. if (empty($hidetop)) {
  1319. // save curent cell padding
  1320. $curentCellPaddinds = $pdf->getCellPaddings();
  1321. // Add space for lines (more if we need to show a second alternative language)
  1322. global $outputlangsbis;
  1323. if (is_object($outputlangsbis)) {
  1324. // set cell padding with column title definition
  1325. $pdf->setCellPaddings($colDef['title']['padding'][3], $colDef['title']['padding'][0], $colDef['title']['padding'][1], 0.5);
  1326. } else {
  1327. // set cell padding with column title definition
  1328. $pdf->setCellPaddings($colDef['title']['padding'][3], $colDef['title']['padding'][0], $colDef['title']['padding'][1], $colDef['title']['padding'][2]);
  1329. }
  1330. $pdf->SetXY($colDef['xStartPos'], $tab_top);
  1331. $textWidth = $colDef['width'];
  1332. $pdf->MultiCell($textWidth, 2, $colDef['title']['label'], '', $colDef['title']['align']);
  1333. // Add variant of translation if $outputlangsbis is an object
  1334. if (is_object($outputlangsbis) && trim($colDef['title']['label'])) {
  1335. $pdf->setCellPaddings($colDef['title']['padding'][3], 0, $colDef['title']['padding'][1], $colDef['title']['padding'][2]);
  1336. $pdf->SetXY($colDef['xStartPos'], $pdf->GetY());
  1337. $textbis = $outputlangsbis->transnoentities($colDef['title']['textkey']);
  1338. $pdf->MultiCell($textWidth, 2, $textbis, '', $colDef['title']['align']);
  1339. }
  1340. $this->tabTitleHeight = max($pdf->GetY() - $tab_top, $this->tabTitleHeight);
  1341. // restore cell padding
  1342. $pdf->setCellPaddings($curentCellPaddinds['L'], $curentCellPaddinds['T'], $curentCellPaddinds['R'], $curentCellPaddinds['B']);
  1343. }
  1344. }
  1345. }
  1346. return $this->tabTitleHeight;
  1347. }
  1348. /**
  1349. * Define Array Column Field for extrafields
  1350. *
  1351. * @param object $object common object det
  1352. * @param Translate $outputlangs langs
  1353. * @param int $hidedetails Do not show line details
  1354. * @return null
  1355. */
  1356. public function defineColumnExtrafield($object, $outputlangs, $hidedetails = 0)
  1357. {
  1358. global $conf;
  1359. if (!empty($hidedetails)) {
  1360. return;
  1361. }
  1362. if (empty($object->table_element)) {
  1363. return;
  1364. }
  1365. // Load extrafiels if not allready does
  1366. if (empty($this->extrafieldsCache)) {
  1367. $this->extrafieldsCache = new ExtraFields($this->db);
  1368. }
  1369. if (empty($this->extrafieldsCache->attributes[$object->table_element])) {
  1370. $this->extrafieldsCache->fetch_name_optionals_label($object->table_element);
  1371. }
  1372. $extrafields = $this->extrafieldsCache;
  1373. if (!empty($extrafields->attributes[$object->table_element]) && is_array($extrafields->attributes[$object->table_element]['label'])) {
  1374. foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $label) {
  1375. // Dont display separator yet even is set to be displayed (not compatible yet)
  1376. if ($extrafields->attributes[$object->table_element]['type'][$key] == 'separate') {
  1377. continue;
  1378. }
  1379. // Enable extrafield ?
  1380. $enabled = 0;
  1381. if (!empty($extrafields->attributes[$object->table_element]['printable'][$key])) {
  1382. $printable = intval($extrafields->attributes[$object->table_element]['printable'][$key]);
  1383. if ($printable === 1 || $printable === 2) {
  1384. $enabled = 1;
  1385. }
  1386. // Note : if $printable === 3 or 4 so, it's displayed after line description not in cols
  1387. }
  1388. if (!$enabled) {
  1389. continue;
  1390. } // don't wast resourses if we don't need them...
  1391. // Load language if required
  1392. if (!empty($extrafields->attributes[$object->table_element]['langfile'][$key])) {
  1393. $outputlangs->load($extrafields->attributes[$object->table_element]['langfile'][$key]);
  1394. }
  1395. // TODO : add more extrafield customisation capacities for PDF like width, rank...
  1396. // set column definition
  1397. $def = array(
  1398. 'rank' => intval($extrafields->attributes[$object->table_element]['pos'][$key]),
  1399. 'width' => 25, // in mm
  1400. 'status' => boolval($enabled),
  1401. 'title' => array(
  1402. 'label' => $outputlangs->transnoentities($label)
  1403. ),
  1404. 'content' => array(
  1405. 'align' => 'C'
  1406. ),
  1407. 'border-left' => true, // add left line separator
  1408. );
  1409. $alignTypeRight = array('double', 'int', 'price');
  1410. if (in_array($extrafields->attributes[$object->table_element]['type'][$key], $alignTypeRight)) {
  1411. $def['content']['align'] = 'R';
  1412. }
  1413. $alignTypeLeft = array('text', 'html');
  1414. if (in_array($extrafields->attributes[$object->table_element]['type'][$key], $alignTypeLeft)) {
  1415. $def['content']['align'] = 'L';
  1416. }
  1417. // for extrafields we use rank of extrafield to place it on PDF
  1418. $this->insertNewColumnDef("options_".$key, $def);
  1419. }
  1420. }
  1421. }
  1422. }