balance.php 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  1. <?php
  2. /* Copyright (C) 2016 Olivier Geffroy <jeff@jeffinfo.com>
  3. * Copyright (C) 2016 Florian Henry <florian.henry@open-concept.pro>
  4. * Copyright (C) 2016-2022 Alexandre Spangaro <aspangaro@open-dsi.fr>
  5. * Copyright (C) 2018 Frédéric France <frederic.france@netlogic.fr>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  19. */
  20. /**
  21. * \file htdocs/accountancy/bookkeeping/balance.php
  22. * \ingroup Accountancy (Double entries)
  23. * \brief Balance of book keeping
  24. */
  25. // Load Dolibarr environment
  26. require '../../main.inc.php';
  27. // Class
  28. require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php';
  29. require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
  30. require_once DOL_DOCUMENT_ROOT.'/accountancy/class/bookkeeping.class.php';
  31. require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingjournal.class.php';
  32. require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingaccount.class.php';
  33. require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountancyexport.class.php';
  34. require_once DOL_DOCUMENT_ROOT.'/core/class/html.formaccounting.class.php';
  35. require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
  36. // Load translation files required by the page
  37. $langs->loadLangs(array("accountancy", "compta"));
  38. $action = GETPOST('action', 'aZ09');
  39. $optioncss = GETPOST('optioncss', 'alpha');
  40. $contextpage = GETPOST('contextpage', 'aZ09');
  41. // Load variable for pagination
  42. $limit = GETPOST('limit', 'int') ?GETPOST('limit', 'int') : $conf->liste_limit;
  43. $sortfield = GETPOST('sortfield', 'aZ09comma');
  44. $sortorder = GETPOST('sortorder', 'aZ09comma');
  45. $page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int');
  46. if (empty($page) || $page == -1 || GETPOST('button_search', 'alpha') || GETPOST('button_removefilter', 'alpha') || (empty($toselect) && $massaction === '0')) {
  47. $page = 0;
  48. } // If $page is not defined, or '' or -1 or if we click on clear filters or if we select empty mass action
  49. $offset = $limit * $page;
  50. $pageprev = $page - 1;
  51. $pagenext = $page + 1;
  52. //if (! $sortfield) $sortfield="p.date_fin";
  53. //if (! $sortorder) $sortorder="DESC";
  54. $show_subgroup = GETPOST('show_subgroup', 'alpha');
  55. $search_date_start = dol_mktime(0, 0, 0, GETPOST('date_startmonth', 'int'), GETPOST('date_startday', 'int'), GETPOST('date_startyear', 'int'));
  56. $search_date_end = dol_mktime(23, 59, 59, GETPOST('date_endmonth', 'int'), GETPOST('date_endday', 'int'), GETPOST('date_endyear', 'int'));
  57. $search_ledger_code = GETPOST('search_ledger_code', 'array');
  58. $search_accountancy_code_start = GETPOST('search_accountancy_code_start', 'alpha');
  59. if ($search_accountancy_code_start == - 1) {
  60. $search_accountancy_code_start = '';
  61. }
  62. $search_accountancy_code_end = GETPOST('search_accountancy_code_end', 'alpha');
  63. if ($search_accountancy_code_end == - 1) {
  64. $search_accountancy_code_end = '';
  65. }
  66. // Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
  67. $object = new BookKeeping($db);
  68. $hookmanager->initHooks(array('balancelist')); // Note that conf->hooks_modules contains array
  69. $formaccounting = new FormAccounting($db);
  70. $formother = new FormOther($db);
  71. $form = new Form($db);
  72. if (empty($search_date_start) && !GETPOSTISSET('formfilteraction')) {
  73. $sql = "SELECT date_start, date_end from ".MAIN_DB_PREFIX."accounting_fiscalyear ";
  74. $sql .= " WHERE date_start < '".$db->idate(dol_now())."' AND date_end > '".$db->idate(dol_now())."'";
  75. $sql .= $db->plimit(1);
  76. $res = $db->query($sql);
  77. if ($res->num_rows > 0) {
  78. $fiscalYear = $db->fetch_object($res);
  79. $search_date_start = strtotime($fiscalYear->date_start);
  80. $search_date_end = strtotime($fiscalYear->date_end);
  81. } else {
  82. $month_start = ($conf->global->SOCIETE_FISCAL_MONTH_START ? ($conf->global->SOCIETE_FISCAL_MONTH_START) : 1);
  83. $year_start = dol_print_date(dol_now(), '%Y');
  84. if (dol_print_date(dol_now(), '%m') < $month_start) {
  85. $year_start--; // If current month is lower that starting fiscal month, we start last year
  86. }
  87. $year_end = $year_start + 1;
  88. $month_end = $month_start - 1;
  89. if ($month_end < 1) {
  90. $month_end = 12;
  91. $year_end--;
  92. }
  93. $search_date_start = dol_mktime(0, 0, 0, $month_start, 1, $year_start);
  94. $search_date_end = dol_get_last_day($year_end, $month_end);
  95. }
  96. }
  97. if ($sortorder == "") {
  98. $sortorder = "ASC";
  99. }
  100. if ($sortfield == "") {
  101. $sortfield = "t.numero_compte";
  102. }
  103. $param = '';
  104. if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) {
  105. $param .= '&contextpage='.urlencode($contextpage);
  106. }
  107. if ($limit > 0 && $limit != $conf->liste_limit) {
  108. $param .= '&limit='.urlencode($limit);
  109. }
  110. $filter = array();
  111. if (!empty($search_date_start)) {
  112. $filter['t.doc_date>='] = $search_date_start;
  113. $param .= '&date_startmonth='.GETPOST('date_startmonth', 'int').'&date_startday='.GETPOST('date_startday', 'int').'&date_startyear='.GETPOST('date_startyear', 'int');
  114. }
  115. if (!empty($search_date_end)) {
  116. $filter['t.doc_date<='] = $search_date_end;
  117. $param .= '&date_endmonth='.GETPOST('date_endmonth', 'int').'&date_endday='.GETPOST('date_endday', 'int').'&date_endyear='.GETPOST('date_endyear', 'int');
  118. }
  119. if (!empty($search_accountancy_code_start)) {
  120. $filter['t.numero_compte>='] = $search_accountancy_code_start;
  121. $param .= '&search_accountancy_code_start='.urlencode($search_accountancy_code_start);
  122. }
  123. if (!empty($search_accountancy_code_end)) {
  124. $filter['t.numero_compte<='] = $search_accountancy_code_end;
  125. $param .= '&search_accountancy_code_end='.urlencode($search_accountancy_code_end);
  126. }
  127. if (!empty($search_ledger_code)) {
  128. $filter['t.code_journal'] = $search_ledger_code;
  129. foreach ($search_ledger_code as $code) {
  130. $param .= '&search_ledger_code[]='.urlencode($code);
  131. }
  132. }
  133. if (!isModEnabled('accounting')) {
  134. accessforbidden();
  135. }
  136. if ($user->socid > 0) {
  137. accessforbidden();
  138. }
  139. if (!$user->hasRight('accounting', 'mouvements', 'lire')) {
  140. accessforbidden();
  141. }
  142. /*
  143. * Action
  144. */
  145. $parameters = array();
  146. $arrayfields = array();
  147. $reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
  148. if ($reshook < 0) {
  149. setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  150. }
  151. if (empty($reshook)) {
  152. 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
  153. $show_subgroup = '';
  154. $search_date_start = '';
  155. $search_date_end = '';
  156. $search_accountancy_code_start = '';
  157. $search_accountancy_code_end = '';
  158. $search_ledger_code = array();
  159. $filter = array();
  160. }
  161. }
  162. /*
  163. * View
  164. */
  165. if ($action == 'export_csv') {
  166. $sep = $conf->global->ACCOUNTING_EXPORT_SEPARATORCSV;
  167. $filename = 'balance';
  168. $type_export = 'balance';
  169. include DOL_DOCUMENT_ROOT.'/accountancy/tpl/export_journal.tpl.php';
  170. $result = $object->fetchAllBalance($sortorder, $sortfield, $limit, 0, $filter);
  171. if ($result < 0) {
  172. setEventMessages($object->error, $object->errors, 'errors');
  173. }
  174. foreach ($object->lines as $line) {
  175. print '"'.length_accountg($line->numero_compte).'"'.$sep;
  176. print '"'.$object->get_compte_desc($line->numero_compte).'"'.$sep;
  177. print '"'.price($line->debit).'"'.$sep;
  178. print '"'.price($line->credit).'"'.$sep;
  179. print '"'.price($line->debit - $line->credit).'"'.$sep;
  180. print "\n";
  181. }
  182. exit;
  183. }
  184. $title_page = $langs->trans("AccountBalance");
  185. llxHeader('', $title_page);
  186. if ($action != 'export_csv') {
  187. // List
  188. $nbtotalofrecords = '';
  189. if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) {
  190. $nbtotalofrecords = $object->fetchAllBalance($sortorder, $sortfield, 0, 0, $filter);
  191. if ($nbtotalofrecords < 0) {
  192. setEventMessages($object->error, $object->errors, 'errors');
  193. }
  194. }
  195. $result = $object->fetchAllBalance($sortorder, $sortfield, $limit, $offset, $filter);
  196. if ($result < 0) {
  197. setEventMessages($object->error, $object->errors, 'errors');
  198. }
  199. print '<form method="POST" id="searchFormList" action="'.$_SERVER["PHP_SELF"].'">';
  200. if ($optioncss != '') {
  201. print '<input type="hidden" name="optioncss" value="'.$optioncss.'">';
  202. }
  203. print '<input type="hidden" name="token" value="'.newToken().'">';
  204. print '<input type="hidden" name="formfilteraction" id="formfilteraction" value="list">';
  205. print '<input type="hidden" name="action" id="action" value="list">';
  206. print '<input type="hidden" name="sortfield" value="'.$sortfield.'">';
  207. print '<input type="hidden" name="sortorder" value="'.$sortorder.'">';
  208. print '<input type="hidden" name="page" value="'.$page.'">';
  209. $parameters = array();
  210. $reshook = $hookmanager->executeHooks('addMoreActionsButtonsList', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
  211. if ($reshook < 0) {
  212. setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  213. }
  214. $button = empty($hookmanager->resPrint) ? '' : $hookmanager->resPrint;
  215. if (empty($reshook)) {
  216. $button .= '<input type="button" id="exportcsvbutton" name="exportcsvbutton" class="butAction" value="'.$langs->trans("Export").' ('.$conf->global->ACCOUNTING_EXPORT_FORMAT.')" />';
  217. print '<script type="text/javascript">
  218. jQuery(document).ready(function() {
  219. jQuery("#exportcsvbutton").click(function() {
  220. event.preventDefault();
  221. console.log("Set action to export_csv");
  222. jQuery("#action").val("export_csv");
  223. jQuery("#searchFormList").submit();
  224. jQuery("#action").val("list");
  225. });
  226. });
  227. </script>';
  228. }
  229. print_barre_liste($title_page, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $button, $result, $nbtotalofrecords, 'title_accountancy', 0, '', '', $limit);
  230. $selectedfields = '';
  231. $moreforfilter = '';
  232. $moreforfilter .= '<div class="divsearchfield">';
  233. $moreforfilter .= $langs->trans('DateStart').': ';
  234. $moreforfilter .= $form->selectDate($search_date_start ? $search_date_start : -1, 'date_start', 0, 0, 1, '', 1, 0);
  235. $moreforfilter .= $langs->trans('DateEnd').': ';
  236. $moreforfilter .= $form->selectDate($search_date_end ? $search_date_end : -1, 'date_end', 0, 0, 1, '', 1, 0);
  237. $moreforfilter .= ' - ';
  238. $moreforfilter .= '<label for="show_subgroup">'.$langs->trans('ShowSubtotalByGroup').'</label>: ';
  239. $moreforfilter .= '<input type="checkbox" name="show_subgroup" id="show_subgroup" value="show_subgroup"'.($show_subgroup == 'show_subgroup' ? ' checked' : '').'>';
  240. $moreforfilter .= '</div>';
  241. $moreforfilter .= '<div class="divsearchfield">';
  242. $moreforfilter .= $langs->trans("Journal");
  243. $moreforfilter .= $formaccounting->multi_select_journal($search_ledger_code, 'search_ledger_code', 0, 1, 1, 1);
  244. $moreforfilter .= '</div>';
  245. if (!empty($moreforfilter)) {
  246. print '<div class="liste_titre liste_titre_bydiv centpercent">';
  247. print $moreforfilter;
  248. $parameters = array();
  249. $reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters); // Note that $action and $object may have been modified by hook
  250. print $hookmanager->resPrint;
  251. print '</div>';
  252. }
  253. $colspan = (!empty($conf->global->ACCOUNTANCY_SHOW_OPENING_BALANCE) ? 5 : 4);
  254. print '<table class="liste '.($moreforfilter ? "listwithfilterbefore" : "").'">';
  255. print '<tr class="liste_titre_filter">';
  256. print '<td class="liste_titre" colspan="'.$colspan.'">';
  257. print $formaccounting->select_account($search_accountancy_code_start, 'search_accountancy_code_start', $langs->trans('From'), array(), 1, 1, '', 'accounts');
  258. print ' ';
  259. print $formaccounting->select_account($search_accountancy_code_end, 'search_accountancy_code_end', $langs->trans('to'), array(), 1, 1, '', 'accounts');
  260. print '</td>';
  261. // Fields from hook
  262. $parameters = array('arrayfields'=>$arrayfields);
  263. $reshook = $hookmanager->executeHooks('printFieldListOption', $parameters, $object); // Note that $action and $object may have been modified by hook
  264. print $hookmanager->resPrint;
  265. // Action column
  266. print '<td class="liste_titre maxwidthsearch">';
  267. $searchpicto = $form->showFilterButtons();
  268. print $searchpicto;
  269. print '</td>';
  270. print '</tr>'."\n";
  271. print '<tr class="liste_titre">';
  272. print_liste_field_titre("AccountAccounting", $_SERVER['PHP_SELF'], "t.numero_compte", "", $param, "", $sortfield, $sortorder);
  273. if (!empty($conf->global->ACCOUNTANCY_SHOW_OPENING_BALANCE)) {
  274. print_liste_field_titre("OpeningBalance", $_SERVER['PHP_SELF'], "", $param, "", 'class="right"', $sortfield, $sortorder);
  275. }
  276. print_liste_field_titre("Debit", $_SERVER['PHP_SELF'], "t.debit", "", $param, 'class="right"', $sortfield, $sortorder);
  277. print_liste_field_titre("Credit", $_SERVER['PHP_SELF'], "t.credit", "", $param, 'class="right"', $sortfield, $sortorder);
  278. print_liste_field_titre("Balance", $_SERVER["PHP_SELF"], "", $param, "", 'class="right"', $sortfield, $sortorder);
  279. // Hook fields
  280. $parameters = array('arrayfields'=>$arrayfields, 'param'=>$param, 'sortfield'=>$sortfield, 'sortorder'=>$sortorder);
  281. $reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters, $object); // Note that $action and $object may have been modified by hook
  282. print $hookmanager->resPrint;
  283. // Action column
  284. print getTitleFieldOfList($selectedfields, 0, $_SERVER["PHP_SELF"], '', '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ')."\n";
  285. print '</tr>'."\n";
  286. $total_debit = 0;
  287. $total_credit = 0;
  288. $sous_total_debit = 0;
  289. $sous_total_credit = 0;
  290. $total_opening_balance = 0;
  291. $sous_total_opening_balance = 0;
  292. $displayed_account = "";
  293. $accountingaccountstatic = new AccountingAccount($db);
  294. // TODO Debug - This feature is dangerous, it takes all the entries and adds all the accounts
  295. // without time and class limits (Class 6 and 7 accounts ???) and does not take into account the "a-nouveau" journal.
  296. if (!empty($conf->global->ACCOUNTANCY_SHOW_OPENING_BALANCE)) {
  297. $sql = "SELECT t.numero_compte, (SUM(t.debit) - SUM(t.credit)) as opening_balance";
  298. $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping as t";
  299. $sql .= " WHERE t.entity = " . $conf->entity; // Never do sharing into accounting features
  300. $sql .= " AND t.doc_date < '" . $db->idate($search_date_start) . "'";
  301. $sql .= " GROUP BY t.numero_compte";
  302. $resql = $db->query($sql);
  303. $nrows = $db->num_rows($resql);
  304. $opening_balances = array();
  305. for ($i = 0; $i < $nrows; $i++) {
  306. $arr = $resql->fetch_array();
  307. $opening_balances["'" . $arr['numero_compte'] . "'"] = $arr['opening_balance'];
  308. }
  309. }
  310. foreach ($object->lines as $line) {
  311. // reset before the fetch (in case of the fetch fails)
  312. $accountingaccountstatic->id = 0;
  313. $accountingaccountstatic->account_number = '';
  314. $accountingaccountstatic->fetch(null, $line->numero_compte, true);
  315. if (!empty($accountingaccountstatic->account_number)) {
  316. $accounting_account = $accountingaccountstatic->getNomUrl(0, 1, 0, '', 0, -1, 0, 'accountcard');
  317. } else {
  318. $accounting_account = length_accountg($line->numero_compte);
  319. }
  320. $link = '';
  321. $total_debit += $line->debit;
  322. $total_credit += $line->credit;
  323. $opening_balance = isset($opening_balances["'".$line->numero_compte."'"]) ? $opening_balances["'".$line->numero_compte."'"] : 0;
  324. $total_opening_balance += $opening_balance;
  325. $tmparrayforrootaccount = $object->getRootAccount($line->numero_compte);
  326. $root_account_description = $tmparrayforrootaccount['label'];
  327. $root_account_number = $tmparrayforrootaccount['account_number'];
  328. //var_dump($tmparrayforrootaccount);
  329. //var_dump($accounting_account);
  330. //var_dump($accountingaccountstatic);
  331. if (empty($accountingaccountstatic->label) && $accountingaccountstatic->id > 0) {
  332. $link = '<a class="editfielda reposition" href="' . DOL_URL_ROOT . '/accountancy/admin/card.php?action=update&token=' . newToken() . '&id=' . $accountingaccountstatic->id . '">' . img_edit() . '</a>';
  333. } elseif ($accounting_account == 'NotDefined') {
  334. $link = '<a href="' . DOL_URL_ROOT . '/accountancy/admin/card.php?action=create&token=' . newToken() . '&accountingaccount=' . length_accountg($line->numero_compte) . '">' . img_edit_add() . '</a>';
  335. } elseif (empty($tmparrayforrootaccount['label'])) {
  336. // $tmparrayforrootaccount['label'] not defined = the account has not parent with a parent.
  337. // This is useless, we should not create a new account when an account has no parent, we must edit it to fix its parent.
  338. // BUG 1: Accounts on level root or level 1 must not have a parent 2 level higher, so should not show a link to create another account.
  339. // BUG 2: Adding a link to create a new accounting account here is useless because it is not add as parent of the orphelin.
  340. //$link = '<a href="' . DOL_URL_ROOT . '/accountancy/admin/card.php?action=create&token=' . newToken() . '&accountingaccount=' . length_accountg($line->numero_compte) . '">' . img_edit_add() . '</a>';
  341. }
  342. if (!empty($show_subgroup)) {
  343. // Show accounting account
  344. if (empty($displayed_account) || $root_account_number != $displayed_account) {
  345. // Show subtotal per accounting account
  346. if ($displayed_account != "") {
  347. print '<tr class="liste_total">';
  348. print '<td class="right">'.$langs->trans("SubTotal").':</td>';
  349. if (!empty($conf->global->ACCOUNTANCY_SHOW_OPENING_BALANCE)) {
  350. print '<td class="right nowraponall amount">'.price($sous_total_opening_balance).'</td>';
  351. }
  352. print '<td class="right nowraponall amount">'.price($sous_total_debit).'</td>';
  353. print '<td class="right nowraponall amount">'.price($sous_total_credit).'</td>';
  354. if (!empty($conf->global->ACCOUNTANCY_SHOW_OPENING_BALANCE)) {
  355. print '<td class="right nowraponall amount">'.price(price2num($sous_total_opening_balance + $sous_total_debit - $sous_total_credit)).'</td>';
  356. } else {
  357. print '<td class="right nowraponall amount">'.price(price2num($sous_total_debit - $sous_total_credit)).'</td>';
  358. }
  359. print "<td></td>\n";
  360. print '</tr>';
  361. }
  362. // Show first line of a break
  363. print '<tr class="trforbreak">';
  364. print '<td colspan="'.($colspan+1).'" class="tdforbreak">'.$line->numero_compte.($root_account_description ? ' - '.$root_account_description : '').'</td>';
  365. print '</tr>';
  366. $displayed_account = $root_account_number;
  367. $sous_total_debit = 0;
  368. $sous_total_credit = 0;
  369. $sous_total_opening_balance = 0;
  370. }
  371. }
  372. print '<tr class="oddeven">';
  373. print '<td>'.$accounting_account.'</td>';
  374. if (!empty($conf->global->ACCOUNTANCY_SHOW_OPENING_BALANCE)) {
  375. print '<td class="right nowraponall amount">'.price(price2num($opening_balance, 'MT')).'</td>';
  376. }
  377. $urlzoom = '';
  378. if ($line->numero_compte) {
  379. $urlzoom = DOL_URL_ROOT.'/accountancy/bookkeeping/listbyaccount.php?search_accountancy_code_start='.urlencode($line->numero_compte).'&search_accountancy_code_end='.urlencode($line->numero_compte);
  380. if (GETPOSTISSET('date_startmonth')) {
  381. $urlzoom .= '&search_date_startmonth='.GETPOST('date_startmonth', 'int').'&search_date_startday='.GETPOST('date_startday', 'int').'&search_date_startyear='.GETPOST('date_startyear', 'int');
  382. }
  383. if (GETPOSTISSET('date_endmonth')) {
  384. $urlzoom .= '&search_date_endmonth='.GETPOST('date_endmonth', 'int').'&search_date_endday='.GETPOST('date_endday', 'int').'&search_date_endyear='.GETPOST('date_endyear', 'int');
  385. }
  386. }
  387. // Debit
  388. print '<td class="right nowraponall amount"><a href="'.$urlzoom.'">'.price(price2num($line->debit, 'MT')).'</a></td>';
  389. // Credit
  390. print '<td class="right nowraponall amount"><a href="'.$urlzoom.'">'.price(price2num($line->credit, 'MT')).'</a></td>';
  391. if (!empty($conf->global->ACCOUNTANCY_SHOW_OPENING_BALANCE)) {
  392. print '<td class="right nowraponall amount">'.price(price2num($opening_balance + $line->debit - $line->credit, 'MT')).'</td>';
  393. } else {
  394. print '<td class="right nowraponall amount">'.price(price2num($line->debit - $line->credit, 'MT')).'</td>';
  395. }
  396. print '<td class="center">';
  397. print $link;
  398. print '</td>';
  399. print "</tr>\n";
  400. // Records the sub-total
  401. $sous_total_debit += $line->debit;
  402. $sous_total_credit += $line->credit;
  403. $sous_total_opening_balance += $opening_balance;
  404. }
  405. if (!empty($show_subgroup)) {
  406. print '<tr class="liste_total"><td class="right">'.$langs->trans("SubTotal").':</td>';
  407. if (!empty($conf->global->ACCOUNTANCY_SHOW_OPENING_BALANCE)) {
  408. print '<td class="right nowraponall amount">'.price(price2num($sous_total_opening_balance, 'MT')).'</td>';
  409. }
  410. print '<td class="right nowraponall amount">'.price(price2num($sous_total_debit, 'MT')).'</td>';
  411. print '<td class="right nowraponall amount">'.price(price2num($sous_total_credit, 'MT')).'</td>';
  412. if (!empty($conf->global->ACCOUNTANCY_SHOW_OPENING_BALANCE)) {
  413. print '<td class="right nowraponall amount">' . price(price2num($sous_total_opening_balance + $sous_total_debit - $sous_total_credit, 'MT')) . '</td>';
  414. } else {
  415. print '<td class="right nowraponall amount">' . price(price2num($sous_total_debit - $sous_total_credit, 'MT')) . '</td>';
  416. }
  417. print "<td></td>\n";
  418. print '</tr>';
  419. }
  420. print '<tr class="liste_total"><td class="right">'.$langs->trans("AccountBalance").':</td>';
  421. if (!empty($conf->global->ACCOUNTANCY_SHOW_OPENING_BALANCE)) {
  422. print '<td class="nowrap right">'.price(price2num($total_opening_balance, 'MT')).'</td>';
  423. }
  424. print '<td class="right nowraponall amount">'.price(price2num($total_debit, 'MT')).'</td>';
  425. print '<td class="right nowraponall amount">'.price(price2num($total_credit, 'MT')).'</td>';
  426. if (!empty($conf->global->ACCOUNTANCY_SHOW_OPENING_BALANCE)) {
  427. print '<td class="right nowraponall amount">' . price(price2num($total_opening_balance + $total_debit - $total_credit, 'MT')) . '</td>';
  428. } else {
  429. print '<td class="right nowraponall amount">' . price(price2num($total_debit - $total_credit, 'MT')) . '</td>';
  430. }
  431. print "<td></td>\n";
  432. print '</tr>';
  433. $parameters = array('arrayfields'=>$arrayfields, 'sql'=>$sql);
  434. $reshook = $hookmanager->executeHooks('printFieldListFooter', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
  435. print $hookmanager->resPrint;
  436. print "</table>";
  437. print '</form>';
  438. }
  439. // End of page
  440. llxFooter();
  441. $db->close();