dolibarr 21.0.0-beta
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
256$sql = "SELECT fk_expensereport, COUNT(erd.rowid) as nb";
257$sql .= " FROM ".MAIN_DB_PREFIX."expensereport_det as erd";
258$sql .= " WHERE erd.fk_code_ventilation <= 0";
259$sql .= " AND erd.total_ttc <> 0";
260$sql .= " AND fk_expensereport IN (".$db->sanitize(implode(",", array_keys($taber))).")";
261$sql .= " GROUP BY fk_expensereport";
262$resql = $db->query($sql);
263
264$num = $db->num_rows($resql);
265$i = 0;
266while ($i < $num) {
267 $obj = $db->fetch_object($resql);
268 if ($obj->nb > 0) {
269 $errorforinvoice[$obj->fk_expensereport] = 'somelinesarenotbound';
270 }
271 $i++;
272}
273
274// Bookkeeping Write
275if ($action == 'writebookkeeping' && !$error && $user->hasRight('accounting', 'bind', 'write')) {
276 $now = dol_now();
277 $error = 0;
278
279 $userstatic = new User($db);
280 $bookkeepingstatic = new BookKeeping($db);
281
282 $accountingaccountexpense = new AccountingAccount($db);
283 $accountingaccountexpense->fetch(0, getDolGlobalString('ACCOUNTING_ACCOUNT_EXPENSEREPORT'), true);
284
285 foreach ($taber as $key => $val) { // Loop on each expense report
286 $errorforline = 0;
287
288 $totalcredit = 0;
289 $totaldebit = 0;
290
291 $db->begin();
292
293 $userstatic->id = $tabuser[$key]['id'];
294 $userstatic->name = $tabuser[$key]['name'];
295 $userstatic->accountancy_code = $tabuser[$key]['user_accountancy_code'];
296
297 // Error if some lines are not binded/ready to be journalized
298 if (!empty($errorforinvoice[$key]) && $errorforinvoice[$key] == 'somelinesarenotbound') {
299 $error++;
300 $errorforline++;
301 setEventMessages($langs->trans('ErrorInvoiceContainsLinesNotYetBounded', $val['ref']), null, 'errors');
302 }
303
304 // Thirdparty
305 if (!$errorforline) {
306 foreach ($tabttc[$key] as $k => $mt) {
307 if ($mt) {
308 $bookkeeping = new BookKeeping($db);
309 $bookkeeping->doc_date = $val["date"];
310 $bookkeeping->doc_ref = $val["ref"];
311 $bookkeeping->date_creation = $now;
312 $bookkeeping->doc_type = 'expense_report';
313 $bookkeeping->fk_doc = $key;
314 $bookkeeping->fk_docdet = $val["fk_expensereportdet"];
315
316 $bookkeeping->subledger_account = $tabuser[$key]['user_accountancy_code'];
317 $bookkeeping->subledger_label = $tabuser[$key]['name'];
318
319 $bookkeeping->numero_compte = getDolGlobalString('ACCOUNTING_ACCOUNT_EXPENSEREPORT');
320 $bookkeeping->label_compte = $accountingaccountexpense->label;
321
322 $bookkeeping->label_operation = $bookkeepingstatic->accountingLabelForOperation($userstatic->name, '', $langs->trans("SubledgerAccount"));
323 $bookkeeping->montant = $mt;
324 $bookkeeping->sens = ($mt >= 0) ? 'C' : 'D';
325 $bookkeeping->debit = ($mt <= 0) ? -$mt : 0;
326 $bookkeeping->credit = ($mt > 0) ? $mt : 0;
327 $bookkeeping->code_journal = $journal;
328 $bookkeeping->journal_label = $langs->transnoentities($journal_label);
329 $bookkeeping->fk_user_author = $user->id;
330 $bookkeeping->entity = $conf->entity;
331
332 $totaldebit += $bookkeeping->debit;
333 $totalcredit += $bookkeeping->credit;
334
335 $result = $bookkeeping->create($user);
336 if ($result < 0) {
337 if ($bookkeeping->error == 'BookkeepingRecordAlreadyExists') { // Already exists
338 $error++;
339 $errorforline++;
340 $errorforinvoice[$key] = 'alreadyjournalized';
341 //setEventMessages('Transaction for ('.$bookkeeping->doc_type.', '.$bookkeeping->fk_doc.', '.$bookkeeping->fk_docdet.') were already recorded', null, 'warnings');
342 } else {
343 $error++;
344 $errorforline++;
345 $errorforinvoice[$key] = 'other';
346 setEventMessages($bookkeeping->error, $bookkeeping->errors, 'errors');
347 }
348 }
349 }
350 }
351 }
352
353 // Fees
354 if (!$errorforline) {
355 foreach ($tabht[$key] as $k => $mt) {
356 if ($mt) {
357 // get compte id and label
358 if ($accountingaccount->fetch(0, $k, true)) {
359 $bookkeeping = new BookKeeping($db);
360 $bookkeeping->doc_date = $val["date"];
361 $bookkeeping->doc_ref = $val["ref"];
362 $bookkeeping->date_creation = $now;
363 $bookkeeping->doc_type = 'expense_report';
364 $bookkeeping->fk_doc = $key;
365 $bookkeeping->fk_docdet = $val["fk_expensereportdet"];
366
367 $bookkeeping->subledger_account = '';
368 $bookkeeping->subledger_label = '';
369
370 $bookkeeping->numero_compte = $k;
371 $bookkeeping->label_compte = $accountingaccount->label;
372
373 $bookkeeping->label_operation = $bookkeepingstatic->accountingLabelForOperation($userstatic->name, '', $accountingaccount->label);
374 $bookkeeping->montant = $mt;
375 $bookkeeping->sens = ($mt < 0) ? 'C' : 'D';
376 $bookkeeping->debit = ($mt > 0) ? $mt : 0;
377 $bookkeeping->credit = ($mt <= 0) ? -$mt : 0;
378 $bookkeeping->code_journal = $journal;
379 $bookkeeping->journal_label = $langs->transnoentities($journal_label);
380 $bookkeeping->fk_user_author = $user->id;
381 $bookkeeping->entity = $conf->entity;
382
383 $totaldebit += $bookkeeping->debit;
384 $totalcredit += $bookkeeping->credit;
385
386 $result = $bookkeeping->create($user);
387 if ($result < 0) {
388 if ($bookkeeping->error == 'BookkeepingRecordAlreadyExists') { // Already exists
389 $error++;
390 $errorforline++;
391 $errorforinvoice[$key] = 'alreadyjournalized';
392 //setEventMessages('Transaction for ('.$bookkeeping->doc_type.', '.$bookkeeping->fk_doc.', '.$bookkeeping->fk_docdet.') were already recorded', null, 'warnings');
393 } else {
394 $error++;
395 $errorforline++;
396 $errorforinvoice[$key] = 'other';
397 setEventMessages($bookkeeping->error, $bookkeeping->errors, 'errors');
398 }
399 }
400 }
401 }
402 }
403 }
404
405 // VAT
406 if (!$errorforline) {
407 $listoftax = array(0, 1, 2);
408 foreach ($listoftax as $numtax) {
409 $arrayofvat = $tabtva;
410 if ($numtax == 1) {
411 $arrayofvat = $tablocaltax1;
412 }
413 if ($numtax == 2) {
414 $arrayofvat = $tablocaltax2;
415 }
416
417 foreach ($arrayofvat[$key] as $k => $mt) {
418 if ($mt) {
419 if (empty($conf->cache['accountingaccountincurrententity'][$k])) {
420 $accountingaccount = new AccountingAccount($db);
421 $accountingaccount->fetch(0, $k, true);
422 $conf->cache['accountingaccountincurrententity'][$k] = $accountingaccount;
423 } else {
424 $accountingaccount = $conf->cache['accountingaccountincurrententity'][$k];
425 }
426
427 $account_label = $accountingaccount->label;
428
429 // get compte id and label
430 $bookkeeping = new BookKeeping($db);
431 $bookkeeping->doc_date = $val["date"];
432 $bookkeeping->doc_ref = $val["ref"];
433 $bookkeeping->date_creation = $now;
434 $bookkeeping->doc_type = 'expense_report';
435 $bookkeeping->fk_doc = $key;
436 $bookkeeping->fk_docdet = $val["fk_expensereportdet"];
437
438 $bookkeeping->subledger_account = '';
439 $bookkeeping->subledger_label = '';
440
441 $bookkeeping->numero_compte = $k;
442 $bookkeeping->label_compte = $account_label;
443
444 $tmpvatrate = (empty($def_tva[$key][$k]) ? (empty($arrayofvat[$key][$k]) ? '' : $arrayofvat[$key][$k]) : implode(', ', $def_tva[$key][$k]));
445 $labelvataccount = $langs->trans("Taxes").' '.$tmpvatrate.' %';
446 $labelvataccount .= ($numtax ? ' - Localtax '.$numtax : '');
447 $bookkeeping->label_operation = $bookkeepingstatic->accountingLabelForOperation($userstatic->name, '', $labelvataccount);
448
449 $bookkeeping->montant = $mt;
450 $bookkeeping->sens = ($mt < 0) ? 'C' : 'D';
451 $bookkeeping->debit = ($mt > 0) ? $mt : 0;
452 $bookkeeping->credit = ($mt <= 0) ? -$mt : 0;
453 $bookkeeping->code_journal = $journal;
454 $bookkeeping->journal_label = $langs->transnoentities($journal_label);
455 $bookkeeping->fk_user_author = $user->id;
456 $bookkeeping->entity = $conf->entity;
457
458 $totaldebit += $bookkeeping->debit;
459 $totalcredit += $bookkeeping->credit;
460
461 $result = $bookkeeping->create($user);
462 if ($result < 0) {
463 if ($bookkeeping->error == 'BookkeepingRecordAlreadyExists') { // Already exists
464 $error++;
465 $errorforline++;
466 $errorforinvoice[$key] = 'alreadyjournalized';
467 //setEventMessages('Transaction for ('.$bookkeeping->doc_type.', '.$bookkeeping->fk_doc.', '.$bookkeeping->fk_docdet.') were already recorded', null, 'warnings');
468 } else {
469 $error++;
470 $errorforline++;
471 $errorforinvoice[$key] = 'other';
472 setEventMessages($bookkeeping->error, $bookkeeping->errors, 'errors');
473 }
474 }
475 }
476 }
477 }
478 }
479
480 // Protection against a bug on lines before
481 if (!$errorforline && (price2num($totaldebit, 'MT') != price2num($totalcredit, 'MT'))) {
482 $error++;
483 $errorforline++;
484 $errorforinvoice[$key] = 'amountsnotbalanced';
485 setEventMessages('We tried to insert a non balanced transaction in book for '.$val["ref"].'. Canceled. Surely a bug.', null, 'errors');
486 }
487
488 if (!$errorforline) {
489 $db->commit();
490 } else {
491 $db->rollback();
492
493 if ($error >= 10) {
494 setEventMessages($langs->trans("ErrorTooManyErrorsProcessStopped"), null, 'errors');
495 break; // Break in the foreach
496 }
497 }
498 }
499
500 $tabpay = $taber;
501
502 if (empty($error) && count($tabpay) > 0) {
503 setEventMessages($langs->trans("GeneralLedgerIsWritten"), null, 'mesgs');
504 } elseif (count($tabpay) == $error) {
505 setEventMessages($langs->trans("NoNewRecordSaved"), null, 'warnings');
506 } else {
507 setEventMessages($langs->trans("GeneralLedgerSomeRecordWasNotRecorded"), null, 'warnings');
508 }
509
510 $action = '';
511
512 // Must reload data, so we make a redirect
513 if (count($tabpay) != $error) {
514 $param = 'id_journal='.$id_journal;
515 $param .= '&date_startday='.$date_startday;
516 $param .= '&date_startmonth='.$date_startmonth;
517 $param .= '&date_startyear='.$date_startyear;
518 $param .= '&date_endday='.$date_endday;
519 $param .= '&date_endmonth='.$date_endmonth;
520 $param .= '&date_endyear='.$date_endyear;
521 $param .= '&in_bookkeeping='.$in_bookkeeping;
522
523 header("Location: ".$_SERVER['PHP_SELF'].($param ? '?'.$param : ''));
524 exit;
525 }
526}
527
528
529/*
530 * View
531 */
532
533$form = new Form($db);
534
535$userstatic = new User($db);
536
537// Export
538if ($action == 'exportcsv' && !$error) { // ISO and not UTF8 !
539 $sep = getDolGlobalString('ACCOUNTING_EXPORT_SEPARATORCSV');
540
541 $filename = 'journal';
542 $type_export = 'journal';
543 include DOL_DOCUMENT_ROOT.'/accountancy/tpl/export_journal.tpl.php';
544
545 $userstatic = new User($db);
546 $bookkeepingstatic = new BookKeeping($db);
547
548 // CSV header line
549 print '"'.$langs->transnoentitiesnoconv("Date").'"'.$sep;
550 print '"'.$langs->transnoentitiesnoconv("Piece").'"'.$sep;
551 print '"'.$langs->transnoentitiesnoconv("AccountAccounting").'"'.$sep;
552 print '"'.$langs->transnoentitiesnoconv("LabelOperation").'"'.$sep;
553 print '"'.$langs->transnoentitiesnoconv("AccountingDebit").'"'.$sep;
554 print '"'.$langs->transnoentitiesnoconv("AccountingCredit").'"'.$sep;
555 print "\n";
556
557 foreach ($taber as $key => $val) {
558 $date = dol_print_date($val["date"], 'day');
559
560 $userstatic->id = $tabuser[$key]['id'];
561 $userstatic->name = $tabuser[$key]['name'];
562
563 // Fees
564 foreach ($tabht[$key] as $k => $mt) {
565 $accountingaccount = new AccountingAccount($db);
566 $accountingaccount->fetch(0, $k, true);
567 if ($mt) {
568 print '"'.$date.'"'.$sep;
569 print '"'.$val["ref"].'"'.$sep;
570 print '"'.length_accountg(html_entity_decode($k)).'"'.$sep;
571 print '"'.csvClean($bookkeepingstatic->accountingLabelForOperation($userstatic->name, '', $accountingaccount->label)).'"'.$sep;
572 print '"'.($mt >= 0 ? price($mt) : '').'"'.$sep;
573 print '"'.($mt < 0 ? price(-$mt) : '').'"';
574 print "\n";
575 }
576 }
577
578 // VAT
579 foreach ($tabtva[$key] as $k => $mt) {
580 if ($mt) {
581 print '"'.$date.'"'.$sep;
582 print '"'.$val["ref"].'"'.$sep;
583 print '"'.length_accountg(html_entity_decode($k)).'"'.$sep;
584 print '"'.csvClean($bookkeepingstatic->accountingLabelForOperation($userstatic->name, '', $langs->trans("VAT").implode($def_tva[$key][$k]).' %')).'"'.$sep;
585 print '"'.($mt >= 0 ? price($mt) : '').'"'.$sep;
586 print '"'.($mt < 0 ? price(-$mt) : '').'"';
587 print "\n";
588 }
589 }
590
591 // Third party
592 foreach ($tabttc[$key] as $k => $mt) {
593 print '"'.$date.'"'.$sep;
594 print '"'.$val["ref"].'"'.$sep;
595 print '"'.length_accounta(html_entity_decode($k)).'"'.$sep;
596 print '"'.csvClean($bookkeepingstatic->accountingLabelForOperation($userstatic->name, '', $langs->trans("Thirdparty"))).'"'.$sep;
597 print '"'.($mt < 0 ? price(-$mt) : '').'"'.$sep;
598 print '"'.($mt >= 0 ? price($mt) : '').'"';
599 }
600 print "\n";
601 }
602}
603
604if (empty($action) || $action == 'view') {
605 $title = $langs->trans("GenerationOfAccountingEntries").' - '.$accountingjournalstatic->getNomUrl(0, 2, 1, '', 1);
606 $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;';
607 llxHeader('', dol_string_nohtmltag($title), $help_url, '', 0, 0, '', '', '', 'mod-accountancy accountancy-generation page-expensereportsjournal');
608
609 $nom = $title;
610 $nomlink = '';
611 $periodlink = '';
612 $exportlink = '';
613 $builddate = dol_now();
614 $description = $langs->trans("DescJournalOnlyBindedVisible").'<br>';
615
616 $listofchoices = array('notyet' => $langs->trans("NotYetInGeneralLedger"), 'already' => $langs->trans("AlreadyInGeneralLedger"));
617 $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);
618 $period .= ' - '.$langs->trans("JournalizationInLedgerStatus").' '.$form->selectarray('in_bookkeeping', $listofchoices, $in_bookkeeping, 1);
619
620 $varlink = 'id_journal='.$id_journal;
621
622 journalHead($nom, $nomlink, $period, $periodlink, $description, $builddate, $exportlink, array('action' => ''), '', $varlink);
623
624 if (getDolGlobalString('ACCOUNTANCY_FISCAL_PERIOD_MODE') != 'blockedonclosed') {
625 // Test that setup is complete (we are in accounting, so test on entity is always on $conf->entity only, no sharing allowed)
626 // Fiscal period test
627 $sql = "SELECT COUNT(rowid) as nb FROM ".MAIN_DB_PREFIX."accounting_fiscalyear WHERE entity = ".((int) $conf->entity);
628 $resql = $db->query($sql);
629 if ($resql) {
630 $obj = $db->fetch_object($resql);
631 if ($obj->nb == 0) {
632 print '<br><div class="warning">'.img_warning().' '.$langs->trans("TheFiscalPeriodIsNotDefined");
633 $desc = ' : '.$langs->trans("AccountancyAreaDescFiscalPeriod", 4, '{link}');
634 $desc = str_replace('{link}', '<strong>'.$langs->transnoentitiesnoconv("MenuAccountancy").'-'.$langs->transnoentitiesnoconv("Setup")."-".$langs->transnoentitiesnoconv("FiscalPeriod").'</strong>', $desc);
635 print $desc;
636 print '</div>';
637 }
638 } else {
639 dol_print_error($db);
640 }
641 }
642
643 // Button to write into Ledger
644 if (!getDolGlobalString('ACCOUNTING_ACCOUNT_EXPENSEREPORT') || getDolGlobalString('ACCOUNTING_ACCOUNT_EXPENSEREPORT') == '-1') {
645 print '<br><div class="warning">'.img_warning().' '.$langs->trans("SomeMandatoryStepsOfSetupWereNotDone");
646 $desc = ' : '.$langs->trans("AccountancyAreaDescMisc", 4, '{link}');
647 $desc = str_replace('{link}', '<strong>'.$langs->transnoentitiesnoconv("MenuAccountancy").'-'.$langs->transnoentitiesnoconv("Setup")."-".$langs->transnoentitiesnoconv("MenuDefaultAccounts").'</strong>', $desc);
648 print $desc;
649 print '</div>';
650 }
651 print '<br><div class="tabsAction tabsActionNoBottom centerimp">';
652
653 if (getDolGlobalString('ACCOUNTING_ENABLE_EXPORT_DRAFT_JOURNAL') && $in_bookkeeping == 'notyet') {
654 print '<input type="button" class="butAction" name="exportcsv" value="'.$langs->trans("ExportDraftJournal").'" onclick="launch_export();" />';
655 }
656 if (!getDolGlobalString('ACCOUNTING_ACCOUNT_EXPENSEREPORT') || getDolGlobalString('ACCOUNTING_ACCOUNT_EXPENSEREPORT') == '-1') {
657 print '<input type="button" class="butActionRefused classfortooltip" title="'.dol_escape_htmltag($langs->trans("SomeMandatoryStepsOfSetupWereNotDone")).'" value="'.$langs->trans("WriteBookKeeping").'" />';
658 } else {
659 if ($in_bookkeeping == 'notyet') {
660 print '<input type="button" class="butAction" name="writebookkeeping" value="'.$langs->trans("WriteBookKeeping").'" onclick="writebookkeeping();" />';
661 } else {
662 print '<a href="#" class="butActionRefused classfortooltip" name="writebookkeeping">'.$langs->trans("WriteBookKeeping").'</a>';
663 }
664 }
665 print '</div>';
666
667 // TODO Avoid using js. We can use a direct link with $param
668 print '
669 <script type="text/javascript">
670 function launch_export() {
671 $("div.fiche form input[name=\"action\"]").val("exportcsv");
672 $("div.fiche form input[type=\"submit\"]").click();
673 $("div.fiche form input[name=\"action\"]").val("");
674 }
675 function writebookkeeping() {
676 console.log("click on writebookkeeping");
677 $("div.fiche form input[name=\"action\"]").val("writebookkeeping");
678 $("div.fiche form input[type=\"submit\"]").click();
679 $("div.fiche form input[name=\"action\"]").val("");
680 }
681 </script>';
682
683 /*
684 * Show result array
685 */
686 print '<br>';
687
688 $i = 0;
689 print '<div class="div-table-responsive">';
690 print "<table class=\"noborder\" width=\"100%\">";
691 print "<tr class=\"liste_titre\">";
692 print "<td>".$langs->trans("Date")."</td>";
693 print "<td>".$langs->trans("Piece").' ('.$langs->trans("ExpenseReportRef").")</td>";
694 print "<td>".$langs->trans("AccountAccounting")."</td>";
695 print "<td>".$langs->trans("SubledgerAccount")."</td>";
696 print "<td>".$langs->trans("LabelOperation")."</td>";
697 print '<td class="right">'.$langs->trans("AccountingDebit")."</td>";
698 print '<td class="right">'.$langs->trans("AccountingCredit")."</td>";
699 print "</tr>\n";
700
701 $i = 0;
702
703 $expensereportstatic = new ExpenseReport($db);
704 $expensereportlinestatic = new ExpenseReportLine($db);
705 $bookkeepingstatic = new BookKeeping($db);
706
707 foreach ($taber as $key => $val) {
708 $expensereportstatic->id = $key;
709 $expensereportstatic->ref = $val["ref"];
710 $expensereportlinestatic->comments = html_entity_decode(dol_trunc($val["comments"], 32));
711
712 $date = dol_print_date($val["date"], 'day');
713
714 if ($errorforinvoice[$key] == 'somelinesarenotbound') {
715 print '<tr class="oddeven">';
716 print "<!-- Some lines are not bound -->";
717 print "<td>".$date."</td>";
718 print "<td>".$expensereportstatic->getNomUrl(1)."</td>";
719 // Account
720 print "<td>";
721 print '<span class="error">'.$langs->trans('ErrorInvoiceContainsLinesNotYetBoundedShort', $val['ref']).'</span>';
722 print '</td>';
723 // Subledger account
724 print "<td>";
725 print '</td>';
726 print "<td>";
727 print "</td>";
728 print '<td class="right"></td>';
729 print '<td class="right"></td>';
730 print "</tr>";
731
732 $i++;
733 }
734
735 // Fees
736 foreach ($tabht[$key] as $k => $mt) {
737 if (empty($conf->cache['accountingaccountincurrententity'][$k])) {
738 $accountingaccount = new AccountingAccount($db);
739 $accountingaccount->fetch(0, $k, true);
740 $conf->cache['accountingaccountincurrententity'][$k] = $accountingaccount;
741 } else {
742 $accountingaccount = $conf->cache['accountingaccountincurrententity'][$k];
743 }
744
745 if ($mt) {
746 print '<tr class="oddeven">';
747 print "<!-- Fees -->";
748 print "<td>".$date."</td>";
749 print "<td>".$expensereportstatic->getNomUrl(1)."</td>";
750 $userstatic->id = $tabuser[$key]['id'];
751 $userstatic->name = $tabuser[$key]['name'];
752 // Account
753 print "<td>";
754 $accountoshow = length_accountg($k);
755 if (($accountoshow == "") || $accountoshow == 'NotDefined') {
756 print '<span class="error">'.$langs->trans("FeeAccountNotDefined").'</span>';
757 } else {
758 print $accountoshow;
759 }
760 print '</td>';
761 // Subledger account
762 print "<td>";
763 print '</td>';
764 $userstatic->id = $tabuser[$key]['id'];
765 $userstatic->name = $tabuser[$key]['name'];
766 print "<td>" . $bookkeepingstatic->accountingLabelForOperation($userstatic->getNomUrl(0, 'user'), '', $accountingaccount->label) . "</td>";
767 print '<td class="right nowraponall amount">'.($mt >= 0 ? price($mt) : '')."</td>";
768 print '<td class="right nowraponall amount">'.($mt < 0 ? price(-$mt) : '')."</td>";
769 print "</tr>";
770
771 $i++;
772 }
773 }
774
775 // Third party
776 foreach ($tabttc[$key] as $k => $mt) {
777 $userstatic->id = $tabuser[$key]['id'];
778 $userstatic->name = $tabuser[$key]['name'];
779
780 print '<tr class="oddeven">';
781 print "<!-- Thirdparty -->";
782 print "<td>".$date."</td>";
783 print "<td>".$expensereportstatic->getNomUrl(1)."</td>";
784 // Account
785 print "<td>";
786 $accountoshow = length_accountg(getDolGlobalString('ACCOUNTING_ACCOUNT_EXPENSEREPORT'));
787 if (($accountoshow == "") || $accountoshow == 'NotDefined') {
788 print '<span class="error">'.$langs->trans("MainAccountForUsersNotDefined").'</span>';
789 } else {
790 print $accountoshow;
791 }
792 print "</td>";
793 // Subledger account
794 print "<td>";
795 $accountoshow = length_accounta($k);
796 if (($accountoshow == "") || $accountoshow == 'NotDefined') {
797 print '<span class="error">'.$langs->trans("UserAccountNotDefined").'</span>';
798 } else {
799 print $accountoshow;
800 }
801 print '</td>';
802 print "<td>" . $bookkeepingstatic->accountingLabelForOperation($userstatic->getNomUrl(0, 'user'), '', $langs->trans("SubledgerAccount")) . "</td>";
803 print '<td class="right nowraponall amount">'.($mt < 0 ? price(-$mt) : '')."</td>";
804 print '<td class="right nowraponall amount">'.($mt >= 0 ? price($mt) : '')."</td>";
805 print "</tr>";
806
807 $i++;
808 }
809
810 // VAT
811 $listoftax = array(0, 1, 2);
812 foreach ($listoftax as $numtax) {
813 $arrayofvat = $tabtva;
814 if ($numtax == 1) {
815 $arrayofvat = $tablocaltax1;
816 }
817 if ($numtax == 2) {
818 $arrayofvat = $tablocaltax2;
819 }
820
821 foreach ($arrayofvat[$key] as $k => $mt) {
822 if ($mt) {
823 print '<tr class="oddeven">';
824 print "<!-- VAT -->";
825 print "<td>".$date."</td>";
826 print "<td>".$expensereportstatic->getNomUrl(1)."</td>";
827 // Account
828 print "<td>";
829 $accountoshow = length_accountg($k);
830 if (($accountoshow == "") || $accountoshow == 'NotDefined') {
831 print '<span class="error">'.$langs->trans("VATAccountNotDefined").'</span>';
832 } else {
833 print $accountoshow;
834 }
835 print "</td>";
836 // Subledger account
837 print "<td>";
838 print '</td>';
839 $tmpvatrate = (empty($def_tva[$key][$k]) ? (empty($arrayofvat[$key][$k]) ? '' : $arrayofvat[$key][$k]) : implode(', ', $def_tva[$key][$k]));
840 $labelvatrate = $langs->trans("Taxes").' '.$tmpvatrate.' %';
841 $labelvatrate .= ($numtax ? ' - Localtax '.$numtax : '');
842 print "<td>" . $bookkeepingstatic->accountingLabelForOperation($userstatic->getNomUrl(0, 'user'), '', $labelvatrate) . "</td>";
843 print '<td class="right nowraponall amount">'.($mt >= 0 ? price($mt) : '')."</td>";
844 print '<td class="right nowraponall amount">'.($mt < 0 ? price(-$mt) : '')."</td>";
845 print "</tr>";
846
847 $i++;
848 }
849 }
850 }
851 }
852
853 if (!$i) {
854 $colspan = 7;
855 print '<tr class="oddeven"><td colspan="'.$colspan.'"><span class="opacitymedium">'.$langs->trans("NoRecordFound").'</span></td></tr>';
856 }
857
858 print "</table>";
859 print '</div>';
860
861 // End of page
862 llxFooter();
863}
864$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.
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
llxFooter()
Footer empty.
Definition document.php:107
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.