cabyuser.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539
  1. <?php
  2. /* Copyright (C) 2001-2003 Rodolphe Quiedeville <rodolphe@quiedeville.org>
  3. * Copyright (C) 2004-2016 Laurent Destailleur <eldy@users.sourceforge.net>
  4. * Copyright (C) 2005-2009 Regis Houssin <regis.houssin@inodbox.com>
  5. * Copyright (C) 2013 Antoine Iauch <aiauch@gpcsolutions.fr>
  6. * Copyright (C) 2018 Frédéric France <frederic.france@netlogic.fr>
  7. * Copyright (C) 2022 Alexandre Spangaro <aspangaro@open-dsi.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/compta/stats/cabyuser.php
  24. * \brief Page reporting Salesover by user
  25. */
  26. // Load Dolibarr environment
  27. require '../../main.inc.php';
  28. require_once DOL_DOCUMENT_ROOT.'/core/lib/report.lib.php';
  29. require_once DOL_DOCUMENT_ROOT.'/core/lib/tax.lib.php';
  30. require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
  31. // Load translation files required by the page
  32. $langs->load("accountancy");
  33. $socid = GETPOST('socid', 'int');
  34. // Security check
  35. if ($user->socid > 0) {
  36. $socid = $user->socid;
  37. }
  38. if (isModEnabled('comptabilite')) {
  39. $result = restrictedArea($user, 'compta', '', '', 'resultat');
  40. }
  41. if (isModEnabled('accounting')) {
  42. $result = restrictedArea($user, 'accounting', '', '', 'comptarapport');
  43. }
  44. // Define modecompta ('CREANCES-DETTES' or 'RECETTES-DEPENSES')
  45. $modecompta = $conf->global->ACCOUNTING_MODE;
  46. if (GETPOST("modecompta")) {
  47. $modecompta = GETPOST("modecompta");
  48. }
  49. $sortorder = GETPOST("sortorder", 'aZ09comma');
  50. $sortfield = GETPOST("sortfield", 'aZ09comma');
  51. if (!$sortorder) {
  52. $sortorder = "asc";
  53. }
  54. if (!$sortfield) {
  55. $sortfield = "name";
  56. }
  57. // Date range
  58. $year = GETPOST("year", 'int');
  59. $month = GETPOST("month", 'int');
  60. $date_startyear = GETPOST("date_startyear", 'int');
  61. $date_startmonth = GETPOST("date_startmonth", 'int');
  62. $date_startday = GETPOST("date_startday", 'int');
  63. $date_endyear = GETPOST("date_endyear", 'int');
  64. $date_endmonth = GETPOST("date_endmonth", 'int');
  65. $date_endday = GETPOST("date_endday", 'int');
  66. if (empty($year)) {
  67. $year_current = dol_print_date(dol_now(), '%Y');
  68. $month_current = dol_print_date(dol_now(), '%m');
  69. $year_start = $year_current;
  70. } else {
  71. $year_current = $year;
  72. $month_current = dol_print_date(dol_now(), '%m');
  73. $year_start = $year;
  74. }
  75. $date_start = dol_mktime(0, 0, 0, GETPOST("date_startmonth"), GETPOST("date_startday"), GETPOST("date_startyear"), 'tzserver'); // We use timezone of server so report is same from everywhere
  76. $date_end = dol_mktime(23, 59, 59, GETPOST("date_endmonth"), GETPOST("date_endday"), GETPOST("date_endyear"), 'tzserver'); // We use timezone of server so report is same from everywhere
  77. // Quarter
  78. if (empty($date_start) || empty($date_end)) { // We define date_start and date_end
  79. $q = GETPOST("q") ?GETPOST("q") : 0;
  80. if ($q == 0) {
  81. // We define date_start and date_end
  82. $month_start = GETPOST("month") ?GETPOST("month") : ($conf->global->SOCIETE_FISCAL_MONTH_START ? ($conf->global->SOCIETE_FISCAL_MONTH_START) : 1);
  83. $year_end = $year_start;
  84. $month_end = $month_start;
  85. if (!GETPOST("month")) { // If month not forced
  86. if (!GETPOST('year') && $month_start > $month_current) {
  87. $year_start--;
  88. $year_end--;
  89. }
  90. $month_end = $month_start - 1;
  91. if ($month_end < 1) {
  92. $month_end = 12;
  93. } else {
  94. $year_end++;
  95. }
  96. }
  97. $date_start = dol_get_first_day($year_start, $month_start, false);
  98. $date_end = dol_get_last_day($year_end, $month_end, false);
  99. }
  100. if ($q == 1) {
  101. $date_start = dol_get_first_day($year_start, 1, false);
  102. $date_end = dol_get_last_day($year_start, 3, false);
  103. }
  104. if ($q == 2) {
  105. $date_start = dol_get_first_day($year_start, 4, false);
  106. $date_end = dol_get_last_day($year_start, 6, false);
  107. }
  108. if ($q == 3) {
  109. $date_start = dol_get_first_day($year_start, 7, false);
  110. $date_end = dol_get_last_day($year_start, 9, false);
  111. }
  112. if ($q == 4) {
  113. $date_start = dol_get_first_day($year_start, 10, false);
  114. $date_end = dol_get_last_day($year_start, 12, false);
  115. }
  116. } else {
  117. // TODO We define q
  118. }
  119. // $date_start and $date_end are defined. We force $year_start and $nbofyear
  120. $tmps = dol_getdate($date_start);
  121. $year_start = $tmps['year'];
  122. $tmpe = dol_getdate($date_end);
  123. $year_end = $tmpe['year'];
  124. $nbofyear = ($year_end - $year_start) + 1;
  125. $commonparams = array();
  126. $commonparams['modecompta'] = $modecompta;
  127. $commonparams['sortorder'] = $sortorder;
  128. $commonparams['sortfield'] = $sortfield;
  129. $headerparams = array();
  130. if (!empty($date_startyear)) {
  131. $headerparams['date_startyear'] = $date_startyear;
  132. }
  133. if (!empty($date_startmonth)) {
  134. $headerparams['date_startmonth'] = $date_startmonth;
  135. }
  136. if (!empty($date_startday)) {
  137. $headerparams['date_startday'] = $date_startday;
  138. }
  139. if (!empty($date_endyear)) {
  140. $headerparams['date_endyear'] = $date_endyear;
  141. }
  142. if (!empty($date_endmonth)) {
  143. $headerparams['date_endmonth'] = $date_endmonth;
  144. }
  145. if (!empty($date_endday)) {
  146. $headerparams['date_endday'] = $date_endday;
  147. }
  148. if (!empty($q)) {
  149. $headerparams['q'] = $q;
  150. }
  151. $tableparams = array();
  152. // Adding common parameters
  153. $allparams = array_merge($commonparams, $headerparams, $tableparams);
  154. $headerparams = array_merge($commonparams, $headerparams);
  155. $tableparams = array_merge($commonparams, $tableparams);
  156. $paramslink="";
  157. foreach ($allparams as $key => $value) {
  158. $paramslink .= '&'.$key.'='.$value;
  159. }
  160. /*
  161. * View
  162. */
  163. llxHeader();
  164. $form = new Form($db);
  165. // TODO Report from bookkeeping not yet available, so we switch on report on business events
  166. if ($modecompta == "BOOKKEEPING") {
  167. $modecompta = "CREANCES-DETTES";
  168. }
  169. if ($modecompta == "BOOKKEEPINGCOLLECTED") {
  170. $modecompta = "RECETTES-DEPENSES";
  171. }
  172. $exportlink="";
  173. $namelink="";
  174. // Show report header
  175. if ($modecompta == "CREANCES-DETTES") {
  176. $name = $langs->trans("Turnover").', '.$langs->trans("ByUserAuthorOfInvoice");
  177. $calcmode = $langs->trans("CalcModeDebt");
  178. //$calcmode.='<br>('.$langs->trans("SeeReportInInputOutputMode",'<a href="'.$_SERVER["PHP_SELF"].'?year='.$year_start.'&modecompta=RECETTES-DEPENSES">','</a>').')';
  179. $description = $langs->trans("RulesCADue");
  180. if (!empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) {
  181. $description .= $langs->trans("DepositsAreNotIncluded");
  182. } else {
  183. $description .= $langs->trans("DepositsAreIncluded");
  184. }
  185. $builddate = dol_now();
  186. //$exportlink=$langs->trans("NotYetAvailable");
  187. } elseif ($modecompta == "RECETTES-DEPENSES") {
  188. $name = $langs->trans("TurnoverCollected").', '.$langs->trans("ByUserAuthorOfInvoice");
  189. $calcmode = $langs->trans("CalcModeEngagement");
  190. //$calcmode.='<br>('.$langs->trans("SeeReportInDueDebtMode",'<a href="'.$_SERVER["PHP_SELF"].'?year='.$year_start.'&modecompta=CREANCES-DETTES">','</a>').')';
  191. $description = $langs->trans("RulesCAIn");
  192. $description .= $langs->trans("DepositsAreIncluded");
  193. $builddate = dol_now();
  194. //$exportlink=$langs->trans("NotYetAvailable");
  195. } elseif ($modecompta == "BOOKKEEPING") {
  196. // TODO
  197. } elseif ($modecompta == "BOOKKEEPINGCOLLECTED") {
  198. // TODO
  199. }
  200. $period = $form->selectDate($date_start, 'date_start', 0, 0, 0, '', 1, 0, 0, '', '', '', '', 1, '', '', 'tzserver');
  201. $period .= ' - ';
  202. $period .= $form->selectDate($date_end, 'date_end', 0, 0, 0, '', 1, 0, 0, '', '', '', '', 1, '', '', 'tzserver');
  203. if ($date_end == dol_time_plus_duree($date_start, 1, 'y') - 1) {
  204. $periodlink = '<a href="'.$_SERVER["PHP_SELF"].'?year='.($year_start - 1).'&modecompta='.$modecompta.'">'.img_previous().'</a> <a href="'.$_SERVER["PHP_SELF"].'?year='.($year_start + 1).'&modecompta='.$modecompta.'">'.img_next().'</a>';
  205. } else {
  206. $periodlink = '';
  207. }
  208. $moreparam = array();
  209. if (!empty($modecompta)) {
  210. $moreparam['modecompta'] = $modecompta;
  211. }
  212. report_header($name, $namelink, $period, $periodlink, $description, $builddate, $exportlink, $moreparam, $calcmode);
  213. if (isModEnabled('accounting') && $modecompta != 'BOOKKEEPING') {
  214. print info_admin($langs->trans("WarningReportNotReliable"), 0, 0, 1);
  215. }
  216. $name = array();
  217. // Show array
  218. print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'">';
  219. print '<input type="hidden" name="token" value="'.newToken().'">'."\n";
  220. // Extra parameters management
  221. foreach ($headerparams as $key => $value) {
  222. print '<input type="hidden" name="'.$key.'" value="'.$value.'">';
  223. }
  224. $catotal = 0;
  225. $catotal_ht = 0;
  226. if ($modecompta == 'CREANCES-DETTES') {
  227. $sql = "SELECT u.rowid as rowid, u.lastname as name, u.firstname as firstname, sum(f.total_ht) as amount, sum(f.total_ttc) as amount_ttc";
  228. $sql .= " FROM ".MAIN_DB_PREFIX."user as u";
  229. $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."facture as f ON f.fk_user_author = u.rowid";
  230. $sql .= " WHERE f.fk_statut in (1,2)";
  231. if (!empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) {
  232. $sql .= " AND f.type IN (0,1,2,5)";
  233. } else {
  234. $sql .= " AND f.type IN (0,1,2,3,5)";
  235. }
  236. if ($date_start && $date_end) {
  237. $sql .= " AND f.datef >= '".$db->idate($date_start)."' AND f.datef <= '".$db->idate($date_end)."'";
  238. }
  239. } elseif ($modecompta == "RECETTES-DEPENSES") {
  240. /*
  241. * List of payments (old payments are not seen by this query because on older versions,
  242. * they were not linked via the table llx_paiement_facture. They are added later)
  243. */
  244. $sql = "SELECT u.rowid as rowid, u.lastname as name, u.firstname as firstname, sum(pf.amount) as amount_ttc";
  245. $sql .= " FROM ".MAIN_DB_PREFIX."user as u";
  246. $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."facture as f ON f.fk_user_author = u.rowid ";
  247. $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."paiement_facture as pf ON pf.fk_facture = f.rowid";
  248. $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."paiement as p ON p.rowid = pf.fk_paiement";
  249. $sql .= " WHERE 1=1";
  250. if ($date_start && $date_end) {
  251. $sql .= " AND p.datep >= '".$db->idate($date_start)."' AND p.datep <= '".$db->idate($date_end)."'";
  252. }
  253. } elseif ($modecompta == "BOOKKEEPING") {
  254. } elseif ($modecompta == "BOOKKEEPINGCOLLECTED") {
  255. }
  256. $sql .= " AND f.entity IN (".getEntity('invoice').")";
  257. if ($socid) {
  258. $sql .= " AND f.fk_soc = ".((int) $socid);
  259. }
  260. $sql .= " GROUP BY u.rowid, u.lastname, u.firstname";
  261. $sql .= " ORDER BY u.rowid";
  262. $amount = array();
  263. dol_syslog("cabyuser", LOG_DEBUG);
  264. $result = $db->query($sql);
  265. if ($result) {
  266. $num = $db->num_rows($result);
  267. $i = 0;
  268. while ($i < $num) {
  269. $obj = $db->fetch_object($result);
  270. $amount_ht[$obj->rowid] = (empty($obj->amount) ? 0 : $obj->amount);
  271. $amount[$obj->rowid] = $obj->amount_ttc;
  272. $name[$obj->rowid] = $obj->name.' '.$obj->firstname;
  273. $catotal_ht += (empty($obj->amount) ? 0 : $obj->amount);
  274. $catotal += $obj->amount_ttc;
  275. $i++;
  276. }
  277. } else {
  278. dol_print_error($db);
  279. }
  280. // Adding old-version payments, non-bound by table llx_paiement_facture then without User
  281. if ($modecompta == 'RECETTES-DEPENSES') {
  282. $sql = "SELECT -1 as rowidx, '' as name, '' as firstname, sum(DISTINCT p.amount) as amount_ttc";
  283. $sql .= " FROM ".MAIN_DB_PREFIX."bank as b";
  284. $sql .= ", ".MAIN_DB_PREFIX."bank_account as ba";
  285. $sql .= ", ".MAIN_DB_PREFIX."paiement as p";
  286. $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."paiement_facture as pf ON p.rowid = pf.fk_paiement";
  287. $sql .= " WHERE pf.rowid IS NULL";
  288. $sql .= " AND p.fk_bank = b.rowid";
  289. $sql .= " AND b.fk_account = ba.rowid";
  290. $sql .= " AND ba.entity IN (".getEntity('bank_account').")";
  291. if ($date_start && $date_end) {
  292. $sql .= " AND p.datep >= '".$db->idate($date_start)."' AND p.datep <= '".$db->idate($date_end)."'";
  293. }
  294. $sql .= " GROUP BY rowidx, name, firstname";
  295. $sql .= " ORDER BY rowidx";
  296. $result = $db->query($sql);
  297. if ($result) {
  298. $num = $db->num_rows($result);
  299. $i = 0;
  300. while ($i < $num) {
  301. $obj = $db->fetch_object($result);
  302. $amount[$obj->rowidx] = $obj->amount_ttc;
  303. $name[$obj->rowidx] = $obj->name.' '.$obj->firstname;
  304. $catotal += $obj->amount_ttc;
  305. $i++;
  306. }
  307. } else {
  308. dol_print_error($db);
  309. }
  310. }
  311. $moreforfilter = '';
  312. print '<div class="div-table-responsive">';
  313. print '<table class="tagtable liste'.($moreforfilter ? " listwithfilterbefore" : "").'">'."\n";
  314. print "<tr class=\"liste_titre\">";
  315. print_liste_field_titre(
  316. $langs->trans("User"),
  317. $_SERVER["PHP_SELF"],
  318. "name",
  319. "",
  320. $paramslink,
  321. "",
  322. $sortfield,
  323. $sortorder
  324. );
  325. if ($modecompta == 'CREANCES-DETTES') {
  326. print_liste_field_titre(
  327. $langs->trans('AmountHT'),
  328. $_SERVER["PHP_SELF"],
  329. "amount_ht",
  330. "",
  331. $paramslink,
  332. 'class="right"',
  333. $sortfield,
  334. $sortorder
  335. );
  336. } else {
  337. print_liste_field_titre('');
  338. }
  339. print_liste_field_titre(
  340. $langs->trans("AmountTTC"),
  341. $_SERVER["PHP_SELF"],
  342. "amount_ttc",
  343. "",
  344. $paramslink,
  345. 'class="right"',
  346. $sortfield,
  347. $sortorder
  348. );
  349. print_liste_field_titre(
  350. $langs->trans("Percentage"),
  351. $_SERVER["PHP_SELF"],
  352. "amount_ttc",
  353. "",
  354. $paramslink,
  355. 'class="right"',
  356. $sortfield,
  357. $sortorder
  358. );
  359. print_liste_field_titre(
  360. $langs->trans("OtherStatistics"),
  361. $_SERVER["PHP_SELF"],
  362. "",
  363. "",
  364. "",
  365. 'align="center" width="20%"'
  366. );
  367. print "</tr>\n";
  368. if (count($amount)) {
  369. $arrayforsort = $name;
  370. // We define arrayforsort
  371. if ($sortfield == 'name' && $sortorder == 'asc') {
  372. asort($name);
  373. $arrayforsort = $name;
  374. }
  375. if ($sortfield == 'name' && $sortorder == 'desc') {
  376. arsort($name);
  377. $arrayforsort = $name;
  378. }
  379. if ($sortfield == 'amount_ht' && $sortorder == 'asc') {
  380. asort($amount_ht);
  381. $arrayforsort = $amount_ht;
  382. }
  383. if ($sortfield == 'amount_ht' && $sortorder == 'desc') {
  384. arsort($amount_ht);
  385. $arrayforsort = $amount_ht;
  386. }
  387. if ($sortfield == 'amount_ttc' && $sortorder == 'asc') {
  388. asort($amount);
  389. $arrayforsort = $amount;
  390. }
  391. if ($sortfield == 'amount_ttc' && $sortorder == 'desc') {
  392. arsort($amount);
  393. $arrayforsort = $amount;
  394. }
  395. $i = 0;
  396. foreach ($arrayforsort as $key => $value) {
  397. print '<tr class="oddeven">';
  398. // Third party
  399. $fullname = $name[$key];
  400. if ($key >= 0) {
  401. $linkname = '<a href="'.DOL_URL_ROOT.'/user/card.php?id='.$key.'">'.img_object($langs->trans("ShowUser"), 'user').' '.$fullname.'</a>';
  402. } else {
  403. $linkname = $langs->trans("PaymentsNotLinkedToUser");
  404. }
  405. print "<td>".$linkname."</td>\n";
  406. // Amount w/o VAT
  407. print '<td class="right">';
  408. if ($modecompta == 'RECETTES-DEPENSES') {
  409. if ($key > 0) {
  410. //print '<a href="'.DOL_URL_ROOT.'/compta/paiement/list.php?userid='.$key.'">';
  411. } else {
  412. //print '<a href="'.DOL_URL_ROOT.'/compta/paiement/list.php?userid=-1">';
  413. }
  414. } elseif ($modecompta == 'CREANCES-DETTES') {
  415. if ($key > 0) {
  416. print '<a href="'.DOL_URL_ROOT.'/compta/facture/list.php?userid='.$key.'">';
  417. } else {
  418. //print '<a href="#">';
  419. }
  420. print price($amount_ht[$key]);
  421. if ($key > 0) {
  422. print '</a>';
  423. }
  424. }
  425. print '</td>';
  426. // Amount with VAT
  427. print '<td class="right">';
  428. if ($modecompta == 'RECETTES-DEPENSES') {
  429. if ($key > 0) {
  430. //print '<a href="'.DOL_URL_ROOT.'/compta/paiement/list.php?userid='.$key.'">';
  431. } else {
  432. //print '<a href="'.DOL_URL_ROOT.'/compta/paiement/list.php?userid=-1">';
  433. }
  434. } elseif ($modecompta == 'CREANCES-DETTES') {
  435. if ($key > 0) {
  436. print '<a href="'.DOL_URL_ROOT.'/compta/facture/list.php?userid='.$key.'">';
  437. } else {
  438. //print '<a href="#">';
  439. }
  440. }
  441. print price($amount[$key]);
  442. if ($modecompta == 'RECETTES-DEPENSES') {
  443. if ($key > 0) {
  444. //print '</a>';
  445. } else {
  446. //print '</a>';
  447. }
  448. } elseif ($modecompta == 'CREANCES-DETTES') {
  449. if ($key > 0) {
  450. print '</a>';
  451. }
  452. }
  453. print '</td>';
  454. // Percent
  455. print '<td class="right">'.($catotal > 0 ? round(100 * $amount[$key] / $catotal, 2).'%' : '&nbsp;').'</td>';
  456. // Other stats
  457. print '<td class="center">';
  458. if (isModEnabled("propal") && $key > 0) {
  459. print '&nbsp;<a href="'.DOL_URL_ROOT.'/comm/propal/stats/index.php?userid='.$key.'">'.img_picto($langs->trans("ProposalStats"), "stats").'</a>&nbsp;';
  460. }
  461. if (isModEnabled('commande') && $key > 0) {
  462. print '&nbsp;<a href="'.DOL_URL_ROOT.'/commande/stats/index.php?userid='.$key.'">'.img_picto($langs->trans("OrderStats"), "stats").'</a>&nbsp;';
  463. }
  464. if (isModEnabled('facture') && $key > 0) {
  465. print '&nbsp;<a href="'.DOL_URL_ROOT.'/compta/facture/stats/index.php?userid='.$key.'">'.img_picto($langs->trans("InvoiceStats"), "stats").'</a>&nbsp;';
  466. }
  467. print '</td>';
  468. print "</tr>\n";
  469. $i++;
  470. }
  471. // Total
  472. print '<tr class="liste_total">';
  473. print '<td>'.$langs->trans("Total").'</td>';
  474. if ($modecompta != 'CREANCES-DETTES') {
  475. print '<td></td>';
  476. } else {
  477. print '<td class="right">'.price($catotal_ht).'</td>';
  478. }
  479. print '<td class="right">'.price($catotal).'</td>';
  480. print '<td>&nbsp;</td>';
  481. print '<td>&nbsp;</td>';
  482. print '</tr>';
  483. $db->free($result);
  484. }
  485. print "</table>";
  486. print '</div>';
  487. print '</form>';
  488. // End of page
  489. llxFooter();
  490. $db->close();