card.php 109 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892
  1. <?php
  2. /* Copyright (C) 2003 Rodolphe Quiedeville <rodolphe@quiedeville.org>
  3. * Copyright (C) 2004-2020 Laurent Destailleur <eldy@users.sourceforge.net>
  4. * Copyright (C) 2005-2009 Regis Houssin <regis.houssin@inodbox.com>
  5. * Copyright (C) 2015-2022 Alexandre Spangaro <aspangaro@open-dsi.fr>
  6. * Copyright (C) 2017 Ferran Marcet <fmarcet@2byte.es>
  7. * Copyright (C) 2018 Frédéric France <frederic.france@netlogic.fr>
  8. *
  9. * This program is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation; either version 3 of the License, or
  12. * (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  21. */
  22. /**
  23. * \file htdocs/expensereport/card.php
  24. * \ingroup expensereport
  25. * \brief Page for trip and expense report card
  26. */
  27. // Load Dolibarr environment
  28. require '../main.inc.php';
  29. require_once DOL_DOCUMENT_ROOT.'/core/class/html.formexpensereport.class.php';
  30. require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
  31. require_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
  32. require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
  33. require_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php';
  34. require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
  35. require_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
  36. require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php';
  37. require_once DOL_DOCUMENT_ROOT.'/core/lib/expensereport.lib.php';
  38. require_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
  39. require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
  40. require_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php';
  41. require_once DOL_DOCUMENT_ROOT.'/core/modules/expensereport/modules_expensereport.php';
  42. require_once DOL_DOCUMENT_ROOT.'/expensereport/class/expensereport.class.php';
  43. require_once DOL_DOCUMENT_ROOT.'/expensereport/class/paymentexpensereport.class.php';
  44. require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
  45. require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
  46. if (isModEnabled('accounting')) {
  47. require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingjournal.class.php';
  48. }
  49. // Load translation files required by the page
  50. $langs->loadLangs(array("trips", "bills", "mails"));
  51. $action = GETPOST('action', 'aZ09');
  52. $cancel = GETPOST('cancel', 'alpha');
  53. $confirm = GETPOST('confirm', 'alpha');
  54. $backtopage = GETPOST('backtopage', 'alpha');
  55. $id = GETPOST('id', 'int');
  56. $date_start = dol_mktime(0, 0, 0, GETPOST('date_debutmonth', 'int'), GETPOST('date_debutday', 'int'), GETPOST('date_debutyear', 'int'));
  57. $date_end = dol_mktime(0, 0, 0, GETPOST('date_finmonth', 'int'), GETPOST('date_finday', 'int'), GETPOST('date_finyear', 'int'));
  58. $date = dol_mktime(0, 0, 0, GETPOST('datemonth', 'int'), GETPOST('dateday', 'int'), GETPOST('dateyear', 'int'));
  59. $fk_project = GETPOST('fk_project', 'int');
  60. $vatrate = GETPOST('vatrate', 'alpha');
  61. $ref = GETPOST("ref", 'alpha');
  62. $comments = GETPOST('comments', 'restricthtml');
  63. $fk_c_type_fees = GETPOST('fk_c_type_fees', 'int');
  64. $socid = GETPOST('socid', 'int') ? GETPOST('socid', 'int') : GETPOST('socid_id', 'int');
  65. $childids = $user->getAllChildIds(1);
  66. if (getDolGlobalString('EXPENSEREPORT_PREFILL_DATES_WITH_CURRENT_MONTH')) {
  67. if (empty($date_start)) {
  68. $date_start = dol_mktime(0, 0, 0, (int) dol_print_date(dol_now(), '%m'), 1, (int) dol_print_date(dol_now(), '%Y'));
  69. }
  70. if (empty($date_end)) {
  71. // date('t') => number of days in the month, so last day of the month too
  72. $date_end = dol_mktime(0, 0, 0, (int) dol_print_date(dol_now(), '%m'), (int) date('t'), (int) dol_print_date(dol_now(), '%Y'));
  73. }
  74. }
  75. // Hack to use expensereport dir
  76. $rootfordata = DOL_DATA_ROOT;
  77. $rootforuser = DOL_DATA_ROOT;
  78. // If multicompany module is enabled, we redefine the root of data
  79. if (isModEnabled('multicompany') && !empty($conf->entity) && $conf->entity > 1) {
  80. $rootfordata .= '/'.$conf->entity;
  81. }
  82. $conf->expensereport->dir_output = $rootfordata.'/expensereport';
  83. // Define $urlwithroot
  84. $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($dolibarr_main_url_root));
  85. $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
  86. //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current
  87. // PDF
  88. $hidedetails = (GETPOST('hidedetails', 'int') ? GETPOST('hidedetails', 'int') : (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_DETAILS') ? 1 : 0));
  89. $hidedesc = (GETPOST('hidedesc', 'int') ? GETPOST('hidedesc', 'int') : (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_DESC') ? 1 : 0));
  90. $hideref = (GETPOST('hideref', 'int') ? GETPOST('hideref', 'int') : (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_REF') ? 1 : 0));
  91. $object = new ExpenseReport($db);
  92. $extrafields = new ExtraFields($db);
  93. // fetch optionals attributes and labels
  94. $extrafields->fetch_name_optionals_label($object->table_element);
  95. // Load object
  96. include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be include, not include_once
  97. // Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
  98. $hookmanager->initHooks(array('expensereportcard', 'globalcard'));
  99. $permissionnote = $user->rights->expensereport->creer; // Used by the include of actions_setnotes.inc.php
  100. $permissiondellink = $user->rights->expensereport->creer; // Used by the include of actions_dellink.inc.php
  101. $permissiontoadd = $user->rights->expensereport->creer; // Used by the include of actions_addupdatedelete.inc.php and actions_lineupdown.inc.php
  102. $upload_dir = $conf->expensereport->dir_output.'/'.dol_sanitizeFileName($object->ref);
  103. $projectRequired = isModEnabled('project') && getDolGlobalString('EXPENSEREPORT_PROJECT_IS_REQUIRED');
  104. $fileRequired = getDolGlobalString('EXPENSEREPORT_FILE_IS_REQUIRED');
  105. if ($object->id > 0) {
  106. // Check current user can read this expense report
  107. $canread = 0;
  108. if ($user->hasRight('expensereport', 'readall')) {
  109. $canread = 1;
  110. }
  111. if ($user->hasRight('expensereport', 'lire') && in_array($object->fk_user_author, $childids)) {
  112. $canread = 1;
  113. }
  114. if (!$canread) {
  115. accessforbidden();
  116. }
  117. }
  118. $candelete = 0;
  119. if ($user->hasRight('expensereport', 'supprimer')) {
  120. $candelete = 1;
  121. }
  122. if ($object->statut == ExpenseReport::STATUS_DRAFT && $user->hasRight('expensereport', 'write') && in_array($object->fk_user_author, $childids)) {
  123. $candelete = 1;
  124. }
  125. // Security check
  126. if ($user->socid) {
  127. $socid = $user->socid;
  128. }
  129. $result = restrictedArea($user, 'expensereport', $object->id, 'expensereport');
  130. $permissiontoadd = $user->rights->expensereport->creer; // Used by the include of actions_dellink.inc.php
  131. /*
  132. * Actions
  133. */
  134. $value_unit_ht = price2num(GETPOST('value_unit_ht', 'alpha'), 'MU');
  135. $value_unit = price2num(GETPOST('value_unit', 'alpha'), 'MU');
  136. $qty = price2num(GETPOST('qty', 'alpha'));
  137. $parameters = array('socid' => $socid);
  138. $reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
  139. if ($reshook < 0) {
  140. setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  141. }
  142. if (empty($reshook)) {
  143. $backurlforlist = DOL_URL_ROOT.'/expensereport/list.php';
  144. if (empty($backtopage) || ($cancel && empty($id))) {
  145. if (empty($backtopage) || ($cancel && strpos($backtopage, '__ID__'))) {
  146. if (empty($id) && (($action != 'add' && $action != 'create') || $cancel)) {
  147. $backtopage = $backurlforlist;
  148. } else {
  149. $backtopage = DOL_URL_ROOT.'/expensereport/card.php?id='.((!empty($id) && $id > 0) ? $id : '__ID__');
  150. }
  151. }
  152. }
  153. if ($cancel) {
  154. if (!empty($backtopageforcancel)) {
  155. header("Location: ".$backtopageforcancel);
  156. exit;
  157. } elseif (!empty($backtopage)) {
  158. header("Location: ".$backtopage);
  159. exit;
  160. }
  161. $action = '';
  162. $fk_project = '';
  163. $date_start = '';
  164. $date_end = '';
  165. $date = '';
  166. $comments = '';
  167. $vatrate = '';
  168. $value_unit_ht = '';
  169. $value_unit = '';
  170. $qty = 1;
  171. $fk_c_type_fees = -1;
  172. }
  173. include DOL_DOCUMENT_ROOT.'/core/actions_linkedfiles.inc.php';
  174. if (!empty(GETPOST('sendit', 'alpha'))) { // If we just submit a file
  175. if ($action == 'updateline') {
  176. $action = 'editline'; // To avoid to make the updateline now
  177. } else {
  178. $action = ''; // To avoid to make the addline now
  179. }
  180. }
  181. include DOL_DOCUMENT_ROOT.'/core/actions_setnotes.inc.php'; // Must be include, not include_once
  182. include DOL_DOCUMENT_ROOT.'/core/actions_dellink.inc.php'; // Must be include, not include_once
  183. include DOL_DOCUMENT_ROOT.'/core/actions_lineupdown.inc.php'; // Must be include, not include_once
  184. // Action clone object
  185. if ($action == 'confirm_clone' && $confirm == 'yes' && $user->hasRight('expensereport', 'creer')) {
  186. if (1 == 0 && !GETPOST('clone_content', 'alpha') && !GETPOST('clone_receivers', 'alpha')) {
  187. setEventMessages($langs->trans("NoCloneOptionsSpecified"), null, 'errors');
  188. } else {
  189. if ($object->id > 0) {
  190. // Because createFromClone modifies the object, we must clone it so that we can restore it later if it fails
  191. $orig = clone $object;
  192. $result = $object->createFromClone($user, GETPOST('fk_user_author', 'int'));
  193. if ($result > 0) {
  194. header("Location: ".$_SERVER['PHP_SELF'].'?id='.$result);
  195. exit;
  196. } else {
  197. setEventMessages($object->error, $object->errors, 'errors');
  198. $object = $orig;
  199. $action = '';
  200. }
  201. }
  202. }
  203. }
  204. if ($action == 'confirm_delete' && GETPOST("confirm", 'alpha') == "yes" && $id > 0 && $candelete) {
  205. $object = new ExpenseReport($db);
  206. $result = $object->fetch($id);
  207. $result = $object->delete($user);
  208. if ($result >= 0) {
  209. header("Location: index.php");
  210. exit;
  211. } else {
  212. setEventMessages($object->error, $object->errors, 'errors');
  213. }
  214. }
  215. if ($action == 'add' && $user->hasRight('expensereport', 'creer')) {
  216. $error = 0;
  217. $object = new ExpenseReport($db);
  218. $object->date_debut = $date_start;
  219. $object->date_fin = $date_end;
  220. $object->fk_user_author = GETPOST('fk_user_author', 'int');
  221. if (!($object->fk_user_author > 0)) {
  222. $object->fk_user_author = $user->id;
  223. }
  224. // Check that expense report is for a user inside the hierarchy, or that advanced permission for all is set
  225. if ((!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && !$user->hasRight('expensereport', 'creer'))
  226. || (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && !$user->hasRight('expensereport', 'creer') && !$user->hasRight('expensereport', 'writeall_advance'))) {
  227. $error++;
  228. setEventMessages($langs->trans("NotEnoughPermissions"), null, 'errors');
  229. }
  230. if (!$error) {
  231. if (!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') || !$user->hasRight('expensereport', 'writeall_advance')) {
  232. if (!in_array($object->fk_user_author, $childids)) {
  233. $error++;
  234. setEventMessages($langs->trans("UserNotInHierachy"), null, 'errors');
  235. }
  236. }
  237. }
  238. $fuser = new User($db);
  239. $fuser->fetch($object->fk_user_author);
  240. $object->status = 1;
  241. $object->fk_c_paiement = GETPOST('fk_c_paiement', 'int');
  242. $object->fk_user_validator = GETPOST('fk_user_validator', 'int');
  243. $object->note_public = GETPOST('note_public', 'restricthtml');
  244. $object->note_private = GETPOST('note_private', 'restricthtml');
  245. // Fill array 'array_options' with data from add form
  246. if (!$error) {
  247. $ret = $extrafields->setOptionalsFromPost(null, $object);
  248. if ($ret < 0) {
  249. $error++;
  250. }
  251. }
  252. if (!$error && !getDolGlobalString('EXPENSEREPORT_ALLOW_OVERLAPPING_PERIODS')) {
  253. $overlappingExpenseReportID = $object->periode_existe($fuser, $object->date_debut, $object->date_fin);
  254. if ($overlappingExpenseReportID > 0) {
  255. $error++;
  256. setEventMessages($langs->trans("ErrorDoubleDeclaration").' <a href="'.$_SERVER['PHP_SELF'].'?id='.$overlappingExpenseReportID.'">'. $langs->trans('ShowTrip').'</a>', null, 'errors');
  257. $action = 'create';
  258. }
  259. }
  260. if (!$error) {
  261. $db->begin();
  262. $id = $object->create($user);
  263. if ($id <= 0) {
  264. $error++;
  265. }
  266. if (!$error) {
  267. $db->commit();
  268. Header("Location: ".$_SERVER["PHP_SELF"]."?id=".$id);
  269. exit;
  270. } else {
  271. setEventMessages($object->error, $object->errors, 'errors');
  272. $db->rollback();
  273. $action = 'create';
  274. }
  275. }
  276. }
  277. if (($action == 'update' || $action == 'updateFromRefuse') && $user->hasRight('expensereport', 'creer')) {
  278. $object = new ExpenseReport($db);
  279. $object->fetch($id);
  280. $object->date_debut = $date_start;
  281. $object->date_fin = $date_end;
  282. if ($object->status < 3) {
  283. $object->fk_user_validator = GETPOST('fk_user_validator', 'int');
  284. }
  285. $object->fk_c_paiement = GETPOST('fk_c_paiement', 'int');
  286. $object->note_public = GETPOST('note_public', 'restricthtml');
  287. $object->note_private = GETPOST('note_private', 'restricthtml');
  288. $object->fk_user_modif = $user->id;
  289. $result = $object->update($user);
  290. if ($result > 0) {
  291. header("Location: ".$_SERVER["PHP_SELF"]."?id=".GETPOST('id', 'int'));
  292. exit;
  293. } else {
  294. setEventMessages($object->error, $object->errors, 'errors');
  295. }
  296. }
  297. if ($action == 'update_extras') {
  298. $object->oldcopy = dol_clone($object, 2);
  299. // Fill array 'array_options' with data from update form
  300. $ret = $extrafields->setOptionalsFromPost(null, $object, GETPOST('attribute', 'restricthtml'));
  301. if ($ret < 0) {
  302. $error++;
  303. }
  304. if (!$error) {
  305. // Actions on extra fields
  306. $result = $object->insertExtraFields('EXPENSEREPORT_MODIFY');
  307. if ($result < 0) {
  308. setEventMessages($object->error, $object->errors, 'errors');
  309. $error++;
  310. }
  311. }
  312. if ($error) {
  313. $action = 'edit_extras';
  314. }
  315. }
  316. if ($action == "confirm_validate" && GETPOST("confirm", 'alpha') == "yes" && $id > 0 && $user->hasRight('expensereport', 'creer')) {
  317. $error = 0;
  318. $db->begin();
  319. $object = new ExpenseReport($db);
  320. $object->fetch($id);
  321. $result = $object->setValidate($user);
  322. if ($result >= 0) {
  323. // Define output language
  324. if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
  325. $outputlangs = $langs;
  326. $newlang = '';
  327. if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
  328. $newlang = GETPOST('lang_id', 'aZ09');
  329. }
  330. if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
  331. $newlang = $object->thirdparty->default_lang;
  332. }
  333. if (!empty($newlang)) {
  334. $outputlangs = new Translate("", $conf);
  335. $outputlangs->setDefaultLang($newlang);
  336. }
  337. $model = $object->model_pdf;
  338. $ret = $object->fetch($id); // Reload to get new records
  339. $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
  340. }
  341. } else {
  342. setEventMessages($object->error, $object->errors, 'errors');
  343. $error++;
  344. }
  345. if (!$error && $result > 0 && $object->fk_user_validator > 0) {
  346. $langs->load("mails");
  347. // TO
  348. $destinataire = new User($db);
  349. $destinataire->fetch($object->fk_user_validator);
  350. $emailTo = $destinataire->email;
  351. // FROM
  352. $expediteur = new User($db);
  353. $expediteur->fetch($object->fk_user_author);
  354. $emailFrom = $conf->global->MAIN_MAIL_EMAIL_FROM;
  355. if ($emailTo && $emailFrom) {
  356. $filename = array();
  357. $filedir = array();
  358. $mimetype = array();
  359. // SUBJECT
  360. $societeName = $conf->global->MAIN_INFO_SOCIETE_NOM;
  361. if (getDolGlobalString('MAIN_APPLICATION_TITLE')) {
  362. $societeName = $conf->global->MAIN_APPLICATION_TITLE;
  363. }
  364. $subject = $societeName." - ".$langs->transnoentities("ExpenseReportWaitingForApproval");
  365. // CONTENT
  366. $link = $urlwithroot.'/expensereport/card.php?id='.$object->id;
  367. $link = '<a href="'.$link.'">'.$link.'</a>';
  368. $message = $langs->transnoentities("ExpenseReportWaitingForApprovalMessage", $expediteur->getFullName($langs), get_date_range($object->date_debut, $object->date_fin, '', $langs), $link);
  369. // Rebuild pdf
  370. /*
  371. $object->setDocModel($user,"");
  372. $resultPDF = expensereport_pdf_create($db,$id,'',"",$langs);
  373. if($resultPDF):
  374. // ATTACHMENT
  375. array_push($filename,dol_sanitizeFileName($object->ref).".pdf");
  376. array_push($filedir,$conf->expensereport->dir_output . "/" . dol_sanitizeFileName($object->ref) . "/" . dol_sanitizeFileName($object->ref).".pdf");
  377. array_push($mimetype,"application/pdf");
  378. */
  379. // PREPARE SEND
  380. $mailfile = new CMailFile($subject, $emailTo, $emailFrom, $message, $filedir, $mimetype, $filename, '', '', 0, -1);
  381. if ($mailfile) {
  382. // SEND
  383. $result = $mailfile->sendfile();
  384. if ($result) {
  385. $mesg = $langs->trans('MailSuccessfulySent', $mailfile->getValidAddress($emailFrom, 2), $mailfile->getValidAddress($emailTo, 2));
  386. setEventMessages($mesg, null, 'mesgs');
  387. } else {
  388. $langs->load("other");
  389. if ($mailfile->error) {
  390. $mesg = '';
  391. $mesg .= $langs->trans('ErrorFailedToSendMail', $emailFrom, $emailTo);
  392. $mesg .= '<br>'.$mailfile->error;
  393. setEventMessages($mesg, null, 'errors');
  394. } else {
  395. setEventMessages('No mail sent. Feature is disabled by option MAIN_DISABLE_ALL_MAILS', null, 'warnings');
  396. }
  397. }
  398. } else {
  399. setEventMessages($mailfile->error, $mailfile->errors, 'errors');
  400. $action = '';
  401. }
  402. } else {
  403. setEventMessages($langs->trans("NoEmailSentBadSenderOrRecipientEmail"), null, 'warnings');
  404. $action = '';
  405. }
  406. }
  407. if (!$error) {
  408. $db->commit();
  409. header("Location: ".$_SERVER["PHP_SELF"]."?id=".$id);
  410. exit;
  411. } else {
  412. $db->rollback();
  413. }
  414. }
  415. if ($action == "confirm_save_from_refuse" && GETPOST("confirm", 'alpha') == "yes" && $id > 0 && $user->hasRight('expensereport', 'creer')) {
  416. $object = new ExpenseReport($db);
  417. $object->fetch($id);
  418. $result = $object->set_save_from_refuse($user);
  419. if ($result > 0) {
  420. // Define output language
  421. if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
  422. $outputlangs = $langs;
  423. $newlang = '';
  424. if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
  425. $newlang = GETPOST('lang_id', 'aZ09');
  426. }
  427. if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
  428. $newlang = $object->thirdparty->default_lang;
  429. }
  430. if (!empty($newlang)) {
  431. $outputlangs = new Translate("", $conf);
  432. $outputlangs->setDefaultLang($newlang);
  433. }
  434. $model = $object->model_pdf;
  435. $ret = $object->fetch($id); // Reload to get new records
  436. $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
  437. }
  438. }
  439. if ($result > 0) {
  440. // Send mail
  441. // TO
  442. $destinataire = new User($db);
  443. $destinataire->fetch($object->fk_user_validator);
  444. $emailTo = $destinataire->email;
  445. // FROM
  446. $expediteur = new User($db);
  447. $expediteur->fetch($object->fk_user_author);
  448. $emailFrom = $conf->global->MAIN_MAIL_EMAIL_FROM;
  449. if ($emailFrom && $emailTo) {
  450. $filename = array();
  451. $filedir = array();
  452. $mimetype = array();
  453. // SUBJECT
  454. $societeName = $conf->global->MAIN_INFO_SOCIETE_NOM;
  455. if (getDolGlobalString('MAIN_APPLICATION_TITLE')) {
  456. $societeName = $conf->global->MAIN_APPLICATION_TITLE;
  457. }
  458. $subject = $societeName." - ".$langs->transnoentities("ExpenseReportWaitingForReApproval");
  459. // CONTENT
  460. $link = $urlwithroot.'/expensereport/card.php?id='.$object->id;
  461. $link = '<a href="'.$link.'">'.$link.'</a>';
  462. $dateRefusEx = explode(" ", $object->date_refuse);
  463. $message = $langs->transnoentities("ExpenseReportWaitingForReApprovalMessage", $dateRefusEx[0], $object->detail_refuse, $expediteur->getFullName($langs), $link);
  464. // Rebuild pdf
  465. /*
  466. $object->setDocModel($user,"");
  467. $resultPDF = expensereport_pdf_create($db,$object,'',"",$langs);
  468. if($resultPDF)
  469. {
  470. // ATTACHMENT
  471. $filename=array(); $filedir=array(); $mimetype=array();
  472. array_push($filename,dol_sanitizeFileName($object->ref).".pdf");
  473. array_push($filedir,$conf->expensereport->dir_output . "/" . dol_sanitizeFileName($object->ref) . "/" . dol_sanitizeFileName($object->ref_number).".pdf");
  474. array_push($mimetype,"application/pdf");
  475. }
  476. */
  477. // PREPARE SEND
  478. $mailfile = new CMailFile($subject, $emailTo, $emailFrom, $message, $filedir, $mimetype, $filename, '', '', 0, -1);
  479. if ($mailfile) {
  480. // SEND
  481. $result = $mailfile->sendfile();
  482. if ($result) {
  483. $mesg = $langs->trans('MailSuccessfulySent', $mailfile->getValidAddress($emailFrom, 2), $mailfile->getValidAddress($emailTo, 2));
  484. setEventMessages($mesg, null, 'mesgs');
  485. header("Location: ".$_SERVER["PHP_SELF"]."?id=".$id);
  486. exit;
  487. } else {
  488. $langs->load("other");
  489. if ($mailfile->error) {
  490. $mesg = '';
  491. $mesg .= $langs->trans('ErrorFailedToSendMail', $emailFrom, $emailTo);
  492. $mesg .= '<br>'.$mailfile->error;
  493. setEventMessages($mesg, null, 'errors');
  494. } else {
  495. setEventMessages('No mail sent. Feature is disabled by option MAIN_DISABLE_ALL_MAILS', null, 'warnings');
  496. }
  497. }
  498. } else {
  499. setEventMessages($mailfile->error, $mailfile->errors, 'errors');
  500. $action = '';
  501. }
  502. } else {
  503. setEventMessages($langs->trans("NoEmailSentBadSenderOrRecipientEmail"), null, 'warnings');
  504. $action = '';
  505. }
  506. } else {
  507. setEventMessages($object->error, $object->errors, 'errors');
  508. }
  509. }
  510. // Approve
  511. if ($action == "confirm_approve" && GETPOST("confirm", 'alpha') == "yes" && $id > 0 && $user->hasRight('expensereport', 'approve')) {
  512. $object = new ExpenseReport($db);
  513. $object->fetch($id);
  514. $result = $object->setApproved($user);
  515. if ($result > 0) {
  516. // Define output language
  517. if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
  518. $outputlangs = $langs;
  519. $newlang = '';
  520. if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
  521. $newlang = GETPOST('lang_id', 'aZ09');
  522. }
  523. if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
  524. $newlang = $object->thirdparty->default_lang;
  525. }
  526. if (!empty($newlang)) {
  527. $outputlangs = new Translate("", $conf);
  528. $outputlangs->setDefaultLang($newlang);
  529. }
  530. $model = $object->model_pdf;
  531. $ret = $object->fetch($id); // Reload to get new records
  532. $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
  533. }
  534. }
  535. if ($result > 0) {
  536. // Send mail
  537. // TO
  538. $destinataire = new User($db);
  539. $destinataire->fetch($object->fk_user_author);
  540. $emailTo = $destinataire->email;
  541. // CC
  542. $emailCC = getDolGlobalString('NDF_CC_EMAILS');
  543. if (empty($emailTo)) {
  544. $emailTo = $emailCC;
  545. }
  546. // FROM
  547. $expediteur = new User($db);
  548. $expediteur->fetch($object->fk_user_approve > 0 ? $object->fk_user_approve : $object->fk_user_validator);
  549. $emailFrom = getDolGlobalString('MAIN_MAIL_EMAIL_FROM');
  550. if ($emailFrom && $emailTo) {
  551. $filename = array();
  552. $filedir = array();
  553. $mimetype = array();
  554. // SUBJECT
  555. $societeName = getDolGlobalString('MAIN_INFO_SOCIETE_NOM');
  556. if (getDolGlobalString('MAIN_APPLICATION_TITLE')) {
  557. $societeName = getDolGlobalString('MAIN_APPLICATION_TITLE');
  558. }
  559. $subject = $societeName." - ".$langs->transnoentities("ExpenseReportApproved");
  560. // CONTENT
  561. $link = $urlwithroot.'/expensereport/card.php?id='.$object->id;
  562. $link = '<a href="'.$link.'">'.$link.'</a>';
  563. $message = $langs->transnoentities("ExpenseReportApprovedMessage", $object->ref, $destinataire->getFullName($langs), $expediteur->getFullName($langs), $link);
  564. // Rebuilt pdf
  565. /*
  566. $object->setDocModel($user,"");
  567. $resultPDF = expensereport_pdf_create($db,$object,'',"",$langs);
  568. if($resultPDF
  569. {
  570. // ATTACHMENT
  571. $filename=array(); $filedir=array(); $mimetype=array();
  572. array_push($filename,dol_sanitizeFileName($object->ref).".pdf");
  573. array_push($filedir, $conf->expensereport->dir_output."/".dol_sanitizeFileName($object->ref)."/".dol_sanitizeFileName($object->ref).".pdf");
  574. array_push($mimetype,"application/pdf");
  575. }
  576. */
  577. $mailfile = new CMailFile($subject, $emailTo, $emailFrom, $message, $filedir, $mimetype, $filename, '', '', 0, -1);
  578. if ($mailfile) {
  579. // SEND
  580. $result = $mailfile->sendfile();
  581. if ($result) {
  582. $mesg = $langs->trans('MailSuccessfulySent', $mailfile->getValidAddress($emailFrom, 2), $mailfile->getValidAddress($emailTo, 2));
  583. setEventMessages($mesg, null, 'mesgs');
  584. header("Location: ".$_SERVER["PHP_SELF"]."?id=".$id);
  585. exit;
  586. } else {
  587. $langs->load("other");
  588. if ($mailfile->error) {
  589. $mesg = '';
  590. $mesg .= $langs->trans('ErrorFailedToSendMail', $emailFrom, $emailTo);
  591. $mesg .= '<br>'.$mailfile->error;
  592. setEventMessages($mesg, null, 'errors');
  593. } else {
  594. setEventMessages('No mail sent. Feature is disabled by option MAIN_DISABLE_ALL_MAILS', null, 'warnings');
  595. }
  596. }
  597. } else {
  598. setEventMessages($mailfile->error, $mailfile->errors, 'errors');
  599. $action = '';
  600. }
  601. } else {
  602. setEventMessages($langs->trans("NoEmailSentBadSenderOrRecipientEmail"), null, 'warnings');
  603. $action = '';
  604. }
  605. } else {
  606. setEventMessages($langs->trans("FailedtoSetToApprove"), null, 'warnings');
  607. $action = '';
  608. }
  609. }
  610. if ($action == "confirm_refuse" && GETPOST('confirm', 'alpha') == "yes" && $id > 0 && $user->hasRight('expensereport', 'approve')) {
  611. $object = new ExpenseReport($db);
  612. $object->fetch($id);
  613. $detailRefuse = GETPOST('detail_refuse', 'alpha');
  614. $result = $object->setDeny($user, $detailRefuse);
  615. if ($result > 0) {
  616. // Define output language
  617. if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
  618. $outputlangs = $langs;
  619. $newlang = '';
  620. if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
  621. $newlang = GETPOST('lang_id', 'aZ09');
  622. }
  623. if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
  624. $newlang = $object->thirdparty->default_lang;
  625. }
  626. if (!empty($newlang)) {
  627. $outputlangs = new Translate("", $conf);
  628. $outputlangs->setDefaultLang($newlang);
  629. }
  630. $model = $object->model_pdf;
  631. $ret = $object->fetch($id); // Reload to get new records
  632. $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
  633. }
  634. }
  635. if ($result > 0) {
  636. // Send mail
  637. // TO
  638. $destinataire = new User($db);
  639. $destinataire->fetch($object->fk_user_author);
  640. $emailTo = $destinataire->email;
  641. // FROM
  642. $expediteur = new User($db);
  643. $expediteur->fetch($object->fk_user_refuse);
  644. $emailFrom = $conf->global->MAIN_MAIL_EMAIL_FROM;
  645. if ($emailFrom && $emailTo) {
  646. $filename = array();
  647. $filedir = array();
  648. $mimetype = array();
  649. // SUBJECT
  650. $societeName = $conf->global->MAIN_INFO_SOCIETE_NOM;
  651. if (getDolGlobalString('MAIN_APPLICATION_TITLE')) {
  652. $societeName = $conf->global->MAIN_APPLICATION_TITLE;
  653. }
  654. $subject = $societeName." - ".$langs->transnoentities("ExpenseReportRefused");
  655. // CONTENT
  656. $link = $urlwithroot.'/expensereport/card.php?id='.$object->id;
  657. $link = '<a href="'.$link.'">'.$link.'</a>';
  658. $message = $langs->transnoentities("ExpenseReportRefusedMessage", $object->ref, $destinataire->getFullName($langs), $expediteur->getFullName($langs), $detailRefuse, $link);
  659. // Rebuilt pdf
  660. /*
  661. $object->setDocModel($user,"");
  662. $resultPDF = expensereport_pdf_create($db,$object,'',"",$langs);
  663. if($resultPDF
  664. {
  665. // ATTACHMENT
  666. $filename=array(); $filedir=array(); $mimetype=array();
  667. array_push($filename,dol_sanitizeFileName($object->ref).".pdf");
  668. array_push($filedir, $conf->expensereport->dir_output."/".dol_sanitizeFileName($object->ref)."/".dol_sanitizeFileName($object->ref).".pdf");
  669. array_push($mimetype,"application/pdf");
  670. }
  671. */
  672. // PREPARE SEND
  673. $mailfile = new CMailFile($subject, $emailTo, $emailFrom, $message, $filedir, $mimetype, $filename, '', '', 0, -1);
  674. if ($mailfile) {
  675. // SEND
  676. $result = $mailfile->sendfile();
  677. if ($result) {
  678. $mesg = $langs->trans('MailSuccessfulySent', $mailfile->getValidAddress($emailFrom, 2), $mailfile->getValidAddress($emailTo, 2));
  679. setEventMessages($mesg, null, 'mesgs');
  680. header("Location: ".$_SERVER["PHP_SELF"]."?id=".$id);
  681. exit;
  682. } else {
  683. $langs->load("other");
  684. if ($mailfile->error) {
  685. $mesg = '';
  686. $mesg .= $langs->trans('ErrorFailedToSendMail', $emailFrom, $emailTo);
  687. $mesg .= '<br>'.$mailfile->error;
  688. setEventMessages($mesg, null, 'errors');
  689. } else {
  690. setEventMessages('No mail sent. Feature is disabled by option MAIN_DISABLE_ALL_MAILS', null, 'warnings');
  691. }
  692. }
  693. } else {
  694. setEventMessages($mailfile->error, $mailfile->errors, 'errors');
  695. $action = '';
  696. }
  697. } else {
  698. setEventMessages($langs->trans("NoEmailSentBadSenderOrRecipientEmail"), null, 'warnings');
  699. $action = '';
  700. }
  701. } else {
  702. setEventMessages($langs->trans("FailedtoSetToDeny"), null, 'warnings');
  703. $action = '';
  704. }
  705. }
  706. //var_dump($user->id == $object->fk_user_validator);exit;
  707. if ($action == "confirm_cancel" && GETPOST('confirm', 'alpha') == "yes" && $id > 0 && $user->hasRight('expensereport', 'creer')) {
  708. if (!GETPOST('detail_cancel', 'alpha')) {
  709. setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Comment")), null, 'errors');
  710. } else {
  711. $object = new ExpenseReport($db);
  712. $object->fetch($id);
  713. if ($user->id == $object->fk_user_valid || $user->id == $object->fk_user_author) {
  714. $detailCancel = GETPOST('detail_cancel', 'alpha');
  715. $result = $object->set_cancel($user, $detailCancel);
  716. if ($result > 0) {
  717. // Define output language
  718. if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
  719. $outputlangs = $langs;
  720. $newlang = '';
  721. if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
  722. $newlang = GETPOST('lang_id', 'aZ09');
  723. }
  724. if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
  725. $newlang = $object->thirdparty->default_lang;
  726. }
  727. if (!empty($newlang)) {
  728. $outputlangs = new Translate("", $conf);
  729. $outputlangs->setDefaultLang($newlang);
  730. }
  731. $model = $object->model_pdf;
  732. $ret = $object->fetch($id); // Reload to get new records
  733. $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
  734. }
  735. }
  736. if ($result > 0) {
  737. // Send mail
  738. // TO
  739. $destinataire = new User($db);
  740. $destinataire->fetch($object->fk_user_author);
  741. $emailTo = $destinataire->email;
  742. // FROM
  743. $expediteur = new User($db);
  744. $expediteur->fetch($object->fk_user_cancel);
  745. $emailFrom = $conf->global->MAIN_MAIL_EMAIL_FROM;
  746. if ($emailFrom && $emailTo) {
  747. $filename = array();
  748. $filedir = array();
  749. $mimetype = array();
  750. // SUBJECT
  751. $societeName = $conf->global->MAIN_INFO_SOCIETE_NOM;
  752. if (getDolGlobalString('MAIN_APPLICATION_TITLE')) {
  753. $societeName = $conf->global->MAIN_APPLICATION_TITLE;
  754. }
  755. $subject = $societeName." - ".$langs->transnoentities("ExpenseReportCanceled");
  756. // CONTENT
  757. $link = $urlwithroot.'/expensereport/card.php?id='.$object->id;
  758. $link = '<a href="'.$link.'">'.$link.'</a>';
  759. $message = $langs->transnoentities("ExpenseReportCanceledMessage", $object->ref, $destinataire->getFullName($langs), $expediteur->getFullName($langs), $detailCancel, $link);
  760. // Rebuilt pdf
  761. /*
  762. $object->setDocModel($user,"");
  763. $resultPDF = expensereport_pdf_create($db,$object,'',"",$langs);
  764. if($resultPDF
  765. {
  766. // ATTACHMENT
  767. $filename=array(); $filedir=array(); $mimetype=array();
  768. array_push($filename,dol_sanitizeFileName($object->ref).".pdf");
  769. array_push($filedir, $conf->expensereport->dir_output."/".dol_sanitizeFileName($object->ref)."/".dol_sanitizeFileName($object->ref).".pdf");
  770. array_push($mimetype,"application/pdf");
  771. }
  772. */
  773. // PREPARE SEND
  774. $mailfile = new CMailFile($subject, $emailTo, $emailFrom, $message, $filedir, $mimetype, $filename, '', '', 0, -1);
  775. if ($mailfile) {
  776. // SEND
  777. $result = $mailfile->sendfile();
  778. if ($result) {
  779. $mesg = $langs->trans('MailSuccessfulySent', $mailfile->getValidAddress($emailFrom, 2), $mailfile->getValidAddress($emailTo, 2));
  780. setEventMessages($mesg, null, 'mesgs');
  781. header("Location: ".$_SERVER["PHP_SELF"]."?id=".$id);
  782. exit;
  783. } else {
  784. $langs->load("other");
  785. if ($mailfile->error) {
  786. $mesg = '';
  787. $mesg .= $langs->trans('ErrorFailedToSendMail', $emailFrom, $emailTo);
  788. $mesg .= '<br>'.$mailfile->error;
  789. setEventMessages($mesg, null, 'errors');
  790. } else {
  791. setEventMessages('No mail sent. Feature is disabled by option MAIN_DISABLE_ALL_MAILS', null, 'warnings');
  792. }
  793. }
  794. } else {
  795. setEventMessages($mailfile->error, $mailfile->errors, 'errors');
  796. $action = '';
  797. }
  798. } else {
  799. setEventMessages($langs->trans("NoEmailSentBadSenderOrRecipientEmail"), null, 'warnings');
  800. $action = '';
  801. }
  802. } else {
  803. setEventMessages($langs->trans("FailedToSetToCancel"), null, 'warnings');
  804. $action = '';
  805. }
  806. } else {
  807. setEventMessages($object->error, $object->errors, 'errors');
  808. }
  809. }
  810. }
  811. if ($action == "confirm_setdraft" && GETPOST('confirm', 'alpha') == "yes" && $id > 0 && $user->hasRight('expensereport', 'creer')) {
  812. $object = new ExpenseReport($db);
  813. $object->fetch($id);
  814. if ($user->id == $object->fk_user_author || $user->id == $object->fk_user_valid) {
  815. $result = $object->setStatut(0);
  816. if ($result > 0) {
  817. // Define output language
  818. if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
  819. $outputlangs = $langs;
  820. $newlang = '';
  821. if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
  822. $newlang = GETPOST('lang_id', 'aZ09');
  823. }
  824. if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
  825. $newlang = $object->thirdparty->default_lang;
  826. }
  827. if (!empty($newlang)) {
  828. $outputlangs = new Translate("", $conf);
  829. $outputlangs->setDefaultLang($newlang);
  830. }
  831. $model = $object->model_pdf;
  832. $ret = $object->fetch($id); // Reload to get new records
  833. $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
  834. }
  835. }
  836. if ($result > 0) {
  837. header("Location: ".$_SERVER["PHP_SELF"]."?id=".$id);
  838. exit;
  839. } else {
  840. setEventMessages($object->error, $object->errors, 'errors');
  841. }
  842. } else {
  843. setEventMessages("NOT_AUTHOR", null, 'errors');
  844. }
  845. }
  846. if ($action == 'set_unpaid' && $id > 0 && $user->hasRight('expensereport', 'to_paid')) {
  847. $object = new ExpenseReport($db);
  848. $object->fetch($id);
  849. $result = $object->setUnpaid($user);
  850. if ($result > 0) {
  851. // Define output language
  852. if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
  853. $outputlangs = $langs;
  854. $newlang = '';
  855. if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
  856. $newlang = GETPOST('lang_id', 'aZ09');
  857. }
  858. if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
  859. $newlang = $object->thirdparty->default_lang;
  860. }
  861. if (!empty($newlang)) {
  862. $outputlangs = new Translate("", $conf);
  863. $outputlangs->setDefaultLang($newlang);
  864. }
  865. $model = $object->model_pdf;
  866. $ret = $object->fetch($id); // Reload to get new records
  867. $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
  868. }
  869. }
  870. }
  871. if ($action == 'set_paid' && $id > 0 && $user->hasRight('expensereport', 'to_paid')) {
  872. $object = new ExpenseReport($db);
  873. $object->fetch($id);
  874. $result = $object->setPaid($id, $user);
  875. if ($result > 0) {
  876. // Define output language
  877. if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
  878. $outputlangs = $langs;
  879. $newlang = '';
  880. if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
  881. $newlang = GETPOST('lang_id', 'aZ09');
  882. }
  883. if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
  884. $newlang = $object->thirdparty->default_lang;
  885. }
  886. if (!empty($newlang)) {
  887. $outputlangs = new Translate("", $conf);
  888. $outputlangs->setDefaultLang($newlang);
  889. }
  890. $model = $object->model_pdf;
  891. $ret = $object->fetch($id); // Reload to get new records
  892. $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
  893. }
  894. }
  895. if ($result > 0) {
  896. // Send mail
  897. // TO
  898. $destinataire = new User($db);
  899. $destinataire->fetch($object->fk_user_author);
  900. $emailTo = $destinataire->email;
  901. // FROM
  902. $expediteur = new User($db);
  903. $expediteur->fetch($user->id);
  904. $emailFrom = $conf->global->MAIN_MAIL_EMAIL_FROM;
  905. if ($emailFrom && $emailTo) {
  906. $filename = array();
  907. $filedir = array();
  908. $mimetype = array();
  909. // SUBJECT
  910. $societeName = $conf->global->MAIN_INFO_SOCIETE_NOM;
  911. if (getDolGlobalString('MAIN_APPLICATION_TITLE')) {
  912. $societeName = $conf->global->MAIN_APPLICATION_TITLE;
  913. }
  914. $subject = $societeName." - ".$langs->transnoentities("ExpenseReportPaid");
  915. // CONTENT
  916. $link = $urlwithroot.'/expensereport/card.php?id='.$object->id;
  917. $link = '<a href="'.$link.'">'.$link.'</a>';
  918. $message = $langs->transnoentities("ExpenseReportPaidMessage", $object->ref, $destinataire->getFullName($langs), $expediteur->getFullName($langs), $link);
  919. // Generate pdf before attachment
  920. $object->setDocModel($user, "");
  921. $resultPDF = expensereport_pdf_create($db, $object, '', "", $langs);
  922. // PREPARE SEND
  923. $mailfile = new CMailFile($subject, $emailTo, $emailFrom, $message, $filedir, $mimetype, $filename, '', '', 0, -1);
  924. if ($mailfile) {
  925. // SEND
  926. $result = $mailfile->sendfile();
  927. if ($result) {
  928. $mesg = $langs->trans('MailSuccessfulySent', $mailfile->getValidAddress($emailFrom, 2), $mailfile->getValidAddress($emailTo, 2));
  929. setEventMessages($mesg, null, 'mesgs');
  930. header("Location: ".$_SERVER["PHP_SELF"]."?id=".$id);
  931. exit;
  932. } else {
  933. $langs->load("other");
  934. if ($mailfile->error) {
  935. $mesg = '';
  936. $mesg .= $langs->trans('ErrorFailedToSendMail', $emailFrom, $emailTo);
  937. $mesg .= '<br>'.$mailfile->error;
  938. setEventMessages($mesg, null, 'errors');
  939. } else {
  940. setEventMessages('No mail sent. Feature is disabled by option MAIN_DISABLE_ALL_MAILS', null, 'warnings');
  941. }
  942. }
  943. } else {
  944. setEventMessages($mailfile->error, $mailfile->errors, 'errors');
  945. $action = '';
  946. }
  947. } else {
  948. setEventMessages($langs->trans("NoEmailSentBadSenderOrRecipientEmail"), null, 'warnings');
  949. $action = '';
  950. }
  951. } else {
  952. setEventMessages($langs->trans("FailedToSetPaid"), null, 'warnings');
  953. $action = '';
  954. }
  955. }
  956. if ($action == "addline" && $user->hasRight('expensereport', 'creer')) {
  957. $error = 0;
  958. // First save uploaded file
  959. $fk_ecm_files = 0;
  960. if (GETPOSTISSET('attachfile')) {
  961. $arrayoffiles = GETPOST('attachfile', 'array');
  962. if (is_array($arrayoffiles) && !empty($arrayoffiles[0])) {
  963. include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
  964. $entityprefix = ($conf->entity != '1') ? $conf->entity.'/' : '';
  965. $relativepath = 'expensereport/'.$object->ref.'/'.$arrayoffiles[0];
  966. $ecmfiles = new EcmFiles($db);
  967. $ecmfiles->fetch(0, '', $relativepath);
  968. $fk_ecm_files = $ecmfiles->id;
  969. }
  970. }
  971. // if VAT is not used in Dolibarr, set VAT rate to 0 because VAT rate is necessary.
  972. if (empty($vatrate)) {
  973. $vatrate = "0.000";
  974. }
  975. $tmpvat = price2num(preg_replace('/\s*\(.*\)/', '', $vatrate));
  976. $value_unit_ht = price2num(GETPOST('value_unit_ht', 'alpha'), 'MU');
  977. $value_unit = price2num(GETPOST('value_unit', 'alpha'), 'MU');
  978. if (empty($value_unit)) {
  979. $value_unit = price2num($value_unit_ht + ($value_unit_ht * $tmpvat / 100), 'MU');
  980. }
  981. $fk_c_exp_tax_cat = GETPOST('fk_c_exp_tax_cat', 'int');
  982. $qty = price2num(GETPOST('qty', 'alpha'));
  983. if (empty($qty)) {
  984. $qty = 1;
  985. }
  986. if (!($fk_c_type_fees > 0)) {
  987. $error++;
  988. setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Type")), null, 'errors');
  989. $action = '';
  990. }
  991. if ((float) $tmpvat < 0 || $tmpvat === '') {
  992. $error++;
  993. setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("VAT")), null, 'errors');
  994. $action = '';
  995. }
  996. // If no date entered
  997. if (empty($date) || $date == "--") {
  998. $error++;
  999. setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Date")), null, 'errors');
  1000. } elseif ($date < $object->date_debut || $date > ($object->date_fin + (24 * 3600 - 1))) {
  1001. // Warning if date out of range
  1002. $langs->load("errors");
  1003. setEventMessages($langs->trans("WarningDateOfLineMustBeInExpenseReportRange"), null, 'warnings');
  1004. }
  1005. // If no price entered
  1006. if ($value_unit == 0) {
  1007. $error++;
  1008. setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("PriceUTTC")), null, 'errors');
  1009. }
  1010. // If no project entered
  1011. if ($projectRequired && $fk_project <= 0) {
  1012. $error++;
  1013. setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Project")), null, 'errors');
  1014. }
  1015. // If no file associated
  1016. if ($fileRequired && $fk_ecm_files == 0) {
  1017. $error++;
  1018. setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("File")), null, 'errors');
  1019. }
  1020. if (!$error) {
  1021. $type = 0; // TODO What if service ? We should take the type product/service from the type of expense report llx_c_type_fees
  1022. // Insert line
  1023. $result = $object->addline($qty, $value_unit, $fk_c_type_fees, $vatrate, $date, $comments, $fk_project, $fk_c_exp_tax_cat, $type, $fk_ecm_files);
  1024. if ($result > 0) {
  1025. $ret = $object->fetch($object->id); // Reload to get new records
  1026. if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
  1027. // Define output language
  1028. $outputlangs = $langs;
  1029. $newlang = GETPOST('lang_id', 'alpha');
  1030. if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
  1031. $user = new User($db);
  1032. $user->fetch($object->fk_user_author);
  1033. $newlang = $user->lang;
  1034. }
  1035. if (!empty($newlang)) {
  1036. $outputlangs = new Translate("", $conf);
  1037. $outputlangs->setDefaultLang($newlang);
  1038. }
  1039. $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
  1040. }
  1041. unset($qty);
  1042. unset($value_unit_ht);
  1043. unset($value_unit);
  1044. unset($vatrate);
  1045. unset($comments);
  1046. unset($fk_c_type_fees);
  1047. unset($fk_project);
  1048. unset($date);
  1049. } else {
  1050. $error++;
  1051. setEventMessages($object->error, $object->errors, 'errors');
  1052. }
  1053. }
  1054. if (!$error) {
  1055. header("Location: ".$_SERVER["PHP_SELF"]."?id=".GETPOST('id', 'int'));
  1056. exit;
  1057. } else {
  1058. $action = '';
  1059. }
  1060. }
  1061. if ($action == 'confirm_delete_line' && GETPOST("confirm", 'alpha') == "yes" && $user->hasRight('expensereport', 'creer')) {
  1062. $object = new ExpenseReport($db);
  1063. $object->fetch($id);
  1064. $object_ligne = new ExpenseReportLine($db);
  1065. $object_ligne->fetch(GETPOST("rowid", 'int'));
  1066. $total_ht = $object_ligne->total_ht;
  1067. $total_tva = $object_ligne->total_tva;
  1068. $result = $object->deleteline(GETPOST("rowid", 'int'), $user);
  1069. if ($result >= 0) {
  1070. if ($result > 0) {
  1071. // Define output language
  1072. if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
  1073. $outputlangs = $langs;
  1074. $newlang = '';
  1075. if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
  1076. $newlang = GETPOST('lang_id', 'aZ09');
  1077. }
  1078. if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
  1079. $newlang = $object->thirdparty->default_lang;
  1080. }
  1081. if (!empty($newlang)) {
  1082. $outputlangs = new Translate("", $conf);
  1083. $outputlangs->setDefaultLang($newlang);
  1084. }
  1085. $model = $object->model_pdf;
  1086. $ret = $object->fetch($id); // Reload to get new records
  1087. $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
  1088. }
  1089. }
  1090. header("Location: ".$_SERVER["PHP_SELF"]."?id=".GETPOST('id', 'int'));
  1091. exit;
  1092. } else {
  1093. setEventMessages($object->error, $object->errors, 'errors');
  1094. }
  1095. }
  1096. if ($action == "updateline" && $user->hasRight('expensereport', 'creer')) {
  1097. $object = new ExpenseReport($db);
  1098. $object->fetch($id);
  1099. // First save uploaded file
  1100. $fk_ecm_files = 0;
  1101. if (GETPOSTISSET('attachfile')) {
  1102. $arrayoffiles = GETPOST('attachfile', 'array');
  1103. if (is_array($arrayoffiles) && !empty($arrayoffiles[0])) {
  1104. include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
  1105. $relativepath = 'expensereport/'.$object->ref.'/'.$arrayoffiles[0];
  1106. $ecmfiles = new EcmFiles($db);
  1107. $ecmfiles->fetch(0, '', $relativepath);
  1108. $fk_ecm_files = $ecmfiles->id;
  1109. }
  1110. }
  1111. $rowid = GETPOST('rowid', 'int');
  1112. $type_fees_id = GETPOST('fk_c_type_fees', 'int');
  1113. $fk_c_exp_tax_cat = GETPOST('fk_c_exp_tax_cat', 'int');
  1114. $projet_id = $fk_project;
  1115. $comments = GETPOST('comments', 'restricthtml');
  1116. $qty = price2num(GETPOST('qty', 'alpha'));
  1117. $vatrate = GETPOST('vatrate', 'alpha');
  1118. // if VAT is not used in Dolibarr, set VAT rate to 0 because VAT rate is necessary.
  1119. if (empty($vatrate)) {
  1120. $vatrate = "0.000";
  1121. }
  1122. $tmpvat = price2num(preg_replace('/\s*\(.*\)/', '', $vatrate));
  1123. $value_unit_ht = price2num(GETPOST('value_unit_ht', 'alpha'), 'MU');
  1124. $value_unit = price2num(GETPOST('value_unit', 'alpha'), 'MU');
  1125. if (empty($value_unit)) {
  1126. $value_unit = price2num($value_unit_ht + ($value_unit_ht * $tmpvat / 100), 'MU');
  1127. }
  1128. if (!GETPOST('fk_c_type_fees', 'int') > 0) {
  1129. $error++;
  1130. setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Type")), null, 'errors');
  1131. $action = '';
  1132. }
  1133. if ((float) $tmpvat < 0 || $tmpvat == '') {
  1134. $error++;
  1135. setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Vat")), null, 'errors');
  1136. $action = '';
  1137. }
  1138. // Warning if date out of range
  1139. if ($date < $object->date_debut || $date > ($object->date_fin + (24 * 3600 - 1))) {
  1140. $langs->load("errors");
  1141. setEventMessages($langs->trans("WarningDateOfLineMustBeInExpenseReportRange"), null, 'warnings');
  1142. }
  1143. // If no project entered
  1144. if ($projectRequired && $projet_id <= 0) {
  1145. $error++;
  1146. setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Project")), null, 'errors');
  1147. }
  1148. if (!$error) {
  1149. // TODO Use update method of ExpenseReportLine
  1150. $result = $object->updateline($rowid, $type_fees_id, $projet_id, $vatrate, $comments, $qty, $value_unit, $date, $id, $fk_c_exp_tax_cat, $fk_ecm_files);
  1151. if ($result >= 0) {
  1152. if ($result > 0) {
  1153. // Define output language
  1154. if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
  1155. $outputlangs = $langs;
  1156. $newlang = '';
  1157. if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
  1158. $newlang = GETPOST('lang_id', 'aZ09');
  1159. }
  1160. if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
  1161. $newlang = $object->thirdparty->default_lang;
  1162. }
  1163. if (!empty($newlang)) {
  1164. $outputlangs = new Translate("", $conf);
  1165. $outputlangs->setDefaultLang($newlang);
  1166. }
  1167. $model = $object->model_pdf;
  1168. $ret = $object->fetch($id); // Reload to get new records
  1169. $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
  1170. }
  1171. unset($qty);
  1172. unset($value_unit_ht);
  1173. unset($value_unit);
  1174. unset($vatrate);
  1175. unset($comments);
  1176. unset($fk_c_type_fees);
  1177. unset($fk_project);
  1178. unset($date);
  1179. }
  1180. //header("Location: ".$_SERVER["PHP_SELF"]."?id=".$id);
  1181. //exit;
  1182. } else {
  1183. setEventMessages($object->error, $object->errors, 'errors');
  1184. }
  1185. }
  1186. }
  1187. // Actions when printing a doc from card
  1188. include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php';
  1189. // Actions to send emails
  1190. $triggersendname = 'EXPENSEREPORT_SENTBYMAIL';
  1191. $autocopy = 'MAIN_MAIL_AUTOCOPY_EXPENSEREPORT_TO';
  1192. $trackid = 'exp'.$object->id;
  1193. include DOL_DOCUMENT_ROOT.'/core/actions_sendmails.inc.php';
  1194. // Actions to build doc
  1195. $upload_dir = $conf->expensereport->dir_output;
  1196. include DOL_DOCUMENT_ROOT.'/core/actions_builddoc.inc.php';
  1197. }
  1198. /*
  1199. * View
  1200. */
  1201. $title = $langs->trans("ExpenseReport")." - ".$langs->trans("Card");
  1202. $help_url = "EN:Module_Expense_Reports|FR:Module_Notes_de_frais";
  1203. llxHeader("", $title, $help_url);
  1204. $form = new Form($db);
  1205. $formfile = new FormFile($db);
  1206. $formproject = new FormProjets($db);
  1207. $projecttmp = new Project($db);
  1208. $paymentexpensereportstatic = new PaymentExpenseReport($db);
  1209. $bankaccountstatic = new Account($db);
  1210. $ecmfilesstatic = new EcmFiles($db);
  1211. $formexpensereport = new FormExpenseReport($db);
  1212. // Create
  1213. if ($action == 'create') {
  1214. print load_fiche_titre($langs->trans("NewTrip"), '', 'trip');
  1215. print '<form action="'.$_SERVER['PHP_SELF'].'" method="post" name="create">';
  1216. print '<input type="hidden" name="token" value="'.newToken().'">';
  1217. print '<input type="hidden" name="action" value="add">';
  1218. print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
  1219. print dol_get_fiche_head('');
  1220. print '<table class="border centpercent">';
  1221. print '<tbody>';
  1222. // Date start
  1223. print '<tr>';
  1224. print '<td class="titlefieldcreate fieldrequired">'.$langs->trans("DateStart").'</td>';
  1225. print '<td>';
  1226. print $form->selectDate($date_start ? $date_start : -1, 'date_debut', 0, 0, 0, '', 1, 1);
  1227. print '</td>';
  1228. print '</tr>';
  1229. // Date end
  1230. print '<tr>';
  1231. print '<td class="fieldrequired">'.$langs->trans("DateEnd").'</td>';
  1232. print '<td>';
  1233. print $form->selectDate($date_end ? $date_end : -1, 'date_fin', 0, 0, 0, '', 1, 1);
  1234. print '</td>';
  1235. print '</tr>';
  1236. // User for expense report
  1237. print '<tr>';
  1238. print '<td class="fieldrequired">'.$langs->trans("User").'</td>';
  1239. print '<td>';
  1240. $defaultselectuser = $user->id;
  1241. if (GETPOST('fk_user_author', 'int') > 0) {
  1242. $defaultselectuser = GETPOST('fk_user_author', 'int');
  1243. }
  1244. $include_users = 'hierarchyme';
  1245. if (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('expensereport', 'writeall_advance')) {
  1246. $include_users = array();
  1247. }
  1248. $s = $form->select_dolusers($defaultselectuser, "fk_user_author", 0, "", 0, $include_users, '', '0,'.$conf->entity);
  1249. print $s;
  1250. print '</td>';
  1251. print '</tr>';
  1252. // Approver
  1253. print '<tr>';
  1254. print '<td>'.$langs->trans("VALIDATOR").'</td>';
  1255. print '<td>';
  1256. $object = new ExpenseReport($db);
  1257. $include_users = $object->fetch_users_approver_expensereport();
  1258. if (empty($include_users)) {
  1259. print img_warning().' '.$langs->trans("NobodyHasPermissionToValidateExpenseReport");
  1260. } else {
  1261. $defaultselectuser = (empty($user->fk_user_expense_validator) ? $user->fk_user : $user->fk_user_expense_validator); // Will work only if supervisor has permission to approve so is inside include_users
  1262. if (getDolGlobalString('EXPENSEREPORT_DEFAULT_VALIDATOR')) {
  1263. $defaultselectuser = $conf->global->EXPENSEREPORT_DEFAULT_VALIDATOR; // Can force default approver
  1264. }
  1265. if (GETPOST('fk_user_validator', 'int') > 0) {
  1266. $defaultselectuser = GETPOST('fk_user_validator', 'int');
  1267. }
  1268. $s = $form->select_dolusers($defaultselectuser, "fk_user_validator", 1, "", ((empty($defaultselectuser) || !getDolGlobalString('EXPENSEREPORT_DEFAULT_VALIDATOR_UNCHANGEABLE')) ? 0 : 1), $include_users);
  1269. print $form->textwithpicto($s, $langs->trans("AnyOtherInThisListCanValidate"));
  1270. }
  1271. print '</td>';
  1272. print '</tr>';
  1273. // Payment mode
  1274. if (getDolGlobalString('EXPENSEREPORT_ASK_PAYMENTMODE_ON_CREATION')) {
  1275. print '<tr>';
  1276. print '<td>'.$langs->trans("ModePaiement").'</td>';
  1277. print '<td>';
  1278. $form->select_types_paiements('', 'fk_c_paiement');
  1279. print '</td>';
  1280. print '</tr>';
  1281. }
  1282. // Public note
  1283. $note_public = GETPOSTISSET('note_public') ? GETPOST('note_public', 'restricthtml') : '';
  1284. print '<tr>';
  1285. print '<td class="tdtop">'.$langs->trans('NotePublic').'</td>';
  1286. print '<td>';
  1287. $doleditor = new DolEditor('note_public', $note_public, '', 80, 'dolibarr_notes', 'In', 0, false, !getDolGlobalString('FCKEDITOR_ENABLE_NOTE_PUBLIC') ? 0 : 1, ROWS_3, '90%');
  1288. print $doleditor->Create(1);
  1289. print '</td></tr>';
  1290. // Private note
  1291. $note_private = GETPOSTISSET('note_private') ? GETPOST('note_private', 'restricthtml') : '';
  1292. if (empty($user->socid)) {
  1293. print '<tr>';
  1294. print '<td class="tdtop">'.$langs->trans('NotePrivate').'</td>';
  1295. print '<td>';
  1296. $doleditor = new DolEditor('note_private', $note_private, '', 80, 'dolibarr_notes', 'In', 0, false, !getDolGlobalString('FCKEDITOR_ENABLE_NOTE_PRIVATE') ? 0 : 1, ROWS_3, '90%');
  1297. print $doleditor->Create(1);
  1298. print '</td></tr>';
  1299. }
  1300. // Other attributes
  1301. $parameters = array('colspan' => ' colspan="3"', 'cols' => 3);
  1302. $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $object, $action); // Note that $action and $object may have been modified by
  1303. print $hookmanager->resPrint;
  1304. if (empty($reshook)) {
  1305. print $object->showOptionals($extrafields, 'create', $parameters);
  1306. }
  1307. print '<tbody>';
  1308. print '</table>';
  1309. print dol_get_fiche_end();
  1310. print $form->buttonsSaveCancel("AddTrip");
  1311. print '</form>';
  1312. } elseif ($id > 0 || $ref) {
  1313. $result = $object->fetch($id, $ref);
  1314. if ($result > 0) {
  1315. if (!in_array($object->fk_user_author, $user->getAllChildIds(1))) {
  1316. if (!$user->hasRight('expensereport', 'readall') && !$user->hasRight('expensereport', 'lire_tous')
  1317. && (!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') || !$user->hasRight('expensereport', 'writeall_advance'))) {
  1318. print load_fiche_titre($langs->trans('TripCard'), '', 'trip');
  1319. print '<div class="tabBar">';
  1320. print $langs->trans('NotUserRightToView');
  1321. print '</div>';
  1322. // End of page
  1323. llxFooter();
  1324. $db->close();
  1325. exit;
  1326. }
  1327. }
  1328. $head = expensereport_prepare_head($object);
  1329. if ($action == 'edit' && ($object->status < 3 || $object->status == 99)) {
  1330. print "<form name='update' action=\"".$_SERVER['PHP_SELF']."\" method=\"post\">\n";
  1331. print '<input type="hidden" name="token" value="'.newToken().'">';
  1332. print '<input type="hidden" name="id" value="'.$id.'">';
  1333. print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
  1334. print dol_get_fiche_head($head, 'card', $langs->trans("ExpenseReport"), 0, 'trip');
  1335. if ($object->status == 99) {
  1336. print '<input type="hidden" name="action" value="updateFromRefuse">';
  1337. } else {
  1338. print '<input type="hidden" name="action" value="update">';
  1339. }
  1340. $linkback = '<a href="'.DOL_URL_ROOT.'/expensereport/list.php?restore_lastsearch_values=1'.(!empty($socid) ? '&socid='.$socid : '').'">'.$langs->trans("BackToList").'</a>';
  1341. print '<table class="border centpercent">';
  1342. print '<tr>';
  1343. print '<td>'.$langs->trans("User").'</td>';
  1344. print '<td>';
  1345. $userfee = new User($db);
  1346. if ($object->fk_user_author > 0) {
  1347. $userfee->fetch($object->fk_user_author);
  1348. print $userfee->getNomUrl(-1);
  1349. }
  1350. print '</td></tr>';
  1351. // Ref
  1352. print '<tr><td class="titlefieldcreate">'.$langs->trans("Ref").'</td><td>';
  1353. print $form->showrefnav($object, 'ref', $linkback, 1, 'ref', 'ref', '');
  1354. print '</td></tr>';
  1355. print '<tr>';
  1356. print '<td>'.$langs->trans("DateStart").'</td>';
  1357. print '<td>';
  1358. print $form->selectDate($object->date_debut, 'date_debut');
  1359. print '</td>';
  1360. print '</tr>';
  1361. print '<tr>';
  1362. print '<td>'.$langs->trans("DateEnd").'</td>';
  1363. print '<td>';
  1364. print $form->selectDate($object->date_fin, 'date_fin');
  1365. print '</td>';
  1366. print '</tr>';
  1367. if (getDolGlobalString('EXPENSEREPORT_ASK_PAYMENTMODE_ON_CREATION')) {
  1368. print '<tr>';
  1369. print '<td>'.$langs->trans("ModePaiement").'</td>';
  1370. print '<td>';
  1371. $form->select_types_paiements($object->fk_c_paiement, 'fk_c_paiement');
  1372. print '</td>';
  1373. print '</tr>';
  1374. }
  1375. if ($object->status < 3) {
  1376. print '<tr>';
  1377. print '<td>'.$langs->trans("VALIDATOR").'</td>'; // Approbator
  1378. print '<td>';
  1379. $include_users = $object->fetch_users_approver_expensereport();
  1380. $s = $form->select_dolusers($object->fk_user_validator, "fk_user_validator", 1, "", 0, $include_users);
  1381. print $form->textwithpicto($s, $langs->trans("AnyOtherInThisListCanValidate"));
  1382. print '</td>';
  1383. print '</tr>';
  1384. } else {
  1385. print '<tr>';
  1386. print '<td>'.$langs->trans("VALIDOR").'</td>';
  1387. print '<td>';
  1388. $userfee = new User($db);
  1389. $userfee->fetch($object->fk_user_valid);
  1390. print $userfee->getNomUrl(-1);
  1391. print '</td></tr>';
  1392. }
  1393. if ($object->status == 6) {
  1394. print '<tr>';
  1395. print '<td>'.$langs->trans("AUTHORPAIEMENT").'</td>';
  1396. print '<td>';
  1397. $userfee = new User($db);
  1398. $userfee->fetch($user->id);
  1399. print $userfee->getNomUrl(-1);
  1400. print '</td></tr>';
  1401. }
  1402. // Other attributes
  1403. //$cols = 3;
  1404. //include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_edit.tpl.php';
  1405. print '</table>';
  1406. print dol_get_fiche_end();
  1407. print $form->buttonsSaveCancel("Modify");
  1408. print '</form>';
  1409. } else {
  1410. $taxlessUnitPriceDisabled = getDolGlobalString('EXPENSEREPORT_FORCE_LINE_AMOUNTS_INCLUDING_TAXES_ONLY') ? ' disabled' : '';
  1411. print dol_get_fiche_head($head, 'card', $langs->trans("ExpenseReport"), -1, 'trip');
  1412. $formconfirm = '';
  1413. // Clone confirmation
  1414. if ($action == 'clone') {
  1415. // Create an array for form
  1416. $criteriaforfilter = 'hierarchyme';
  1417. if ($user->hasRight('expensereport', 'readall')) {
  1418. $criteriaforfilter = '';
  1419. }
  1420. $formquestion = array(
  1421. 'text' => '',
  1422. array('type' => 'other', 'name' => 'fk_user_author', 'label' => $langs->trans("SelectTargetUser"), 'value' => $form->select_dolusers((GETPOST('fk_user_author', 'int') > 0 ? GETPOST('fk_user_author', 'int') : $user->id), 'fk_user_author', 0, null, 0, $criteriaforfilter, '', '0', 0, 0, '', 0, '', 'maxwidth150'))
  1423. );
  1424. // Paiement incomplet. On demande si motif = escompte ou autre
  1425. $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ToClone'), $langs->trans('ConfirmCloneExpenseReport', $object->ref), 'confirm_clone', $formquestion, 'yes', 1);
  1426. }
  1427. if ($action == 'save') {
  1428. $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"]."?id=".$id, $langs->trans("SaveTrip"), $langs->trans("ConfirmSaveTrip"), "confirm_validate", "", "", 1);
  1429. }
  1430. if ($action == 'save_from_refuse') {
  1431. $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"]."?id=".$id, $langs->trans("SaveTrip"), $langs->trans("ConfirmSaveTrip"), "confirm_save_from_refuse", "", "", 1);
  1432. }
  1433. if ($action == 'delete') {
  1434. $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"]."?id=".$id, $langs->trans("DeleteTrip"), $langs->trans("ConfirmDeleteTrip"), "confirm_delete", "", "", 1);
  1435. }
  1436. if ($action == 'validate') {
  1437. $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"]."?id=".$id, $langs->trans("ValideTrip"), $langs->trans("ConfirmValideTrip"), "confirm_approve", "", "", 1);
  1438. }
  1439. if ($action == 'paid') {
  1440. $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"]."?id=".$id, $langs->trans("PaidTrip"), $langs->trans("ConfirmPaidTrip"), "confirm_paid", "", "", 1);
  1441. }
  1442. if ($action == 'cancel') {
  1443. $array_input = array('text'=>$langs->trans("ConfirmCancelTrip"), array('type'=>"text", 'label'=>'<strong>'.$langs->trans("Comment").'</strong>', 'name'=>"detail_cancel", 'value'=>""));
  1444. $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"]."?id=".$id, $langs->trans("Cancel"), "", "confirm_cancel", $array_input, "", 1);
  1445. }
  1446. if ($action == 'setdraft') {
  1447. $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"]."?id=".$id, $langs->trans("BrouillonnerTrip"), $langs->trans("ConfirmBrouillonnerTrip"), "confirm_setdraft", "", "", 1);
  1448. }
  1449. if ($action == 'refuse') { // Deny
  1450. $array_input = array('text'=>$langs->trans("ConfirmRefuseTrip"), array('type'=>"text", 'label'=>$langs->trans("Comment"), 'name'=>"detail_refuse", 'value'=>""));
  1451. $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"]."?id=".$id, $langs->trans("Deny"), '', "confirm_refuse", $array_input, "yes", 1);
  1452. }
  1453. if ($action == 'delete_line') {
  1454. $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"]."?id=".$id."&rowid=".GETPOST('rowid', 'int'), $langs->trans("DeleteLine"), $langs->trans("ConfirmDeleteLine"), "confirm_delete_line", '', 'yes', 1);
  1455. }
  1456. // Print form confirm
  1457. print $formconfirm;
  1458. // Expense report card
  1459. $linkback = '<a href="'.DOL_URL_ROOT.'/expensereport/list.php?restore_lastsearch_values=1'.(!empty($socid) ? '&socid='.$socid : '').'">'.$langs->trans("BackToList").'</a>';
  1460. $morehtmlref = '<div class="refidno">';
  1461. $morehtmlref .= '</div>';
  1462. dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref);
  1463. print '<div class="fichecenter">';
  1464. print '<div class="fichehalfleft">';
  1465. print '<div class="underbanner clearboth"></div>';
  1466. print '<table class="border tableforfield centpercent">';
  1467. // Author
  1468. print '<tr>';
  1469. print '<td class="titlefield">'.$langs->trans("User").'</td>';
  1470. print '<td>';
  1471. if ($object->fk_user_author > 0) {
  1472. $userauthor = new User($db);
  1473. $result = $userauthor->fetch($object->fk_user_author);
  1474. if ($result < 0) {
  1475. dol_print_error('', $userauthor->error);
  1476. } elseif ($result > 0) {
  1477. print $userauthor->getNomUrl(-1);
  1478. }
  1479. }
  1480. print '</td></tr>';
  1481. // Period
  1482. print '<tr>';
  1483. print '<td class="titlefield">'.$langs->trans("Period").'</td>';
  1484. print '<td>';
  1485. print get_date_range($object->date_debut, $object->date_fin, 'day', $langs, 0);
  1486. print '</td>';
  1487. print '</tr>';
  1488. if (getDolGlobalString('EXPENSEREPORT_ASK_PAYMENTMODE_ON_CREATION')) {
  1489. print '<tr>';
  1490. print '<td>'.$langs->trans("ModePaiement").'</td>';
  1491. print '<td>'.$object->fk_c_paiement.'</td>';
  1492. print '</tr>';
  1493. }
  1494. // Validation date
  1495. print '<tr>';
  1496. print '<td>'.$langs->trans("DATE_SAVE").'</td>';
  1497. print '<td>'.dol_print_date($object->date_valid, 'dayhour', 'tzuser');
  1498. if ($object->status == 2 && $object->hasDelay('toapprove')) {
  1499. print ' '.img_warning($langs->trans("Late").' - '.$langs->trans("ToApprove"));
  1500. }
  1501. if ($object->status == 5 && $object->hasDelay('topay')) {
  1502. print ' '.img_warning($langs->trans("Late").' - '.$langs->trans("ToPay"));
  1503. }
  1504. print '</td></tr>';
  1505. print '</tr>';
  1506. // User to inform for approval
  1507. if ($object->status <= ExpenseReport::STATUS_VALIDATED) { // informed
  1508. print '<tr>';
  1509. print '<td>'.$langs->trans("VALIDATOR").'</td>'; // approver
  1510. print '<td>';
  1511. if ($object->fk_user_validator > 0) {
  1512. $userfee = new User($db);
  1513. $result = $userfee->fetch($object->fk_user_validator);
  1514. if ($result > 0) {
  1515. print $userfee->getNomUrl(-1);
  1516. }
  1517. if (empty($userfee->email) || !isValidEmail($userfee->email)) {
  1518. $langs->load("errors");
  1519. print img_warning($langs->trans("ErrorBadEMail", $userfee->email));
  1520. }
  1521. }
  1522. print '</td></tr>';
  1523. } elseif ($object->status == ExpenseReport::STATUS_CANCELED) {
  1524. print '<tr>';
  1525. print '<td>'.$langs->trans("CANCEL_USER").'</span></td>';
  1526. print '<td>';
  1527. if ($object->fk_user_cancel > 0) {
  1528. $userfee = new User($db);
  1529. $result = $userfee->fetch($object->fk_user_cancel);
  1530. if ($result > 0) {
  1531. print $userfee->getNomUrl(-1);
  1532. }
  1533. }
  1534. print '</td></tr>';
  1535. print '<tr>';
  1536. print '<td>'.$langs->trans("MOTIF_CANCEL").'</td>';
  1537. print '<td>'.$object->detail_cancel.'</td></tr>';
  1538. print '</tr>';
  1539. print '<tr>';
  1540. print '<td>'.$langs->trans("DATE_CANCEL").'</td>';
  1541. print '<td>'.dol_print_date($object->date_cancel, 'dayhour', 'tzuser').'</td></tr>';
  1542. print '</tr>';
  1543. } else {
  1544. print '<tr>';
  1545. print '<td>'.$langs->trans("ApprovedBy").'</td>';
  1546. print '<td>';
  1547. if ($object->fk_user_approve > 0) {
  1548. $userapp = new User($db);
  1549. $result = $userapp->fetch($object->fk_user_approve);
  1550. if ($result > 0) {
  1551. print $userapp->getNomUrl(-1);
  1552. }
  1553. }
  1554. print '</td></tr>';
  1555. print '<tr>';
  1556. print '<td>'.$langs->trans("DateApprove").'</td>';
  1557. print '<td>'.dol_print_date($object->date_approve, 'dayhour', 'tzuser').'</td></tr>';
  1558. print '</tr>';
  1559. }
  1560. if ($object->status == 99 || !empty($object->detail_refuse)) {
  1561. print '<tr>';
  1562. print '<td>'.$langs->trans("REFUSEUR").'</td>';
  1563. print '<td>';
  1564. $userfee = new User($db);
  1565. $result = $userfee->fetch($object->fk_user_refuse);
  1566. if ($result > 0) {
  1567. print $userfee->getNomUrl(-1);
  1568. }
  1569. print '</td></tr>';
  1570. print '<tr>';
  1571. print '<td>'.$langs->trans("DATE_REFUS").'</td>';
  1572. print '<td>'.dol_print_date($object->date_refuse, 'dayhour', 'tzuser');
  1573. if ($object->detail_refuse) {
  1574. print ' - '.$object->detail_refuse;
  1575. }
  1576. print '</td>';
  1577. print '</tr>';
  1578. }
  1579. if ($object->status == $object::STATUS_CLOSED) {
  1580. /* TODO this fields are not yet filled
  1581. print '<tr>';
  1582. print '<td>'.$langs->trans("AUTHORPAIEMENT").'</td>';
  1583. print '<td>';
  1584. $userfee=new User($db);
  1585. $userfee->fetch($object->fk_user_paid);
  1586. print $userfee->getNomUrl(-1);
  1587. print '</td></tr>';
  1588. print '<tr>';
  1589. print '<td>'.$langs->trans("DATE_PAIEMENT").'</td>';
  1590. print '<td>'.$object->date_paiement.'</td></tr>';
  1591. print '</tr>';
  1592. */
  1593. }
  1594. // Other attributes
  1595. $cols = 2;
  1596. include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php';
  1597. print '</table>';
  1598. print '</div>';
  1599. print '<div class="fichehalfright">';
  1600. print '<div class="underbanner clearboth"></div>';
  1601. print '<table class="border tableforfield centpercent">';
  1602. // Amount
  1603. print '<tr>';
  1604. print '<td class="titlefieldmiddle">'.$langs->trans("AmountHT").'</td>';
  1605. print '<td class="nowrap amountcard">'.price($object->total_ht, 1, '', 1, - 1, - 1, $conf->currency).'</td>';
  1606. $rowspan = 5;
  1607. if ($object->status <= ExpenseReport::STATUS_VALIDATED) {
  1608. $rowspan++;
  1609. } elseif ($object->status == ExpenseReport::STATUS_CANCELED) {
  1610. $rowspan += 2;
  1611. } else {
  1612. $rowspan += 2;
  1613. }
  1614. if ($object->status == ExpenseReport::STATUS_REFUSED || !empty($object->detail_refuse)) {
  1615. $rowspan += 2;
  1616. }
  1617. if ($object->status == ExpenseReport::STATUS_CLOSED) {
  1618. $rowspan += 2;
  1619. }
  1620. print "</td>";
  1621. print '</tr>';
  1622. print '<tr>';
  1623. print '<td>'.$langs->trans("AmountVAT").'</td>';
  1624. print '<td class="nowrap amountcard">'.price($object->total_tva, 1, '', 1, -1, -1, $conf->currency).'</td>';
  1625. print '</tr>';
  1626. // Amount Local Taxes
  1627. if ($mysoc->localtax1_assuj == "1" || $object->total_localtax1 != 0) { // Localtax1
  1628. print '<tr><td>'.$langs->transcountry("AmountLT1", $mysoc->country_code).'</td>';
  1629. print '<td class="valuefield">'.price($object->total_localtax1, 1, '', 1, -1, -1, $conf->currency).'</td></tr>';
  1630. }
  1631. if ($mysoc->localtax2_assuj == "1" || $object->total_localtax2 != 0) { // Localtax2 IRPF
  1632. print '<tr><td>'.$langs->transcountry("AmountLT2", $mysoc->country_code).'</td>';
  1633. print '<td class="valuefield">'.price($object->total_localtax2, 1, '', 1, -1, -1, $conf->currency).'</td></tr>';
  1634. }
  1635. print '<tr>';
  1636. print '<td>'.$langs->trans("AmountTTC").'</td>';
  1637. print '<td class="nowrap amountcard">'.price($object->total_ttc, 1, '', 1, -1, -1, $conf->currency).'</td>';
  1638. print '</tr>';
  1639. // List of payments already done
  1640. $nbcols = 3;
  1641. $nbrows = 0;
  1642. if (isModEnabled("banque")) {
  1643. $nbrows++;
  1644. $nbcols++;
  1645. }
  1646. print '<table class="noborder paymenttable centpercent">';
  1647. print '<tr class="liste_titre">';
  1648. print '<td class="liste_titre">'.$langs->trans('Payments').'</td>';
  1649. print '<td class="liste_titre">'.$langs->trans('Date').'</td>';
  1650. print '<td class="liste_titre">'.$langs->trans('Type').'</td>';
  1651. if (isModEnabled("banque")) {
  1652. print '<td class="liste_titre right">'.$langs->trans('BankAccount').'</td>';
  1653. }
  1654. print '<td class="liste_titre right">'.$langs->trans('Amount').'</td>';
  1655. print '<td class="liste_titre" width="18">&nbsp;</td>';
  1656. print '</tr>';
  1657. // Payments already done (from payment on this expensereport)
  1658. $sql = "SELECT p.rowid, p.num_payment, p.datep as dp, p.amount, p.fk_bank,";
  1659. $sql .= "c.code as payment_code, c.libelle as payment_type,";
  1660. $sql .= "ba.rowid as baid, ba.ref as baref, ba.label, ba.number as banumber, ba.account_number, ba.fk_accountancy_journal";
  1661. $sql .= " FROM ".MAIN_DB_PREFIX."expensereport as e, ".MAIN_DB_PREFIX."payment_expensereport as p";
  1662. $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_paiement as c ON p.fk_typepayment = c.id";
  1663. $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'bank as b ON p.fk_bank = b.rowid';
  1664. $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'bank_account as ba ON b.fk_account = ba.rowid';
  1665. $sql .= " WHERE e.rowid = ".((int) $id);
  1666. $sql .= " AND p.fk_expensereport = e.rowid";
  1667. $sql .= ' AND e.entity IN ('.getEntity('expensereport').')';
  1668. $sql .= " ORDER BY dp";
  1669. $resql = $db->query($sql);
  1670. if ($resql) {
  1671. $num = $db->num_rows($resql);
  1672. $i = 0;
  1673. $totalpaid = 0;
  1674. while ($i < $num) {
  1675. $objp = $db->fetch_object($resql);
  1676. $paymentexpensereportstatic->id = $objp->rowid;
  1677. $paymentexpensereportstatic->datep = $db->jdate($objp->dp);
  1678. $paymentexpensereportstatic->ref = $objp->rowid;
  1679. $paymentexpensereportstatic->num_payment = $objp->num_payment;
  1680. $paymentexpensereportstatic->type_code = $objp->payment_code;
  1681. $paymentexpensereportstatic->type_label = $objp->payment_type;
  1682. print '<tr class="oddseven">';
  1683. print '<td>';
  1684. print $paymentexpensereportstatic->getNomUrl(1);
  1685. print '</td>';
  1686. print '<td>'.dol_print_date($db->jdate($objp->dp), 'day')."</td>\n";
  1687. $labeltype = $langs->trans("PaymentType".$objp->payment_code) != "PaymentType".$objp->payment_code ? $langs->trans("PaymentType".$objp->payment_code) : $objp->payment_type;
  1688. print "<td>".$labeltype.' '.$objp->num_payment."</td>\n";
  1689. // Bank account
  1690. if (isModEnabled("banque")) {
  1691. $bankaccountstatic->id = $objp->baid;
  1692. $bankaccountstatic->ref = $objp->baref;
  1693. $bankaccountstatic->label = $objp->baref;
  1694. $bankaccountstatic->number = $objp->banumber;
  1695. if (isModEnabled('accounting')) {
  1696. $bankaccountstatic->account_number = $objp->account_number;
  1697. $accountingjournal = new AccountingJournal($db);
  1698. $accountingjournal->fetch($objp->fk_accountancy_journal);
  1699. $bankaccountstatic->accountancy_journal = $accountingjournal->getNomUrl(0, 1, 1, '', 1);
  1700. }
  1701. print '<td class="right">';
  1702. if ($bankaccountstatic->id) {
  1703. print $bankaccountstatic->getNomUrl(1, 'transactions');
  1704. }
  1705. print '</td>';
  1706. }
  1707. print '<td class="right">'.price($objp->amount)."</td>";
  1708. print '<td></td>';
  1709. print "</tr>";
  1710. $totalpaid += $objp->amount;
  1711. $i++;
  1712. }
  1713. if (!is_null($totalpaid)) {
  1714. $totalpaid = price2num($totalpaid); // Round $totalpaid to fix floating problem after addition into loop
  1715. }
  1716. $remaintopay = price2num($object->total_ttc - $totalpaid);
  1717. $resteapayeraffiche = $remaintopay;
  1718. $cssforamountpaymentcomplete = 'amountpaymentcomplete';
  1719. if ($object->status == ExpenseReport::STATUS_REFUSED) {
  1720. $cssforamountpaymentcomplete = 'amountpaymentneutral';
  1721. $resteapayeraffiche = 0;
  1722. } elseif ($object->paid == 0) {
  1723. $cssforamountpaymentcomplete = 'amountpaymentneutral';
  1724. }
  1725. print '<tr><td colspan="'.$nbcols.'" class="right">'.$langs->trans("AlreadyPaid").':</td><td class="right">'.price($totalpaid).'</td><td></td></tr>';
  1726. print '<tr><td colspan="'.$nbcols.'" class="right">'.$langs->trans("AmountExpected").':</td><td class="right">'.price($object->total_ttc).'</td><td></td></tr>';
  1727. print '<tr><td colspan="'.$nbcols.'" class="right">'.$langs->trans("RemainderToPay").':</td>';
  1728. print '<td class="right'.($resteapayeraffiche ? ' amountremaintopay' : (' '.$cssforamountpaymentcomplete)).'">'.price($resteapayeraffiche).'</td><td></td></tr>';
  1729. $db->free($resql);
  1730. } else {
  1731. dol_print_error($db);
  1732. }
  1733. print "</table>";
  1734. print '</div>';
  1735. print '</div>';
  1736. print '<div class="clearboth"></div><br>';
  1737. print '<div style="clear: both;"></div>';
  1738. $actiontouse = 'updateline';
  1739. if (($object->status == 0 || $object->status == 99) && $action != 'editline') {
  1740. $actiontouse = 'addline';
  1741. }
  1742. print '<form name="expensereport" action="'.$_SERVER["PHP_SELF"].'" enctype="multipart/form-data" method="post" >';
  1743. print '<input type="hidden" name="token" value="'.newToken().'">';
  1744. print '<input type="hidden" name="action" value="'.$actiontouse.'">';
  1745. print '<input type="hidden" name="id" value="'.$object->id.'">';
  1746. print '<input type="hidden" name="fk_expensereport" value="'.$object->id.'" />';
  1747. print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
  1748. print '<input type="hidden" name="page_y" value="">';
  1749. print '<div class="div-table-responsive-no-min">';
  1750. print '<table id="tablelines" class="noborder centpercent">';
  1751. if (!empty($object->lines)) {
  1752. $i = 0;
  1753. $total = 0;
  1754. print '<tr class="liste_titre headerexpensereportdet">';
  1755. print '<td class="center linecollinenb">'.$langs->trans('LineNb').'</td>';
  1756. //print '<td class="center">'.$langs->trans('Piece').'</td>';
  1757. print '<td class="center linecoldate">'.$langs->trans('Date').'</td>';
  1758. if (isModEnabled('project')) {
  1759. print '<td class="minwidth100imp linecolproject">'.$langs->trans('Project').'</td>';
  1760. }
  1761. print '<td class="center linecoltype">'.$langs->trans('Type').'</td>';
  1762. if (getDolGlobalString('MAIN_USE_EXPENSE_IK')) {
  1763. print '<td class="center linecolcarcategory">'.$langs->trans('CarCategory').'</td>';
  1764. }
  1765. print '<td class="linecoldescription">'.$langs->trans('Description').'</td>';
  1766. print '<td class="right linecolvat">'.$langs->trans('VAT').'</td>';
  1767. print '<td class="right linecolpriceuht">'.$langs->trans('PriceUHT').'</td>';
  1768. print '<td class="right linecolpriceuttc">'.$langs->trans('PriceUTTC').'</td>';
  1769. print '<td class="right linecolqty">'.$langs->trans('Qty').'</td>';
  1770. if ($action != 'editline') {
  1771. print '<td class="right linecolamountht">'.$langs->trans('AmountHT').'</td>';
  1772. print '<td class="right linecolamountttc">'.$langs->trans('AmountTTC').'</td>';
  1773. }
  1774. // Picture
  1775. print '<td>';
  1776. print '</td>';
  1777. // Information if theres a rule restriction
  1778. print '<td>';
  1779. print '</td>';
  1780. // Ajout des boutons de modification/suppression
  1781. if (($object->status < 2 || $object->status == 99) && $user->hasRight('expensereport', 'creer')) {
  1782. print '<td class="right"></td>';
  1783. }
  1784. print '</tr>';
  1785. foreach ($object->lines as &$line) {
  1786. $numline = $i + 1;
  1787. if ($action != 'editline' || $line->id != GETPOST('rowid', 'int')) {
  1788. print '<tr class="oddeven linetr" data-id="'.$line->id.'">';
  1789. // Num
  1790. print '<td class="center linecollinenb">';
  1791. print $numline;
  1792. print '</td>';
  1793. // Date
  1794. print '<td class="center linecoldate">'.dol_print_date($db->jdate($line->date), 'day').'</td>';
  1795. // Project
  1796. if (isModEnabled('project')) {
  1797. print '<td class="lineproject">';
  1798. if ($line->fk_project > 0) {
  1799. $projecttmp->id = $line->fk_project;
  1800. $projecttmp->ref = $line->projet_ref;
  1801. $projecttmp->title = $line->projet_title;
  1802. print $projecttmp->getNomUrl(1);
  1803. }
  1804. print '</td>';
  1805. }
  1806. $titlealt = '';
  1807. if (isModEnabled('accounting')) {
  1808. require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingaccount.class.php';
  1809. $accountingaccount = new AccountingAccount($db);
  1810. $resaccountingaccount = $accountingaccount->fetch(0, $line->type_fees_accountancy_code, 1);
  1811. //$titlealt .= '<span class="opacitymedium">';
  1812. $titlealt .= $langs->trans("AccountancyCode").': ';
  1813. if ($resaccountingaccount > 0) {
  1814. $titlealt .= $accountingaccount->account_number;
  1815. } else {
  1816. $titlealt .= $langs->trans("NotFound");
  1817. }
  1818. //$titlealt .= '</span>';
  1819. }
  1820. // Type of fee
  1821. print '<td class="center linecoltype" title="'.dol_escape_htmltag($titlealt).'">';
  1822. $labeltype = ($langs->trans(($line->type_fees_code)) == $line->type_fees_code ? $line->type_fees_libelle : $langs->trans($line->type_fees_code));
  1823. print $labeltype;
  1824. print '</td>';
  1825. // IK
  1826. if (getDolGlobalString('MAIN_USE_EXPENSE_IK')) {
  1827. print '<td class="fk_c_exp_tax_cat linecoltaxcat">';
  1828. $exp_tax_cat_label = dol_getIdFromCode($db, $line->fk_c_exp_tax_cat, 'c_exp_tax_cat', 'rowid', 'label');
  1829. print $langs->trans($exp_tax_cat_label);
  1830. print '</td>';
  1831. }
  1832. // Comment
  1833. print '<td class="left linecolcomment">'.dol_nl2br($line->comments).'</td>';
  1834. // VAT rate
  1835. print '<td class="right linecolvatrate">'.vatrate($line->vatrate.($line->vat_src_code ? ' ('.$line->vat_src_code.')' : ''), true).'</td>';
  1836. // Unit price HT
  1837. print '<td class="right linecolunitht">';
  1838. if (!empty($line->value_unit_ht)) {
  1839. print price($line->value_unit_ht);
  1840. } else {
  1841. $tmpvat = price2num(preg_replace('/\s*\(.*\)/', '', $line->vatrate));
  1842. $pricenettoshow = price2num($line->value_unit / (1 + $tmpvat / 100), 'MU');
  1843. print price($pricenettoshow);
  1844. }
  1845. print '</td>';
  1846. print '<td class="right linecolunitttc">'.price($line->value_unit).'</td>';
  1847. print '<td class="right linecolqty">'.dol_escape_htmltag($line->qty).'</td>';
  1848. if ($action != 'editline') {
  1849. print '<td class="right linecoltotalht">'.price($line->total_ht).'</td>';
  1850. print '<td class="right linecoltotalttc">'.price($line->total_ttc).'</td>';
  1851. }
  1852. // Column with preview
  1853. print '<td class="center linecolpreview">';
  1854. if ($line->fk_ecm_files > 0) {
  1855. $modulepart = 'expensereport';
  1856. $maxheightmini = 32;
  1857. $result = $ecmfilesstatic->fetch($line->fk_ecm_files);
  1858. if ($result > 0) {
  1859. $relativepath = preg_replace('/expensereport\//', '', $ecmfilesstatic->filepath);
  1860. $fileinfo = pathinfo($ecmfilesstatic->filepath.'/'.$ecmfilesstatic->filename);
  1861. if (image_format_supported($fileinfo['basename']) > 0) {
  1862. $minifile = getImageFileNameForSize($fileinfo['basename'], '_mini'); // For new thumbs using same ext (in lower case howerver) than original
  1863. if (!dol_is_file($conf->expensereport->dir_output.'/'.$relativepath.'/'.$minifile)) {
  1864. $minifile = getImageFileNameForSize($fileinfo['basename'], '_mini', '.png'); // For backward compatibility of old thumbs that were created with filename in lower case and with .png extension
  1865. }
  1866. //print $file['path'].'/'.$minifile.'<br>';
  1867. $urlforhref = getAdvancedPreviewUrl($modulepart, $relativepath.'/'.$fileinfo['filename'].'.'.strtolower($fileinfo['extension']), 1, '&entity='.(empty($object->entity) ? $conf->entity : $object->entity));
  1868. if (empty($urlforhref)) {
  1869. $urlforhref = DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.(empty($object->entity) ? $conf->entity : $object->entity).'&file='.urlencode($relativepath.$fileinfo['filename'].'.'.strtolower($fileinfo['extension']));
  1870. print '<a href="'.$urlforhref.'" class="aphoto" target="_blank" rel="noopener noreferrer">';
  1871. } else {
  1872. print '<a href="'.$urlforhref['url'].'" class="'.$urlforhref['css'].'" target="'.$urlforhref['target'].'" mime="'.$urlforhref['mime'].'">';
  1873. }
  1874. print '<img class="photo" height="'.$maxheightmini.'" src="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.(empty($object->entity) ? $conf->entity : $object->entity).'&file='.urlencode($relativepath.'/'.$minifile).'" title="">';
  1875. print '</a>';
  1876. } else {
  1877. $modulepart = 'expensereport';
  1878. $thumbshown = 0;
  1879. if (preg_match('/\.pdf$/i', $ecmfilesstatic->filename)) {
  1880. $filepdf = $conf->expensereport->dir_output.'/'.$relativepath.'/'.$ecmfilesstatic->filename;
  1881. $fileimage = $conf->expensereport->dir_output.'/'.$relativepath.'/'.$ecmfilesstatic->filename.'_preview.png';
  1882. $relativepathimage = $relativepath.'/'.$ecmfilesstatic->filename.'_preview.png';
  1883. $pdfexists = file_exists($filepdf);
  1884. if ($pdfexists) {
  1885. // Conversion du PDF en image png si fichier png non existant
  1886. if (!file_exists($fileimage) || (filemtime($fileimage) < filemtime($filepdf))) {
  1887. if (!getDolGlobalString('MAIN_DISABLE_PDF_THUMBS')) { // If you experience trouble with pdf thumb generation and imagick, you can disable here.
  1888. include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
  1889. $ret = dol_convert_file($filepdf, 'png', $fileimage, '0'); // Convert first page of PDF into a file _preview.png
  1890. if ($ret < 0) {
  1891. $error++;
  1892. }
  1893. }
  1894. }
  1895. }
  1896. if ($pdfexists && !$error) {
  1897. $heightforphotref = 70;
  1898. if (!empty($conf->dol_optimize_smallscreen)) {
  1899. $heightforphotref = 60;
  1900. }
  1901. // If the preview file is found
  1902. if (file_exists($fileimage)) {
  1903. $thumbshown = 1;
  1904. $urlforhref = getAdvancedPreviewUrl($modulepart, $relativepath.'/'.$fileinfo['filename'].'.'.strtolower($fileinfo['extension']), 1, '&entity='.(empty($object->entity) ? $conf->entity : $object->entity));
  1905. print '<a href="'.$urlforhref['url'].'" class="'.$urlforhref['css'].'" target="'.$urlforhref['target'].'" mime="'.$urlforhref['mime'].'">';
  1906. print '<img height="'.$heightforphotref.'" class="photo photowithmargin photowithborder" src="'.DOL_URL_ROOT.'/viewimage.php?modulepart=apercu'.$modulepart.'&amp;file='.urlencode($relativepathimage).'">';
  1907. print '</a>';
  1908. }
  1909. }
  1910. }
  1911. if (!$thumbshown) {
  1912. print img_mime($ecmfilesstatic->filename);
  1913. }
  1914. }
  1915. }
  1916. }
  1917. print '</td>';
  1918. print '<td class="nowrap right linecolwarning">';
  1919. print !empty($line->rule_warning_message) ? img_warning(html_entity_decode($line->rule_warning_message)) : '&nbsp;';
  1920. print '</td>';
  1921. // Ajout des boutons de modification/suppression
  1922. if (($object->status < ExpenseReport::STATUS_VALIDATED || $object->status == ExpenseReport::STATUS_REFUSED) && $user->hasRight('expensereport', 'creer')) {
  1923. print '<td class="nowrap right linecolaction">';
  1924. print '<a class="editfielda reposition paddingrightonly" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=editline&token='.newToken().'&rowid='.$line->rowid.'">';
  1925. print img_edit();
  1926. print '</a> &nbsp; ';
  1927. print '<a class="paddingrightonly" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=delete_line&token='.newToken().'&rowid='.$line->rowid.'">';
  1928. print img_delete();
  1929. print '</a>';
  1930. print '</td>';
  1931. }
  1932. print '</tr>';
  1933. }
  1934. if ($action == 'editline' && $line->id == GETPOST('rowid', 'int')) {
  1935. // Add line with link to add new file or attach line to an existing file
  1936. $colspan = 11;
  1937. if (isModEnabled('project')) {
  1938. $colspan++;
  1939. }
  1940. if (getDolGlobalString('MAIN_USE_EXPENSE_IK')) {
  1941. $colspan++;
  1942. }
  1943. print '<!-- line of expense report -->'."\n";
  1944. print '<tr class="tredited">';
  1945. print '<td class="center">';
  1946. print $numline;
  1947. print '</td>';
  1948. print '<td colspan="'.($colspan - 1).'" class="liste_titre"> ';
  1949. print '<a href="" class="commonlink auploadnewfilenow reposition">'.$langs->trans("UploadANewFileNow");
  1950. print img_picto($langs->trans("UploadANewFileNow"), 'chevron-down', '', false, 0, 0, '', 'marginleftonly');
  1951. print '</a>';
  1952. if (!getDolGlobalString('EXPENSEREPORT_DISABLE_ATTACHMENT_ON_LINES')) {
  1953. print ' &nbsp; - &nbsp; <a href="" class="commonlink aattachtodoc reposition">'.$langs->trans("AttachTheNewLineToTheDocument");
  1954. print img_picto($langs->trans("AttachTheNewLineToTheDocument"), 'chevron-down', '', false, 0, 0, '', 'marginleftonly');
  1955. print '</a>';
  1956. }
  1957. print '<!-- Code to open/close section to submit or link files in edit mode -->'."\n";
  1958. print '<script type="text/javascript">'."\n";
  1959. print '$(document).ready(function() {
  1960. $( ".auploadnewfilenow" ).click(function() {
  1961. jQuery(".truploadnewfilenow").toggle();
  1962. jQuery(".trattachnewfilenow").hide();
  1963. return false;
  1964. });
  1965. $( ".aattachtodoc" ).click(function() {
  1966. jQuery(".trattachnewfilenow").toggle();
  1967. jQuery(".truploadnewfilenow").hide();
  1968. return false;
  1969. });';
  1970. if (is_array(GETPOST('attachfile', 'array')) && count(GETPOST('attachfile', 'array'))) {
  1971. print 'jQuery(".trattachnewfilenow").toggle();'."\n";
  1972. }
  1973. print '
  1974. jQuery("form[name=\"expensereport\"]").submit(function() {
  1975. if (jQuery(".truploadnewfilenow").is(":hidden")) {
  1976. jQuery("input[name=\"sendit\"]").val("");
  1977. }
  1978. });
  1979. ';
  1980. print '
  1981. });
  1982. ';
  1983. print '</script>'."\n";
  1984. print '</td></tr>';
  1985. $filenamelinked = '';
  1986. if ($line->fk_ecm_files > 0) {
  1987. $result = $ecmfilesstatic->fetch($line->fk_ecm_files);
  1988. if ($result > 0) {
  1989. $filenamelinked = $ecmfilesstatic->filename;
  1990. }
  1991. }
  1992. $tredited = 'tredited'; // Case the addfile and linkto file is used for edit (used by following tpl)
  1993. include DOL_DOCUMENT_ROOT.'/expensereport/tpl/expensereport_addfile.tpl.php';
  1994. include DOL_DOCUMENT_ROOT.'/expensereport/tpl/expensereport_linktofile.tpl.php';
  1995. print '<tr class="oddeven tredited">';
  1996. print '<td></td>';
  1997. // Select date
  1998. print '<td class="center">';
  1999. print $form->selectDate($line->date, 'date');
  2000. print '</td>';
  2001. // Select project
  2002. if (isModEnabled('project')) {
  2003. print '<td>';
  2004. $formproject->select_projects(-1, $line->fk_project, 'fk_project', 0, 0, $projectRequired ? 0 : 1, 1, 0, 0, 0, '', 0, 0, 'maxwidth300');
  2005. print '</td>';
  2006. }
  2007. // Select type
  2008. print '<td class="center">';
  2009. print $formexpensereport->selectTypeExpenseReport($line->fk_c_type_fees, 'fk_c_type_fees');
  2010. print '</td>';
  2011. if (getDolGlobalString('MAIN_USE_EXPENSE_IK')) {
  2012. print '<td class="fk_c_exp_tax_cat">';
  2013. $params = array('fk_expense' => $object->id, 'fk_expense_det' => $line->id, 'date' => $line->date);
  2014. print $form->selectExpenseCategories($line->fk_c_exp_tax_cat, 'fk_c_exp_tax_cat', 1, array(), 'fk_c_type_fees', $userauthor->default_c_exp_tax_cat, $params);
  2015. print '</td>';
  2016. }
  2017. // Add comments
  2018. print '<td>';
  2019. print '<textarea name="comments" class="flat_ndf centpercent">'.dol_escape_htmltag($line->comments, 0, 1).'</textarea>';
  2020. print '</td>';
  2021. // VAT
  2022. $selectedvat = price2num($line->vatrate).(!empty($line->vat_src_code) ? ' ('.$line->vat_src_code.')' : '');
  2023. print '<td class="right">';
  2024. print $form->load_tva('vatrate', (GETPOSTISSET("vatrate") ? GETPOST("vatrate") : $selectedvat), $mysoc, '', 0, 0, '', false, 1);
  2025. print '</td>';
  2026. // Unit price
  2027. print '<td class="right">';
  2028. print '<input type="text" min="0" class="right maxwidth50" id="value_unit_ht" name="value_unit_ht" value="'.dol_escape_htmltag(price2num((!empty($line->value_unit_ht) ? $line->value_unit_ht : ""))).'"'.$taxlessUnitPriceDisabled.' />';
  2029. print '</td>';
  2030. // Unit price with tax
  2031. print '<td class="right">';
  2032. print '<input type="text" min="0" class="right maxwidth50" id="value_unit" name="value_unit" value="'.dol_escape_htmltag(price2num($line->value_unit)).'" />';
  2033. print '</td>';
  2034. // Quantity
  2035. print '<td class="right">';
  2036. print '<input type="text" min="0" class="input_qty right maxwidth50" name="qty" value="'.dol_escape_htmltag($line->qty).'" />'; // We must be able to enter decimal qty
  2037. print '</td>';
  2038. //print '<td class="right">'.$langs->trans('AmountHT').'</td>';
  2039. //print '<td class="right">'.$langs->trans('AmountTTC').'</td>';
  2040. // Picture
  2041. print '<td class="center">';
  2042. //print $line->fk_ecm_files;
  2043. print '</td>';
  2044. // Information if theres a rule restriction
  2045. print '<td class="center">';
  2046. print '</td>';
  2047. print '<td>';
  2048. print '<input type="hidden" name="rowid" value="'.$line->rowid.'">';
  2049. print $form->buttonsSaveCancel('Save', 'Cancel', array(), 0, 'small');
  2050. print '</td>';
  2051. print '</tr>';
  2052. }
  2053. $i++;
  2054. }
  2055. }
  2056. // Add a new line
  2057. if (($object->status == ExpenseReport::STATUS_DRAFT || $object->status == ExpenseReport::STATUS_REFUSED) && $action != 'editline' && $user->hasRight('expensereport', 'creer')) {
  2058. $colspan = 12;
  2059. if (getDolGlobalString('MAIN_USE_EXPENSE_IK')) {
  2060. $colspan++;
  2061. }
  2062. if (isModEnabled('project')) {
  2063. $colspan++;
  2064. }
  2065. if ($action != 'editline') {
  2066. $colspan++;
  2067. }
  2068. $nbFiles = $nbLinks = 0;
  2069. $arrayoffiles = array();
  2070. if (!getDolGlobalString('EXPENSEREPORT_DISABLE_ATTACHMENT_ON_LINES')) {
  2071. require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
  2072. require_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php';
  2073. require_once DOL_DOCUMENT_ROOT.'/core/class/link.class.php';
  2074. $upload_dir = $conf->expensereport->dir_output."/".dol_sanitizeFileName($object->ref);
  2075. $arrayoffiles = dol_dir_list($upload_dir, 'files', 0, '', '(\.meta|_preview.*\.png|'.preg_quote(dol_sanitizeFileName($object->ref.'.pdf'), '/').')$');
  2076. $nbFiles = count($arrayoffiles);
  2077. $nbLinks = Link::count($db, $object->element, $object->id);
  2078. }
  2079. // Add line with link to add new file or attach to an existing file
  2080. print '<tr class="liste_titre">';
  2081. print '<td colspan="'.$colspan.'" class="liste_titre expensereportautoload">';
  2082. print '<a href="" class="commonlink auploadnewfilenow reposition">'.$langs->trans("UploadANewFileNow");
  2083. print img_picto($langs->trans("UploadANewFileNow"), 'chevron-down', '', false, 0, 0, '', 'marginleftonly');
  2084. print '</a>';
  2085. if (!getDolGlobalString('EXPENSEREPORT_DISABLE_ATTACHMENT_ON_LINES')) {
  2086. print ' &nbsp; - &nbsp; <a href="" class="commonlink aattachtodoc reposition">'.$langs->trans("AttachTheNewLineToTheDocument");
  2087. print img_picto($langs->trans("AttachTheNewLineToTheDocument"), 'chevron-down', '', false, 0, 0, '', 'marginleftonly');
  2088. print '</a>';
  2089. }
  2090. print '<!-- Code to open/close section to submit or link files in the form to add new line -->'."\n";
  2091. print '<script type="text/javascript">'."\n";
  2092. print '$(document).ready(function() {
  2093. $( ".auploadnewfilenow" ).click(function() {
  2094. console.log("We click on toggle of auploadnewfilenow");
  2095. jQuery(".truploadnewfilenow").toggle();
  2096. jQuery(".trattachnewfilenow").hide();
  2097. if (jQuery(".truploadnewfilenow").is(":hidden")) {
  2098. jQuery("input[name=\"sendit\"]").prop("name", "senditdisabled");
  2099. } else {
  2100. jQuery("input[name=\"senditdisabled\"]").prop("name", "sendit");
  2101. }
  2102. // TODO Switch css fa-chevron-dow and add fa-chevron-up
  2103. return false;
  2104. });
  2105. $( ".aattachtodoc" ).click(function() {
  2106. console.log("We click on toggle of aattachtodoc");
  2107. jQuery(".trattachnewfilenow").toggle();
  2108. jQuery(".truploadnewfilenow").hide();
  2109. // TODO Switch css fa-chevron-dow and add fa-chevron-up
  2110. return false;
  2111. });'."\n";
  2112. if (is_array(GETPOST('attachfile', 'array')) && count(GETPOST('attachfile', 'array')) && $action != 'updateline') {
  2113. print 'jQuery(".trattachnewfilenow").show();'."\n";
  2114. }
  2115. print '
  2116. jQuery("form[name=\"expensereport\"]").submit(function() {
  2117. if (jQuery(".truploadnewfilenow").is(":hidden")) {
  2118. /* When section to send file is not expanded, we disable the button sendit that submit form to add a new file, so button to submit line will work. */
  2119. jQuery("input[name=\"sendit\"]").val("");
  2120. jQuery("input[name=\"sendit\"]").prop("name", "senditdisabled");
  2121. } else {
  2122. jQuery("input[name=\"senditdisabled\"]").prop("name", "sendit");
  2123. }
  2124. });
  2125. ';
  2126. print '
  2127. });
  2128. ';
  2129. print '</script>'."\n";
  2130. print '</td></tr>';
  2131. $tredited = ''; // Case the addfile and linkto file is used for edit (used by following tpl)
  2132. include DOL_DOCUMENT_ROOT.'/expensereport/tpl/expensereport_linktofile.tpl.php';
  2133. include DOL_DOCUMENT_ROOT.'/expensereport/tpl/expensereport_addfile.tpl.php';
  2134. print '<tr class="liste_titre expensereportcreate">';
  2135. print '<td></td>';
  2136. print '<td class="center expensereportcreatedate">'.$langs->trans('Date').'</td>';
  2137. if (isModEnabled('project')) {
  2138. print '<td class="minwidth100imp">'.$form->textwithpicto($langs->trans('Project'), $langs->trans("ClosedProjectsAreHidden")).'</td>';
  2139. }
  2140. print '<td class="center expensereportcreatetype">'.$langs->trans('Type').'</td>';
  2141. if (getDolGlobalString('MAIN_USE_EXPENSE_IK')) {
  2142. print '<td>'.$langs->trans('CarCategory').'</td>';
  2143. }
  2144. print '<td class="expensereportcreatedescription">'.$langs->trans('Description').'</td>';
  2145. print '<td class="right expensereportcreatevat">'.$langs->trans('VAT').'</td>';
  2146. print '<td class="right expensereportcreatepriceuth">'.$langs->trans('PriceUHT').'</td>';
  2147. print '<td class="right expensereportcreatepricettc">'.$langs->trans('PriceUTTC').'</td>';
  2148. print '<td class="right expensereportcreateqty">'.$langs->trans('Qty').'</td>';
  2149. print '<td></td>';
  2150. print '<td></td>';
  2151. print '<td></td>';
  2152. print '<td></td>';
  2153. print '<td></td>';
  2154. print '</tr>';
  2155. print '<tr class="oddeven nohover">';
  2156. // Line number
  2157. print '<td></td>';
  2158. // Select date
  2159. print '<td class="center inputdate">';
  2160. print $form->selectDate(!empty($date) ? $date : -1, 'date', 0, 0, 0, '', 1, 1);
  2161. print '</td>';
  2162. // Select project
  2163. if (isModEnabled('project')) {
  2164. print '<td class="inputproject">';
  2165. $formproject->select_projects(-1, !empty($fk_project) ? $fk_project : 0, 'fk_project', 0, 0, $projectRequired ? 0 : 1, -1, 0, 0, 0, '', 0, 0, 'maxwidth300');
  2166. print '</td>';
  2167. }
  2168. // Select type
  2169. print '<td class="center inputtype">';
  2170. print $formexpensereport->selectTypeExpenseReport(!empty($fk_c_type_fees) ? $fk_c_type_fees : "", 'fk_c_type_fees', 1);
  2171. print '</td>';
  2172. if (getDolGlobalString('MAIN_USE_EXPENSE_IK')) {
  2173. print '<td class="fk_c_exp_tax_cat">';
  2174. $params = array('fk_expense' => $object->id);
  2175. print $form->selectExpenseCategories('', 'fk_c_exp_tax_cat', 1, array(), 'fk_c_type_fees', $userauthor->default_c_exp_tax_cat, $params, 0);
  2176. print '</td>';
  2177. }
  2178. // Add comments
  2179. print '<td class="inputcomment">';
  2180. print '<textarea class="flat_ndf centpercent" name="comments" rows="'.ROWS_2.'">'.dol_escape_htmltag(!empty($comments) ? $comments : "", 0, 1).'</textarea>';
  2181. print '</td>';
  2182. // Select VAT
  2183. print '<td class="right inputvat">';
  2184. $defaultvat = -1;
  2185. if (getDolGlobalString('EXPENSEREPORT_NO_DEFAULT_VAT')) {
  2186. // If option to have no default VAT on expense report is on, we force MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS
  2187. $conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS = 'none';
  2188. }
  2189. print $form->load_tva('vatrate', (!empty($vatrate) ? $vatrate : $defaultvat), $mysoc, '', 0, 0, '', false, 1);
  2190. print '</td>';
  2191. // Unit price net
  2192. print '<td class="right inputpricenet">';
  2193. print '<input type="text" class="right maxwidth50" id="value_unit_ht" name="value_unit_ht" value="'.dol_escape_htmltag((!empty($value_unit_ht) ? $value_unit_ht : 0)).'"'.$taxlessUnitPriceDisabled.' />';
  2194. print '</td>';
  2195. // Unit price with tax
  2196. print '<td class="right inputtax">';
  2197. print '<input type="text" class="right maxwidth50" id="value_unit" name="value_unit" value="'.dol_escape_htmltag((!empty($value_unit) ? $value_unit : 0)).'">';
  2198. print '</td>';
  2199. // Quantity
  2200. print '<td class="right inputqty">';
  2201. print '<input type="text" min="0" class=" input_qty right maxwidth50" name="qty" value="'.dol_escape_htmltag(!empty($qty) ? $qty : 1).'">'; // We must be able to enter decimal qty
  2202. print '</td>';
  2203. // Picture
  2204. print '<td></td>';
  2205. if ($action != 'editline') {
  2206. print '<td class="right"></td>';
  2207. print '<td class="right"></td>';
  2208. }
  2209. print '<td class="center inputbuttons">';
  2210. print $form->buttonsSaveCancel("Add", '', '', 1, 'reposition');
  2211. print '</td>';
  2212. print '</tr>';
  2213. } // Fin si c'est payé/validé
  2214. print '</table>';
  2215. print '</div>';
  2216. print '<script>
  2217. /* JQuery for product free or predefined select */
  2218. jQuery(document).ready(function() {
  2219. jQuery("#value_unit_ht").keyup(function(event) {
  2220. console.log(event.which); // discard event tag and arrows
  2221. if (event.which != 9 && (event.which < 37 ||event.which > 40) && jQuery("#value_unit_ht").val() != "") {
  2222. jQuery("#value_unit").val("");
  2223. }
  2224. });
  2225. jQuery("#value_unit").keyup(function(event) {
  2226. console.log(event.which); // discard event tag and arrows
  2227. if (event.which != 9 && (event.which < 37 || event.which > 40) && jQuery("#value_unit").val() != "") {
  2228. jQuery("#value_unit_ht").val("");
  2229. }
  2230. });
  2231. ';
  2232. if (getDolGlobalString('MAIN_USE_EXPENSE_IK')) {
  2233. print '
  2234. /* unit price coef calculation */
  2235. jQuery(".input_qty, #fk_c_type_fees, #select_fk_c_exp_tax_cat, #vatrate ").change(function(event) {
  2236. console.log("We change a parameter");
  2237. let type_fee = jQuery("#fk_c_type_fees").find(":selected").val();
  2238. let tax_cat = jQuery("#select_fk_c_exp_tax_cat").find(":selected").val();
  2239. let tva = jQuery("#vatrate").find(":selected").val();
  2240. let qty = jQuery(".input_qty").val();
  2241. let path = "'.DOL_DOCUMENT_ROOT.'/expensereport/ajax/ajaxik.php";
  2242. path += "?fk_c_exp_tax_cat="+tax_cat;
  2243. path += "&fk_expense="+'.((int) $object->id).';
  2244. path += "&vatrate="+tva;
  2245. path += "&qty="+qty;
  2246. if (type_fee == 4) { // frais_kilométriques
  2247. if (tax_cat == "" || parseInt(tax_cat) <= 0){
  2248. return ;
  2249. }
  2250. jQuery.ajax({
  2251. url: path,
  2252. async: true,
  2253. dataType: "json",
  2254. success: function(response) {
  2255. if (response.response_status == "success"){';
  2256. if (getDolGlobalString('EXPENSEREPORT_FORCE_LINE_AMOUNTS_INCLUDING_TAXES_ONLY')) {
  2257. print '
  2258. jQuery("#value_unit").val(parseFloat(response.data) * (100 + parseFloat(tva)) / 100);
  2259. jQuery("#value_unit").trigger("change");
  2260. ';
  2261. } else {
  2262. print '
  2263. jQuery("#value_unit_ht").val(response.data);
  2264. jQuery("#value_unit_ht").trigger("change");
  2265. jQuery("#value_unit").val("");
  2266. ';
  2267. }
  2268. print '
  2269. } else if(response.response_status == "error" && response.errorMessage != undefined && response.errorMessage.length > 0 ) {
  2270. console.log("We get an error result");
  2271. $.jnotify(response.errorMessage, "error", {timeout: 0, type: "error"},{ remove: function (){} } );
  2272. }
  2273. }
  2274. });
  2275. }
  2276. /*console.log(event.which); // discard event tag and arrows
  2277. if (event.which != 9 && (event.which < 37 || event.which > 40) && jQuery("#value_unit").val() != "") {
  2278. jQuery("#value_unit_ht").val("");
  2279. }*/
  2280. });
  2281. ';
  2282. }
  2283. print '
  2284. });
  2285. </script>';
  2286. print '</form>';
  2287. print dol_get_fiche_end();
  2288. }
  2289. } else {
  2290. dol_print_error($db);
  2291. }
  2292. } else {
  2293. print 'Record not found';
  2294. llxFooter();
  2295. exit(1);
  2296. }
  2297. /*
  2298. * Action bar
  2299. */
  2300. print '<div class="tabsAction">';
  2301. if ($action != 'create' && $action != 'edit' && $action != 'editline') {
  2302. $object = new ExpenseReport($db);
  2303. $object->fetch($id, $ref);
  2304. // Send
  2305. if (empty($user->socid)) {
  2306. if ($object->status > ExpenseReport::STATUS_DRAFT) {
  2307. //if ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) || $user->rights->expensereport->expensereport_advance->send)) {
  2308. print '<div class="inline-block divButAction"><a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=presend&mode=init#formmailbeforetitle">'.$langs->trans('SendMail').'</a></div>';
  2309. //} else
  2310. // print '<div class="inline-block divButAction"><a class="butActionRefused classfortooltip" href="#">' . $langs->trans('SendMail') . '</a></div>';
  2311. }
  2312. }
  2313. /* Si l'état est "Brouillon"
  2314. * ET user à droit "creer/supprimer"
  2315. * ET fk_user_author == user courant
  2316. * Afficher : "Enregistrer" / "Modifier" / "Supprimer"
  2317. */
  2318. if ($user->hasRight('expensereport', 'creer') && $object->status == ExpenseReport::STATUS_DRAFT) {
  2319. if (in_array($object->fk_user_author, $user->getAllChildIds(1)) || $user->hasRight('expensereport', 'writeall_advance')) {
  2320. // Modify
  2321. print '<div class="inline-block divButAction"><a class="butAction" href="'.$_SERVER["PHP_SELF"].'?action=edit&token='.newToken().'&id='.$object->id.'">'.$langs->trans('Modify').'</a></div>';
  2322. // Validate
  2323. if (count($object->lines) > 0) {
  2324. print '<div class="inline-block divButAction"><a class="butAction" href="'.$_SERVER["PHP_SELF"].'?action=save&token='.newToken().'&id='.$object->id.'">'.$langs->trans('ValidateAndSubmit').'</a></div>';
  2325. }
  2326. }
  2327. }
  2328. /* Si l'état est "Refusée"
  2329. * ET user à droit "creer/supprimer"
  2330. * ET fk_user_author == user courant
  2331. * Afficher : "Enregistrer" / "Modifier" / "Supprimer"
  2332. */
  2333. if ($user->hasRight('expensereport', 'creer') && $object->status == ExpenseReport::STATUS_REFUSED) {
  2334. if ($user->id == $object->fk_user_author || $user->id == $object->fk_user_valid) {
  2335. // Modify
  2336. print '<div class="inline-block divButAction"><a class="butAction" href="'.$_SERVER["PHP_SELF"].'?action=edit&token='.newToken().'&id='.$object->id.'">'.$langs->trans('Modify').'</a></div>';
  2337. // setdraft (le statut refusée est identique à brouillon)
  2338. //print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?action=brouillonner&id='.$id.'">'.$langs->trans('ReOpen').'</a>';
  2339. // Enregistrer depuis le statut "Refusée"
  2340. print '<div class="inline-block divButAction"><a class="butAction" href="'.$_SERVER["PHP_SELF"].'?action=save_from_refuse&token='.newToken().'&id='.$object->id.'">'.$langs->trans('ValidateAndSubmit').'</a></div>';
  2341. }
  2342. }
  2343. if ($user->hasRight('expensereport', 'to_paid') && $object->status == ExpenseReport::STATUS_APPROVED) {
  2344. if ($user->id == $object->fk_user_author || $user->id == $object->fk_user_valid) {
  2345. // setdraft
  2346. print '<div class="inline-block divButAction"><a class="butAction" href="'.$_SERVER["PHP_SELF"].'?action=setdraft&token='.newToken().'&id='.$object->id.'">'.$langs->trans('SetToDraft').'</a></div>';
  2347. }
  2348. }
  2349. /* Si l'état est "En attente d'approbation"
  2350. * ET user à droit de "approve"
  2351. * ET fk_user_validator == user courant
  2352. * Afficher : "Valider" / "Refuser" / "Supprimer"
  2353. */
  2354. if ($object->status == ExpenseReport::STATUS_VALIDATED) {
  2355. if (in_array($object->fk_user_author, $user->getAllChildIds(1))) {
  2356. // set draft
  2357. print '<div class="inline-block divButAction"><a class="butAction" href="'.$_SERVER["PHP_SELF"].'?action=setdraft&token='.newToken().'&id='.$object->id.'">'.$langs->trans('SetToDraft').'</a></div>';
  2358. }
  2359. }
  2360. if ($user->hasRight('expensereport', 'approve') && $object->status == ExpenseReport::STATUS_VALIDATED) {
  2361. //if($object->fk_user_validator==$user->id)
  2362. //{
  2363. // Validate
  2364. print '<div class="inline-block divButAction"><a class="butAction" href="'.$_SERVER["PHP_SELF"].'?action=validate&id='.$object->id.'">'.$langs->trans('Approve').'</a></div>';
  2365. // Deny
  2366. print '<div class="inline-block divButAction"><a class="butAction" href="'.$_SERVER["PHP_SELF"].'?action=refuse&id='.$object->id.'">'.$langs->trans('Deny').'</a></div>';
  2367. //}
  2368. if ($user->id == $object->fk_user_author || $user->id == $object->fk_user_valid) {
  2369. // Cancel
  2370. print '<div class="inline-block divButAction"><a class="butAction" href="'.$_SERVER["PHP_SELF"].'?action=cancel&id='.$object->id.'">'.$langs->trans("Cancel").'</a></div>';
  2371. }
  2372. }
  2373. // If status is Approved
  2374. // ---------------------
  2375. if ($user->hasRight('expensereport', 'approve') && $object->status == ExpenseReport::STATUS_APPROVED) {
  2376. print '<div class="inline-block divButAction"><a class="butAction" href="'.$_SERVER["PHP_SELF"].'?action=refuse&id='.$object->id.'">'.$langs->trans('Deny').'</a></div>';
  2377. }
  2378. // If bank module is used
  2379. if ($user->hasRight('expensereport', 'to_paid') && isModEnabled("banque") && $object->status == ExpenseReport::STATUS_APPROVED) {
  2380. // Pay
  2381. if ($remaintopay == 0) {
  2382. print '<div class="inline-block divButAction"><span class="butActionRefused classfortooltip" title="'.$langs->trans("DisabledBecauseRemainderToPayIsZero").'">'.$langs->trans('DoPayment').'</span></div>';
  2383. } else {
  2384. print '<div class="inline-block divButAction"><a class="butAction" href="'.DOL_URL_ROOT.'/expensereport/payment/payment.php?id='.$object->id.'&amp;action=create">'.$langs->trans('DoPayment').'</a></div>';
  2385. }
  2386. }
  2387. // If bank module is not used
  2388. if (($user->hasRight('expensereport', 'to_paid') || empty(isModEnabled("banque"))) && $object->status == ExpenseReport::STATUS_APPROVED) {
  2389. //if ((round($remaintopay) == 0 || !isModEnabled("banque")) && $object->paid == 0)
  2390. if ($object->paid == 0) {
  2391. print '<div class="inline-block divButAction"><a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=set_paid&token='.newToken().'">'.$langs->trans("ClassifyPaid")."</a></div>";
  2392. }
  2393. }
  2394. if ($user->hasRight('expensereport', 'creer') && ($user->id == $object->fk_user_author || $user->id == $object->fk_user_valid) && $object->status == ExpenseReport::STATUS_APPROVED) {
  2395. // Cancel
  2396. print '<div class="inline-block divButAction"><a class="butAction" href="'.$_SERVER["PHP_SELF"].'?action=cancel&token='.newToken().'&id='.$object->id.'">'.$langs->trans("Cancel").'</a></div>';
  2397. }
  2398. // TODO Replace this. It should be SetUnpaid and should go back to status unpaid not canceled.
  2399. if (($user->hasRight('expensereport', 'approve') || $user->hasRight('expensereport', 'to_paid')) && $object->status == ExpenseReport::STATUS_CLOSED) {
  2400. // Cancel
  2401. print '<div class="inline-block divButAction"><a class="butAction" href="'.$_SERVER["PHP_SELF"].'?action=cancel&token='.newToken().'&id='.$object->id.'">'.$langs->trans("Cancel").'</a></div>';
  2402. }
  2403. if ($user->hasRight('expensereport', 'to_paid') && $object->paid && $object->status == ExpenseReport::STATUS_CLOSED) {
  2404. // Set unpaid
  2405. print '<div class="inline-block divButAction"><a class="butAction" href="'.$_SERVER["PHP_SELF"].'?action=set_unpaid&token='.newToken().'&id='.$object->id.'">'.$langs->trans('ClassifyUnPaid').'</a></div>';
  2406. }
  2407. // Clone
  2408. if ($user->hasRight('expensereport', 'creer')) {
  2409. print '<div class="inline-block divButAction"><a class="butAction" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=clone&token='.newToken().'">'.$langs->trans("ToClone").'</a></div>';
  2410. }
  2411. /* If draft, validated, cancel, and user can create, he can always delete its card before it is approved */
  2412. if ($user->hasRight('expensereport', 'creer') && $user->id == $object->fk_user_author && $object->status < ExpenseReport::STATUS_APPROVED) {
  2413. // Delete
  2414. print '<div class="inline-block divButAction"><a class="butActionDelete" href="'.$_SERVER["PHP_SELF"].'?action=delete&token='.newToken().'&id='.$object->id.'">'.$langs->trans('Delete').'</a></div>';
  2415. } elseif ($candelete && $object->status != ExpenseReport::STATUS_CLOSED) {
  2416. // Delete
  2417. print '<div class="inline-block divButAction"><a class="butActionDelete" href="'.$_SERVER["PHP_SELF"].'?action=delete&token='.newToken().'&id='.$object->id.'">'.$langs->trans('Delete').'</a></div>';
  2418. }
  2419. $parameters = array();
  2420. $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been
  2421. }
  2422. print '</div>';
  2423. // Select mail models is same action as presend
  2424. if (GETPOST('modelselected', 'alpha')) {
  2425. $action = 'presend';
  2426. }
  2427. if ($action != 'presend') {
  2428. /*
  2429. * Generate documents
  2430. */
  2431. print '<div class="fichecenter"><div class="fichehalfleft">';
  2432. print '<a name="builddoc"></a>'; // ancre
  2433. if ($user->hasRight('expensereport', 'creer') && $action != 'create' && $action != 'edit') {
  2434. $filename = dol_sanitizeFileName($object->ref);
  2435. $filedir = $conf->expensereport->dir_output."/".dol_sanitizeFileName($object->ref);
  2436. $urlsource = $_SERVER["PHP_SELF"]."?id=".$object->id;
  2437. $genallowed = $user->rights->expensereport->creer;
  2438. $delallowed = $user->rights->expensereport->creer;
  2439. $var = true;
  2440. print $formfile->showdocuments('expensereport', $filename, $filedir, $urlsource, $genallowed, $delallowed);
  2441. $somethingshown = $formfile->numoffiles;
  2442. }
  2443. // Disabled for expensereport, there is no thirdparty on expensereport, so nothing to define the list of other object we can suggest to link to
  2444. /*
  2445. if ($action != 'create' && $action != 'edit' && ($id || $ref))
  2446. {
  2447. $linktoelem = $form->showLinkToObjectBlock($object, null, array('expensereport'));
  2448. $somethingshown = $form->showLinkedObjectBlock($object, $linktoelem);
  2449. }
  2450. */
  2451. print '</div><div class="fichehalfright">';
  2452. // List of actions on element
  2453. include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
  2454. $formactions = new FormActions($db);
  2455. $somethingshown = $formactions->showactions($object, 'expensereport', null);
  2456. print '</div></div>';
  2457. }
  2458. // Presend form
  2459. $modelmail = 'expensereport';
  2460. $defaulttopic = 'SendExpenseReportRef';
  2461. $diroutput = $conf->expensereport->dir_output;
  2462. $trackid = 'exp'.$object->id;
  2463. include DOL_DOCUMENT_ROOT.'/core/tpl/card_presend.tpl.php';
  2464. llxFooter();
  2465. $db->close();