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