commondocgenerator.class.php 62 KB

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