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