dolibarr 21.0.3
expensereportsjournal.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2007-2010 Laurent Destailleur <eldy@users.sourceforge.net>
3 * Copyright (C) 2007-2010 Jean Heimburger <jean@tiaris.info>
4 * Copyright (C) 2011 Juanjo Menent <jmenent@2byte.es>
5 * Copyright (C) 2012 Regis Houssin <regis.houssin@inodbox.com>
6 * Copyright (C) 2013-2024 Alexandre Spangaro <alexandre@inovea-conseil.com>
7 * Copyright (C) 2013-2016 Olivier Geffroy <jeff@jeffinfo.com>
8 * Copyright (C) 2013-2016 Florian Henry <florian.henry@open-concept.pro>
9 * Copyright (C) 2018-2024 Frédéric France <frederic.france@free.fr>
10 * Copyright (C) 2018 Eric Seigne <eric.seigne@cap-rel.fr>
11 * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 3 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program. If not, see <https://www.gnu.org/licenses/>.
25 */
26
32require '../../main.inc.php';
33require_once DOL_DOCUMENT_ROOT.'/core/lib/report.lib.php';
34require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
35require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php';
36require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingjournal.class.php';
37require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingaccount.class.php';
38require_once DOL_DOCUMENT_ROOT.'/expensereport/class/expensereport.class.php';
39require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
40require_once DOL_DOCUMENT_ROOT.'/accountancy/class/bookkeeping.class.php';
41
51// Load translation files required by the page
52$langs->loadLangs(array("commercial", "compta", "bills", "other", "accountancy", "trips", "errors"));
53
54$id_journal = GETPOSTINT('id_journal');
55$action = GETPOST('action', 'aZ09');
56
57$date_startmonth = GETPOSTINT('date_startmonth');
58$date_startday = GETPOSTINT('date_startday');
59$date_startyear = GETPOSTINT('date_startyear');
60$date_endmonth = GETPOSTINT('date_endmonth');
61$date_endday = GETPOSTINT('date_endday');
62$date_endyear = GETPOSTINT('date_endyear');
63$in_bookkeeping = GETPOST('in_bookkeeping');
64if ($in_bookkeeping == '') {
65 $in_bookkeeping = 'notyet';
66}
67
68$now = dol_now();
69
70$hookmanager->initHooks(array('expensereportsjournal'));
71$parameters = array();
72
73$taber = array(); // Initialise for static analysis
74$tabht = array();
75$tabtva = array();
76$tabttc = array();
77$tablocaltax1 = array();
78$tablocaltax2 = array();
79$tabuser = array();
80
81// Security check
82if (!isModEnabled('accounting')) {
84}
85if ($user->socid > 0) {
87}
88if (!$user->hasRight('accounting', 'bind', 'write')) {
90}
91
92$error = 0;
93$errorforinvoice = array();
94
95
96/*
97 * Actions
98 */
99
100$accountingaccount = new AccountingAccount($db);
101
102// Get information of a journal
103$accountingjournalstatic = new AccountingJournal($db);
104$accountingjournalstatic->fetch($id_journal);
105$journal = $accountingjournalstatic->code;
106$journal_label = $accountingjournalstatic->label;
107
108$date_start = dol_mktime(0, 0, 0, $date_startmonth, $date_startday, $date_startyear);
109$date_end = dol_mktime(23, 59, 59, $date_endmonth, $date_endday, $date_endyear);
110
111$pastmonth = null; // Initialise (could be unset)
112$pastmonthyear = null; // Initialise (could be unset)
113
114if (empty($date_startmonth)) {
115 // Period by default on transfer
117 $date_start = $dates['date_start'];
118 $pastmonthyear = $dates['pastmonthyear'];
119 $pastmonth = $dates['pastmonth'];
120}
121if (empty($date_endmonth)) {
122 // Period by default on transfer
124 $date_end = $dates['date_end'];
125 $pastmonthyear = $dates['pastmonthyear'];
126 $pastmonth = $dates['pastmonth'];
127}
128
129if (!GETPOSTISSET('date_startmonth') && (empty($date_start) || empty($date_end))) { // We define date_start and date_end, only if we did not submit the form
130 $date_start = dol_get_first_day($pastmonthyear, $pastmonth, false);
131 $date_end = dol_get_last_day($pastmonthyear, $pastmonth, false);
132}
133
134$sql = "SELECT er.rowid, er.ref, er.date_debut as de, er.date_fin as df,";
135$sql .= " erd.rowid as erdid, erd.comments, erd.total_ht, erd.total_tva, erd.total_localtax1, erd.total_localtax2, erd.tva_tx, erd.total_ttc, erd.fk_code_ventilation, erd.vat_src_code, ";
136$sql .= " u.rowid as uid, u.firstname, u.lastname, u.accountancy_code as user_accountancy_account,";
137$sql .= " f.accountancy_code, aa.rowid as fk_compte, aa.account_number as compte, aa.label as label_compte";
138$parameters = array();
139$reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters); // Note that $action and $object may have been modified by hook
140$sql .= $hookmanager->resPrint;
141$sql .= " FROM ".MAIN_DB_PREFIX."expensereport_det as erd";
142$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_type_fees as f ON f.id = erd.fk_c_type_fees";
143$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."accounting_account as aa ON aa.rowid = erd.fk_code_ventilation";
144$sql .= " JOIN ".MAIN_DB_PREFIX."expensereport as er ON er.rowid = erd.fk_expensereport";
145$sql .= " JOIN ".MAIN_DB_PREFIX."user as u ON u.rowid = er.fk_user_author";
146$parameters = array();
147$reshook = $hookmanager->executeHooks('printFieldListFrom', $parameters); // Note that $action and $object may have been modified by hook
148$sql .= $hookmanager->resPrint;
149$sql .= " WHERE er.fk_statut > 0";
150$sql .= " AND erd.fk_code_ventilation > 0";
151$sql .= " AND er.entity IN (".getEntity('expensereport', 0).")"; // We don't share object for accountancy
152if ($date_start && $date_end) {
153 $sql .= " AND er.date_debut >= '".$db->idate($date_start)."' AND er.date_debut <= '".$db->idate($date_end)."'";
154}
155// Define begin binding date
156if (getDolGlobalString('ACCOUNTING_DATE_START_BINDING')) {
157 $sql .= " AND er.date_debut >= '".$db->idate(getDolGlobalString('ACCOUNTING_DATE_START_BINDING'))."'";
158}
159// Already in bookkeeping or not
160if ($in_bookkeeping == 'already') {
161 $sql .= " AND er.rowid IN (SELECT fk_doc FROM ".MAIN_DB_PREFIX."accounting_bookkeeping as ab WHERE ab.doc_type='expense_report')";
162}
163if ($in_bookkeeping == 'notyet') {
164 $sql .= " AND er.rowid NOT IN (SELECT fk_doc FROM ".MAIN_DB_PREFIX."accounting_bookkeeping as ab WHERE ab.doc_type='expense_report')";
165}
166$parameters = array();
167$reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters); // Note that $action and $object may have been modified by hook
168$sql .= $hookmanager->resPrint;
169$sql .= " ORDER BY er.date_debut";
170
171dol_syslog('accountancy/journal/expensereportsjournal.php', LOG_DEBUG);
172$result = $db->query($sql);
173if ($result) {
174 $taber = array();
175 $tabht = array();
176 $tabtva = array();
177 $def_tva = array();
178 $tabttc = array();
179 $tablocaltax1 = array();
180 $tablocaltax2 = array();
181 $tabuser = array();
182
183 $num = $db->num_rows($result);
184
185 // Variables
186 $account_salary = getDolGlobalString('ACCOUNTING_ACCOUNT_EXPENSEREPORT', 'NotDefined');
187 $account_vat = getDolGlobalString('ACCOUNTING_VAT_BUY_ACCOUNT', 'NotDefined');
188 $noTaxDispatchingKeepWithLines = getDolGlobalInt('ACCOUNTING_EXPENSEREPORT_DO_NOT_DISPATCH_TAXES'); //If enabled, Tax will NOT get split off from the base entry and credited to a separate tax account (good for non-VAT countries like USA)
189
190 $i = 0;
191 while ($i < $num) {
192 $obj = $db->fetch_object($result);
193
194 // Controls
195 $compta_user = (!empty($obj->user_accountancy_account)) ? $obj->user_accountancy_account : $account_salary;
196 $compta_fees = $obj->compte;
197
198 $vatdata = getTaxesFromId($obj->tva_tx.($obj->vat_src_code ? ' ('.$obj->vat_src_code.')' : ''), $mysoc, $mysoc, 0);
199 $compta_tva = (!empty($vatdata['accountancy_code_buy']) ? $vatdata['accountancy_code_buy'] : $account_vat);
200 $compta_localtax1 = (!empty($vatdata['accountancy_code_buy']) ? $vatdata['accountancy_code_buy'] : $account_vat);
201 $compta_localtax2 = (!empty($vatdata['accountancy_code_buy']) ? $vatdata['accountancy_code_buy'] : $account_vat);
202
203 // Define an array to display all VAT rates that use this accounting account $compta_tva
204 if (price2num($obj->tva_tx) || !empty($obj->vat_src_code)) {
205 $def_tva[$obj->rowid][$compta_tva][vatrate($obj->tva_tx).($obj->vat_src_code ? ' ('.$obj->vat_src_code.')' : '')] = (vatrate($obj->tva_tx).($obj->vat_src_code ? ' ('.$obj->vat_src_code.')' : ''));
206 }
207
208 if (getDolGlobalInt('ACCOUNTANCY_ER_DATE_RECORD')) {
209 $taber[$obj->rowid]["date"] = $db->jdate($obj->df);
210 } else {
211 $taber[$obj->rowid]["date"] = $db->jdate($obj->de);
212 }
213 $taber[$obj->rowid]["ref"] = $obj->ref;
214 $taber[$obj->rowid]["comments"] = $obj->comments;
215 $taber[$obj->rowid]["fk_expensereportdet"] = $obj->erdid;
216
217 // Avoid warnings
218 if (!isset($tabttc[$obj->rowid][$compta_user])) {
219 $tabttc[$obj->rowid][$compta_user] = 0;
220 }
221 if (!isset($tabht[$obj->rowid][$compta_fees])) {
222 $tabht[$obj->rowid][$compta_fees] = 0;
223 }
224 if (!isset($tabtva[$obj->rowid][$compta_tva])) {
225 $tabtva[$obj->rowid][$compta_tva] = 0;
226 }
227 if (!isset($tablocaltax1[$obj->rowid][$compta_localtax1])) {
228 $tablocaltax1[$obj->rowid][$compta_localtax1] = 0;
229 }
230 if (!isset($tablocaltax2[$obj->rowid][$compta_localtax2])) {
231 $tablocaltax2[$obj->rowid][$compta_localtax2] = 0;
232 }
233
234 $tabttc[$obj->rowid][$compta_user] += $obj->total_ttc;
235 if ($noTaxDispatchingKeepWithLines) { //case where all taxes paid should be grouped with the same account as the main expense (best for USA)
236 $tabht[$obj->rowid][$compta_fees] += $obj->total_ttc;
237 } else { //case where every tax paid should be broken out into its own account for future recovery (best for VAT countries)
238 $tabht[$obj->rowid][$compta_fees] += $obj->total_ht;
239 $tabtva[$obj->rowid][$compta_tva] += $obj->total_tva;
240 $tablocaltax1[$obj->rowid][$compta_localtax1] += $obj->total_localtax1;
241 $tablocaltax2[$obj->rowid][$compta_localtax2] += $obj->total_localtax2;
242 }
243 $tabuser[$obj->rowid] = array(
244 'id' => $obj->uid,
245 'name' => dolGetFirstLastname($obj->firstname, $obj->lastname),
246 'user_accountancy_code' => $obj->user_accountancy_account
247 );
248
249 $i++;
250 }
251} else {
252 dol_print_error($db);
253}
254
255// Load all unbound lines
256if (!empty($taber)) {
257 $sql = "SELECT fk_expensereport, COUNT(erd.rowid) as nb";
258 $sql .= " FROM ".MAIN_DB_PREFIX."expensereport_det as erd";
259 $sql .= " WHERE erd.fk_code_ventilation <= 0";
260 $sql .= " AND erd.total_ttc <> 0";
261 $sql .= " AND fk_expensereport IN (".$db->sanitize(implode(",", array_keys($taber))).")";
262 $sql .= " GROUP BY fk_expensereport";
263 $resql = $db->query($sql);
264
265 $num = $db->num_rows($resql);
266 $i = 0;
267 while ($i < $num) {
268 $obj = $db->fetch_object($resql);
269 if ($obj->nb > 0) {
270 $errorforinvoice[$obj->fk_expensereport] = 'somelinesarenotbound';
271 }
272 $i++;
273 }
274}
275
276// Bookkeeping Write
277if ($action == 'writebookkeeping' && !$error && $user->hasRight('accounting', 'bind', 'write')) {
278 $now = dol_now();
279 $error = 0;
280
281 $userstatic = new User($db);
282 $bookkeepingstatic = new BookKeeping($db);
283
284 $accountingaccountexpense = new AccountingAccount($db);
285 $accountingaccountexpense->fetch(0, getDolGlobalString('ACCOUNTING_ACCOUNT_EXPENSEREPORT'), true);
286
287 foreach ($taber as $key => $val) { // Loop on each expense report
288 $errorforline = 0;
289
290 $totalcredit = 0;
291 $totaldebit = 0;
292
293 $db->begin();
294
295 $userstatic->id = $tabuser[$key]['id'];
296 $userstatic->name = $tabuser[$key]['name'];
297 $userstatic->accountancy_code = $tabuser[$key]['user_accountancy_code'];
298
299 // Error if some lines are not binded/ready to be journalized
300 if (!empty($errorforinvoice[$key]) && $errorforinvoice[$key] == 'somelinesarenotbound') {
301 $error++;
302 $errorforline++;
303 setEventMessages($langs->trans('ErrorInvoiceContainsLinesNotYetBounded', $val['ref']), null, 'errors');
304 }
305
306 // Thirdparty
307 if (!$errorforline) {
308 foreach ($tabttc[$key] as $k => $mt) {
309 if ($mt) {
310 $bookkeeping = new BookKeeping($db);
311 $bookkeeping->doc_date = $val["date"];
312 $bookkeeping->doc_ref = $val["ref"];
313 $bookkeeping->date_creation = $now;
314 $bookkeeping->doc_type = 'expense_report';
315 $bookkeeping->fk_doc = $key;
316 $bookkeeping->fk_docdet = $val["fk_expensereportdet"];
317
318 $bookkeeping->subledger_account = $tabuser[$key]['user_accountancy_code'];
319 $bookkeeping->subledger_label = $tabuser[$key]['name'];
320
321 $bookkeeping->numero_compte = getDolGlobalString('ACCOUNTING_ACCOUNT_EXPENSEREPORT');
322 $bookkeeping->label_compte = $accountingaccountexpense->label;
323
324 $bookkeeping->label_operation = $bookkeepingstatic->accountingLabelForOperation($userstatic->name, '', $langs->trans("SubledgerAccount"));
325 $bookkeeping->montant = $mt;
326 $bookkeeping->sens = ($mt >= 0) ? 'C' : 'D';
327 $bookkeeping->debit = ($mt <= 0) ? -$mt : 0;
328 $bookkeeping->credit = ($mt > 0) ? $mt : 0;
329 $bookkeeping->code_journal = $journal;
330 $bookkeeping->journal_label = $langs->transnoentities($journal_label);
331 $bookkeeping->fk_user_author = $user->id;
332 $bookkeeping->entity = $conf->entity;
333
334 $totaldebit += $bookkeeping->debit;
335 $totalcredit += $bookkeeping->credit;
336
337 $result = $bookkeeping->create($user);
338 if ($result < 0) {
339 if ($bookkeeping->error == 'BookkeepingRecordAlreadyExists') { // Already exists
340 $error++;
341 $errorforline++;
342 $errorforinvoice[$key] = 'alreadyjournalized';
343 //setEventMessages('Transaction for ('.$bookkeeping->doc_type.', '.$bookkeeping->fk_doc.', '.$bookkeeping->fk_docdet.') were already recorded', null, 'warnings');
344 } else {
345 $error++;
346 $errorforline++;
347 $errorforinvoice[$key] = 'other';
348 setEventMessages($bookkeeping->error, $bookkeeping->errors, 'errors');
349 }
350 }
351 }
352 }
353 }
354
355 // Fees
356 if (!$errorforline) {
357 foreach ($tabht[$key] as $k => $mt) {
358 if ($mt) {
359 // get compte id and label
360 if ($accountingaccount->fetch(0, $k, true)) {
361 $bookkeeping = new BookKeeping($db);
362 $bookkeeping->doc_date = $val["date"];
363 $bookkeeping->doc_ref = $val["ref"];
364 $bookkeeping->date_creation = $now;
365 $bookkeeping->doc_type = 'expense_report';
366 $bookkeeping->fk_doc = $key;
367 $bookkeeping->fk_docdet = $val["fk_expensereportdet"];
368
369 $bookkeeping->subledger_account = '';
370 $bookkeeping->subledger_label = '';
371
372 $bookkeeping->numero_compte = $k;
373 $bookkeeping->label_compte = $accountingaccount->label;
374
375 $bookkeeping->label_operation = $bookkeepingstatic->accountingLabelForOperation($userstatic->name, '', $accountingaccount->label);
376 $bookkeeping->montant = $mt;
377 $bookkeeping->sens = ($mt < 0) ? 'C' : 'D';
378 $bookkeeping->debit = ($mt > 0) ? $mt : 0;
379 $bookkeeping->credit = ($mt <= 0) ? -$mt : 0;
380 $bookkeeping->code_journal = $journal;
381 $bookkeeping->journal_label = $langs->transnoentities($journal_label);
382 $bookkeeping->fk_user_author = $user->id;
383 $bookkeeping->entity = $conf->entity;
384
385 $totaldebit += $bookkeeping->debit;
386 $totalcredit += $bookkeeping->credit;
387
388 $result = $bookkeeping->create($user);
389 if ($result < 0) {
390 if ($bookkeeping->error == 'BookkeepingRecordAlreadyExists') { // Already exists
391 $error++;
392 $errorforline++;
393 $errorforinvoice[$key] = 'alreadyjournalized';
394 //setEventMessages('Transaction for ('.$bookkeeping->doc_type.', '.$bookkeeping->fk_doc.', '.$bookkeeping->fk_docdet.') were already recorded', null, 'warnings');
395 } else {
396 $error++;
397 $errorforline++;
398 $errorforinvoice[$key] = 'other';
399 setEventMessages($bookkeeping->error, $bookkeeping->errors, 'errors');
400 }
401 }
402 }
403 }
404 }
405 }
406
407 // VAT
408 if (!$errorforline) {
409 $listoftax = array(0, 1, 2);
410 foreach ($listoftax as $numtax) {
411 $arrayofvat = $tabtva;
412 if ($numtax == 1) {
413 $arrayofvat = $tablocaltax1;
414 }
415 if ($numtax == 2) {
416 $arrayofvat = $tablocaltax2;
417 }
418
419 foreach ($arrayofvat[$key] as $k => $mt) {
420 if ($mt) {
421 if (empty($conf->cache['accountingaccountincurrententity'][$k])) {
422 $accountingaccount = new AccountingAccount($db);
423 $accountingaccount->fetch(0, $k, true);
424 $conf->cache['accountingaccountincurrententity'][$k] = $accountingaccount;
425 } else {
426 $accountingaccount = $conf->cache['accountingaccountincurrententity'][$k];
427 }
428
429 $account_label = $accountingaccount->label;
430
431 // get compte id and label
432 $bookkeeping = new BookKeeping($db);
433 $bookkeeping->doc_date = $val["date"];
434 $bookkeeping->doc_ref = $val["ref"];
435 $bookkeeping->date_creation = $now;
436 $bookkeeping->doc_type = 'expense_report';
437 $bookkeeping->fk_doc = $key;
438 $bookkeeping->fk_docdet = $val["fk_expensereportdet"];
439
440 $bookkeeping->subledger_account = '';
441 $bookkeeping->subledger_label = '';
442
443 $bookkeeping->numero_compte = $k;
444 $bookkeeping->label_compte = $account_label;
445
446 $tmpvatrate = (empty($def_tva[$key][$k]) ? (empty($arrayofvat[$key][$k]) ? '' : $arrayofvat[$key][$k]) : implode(', ', $def_tva[$key][$k]));
447 $labelvataccount = $langs->trans("Taxes").' '.$tmpvatrate.' %';
448 $labelvataccount .= ($numtax ? ' - Localtax '.$numtax : '');
449 $bookkeeping->label_operation = $bookkeepingstatic->accountingLabelForOperation($userstatic->name, '', $labelvataccount);
450
451 $bookkeeping->montant = $mt;
452 $bookkeeping->sens = ($mt < 0) ? 'C' : 'D';
453 $bookkeeping->debit = ($mt > 0) ? $mt : 0;
454 $bookkeeping->credit = ($mt <= 0) ? -$mt : 0;
455 $bookkeeping->code_journal = $journal;
456 $bookkeeping->journal_label = $langs->transnoentities($journal_label);
457 $bookkeeping->fk_user_author = $user->id;
458 $bookkeeping->entity = $conf->entity;
459
460 $totaldebit += $bookkeeping->debit;
461 $totalcredit += $bookkeeping->credit;
462
463 $result = $bookkeeping->create($user);
464 if ($result < 0) {
465 if ($bookkeeping->error == 'BookkeepingRecordAlreadyExists') { // Already exists
466 $error++;
467 $errorforline++;
468 $errorforinvoice[$key] = 'alreadyjournalized';
469 //setEventMessages('Transaction for ('.$bookkeeping->doc_type.', '.$bookkeeping->fk_doc.', '.$bookkeeping->fk_docdet.') were already recorded', null, 'warnings');
470 } else {
471 $error++;
472 $errorforline++;
473 $errorforinvoice[$key] = 'other';
474 setEventMessages($bookkeeping->error, $bookkeeping->errors, 'errors');
475 }
476 }
477 }
478 }
479 }
480 }
481
482 // Protection against a bug on lines before
483 if (!$errorforline && (price2num($totaldebit, 'MT') != price2num($totalcredit, 'MT'))) {
484 $error++;
485 $errorforline++;
486 $errorforinvoice[$key] = 'amountsnotbalanced';
487 setEventMessages('We tried to insert a non balanced transaction in book for '.$val["ref"].'. Canceled. Surely a bug.', null, 'errors');
488 }
489
490 if (!$errorforline) {
491 $db->commit();
492 } else {
493 $db->rollback();
494
495 if ($error >= 10) {
496 setEventMessages($langs->trans("ErrorTooManyErrorsProcessStopped"), null, 'errors');
497 break; // Break in the foreach
498 }
499 }
500 }
501
502 $tabpay = $taber;
503
504 if (empty($error) && count($tabpay) > 0) {
505 setEventMessages($langs->trans("GeneralLedgerIsWritten"), null, 'mesgs');
506 } elseif (count($tabpay) == $error) {
507 setEventMessages($langs->trans("NoNewRecordSaved"), null, 'warnings');
508 } else {
509 setEventMessages($langs->trans("GeneralLedgerSomeRecordWasNotRecorded"), null, 'warnings');
510 }
511
512 $action = '';
513
514 // Must reload data, so we make a redirect
515 if (count($tabpay) != $error) {
516 $param = 'id_journal='.$id_journal;
517 $param .= '&date_startday='.$date_startday;
518 $param .= '&date_startmonth='.$date_startmonth;
519 $param .= '&date_startyear='.$date_startyear;
520 $param .= '&date_endday='.$date_endday;
521 $param .= '&date_endmonth='.$date_endmonth;
522 $param .= '&date_endyear='.$date_endyear;
523 $param .= '&in_bookkeeping='.$in_bookkeeping;
524
525 header("Location: ".$_SERVER['PHP_SELF'].($param ? '?'.$param : ''));
526 exit;
527 }
528}
529
530
531/*
532 * View
533 */
534
535$form = new Form($db);
536
537$userstatic = new User($db);
538
539// Export
540if ($action == 'exportcsv' && !$error) { // ISO and not UTF8 !
541 $sep = getDolGlobalString('ACCOUNTING_EXPORT_SEPARATORCSV');
542
543 $filename = 'journal';
544 $type_export = 'journal';
545 include DOL_DOCUMENT_ROOT.'/accountancy/tpl/export_journal.tpl.php';
546
547 $userstatic = new User($db);
548 $bookkeepingstatic = new BookKeeping($db);
549
550 // CSV header line
551 print '"'.$langs->transnoentitiesnoconv("Date").'"'.$sep;
552 print '"'.$langs->transnoentitiesnoconv("Piece").'"'.$sep;
553 print '"'.$langs->transnoentitiesnoconv("AccountAccounting").'"'.$sep;
554 print '"'.$langs->transnoentitiesnoconv("LabelOperation").'"'.$sep;
555 print '"'.$langs->transnoentitiesnoconv("AccountingDebit").'"'.$sep;
556 print '"'.$langs->transnoentitiesnoconv("AccountingCredit").'"'.$sep;
557 print "\n";
558
559 foreach ($taber as $key => $val) {
560 $date = dol_print_date($val["date"], 'day');
561
562 $userstatic->id = $tabuser[$key]['id'];
563 $userstatic->name = $tabuser[$key]['name'];
564
565 // Fees
566 foreach ($tabht[$key] as $k => $mt) {
567 $accountingaccount = new AccountingAccount($db);
568 $accountingaccount->fetch(0, $k, true);
569 if ($mt) {
570 print '"'.$date.'"'.$sep;
571 print '"'.$val["ref"].'"'.$sep;
572 print '"'.length_accountg(html_entity_decode($k)).'"'.$sep;
573 print '"'.csvClean($bookkeepingstatic->accountingLabelForOperation($userstatic->name, '', $accountingaccount->label)).'"'.$sep;
574 print '"'.($mt >= 0 ? price($mt) : '').'"'.$sep;
575 print '"'.($mt < 0 ? price(-$mt) : '').'"';
576 print "\n";
577 }
578 }
579
580 // VAT
581 foreach ($tabtva[$key] as $k => $mt) {
582 if ($mt) {
583 print '"'.$date.'"'.$sep;
584 print '"'.$val["ref"].'"'.$sep;
585 print '"'.length_accountg(html_entity_decode($k)).'"'.$sep;
586 print '"'.csvClean($bookkeepingstatic->accountingLabelForOperation($userstatic->name, '', $langs->trans("VAT").implode($def_tva[$key][$k]).' %')).'"'.$sep;
587 print '"'.($mt >= 0 ? price($mt) : '').'"'.$sep;
588 print '"'.($mt < 0 ? price(-$mt) : '').'"';
589 print "\n";
590 }
591 }
592
593 // Third party
594 foreach ($tabttc[$key] as $k => $mt) {
595 print '"'.$date.'"'.$sep;
596 print '"'.$val["ref"].'"'.$sep;
597 print '"'.length_accounta(html_entity_decode($k)).'"'.$sep;
598 print '"'.csvClean($bookkeepingstatic->accountingLabelForOperation($userstatic->name, '', $langs->trans("Thirdparty"))).'"'.$sep;
599 print '"'.($mt < 0 ? price(-$mt) : '').'"'.$sep;
600 print '"'.($mt >= 0 ? price($mt) : '').'"';
601 }
602 print "\n";
603 }
604}
605
606if (empty($action) || $action == 'view') {
607 $title = $langs->trans("GenerationOfAccountingEntries").' - '.$accountingjournalstatic->getNomUrl(0, 2, 1, '', 1);
608 $help_url = 'EN:Module_Double_Entry_Accounting|FR:Module_Comptabilit&eacute;_en_Partie_Double#G&eacute;n&eacute;ration_des_&eacute;critures_en_comptabilit&eacute;';
609 llxHeader('', dol_string_nohtmltag($title), $help_url, '', 0, 0, '', '', '', 'mod-accountancy accountancy-generation page-expensereportsjournal');
610
611 $nom = $title;
612 $nomlink = '';
613 $periodlink = '';
614 $exportlink = '';
615 $builddate = dol_now();
616 $description = $langs->trans("DescJournalOnlyBindedVisible").'<br>';
617
618 $listofchoices = array('notyet' => $langs->trans("NotYetInGeneralLedger"), 'already' => $langs->trans("AlreadyInGeneralLedger"));
619 $period = $form->selectDate($date_start ? $date_start : -1, 'date_start', 0, 0, 0, '', 1, 0).' - '.$form->selectDate($date_end ? $date_end : -1, 'date_end', 0, 0, 0, '', 1, 0);
620 $period .= ' - '.$langs->trans("JournalizationInLedgerStatus").' '.$form->selectarray('in_bookkeeping', $listofchoices, $in_bookkeeping, 1);
621
622 $varlink = 'id_journal='.$id_journal;
623
624 journalHead($nom, $nomlink, $period, $periodlink, $description, $builddate, $exportlink, array('action' => ''), '', $varlink);
625
626 if (getDolGlobalString('ACCOUNTANCY_FISCAL_PERIOD_MODE') != 'blockedonclosed') {
627 // Test that setup is complete (we are in accounting, so test on entity is always on $conf->entity only, no sharing allowed)
628 // Fiscal period test
629 $sql = "SELECT COUNT(rowid) as nb FROM ".MAIN_DB_PREFIX."accounting_fiscalyear WHERE entity = ".((int) $conf->entity);
630 $resql = $db->query($sql);
631 if ($resql) {
632 $obj = $db->fetch_object($resql);
633 if ($obj->nb == 0) {
634 print '<br><div class="warning">'.img_warning().' '.$langs->trans("TheFiscalPeriodIsNotDefined");
635 $desc = ' : '.$langs->trans("AccountancyAreaDescFiscalPeriod", 4, '{link}');
636 $desc = str_replace('{link}', '<strong>'.$langs->transnoentitiesnoconv("MenuAccountancy").'-'.$langs->transnoentitiesnoconv("Setup")."-".$langs->transnoentitiesnoconv("FiscalPeriod").'</strong>', $desc);
637 print $desc;
638 print '</div>';
639 }
640 } else {
641 dol_print_error($db);
642 }
643 }
644
645 // Button to write into Ledger
646 if (!getDolGlobalString('ACCOUNTING_ACCOUNT_EXPENSEREPORT') || getDolGlobalString('ACCOUNTING_ACCOUNT_EXPENSEREPORT') == '-1') {
647 print '<br><div class="warning">'.img_warning().' '.$langs->trans("SomeMandatoryStepsOfSetupWereNotDone");
648 $desc = ' : '.$langs->trans("AccountancyAreaDescMisc", 4, '{link}');
649 $desc = str_replace('{link}', '<strong>'.$langs->transnoentitiesnoconv("MenuAccountancy").'-'.$langs->transnoentitiesnoconv("Setup")."-".$langs->transnoentitiesnoconv("MenuDefaultAccounts").'</strong>', $desc);
650 print $desc;
651 print '</div>';
652 }
653 print '<br><div class="tabsAction tabsActionNoBottom centerimp">';
654
655 if (getDolGlobalString('ACCOUNTING_ENABLE_EXPORT_DRAFT_JOURNAL') && $in_bookkeeping == 'notyet') {
656 print '<input type="button" class="butAction" name="exportcsv" value="'.$langs->trans("ExportDraftJournal").'" onclick="launch_export();" />';
657 }
658 if (!getDolGlobalString('ACCOUNTING_ACCOUNT_EXPENSEREPORT') || getDolGlobalString('ACCOUNTING_ACCOUNT_EXPENSEREPORT') == '-1') {
659 print '<input type="button" class="butActionRefused classfortooltip" title="'.dol_escape_htmltag($langs->trans("SomeMandatoryStepsOfSetupWereNotDone")).'" value="'.$langs->trans("WriteBookKeeping").'" />';
660 } else {
661 if ($in_bookkeeping == 'notyet') {
662 print '<input type="button" class="butAction" name="writebookkeeping" value="'.$langs->trans("WriteBookKeeping").'" onclick="writebookkeeping();" />';
663 } else {
664 print '<a href="#" class="butActionRefused classfortooltip" name="writebookkeeping">'.$langs->trans("WriteBookKeeping").'</a>';
665 }
666 }
667 print '</div>';
668
669 // TODO Avoid using js. We can use a direct link with $param
670 print '
671 <script type="text/javascript">
672 function launch_export() {
673 $("div.fiche form input[name=\"action\"]").val("exportcsv");
674 $("div.fiche form input[type=\"submit\"]").click();
675 $("div.fiche form input[name=\"action\"]").val("");
676 }
677 function writebookkeeping() {
678 console.log("click on writebookkeeping");
679 $("div.fiche form input[name=\"action\"]").val("writebookkeeping");
680 $("div.fiche form input[type=\"submit\"]").click();
681 $("div.fiche form input[name=\"action\"]").val("");
682 }
683 </script>';
684
685 /*
686 * Show result array
687 */
688 print '<br>';
689
690 $i = 0;
691 print '<div class="div-table-responsive">';
692 print "<table class=\"noborder\" width=\"100%\">";
693 print "<tr class=\"liste_titre\">";
694 print "<td>".$langs->trans("Date")."</td>";
695 print "<td>".$langs->trans("Piece").' ('.$langs->trans("ExpenseReportRef").")</td>";
696 print "<td>".$langs->trans("AccountAccounting")."</td>";
697 print "<td>".$langs->trans("SubledgerAccount")."</td>";
698 print "<td>".$langs->trans("LabelOperation")."</td>";
699 print '<td class="right">'.$langs->trans("AccountingDebit")."</td>";
700 print '<td class="right">'.$langs->trans("AccountingCredit")."</td>";
701 print "</tr>\n";
702
703 $i = 0;
704
705 $expensereportstatic = new ExpenseReport($db);
706 $expensereportlinestatic = new ExpenseReportLine($db);
707 $bookkeepingstatic = new BookKeeping($db);
708
709 foreach ($taber as $key => $val) {
710 $expensereportstatic->id = $key;
711 $expensereportstatic->ref = $val["ref"];
712 $expensereportlinestatic->comments = html_entity_decode(dol_trunc($val["comments"], 32));
713
714 $date = dol_print_date($val["date"], 'day');
715
716 if ($errorforinvoice[$key] == 'somelinesarenotbound') {
717 print '<tr class="oddeven">';
718 print "<!-- Some lines are not bound -->";
719 print "<td>".$date."</td>";
720 print "<td>".$expensereportstatic->getNomUrl(1)."</td>";
721 // Account
722 print "<td>";
723 print '<span class="error">'.$langs->trans('ErrorInvoiceContainsLinesNotYetBoundedShort', $val['ref']).'</span>';
724 print '</td>';
725 // Subledger account
726 print "<td>";
727 print '</td>';
728 print "<td>";
729 print "</td>";
730 print '<td class="right"></td>';
731 print '<td class="right"></td>';
732 print "</tr>";
733
734 $i++;
735 }
736
737 // Fees
738 foreach ($tabht[$key] as $k => $mt) {
739 if (empty($conf->cache['accountingaccountincurrententity'][$k])) {
740 $accountingaccount = new AccountingAccount($db);
741 $accountingaccount->fetch(0, $k, true);
742 $conf->cache['accountingaccountincurrententity'][$k] = $accountingaccount;
743 } else {
744 $accountingaccount = $conf->cache['accountingaccountincurrententity'][$k];
745 }
746
747 if ($mt) {
748 print '<tr class="oddeven">';
749 print "<!-- Fees -->";
750 print "<td>".$date."</td>";
751 print "<td>".$expensereportstatic->getNomUrl(1)."</td>";
752 $userstatic->id = $tabuser[$key]['id'];
753 $userstatic->name = $tabuser[$key]['name'];
754 // Account
755 print "<td>";
756 $accountoshow = length_accountg($k);
757 if (($accountoshow == "") || $accountoshow == 'NotDefined') {
758 print '<span class="error">'.$langs->trans("FeeAccountNotDefined").'</span>';
759 } else {
760 print $accountoshow;
761 }
762 print '</td>';
763 // Subledger account
764 print "<td>";
765 print '</td>';
766 $userstatic->id = $tabuser[$key]['id'];
767 $userstatic->name = $tabuser[$key]['name'];
768 print "<td>" . $bookkeepingstatic->accountingLabelForOperation($userstatic->getNomUrl(0, 'user'), '', $accountingaccount->label, 1) . "</td>";
769 print '<td class="right nowraponall amount">'.($mt >= 0 ? price($mt) : '')."</td>";
770 print '<td class="right nowraponall amount">'.($mt < 0 ? price(-$mt) : '')."</td>";
771 print "</tr>";
772
773 $i++;
774 }
775 }
776
777 // Third party
778 foreach ($tabttc[$key] as $k => $mt) {
779 $userstatic->id = $tabuser[$key]['id'];
780 $userstatic->name = $tabuser[$key]['name'];
781
782 print '<tr class="oddeven">';
783 print "<!-- Thirdparty -->";
784 print "<td>".$date."</td>";
785 print "<td>".$expensereportstatic->getNomUrl(1)."</td>";
786 // Account
787 print "<td>";
788 $accountoshow = length_accountg(getDolGlobalString('ACCOUNTING_ACCOUNT_EXPENSEREPORT'));
789 if (($accountoshow == "") || $accountoshow == 'NotDefined') {
790 print '<span class="error">'.$langs->trans("MainAccountForUsersNotDefined").'</span>';
791 } else {
792 print $accountoshow;
793 }
794 print "</td>";
795 // Subledger account
796 print "<td>";
797 $accountoshow = length_accounta($k);
798 if (($accountoshow == "") || $accountoshow == 'NotDefined') {
799 print '<span class="error">'.$langs->trans("UserAccountNotDefined").'</span>';
800 } else {
801 print $accountoshow;
802 }
803 print '</td>';
804 print "<td>" . $bookkeepingstatic->accountingLabelForOperation($userstatic->getNomUrl(0, 'user'), '', $langs->trans("SubledgerAccount"), 1) . "</td>";
805 print '<td class="right nowraponall amount">'.($mt < 0 ? price(-$mt) : '')."</td>";
806 print '<td class="right nowraponall amount">'.($mt >= 0 ? price($mt) : '')."</td>";
807 print "</tr>";
808
809 $i++;
810 }
811
812 // VAT
813 $listoftax = array(0, 1, 2);
814 foreach ($listoftax as $numtax) {
815 $arrayofvat = $tabtva;
816 if ($numtax == 1) {
817 $arrayofvat = $tablocaltax1;
818 }
819 if ($numtax == 2) {
820 $arrayofvat = $tablocaltax2;
821 }
822
823 foreach ($arrayofvat[$key] as $k => $mt) {
824 if ($mt) {
825 print '<tr class="oddeven">';
826 print "<!-- VAT -->";
827 print "<td>".$date."</td>";
828 print "<td>".$expensereportstatic->getNomUrl(1)."</td>";
829 // Account
830 print "<td>";
831 $accountoshow = length_accountg($k);
832 if (($accountoshow == "") || $accountoshow == 'NotDefined') {
833 print '<span class="error">'.$langs->trans("VATAccountNotDefined").'</span>';
834 } else {
835 print $accountoshow;
836 }
837 print "</td>";
838 // Subledger account
839 print "<td>";
840 print '</td>';
841 $tmpvatrate = (empty($def_tva[$key][$k]) ? (empty($arrayofvat[$key][$k]) ? '' : $arrayofvat[$key][$k]) : implode(', ', $def_tva[$key][$k]));
842 $labelvatrate = $langs->trans("Taxes").' '.$tmpvatrate.' %';
843 $labelvatrate .= ($numtax ? ' - Localtax '.$numtax : '');
844 print "<td>" . $bookkeepingstatic->accountingLabelForOperation($userstatic->getNomUrl(0, 'user'), '', $labelvatrate, 1) . "</td>";
845 print '<td class="right nowraponall amount">'.($mt >= 0 ? price($mt) : '')."</td>";
846 print '<td class="right nowraponall amount">'.($mt < 0 ? price(-$mt) : '')."</td>";
847 print "</tr>";
848
849 $i++;
850 }
851 }
852 }
853 }
854
855 if (!$i) {
856 $colspan = 7;
857 print '<tr class="oddeven"><td colspan="'.$colspan.'"><span class="opacitymedium">'.$langs->trans("NoRecordFound").'</span></td></tr>';
858 }
859
860 print "</table>";
861 print '</div>';
862
863 // End of page
864 llxFooter();
865}
866$db->close();
length_accountg($account)
Return General accounting account with defined length (used for product and miscellaneous)
journalHead($nom, $variant, $period, $periodlink, $description, $builddate, $exportlink='', $moreparam=array(), $calcmode='', $varlink='', $moreoptions=array())
Show header of a page used to transfer/dispatch data in accounting.
getDefaultDatesForTransfer()
Return Default dates for transfer based on periodicity option in accountancy setup.
length_accounta($accounta)
Return Auxiliary accounting account of thirdparties with defined length.
llxFooter($comment='', $zone='private', $disabledoutputofmessages=0)
Empty footer.
Definition wrapper.php:87
if(!defined('NOREQUIRESOC')) if(!defined( 'NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined( 'NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined( 'NOREQUIREAJAX')) llxHeader($head='', $title='', $help_url='', $target='', $disablejs=0, $disablehead=0, $arrayofjs='', $arrayofcss='', $morequerystring='', $morecssonbody='', $replacemainareaby='', $disablenofollow=0, $disablenoindex=0)
Empty header.
Definition wrapper.php:71
Class to manage accounting accounts.
Class to manage accounting journals.
Class to manage Ledger (General Ledger and Subledger)
Class to manage Trips and Expenses.
Class of expense report details lines.
Class to manage generation of HTML components Only common components must be here.
Class to manage Dolibarr users.
dol_get_first_day($year, $month=1, $gm=false)
Return GMT time for first day of a month or year.
Definition date.lib.php:600
dol_get_last_day($year, $month=12, $gm=false)
Return GMT time for last day of a month or year.
Definition date.lib.php:619
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed information (by default a local PHP server timestamp) Rep...
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0, $attop=0)
Set event messages in dol_events session object.
vatrate($rate, $addpercent=false, $info_bits=0, $usestarfornpr=0, $html=0)
Return a string with VAT rate label formatted for view output Used into pdf and HTML pages.
GETPOSTINT($paramname, $method=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
dol_string_nohtmltag($stringtoclean, $removelinefeed=1, $pagecodeto='UTF-8', $strip_tags=0, $removedoublespaces=1)
Clean a string from all HTML tags and entities.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
getTaxesFromId($vatrate, $buyer=null, $seller=null, $firstparamisid=1)
Get tax (VAT) main information from Id.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
dolGetFirstLastname($firstname, $lastname, $nameorder=-1)
Return firstname and lastname in correct order.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
global $conf
The following vars must be defined: $type2label $form $conf, $lang, The following vars may also be de...
Definition member.php:79
accessforbidden($message='', $printheader=1, $printfooter=1, $showonlymessage=0, $params=null)
Show a message to say access is forbidden and stop program.