1<?php 2/* Copyright (C) 2016 Neil Orley <neil.orley@oeris.fr> 3 * Copyright (C) 2013-2016 Olivier Geffroy <jeff@jeffinfo.com> 4 * Copyright (C) 2013-2020 Florian Henry <florian.henry@open-concept.pro> 5 * Copyright (C) 2013-2021 Alexandre Spangaro <aspangaro@open-dsi.fr> 6 * Copyright (C) 2018-2020 Frédéric France <frederic.france@netlogic.fr> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 3 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program. If not, see <https://www.gnu.org/licenses/>. 20 */ 21 22/** 23 * \file htdocs/accountancy/bookkeeping/listbysubaccount.php 24 * \ingroup Accountancy (Double entries) 25 * \brief List operation of ledger ordered by subaccount number 26 */ 27 28require '../../main.inc.php'; 29 30require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php'; 31require_once DOL_DOCUMENT_ROOT.'/accountancy/class/bookkeeping.class.php'; 32require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingjournal.class.php'; 33require_once DOL_DOCUMENT_ROOT.'/core/class/html.formaccounting.class.php'; 34require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; 35require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; 36require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; 37 38// Load translation files required by the page 39$langs->loadLangs(array("accountancy", "compta")); 40 41$action = GETPOST('action', 'aZ09'); 42$search_date_startyear = GETPOST('search_date_startyear', 'int'); 43$search_date_startmonth = GETPOST('search_date_startmonth', 'int'); 44$search_date_startday = GETPOST('search_date_startday', 'int'); 45$search_date_endyear = GETPOST('search_date_endyear', 'int'); 46$search_date_endmonth = GETPOST('search_date_endmonth', 'int'); 47$search_date_endday = GETPOST('search_date_endday', 'int'); 48$search_date_start = dol_mktime(0, 0, 0, $search_date_startmonth, $search_date_startday, $search_date_startyear); 49$search_date_end = dol_mktime(23, 59, 59, $search_date_endmonth, $search_date_endday, $search_date_endyear); 50$search_doc_date = dol_mktime(0, 0, 0, GETPOST('doc_datemonth', 'int'), GETPOST('doc_dateday', 'int'), GETPOST('doc_dateyear', 'int')); 51$search_date_export_startyear = GETPOST('search_date_export_startyear', 'int'); 52$search_date_export_startmonth = GETPOST('search_date_export_startmonth', 'int'); 53$search_date_export_startday = GETPOST('search_date_export_startday', 'int'); 54$search_date_export_endyear = GETPOST('search_date_export_endyear', 'int'); 55$search_date_export_endmonth = GETPOST('search_date_export_endmonth', 'int'); 56$search_date_export_endday = GETPOST('search_date_export_endday', 'int'); 57$search_date_export_start = dol_mktime(0, 0, 0, $search_date_export_startmonth, $search_date_export_startday, $search_date_export_startyear); 58$search_date_export_end = dol_mktime(23, 59, 59, $search_date_export_endmonth, $search_date_export_endday, $search_date_export_endyear); 59$search_date_validation_startyear = GETPOST('search_date_validation_startyear', 'int'); 60$search_date_validation_startmonth = GETPOST('search_date_validation_startmonth', 'int'); 61$search_date_validation_startday = GETPOST('search_date_validation_startday', 'int'); 62$search_date_validation_endyear = GETPOST('search_date_validation_endyear', 'int'); 63$search_date_validation_endmonth = GETPOST('search_date_validation_endmonth', 'int'); 64$search_date_validation_endday = GETPOST('search_date_validation_endday', 'int'); 65$search_date_validation_start = dol_mktime(0, 0, 0, $search_date_validation_startmonth, $search_date_validation_startday, $search_date_validation_startyear); 66$search_date_validation_end = dol_mktime(23, 59, 59, $search_date_validation_endmonth, $search_date_validation_endday, $search_date_validation_endyear); 67 68$search_accountancy_code = GETPOST("search_accountancy_code"); 69$search_accountancy_code_start = GETPOST('search_accountancy_code_start', 'alpha'); 70if ($search_accountancy_code_start == - 1) { 71 $search_accountancy_code_start = ''; 72} 73$search_accountancy_code_end = GETPOST('search_accountancy_code_end', 'alpha'); 74if ($search_accountancy_code_end == - 1) { 75 $search_accountancy_code_end = ''; 76} 77$search_doc_ref = GETPOST('search_doc_ref', 'alpha'); 78$search_label_operation = GETPOST('search_label_operation', 'alpha'); 79$search_mvt_num = GETPOST('search_mvt_num', 'int'); 80$search_direction = GETPOST('search_direction', 'alpha'); 81$search_ledger_code = GETPOST('search_ledger_code', 'array'); 82$search_debit = GETPOST('search_debit', 'alpha'); 83$search_credit = GETPOST('search_credit', 'alpha'); 84$search_lettering_code = GETPOST('search_lettering_code', 'alpha'); 85$search_not_reconciled = GETPOST('search_not_reconciled', 'alpha'); 86 87if (GETPOST("button_delmvt_x") || GETPOST("button_delmvt.x") || GETPOST("button_delmvt")) { 88 $action = 'delbookkeepingyear'; 89} 90 91// Load variable for pagination 92$limit = GETPOST('limit', 'int') ? GETPOST('limit', 'int') : (empty($conf->global->ACCOUNTING_LIMIT_LIST_VENTILATION) ? $conf->liste_limit : $conf->global->ACCOUNTING_LIMIT_LIST_VENTILATION); 93$sortfield = GETPOST('sortfield', 'aZ09comma'); 94$sortorder = GETPOST('sortorder', 'aZ09comma'); 95$page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int'); 96if (empty($page) || $page < 0) { 97 $page = 0; 98} 99$offset = $limit * $page; 100$pageprev = $page - 1; 101$pagenext = $page + 1; 102if ($sortorder == "") { 103 $sortorder = "ASC"; 104} 105if ($sortfield == "") { 106 $sortfield = "t.doc_date,t.rowid"; 107} 108 109// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context 110$object = new BookKeeping($db); 111$formfile = new FormFile($db); 112$hookmanager->initHooks(array('bookkeepingbysubaccountlist')); 113 114$formaccounting = new FormAccounting($db); 115$form = new Form($db); 116 117if (empty($search_date_start) && empty($search_date_end) && !GETPOSTISSET('search_date_startday') && !GETPOSTISSET('search_date_startmonth') && !GETPOSTISSET('search_date_starthour')) { 118 $sql = "SELECT date_start, date_end from ".MAIN_DB_PREFIX."accounting_fiscalyear "; 119 $sql .= " where date_start < '".$db->idate(dol_now())."' and date_end > '".$db->idate(dol_now())."'"; 120 $sql .= $db->plimit(1); 121 $res = $db->query($sql); 122 123 if ($res->num_rows > 0) { 124 $fiscalYear = $db->fetch_object($res); 125 $search_date_start = strtotime($fiscalYear->date_start); 126 $search_date_end = strtotime($fiscalYear->date_end); 127 } else { 128 $month_start = ($conf->global->SOCIETE_FISCAL_MONTH_START ? ($conf->global->SOCIETE_FISCAL_MONTH_START) : 1); 129 $year_start = dol_print_date(dol_now(), '%Y'); 130 if (dol_print_date(dol_now(), '%m') < $month_start) { 131 $year_start--; // If current month is lower that starting fiscal month, we start last year 132 } 133 $year_end = $year_start + 1; 134 $month_end = $month_start - 1; 135 if ($month_end < 1) { 136 $month_end = 12; 137 $year_end--; 138 } 139 $search_date_start = dol_mktime(0, 0, 0, $month_start, 1, $year_start); 140 $search_date_end = dol_get_last_day($year_end, $month_end); 141 } 142} 143 144$arrayfields = array( 145 // 't.subledger_account'=>array('label'=>$langs->trans("SubledgerAccount"), 'checked'=>1), 146 't.piece_num'=>array('label'=>$langs->trans("TransactionNumShort"), 'checked'=>1), 147 't.code_journal'=>array('label'=>$langs->trans("Codejournal"), 'checked'=>1), 148 't.doc_date'=>array('label'=>$langs->trans("Docdate"), 'checked'=>1), 149 't.doc_ref'=>array('label'=>$langs->trans("Piece"), 'checked'=>1), 150 't.label_operation'=>array('label'=>$langs->trans("Label"), 'checked'=>1), 151 't.debit'=>array('label'=>$langs->trans("Debit"), 'checked'=>1), 152 't.credit'=>array('label'=>$langs->trans("Credit"), 'checked'=>1), 153 't.lettering_code'=>array('label'=>$langs->trans("LetteringCode"), 'checked'=>1), 154 't.date_export'=>array('label'=>$langs->trans("DateExport"), 'checked'=>1), 155 't.date_validated'=>array('label'=>$langs->trans("DateValidation"), 'checked'=>1), 156); 157 158if (empty($conf->global->ACCOUNTING_ENABLE_LETTERING)) { 159 unset($arrayfields['t.lettering_code']); 160} 161 162if ($search_date_start && empty($search_date_startyear)) { 163 $tmparray = dol_getdate($search_date_start); 164 $search_date_startyear = $tmparray['year']; 165 $search_date_startmonth = $tmparray['mon']; 166 $search_date_startday = $tmparray['mday']; 167} 168if ($search_date_end && empty($search_date_endyear)) { 169 $tmparray = dol_getdate($search_date_end); 170 $search_date_endyear = $tmparray['year']; 171 $search_date_endmonth = $tmparray['mon']; 172 $search_date_endday = $tmparray['mday']; 173} 174 175if (empty($conf->accounting->enabled)) { 176 accessforbidden(); 177} 178if ($user->socid > 0) { 179 accessforbidden(); 180} 181if (empty($user->rights->accounting->mouvements->lire)) { 182 accessforbidden(); 183} 184 185 186/* 187 * Action 188 */ 189 190if (GETPOST('cancel', 'alpha')) { 191 $action = 'list'; $massaction = ''; 192} 193if (!GETPOST('confirmmassaction', 'alpha') && $massaction != 'presend' && $massaction != 'confirm_presend') { 194 $massaction = ''; 195} 196 197$parameters = array('socid'=>$socid); 198$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks 199if ($reshook < 0) { 200 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); 201} 202 203if (empty($reshook)) { 204 include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php'; 205 206 if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // All tests are required to be compatible with all browsers 207 $search_doc_date = ''; 208 $search_accountancy_code = ''; 209 $search_accountancy_code_start = ''; 210 $search_accountancy_code_end = ''; 211 $search_label_account = ''; 212 $search_doc_ref = ''; 213 $search_label_operation = ''; 214 $search_mvt_num = ''; 215 $search_direction = ''; 216 $search_ledger_code = array(); 217 $search_date_start = ''; 218 $search_date_end = ''; 219 $search_date_startyear = ''; 220 $search_date_startmonth = ''; 221 $search_date_startday = ''; 222 $search_date_endyear = ''; 223 $search_date_endmonth = ''; 224 $search_date_endday = ''; 225 $search_date_export_start = ''; 226 $search_date_export_end = ''; 227 $search_date_export_startyear = ''; 228 $search_date_export_startmonth = ''; 229 $search_date_export_startday = ''; 230 $search_date_export_endyear = ''; 231 $search_date_export_endmonth = ''; 232 $search_date_export_endday = ''; 233 $search_date_validation_start = ''; 234 $search_date_validation_end = ''; 235 $search_date_validation_startyear = ''; 236 $search_date_validation_startmonth = ''; 237 $search_date_validation_startday = ''; 238 $search_date_validation_endyear = ''; 239 $search_date_validation_endmonth = ''; 240 $search_date_validation_endday = ''; 241 $search_debit = ''; 242 $search_credit = ''; 243 $search_lettering_code = ''; 244 $search_not_reconciled = ''; 245 } 246 247 // Must be after the remove filter action, before the export. 248 $param = ''; 249 $filter = array(); 250 251 if (!empty($search_date_start)) { 252 $filter['t.doc_date>='] = $search_date_start; 253 $param .= '&search_date_startmonth='.$search_date_startmonth.'&search_date_startday='.$search_date_startday.'&search_date_startyear='.$search_date_startyear; 254 } 255 if (!empty($search_date_end)) { 256 $filter['t.doc_date<='] = $search_date_end; 257 $param .= '&search_date_endmonth='.$search_date_endmonth.'&search_date_endday='.$search_date_endday.'&search_date_endyear='.$search_date_endyear; 258 } 259 if (!empty($search_doc_date)) { 260 $filter['t.doc_date'] = $search_doc_date; 261 $param .= '&doc_datemonth='.GETPOST('doc_datemonth', 'int').'&doc_dateday='.GETPOST('doc_dateday', 'int').'&doc_dateyear='.GETPOST('doc_dateyear', 'int'); 262 } 263 if (!empty($search_accountancy_code_start)) { 264 $filter['t.subledger_account>='] = $search_accountancy_code_start; 265 $param .= '&search_accountancy_code_start='.urlencode($search_accountancy_code_start); 266 } 267 if (!empty($search_accountancy_code_end)) { 268 $filter['t.subledger_account<='] = $search_accountancy_code_end; 269 $param .= '&search_accountancy_code_end='.urlencode($search_accountancy_code_end); 270 } 271 if (!empty($search_label_account)) { 272 $filter['t.label_compte'] = $search_label_account; 273 $param .= '&search_label_compte='.urlencode($search_label_account); 274 } 275 if (!empty($search_mvt_num)) { 276 $filter['t.piece_num'] = $search_mvt_num; 277 $param .= '&search_mvt_num='.urlencode($search_mvt_num); 278 } 279 if (!empty($search_doc_ref)) { 280 $filter['t.doc_ref'] = $search_doc_ref; 281 $param .= '&search_doc_ref='.urlencode($search_doc_ref); 282 } 283 if (!empty($search_label_operation)) { 284 $filter['t.label_operation'] = $search_label_operation; 285 $param .= '&search_label_operation='.urlencode($search_label_operation); 286 } 287 if (!empty($search_direction)) { 288 $filter['t.sens'] = $search_direction; 289 $param .= '&search_direction='.urlencode($search_direction); 290 } 291 if (!empty($search_ledger_code)) { 292 $filter['t.code_journal'] = $search_ledger_code; 293 foreach ($search_ledger_code as $code) { 294 $param .= '&search_ledger_code[]='.urlencode($code); 295 } 296 } 297 if (!empty($search_debit)) { 298 $filter['t.debit'] = $search_debit; 299 $param .= '&search_debit='.urlencode($search_debit); 300 } 301 if (!empty($search_credit)) { 302 $filter['t.credit'] = $search_credit; 303 $param .= '&search_credit='.urlencode($search_credit); 304 } 305 if (!empty($search_lettering_code)) { 306 $filter['t.lettering_code'] = $search_lettering_code; 307 $param .= '&search_lettering_code='.urlencode($search_lettering_code); 308 } 309 if (!empty($search_not_reconciled)) { 310 $filter['t.reconciled_option'] = $search_not_reconciled; 311 $param .= '&search_not_reconciled='.urlencode($search_not_reconciled); 312 } 313 if (!empty($search_date_export_start)) { 314 $filter['t.date_export>='] = $search_date_export_start; 315 $param .= '&search_date_export_startmonth='.$search_date_export_startmonth.'&search_date_export_startday='.$search_date_export_startday.'&search_date_export_startyear='.$search_date_export_startyear; 316 } 317 if (!empty($search_date_export_end)) { 318 $filter['t.date_export<='] = $search_date_export_end; 319 $param .= '&search_date_export_endmonth='.$search_date_export_endmonth.'&search_date_export_endday='.$search_date_export_endday.'&search_date_export_endyear='.$search_date_export_endyear; 320 } 321 if (!empty($search_date_validation_start)) { 322 $filter['t.date_validated>='] = $search_date_validation_start; 323 $param .= '&search_date_validation_startmonth='.$search_date_validation_startmonth.'&search_date_validation_startday='.$search_date_validation_startday.'&search_date_validation_startyear='.$search_date_validation_startyear; 324 } 325 if (!empty($search_date_validation_end)) { 326 $filter['t.date_validated<='] = $search_date_validation_end; 327 $param .= '&search_date_validation_endmonth='.$search_date_validation_endmonth.'&search_date_validation_endday='.$search_date_validation_endday.'&search_date_validation_endyear='.$search_date_validation_endyear; 328 } 329} 330 331if ($action == 'delbookkeeping' && $user->rights->accounting->mouvements->supprimer) { 332 $import_key = GETPOST('importkey', 'alpha'); 333 334 if (!empty($import_key)) { 335 $result = $object->deleteByImportkey($import_key); 336 if ($result < 0) { 337 setEventMessages($object->error, $object->errors, 'errors'); 338 } 339 340 // Make a redirect to avoid to launch the delete later after a back button 341 header("Location: ".$_SERVER["PHP_SELF"].($param ? '?'.$param : '')); 342 exit; 343 } 344} 345if ($action == 'delbookkeepingyearconfirm' && $user->rights->accounting->mouvements->supprimer_tous) { 346 $delmonth = GETPOST('delmonth', 'int'); 347 $delyear = GETPOST('delyear', 'int'); 348 if ($delyear == -1) { 349 $delyear = 0; 350 } 351 $deljournal = GETPOST('deljournal', 'alpha'); 352 if ($deljournal == -1) { 353 $deljournal = 0; 354 } 355 356 if (!empty($delmonth) || !empty($delyear) || !empty($deljournal)) { 357 $result = $object->deleteByYearAndJournal($delyear, $deljournal, '', ($delmonth > 0 ? $delmonth : 0)); 358 if ($result < 0) { 359 setEventMessages($object->error, $object->errors, 'errors'); 360 } else { 361 setEventMessages("RecordDeleted", null, 'mesgs'); 362 } 363 364 // Make a redirect to avoid to launch the delete later after a back button 365 header("Location: ".$_SERVER["PHP_SELF"].($param ? '?'.$param : '')); 366 exit; 367 } else { 368 setEventMessages("NoRecordDeleted", null, 'warnings'); 369 } 370} 371if ($action == 'delmouvconfirm' && $user->rights->accounting->mouvements->supprimer) { 372 $mvt_num = GETPOST('mvt_num', 'int'); 373 374 if (!empty($mvt_num)) { 375 $result = $object->deleteMvtNum($mvt_num); 376 if ($result < 0) { 377 setEventMessages($object->error, $object->errors, 'errors'); 378 } else { 379 setEventMessages($langs->trans("RecordDeleted"), null, 'mesgs'); 380 } 381 382 header("Location: ".$_SERVER["PHP_SELF"]."?noreset=1".($param ? '&'.$param : '')); 383 exit; 384 } 385} 386 387 388/* 389 * View 390 */ 391 392$formaccounting = new FormAccounting($db); 393$formfile = new FormFile($db); 394$formother = new FormOther($db); 395$form = new Form($db); 396 397$title_page = $langs->trans("Operations").' - '.$langs->trans("VueByAccountAccounting").' ('.$langs->trans("BookkeepingSubAccount").')'; 398 399llxHeader('', $title_page); 400 401// List 402$nbtotalofrecords = ''; 403if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { 404 $nbtotalofrecords = $object->fetchAllByAccount($sortorder, $sortfield, 0, 0, $filter, 'AND', 1); 405 if ($nbtotalofrecords < 0) { 406 setEventMessages($object->error, $object->errors, 'errors'); 407 } 408} 409 410$result = $object->fetchAllByAccount($sortorder, $sortfield, $limit, $offset, $filter, 'AND', 1); 411 412if ($result < 0) { 413 setEventMessages($object->error, $object->errors, 'errors'); 414} 415 416$num = count($object->lines); 417 418 419if ($action == 'delmouv') { 420 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?mvt_num='.GETPOST('mvt_num'), $langs->trans('DeleteMvt'), $langs->trans('ConfirmDeleteMvtPartial'), 'delmouvconfirm', '', 0, 1); 421 print $formconfirm; 422} 423if ($action == 'delbookkeepingyear') { 424 $form_question = array(); 425 $delyear = GETPOST('delyear', 'int'); 426 $deljournal = GETPOST('deljournal', 'alpha'); 427 428 if (empty($delyear)) { 429 $delyear = dol_print_date(dol_now(), '%Y'); 430 } 431 $month_array = array(); 432 for ($i = 1; $i <= 12; $i++) { 433 $month_array[$i] = $langs->trans("Month".sprintf("%02d", $i)); 434 } 435 $year_array = $formaccounting->selectyear_accountancy_bookkepping($delyear, 'delyear', 0, 'array'); 436 $journal_array = $formaccounting->select_journal($deljournal, 'deljournal', '', 1, 1, 1, '', 0, 1); 437 438 $form_question['delmonth'] = array( 439 'name' => 'delmonth', 440 'type' => 'select', 441 'label' => $langs->trans('DelMonth'), 442 'values' => $month_array, 443 'default' => '' 444 ); 445 $form_question['delyear'] = array( 446 'name' => 'delyear', 447 'type' => 'select', 448 'label' => $langs->trans('DelYear'), 449 'values' => $year_array, 450 'default' => $delyear 451 ); 452 $form_question['deljournal'] = array( 453 'name' => 'deljournal', 454 'type' => 'other', // We don't use select here, the journal_array is already a select html component 455 'label' => $langs->trans('DelJournal'), 456 'value' => $journal_array, 457 'default' => $deljournal 458 ); 459 460 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?'.$param, $langs->trans('DeleteMvt'), $langs->trans('ConfirmDeleteMvt', $langs->transnoentitiesnoconv("RegistrationInAccounting")), 'delbookkeepingyearconfirm', $form_question, '', 1, 300); 461 print $formconfirm; 462} 463 464 465print '<form method="POST" id="searchFormList" action="'.$_SERVER["PHP_SELF"].'">'; 466print '<input type="hidden" name="token" value="'.newToken().'">'; 467print '<input type="hidden" name="action" value="list">'; 468if ($optioncss != '') { 469 print '<input type="hidden" name="optioncss" value="'.$optioncss.'">'; 470} 471print '<input type="hidden" name="formfilteraction" id="formfilteraction" value="list">'; 472print '<input type="hidden" name="sortfield" value="'.$sortfield.'">'; 473print '<input type="hidden" name="sortorder" value="'.$sortorder.'">'; 474 475$parameters = array(); 476$reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook 477if (empty($reshook)) { 478 $newcardbutton = dolGetButtonTitle($langs->trans('ViewFlatList'), '', 'fa fa-list paddingleft imgforviewmode', DOL_URL_ROOT.'/accountancy/bookkeeping/list.php?'.$param); 479 $newcardbutton .= dolGetButtonTitle($langs->trans('GroupByAccountAccounting'), '', 'fa fa-stream paddingleft imgforviewmode', DOL_URL_ROOT.'/accountancy/bookkeeping/listbyaccount.php?'.$param, '', 1, array('morecss' => 'marginleftonly')); 480 $newcardbutton .= dolGetButtonTitle($langs->trans('GroupBySubAccountAccounting'), '', 'fa fa-align-left vmirror paddingleft imgforviewmode', DOL_URL_ROOT.'/accountancy/bookkeeping/listbysubaccount.php?'.$param, '', 1, array('morecss' => 'marginleftonly btnTitleSelected')); 481 $newcardbutton .= dolGetButtonTitle($langs->trans('NewAccountingMvt'), '', 'fa fa-plus-circle paddingleft', DOL_URL_ROOT.'/accountancy/bookkeeping/card.php?action=create'); 482} 483 484if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) { 485 $param .= '&contextpage='.urlencode($contextpage); 486} 487if ($limit > 0 && $limit != $conf->liste_limit) { 488 $param .= '&limit='.urlencode($limit); 489} 490 491print_barre_liste($title_page, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $result, $nbtotalofrecords, 'title_accountancy', 0, $newcardbutton, '', $limit, 0, 0, 1); 492 493print info_admin($langs->trans("WarningRecordWithoutSubledgerAreExcluded")); 494 495$varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage; 496$selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields 497if ($massactionbutton) { 498 $selectedfields .= $form->showCheckAddButtons('checkforselect', 1); 499} 500 501// Reverse sort order 502if (preg_match('/^asc/i', $sortorder)) { 503 $sortorder = "asc"; 504} else { 505 $sortorder = "desc"; 506} 507 508$moreforfilter = ''; 509 510// Accountancy account 511$moreforfilter .= '<div class="divsearchfield">'; 512$moreforfilter .= $langs->trans('AccountAccounting').': '; 513$moreforfilter .= '<div class="nowrap inline-block">'; 514$moreforfilter .= $formaccounting->select_auxaccount($search_accountancy_code_start, 'search_accountancy_code_start', $langs->trans('From'), 'maxwidth200'); 515$moreforfilter .= ' '; 516$moreforfilter .= $formaccounting->select_auxaccount($search_accountancy_code_end, 'search_accountancy_code_end', $langs->trans('to'), 'maxwidth200'); 517$moreforfilter .= '</div>'; 518$moreforfilter .= '</div>'; 519 520$parameters = array(); 521$reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters); // Note that $action and $object may have been modified by hook 522if (empty($reshook)) { 523 $moreforfilter .= $hookmanager->resPrint; 524} else { 525 $moreforfilter = $hookmanager->resPrint; 526} 527 528print '<div class="liste_titre liste_titre_bydiv centpercent">'; 529print $moreforfilter; 530print '</div>'; 531 532print '<div class="div-table-responsive">'; 533print '<table class="tagtable liste centpercent">'; 534 535// Filters lines 536print '<tr class="liste_titre_filter">'; 537 538// Movement number 539if (!empty($arrayfields['t.piece_num']['checked'])) { 540 print '<td class="liste_titre"><input type="text" name="search_mvt_num" size="6" value="'.dol_escape_htmltag($search_mvt_num).'"></td>'; 541} 542// Code journal 543if (!empty($arrayfields['t.code_journal']['checked'])) { 544 print '<td class="liste_titre center">'; 545 print $formaccounting->multi_select_journal($search_ledger_code, 'search_ledger_code', 0, 1, 1, 1); 546 print '</td>'; 547} 548// Date document 549if (!empty($arrayfields['t.doc_date']['checked'])) { 550 print '<td class="liste_titre center">'; 551 print '<div class="nowrap">'; 552 print $form->selectDate($search_date_start, 'search_date_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("From")); 553 print '</div>'; 554 print '<div class="nowrap">'; 555 print $form->selectDate($search_date_end, 'search_date_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to")); 556 print '</div>'; 557 print '</td>'; 558} 559// Ref document 560if (!empty($arrayfields['t.doc_ref']['checked'])) { 561 print '<td class="liste_titre"><input type="text" size="7" class="flat" name="search_doc_ref" value="'.dol_escape_htmltag($search_doc_ref).'"/></td>'; 562} 563// Label operation 564if (!empty($arrayfields['t.label_operation']['checked'])) { 565 print '<td class="liste_titre"><input type="text" size="7" class="flat" name="search_label_operation" value="'.dol_escape_htmltag($search_label_operation).'"/></td>'; 566} 567// Debit 568if (!empty($arrayfields['t.debit']['checked'])) { 569 print '<td class="liste_titre right"><input type="text" class="flat" name="search_debit" size="4" value="'.dol_escape_htmltag($search_debit).'"></td>'; 570} 571// Credit 572if (!empty($arrayfields['t.credit']['checked'])) { 573 print '<td class="liste_titre right"><input type="text" class="flat" name="search_credit" size="4" value="'.dol_escape_htmltag($search_credit).'"></td>'; 574} 575// Lettering code 576if (!empty($arrayfields['t.lettering_code']['checked'])) { 577 print '<td class="liste_titre center">'; 578 print '<input type="text" size="3" class="flat" name="search_lettering_code" value="'.$search_lettering_code.'"/>'; 579 print '<br><span class="nowrap"><input type="checkbox" name="search_not_reconciled" value="notreconciled"'.($search_not_reconciled == 'notreconciled' ? ' checked' : '').'>'.$langs->trans("NotReconciled").'</span>'; 580 print '</td>'; 581} 582// Date export 583if (!empty($arrayfields['t.date_export']['checked'])) { 584 print '<td class="liste_titre center">'; 585 print '<div class="nowrap">'; 586 print $form->selectDate($search_date_export_start, 'search_date_export_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("From")); 587 print '</div>'; 588 print '<div class="nowrap">'; 589 print $form->selectDate($search_date_export_end, 'search_date_export_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to")); 590 print '</div>'; 591 print '</td>'; 592} 593// Date validation 594if (!empty($arrayfields['t.date_validated']['checked'])) { 595 print '<td class="liste_titre center">'; 596 print '<div class="nowrap">'; 597 print $form->selectDate($search_date_validation_start, 'search_date_validation_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("From")); 598 print '</div>'; 599 print '<div class="nowrap">'; 600 print $form->selectDate($search_date_validation_end, 'search_date_validation_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to")); 601 print '</div>'; 602 print '</td>'; 603} 604 605// Fields from hook 606$parameters = array('arrayfields'=>$arrayfields); 607$reshook = $hookmanager->executeHooks('printFieldListOption', $parameters); // Note that $action and $object may have been modified by hook 608print $hookmanager->resPrint; 609 610// Action column 611print '<td class="liste_titre center">'; 612$searchpicto = $form->showFilterButtons(); 613print $searchpicto; 614print '</td>'; 615print "</tr>\n"; 616 617print '<tr class="liste_titre">'; 618if (!empty($arrayfields['t.piece_num']['checked'])) { 619 print_liste_field_titre($arrayfields['t.piece_num']['label'], $_SERVER['PHP_SELF'], "t.piece_num", "", $param, '', $sortfield, $sortorder); 620} 621if (!empty($arrayfields['t.code_journal']['checked'])) { 622 print_liste_field_titre($arrayfields['t.code_journal']['label'], $_SERVER['PHP_SELF'], "t.code_journal", "", $param, '', $sortfield, $sortorder, 'center '); 623} 624if (!empty($arrayfields['t.doc_date']['checked'])) { 625 print_liste_field_titre($arrayfields['t.doc_date']['label'], $_SERVER['PHP_SELF'], "t.doc_date", "", $param, '', $sortfield, $sortorder, 'center '); 626} 627if (!empty($arrayfields['t.doc_ref']['checked'])) { 628 print_liste_field_titre($arrayfields['t.doc_ref']['label'], $_SERVER['PHP_SELF'], "t.doc_ref", "", $param, "", $sortfield, $sortorder); 629} 630if (!empty($arrayfields['t.label_operation']['checked'])) { 631 print_liste_field_titre($arrayfields['t.label_operation']['label'], $_SERVER['PHP_SELF'], "t.label_operation", "", $param, "", $sortfield, $sortorder); 632} 633if (!empty($arrayfields['t.debit']['checked'])) { 634 print_liste_field_titre($arrayfields['t.debit']['label'], $_SERVER['PHP_SELF'], "t.debit", "", $param, '', $sortfield, $sortorder, 'right '); 635} 636if (!empty($arrayfields['t.credit']['checked'])) { 637 print_liste_field_titre($arrayfields['t.credit']['label'], $_SERVER['PHP_SELF'], "t.credit", "", $param, '', $sortfield, $sortorder, 'right '); 638} 639if (!empty($arrayfields['t.lettering_code']['checked'])) { 640 print_liste_field_titre($arrayfields['t.lettering_code']['label'], $_SERVER['PHP_SELF'], "t.lettering_code", "", $param, '', $sortfield, $sortorder, 'center '); 641} 642if (!empty($arrayfields['t.date_export']['checked'])) { 643 print_liste_field_titre($arrayfields['t.date_export']['label'], $_SERVER['PHP_SELF'], "t.date_export", "", $param, '', $sortfield, $sortorder, 'center '); 644} 645if (!empty($arrayfields['t.date_validated']['checked'])) { 646 print_liste_field_titre($arrayfields['t.date_validated']['label'], $_SERVER['PHP_SELF'], "t.date_validated", "", $param, '', $sortfield, $sortorder, 'center '); 647} 648// Hook fields 649$parameters = array('arrayfields'=>$arrayfields, 'param'=>$param, 'sortfield'=>$sortfield, 'sortorder'=>$sortorder); 650$reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters); // Note that $action and $object may have been modified by hook 651print $hookmanager->resPrint; 652print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'center maxwidthsearch '); 653print "</tr>\n"; 654 655 656$total_debit = 0; 657$total_credit = 0; 658$sous_total_debit = 0; 659$sous_total_credit = 0; 660$displayed_account_number = null; // Start with undefined to be able to distinguish with empty 661 662// Loop on record 663// -------------------------------------------------------------------- 664$i = 0; 665$totalarray = array(); 666while ($i < min($num, $limit)) { 667 $line = $object->lines[$i]; 668 669 $total_debit += $line->debit; 670 $total_credit += $line->credit; 671 672 $accountg = length_accounta($line->subledger_account); 673 //if (empty($accountg)) $accountg = '-'; 674 675 $colspan = 0; // colspan before field 'label of operation' 676 $colspanend = 3; // colspan after debit/credit 677 if (!empty($arrayfields['t.piece_num']['checked'])) { $colspan++; } 678 if (!empty($arrayfields['t.code_journal']['checked'])) { $colspan++; } 679 if (!empty($arrayfields['t.doc_date']['checked'])) { $colspan++; } 680 if (!empty($arrayfields['t.doc_ref']['checked'])) { $colspan++; } 681 if (!empty($arrayfields['t.label_operation']['checked'])) { $colspan++; } 682 if (!empty($arrayfields['t.date_export']['checked'])) { $colspanend++; } 683 if (!empty($arrayfields['t.date_validating']['checked'])) { $colspanend++; } 684 if (!empty($arrayfields['t.lettering_code']['checked'])) { $colspanend++; } 685 686 // Is it a break ? 687 if ($accountg != $displayed_account_number || !isset($displayed_account_number)) { 688 // Show a subtotal by accounting account 689 if (isset($displayed_account_number)) { 690 print '<tr class="liste_total">'; 691 print '<td class="right" colspan="'.$colspan.'">'.$langs->trans("TotalForAccount").' '.length_accounta($displayed_account_number).':</td>'; 692 print '<td class="nowrap right">'.price($sous_total_debit).'</td>'; 693 print '<td class="nowrap right">'.price($sous_total_credit).'</td>'; 694 print '<td colspan="'.$colspanend.'"></td>'; 695 print '</tr>'; 696 // Show balance of last shown account 697 $balance = $sous_total_debit - $sous_total_credit; 698 print '<tr class="liste_total">'; 699 print '<td class="right" colspan="'.$colspan.'">'.$langs->trans("Balance").':</td>'; 700 if ($balance > 0) { 701 print '<td class="nowraponall right">'; 702 print price($sous_total_debit - $sous_total_credit); 703 print '</td>'; 704 print '<td></td>'; 705 } else { 706 print '<td></td>'; 707 print '<td class="nowraponall right">'; 708 print price($sous_total_credit - $sous_total_debit); 709 print '</td>'; 710 } 711 print '<td colspan="'.$colspanend.'"></td>'; 712 print '</tr>'; 713 } 714 715 // Show the break account 716 print "<tr>"; 717 print '<td colspan="'.($totalarray['nbfield'] ? $totalarray['nbfield'] : 10).'" style="font-weight:bold; border-bottom: 1pt solid black;">'; 718 if ($line->subledger_account != "" && $line->subledger_account != '-1') { 719 print $line->subledger_label.' : '.length_accounta($line->subledger_account); 720 } else { 721 // Should not happen: subledger account must be null or a non empty value 722 print '<span class="error">'.$langs->trans("Unknown"); 723 if ($line->subledger_label) { 724 print ' ('.$line->subledger_label.')'; 725 $htmltext = 'EmptyStringForSubledgerAccountButSubledgerLabelDefined'; 726 } else { 727 $htmltext = 'EmptyStringForSubledgerAccountAndSubledgerLabel'; 728 } 729 print $form->textwithpicto('', $htmltext); 730 print '</span>'; 731 } 732 print '</td>'; 733 print '</tr>'; 734 735 $displayed_account_number = $accountg; 736 //if (empty($displayed_account_number)) $displayed_account_number='-'; 737 $sous_total_debit = 0; 738 $sous_total_credit = 0; 739 740 $colspan = 0; 741 } 742 743 print '<tr class="oddeven">'; 744 745 // Piece number 746 if (!empty($arrayfields['t.piece_num']['checked'])) { 747 print '<td>'; 748 $object->id = $line->id; 749 $object->piece_num = $line->piece_num; 750 print $object->getNomUrl(1, '', 0, '', 1); 751 print '</td>'; 752 if (!$i) { 753 $totalarray['nbfield']++; 754 } 755 } 756 757 // Journal code 758 if (!empty($arrayfields['t.code_journal']['checked'])) { 759 $accountingjournal = new AccountingJournal($db); 760 $result = $accountingjournal->fetch('', $line->code_journal); 761 $journaltoshow = (($result > 0) ? $accountingjournal->getNomUrl(0, 0, 0, '', 0) : $line->code_journal); 762 print '<td class="center">'.$journaltoshow.'</td>'; 763 if (!$i) { 764 $totalarray['nbfield']++; 765 } 766 } 767 768 // Document date 769 if (!empty($arrayfields['t.doc_date']['checked'])) { 770 print '<td class="center">'.dol_print_date($line->doc_date, 'day').'</td>'; 771 if (!$i) { 772 $totalarray['nbfield']++; 773 } 774 } 775 776 // Document ref 777 if (!empty($arrayfields['t.doc_ref']['checked'])) { 778 if ($line->doc_type == 'customer_invoice') { 779 $langs->loadLangs(array('bills')); 780 781 require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php'; 782 $objectstatic = new Facture($db); 783 $objectstatic->fetch($line->fk_doc); 784 //$modulepart = 'facture'; 785 786 $filename = dol_sanitizeFileName($line->doc_ref); 787 $filedir = $conf->facture->dir_output.'/'.dol_sanitizeFileName($line->doc_ref); 788 $urlsource = $_SERVER['PHP_SELF'].'?id='.$objectstatic->id; 789 $documentlink = $formfile->getDocumentsLink($objectstatic->element, $filename, $filedir); 790 } elseif ($line->doc_type == 'supplier_invoice') { 791 $langs->loadLangs(array('bills')); 792 793 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php'; 794 $objectstatic = new FactureFournisseur($db); 795 $objectstatic->fetch($line->fk_doc); 796 //$modulepart = 'invoice_supplier'; 797 798 $filename = dol_sanitizeFileName($line->doc_ref); 799 $filedir = $conf->fournisseur->facture->dir_output.'/'.get_exdir($line->fk_doc, 2, 0, 0, $objectstatic, $modulepart).dol_sanitizeFileName($line->doc_ref); 800 $subdir = get_exdir($objectstatic->id, 2, 0, 0, $objectstatic, $modulepart).dol_sanitizeFileName($line->doc_ref); 801 $documentlink = $formfile->getDocumentsLink($objectstatic->element, $subdir, $filedir); 802 } elseif ($line->doc_type == 'expense_report') { 803 $langs->loadLangs(array('trips')); 804 805 require_once DOL_DOCUMENT_ROOT.'/expensereport/class/expensereport.class.php'; 806 $objectstatic = new ExpenseReport($db); 807 $objectstatic->fetch($line->fk_doc); 808 //$modulepart = 'expensereport'; 809 810 $filename = dol_sanitizeFileName($line->doc_ref); 811 $filedir = $conf->expensereport->dir_output.'/'.dol_sanitizeFileName($line->doc_ref); 812 $urlsource = $_SERVER['PHP_SELF'].'?id='.$objectstatic->id; 813 $documentlink = $formfile->getDocumentsLink($objectstatic->element, $filename, $filedir); 814 } elseif ($line->doc_type == 'bank') { 815 require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php'; 816 $objectstatic = new AccountLine($db); 817 $objectstatic->fetch($line->fk_doc); 818 } else { 819 // Other type 820 } 821 822 print '<td class="maxwidth400">'; 823 824 print '<table class="nobordernopadding"><tr class="nocellnopadd">'; 825 // Picto + Ref 826 print '<td class="nobordernopadding">'; 827 828 if ($line->doc_type == 'customer_invoice' || $line->doc_type == 'supplier_invoice' || $line->doc_type == 'expense_report') { 829 print $objectstatic->getNomUrl(1, '', 0, 0, '', 0, -1, 1); 830 print $documentlink; 831 } elseif ($line->doc_type == 'bank') { 832 print $objectstatic->getNomUrl(1); 833 $bank_ref = strstr($line->doc_ref, '-'); 834 print " " . $bank_ref; 835 } else { 836 print $line->doc_ref; 837 } 838 print '</td></tr></table>'; 839 840 print "</td>\n"; 841 if (!$i) { 842 $totalarray['nbfield']++; 843 } 844 } 845 846 // Label operation 847 if (!empty($arrayfields['t.label_operation']['checked'])) { 848 // Affiche un lien vers la facture client/fournisseur 849 $doc_ref = preg_replace('/\(.*\)/', '', $line->doc_ref); 850 print strlen(length_accounta($line->subledger_account)) == 0 ? '<td>'.$line->label_operation.'</td>' : '<td>'.$line->label_operation.'<br><span style="font-size:0.8em">('.length_accounta($line->subledger_account).')</span></td>'; 851 if (!$i) { 852 $totalarray['nbfield']++; 853 } 854 } 855 856 // Amount debit 857 if (!empty($arrayfields['t.debit']['checked'])) { 858 print '<td class="right nowraponall amount">'.($line->debit ? price($line->debit) : '').'</td>'; 859 if (!$i) { 860 $totalarray['nbfield']++; 861 } 862 if (!$i) { 863 $totalarray['pos'][$totalarray['nbfield']] = 'totaldebit'; 864 } 865 $totalarray['val']['totaldebit'] += $line->debit; 866 } 867 868 // Amount credit 869 if (!empty($arrayfields['t.credit']['checked'])) { 870 print '<td class="right nowraponall amount">'.($line->credit ? price($line->credit) : '').'</td>'; 871 if (!$i) { 872 $totalarray['nbfield']++; 873 } 874 if (!$i) { 875 $totalarray['pos'][$totalarray['nbfield']] = 'totalcredit'; 876 } 877 $totalarray['val']['totalcredit'] += $line->credit; 878 } 879 880 // Lettering code 881 if (!empty($arrayfields['t.lettering_code']['checked'])) { 882 print '<td class="center">'.$line->lettering_code.'</td>'; 883 if (!$i) { 884 $totalarray['nbfield']++; 885 } 886 } 887 888 // Exported operation date 889 if (!empty($arrayfields['t.date_export']['checked'])) { 890 print '<td class="center">'.dol_print_date($line->date_export, 'dayhour').'</td>'; 891 if (!$i) { 892 $totalarray['nbfield']++; 893 } 894 } 895 896 // Validated operation date 897 if (!empty($arrayfields['t.date_validated']['checked'])) { 898 print '<td class="center">'.dol_print_date($line->date_validation, 'dayhour').'</td>'; 899 if (!$i) { 900 $totalarray['nbfield']++; 901 } 902 } 903 904 // Fields from hook 905 $parameters = array('arrayfields'=>$arrayfields, 'obj'=>$obj); 906 $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters); // Note that $action and $object may have been modified by hook 907 print $hookmanager->resPrint; 908 909 // Action column 910 print '<td class="nowraponall center">'; 911 if (empty($line->date_export) && empty($line->date_validation)) { 912 if ($user->rights->accounting->mouvements->creer) { 913 print '<a class="editfielda paddingleft marginrightonly" href="' . DOL_URL_ROOT . '/accountancy/bookkeeping/card.php?piece_num=' . $line->piece_num . $param . '&page=' . $page . ($sortfield ? '&sortfield=' . $sortfield : '') . ($sortorder ? '&sortorder=' . $sortorder : '') . '">' . img_edit() . '</a>'; 914 } 915 } 916 if (empty($line->date_validation)) { 917 if ($user->rights->accounting->mouvements->supprimer) { 918 print '<a class="reposition paddingleft marginrightonly" href="'.$_SERVER['PHP_SELF'].'?action=delmouv&mvt_num='.$line->piece_num.$param.'&page='.$page.($sortfield ? '&sortfield='.$sortfield : '').($sortorder ? '&sortorder='.$sortorder : '').'">'.img_delete().'</a>'; 919 } 920 } 921 print '</td>'; 922 if (!$i) { 923 $totalarray['nbfield']++; 924 } 925 926 // Comptabilise le sous-total 927 $sous_total_debit += $line->debit; 928 $sous_total_credit += $line->credit; 929 930 print "</tr>\n"; 931 932 $i++; 933} 934 935if ($num > 0 && $colspan > 0) { 936 print '<tr class="liste_total">'; 937 print '<td class="right" colspan="'.$colspan.'">'.$langs->trans("TotalForAccount").' '.$accountg.':</td>'; 938 print '<td class="nowrap right">'.price($sous_total_debit).'</td>'; 939 print '<td class="nowrap right">'.price($sous_total_credit).'</td>'; 940 print '<td colspan="'.$colspanend.'"></td>'; 941 print '</tr>'; 942 // Show balance of last shown account 943 $balance = $sous_total_debit - $sous_total_credit; 944 print '<tr class="liste_total">'; 945 print '<td class="right" colspan="'.$colspan.'">'.$langs->trans("Balance").':</td>'; 946 if ($balance > 0) { 947 print '<td class="nowraponall right">'; 948 print price($sous_total_debit - $sous_total_credit); 949 print '</td>'; 950 print '<td></td>'; 951 } else { 952 print '<td></td>'; 953 print '<td class="nowraponall right">'; 954 print price($sous_total_credit - $sous_total_debit); 955 print '</td>'; 956 } 957 print '<td colspan="'.$colspanend.'"></td>'; 958 print '</tr>'; 959} 960 961// Show total line 962include DOL_DOCUMENT_ROOT.'/core/tpl/list_print_total.tpl.php'; 963 964 965print "</table>"; 966print '</div>'; 967 968// TODO Replace this with mass delete action 969if ($user->rights->accounting->mouvements->supprimer_tous) { 970 print '<div class="tabsAction tabsActionNoBottom">'."\n"; 971 print '<a class="butActionDelete" name="button_delmvt" href="'.$_SERVER["PHP_SELF"].'?action=delbookkeepingyear'.($param ? '&'.$param : '').'">'.$langs->trans("DeleteMvt").'</a>'; 972 print '</div>'; 973} 974 975print '</form>'; 976 977// End of page 978llxFooter(); 979$db->close(); 980