dolibarr 19.0.4
bookkeeping.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2014-2017 Olivier Geffroy <jeff@jeffinfo.com>
3 * Copyright (C) 2015-2022 Alexandre Spangaro <aspangaro@open-dsi.fr>
4 * Copyright (C) 2015-2020 Florian Henry <florian.henry@open-concept.pro>
5 * Copyright (C) 2018-2020 Frédéric France <frederic.france@netlogic.fr>
6 * Copyright (C) 2024 Jose MARTINEZ <jose.martinez@pichinov.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
28// Class
29require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
30require_once DOL_DOCUMENT_ROOT.'/core/class/commonobjectline.class.php';
31require_once DOL_DOCUMENT_ROOT.'/core/class/fiscalyear.class.php';
32require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingjournal.class.php';
33require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingaccount.class.php';
34
39{
43 public $element = 'accountingbookkeeping';
44
48 public $table_element = 'accounting_bookkeeping';
49
53 public $entity;
54
58 public $lines = array();
59
63 public $id;
64
68 public $doc_date;
69
73 public $date_lim_reglement;
74
78 public $doc_type;
79
83 public $doc_ref;
84
88 public $fk_doc;
89
93 public $fk_docdet;
94
98 public $thirdparty_code;
99
103 public $subledger_account;
104
108 public $subledger_label;
109
113 public $numero_compte;
114
118 public $label_compte;
119
123 public $label_operation;
124
128 public $debit;
129
133 public $credit;
134
139 public $montant;
140
145 public $amount;
146
150 public $sens;
151
155 public $fk_user_author;
156
160 public $import_key;
161
165 public $code_journal;
166
170 public $journal_label;
171
175 public $piece_num;
176
180 public $linesmvt = array();
181
185 public $linesexport = array();
186
190 public $date_validation;
191
195 public $date_export;
196
200 public $picto = 'generic';
201
205 public static $can_modify_bookkeeping_sql_cached;
206
207
213 public function __construct(DoliDB $db)
214 {
215 $this->db = $db;
216 }
217
225 public function create(User $user, $notrigger = false)
226 {
227 global $conf, $langs;
228
229 dol_syslog(__METHOD__, LOG_DEBUG);
230
231 $error = 0;
232
233 // Clean parameters</center>
234 if (isset($this->doc_type)) {
235 $this->doc_type = trim($this->doc_type);
236 }
237 if (isset($this->doc_ref)) {
238 $this->doc_ref = trim($this->doc_ref);
239 }
240 if (isset($this->fk_doc)) {
241 $this->fk_doc = (int) $this->fk_doc;
242 }
243 if (isset($this->fk_docdet)) {
244 $this->fk_docdet = (int) $this->fk_docdet;
245 }
246 if (isset($this->thirdparty_code)) {
247 $this->thirdparty_code = trim($this->thirdparty_code);
248 }
249 if (isset($this->subledger_account)) {
250 $this->subledger_account = trim($this->subledger_account);
251 }
252 if (isset($this->subledger_label)) {
253 $this->subledger_label = trim($this->subledger_label);
254 }
255 if (isset($this->numero_compte)) {
256 $this->numero_compte = trim($this->numero_compte);
257 }
258 if (isset($this->label_compte)) {
259 $this->label_compte = trim($this->label_compte);
260 }
261 if (isset($this->label_operation)) {
262 $this->label_operation = trim($this->label_operation);
263 }
264 if (isset($this->debit)) {
265 $this->debit = (float) $this->debit;
266 }
267 if (isset($this->credit)) {
268 $this->credit = (float) $this->credit;
269 }
270 if (isset($this->montant)) {
271 $this->montant = (float) $this->montant;
272 }
273 if (isset($this->amount)) {
274 $this->amount = (float) $this->amount;
275 }
276 if (isset($this->sens)) {
277 $this->sens = trim($this->sens);
278 }
279 if (isset($this->import_key)) {
280 $this->import_key = trim($this->import_key);
281 }
282 if (isset($this->code_journal)) {
283 $this->code_journal = trim($this->code_journal);
284 }
285 if (isset($this->journal_label)) {
286 $this->journal_label = trim($this->journal_label);
287 }
288 if (isset($this->piece_num)) {
289 $this->piece_num = trim($this->piece_num);
290 }
291 if (empty($this->debit)) {
292 $this->debit = 0.0;
293 }
294 if (empty($this->credit)) {
295 $this->credit = 0.0;
296 }
297
298 $result = $this->validBookkeepingDate($this->doc_date);
299 if ($result < 0) {
300 return -1;
301 } elseif ($result == 0) {
302 if (getDolGlobalString('ACCOUNTANCY_FISCAL_PERIOD_MODE') == 'blockedonclosed') {
303 $this->errors[] = $langs->trans('ErrorBookkeepingDocDateIsOnAClosedFiscalPeriod');
304 } else {
305 $this->errors[] = $langs->trans('ErrorBookkeepingDocDateNotOnActiveFiscalPeriod');
306 }
307 return -1;
308 }
309
310 // Check parameters
311 if (($this->numero_compte == "") || $this->numero_compte == '-1' || $this->numero_compte == 'NotDefined') {
312 $langs->loadLangs(array("errors"));
313 if (in_array($this->doc_type, array('bank', 'expense_report'))) {
314 $this->errors[] = $langs->trans('ErrorFieldAccountNotDefinedForBankLine', $this->fk_docdet, $this->doc_type);
315 } else {
316 //$this->errors[]=$langs->trans('ErrorFieldAccountNotDefinedForInvoiceLine', $this->doc_ref, $this->label_compte);
317 $mesg = $this->doc_ref.', '.$langs->trans("AccountAccounting").': '.($this->numero_compte != -1 ? $this->numero_compte : $langs->trans("Unknown"));
318 if ($this->subledger_account && $this->subledger_account != $this->numero_compte) {
319 $mesg .= ', '.$langs->trans("SubledgerAccount").': '.$this->subledger_account;
320 }
321 $this->errors[] = $langs->trans('ErrorFieldAccountNotDefinedForLine', $mesg);
322 }
323
324 return -1;
325 }
326
327 $this->db->begin();
328
329 $this->piece_num = 0;
330
331 // First check if line not yet already in bookkeeping.
332 // Note that we must include 'doc_type - fk_doc - numero_compte - label - subledger_account (if not empty)' to be sure to have unicity of line (because we may have several lines
333 // with same doc_type, fk_doc, numero_compte for 1 invoice line when using localtaxes with same account)
334 // WARNING: This is not reliable, label may have been modified. This is just a small protection.
335 // The page that make transfer make the test on couple (doc_type - fk_doc) only.
336 $sql = "SELECT count(*) as nb";
337 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element;
338 $sql .= " WHERE doc_type = '".$this->db->escape($this->doc_type)."'";
339 $sql .= " AND fk_doc = ".((int) $this->fk_doc);
340 if (getDolGlobalString('ACCOUNTANCY_ENABLE_FKDOCDET')) {
341 // DO NOT USE THIS IN PRODUCTION. This will generate a lot of trouble into reports and will corrupt database (by generating duplicate entries.
342 $sql .= " AND fk_docdet = ".((int) $this->fk_docdet); // This field can be 0 if record is for several lines
343 }
344 $sql .= " AND numero_compte = '".$this->db->escape($this->numero_compte)."'";
345 $sql .= " AND label_operation = '".$this->db->escape($this->label_operation)."'";
346 if (!empty($this->subledger_account)) {
347 $sql .= " AND subledger_account = '".$this->db->escape($this->subledger_account)."'";
348 }
349 $sql .= " AND entity = ".$conf->entity; // Do not use getEntity for accounting features
350
351 $resql = $this->db->query($sql);
352
353 if ($resql) {
354 $row = $this->db->fetch_object($resql);
355 if ($row->nb == 0) { // Not already into bookkeeping
356 // Check to know if piece_num already exists for data we try to insert to reuse the same value
357 $sqlnum = "SELECT piece_num";
358 $sqlnum .= " FROM ".MAIN_DB_PREFIX.$this->table_element;
359 $sqlnum .= " WHERE doc_type = '".$this->db->escape($this->doc_type)."'"; // For example doc_type = 'bank'
360 $sqlnum .= " AND fk_doc = ".((int) $this->fk_doc);
361 if (getDolGlobalString('ACCOUNTANCY_ENABLE_FKDOCDET')) {
362 // fk_docdet is rowid into llx_bank or llx_facturedet or llx_facturefourndet, or ...
363 $sqlnum .= " AND fk_docdet = ".((int) $this->fk_docdet);
364 }
365 $sqlnum .= " AND doc_ref = '".$this->db->escape($this->doc_ref)."'"; // ref of source object
366 $sqlnum .= " AND entity = ".$conf->entity; // Do not use getEntity for accounting features
367
368 dol_syslog(get_class($this).":: create sqlnum=".$sqlnum, LOG_DEBUG);
369 $resqlnum = $this->db->query($sqlnum);
370 if ($resqlnum) {
371 $objnum = $this->db->fetch_object($resqlnum);
372 $this->piece_num = $objnum->piece_num;
373 }
374
375 dol_syslog(get_class($this)."::create this->piece_num=".$this->piece_num, LOG_DEBUG);
376 if (empty($this->piece_num)) {
377 $sqlnum = "SELECT MAX(piece_num)+1 as maxpiecenum";
378 $sqlnum .= " FROM ".MAIN_DB_PREFIX.$this->table_element;
379 $sqlnum .= " WHERE entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
380
381 $resqlnum = $this->db->query($sqlnum);
382 if ($resqlnum) {
383 $objnum = $this->db->fetch_object($resqlnum);
384 $this->piece_num = $objnum->maxpiecenum;
385 }
386 dol_syslog(get_class($this).":: create now this->piece_num=".$this->piece_num, LOG_DEBUG);
387 }
388 if (empty($this->piece_num)) {
389 $this->piece_num = 1;
390 }
391
392 $now = dol_now();
393
394 $sql = "INSERT INTO ".MAIN_DB_PREFIX.$this->table_element." (";
395 $sql .= "doc_date";
396 $sql .= ", date_lim_reglement";
397 $sql .= ", doc_type";
398 $sql .= ", doc_ref";
399 $sql .= ", fk_doc";
400 $sql .= ", fk_docdet";
401 $sql .= ", thirdparty_code";
402 $sql .= ", subledger_account";
403 $sql .= ", subledger_label";
404 $sql .= ", numero_compte";
405 $sql .= ", label_compte";
406 $sql .= ", label_operation";
407 $sql .= ", debit";
408 $sql .= ", credit";
409 $sql .= ", montant";
410 $sql .= ", sens";
411 $sql .= ", fk_user_author";
412 $sql .= ", date_creation";
413 $sql .= ", code_journal";
414 $sql .= ", journal_label";
415 $sql .= ", piece_num";
416 $sql .= ', entity';
417 $sql .= ") VALUES (";
418 $sql .= "'".$this->db->idate($this->doc_date)."'";
419 $sql .= ", ".(!isset($this->date_lim_reglement) || dol_strlen($this->date_lim_reglement) == 0 ? 'NULL' : "'".$this->db->idate($this->date_lim_reglement)."'");
420 $sql .= ", '".$this->db->escape($this->doc_type)."'";
421 $sql .= ", '".$this->db->escape($this->doc_ref)."'";
422 $sql .= ", ".((int) $this->fk_doc);
423 $sql .= ", ".((int) $this->fk_docdet);
424 $sql .= ", ".(!empty($this->thirdparty_code) ? ("'".$this->db->escape($this->thirdparty_code)."'") : "NULL");
425 $sql .= ", ".(!empty($this->subledger_account) ? ("'".$this->db->escape($this->subledger_account)."'") : "NULL");
426 $sql .= ", ".(!empty($this->subledger_label) ? ("'".$this->db->escape($this->subledger_label)."'") : "NULL");
427 $sql .= ", '".$this->db->escape($this->numero_compte)."'";
428 $sql .= ", ".(!empty($this->label_compte) ? ("'".$this->db->escape($this->label_compte)."'") : "NULL");
429 $sql .= ", '".$this->db->escape($this->label_operation)."'";
430 $sql .= ", ".((float) $this->debit);
431 $sql .= ", ".((float) $this->credit);
432 $sql .= ", ".((float) $this->montant);
433 $sql .= ", ".(!empty($this->sens) ? ("'".$this->db->escape($this->sens)."'") : "NULL");
434 $sql .= ", '".$this->db->escape($this->fk_user_author)."'";
435 $sql .= ", '".$this->db->idate($now)."'";
436 $sql .= ", '".$this->db->escape($this->code_journal)."'";
437 $sql .= ", ".(!empty($this->journal_label) ? ("'".$this->db->escape($this->journal_label)."'") : "NULL");
438 $sql .= ", ".((int) $this->piece_num);
439 $sql .= ", ".(!isset($this->entity) ? $conf->entity : $this->entity);
440 $sql .= ")";
441
442 $resql = $this->db->query($sql);
443 if ($resql) {
444 $id = $this->db->last_insert_id(MAIN_DB_PREFIX.$this->table_element);
445
446 if ($id > 0) {
447 $this->id = $id;
448 $result = 0;
449 } else {
450 $result = -2;
451 $error++;
452 $this->errors[] = 'Error Create Error '.$result.' lecture ID';
453 dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
454 }
455 } else {
456 $result = -1;
457 $error++;
458 $this->errors[] = 'Error '.$this->db->lasterror();
459 dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
460 }
461 } else { // Already exists
462 $result = -3;
463 $error++;
464 $this->error = 'BookkeepingRecordAlreadyExists';
465 dol_syslog(__METHOD__.' '.$this->error, LOG_WARNING);
466 }
467 } else {
468 $result = -5;
469 $error++;
470 $this->errors[] = 'Error '.$this->db->lasterror();
471 dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
472 }
473
474 // Uncomment this and change MYOBJECT to your own tag if you
475 // want this action to call a trigger.
476 //if (! $error && ! $notrigger) {
477
478 // // Call triggers
479 // $result=$this->call_trigger('MYOBJECT_CREATE',$user);
480 // if ($result < 0) $error++;
481 // // End call triggers
482 //}
483
484 // Commit or rollback
485 if ($error) {
486 $this->db->rollback();
487 return -1 * $error;
488 } else {
489 $this->db->commit();
490 return $result;
491 }
492 }
493
504 public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
505 {
506 global $db, $conf, $langs;
507 global $dolibarr_main_authentication, $dolibarr_main_demo;
508 global $menumanager, $hookmanager;
509
510 if (!empty($conf->dol_no_mouse_hover)) {
511 $notooltip = 1; // Force disable tooltips
512 }
513
514 $result = '';
515 $companylink = '';
516
517 $label = '<u>'.$langs->trans("Transaction").'</u>';
518 $label .= '<br>';
519 $label .= '<b>'.$langs->trans('Ref').':</b> '.$this->piece_num;
520
521 $url = DOL_URL_ROOT.'/accountancy/bookkeeping/card.php?piece_num='.$this->piece_num;
522
523 if ($option != 'nolink') {
524 // Add param to save lastsearch_values or not
525 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
526 if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
527 $add_save_lastsearch_values = 1;
528 }
529 if ($add_save_lastsearch_values) {
530 $url .= '&save_lastsearch_values=1';
531 }
532 }
533
534 $linkclose = '';
535 if (empty($notooltip)) {
536 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
537 $label = $langs->trans("ShowTransaction");
538 $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
539 }
540 $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
541 $linkclose .= ' class="classfortooltip'.($morecss ? ' '.$morecss : '').'"';
542 } else {
543 $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
544 }
545
546 $linkstart = '<a href="'.$url.'"';
547 $linkstart .= $linkclose.'>';
548 $linkend = '</a>';
549
550 $result .= $linkstart;
551 if ($withpicto) {
552 $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip ? 0 : 1);
553 }
554 if ($withpicto != 2) {
555 $result .= $this->piece_num;
556 }
557 $result .= $linkend;
558 //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
559
560 global $action;
561 $hookmanager->initHooks(array($this->element . 'dao'));
562 $parameters = array('id'=>$this->id, 'getnomurl' => &$result);
563 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
564 if ($reshook > 0) {
565 $result = $hookmanager->resPrint;
566 } else {
567 $result .= $hookmanager->resPrint;
568 }
569 return $result;
570 }
571
580 public function createStd(User $user, $notrigger = false, $mode = '')
581 {
582 global $conf, $langs;
583
584 $langs->loadLangs(array("accountancy", "bills", "compta"));
585
586 dol_syslog(__METHOD__, LOG_DEBUG);
587
588 $error = 0;
589
590 // Clean parameters
591 if (isset($this->doc_type)) {
592 $this->doc_type = trim($this->doc_type);
593 }
594 if (isset($this->doc_ref)) {
595 $this->doc_ref = trim($this->doc_ref);
596 }
597 if (isset($this->fk_doc)) {
598 $this->fk_doc = (int) $this->fk_doc;
599 }
600 if (isset($this->fk_docdet)) {
601 $this->fk_docdet = (int) $this->fk_docdet;
602 }
603 if (isset($this->thirdparty_code)) {
604 $this->thirdparty_code = trim($this->thirdparty_code);
605 }
606 if (isset($this->subledger_account)) {
607 $this->subledger_account = trim($this->subledger_account);
608 }
609 if (isset($this->subledger_label)) {
610 $this->subledger_label = trim($this->subledger_label);
611 }
612 if (isset($this->numero_compte)) {
613 $this->numero_compte = trim($this->numero_compte);
614 }
615 if (isset($this->label_compte)) {
616 $this->label_compte = trim($this->label_compte);
617 }
618 if (isset($this->label_operation)) {
619 $this->label_operation = trim($this->label_operation);
620 }
621 if (isset($this->debit)) {
622 $this->debit = trim($this->debit);
623 }
624 if (isset($this->credit)) {
625 $this->credit = trim($this->credit);
626 }
627 if (isset($this->montant)) {
628 $this->montant = trim($this->montant);
629 }
630 if (isset($this->amount)) {
631 $this->amount = trim($this->amount);
632 }
633 if (isset($this->sens)) {
634 $this->sens = trim($this->sens);
635 }
636 if (isset($this->import_key)) {
637 $this->import_key = trim($this->import_key);
638 }
639 if (isset($this->code_journal)) {
640 $this->code_journal = trim($this->code_journal);
641 }
642 if (isset($this->journal_label)) {
643 $this->journal_label = trim($this->journal_label);
644 }
645 if (isset($this->piece_num)) {
646 $this->piece_num = trim($this->piece_num);
647 }
648 if (empty($this->debit)) {
649 $this->debit = 0;
650 }
651 if (empty($this->credit)) {
652 $this->credit = 0;
653 }
654 if (empty($this->montant)) {
655 $this->montant = 0;
656 }
657
658 $result = $this->validBookkeepingDate($this->doc_date);
659 if ($result < 0) {
660 return -1;
661 } elseif ($result == 0) {
662 if (getDolGlobalString('ACCOUNTANCY_FISCAL_PERIOD_MODE') == 'blockedonclosed') {
663 $this->errors[] = $langs->trans('ErrorBookkeepingDocDateIsOnAClosedFiscalPeriod');
664 } else {
665 $this->errors[] = $langs->trans('ErrorBookkeepingDocDateNotOnActiveFiscalPeriod');
666 }
667 return -1;
668 }
669
670 $this->debit = price2num($this->debit, 'MT');
671 $this->credit = price2num($this->credit, 'MT');
672 $this->montant = price2num($this->montant, 'MT');
673
674 $now = dol_now();
675
676 // Check parameters
677 $this->journal_label = $langs->trans($this->journal_label);
678
679 // Insert request
680 $sql = 'INSERT INTO '.MAIN_DB_PREFIX.$this->table_element.$mode.' (';
681 $sql .= 'doc_date,';
682 $sql .= 'date_lim_reglement,';
683 $sql .= 'doc_type,';
684 $sql .= 'doc_ref,';
685 $sql .= 'fk_doc,';
686 $sql .= 'fk_docdet,';
687 $sql .= 'thirdparty_code,';
688 $sql .= 'subledger_account,';
689 $sql .= 'subledger_label,';
690 $sql .= 'numero_compte,';
691 $sql .= 'label_compte,';
692 $sql .= 'label_operation,';
693 $sql .= 'debit,';
694 $sql .= 'credit,';
695 $sql .= 'montant,';
696 $sql .= 'sens,';
697 $sql .= 'fk_user_author,';
698 $sql .= 'date_creation,';
699 $sql .= 'code_journal,';
700 $sql .= 'journal_label,';
701 $sql .= 'piece_num,';
702 $sql .= 'entity';
703 $sql .= ') VALUES (';
704 $sql .= ' '.(!isset($this->doc_date) || dol_strlen($this->doc_date) == 0 ? 'NULL' : "'".$this->db->idate($this->doc_date)."'").',';
705 $sql .= ' '.(!isset($this->date_lim_reglement) || dol_strlen($this->date_lim_reglement) == 0 ? 'NULL' : "'".$this->db->idate($this->date_lim_reglement)."'").',';
706 $sql .= ' '.(!isset($this->doc_type) ? 'NULL' : "'".$this->db->escape($this->doc_type)."'").',';
707 $sql .= ' '.(!isset($this->doc_ref) ? 'NULL' : "'".$this->db->escape($this->doc_ref)."'").',';
708 $sql .= ' '.(empty($this->fk_doc) ? '0' : (int) $this->fk_doc).',';
709 $sql .= ' '.(empty($this->fk_docdet) ? '0' : (int) $this->fk_docdet).',';
710 $sql .= ' '.(!isset($this->thirdparty_code) ? 'NULL' : "'".$this->db->escape($this->thirdparty_code)."'").',';
711 $sql .= ' '.(!isset($this->subledger_account) ? 'NULL' : "'".$this->db->escape($this->subledger_account)."'").',';
712 $sql .= ' '.(!isset($this->subledger_label) ? 'NULL' : "'".$this->db->escape($this->subledger_label)."'").',';
713 $sql .= ' '.(!isset($this->numero_compte) ? 'NULL' : "'".$this->db->escape($this->numero_compte)."'").',';
714 $sql .= ' '.(!isset($this->label_compte) ? 'NULL' : "'".$this->db->escape($this->label_compte)."'").',';
715 $sql .= ' '.(!isset($this->label_operation) ? 'NULL' : "'".$this->db->escape($this->label_operation)."'").',';
716 $sql .= ' '.(!isset($this->debit) ? 'NULL' : $this->debit).',';
717 $sql .= ' '.(!isset($this->credit) ? 'NULL' : $this->credit).',';
718 $sql .= ' '.(!isset($this->montant) ? 'NULL' : $this->montant).',';
719 $sql .= ' '.(!isset($this->sens) ? 'NULL' : "'".$this->db->escape($this->sens)."'").',';
720 $sql .= ' '.((int) $user->id).',';
721 $sql .= ' '."'".$this->db->idate($now)."',";
722 $sql .= ' '.(empty($this->code_journal) ? 'NULL' : "'".$this->db->escape($this->code_journal)."'").',';
723 $sql .= ' '.(empty($this->journal_label) ? 'NULL' : "'".$this->db->escape($this->journal_label)."'").',';
724 $sql .= ' '.(empty($this->piece_num) ? 'NULL' : $this->db->escape($this->piece_num)).',';
725 $sql .= ' '.(!isset($this->entity) ? $conf->entity : $this->entity);
726 $sql .= ')';
727
728 $this->db->begin();
729
730 $resql = $this->db->query($sql);
731 if (!$resql) {
732 $error++;
733 $this->errors[] = 'Error '.$this->db->lasterror();
734 dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
735 }
736
737 if (!$error) {
738 $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.$this->table_element.$mode);
739
740 // Uncomment this and change MYOBJECT to your own tag if you
741 // want this action to call a trigger.
742 //if (! $notrigger) {
743
744 // // Call triggers
745 // $result=$this->call_trigger('MYOBJECT_CREATE',$user);
746 // if ($result < 0) $error++;
747 // // End call triggers
748 //}
749 }
750
751 // Commit or rollback
752 if ($error) {
753 $this->db->rollback();
754
755 return -1 * $error;
756 } else {
757 $this->db->commit();
758
759 return $this->id;
760 }
761 }
762
771 public function fetch($id, $ref = null, $mode = '')
772 {
773 global $conf;
774
775 dol_syslog(__METHOD__, LOG_DEBUG);
776
777 $sql = 'SELECT';
778 $sql .= ' t.rowid,';
779 $sql .= " t.doc_date,";
780 $sql .= " t.date_lim_reglement,";
781 $sql .= " t.doc_type,";
782 $sql .= " t.doc_ref,";
783 $sql .= " t.fk_doc,";
784 $sql .= " t.fk_docdet,";
785 $sql .= " t.thirdparty_code,";
786 $sql .= " t.subledger_account,";
787 $sql .= " t.subledger_label,";
788 $sql .= " t.numero_compte,";
789 $sql .= " t.label_compte,";
790 $sql .= " t.label_operation,";
791 $sql .= " t.debit,";
792 $sql .= " t.credit,";
793 $sql .= " t.montant as amount,";
794 $sql .= " t.sens,";
795 $sql .= " t.fk_user_author,";
796 $sql .= " t.import_key,";
797 $sql .= " t.code_journal,";
798 $sql .= " t.journal_label,";
799 $sql .= " t.piece_num,";
800 $sql .= " t.date_creation,";
801 // In llx_accounting_bookkeeping_tmp, field date_export doesn't exist
802 if ($mode != "_tmp") {
803 $sql .= " t.date_export,";
804 }
805 $sql .= " t.date_validated as date_validation";
806 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.$mode.' as t';
807 $sql .= ' WHERE 1 = 1';
808 $sql .= " AND entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
809 if (null !== $ref) {
810 $sql .= " AND t.rowid = ".((int) $ref);
811 } else {
812 $sql .= " AND t.rowid = ".((int) $id);
813 }
814
815 $resql = $this->db->query($sql);
816 if ($resql) {
817 $numrows = $this->db->num_rows($resql);
818 if ($numrows) {
819 $obj = $this->db->fetch_object($resql);
820
821 $this->id = $obj->rowid;
822
823 $this->doc_date = $this->db->jdate($obj->doc_date);
824 $this->date_lim_reglement = $this->db->jdate($obj->date_lim_reglement);
825 $this->doc_type = $obj->doc_type;
826 $this->doc_ref = $obj->doc_ref;
827 $this->fk_doc = $obj->fk_doc;
828 $this->fk_docdet = $obj->fk_docdet;
829 $this->thirdparty_code = $obj->thirdparty_code;
830 $this->subledger_account = $obj->subledger_account;
831 $this->subledger_label = $obj->subledger_label;
832 $this->numero_compte = $obj->numero_compte;
833 $this->label_compte = $obj->label_compte;
834 $this->label_operation = $obj->label_operation;
835 $this->debit = $obj->debit;
836 $this->credit = $obj->credit;
837 $this->montant = $obj->amount;
838 $this->amount = $obj->amount;
839 $this->sens = $obj->sens;
840 $this->fk_user_author = $obj->fk_user_author;
841 $this->import_key = $obj->import_key;
842 $this->code_journal = $obj->code_journal;
843 $this->journal_label = $obj->journal_label;
844 $this->piece_num = $obj->piece_num;
845 $this->date_creation = $this->db->jdate($obj->date_creation);
846 $this->date_export = $this->db->jdate($obj->date_export);
847 $this->date_validation = isset($obj->date_validation) ? $this->db->jdate($obj->date_validation) : '';
848 }
849 $this->db->free($resql);
850
851 if ($numrows) {
852 return 1;
853 } else {
854 return 0;
855 }
856 } else {
857 $this->errors[] = 'Error '.$this->db->lasterror();
858 dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
859
860 return -1;
861 }
862 }
863
864
878 public function fetchAllByAccount($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND', $option = 0, $countonly = 0)
879 {
880 global $conf;
881
882 dol_syslog(__METHOD__, LOG_DEBUG);
883
884 $this->lines = array();
885 $num = 0;
886
887 $sql = 'SELECT';
888 if ($countonly) {
889 $sql .= ' COUNT(t.rowid) as nb';
890 } else {
891 $sql .= ' t.rowid,';
892 $sql .= " t.doc_date,";
893 $sql .= " t.doc_type,";
894 $sql .= " t.doc_ref,";
895 $sql .= " t.fk_doc,";
896 $sql .= " t.fk_docdet,";
897 $sql .= " t.thirdparty_code,";
898 $sql .= " t.subledger_account,";
899 $sql .= " t.subledger_label,";
900 $sql .= " t.numero_compte,";
901 $sql .= " t.label_compte,";
902 $sql .= " t.label_operation,";
903 $sql .= " t.debit,";
904 $sql .= " t.credit,";
905 $sql .= " t.montant as amount,";
906 $sql .= " t.sens,";
907 $sql .= " t.multicurrency_amount,";
908 $sql .= " t.multicurrency_code,";
909 $sql .= " t.lettering_code,";
910 $sql .= " t.date_lettering,";
911 $sql .= " t.fk_user_author,";
912 $sql .= " t.import_key,";
913 $sql .= " t.code_journal,";
914 $sql .= " t.journal_label,";
915 $sql .= " t.piece_num,";
916 $sql .= " t.date_creation,";
917 $sql .= " t.date_export,";
918 $sql .= " t.date_validated as date_validation,";
919 $sql .= " t.import_key";
920 }
921 // Manage filter
922 $sqlwhere = array();
923 if (count($filter) > 0) {
924 foreach ($filter as $key => $value) {
925 if ($key == 't.doc_date') {
926 $sqlwhere[] = $key.'=\''.$this->db->idate($value).'\'';
927 } elseif ($key == 't.doc_date>=' || $key == 't.doc_date<=') {
928 $sqlwhere[] = $key.'\''.$this->db->idate($value).'\'';
929 } elseif ($key == 't.numero_compte>=' || $key == 't.numero_compte<=' || $key == 't.subledger_account>=' || $key == 't.subledger_account<=') {
930 $sqlwhere[] = $key.'\''.$this->db->escape($value).'\'';
931 } elseif ($key == 't.fk_doc' || $key == 't.fk_docdet' || $key == 't.piece_num') {
932 $sqlwhere[] = $key.'='.$value;
933 } elseif ($key == 't.subledger_account' || $key == 't.numero_compte') {
934 $sqlwhere[] = $key.' LIKE \''.$this->db->escape($this->db->escapeforlike($value)).'%\'';
935 } elseif ($key == 't.date_creation>=' || $key == 't.date_creation<=') {
936 $sqlwhere[] = $key.'\''.$this->db->idate($value).'\'';
937 } elseif ($key == 't.date_export>=' || $key == 't.date_export<=') {
938 $sqlwhere[] = $key.'\''.$this->db->idate($value).'\'';
939 } elseif ($key == 't.date_validated>=' || $key == 't.date_validated<=') {
940 $sqlwhere[] = $key.'\''.$this->db->idate($value).'\'';
941 } elseif ($key == 't.credit' || $key == 't.debit') {
942 $sqlwhere[] = natural_search($key, $value, 1, 1);
943 } elseif ($key == 't.reconciled_option') {
944 $sqlwhere[] = 't.lettering_code IS NULL';
945 } elseif ($key == 't.code_journal' && !empty($value)) {
946 if (is_array($value)) {
947 $sqlwhere[] = natural_search("t.code_journal", join(',', $value), 3, 1);
948 } else {
949 $sqlwhere[] = natural_search("t.code_journal", $value, 3, 1);
950 }
951 } elseif ($key == 't.search_accounting_code_in' && !empty($value)) {
952 $sqlwhere[] = 't.numero_compte IN ('.$this->db->sanitize($value, 1).')';
953 } else {
954 $sqlwhere[] = natural_search($key, $value, 0, 1);
955 }
956 }
957 }
958 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
959 $sql .= ' WHERE entity = ' . ((int) $conf->entity); // Do not use getEntity for accounting features
960 if (count($sqlwhere) > 0) {
961 $sql .= " AND ".implode(" ".$filtermode." ", $sqlwhere);
962 }
963 // Filter by ledger account or subledger account
964 if (!empty($option)) {
965 $sql .= " AND t.subledger_account IS NOT NULL";
966 $sql .= " AND t.subledger_account <> ''";
967 $sortfield = 't.subledger_account'.($sortfield ? ','.$sortfield : '');
968 $sortorder = 'ASC'.($sortfield ? ','.$sortfield : '');
969 } else {
970 $sortfield = 't.numero_compte'.($sortfield ? ','.$sortfield : '');
971 $sortorder = 'ASC'.($sortorder ? ','.$sortorder : '');
972 }
973
974 if (!$countonly) {
975 $sql .= $this->db->order($sortfield, $sortorder);
976 if (!empty($limit)) {
977 $sql .= $this->db->plimit($limit + 1, $offset);
978 }
979 }
980
981 $resql = $this->db->query($sql);
982 if ($resql) {
983 if ($countonly) {
984 $obj = $this->db->fetch_object($resql);
985 if ($obj) {
986 $num = $obj->nb;
987 }
988 } else {
989 $num = $this->db->num_rows($resql);
990
991 $i = 0;
992 while (($obj = $this->db->fetch_object($resql)) && (empty($limit) || $i < min($limit, $num))) {
993 $line = new BookKeepingLine();
994
995 $line->id = $obj->rowid;
996
997 $line->doc_date = $this->db->jdate($obj->doc_date);
998 $line->doc_type = $obj->doc_type;
999 $line->doc_ref = $obj->doc_ref;
1000 $line->fk_doc = $obj->fk_doc;
1001 $line->fk_docdet = $obj->fk_docdet;
1002 $line->thirdparty_code = $obj->thirdparty_code;
1003 $line->subledger_account = $obj->subledger_account;
1004 $line->subledger_label = $obj->subledger_label;
1005 $line->numero_compte = $obj->numero_compte;
1006 $line->label_compte = $obj->label_compte;
1007 $line->label_operation = $obj->label_operation;
1008 $line->debit = $obj->debit;
1009 $line->credit = $obj->credit;
1010 $line->montant = $obj->amount; // deprecated
1011 $line->amount = $obj->amount;
1012 $line->sens = $obj->sens;
1013 $line->multicurrency_amount = $obj->multicurrency_amount;
1014 $line->multicurrency_code = $obj->multicurrency_code;
1015 $line->lettering_code = $obj->lettering_code;
1016 $line->date_lettering = $obj->date_lettering;
1017 $line->fk_user_author = $obj->fk_user_author;
1018 $line->import_key = $obj->import_key;
1019 $line->code_journal = $obj->code_journal;
1020 $line->journal_label = $obj->journal_label;
1021 $line->piece_num = $obj->piece_num;
1022 $line->date_creation = $this->db->jdate($obj->date_creation);
1023 $line->date_export = $this->db->jdate($obj->date_export);
1024 $line->date_validation = $this->db->jdate($obj->date_validation);
1025 $line->import_key = $obj->import_key;
1026
1027 $this->lines[] = $line;
1028
1029 $i++;
1030 }
1031 }
1032 $this->db->free($resql);
1033
1034 return $num;
1035 } else {
1036 $this->errors[] = 'Error '.$this->db->lasterror();
1037 dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
1038
1039 return -1;
1040 }
1041 }
1042
1055 public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND', $showAlreadyExportMovements = 1)
1056 {
1057 global $conf;
1058
1059 dol_syslog(__METHOD__, LOG_DEBUG);
1060
1061 $sql = 'SELECT';
1062 $sql .= ' t.rowid,';
1063 $sql .= " t.doc_date,";
1064 $sql .= " t.doc_type,";
1065 $sql .= " t.doc_ref,";
1066 $sql .= " t.fk_doc,";
1067 $sql .= " t.fk_docdet,";
1068 $sql .= " t.thirdparty_code,";
1069 $sql .= " t.subledger_account,";
1070 $sql .= " t.subledger_label,";
1071 $sql .= " t.numero_compte,";
1072 $sql .= " t.label_compte,";
1073 $sql .= " t.label_operation,";
1074 $sql .= " t.debit,";
1075 $sql .= " t.credit,";
1076 $sql .= " t.lettering_code,";
1077 $sql .= " t.date_lettering,";
1078 $sql .= " t.montant as amount,";
1079 $sql .= " t.sens,";
1080 $sql .= " t.fk_user_author,";
1081 $sql .= " t.import_key,";
1082 $sql .= " t.code_journal,";
1083 $sql .= " t.journal_label,";
1084 $sql .= " t.piece_num,";
1085 $sql .= " t.date_creation,";
1086 $sql .= " t.date_lim_reglement,";
1087 $sql .= " t.tms as date_modification,";
1088 $sql .= " t.date_export,";
1089 $sql .= " t.date_validated as date_validation";
1090 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
1091 // Manage filter
1092 $sqlwhere = array();
1093 if (count($filter) > 0) {
1094 foreach ($filter as $key => $value) {
1095 if ($key == 't.doc_date') {
1096 $sqlwhere[] = $key.'=\''.$this->db->idate($value).'\'';
1097 } elseif ($key == 't.doc_date>=' || $key == 't.doc_date<=') {
1098 $sqlwhere[] = $key.'\''.$this->db->idate($value).'\'';
1099 } elseif ($key == 't.numero_compte>=' || $key == 't.numero_compte<=' || $key == 't.subledger_account>=' || $key == 't.subledger_account<=') {
1100 $sqlwhere[] = $key.'\''.$this->db->escape($value).'\'';
1101 } elseif ($key == 't.fk_doc' || $key == 't.fk_docdet' || $key == 't.piece_num') {
1102 $sqlwhere[] = $key.'='.((int) $value);
1103 } elseif ($key == 't.subledger_account' || $key == 't.numero_compte') {
1104 $sqlwhere[] = $key.' LIKE \''.$this->db->escape($value).'%\'';
1105 } elseif ($key == 't.date_creation>=' || $key == 't.date_creation<=') {
1106 $sqlwhere[] = $key.'\''.$this->db->idate($value).'\'';
1107 } elseif ($key == 't.tms>=' || $key == 't.tms<=') {
1108 $sqlwhere[] = $key.'\''.$this->db->idate($value).'\'';
1109 } elseif ($key == 't.date_export>=' || $key == 't.date_export<=') {
1110 $sqlwhere[] = $key.'\''.$this->db->idate($value).'\'';
1111 } elseif ($key == 't.date_validated>=' || $key == 't.date_validated<=') {
1112 $sqlwhere[] = $key.'\''.$this->db->idate($value).'\'';
1113 } elseif ($key == 't.credit' || $key == 't.debit') {
1114 $sqlwhere[] = natural_search($key, $value, 1, 1);
1115 } elseif ($key == 't.code_journal' && !empty($value)) {
1116 if (is_array($value)) {
1117 $sqlwhere[] = natural_search("t.code_journal", (string) join(',', $value), 3, 1);
1118 } else {
1119 $sqlwhere[] = natural_search("t.code_journal", $value, 3, 1);
1120 }
1121 } else {
1122 $sqlwhere[] = natural_search($key, $value, 0, 1);
1123 }
1124 }
1125 }
1126 $sql .= ' WHERE t.entity = ' . ((int) $conf->entity); // Do not use getEntity for accounting features
1127 if ($showAlreadyExportMovements == 0) {
1128 $sql .= " AND t.date_export IS NULL";
1129 }
1130 if (count($sqlwhere) > 0) {
1131 $sql .= ' AND '.implode(" ".$filtermode." ", $sqlwhere);
1132 }
1133 if (!empty($sortfield)) {
1134 $sql .= $this->db->order($sortfield, $sortorder);
1135 }
1136 if (!empty($limit)) {
1137 $sql .= $this->db->plimit($limit + 1, $offset);
1138 }
1139 $this->lines = array();
1140
1141 $resql = $this->db->query($sql);
1142 if ($resql) {
1143 $num = $this->db->num_rows($resql);
1144
1145 $i = 0;
1146 while (($obj = $this->db->fetch_object($resql)) && (empty($limit) || $i < min($limit, $num))) {
1147 $line = new BookKeepingLine();
1148
1149 $line->id = $obj->rowid;
1150
1151 $line->doc_date = $this->db->jdate($obj->doc_date);
1152 $line->doc_type = $obj->doc_type;
1153 $line->doc_ref = $obj->doc_ref;
1154 $line->fk_doc = $obj->fk_doc;
1155 $line->fk_docdet = $obj->fk_docdet;
1156 $line->thirdparty_code = $obj->thirdparty_code;
1157 $line->subledger_account = $obj->subledger_account;
1158 $line->subledger_label = $obj->subledger_label;
1159 $line->numero_compte = $obj->numero_compte;
1160 $line->label_compte = $obj->label_compte;
1161 $line->label_operation = $obj->label_operation;
1162 $line->debit = $obj->debit;
1163 $line->credit = $obj->credit;
1164 $line->montant = $obj->amount; // deprecated
1165 $line->amount = $obj->amount;
1166 $line->sens = $obj->sens;
1167 $line->lettering_code = $obj->lettering_code;
1168 $line->date_lettering = $obj->date_lettering;
1169 $line->fk_user_author = $obj->fk_user_author;
1170 $line->import_key = $obj->import_key;
1171 $line->code_journal = $obj->code_journal;
1172 $line->journal_label = $obj->journal_label;
1173 $line->piece_num = $obj->piece_num;
1174 $line->date_creation = $this->db->jdate($obj->date_creation);
1175 $line->date_lim_reglement = $this->db->jdate($obj->date_lim_reglement);
1176 $line->date_modification = $this->db->jdate($obj->date_modification);
1177 $line->date_export = $this->db->jdate($obj->date_export);
1178 $line->date_validation = $this->db->jdate($obj->date_validation);
1179
1180 $this->lines[] = $line;
1181
1182 $i++;
1183 }
1184 $this->db->free($resql);
1185
1186 return $num;
1187 } else {
1188 $this->errors[] = 'Error '.$this->db->lasterror();
1189 dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
1190 return -1;
1191 }
1192 }
1193
1206 public function fetchAllBalance($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND', $option = 0)
1207 {
1208 global $conf;
1209
1210 $this->lines = array();
1211
1212 dol_syslog(__METHOD__, LOG_DEBUG);
1213
1214 $sql = 'SELECT';
1215 $sql .= " t.numero_compte,";
1216 if (!empty($option)) {
1217 $sql .= " t.subledger_account,";
1218 $sql .= " t.subledger_label,";
1219 }
1220 $sql .= " SUM(t.debit) as debit,";
1221 $sql .= " SUM(t.credit) as credit";
1222 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
1223 // Manage filter
1224 $sqlwhere = array();
1225 if (count($filter) > 0) {
1226 foreach ($filter as $key => $value) {
1227 if ($key == 't.doc_date') {
1228 $sqlwhere[] = $key." = '".$this->db->idate($value)."'";
1229 } elseif ($key == 't.doc_date>=' || $key == 't.doc_date<=' || $key == 't.doc_date>' || $key == 't.doc_date<') {
1230 $sqlwhere[] = $key."'".$this->db->idate($value)."'";
1231 } elseif ($key == 't.numero_compte>=' || $key == 't.numero_compte<=' || $key == 't.subledger_account>=' || $key == 't.subledger_account<=') {
1232 $sqlwhere[] = $key."'".$this->db->escape($value)."'";
1233 } elseif ($key == 't.fk_doc' || $key == 't.fk_docdet' || $key == 't.piece_num') {
1234 $sqlwhere[] = $key." = ".((int) $value);
1235 } elseif ($key == 't.subledger_account' || $key == 't.numero_compte') {
1236 $sqlwhere[] = $key." LIKE '".$this->db->escape($value)."%'";
1237 } elseif ($key == 't.subledger_label') {
1238 $sqlwhere[] = $key." LIKE '".$this->db->escape($value)."%'";
1239 } elseif ($key == 't.code_journal' && !empty($value)) {
1240 if (is_array($value)) {
1241 $sqlwhere[] = natural_search("t.code_journal", join(',', $value), 3, 1);
1242 } else {
1243 $sqlwhere[] = natural_search("t.code_journal", $value, 3, 1);
1244 }
1245 } elseif ($key == 't.reconciled_option') {
1246 $sqlwhere[] = 't.lettering_code IS NULL';
1247 } else {
1248 $sqlwhere[] = $key." LIKE '%".$this->db->escape($value)."%'";
1249 }
1250 }
1251 }
1252 $sql .= ' WHERE entity = ' . ((int) $conf->entity); // Do not use getEntity for accounting features
1253 if (count($sqlwhere) > 0) {
1254 $sql .= " AND ".implode(" ".$filtermode." ", $sqlwhere);
1255 }
1256
1257 if (!empty($option)) {
1258 $sql .= " AND t.subledger_account IS NOT NULL";
1259 $sql .= " AND t.subledger_account <> ''";
1260 $sql .= " GROUP BY t.numero_compte, t.subledger_account, t.subledger_label";
1261 $sortfield = 't.subledger_account'.($sortfield ? ','.$sortfield : '');
1262 $sortorder = 'ASC'.($sortfield ? ','.$sortfield : '');
1263 } else {
1264 $sql .= ' GROUP BY t.numero_compte';
1265 $sortfield = 't.numero_compte'.($sortfield ? ','.$sortfield : '');
1266 $sortorder = 'ASC'.($sortorder ? ','.$sortorder : '');
1267 }
1268
1269 if (!empty($sortfield)) {
1270 $sql .= $this->db->order($sortfield, $sortorder);
1271 }
1272 if (!empty($limit)) {
1273 $sql .= $this->db->plimit($limit + 1, $offset);
1274 }
1275
1276 $resql = $this->db->query($sql);
1277 if ($resql) {
1278 $num = $this->db->num_rows($resql);
1279
1280 $i = 0;
1281 while (($obj = $this->db->fetch_object($resql)) && (empty($limit) || $i < min($limit, $num))) {
1282 $line = new BookKeepingLine();
1283
1284 $line->numero_compte = $obj->numero_compte;
1285 //$line->label_compte = $obj->label_compte;
1286 if (!empty($option)) {
1287 $line->subledger_account = $obj->subledger_account;
1288 $line->subledger_label = $obj->subledger_label;
1289 }
1290 $line->debit = $obj->debit;
1291 $line->credit = $obj->credit;
1292
1293 $this->lines[] = $line;
1294
1295 $i++;
1296 }
1297 $this->db->free($resql);
1298
1299 return $num;
1300 } else {
1301 $this->errors[] = 'Error '.$this->db->lasterror();
1302 dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
1303
1304 return -1;
1305 }
1306 }
1307
1316 public function update(User $user, $notrigger = false, $mode = '')
1317 {
1318 global $langs;
1319 $error = 0;
1320
1321 dol_syslog(__METHOD__, LOG_DEBUG);
1322
1323 // Clean parameters
1324 if (isset($this->doc_type)) {
1325 $this->doc_type = trim($this->doc_type);
1326 }
1327 if (isset($this->doc_ref)) {
1328 $this->doc_ref = trim($this->doc_ref);
1329 }
1330 if (isset($this->fk_doc)) {
1331 $this->fk_doc = (int) $this->fk_doc;
1332 }
1333 if (isset($this->fk_docdet)) {
1334 $this->fk_docdet = (int) $this->fk_docdet;
1335 }
1336 if (isset($this->thirdparty_code)) {
1337 $this->thirdparty_code = trim($this->thirdparty_code);
1338 }
1339 if (isset($this->subledger_account)) {
1340 $this->subledger_account = trim($this->subledger_account);
1341 }
1342 if (isset($this->subledger_label)) {
1343 $this->subledger_label = trim($this->subledger_label);
1344 }
1345 if (isset($this->numero_compte)) {
1346 $this->numero_compte = trim($this->numero_compte);
1347 }
1348 if (isset($this->label_compte)) {
1349 $this->label_compte = trim($this->label_compte);
1350 }
1351 if (isset($this->label_operation)) {
1352 $this->label_operation = trim($this->label_operation);
1353 }
1354 if (isset($this->debit)) {
1355 $this->debit = trim($this->debit);
1356 }
1357 if (isset($this->credit)) {
1358 $this->credit = trim($this->credit);
1359 }
1360 if (isset($this->amount)) {
1361 $this->amount = trim($this->amount);
1362 }
1363 if (isset($this->sens)) {
1364 $this->sens = trim($this->sens);
1365 }
1366 if (isset($this->import_key)) {
1367 $this->import_key = trim($this->import_key);
1368 }
1369 if (isset($this->code_journal)) {
1370 $this->code_journal = trim($this->code_journal);
1371 }
1372 if (isset($this->journal_label)) {
1373 $this->journal_label = trim($this->journal_label);
1374 }
1375 if (isset($this->piece_num)) {
1376 $this->piece_num = trim($this->piece_num);
1377 }
1378
1379 $result = $this->canModifyBookkeeping($this->id);
1380 if ($result < 0) {
1381 return -1;
1382 } elseif ($result == 0) {
1383 if (getDolGlobalString('ACCOUNTANCY_FISCAL_PERIOD_MODE') == 'blockedonclosed') {
1384 $this->errors[] = $langs->trans('ErrorBookkeepingDocDateIsOnAClosedFiscalPeriod');
1385 } else {
1386 $this->errors[] = $langs->trans('ErrorBookkeepingDocDateNotOnActiveFiscalPeriod');
1387 }
1388 return -1;
1389 }
1390
1391 $this->debit = price2num($this->debit, 'MT');
1392 $this->credit = price2num($this->credit, 'MT');
1393
1394 // Check parameters
1395 // Put here code to add a control on parameters values
1396
1397 // Update request
1398 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element.$mode.' SET';
1399 $sql .= ' doc_date = '.(!isset($this->doc_date) || dol_strlen($this->doc_date) != 0 ? "'".$this->db->idate($this->doc_date)."'" : 'null').',';
1400 $sql .= ' doc_type = '.(isset($this->doc_type) ? "'".$this->db->escape($this->doc_type)."'" : "null").',';
1401 $sql .= ' doc_ref = '.(isset($this->doc_ref) ? "'".$this->db->escape($this->doc_ref)."'" : "null").',';
1402 $sql .= ' fk_doc = '.(isset($this->fk_doc) ? $this->fk_doc : "null").',';
1403 $sql .= ' fk_docdet = '.(isset($this->fk_docdet) ? $this->fk_docdet : "null").',';
1404 $sql .= ' thirdparty_code = '.(isset($this->thirdparty_code) ? "'".$this->db->escape($this->thirdparty_code)."'" : "null").',';
1405 $sql .= ' subledger_account = '.(isset($this->subledger_account) ? "'".$this->db->escape($this->subledger_account)."'" : "null").',';
1406 $sql .= ' subledger_label = '.(isset($this->subledger_label) ? "'".$this->db->escape($this->subledger_label)."'" : "null").',';
1407 $sql .= ' numero_compte = '.(isset($this->numero_compte) ? "'".$this->db->escape($this->numero_compte)."'" : "null").',';
1408 $sql .= ' label_compte = '.(isset($this->label_compte) ? "'".$this->db->escape($this->label_compte)."'" : "null").',';
1409 $sql .= ' label_operation = '.(isset($this->label_operation) ? "'".$this->db->escape($this->label_operation)."'" : "null").',';
1410 $sql .= ' debit = '.(isset($this->debit) ? $this->debit : "null").',';
1411 $sql .= ' credit = '.(isset($this->credit) ? $this->credit : "null").',';
1412 $sql .= ' montant = '.(isset($this->montant) ? $this->montant : "null").',';
1413 $sql .= ' sens = '.(isset($this->sens) ? "'".$this->db->escape($this->sens)."'" : "null").',';
1414 $sql .= ' fk_user_author = '.(isset($this->fk_user_author) ? $this->fk_user_author : "null").',';
1415 $sql .= ' import_key = '.(isset($this->import_key) ? "'".$this->db->escape($this->import_key)."'" : "null").',';
1416 $sql .= ' code_journal = '.(isset($this->code_journal) ? "'".$this->db->escape($this->code_journal)."'" : "null").',';
1417 $sql .= ' journal_label = '.(isset($this->journal_label) ? "'".$this->db->escape($this->journal_label)."'" : "null").',';
1418 $sql .= ' piece_num = '.(isset($this->piece_num) ? $this->piece_num : "null");
1419 $sql .= ' WHERE rowid='.((int) $this->id);
1420
1421 $this->db->begin();
1422
1423 $resql = $this->db->query($sql);
1424 if (!$resql) {
1425 $error++;
1426 $this->errors[] = 'Error '.$this->db->lasterror();
1427 dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
1428 }
1429
1430 // Uncomment this and change MYOBJECT to your own tag if you
1431 // want this action calls a trigger.
1432 //if (! $error && ! $notrigger) {
1433
1434 // // Call triggers
1435 // $result=$this->call_trigger('MYOBJECT_MODIFY',$user);
1436 // if ($result < 0) { $error++; //Do also what you must do to rollback action if trigger fail}
1437 // // End call triggers
1438 //}
1439
1440 // Commit or rollback
1441 if ($error) {
1442 $this->db->rollback();
1443
1444 return -1 * $error;
1445 } else {
1446 $this->db->commit();
1447
1448 return 1;
1449 }
1450 }
1451
1461 public function updateByMvt($piece_num = '', $field = '', $value = '', $mode = '')
1462 {
1463 global $conf;
1464 $error = 0;
1465
1466 $sql_filter = $this->getCanModifyBookkeepingSQL();
1467 if (!isset($sql_filter)) {
1468 return -1;
1469 }
1470
1471 $this->db->begin();
1472
1473 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element.$mode;
1474 $sql .= " SET ".$field." = ".(is_numeric($value) ? ((float) $value) : "'".$this->db->escape($value)."'");
1475 $sql .= " WHERE piece_num = ".((int) $piece_num);
1476 $sql .= " AND entity = " . ((int) $conf->entity);
1477 $sql .= $sql_filter;
1478
1479 $resql = $this->db->query($sql);
1480
1481 if (!$resql) {
1482 $error++;
1483 $this->errors[] = 'Error '.$this->db->lasterror();
1484 dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
1485 }
1486 if ($error) {
1487 $this->db->rollback();
1488
1489 return -1 * $error;
1490 } else {
1491 $this->db->commit();
1492
1493 return 1;
1494 }
1495 }
1496
1505 public function delete(User $user, $notrigger = 0, $mode = '')
1506 {
1507 global $langs;
1508
1509 dol_syslog(__METHOD__, LOG_DEBUG);
1510
1511 $result = $this->canModifyBookkeeping($this->id, $mode);
1512 if ($result < 0) {
1513 return -1;
1514 } elseif ($result == 0) {
1515 if (getDolGlobalString('ACCOUNTANCY_FISCAL_PERIOD_MODE') == 'blockedonclosed') {
1516 $this->errors[] = $langs->trans('ErrorBookkeepingDocDateIsOnAClosedFiscalPeriod');
1517 } else {
1518 $this->errors[] = $langs->trans('ErrorBookkeepingDocDateNotOnActiveFiscalPeriod');
1519 }
1520 return -1;
1521 }
1522
1523 $error = 0;
1524
1525 $this->db->begin();
1526
1527 // Uncomment this and change MYOBJECT to your own tag if you
1528 // want this action calls a trigger.
1529 //if (! $error && ! $notrigger) {
1530
1531 // // Call triggers
1532 // $result=$this->call_trigger('MYOBJECT_DELETE',$user);
1533 // if ($result < 0) { $error++; //Do also what you must do to rollback action if trigger fail}
1534 // // End call triggers
1535 //}
1536
1537 if (!$error) {
1538 $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.$mode;
1539 $sql .= ' WHERE rowid='.((int) $this->id);
1540
1541 $resql = $this->db->query($sql);
1542 if (!$resql) {
1543 $error++;
1544 $this->errors[] = 'Error '.$this->db->lasterror();
1545 dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
1546 }
1547 }
1548
1549 // Commit or rollback
1550 if ($error) {
1551 $this->db->rollback();
1552
1553 return -1 * $error;
1554 } else {
1555 $this->db->commit();
1556
1557 return 1;
1558 }
1559 }
1560
1568 public function deleteByImportkey($importkey, $mode = '')
1569 {
1570 $this->db->begin();
1571
1572 $sql_filter = $this->getCanModifyBookkeepingSQL();
1573 if (!isset($sql_filter)) {
1574 return -1;
1575 }
1576
1577 // first check if line not yet in bookkeeping
1578 $sql = "DELETE";
1579 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element.$mode;
1580 $sql .= " WHERE import_key = '".$this->db->escape($importkey)."'";
1581 $sql .= $sql_filter;
1582
1583 $resql = $this->db->query($sql);
1584
1585 if (!$resql) {
1586 $this->errors[] = "Error ".$this->db->lasterror();
1587 dol_syslog(get_class($this)."::delete Error ".$this->db->lasterror(), LOG_ERR);
1588 $this->db->rollback();
1589 return -1;
1590 }
1591
1592 $this->db->commit();
1593 return 1;
1594 }
1595
1605 public function deleteByYearAndJournal($delyear = 0, $journal = '', $mode = '', $delmonth = 0)
1606 {
1607 global $conf, $langs;
1608
1609 if (empty($delyear) && empty($journal)) {
1610 $this->error = 'ErrorOneFieldRequired';
1611 return -1;
1612 }
1613 if (!empty($delmonth) && empty($delyear)) {
1614 $this->error = 'YearRequiredIfMonthDefined';
1615 return -2;
1616 }
1617
1618 $sql_filter = $this->getCanModifyBookkeepingSQL();
1619 if (!isset($sql_filter)) {
1620 return -1;
1621 }
1622
1623 $this->db->begin();
1624
1625 // Delete record in bookkeeping
1626 $sql = "DELETE";
1627 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element.$mode;
1628 $sql .= " WHERE 1 = 1";
1629 $sql .= dolSqlDateFilter('doc_date', 0, $delmonth, $delyear);
1630 if (!empty($journal)) {
1631 $sql .= " AND code_journal = '".$this->db->escape($journal)."'";
1632 }
1633 $sql .= " AND entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
1634 // Exclusion of validated entries at the time of deletion
1635 $sql .= " AND date_validated IS NULL";
1636 $sql .= $sql_filter;
1637
1638 // TODO: In a future we must forbid deletion if record is inside a closed fiscal period.
1639
1640 $resql = $this->db->query($sql);
1641
1642 if (!$resql) {
1643 $this->errors[] = "Error ".$this->db->lasterror();
1644 foreach ($this->errors as $errmsg) {
1645 dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR);
1646 $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
1647 }
1648 $this->db->rollback();
1649 return -1;
1650 }
1651
1652 $this->db->commit();
1653 return 1;
1654 }
1655
1663 public function deleteMvtNum($piecenum, $mode = '')
1664 {
1665 global $conf;
1666
1667 $sql_filter = $this->getCanModifyBookkeepingSQL();
1668 if (!isset($sql_filter)) {
1669 return -1;
1670 }
1671
1672 $this->db->begin();
1673
1674 // first check if line not yet in bookkeeping
1675 $sql = "DELETE";
1676 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element.$mode;
1677 $sql .= " WHERE piece_num = ".(int) $piecenum;
1678 $sql .= " AND date_validated IS NULL"; // For security, exclusion of validated entries at the time of deletion
1679 $sql .= " AND entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
1680 $sql .= $sql_filter;
1681
1682 $resql = $this->db->query($sql);
1683
1684 if (!$resql) {
1685 $this->errors[] = "Error ".$this->db->lasterror();
1686 foreach ($this->errors as $errmsg) {
1687 dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR);
1688 $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
1689 }
1690 $this->db->rollback();
1691 return -1;
1692 }
1693
1694 $this->db->commit();
1695 return 1;
1696 }
1697
1705 public function createFromClone(User $user, $fromid)
1706 {
1707 dol_syslog(__METHOD__, LOG_DEBUG);
1708
1709 $error = 0;
1710 $object = new BookKeeping($this->db);
1711
1712 $this->db->begin();
1713
1714 // Load source object
1715 $object->fetch($fromid);
1716 // Reset object
1717 $object->id = 0;
1718
1719 // Clear fields
1720 // ...
1721
1722 // Create clone
1723 $object->context['createfromclone'] = 'createfromclone';
1724 $result = $object->create($user);
1725
1726 // Other options
1727 if ($result < 0) {
1728 $error++;
1729 $this->errors = $object->errors;
1730 dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
1731 }
1732
1733 unset($object->context['createfromclone']);
1734
1735 // End
1736 if (!$error) {
1737 $this->db->commit();
1738
1739 return $object->id;
1740 } else {
1741 $this->db->rollback();
1742
1743 return -1;
1744 }
1745 }
1746
1753 public function initAsSpecimen()
1754 {
1755 global $user;
1756
1757 $now = dol_now();
1758
1759 $this->id = 0;
1760 $this->doc_date = $now;
1761 $this->doc_type = '';
1762 $this->doc_ref = '';
1763 $this->fk_doc = 0;
1764 $this->fk_docdet = 0;
1765 $this->thirdparty_code = 'CU001';
1766 $this->subledger_account = '41100001';
1767 $this->subledger_label = 'My customer company';
1768 $this->numero_compte = '411';
1769 $this->label_compte = 'Customer';
1770 $this->label_operation = 'Sales of pea';
1771 $this->debit = 99.9;
1772 $this->credit = 0.0;
1773 $this->amount = 0.0;
1774 $this->sens = 'D';
1775 $this->fk_user_author = $user->id;
1776 $this->import_key = '20201027';
1777 $this->code_journal = 'VT';
1778 $this->journal_label = 'Journal de vente';
1779 $this->piece_num = 1234;
1780 $this->date_creation = $now;
1781 }
1782
1790 public function fetchPerMvt($piecenum, $mode = '')
1791 {
1792 global $conf;
1793
1794 $sql = "SELECT piece_num, doc_date,code_journal, journal_label, doc_ref, doc_type,";
1795 $sql .= " date_creation, tms as date_modification, date_validated as date_validation";
1796 // In llx_accounting_bookkeeping_tmp, field date_export doesn't exist
1797 if ($mode != "_tmp") {
1798 $sql .= ", date_export";
1799 }
1800 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element.$mode;
1801 $sql .= " WHERE piece_num = ".((int) $piecenum);
1802 $sql .= " AND entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
1803
1804 dol_syslog(__METHOD__, LOG_DEBUG);
1805 $result = $this->db->query($sql);
1806 if ($result) {
1807 $obj = $this->db->fetch_object($result);
1808
1809 $this->piece_num = $obj->piece_num;
1810 $this->code_journal = $obj->code_journal;
1811 $this->journal_label = $obj->journal_label;
1812 $this->doc_date = $this->db->jdate($obj->doc_date);
1813 $this->doc_ref = $obj->doc_ref;
1814 $this->doc_type = $obj->doc_type;
1815 $this->date_creation = $this->db->jdate($obj->date_creation);
1816 $this->date_modification = $this->db->jdate($obj->date_modification);
1817 if ($mode != "_tmp") {
1818 $this->date_export = $this->db->jdate($obj->date_export);
1819 }
1820 $this->date_validation = $this->db->jdate($obj->date_validation);
1821 } else {
1822 $this->error = "Error ".$this->db->lasterror();
1823 dol_syslog(__METHOD__.$this->error, LOG_ERR);
1824 return -1;
1825 }
1826
1827 return 1;
1828 }
1829
1836 public function getNextNumMvt($mode = '')
1837 {
1838 global $conf;
1839
1840 $sql = "SELECT MAX(piece_num)+1 as max FROM ".MAIN_DB_PREFIX.$this->table_element.$mode;
1841 $sql .= " WHERE entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
1842
1843 dol_syslog(get_class($this)."::getNextNumMvt", LOG_DEBUG);
1844
1845 $result = $this->db->query($sql);
1846
1847 if ($result) {
1848 $obj = $this->db->fetch_object($result);
1849 if ($obj) {
1850 $result = $obj->max;
1851 }
1852 if (empty($result)) {
1853 $result = 1;
1854 }
1855 return $result;
1856 } else {
1857 $this->error = "Error ".$this->db->lasterror();
1858 dol_syslog(get_class($this)."::getNextNumMvt ".$this->error, LOG_ERR);
1859 return -1;
1860 }
1861 }
1862
1870 public function fetchAllPerMvt($piecenum, $mode = '')
1871 {
1872 global $conf;
1873
1874 $sql = "SELECT rowid, doc_date, doc_type,";
1875 $sql .= " doc_ref, fk_doc, fk_docdet, thirdparty_code, subledger_account, subledger_label,";
1876 $sql .= " numero_compte, label_compte, label_operation, debit, credit,";
1877 $sql .= " montant as amount, sens, fk_user_author, import_key, code_journal, journal_label, piece_num,";
1878 $sql .= " date_creation, tms as date_modification, date_validated as date_validation";
1879 // In llx_accounting_bookkeeping_tmp, field date_export doesn't exist
1880 if ($mode != "_tmp") {
1881 $sql .= ", date_export";
1882 }
1883 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element.$mode;
1884 $sql .= " WHERE piece_num = ".((int) $piecenum);
1885 $sql .= " AND entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
1886
1887 dol_syslog(__METHOD__, LOG_DEBUG);
1888 $result = $this->db->query($sql);
1889 if ($result) {
1890 while ($obj = $this->db->fetch_object($result)) {
1891 $line = new BookKeepingLine();
1892
1893 $line->id = $obj->rowid;
1894
1895 $line->doc_date = $this->db->jdate($obj->doc_date);
1896 $line->doc_type = $obj->doc_type;
1897 $line->doc_ref = $obj->doc_ref;
1898 $line->fk_doc = $obj->fk_doc;
1899 $line->fk_docdet = $obj->fk_docdet;
1900 $line->thirdparty_code = $obj->thirdparty_code;
1901 $line->subledger_account = $obj->subledger_account;
1902 $line->subledger_label = $obj->subledger_label;
1903 $line->numero_compte = $obj->numero_compte;
1904 $line->label_compte = $obj->label_compte;
1905 $line->label_operation = $obj->label_operation;
1906 $line->debit = $obj->debit;
1907 $line->credit = $obj->credit;
1908 $line->montant = $obj->amount;
1909 $line->amount = $obj->amount;
1910 $line->sens = $obj->sens;
1911 $line->code_journal = $obj->code_journal;
1912 $line->journal_label = $obj->journal_label;
1913 $line->piece_num = $obj->piece_num;
1914 $line->date_creation = $obj->date_creation;
1915 $line->date_modification = $obj->date_modification;
1916 if ($mode != "_tmp") {
1917 $line->date_export = $obj->date_export;
1918 }
1919 $line->date_validation = $obj->date_validation;
1920
1921 $this->linesmvt[] = $line;
1922 }
1923 } else {
1924 $this->error = "Error ".$this->db->lasterror();
1925 dol_syslog(__METHOD__.$this->error, LOG_ERR);
1926 return -1;
1927 }
1928
1929 return 1;
1930 }
1931
1932 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1939 public function export_bookkeeping($model = 'ebp')
1940 {
1941 // phpcs:enable
1942 global $conf;
1943
1944 $sql = "SELECT rowid, doc_date, doc_type,";
1945 $sql .= " doc_ref, fk_doc, fk_docdet, thirdparty_code, subledger_account, subledger_label,";
1946 $sql .= " numero_compte, label_compte, label_operation, debit, credit,";
1947 $sql .= " montant as amount, sens, fk_user_author, import_key, code_journal, piece_num,";
1948 $sql .= " date_validated as date_validation";
1949 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element;
1950 $sql .= " WHERE entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
1951
1952 dol_syslog(get_class($this)."::export_bookkeeping", LOG_DEBUG);
1953
1954 $resql = $this->db->query($sql);
1955
1956 if ($resql) {
1957 $this->linesexport = array();
1958
1959 $num = $this->db->num_rows($resql);
1960 while ($obj = $this->db->fetch_object($resql)) {
1961 $line = new BookKeepingLine();
1962
1963 $line->id = $obj->rowid;
1964
1965 $line->doc_date = $this->db->jdate($obj->doc_date);
1966 $line->doc_type = $obj->doc_type;
1967 $line->doc_ref = $obj->doc_ref;
1968 $line->fk_doc = $obj->fk_doc;
1969 $line->fk_docdet = $obj->fk_docdet;
1970 $line->thirdparty_code = $obj->thirdparty_code;
1971 $line->subledger_account = $obj->subledger_account;
1972 $line->subledger_label = $obj->subledger_label;
1973 $line->numero_compte = $obj->numero_compte;
1974 $line->label_compte = $obj->label_compte;
1975 $line->label_operation = $obj->label_operation;
1976 $line->debit = $obj->debit;
1977 $line->credit = $obj->credit;
1978 $line->montant = $obj->amount;
1979 $line->amount = $obj->amount;
1980 $line->sens = $obj->sens;
1981 $line->code_journal = $obj->code_journal;
1982 $line->piece_num = $obj->piece_num;
1983 $line->date_validation = $obj->date_validation;
1984
1985 $this->linesexport[] = $line;
1986 }
1987 $this->db->free($resql);
1988
1989 return $num;
1990 } else {
1991 $this->error = "Error ".$this->db->lasterror();
1992 dol_syslog(get_class($this)."::export_bookkeeping ".$this->error, LOG_ERR);
1993 return -1;
1994 }
1995 }
1996
2004 public function transformTransaction($direction = 0, $piece_num = '')
2005 {
2006 global $conf;
2007
2008 $error = 0;
2009
2010 $sql_filter = $this->getCanModifyBookkeepingSQL();
2011 if (!isset($sql_filter)) {
2012 return -1;
2013 }
2014
2015 $this->db->begin();
2016
2017 if ($direction == 0) {
2018 $next_piecenum = $this->getNextNumMvt();
2019 $now = dol_now();
2020
2021 if ($next_piecenum < 0) {
2022 $error++;
2023 }
2024
2025 if (!$error) {
2026 // Delete if there is an empty line
2027 $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.'_tmp WHERE piece_num = '.((int) $piece_num).' AND entity = ' .((int) $conf->entity)." AND numero_compte IS NULL AND debit = 0 AND credit = 0";
2028 $resql = $this->db->query($sql);
2029 if (!$resql) {
2030 $error++;
2031 $this->errors[] = 'Error '.$this->db->lasterror();
2032 dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
2033 }
2034 }
2035
2036 if (!$error) {
2037 $sql = 'INSERT INTO '.MAIN_DB_PREFIX.$this->table_element.' (doc_date, doc_type,';
2038 $sql .= ' doc_ref, fk_doc, fk_docdet, entity, thirdparty_code, subledger_account, subledger_label,';
2039 $sql .= ' numero_compte, label_compte, label_operation, debit, credit,';
2040 $sql .= ' montant, sens, fk_user_author, import_key, code_journal, journal_label, piece_num, date_creation)';
2041 $sql .= ' SELECT doc_date, doc_type,';
2042 $sql .= ' doc_ref, fk_doc, fk_docdet, entity, thirdparty_code, subledger_account, subledger_label,';
2043 $sql .= ' numero_compte, label_compte, label_operation, debit, credit,';
2044 $sql .= ' montant, sens, fk_user_author, import_key, code_journal, journal_label, '.((int) $next_piecenum).", '".$this->db->idate($now)."'";
2045 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.'_tmp WHERE piece_num = '.((int) $piece_num).' AND numero_compte IS NOT NULL AND entity = ' .((int) $conf->entity);
2046 $sql .= $sql_filter;
2047 $resql = $this->db->query($sql);
2048 if (!$resql) {
2049 $error++;
2050 $this->errors[] = 'Error '.$this->db->lasterror();
2051 dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
2052 }
2053 }
2054
2055 if (!$error) {
2056 $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.'_tmp WHERE piece_num = '.((int) $piece_num).' AND entity = ' .((int) $conf->entity);
2057 $resql = $this->db->query($sql);
2058 if (!$resql) {
2059 $error++;
2060 $this->errors[] = 'Error '.$this->db->lasterror();
2061 dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
2062 }
2063 }
2064 } elseif ($direction == 1) {
2065 if (!$error) {
2066 $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.'_tmp WHERE piece_num = '.((int) $piece_num).' AND entity = ' .((int) $conf->entity);
2067 $resql = $this->db->query($sql);
2068 if (!$resql) {
2069 $error++;
2070 $this->errors[] = 'Error '.$this->db->lasterror();
2071 dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
2072 }
2073 }
2074
2075 if (!$error) {
2076 $sql = 'INSERT INTO '.MAIN_DB_PREFIX.$this->table_element.'_tmp (doc_date, doc_type,';
2077 $sql .= ' doc_ref, fk_doc, fk_docdet, thirdparty_code, subledger_account, subledger_label,';
2078 $sql .= ' numero_compte, label_compte, label_operation, debit, credit,';
2079 $sql .= ' montant, sens, fk_user_author, import_key, code_journal, journal_label, piece_num)';
2080 $sql .= ' SELECT doc_date, doc_type,';
2081 $sql .= ' doc_ref, fk_doc, fk_docdet, thirdparty_code, subledger_account, subledger_label,';
2082 $sql .= ' numero_compte, label_compte, label_operation, debit, credit,';
2083 $sql .= ' montant, sens, fk_user_author, import_key, code_journal, journal_label, piece_num';
2084 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' WHERE piece_num = '.((int) $piece_num).' AND entity = ' .((int) $conf->entity);
2085 $sql .= $sql_filter;
2086 $resql = $this->db->query($sql);
2087 if (!$resql) {
2088 $error++;
2089 $this->errors[] = 'Error '.$this->db->lasterror();
2090 dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
2091 }
2092 }
2093
2094 if (!$error) {
2095 $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.'_tmp WHERE piece_num = '.((int) $piece_num).' AND entity = ' .((int) $conf->entity);
2096 $sql .= $sql_filter;
2097 $resql = $this->db->query($sql);
2098 if (!$resql) {
2099 $error++;
2100 $this->errors[] = 'Error '.$this->db->lasterror();
2101 dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
2102 }
2103 }
2104 }
2105 if (!$error) {
2106 $this->db->commit();
2107 return 1;
2108 } else {
2109 $this->db->rollback();
2110 return -1;
2111 }
2112 /*
2113 $sql = "DELETE FROM ";
2114 $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping as ab";
2115 $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "accounting_account as aa ON aa.account_number = ab.numero_compte";
2116 $sql .= " AND aa.active = 1";
2117 $sql .= " INNER JOIN " . MAIN_DB_PREFIX . "accounting_system as asy ON aa.fk_pcg_version = asy.pcg_version";
2118 $sql .= " AND asy.rowid = " . ((int) $pcgver);
2119 $sql .= " AND ab.entity IN (" . getEntity('accountancy') . ")";
2120 $sql .= " ORDER BY account_number ASC";
2121 */
2122 }
2123
2124 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2137 public function select_account($selectid, $htmlname = 'account', $showempty = 0, $event = array(), $select_in = 0, $select_out = 0, $aabase = '')
2138 {
2139 // phpcs:enable
2140 global $conf;
2141
2142 require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php';
2143
2144 $pcgver = getDolGlobalInt('CHARTOFACCOUNTS');
2145
2146 $sql = "SELECT DISTINCT ab.numero_compte as account_number, aa.label as label, aa.rowid as rowid, aa.fk_pcg_version";
2147 $sql .= " FROM ".MAIN_DB_PREFIX."accounting_bookkeeping as ab";
2148 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."accounting_account as aa ON aa.account_number = ab.numero_compte";
2149 $sql .= " AND aa.active = 1";
2150 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."accounting_system as asy ON aa.fk_pcg_version = asy.pcg_version";
2151 $sql .= " AND asy.rowid = ".((int) $pcgver);
2152 $sql .= " AND ab.entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
2153 $sql .= " ORDER BY account_number ASC";
2154
2155 dol_syslog(get_class($this)."::select_account", LOG_DEBUG);
2156 $resql = $this->db->query($sql);
2157
2158 if (!$resql) {
2159 $this->error = "Error ".$this->db->lasterror();
2160 dol_syslog(get_class($this)."::select_account ".$this->error, LOG_ERR);
2161 return -1;
2162 }
2163
2164 $out = ajax_combobox($htmlname, $event);
2165
2166 $options = array();
2167 $selected = null;
2168
2169 while ($obj = $this->db->fetch_object($resql)) {
2170 $label = length_accountg($obj->account_number).' - '.$obj->label;
2171
2172 $select_value_in = $obj->rowid;
2173 $select_value_out = $obj->rowid;
2174
2175 if ($select_in == 1) {
2176 $select_value_in = $obj->account_number;
2177 }
2178 if ($select_out == 1) {
2179 $select_value_out = $obj->account_number;
2180 }
2181
2182 // Remember guy's we store in database llx_facturedet the rowid of accounting_account and not the account_number
2183 // Because same account_number can be share between different accounting_system and do have the same meaning
2184 if (($selectid != '') && $selectid == $select_value_in) {
2185 $selected = $select_value_out;
2186 }
2187
2188 $options[$select_value_out] = $label;
2189 }
2190
2191 $out .= Form::selectarray($htmlname, $options, $selected, $showempty, 0, 0, '', 0, 0, 0, '', 'maxwidth300');
2192 $this->db->free($resql);
2193 return $out;
2194 }
2195
2203 public function getRootAccount($account = null)
2204 {
2205 global $conf;
2206 $pcgver = getDolGlobalInt('CHARTOFACCOUNTS');
2207
2208 $sql = "SELECT root.rowid, root.account_number, root.label as label,";
2209 $sql .= " parent.rowid as parent_rowid, parent.account_number as parent_account_number, parent.label as parent_label";
2210 $sql .= " FROM ".MAIN_DB_PREFIX."accounting_account as aa";
2211 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."accounting_system as asy ON aa.fk_pcg_version = asy.pcg_version";
2212 $sql .= " AND asy.rowid = ".((int) $pcgver);
2213 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."accounting_account as parent ON aa.account_parent = parent.rowid AND parent.active = 1";
2214 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."accounting_account as root ON parent.account_parent = root.rowid AND root.active = 1";
2215 $sql .= " WHERE aa.account_number = '".$this->db->escape($account)."'";
2216 $sql .= " AND aa.entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
2217
2218 dol_syslog(get_class($this)."::select_account", LOG_DEBUG);
2219 $resql = $this->db->query($sql);
2220 if ($resql) {
2221 $obj = '';
2222 if ($this->db->num_rows($resql)) {
2223 $obj = $this->db->fetch_object($resql);
2224 }
2225
2226 $result = array('id'=>$obj->rowid, 'account_number'=>$obj->account_number, 'label'=>$obj->label);
2227 return $result;
2228 } else {
2229 $this->error = "Error ".$this->db->lasterror();
2230 dol_syslog(__METHOD__." ".$this->error, LOG_ERR);
2231
2232 return -1;
2233 }
2234 }
2235
2236 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2243 public function get_compte_desc($account = null)
2244 {
2245 // phpcs:enable
2246 global $conf;
2247
2248 $pcgver = getDolGlobalInt('CHARTOFACCOUNTS');
2249 $sql = "SELECT aa.account_number, aa.label, aa.rowid, aa.fk_pcg_version, cat.label as category";
2250 $sql .= " FROM ".MAIN_DB_PREFIX."accounting_account as aa ";
2251 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."accounting_system as asy ON aa.fk_pcg_version = asy.pcg_version";
2252 $sql .= " AND aa.account_number = '".$this->db->escape($account)."'";
2253 $sql .= " AND asy.rowid = ".((int) $pcgver);
2254 $sql .= " AND aa.active = 1";
2255 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_accounting_category as cat ON aa.fk_accounting_category = cat.rowid";
2256 $sql .= " WHERE aa.entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
2257
2258 dol_syslog(get_class($this)."::select_account", LOG_DEBUG);
2259 $resql = $this->db->query($sql);
2260 if ($resql) {
2261 $obj = (object) array('label' => '');
2262 if ($this->db->num_rows($resql)) {
2263 $obj = $this->db->fetch_object($resql);
2264 }
2265 if (empty($obj->category)) {
2266 return $obj->label;
2267 } else {
2268 return $obj->label.' ('.$obj->category.')';
2269 }
2270 } else {
2271 $this->error = "Error ".$this->db->lasterror();
2272 dol_syslog(__METHOD__." ".$this->error, LOG_ERR);
2273 return -1;
2274 }
2275 }
2276
2284 public function getCanModifyBookkeepingSQL($alias = '', $force = false)
2285 {
2286 global $conf;
2287
2288 $alias = trim($alias);
2289 $alias = !empty($alias) && strpos($alias, '.') < 0 ? $alias . "." : $alias;
2290
2291 if (!isset(self::$can_modify_bookkeeping_sql_cached[$alias]) || $force) {
2292 $result = $this->loadFiscalPeriods($force, 'active');
2293 if ($result < 0) {
2294 return null;
2295 }
2296
2297 $sql_list = array();
2298 if (!empty($conf->cache['active_fiscal_period_cached']) && is_array($conf->cache['active_fiscal_period_cached'])) {
2299 foreach ($conf->cache['active_fiscal_period_cached'] as $fiscal_period) {
2300 $sql_list[] = "('" . $this->db->idate($fiscal_period['date_start']) . "' <= {$alias}doc_date AND {$alias}doc_date <= '" . $this->db->idate($fiscal_period['date_end']) . "')";
2301 }
2302 }
2303 self::$can_modify_bookkeeping_sql_cached[$alias] = !empty($sql_list) ? ' AND (' . implode(' OR ', $sql_list) . ')' : '';
2304 }
2305
2306 return self::$can_modify_bookkeeping_sql_cached[$alias];
2307 }
2308
2316 public function canModifyBookkeeping($id, $mode = '')
2317 {
2318 global $conf;
2319
2320 if (getDolGlobalString('ACCOUNTANCY_FISCAL_PERIOD_MODE') == 'blockedonclosed') {
2321 $result = $this->loadFiscalPeriods(false, 'closed');
2322
2323 if ($result < 0) {
2324 return -1;
2325 }
2326
2327 $bookkeeping = new BookKeeping($this->db);
2328 $result = $bookkeeping->fetch($id, null, $mode);
2329 if ($result <= 0) {
2330 return $result;
2331 }
2332
2333 if (!empty($conf->cache['closed_fiscal_period_cached']) && is_array($conf->cache['closed_fiscal_period_cached'])) {
2334 foreach ($conf->cache['closed_fiscal_period_cached'] as $fiscal_period) {
2335 if ($fiscal_period['date_start'] <= $bookkeeping->doc_date && $bookkeeping->doc_date <= $fiscal_period['date_end']) {
2336 return 0;
2337 }
2338 }
2339 }
2340
2341 return 1;
2342 } else {
2343 $result = $this->loadFiscalPeriods(false, 'active');
2344 if ($result < 0) {
2345 return -1;
2346 }
2347
2348 $bookkeeping = new BookKeeping($this->db);
2349 $result = $bookkeeping->fetch($id, null, $mode);
2350 if ($result <= 0) {
2351 return $result;
2352 }
2353
2354 if (!empty($conf->cache['active_fiscal_period_cached']) && is_array($conf->cache['active_fiscal_period_cached'])) {
2355 foreach ($conf->cache['active_fiscal_period_cached'] as $fiscal_period) {
2356 if ($fiscal_period['date_start'] <= $bookkeeping->doc_date && $bookkeeping->doc_date <= $fiscal_period['date_end']) {
2357 return 1;
2358 }
2359 }
2360 }
2361
2362 return 0;
2363 }
2364 }
2365
2372 public function validBookkeepingDate($date)
2373 {
2374 global $conf;
2375
2376 if (getDolGlobalString('ACCOUNTANCY_FISCAL_PERIOD_MODE') == 'blockedonclosed') {
2377 $result = $this->loadFiscalPeriods(false, 'closed');
2378
2379 if ($result < 0) {
2380 return -1;
2381 }
2382
2383 if (!empty($conf->cache['closed_fiscal_period_cached']) && is_array($conf->cache['closed_fiscal_period_cached'])) {
2384 foreach ($conf->cache['closed_fiscal_period_cached'] as $fiscal_period) {
2385 if ($fiscal_period['date_start'] <= $date && $date <= $fiscal_period['date_end']) {
2386 return 0;
2387 }
2388 }
2389 }
2390
2391 return 1;
2392 } else {
2393 $result = $this->loadFiscalPeriods(false, 'active');
2394 if ($result < 0) {
2395 return -1;
2396 }
2397
2398 if (!empty($conf->cache['active_fiscal_period_cached']) && is_array($conf->cache['active_fiscal_period_cached'])) {
2399 foreach ($conf->cache['active_fiscal_period_cached'] as $fiscal_period) {
2400 if ($fiscal_period['date_start'] <= $date && $date <= $fiscal_period['date_end']) {
2401 return 1;
2402 }
2403 }
2404 }
2405
2406 return 0;
2407 }
2408 }
2409
2417 public function loadFiscalPeriods($force = false, $mode = 'active')
2418 {
2419 global $conf;
2420
2421 if ($mode == 'active') {
2422 if (!isset($conf->cache['active_fiscal_period_cached']) || $force) {
2423 $sql = "SELECT date_start, date_end";
2424 $sql .= " FROM " . $this->db->prefix() . "accounting_fiscalyear";
2425 $sql .= " WHERE entity = " . ((int) $conf->entity);
2426 $sql .= " AND statut = 0";
2427
2428 $resql = $this->db->query($sql);
2429 if (!$resql) {
2430 $this->errors[] = $this->db->lasterror();
2431 return -1;
2432 }
2433
2434 $list = array();
2435 while ($obj = $this->db->fetch_object($resql)) {
2436 $list[] = array(
2437 'date_start' => $this->db->jdate($obj->date_start),
2438 'date_end' => $this->db->jdate($obj->date_end),
2439 );
2440 }
2441 $conf->cache['active_fiscal_period_cached'] = $list;
2442 }
2443 }
2444 if ($mode == 'closed') {
2445 if (!isset($conf->cache['closed_fiscal_period_cached']) || $force) {
2446 $sql = "SELECT date_start, date_end";
2447 $sql .= " FROM " . $this->db->prefix() . "accounting_fiscalyear";
2448 $sql .= " WHERE entity = " . ((int) $conf->entity);
2449 $sql .= " AND statut = 1";
2450
2451 $resql = $this->db->query($sql);
2452 if (!$resql) {
2453 $this->errors[] = $this->db->lasterror();
2454 return -1;
2455 }
2456
2457 $list = array();
2458 while ($obj = $this->db->fetch_object($resql)) {
2459 $list[] = array(
2460 'date_start' => $this->db->jdate($obj->date_start),
2461 'date_end' => $this->db->jdate($obj->date_end),
2462 );
2463 }
2464 $conf->cache['closed_fiscal_period_cached'] = $list;
2465 }
2466 }
2467
2468 return 1;
2469 }
2470
2477 public function getFiscalPeriods($filter = '')
2478 {
2479 global $conf;
2480 $list = array();
2481
2482 $sql = "SELECT rowid, label, date_start, date_end, statut";
2483 $sql .= " FROM " . $this->db->prefix() . "accounting_fiscalyear";
2484 $sql .= " WHERE entity = " . ((int) $conf->entity);
2485 if (!empty($filter)) {
2486 $sql .= " AND (" . $filter . ')';
2487 }
2488 $sql .= $this->db->order('date_start', 'ASC');
2489
2490 $resql = $this->db->query($sql);
2491 if (!$resql) {
2492 $this->errors[] = $this->db->lasterror();
2493 return -1;
2494 }
2495
2496 while ($obj = $this->db->fetch_object($resql)) {
2497 $list[$obj->rowid] = array(
2498 'id' => $obj->rowid,
2499 'label' => $obj->label,
2500 'date_start' => $this->db->jdate($obj->date_start),
2501 'date_end' => $this->db->jdate($obj->date_end),
2502 'status' => $obj->statut,
2503 );
2504 }
2505
2506 return $list;
2507 }
2508
2516 public function getCountByMonthForFiscalPeriod($date_start, $date_end)
2517 {
2518 $total = 0;
2519 $list = array();
2520
2521 $sql = "SELECT YEAR(b.doc_date) as year";
2522 for ($i = 1; $i <= 12; $i++) {
2523 $sql .= ", SUM(" . $this->db->ifsql("MONTH(b.doc_date)=" . $i, "1", "0") . ") AS month" . $i;
2524 }
2525 $sql .= ", COUNT(b.rowid) as total";
2526 $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping as b";
2527 $sql .= " WHERE b.doc_date >= '" . $this->db->idate($date_start) . "'";
2528 $sql .= " AND b.doc_date <= '" . $this->db->idate($date_end) . "'";
2529 $sql .= " AND b.entity IN (" . getEntity('bookkeeping', 0) . ")"; // We don't share object for accountancy
2530
2531 // Get count for each month into the fiscal period
2532 if (getDolGlobalString("ACCOUNTANCY_DISABLE_CLOSURE_LINE_BY_LINE")) {
2533 // TODO Analyse is done by finding record not into a closed period
2534 // Loop on each closed period
2535 $sql .= " AND b.doc_date BETWEEN 0 AND 0";
2536 } else {
2537 // Analyse closed record using the unitary flag/date on each record
2538 $sql .= " AND date_validated IS NULL";
2539 }
2540
2541 $sql .= " GROUP BY YEAR(b.doc_date)";
2542 $sql .= $this->db->order("year", 'ASC');
2543
2544 dol_syslog(__METHOD__, LOG_DEBUG);
2545 $resql = $this->db->query($sql);
2546 if (!$resql) {
2547 $this->errors[] = $this->db->lasterror();
2548 return -1;
2549 }
2550
2551 while ($obj = $this->db->fetch_object($resql)) {
2552 $total += (int) $obj->total;
2553 $year_list = array(
2554 'year' => (int) $obj->year,
2555 'count' => array(),
2556 'total' => (int) $obj->total,
2557 );
2558 for ($i = 1; $i <= 12; $i++) {
2559 $year_list['count'][$i] = (int) $obj->{'month' . $i};
2560 }
2561
2562 $list[] = $year_list;
2563 }
2564
2565 $this->db->free($resql);
2566
2567 return array(
2568 'total' => $total,
2569 'list' => $list,
2570 );
2571 }
2572
2580 public function validateMovementForFiscalPeriod($date_start, $date_end)
2581 {
2582 global $conf;
2583
2584 $now = dol_now();
2585
2586 // Specify as export : update field date_validated on selected month/year
2587 $sql = " UPDATE " . MAIN_DB_PREFIX . "accounting_bookkeeping";
2588 $sql .= " SET date_validated = '" . $this->db->idate($now) . "'";
2589 $sql .= " WHERE entity = " . ((int) $conf->entity);
2590 $sql .= " AND DATE(doc_date) >= '" . $this->db->idate($date_start) . "'";
2591 $sql .= " AND DATE(doc_date) <= '" . $this->db->idate($date_end) . "'";
2592 $sql .= " AND date_validated IS NULL";
2593
2594 dol_syslog(__METHOD__, LOG_DEBUG);
2595 $resql = $this->db->query($sql);
2596 if (!$resql) {
2597 $this->errors[] = $this->db->lasterror();
2598 return -1;
2599 }
2600
2601 return 1;
2602 }
2603
2613 public function closeFiscalPeriod($fiscal_period_id, $new_fiscal_period_id, $separate_auxiliary_account = false, $generate_bookkeeping_records = true)
2614 {
2615 global $conf, $langs, $user;
2616
2617 // Current fiscal period
2618 $fiscal_period_id = max(0, $fiscal_period_id);
2619 if (empty($fiscal_period_id)) {
2620 $langs->load('errors');
2621 $this->errors[] = $langs->trans('ErrorBadParameters');
2622 return -1;
2623 }
2624 $fiscal_period = new Fiscalyear($this->db);
2625 $result = $fiscal_period->fetch($fiscal_period_id);
2626 if ($result < 0) {
2627 $this->error = $fiscal_period->error;
2628 $this->errors = $fiscal_period->errors;
2629 return -1;
2630 } elseif (empty($fiscal_period->id)) {
2631 $langs->loadLangs(array('errors', 'compta'));
2632 $this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('FiscalPeriod') . ' (' . $fiscal_period_id . ')';
2633 return -1;
2634 }
2635
2636 // New fiscal period
2637 $new_fiscal_period_id = max(0, $new_fiscal_period_id);
2638 if (empty($new_fiscal_period_id)) {
2639 $langs->load('errors');
2640 $this->errors[] = $langs->trans('ErrorBadParameters');
2641 return -1;
2642 }
2643 $new_fiscal_period = new Fiscalyear($this->db);
2644 $result = $new_fiscal_period->fetch($new_fiscal_period_id);
2645 if ($result < 0) {
2646 $this->error = $new_fiscal_period->error;
2647 $this->errors = $new_fiscal_period->errors;
2648 return -1;
2649 } elseif (empty($new_fiscal_period->id)) {
2650 $langs->loadLangs(array('errors', 'compta'));
2651 $this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('FiscalPeriod') . ' (' . $new_fiscal_period_id . ')';
2652 return -1;
2653 }
2654
2655 $error = 0;
2656 $this->db->begin();
2657
2658 $fiscal_period->statut = Fiscalyear::STATUS_CLOSED;
2659 $fiscal_period->status = Fiscalyear::STATUS_CLOSED; // Actually not used
2660 $result = $fiscal_period->update($user);
2661 if ($result < 0) {
2662 $this->error = $fiscal_period->error;
2663 $this->errors = $fiscal_period->errors;
2664 $error++;
2665 }
2666
2667 if (!$error && !empty($generate_bookkeeping_records)) {
2668 $journal_id = max(0, getDolGlobalString('ACCOUNTING_CLOSURE_DEFAULT_JOURNAL'));
2669 if (empty($journal_id)) {
2670 $langs->loadLangs(array('errors', 'accountancy'));
2671 $this->errors[] = $langs->trans('ErrorBadParameters') . ' - ' . $langs->trans('Codejournal') . ' (' . $langs->trans('AccountingJournalType9') . ')';
2672 $error++;
2673 }
2674
2675 // Fetch journal
2676 if (!$error) {
2677 $journal = new AccountingJournal($this->db);
2678 $result = $journal->fetch($journal_id);
2679 if ($result < 0) {
2680 $this->error = $journal->error;
2681 $this->errors = $journal->errors;
2682 $error++;
2683 } elseif ($result == 0) {
2684 $langs->loadLangs(array('errors', 'accountancy'));
2685 $this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('Codejournal') . ' (' . $langs->trans('AccountingJournalType9') . ')';
2686 $error++;
2687 }
2688 }
2689
2690 if (!$error) {
2691 $accounting_groups_used_for_balance_sheet_account = array_filter(array_map('trim', explode(',', getDolGlobalString('ACCOUNTING_CLOSURE_ACCOUNTING_GROUPS_USED_FOR_BALANCE_SHEET_ACCOUNT'))), 'strlen');
2692 $accounting_groups_used_for_income_statement = array_filter(array_map('trim', explode(',', getDolGlobalString('ACCOUNTING_CLOSURE_ACCOUNTING_GROUPS_USED_FOR_INCOME_STATEMENT'))), 'strlen');
2693
2694 $pcg_type_filter = array();
2695 $tmp = array_merge($accounting_groups_used_for_balance_sheet_account, $accounting_groups_used_for_income_statement);
2696 foreach ($tmp as $item) {
2697 $pcg_type_filter[] = "'" . $this->db->escape($item) . "'";
2698 }
2699
2700 $sql = 'SELECT';
2701 $sql .= " t.numero_compte,";
2702 if ($separate_auxiliary_account) {
2703 $sql .= " NULLIF(t.subledger_account, '') as subledger_account,"; // fix db issues with Null or "" values
2704 }
2705 $sql .= " aa.pcg_type,";
2706 $sql .= " (SUM(t.credit) - SUM(t.debit)) as opening_balance";
2707 $sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . ' as t';
2708 $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'accounting_account as aa ON aa.account_number = t.numero_compte';
2709 $sql .= ' WHERE t.entity = ' . ((int) $conf->entity); // Do not use getEntity for accounting features
2710 $sql .= " AND aa.entity = ". ((int) $conf->entity);
2711 $sql .= ' AND aa.fk_pcg_version IN (SELECT pcg_version FROM '.MAIN_DB_PREFIX.'accounting_system WHERE rowid = '.((int) getDolGlobalInt('CHARTOFACCOUNTS')).')';
2712 $sql .= ' AND aa.pcg_type IN (' . $this->db->sanitize(implode(',', $pcg_type_filter), 1) . ')';
2713 $sql .= " AND DATE(t.doc_date) >= '" . $this->db->idate($fiscal_period->date_start) . "'";
2714 $sql .= " AND DATE(t.doc_date) <= '" . $this->db->idate($fiscal_period->date_end) . "'";
2715 $sql .= ' GROUP BY t.numero_compte, aa.pcg_type';
2716 if ($separate_auxiliary_account) {
2717 $sql .= " , NULLIF(t.subledger_account, '')";
2718 }
2719 $sql .= ' HAVING (SUM(t.credit) - SUM(t.debit)) != 0 '; // Exclude rows with opening_balance = 0
2720 $sql .= $this->db->order("t.numero_compte", "ASC");
2721
2722 $resql = $this->db->query($sql);
2723 if (!$resql) {
2724 $this->errors[] = 'Error ' . $this->db->lasterror();
2725 dol_syslog(__METHOD__ . ' ' . join(',', $this->errors), LOG_ERR);
2726
2727 $error++;
2728 } else {
2729 $now = dol_now();
2730 $income_statement_amount = 0;
2731 while ($obj = $this->db->fetch_object($resql)) {
2732 if (in_array($obj->pcg_type, $accounting_groups_used_for_income_statement)) {
2733 $income_statement_amount += $obj->opening_balance;
2734 } else {
2735 // Insert bookkeeping record for balance sheet account
2736 $mt = $obj->opening_balance;
2737
2738 $bookkeeping = new BookKeeping($this->db);
2739 $bookkeeping->doc_date = $new_fiscal_period->date_start;
2740 $bookkeeping->date_lim_reglement = '';
2741 $bookkeeping->doc_ref = $fiscal_period->label;
2742 $bookkeeping->date_creation = $now;
2743 $bookkeeping->doc_type = 'closure';
2744 $bookkeeping->fk_doc = $fiscal_period->id;
2745 $bookkeeping->fk_docdet = 0; // Useless, can be several lines that are source of this record to add
2746 $bookkeeping->thirdparty_code = '';
2747
2748 if ($separate_auxiliary_account) {
2749 $bookkeeping->subledger_account = $obj->subledger_account;
2750 $sql = 'SELECT';
2751 $sql .= " subledger_label";
2752 $sql .= " FROM " . MAIN_DB_PREFIX . $this->table_element;
2753 $sql .= " WHERE subledger_account = '" . $this->db->escape($obj->subledger_account) . "'";
2754 $sql .= " ORDER BY doc_date DESC";
2755 $sql .= " LIMIT 1";
2756 $result = $this->db->query($sql);
2757 if (!$result) {
2758 $this->errors[] = 'Error: ' . $this->db->lasterror();
2759 dol_syslog(__METHOD__ . ' ' . join(',', $this->errors), LOG_ERR);
2760 $error++;
2761 }
2762 $objtmp = $this->db->fetch_object($result);
2763 $bookkeeping->subledger_label = $objtmp->subledger_label; // latest subledger label used
2764 } else {
2765 $bookkeeping->subledger_account = null;
2766 $bookkeeping->subledger_label = null;
2767 }
2768
2769 $bookkeeping->numero_compte = $obj->numero_compte;
2770 $accountingaccount = new AccountingAccount($this->db);
2771 $accountingaccount->fetch('', $obj->numero_compte);
2772 $bookkeeping->label_compte = $accountingaccount->label; // latest account label used
2773
2774 $bookkeeping->label_operation = $new_fiscal_period->label;
2775 $bookkeeping->montant = $mt;
2776 $bookkeeping->sens = ($mt >= 0) ? 'C' : 'D';
2777 $bookkeeping->debit = ($mt < 0) ? -$mt : 0;
2778 $bookkeeping->credit = ($mt >= 0) ? $mt : 0;
2779 $bookkeeping->code_journal = $journal->code;
2780 $bookkeeping->journal_label = $langs->transnoentities($journal->label);
2781 $bookkeeping->fk_user_author = $user->id;
2782 $bookkeeping->entity = $conf->entity;
2783
2784 $result = $bookkeeping->create($user);
2785 if ($result < 0) {
2786 $this->error = $bookkeeping->error;
2787 $this->errors = $bookkeeping->errors;
2788 $error++;
2789 break;
2790 }
2791 }
2792 }
2793
2794 // Insert bookkeeping record for income statement
2795 if (!$error && $income_statement_amount != 0) {
2796 $mt = $income_statement_amount;
2797 $accountingaccount = new AccountingAccount($this->db);
2798 $accountingaccount->fetch(null, getDolGlobalString($income_statement_amount < 0 ? 'ACCOUNTING_RESULT_LOSS' : 'ACCOUNTING_RESULT_PROFIT'), true);
2799
2800 $bookkeeping = new BookKeeping($this->db);
2801 $bookkeeping->doc_date = $new_fiscal_period->date_start;
2802 $bookkeeping->date_lim_reglement = '';
2803 $bookkeeping->doc_ref = $fiscal_period->label;
2804 $bookkeeping->date_creation = $now;
2805 $bookkeeping->doc_type = 'closure';
2806 $bookkeeping->fk_doc = $fiscal_period->id;
2807 $bookkeeping->fk_docdet = 0; // Useless, can be several lines that are source of this record to add
2808 $bookkeeping->thirdparty_code = '';
2809
2810 if ($separate_auxiliary_account) {
2811 $bookkeeping->subledger_account = $obj->subledger_account;
2812 $sql = 'SELECT';
2813 $sql .= " subledger_label";
2814 $sql .= " FROM " . MAIN_DB_PREFIX . $this->table_element;
2815 $sql .= " WHERE subledger_account = '" . $this->db->escape($obj->subledger_account) . "'";
2816 $sql .= " ORDER BY doc_date DESC";
2817 $sql .= " LIMIT 1";
2818 $result = $this->db->query($sql);
2819 if (!$result) {
2820 $this->errors[] = 'Error: ' . $this->db->lasterror();
2821 dol_syslog(__METHOD__ . ' ' . join(',', $this->errors), LOG_ERR);
2822 $error++;
2823 }
2824 $objtmp = $this->db->fetch_object($result);
2825 $bookkeeping->subledger_label = $objtmp->subledger_label; // latest subledger label used
2826 } else {
2827 $bookkeeping->subledger_account = null;
2828 $bookkeeping->subledger_label = null;
2829 }
2830
2831 $bookkeeping->numero_compte = $accountingaccount->account_number;
2832 $bookkeeping->label_compte = $accountingaccount->label;
2833
2834 $bookkeeping->label_operation = $new_fiscal_period->label;
2835 $bookkeeping->montant = $mt;
2836 $bookkeeping->sens = ($mt >= 0) ? 'C' : 'D';
2837 $bookkeeping->debit = ($mt < 0) ? -$mt : 0;
2838 $bookkeeping->credit = ($mt >= 0) ? $mt : 0;
2839 $bookkeeping->code_journal = $journal->code;
2840 $bookkeeping->journal_label = $langs->transnoentities($journal->label);
2841 $bookkeeping->fk_user_author = $user->id;
2842 $bookkeeping->entity = $conf->entity;
2843
2844 $result = $bookkeeping->create($user);
2845 if ($result < 0) {
2846 $this->error = $bookkeeping->error;
2847 $this->errors = $bookkeeping->errors;
2848 $error++;
2849 }
2850 }
2851 $this->db->free($resql);
2852 }
2853 }
2854 }
2855
2856 if ($error) {
2857 $this->db->rollback();
2858 return -1;
2859 } else {
2860 $this->db->commit();
2861 return 1;
2862 }
2863 }
2864
2875 public function insertAccountingReversal($fiscal_period_id, $inventory_journal_id, $new_fiscal_period_id, $date_start, $date_end)
2876 {
2877 global $conf, $langs, $user;
2878
2879 // Current fiscal period
2880 $fiscal_period_id = max(0, $fiscal_period_id);
2881 if (empty($fiscal_period_id)) {
2882 $langs->load('errors');
2883 $this->errors[] = $langs->trans('ErrorBadParameters');
2884 return -1;
2885 }
2886 $fiscal_period = new Fiscalyear($this->db);
2887 $result = $fiscal_period->fetch($fiscal_period_id);
2888 if ($result < 0) {
2889 $this->error = $fiscal_period->error;
2890 $this->errors = $fiscal_period->errors;
2891 return -1;
2892 } elseif (empty($fiscal_period->id)) {
2893 $langs->loadLangs(array('errors', 'compta'));
2894 $this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('FiscalPeriod') . ' (' . $fiscal_period_id . ')';
2895 return -1;
2896 }
2897
2898 // New fiscal period
2899 $new_fiscal_period_id = max(0, $new_fiscal_period_id);
2900 if (empty($new_fiscal_period_id)) {
2901 $langs->load('errors');
2902 $this->errors[] = $langs->trans('ErrorBadParameters');
2903 return -1;
2904 }
2905 $new_fiscal_period = new Fiscalyear($this->db);
2906 $result = $new_fiscal_period->fetch($new_fiscal_period_id);
2907 if ($result < 0) {
2908 $this->error = $new_fiscal_period->error;
2909 $this->errors = $new_fiscal_period->errors;
2910 return -1;
2911 } elseif (empty($new_fiscal_period->id)) {
2912 $langs->loadLangs(array('errors', 'compta'));
2913 $this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('FiscalPeriod') . ' (' . $new_fiscal_period_id . ')';
2914 return -1;
2915 }
2916
2917 // Inventory journal
2918 $inventory_journal_id = max(0, $inventory_journal_id);
2919 if (empty($inventory_journal_id)) {
2920 $langs->load('errors');
2921 $this->errors[] = $langs->trans('ErrorBadParameters');
2922 return -1;
2923 }
2924 // Fetch journal
2925 $inventory_journal = new AccountingJournal($this->db);
2926 $result = $inventory_journal->fetch($inventory_journal_id);
2927 if ($result < 0) {
2928 $this->error = $inventory_journal->error;
2929 $this->errors = $inventory_journal->errors;
2930 return -1;
2931 } elseif ($result == 0) {
2932 $langs->loadLangs(array('errors', 'accountancy'));
2933 $this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('InventoryJournal');
2934 return -1;
2935 }
2936
2937 $error = 0;
2938 $this->db->begin();
2939
2940 $sql = 'SELECT t.rowid';
2941 $sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . ' as t';
2942 $sql .= ' WHERE t.entity = ' . ((int) $conf->entity); // Do not use getEntity for accounting features
2943 $sql .= " AND code_journal = '" . $this->db->escape($inventory_journal->code) . "'";
2944 $sql .= " AND DATE(t.doc_date) >= '" . $this->db->idate($date_start) . "'";
2945 $sql .= " AND DATE(t.doc_date) <= '" . $this->db->idate($date_end) . "'";
2946 $sql .= " AND DATE(t.doc_date) >= '" . $this->db->idate($fiscal_period->date_start) . "'";
2947 $sql .= " AND DATE(t.doc_date) <= '" . $this->db->idate($fiscal_period->date_end) . "'";
2948
2949 $resql = $this->db->query($sql);
2950 if (!$resql) {
2951 $this->errors[] = 'Error ' . $this->db->lasterror();
2952 dol_syslog(__METHOD__ . ' ' . join(',', $this->errors), LOG_ERR);
2953
2954 $error++;
2955 } else {
2956 $now = dol_now();
2957 while ($obj = $this->db->fetch_object($resql)) {
2958 $bookkeeping = new BookKeeping($this->db);
2959 $result = $bookkeeping->fetch($obj->rowid);
2960 if ($result < 0) {
2961 $this->error = $inventory_journal->error;
2962 $this->errors = $inventory_journal->errors;
2963 $error++;
2964 break;
2965 } elseif ($result == 0) {
2966 $langs->loadLangs(array('errors', 'accountancy'));
2967 $this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('LineId') . ': ' . $obj->rowid;
2968 $error++;
2969 break;
2970 }
2971
2972 $bookkeeping->id = 0;
2973 $bookkeeping->doc_date = $new_fiscal_period->date_start;
2974 $bookkeeping->doc_ref = $new_fiscal_period->label;
2975 $bookkeeping->date_creation = $now;
2976 $bookkeeping->doc_type = 'accounting_reversal';
2977 $bookkeeping->fk_doc = $new_fiscal_period->id;
2978 $bookkeeping->fk_docdet = 0; // Useless, can be several lines that are source of this record to add
2979
2980 $bookkeeping->montant = -$bookkeeping->montant;
2981 $bookkeeping->sens = ($bookkeeping->montant >= 0) ? 'C' : 'D';
2982 $old_debit = $bookkeeping->debit;
2983 $bookkeeping->debit = $bookkeeping->credit;
2984 $bookkeeping->credit = $old_debit;
2985
2986 $bookkeeping->fk_user_author = $user->id;
2987 $bookkeeping->entity = $conf->entity;
2988
2989 $result = $bookkeeping->create($user);
2990 if ($result < 0) {
2991 $this->error = $bookkeeping->error;
2992 $this->errors = $bookkeeping->errors;
2993 $error++;
2994 break;
2995 }
2996 }
2997 $this->db->free($resql);
2998 }
2999
3000 if ($error) {
3001 $this->db->rollback();
3002 return -1;
3003 } else {
3004 $this->db->commit();
3005 return 1;
3006 }
3007 }
3008}
3009
3014{
3018 public $id;
3019
3020 public $doc_date = '';
3021 public $doc_type;
3022 public $doc_ref;
3023
3027 public $fk_doc;
3028
3032 public $fk_docdet;
3033
3034 public $thirdparty_code;
3035 public $subledger_account;
3036 public $subledger_label;
3037 public $numero_compte;
3038 public $label_compte;
3039 public $label_operation;
3040 public $debit;
3041 public $credit;
3042
3047 public $montant;
3048
3052 public $amount;
3053
3057 public $multicurrency_amount;
3058
3062 public $multicurrency_code;
3063
3067 public $sens;
3068 public $lettering_code;
3069 public $date_lettering;
3070
3074 public $fk_user_author;
3075
3076 public $import_key;
3077 public $code_journal;
3078 public $journal_label;
3079 public $piece_num;
3080
3084 public $date_creation;
3085
3089 public $date_modification;
3090
3094 public $date_export;
3095
3099 public $date_validation;
3100
3104 public $date_lim_reglement;
3105}
length_accountg($account)
Return General accounting account with defined length (used for product and miscellaneous)
ajax_combobox($htmlname, $events=array(), $minLengthToAutocomplete=0, $forcefocus=0, $widthTypeOfAutocomplete='resolve', $idforemptyvalue='-1', $morecss='')
Convert a html select field into an ajax combobox.
Definition ajax.lib.php:455
Class to manage accounting accounts.
Class to manage accounting journals.
Class to manage Ledger (General Ledger and Subledger)
fetchAllBalance($sortorder='', $sortfield='', $limit=0, $offset=0, array $filter=array(), $filtermode='AND', $option=0)
Load object in memory from the database.
closeFiscalPeriod($fiscal_period_id, $new_fiscal_period_id, $separate_auxiliary_account=false, $generate_bookkeeping_records=true)
Close fiscal period.
getCountByMonthForFiscalPeriod($date_start, $date_end)
Get list of count by month into the fiscal period.
create(User $user, $notrigger=false)
Create object into database.
createStd(User $user, $notrigger=false, $mode='')
Create object into database.
getNomUrl($withpicto=0, $option='', $notooltip=0, $morecss='', $save_lastsearch_value=-1)
Return a link to the object card (with optionally the picto)
select_account($selectid, $htmlname='account', $showempty=0, $event=array(), $select_in=0, $select_out=0, $aabase='')
Return list of accounts with label by chart of accounts.
update(User $user, $notrigger=false, $mode='')
Update object into database.
getNextNumMvt($mode='')
Return next number movement.
get_compte_desc($account=null)
Description of accounting account.
__construct(DoliDB $db)
Constructor.
createFromClone(User $user, $fromid)
Load an object from its id and create a new one in database.
deleteByImportkey($importkey, $mode='')
Delete bookkeeping by importkey.
getRootAccount($account=null)
Return id and description of a root accounting account.
transformTransaction($direction=0, $piece_num='')
Transform transaction.
insertAccountingReversal($fiscal_period_id, $inventory_journal_id, $new_fiscal_period_id, $date_start, $date_end)
Insert accounting reversal into the inventory journal of the new fiscal period.
fetchPerMvt($piecenum, $mode='')
Load an accounting document into memory from database.
updateByMvt($piece_num='', $field='', $value='', $mode='')
Update accounting movement.
deleteMvtNum($piecenum, $mode='')
Delete bookkeeping by piece number.
getFiscalPeriods($filter='')
Get list of fiscal period ordered by start date.
validBookkeepingDate($date)
Is the bookkeeping date valid (on an open period or not on a closed period) ?
deleteByYearAndJournal($delyear=0, $journal='', $mode='', $delmonth=0)
Delete bookkeeping by year.
loadFiscalPeriods($force=false, $mode='active')
Load list of active fiscal period.
fetchAllByAccount($sortorder='', $sortfield='', $limit=0, $offset=0, array $filter=array(), $filtermode='AND', $option=0, $countonly=0)
Load object in memory from the database in ->lines.
initAsSpecimen()
Initialise object with example values Id must be 0 if object instance is a specimen.
getCanModifyBookkeepingSQL($alias='', $force=false)
Get SQL string for check if the bookkeeping can be modified or deleted ? (cached)
fetch($id, $ref=null, $mode='')
Load object in memory from the database.
canModifyBookkeeping($id, $mode='')
Is the bookkeeping can be modified or deleted ?
fetchAll($sortorder='', $sortfield='', $limit=0, $offset=0, array $filter=array(), $filtermode='AND', $showAlreadyExportMovements=1)
Load object in memory from the database.
fetchAllPerMvt($piecenum, $mode='')
Load all informations of accountancy document.
validateMovementForFiscalPeriod($date_start, $date_end)
Validate all movement between the specified dates.
export_bookkeeping($model='ebp')
Export bookkeeping.
Class BookKeepingLine.
Parent class of all other business classes (invoices, contracts, proposals, orders,...
Class to manage Dolibarr database access.
Class to manage fiscal year.
static selectarray($htmlname, $array, $id='', $show_empty=0, $key_in_label=0, $value_as_key=0, $moreparam='', $translate=0, $maxlen=0, $disabled=0, $sort='', $morecss='minwidth75', $addjscombo=1, $moreparamonempty='', $disablebademail=0, $nohtmlescape=0)
Return a HTML select string, built from an array of key+value.
Class to manage Dolibarr users.
dolSqlDateFilter($datefield, $day_date, $month_date, $year_date, $excludefirstand=0, $gm=false)
Generate a SQL string to make a filter into a range (for second of date until last second of date).
Definition date.lib.php:377
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
natural_search($fields, $value, $mode=0, $nofirstand=0)
Generate natural SQL search string for a criteria (this criteria can be tested on one or several fiel...
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.