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", 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 $error = 0;
1464
1465 $sql_filter = $this->getCanModifyBookkeepingSQL();
1466 if (!isset($sql_filter)) {
1467 return -1;
1468 }
1469
1470 $this->db->begin();
1471
1472 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element.$mode;
1473 $sql .= " SET ".$field." = ".(is_numeric($value) ? ((float) $value) : "'".$this->db->escape($value)."'");
1474 $sql .= " WHERE piece_num = ".((int) $piece_num);
1475 $sql .= $sql_filter;
1476
1477 $resql = $this->db->query($sql);
1478
1479 if (!$resql) {
1480 $error++;
1481 $this->errors[] = 'Error '.$this->db->lasterror();
1482 dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
1483 }
1484 if ($error) {
1485 $this->db->rollback();
1486
1487 return -1 * $error;
1488 } else {
1489 $this->db->commit();
1490
1491 return 1;
1492 }
1493 }
1494
1503 public function delete(User $user, $notrigger = 0, $mode = '')
1504 {
1505 global $langs;
1506
1507 dol_syslog(__METHOD__, LOG_DEBUG);
1508
1509 $result = $this->canModifyBookkeeping($this->id, $mode);
1510 if ($result < 0) {
1511 return -1;
1512 } elseif ($result == 0) {
1513 if (getDolGlobalString('ACCOUNTANCY_FISCAL_PERIOD_MODE') == 'blockedonclosed') {
1514 $this->errors[] = $langs->trans('ErrorBookkeepingDocDateIsOnAClosedFiscalPeriod');
1515 } else {
1516 $this->errors[] = $langs->trans('ErrorBookkeepingDocDateNotOnActiveFiscalPeriod');
1517 }
1518 return -1;
1519 }
1520
1521 $error = 0;
1522
1523 $this->db->begin();
1524
1525 // Uncomment this and change MYOBJECT to your own tag if you
1526 // want this action calls a trigger.
1527 //if (! $error && ! $notrigger) {
1528
1529 // // Call triggers
1530 // $result=$this->call_trigger('MYOBJECT_DELETE',$user);
1531 // if ($result < 0) { $error++; //Do also what you must do to rollback action if trigger fail}
1532 // // End call triggers
1533 //}
1534
1535 if (!$error) {
1536 $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.$mode;
1537 $sql .= ' WHERE rowid='.((int) $this->id);
1538
1539 $resql = $this->db->query($sql);
1540 if (!$resql) {
1541 $error++;
1542 $this->errors[] = 'Error '.$this->db->lasterror();
1543 dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
1544 }
1545 }
1546
1547 // Commit or rollback
1548 if ($error) {
1549 $this->db->rollback();
1550
1551 return -1 * $error;
1552 } else {
1553 $this->db->commit();
1554
1555 return 1;
1556 }
1557 }
1558
1566 public function deleteByImportkey($importkey, $mode = '')
1567 {
1568 $this->db->begin();
1569
1570 $sql_filter = $this->getCanModifyBookkeepingSQL();
1571 if (!isset($sql_filter)) {
1572 return -1;
1573 }
1574
1575 // first check if line not yet in bookkeeping
1576 $sql = "DELETE";
1577 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element.$mode;
1578 $sql .= " WHERE import_key = '".$this->db->escape($importkey)."'";
1579 $sql .= $sql_filter;
1580
1581 $resql = $this->db->query($sql);
1582
1583 if (!$resql) {
1584 $this->errors[] = "Error ".$this->db->lasterror();
1585 dol_syslog(get_class($this)."::delete Error ".$this->db->lasterror(), LOG_ERR);
1586 $this->db->rollback();
1587 return -1;
1588 }
1589
1590 $this->db->commit();
1591 return 1;
1592 }
1593
1603 public function deleteByYearAndJournal($delyear = 0, $journal = '', $mode = '', $delmonth = 0)
1604 {
1605 global $conf, $langs;
1606
1607 if (empty($delyear) && empty($journal)) {
1608 $this->error = 'ErrorOneFieldRequired';
1609 return -1;
1610 }
1611 if (!empty($delmonth) && empty($delyear)) {
1612 $this->error = 'YearRequiredIfMonthDefined';
1613 return -2;
1614 }
1615
1616 $sql_filter = $this->getCanModifyBookkeepingSQL();
1617 if (!isset($sql_filter)) {
1618 return -1;
1619 }
1620
1621 $this->db->begin();
1622
1623 // Delete record in bookkeeping
1624 $sql = "DELETE";
1625 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element.$mode;
1626 $sql .= " WHERE 1 = 1";
1627 $sql .= dolSqlDateFilter('doc_date', 0, $delmonth, $delyear);
1628 if (!empty($journal)) {
1629 $sql .= " AND code_journal = '".$this->db->escape($journal)."'";
1630 }
1631 $sql .= " AND entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
1632 // Exclusion of validated entries at the time of deletion
1633 $sql .= " AND date_validated IS NULL";
1634 $sql .= $sql_filter;
1635
1636 // TODO: In a future we must forbid deletion if record is inside a closed fiscal period.
1637
1638 $resql = $this->db->query($sql);
1639
1640 if (!$resql) {
1641 $this->errors[] = "Error ".$this->db->lasterror();
1642 foreach ($this->errors as $errmsg) {
1643 dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR);
1644 $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
1645 }
1646 $this->db->rollback();
1647 return -1;
1648 }
1649
1650 $this->db->commit();
1651 return 1;
1652 }
1653
1661 public function deleteMvtNum($piecenum, $mode = '')
1662 {
1663 global $conf;
1664
1665 $sql_filter = $this->getCanModifyBookkeepingSQL();
1666 if (!isset($sql_filter)) {
1667 return -1;
1668 }
1669
1670 $this->db->begin();
1671
1672 // first check if line not yet in bookkeeping
1673 $sql = "DELETE";
1674 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element.$mode;
1675 $sql .= " WHERE piece_num = ".(int) $piecenum;
1676 $sql .= " AND date_validated IS NULL"; // For security, exclusion of validated entries at the time of deletion
1677 $sql .= " AND entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
1678 $sql .= $sql_filter;
1679
1680 $resql = $this->db->query($sql);
1681
1682 if (!$resql) {
1683 $this->errors[] = "Error ".$this->db->lasterror();
1684 foreach ($this->errors as $errmsg) {
1685 dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR);
1686 $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
1687 }
1688 $this->db->rollback();
1689 return -1;
1690 }
1691
1692 $this->db->commit();
1693 return 1;
1694 }
1695
1703 public function createFromClone(User $user, $fromid)
1704 {
1705 dol_syslog(__METHOD__, LOG_DEBUG);
1706
1707 $error = 0;
1708 $object = new BookKeeping($this->db);
1709
1710 $this->db->begin();
1711
1712 // Load source object
1713 $object->fetch($fromid);
1714 // Reset object
1715 $object->id = 0;
1716
1717 // Clear fields
1718 // ...
1719
1720 // Create clone
1721 $object->context['createfromclone'] = 'createfromclone';
1722 $result = $object->create($user);
1723
1724 // Other options
1725 if ($result < 0) {
1726 $error++;
1727 $this->errors = $object->errors;
1728 dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
1729 }
1730
1731 unset($object->context['createfromclone']);
1732
1733 // End
1734 if (!$error) {
1735 $this->db->commit();
1736
1737 return $object->id;
1738 } else {
1739 $this->db->rollback();
1740
1741 return -1;
1742 }
1743 }
1744
1751 public function initAsSpecimen()
1752 {
1753 global $user;
1754
1755 $now = dol_now();
1756
1757 $this->id = 0;
1758 $this->doc_date = $now;
1759 $this->doc_type = '';
1760 $this->doc_ref = '';
1761 $this->fk_doc = 0;
1762 $this->fk_docdet = 0;
1763 $this->thirdparty_code = 'CU001';
1764 $this->subledger_account = '41100001';
1765 $this->subledger_label = 'My customer company';
1766 $this->numero_compte = '411';
1767 $this->label_compte = 'Customer';
1768 $this->label_operation = 'Sales of pea';
1769 $this->debit = 99.9;
1770 $this->credit = 0.0;
1771 $this->amount = 0.0;
1772 $this->sens = 'D';
1773 $this->fk_user_author = $user->id;
1774 $this->import_key = '20201027';
1775 $this->code_journal = 'VT';
1776 $this->journal_label = 'Journal de vente';
1777 $this->piece_num = 1234;
1778 $this->date_creation = $now;
1779 }
1780
1788 public function fetchPerMvt($piecenum, $mode = '')
1789 {
1790 global $conf;
1791
1792 $sql = "SELECT piece_num, doc_date,code_journal, journal_label, doc_ref, doc_type,";
1793 $sql .= " date_creation, tms as date_modification, date_validated as date_validation";
1794 // In llx_accounting_bookkeeping_tmp, field date_export doesn't exist
1795 if ($mode != "_tmp") {
1796 $sql .= ", date_export";
1797 }
1798 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element.$mode;
1799 $sql .= " WHERE piece_num = ".((int) $piecenum);
1800 $sql .= " AND entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
1801
1802 dol_syslog(__METHOD__, LOG_DEBUG);
1803 $result = $this->db->query($sql);
1804 if ($result) {
1805 $obj = $this->db->fetch_object($result);
1806
1807 $this->piece_num = $obj->piece_num;
1808 $this->code_journal = $obj->code_journal;
1809 $this->journal_label = $obj->journal_label;
1810 $this->doc_date = $this->db->jdate($obj->doc_date);
1811 $this->doc_ref = $obj->doc_ref;
1812 $this->doc_type = $obj->doc_type;
1813 $this->date_creation = $this->db->jdate($obj->date_creation);
1814 $this->date_modification = $this->db->jdate($obj->date_modification);
1815 if ($mode != "_tmp") {
1816 $this->date_export = $this->db->jdate($obj->date_export);
1817 }
1818 $this->date_validation = $this->db->jdate($obj->date_validation);
1819 } else {
1820 $this->error = "Error ".$this->db->lasterror();
1821 dol_syslog(__METHOD__.$this->error, LOG_ERR);
1822 return -1;
1823 }
1824
1825 return 1;
1826 }
1827
1834 public function getNextNumMvt($mode = '')
1835 {
1836 global $conf;
1837
1838 $sql = "SELECT MAX(piece_num)+1 as max FROM ".MAIN_DB_PREFIX.$this->table_element.$mode;
1839 $sql .= " WHERE entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
1840
1841 dol_syslog(get_class($this)."::getNextNumMvt", LOG_DEBUG);
1842
1843 $result = $this->db->query($sql);
1844
1845 if ($result) {
1846 $obj = $this->db->fetch_object($result);
1847 if ($obj) {
1848 $result = $obj->max;
1849 }
1850 if (empty($result)) {
1851 $result = 1;
1852 }
1853 return $result;
1854 } else {
1855 $this->error = "Error ".$this->db->lasterror();
1856 dol_syslog(get_class($this)."::getNextNumMvt ".$this->error, LOG_ERR);
1857 return -1;
1858 }
1859 }
1860
1868 public function fetchAllPerMvt($piecenum, $mode = '')
1869 {
1870 global $conf;
1871
1872 $sql = "SELECT rowid, doc_date, doc_type,";
1873 $sql .= " doc_ref, fk_doc, fk_docdet, thirdparty_code, subledger_account, subledger_label,";
1874 $sql .= " numero_compte, label_compte, label_operation, debit, credit,";
1875 $sql .= " montant as amount, sens, fk_user_author, import_key, code_journal, journal_label, piece_num,";
1876 $sql .= " date_creation, tms as date_modification, date_validated as date_validation";
1877 // In llx_accounting_bookkeeping_tmp, field date_export doesn't exist
1878 if ($mode != "_tmp") {
1879 $sql .= ", date_export";
1880 }
1881 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element.$mode;
1882 $sql .= " WHERE piece_num = ".((int) $piecenum);
1883 $sql .= " AND entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
1884
1885 dol_syslog(__METHOD__, LOG_DEBUG);
1886 $result = $this->db->query($sql);
1887 if ($result) {
1888 while ($obj = $this->db->fetch_object($result)) {
1889 $line = new BookKeepingLine();
1890
1891 $line->id = $obj->rowid;
1892
1893 $line->doc_date = $this->db->jdate($obj->doc_date);
1894 $line->doc_type = $obj->doc_type;
1895 $line->doc_ref = $obj->doc_ref;
1896 $line->fk_doc = $obj->fk_doc;
1897 $line->fk_docdet = $obj->fk_docdet;
1898 $line->thirdparty_code = $obj->thirdparty_code;
1899 $line->subledger_account = $obj->subledger_account;
1900 $line->subledger_label = $obj->subledger_label;
1901 $line->numero_compte = $obj->numero_compte;
1902 $line->label_compte = $obj->label_compte;
1903 $line->label_operation = $obj->label_operation;
1904 $line->debit = $obj->debit;
1905 $line->credit = $obj->credit;
1906 $line->montant = $obj->amount;
1907 $line->amount = $obj->amount;
1908 $line->sens = $obj->sens;
1909 $line->code_journal = $obj->code_journal;
1910 $line->journal_label = $obj->journal_label;
1911 $line->piece_num = $obj->piece_num;
1912 $line->date_creation = $obj->date_creation;
1913 $line->date_modification = $obj->date_modification;
1914 if ($mode != "_tmp") {
1915 $line->date_export = $obj->date_export;
1916 }
1917 $line->date_validation = $obj->date_validation;
1918
1919 $this->linesmvt[] = $line;
1920 }
1921 } else {
1922 $this->error = "Error ".$this->db->lasterror();
1923 dol_syslog(__METHOD__.$this->error, LOG_ERR);
1924 return -1;
1925 }
1926
1927 return 1;
1928 }
1929
1930 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1937 public function export_bookkeeping($model = 'ebp')
1938 {
1939 // phpcs:enable
1940 global $conf;
1941
1942 $sql = "SELECT rowid, doc_date, doc_type,";
1943 $sql .= " doc_ref, fk_doc, fk_docdet, thirdparty_code, subledger_account, subledger_label,";
1944 $sql .= " numero_compte, label_compte, label_operation, debit, credit,";
1945 $sql .= " montant as amount, sens, fk_user_author, import_key, code_journal, piece_num,";
1946 $sql .= " date_validated as date_validation";
1947 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element;
1948 $sql .= " WHERE entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
1949
1950 dol_syslog(get_class($this)."::export_bookkeeping", LOG_DEBUG);
1951
1952 $resql = $this->db->query($sql);
1953
1954 if ($resql) {
1955 $this->linesexport = array();
1956
1957 $num = $this->db->num_rows($resql);
1958 while ($obj = $this->db->fetch_object($resql)) {
1959 $line = new BookKeepingLine();
1960
1961 $line->id = $obj->rowid;
1962
1963 $line->doc_date = $this->db->jdate($obj->doc_date);
1964 $line->doc_type = $obj->doc_type;
1965 $line->doc_ref = $obj->doc_ref;
1966 $line->fk_doc = $obj->fk_doc;
1967 $line->fk_docdet = $obj->fk_docdet;
1968 $line->thirdparty_code = $obj->thirdparty_code;
1969 $line->subledger_account = $obj->subledger_account;
1970 $line->subledger_label = $obj->subledger_label;
1971 $line->numero_compte = $obj->numero_compte;
1972 $line->label_compte = $obj->label_compte;
1973 $line->label_operation = $obj->label_operation;
1974 $line->debit = $obj->debit;
1975 $line->credit = $obj->credit;
1976 $line->montant = $obj->amount;
1977 $line->amount = $obj->amount;
1978 $line->sens = $obj->sens;
1979 $line->code_journal = $obj->code_journal;
1980 $line->piece_num = $obj->piece_num;
1981 $line->date_validation = $obj->date_validation;
1982
1983 $this->linesexport[] = $line;
1984 }
1985 $this->db->free($resql);
1986
1987 return $num;
1988 } else {
1989 $this->error = "Error ".$this->db->lasterror();
1990 dol_syslog(get_class($this)."::export_bookkeeping ".$this->error, LOG_ERR);
1991 return -1;
1992 }
1993 }
1994
2002 public function transformTransaction($direction = 0, $piece_num = '')
2003 {
2004 global $conf;
2005
2006 $error = 0;
2007
2008 $sql_filter = $this->getCanModifyBookkeepingSQL();
2009 if (!isset($sql_filter)) {
2010 return -1;
2011 }
2012
2013 $this->db->begin();
2014
2015 if ($direction == 0) {
2016 $next_piecenum = $this->getNextNumMvt();
2017 $now = dol_now();
2018
2019 if ($next_piecenum < 0) {
2020 $error++;
2021 }
2022
2023 if (!$error) {
2024 // Delete if there is an empty line
2025 $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";
2026 $resql = $this->db->query($sql);
2027 if (!$resql) {
2028 $error++;
2029 $this->errors[] = 'Error '.$this->db->lasterror();
2030 dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
2031 }
2032 }
2033
2034 if (!$error) {
2035 $sql = 'INSERT INTO '.MAIN_DB_PREFIX.$this->table_element.' (doc_date, doc_type,';
2036 $sql .= ' doc_ref, fk_doc, fk_docdet, entity, thirdparty_code, subledger_account, subledger_label,';
2037 $sql .= ' numero_compte, label_compte, label_operation, debit, credit,';
2038 $sql .= ' montant, sens, fk_user_author, import_key, code_journal, journal_label, piece_num, date_creation)';
2039 $sql .= ' SELECT doc_date, doc_type,';
2040 $sql .= ' doc_ref, fk_doc, fk_docdet, entity, thirdparty_code, subledger_account, subledger_label,';
2041 $sql .= ' numero_compte, label_compte, label_operation, debit, credit,';
2042 $sql .= ' montant, sens, fk_user_author, import_key, code_journal, journal_label, '.((int) $next_piecenum).", '".$this->db->idate($now)."'";
2043 $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);
2044 $sql .= $sql_filter;
2045 $resql = $this->db->query($sql);
2046 if (!$resql) {
2047 $error++;
2048 $this->errors[] = 'Error '.$this->db->lasterror();
2049 dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
2050 }
2051 }
2052
2053 if (!$error) {
2054 $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.'_tmp WHERE piece_num = '.((int) $piece_num).' AND entity = ' .((int) $conf->entity);
2055 $resql = $this->db->query($sql);
2056 if (!$resql) {
2057 $error++;
2058 $this->errors[] = 'Error '.$this->db->lasterror();
2059 dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
2060 }
2061 }
2062 } elseif ($direction == 1) {
2063 if (!$error) {
2064 $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.'_tmp WHERE piece_num = '.((int) $piece_num).' AND entity = ' .((int) $conf->entity);
2065 $resql = $this->db->query($sql);
2066 if (!$resql) {
2067 $error++;
2068 $this->errors[] = 'Error '.$this->db->lasterror();
2069 dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
2070 }
2071 }
2072
2073 if (!$error) {
2074 $sql = 'INSERT INTO '.MAIN_DB_PREFIX.$this->table_element.'_tmp (doc_date, doc_type,';
2075 $sql .= ' doc_ref, fk_doc, fk_docdet, thirdparty_code, subledger_account, subledger_label,';
2076 $sql .= ' numero_compte, label_compte, label_operation, debit, credit,';
2077 $sql .= ' montant, sens, fk_user_author, import_key, code_journal, journal_label, piece_num)';
2078 $sql .= ' SELECT doc_date, doc_type,';
2079 $sql .= ' doc_ref, fk_doc, fk_docdet, thirdparty_code, subledger_account, subledger_label,';
2080 $sql .= ' numero_compte, label_compte, label_operation, debit, credit,';
2081 $sql .= ' montant, sens, fk_user_author, import_key, code_journal, journal_label, piece_num';
2082 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' WHERE piece_num = '.((int) $piece_num).' AND entity = ' .((int) $conf->entity);
2083 $sql .= $sql_filter;
2084 $resql = $this->db->query($sql);
2085 if (!$resql) {
2086 $error++;
2087 $this->errors[] = 'Error '.$this->db->lasterror();
2088 dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
2089 }
2090 }
2091
2092 if (!$error) {
2093 $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.'_tmp WHERE piece_num = '.((int) $piece_num).' AND entity = ' .((int) $conf->entity);
2094 $sql .= $sql_filter;
2095 $resql = $this->db->query($sql);
2096 if (!$resql) {
2097 $error++;
2098 $this->errors[] = 'Error '.$this->db->lasterror();
2099 dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
2100 }
2101 }
2102 }
2103 if (!$error) {
2104 $this->db->commit();
2105 return 1;
2106 } else {
2107 $this->db->rollback();
2108 return -1;
2109 }
2110 /*
2111 $sql = "DELETE FROM ";
2112 $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping as ab";
2113 $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "accounting_account as aa ON aa.account_number = ab.numero_compte";
2114 $sql .= " AND aa.active = 1";
2115 $sql .= " INNER JOIN " . MAIN_DB_PREFIX . "accounting_system as asy ON aa.fk_pcg_version = asy.pcg_version";
2116 $sql .= " AND asy.rowid = " . ((int) $pcgver);
2117 $sql .= " AND ab.entity IN (" . getEntity('accountancy') . ")";
2118 $sql .= " ORDER BY account_number ASC";
2119 */
2120 }
2121
2122 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2135 public function select_account($selectid, $htmlname = 'account', $showempty = 0, $event = array(), $select_in = 0, $select_out = 0, $aabase = '')
2136 {
2137 // phpcs:enable
2138 global $conf;
2139
2140 require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php';
2141
2142 $pcgver = getDolGlobalInt('CHARTOFACCOUNTS');
2143
2144 $sql = "SELECT DISTINCT ab.numero_compte as account_number, aa.label as label, aa.rowid as rowid, aa.fk_pcg_version";
2145 $sql .= " FROM ".MAIN_DB_PREFIX."accounting_bookkeeping as ab";
2146 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."accounting_account as aa ON aa.account_number = ab.numero_compte";
2147 $sql .= " AND aa.active = 1";
2148 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."accounting_system as asy ON aa.fk_pcg_version = asy.pcg_version";
2149 $sql .= " AND asy.rowid = ".((int) $pcgver);
2150 $sql .= " AND ab.entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
2151 $sql .= " ORDER BY account_number ASC";
2152
2153 dol_syslog(get_class($this)."::select_account", LOG_DEBUG);
2154 $resql = $this->db->query($sql);
2155
2156 if (!$resql) {
2157 $this->error = "Error ".$this->db->lasterror();
2158 dol_syslog(get_class($this)."::select_account ".$this->error, LOG_ERR);
2159 return -1;
2160 }
2161
2162 $out = ajax_combobox($htmlname, $event);
2163
2164 $options = array();
2165 $selected = null;
2166
2167 while ($obj = $this->db->fetch_object($resql)) {
2168 $label = length_accountg($obj->account_number).' - '.$obj->label;
2169
2170 $select_value_in = $obj->rowid;
2171 $select_value_out = $obj->rowid;
2172
2173 if ($select_in == 1) {
2174 $select_value_in = $obj->account_number;
2175 }
2176 if ($select_out == 1) {
2177 $select_value_out = $obj->account_number;
2178 }
2179
2180 // Remember guy's we store in database llx_facturedet the rowid of accounting_account and not the account_number
2181 // Because same account_number can be share between different accounting_system and do have the same meaning
2182 if (($selectid != '') && $selectid == $select_value_in) {
2183 $selected = $select_value_out;
2184 }
2185
2186 $options[$select_value_out] = $label;
2187 }
2188
2189 $out .= Form::selectarray($htmlname, $options, $selected, $showempty, 0, 0, '', 0, 0, 0, '', 'maxwidth300');
2190 $this->db->free($resql);
2191 return $out;
2192 }
2193
2201 public function getRootAccount($account = null)
2202 {
2203 global $conf;
2204 $pcgver = getDolGlobalInt('CHARTOFACCOUNTS');
2205
2206 $sql = "SELECT root.rowid, root.account_number, root.label as label,";
2207 $sql .= " parent.rowid as parent_rowid, parent.account_number as parent_account_number, parent.label as parent_label";
2208 $sql .= " FROM ".MAIN_DB_PREFIX."accounting_account as aa";
2209 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."accounting_system as asy ON aa.fk_pcg_version = asy.pcg_version";
2210 $sql .= " AND asy.rowid = ".((int) $pcgver);
2211 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."accounting_account as parent ON aa.account_parent = parent.rowid AND parent.active = 1";
2212 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."accounting_account as root ON parent.account_parent = root.rowid AND root.active = 1";
2213 $sql .= " WHERE aa.account_number = '".$this->db->escape($account)."'";
2214 $sql .= " AND aa.entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
2215
2216 dol_syslog(get_class($this)."::select_account", LOG_DEBUG);
2217 $resql = $this->db->query($sql);
2218 if ($resql) {
2219 $obj = '';
2220 if ($this->db->num_rows($resql)) {
2221 $obj = $this->db->fetch_object($resql);
2222 }
2223
2224 $result = array('id'=>$obj->rowid, 'account_number'=>$obj->account_number, 'label'=>$obj->label);
2225 return $result;
2226 } else {
2227 $this->error = "Error ".$this->db->lasterror();
2228 dol_syslog(__METHOD__." ".$this->error, LOG_ERR);
2229
2230 return -1;
2231 }
2232 }
2233
2234 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2241 public function get_compte_desc($account = null)
2242 {
2243 // phpcs:enable
2244 global $conf;
2245
2246 $pcgver = getDolGlobalInt('CHARTOFACCOUNTS');
2247 $sql = "SELECT aa.account_number, aa.label, aa.rowid, aa.fk_pcg_version, cat.label as category";
2248 $sql .= " FROM ".MAIN_DB_PREFIX."accounting_account as aa ";
2249 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."accounting_system as asy ON aa.fk_pcg_version = asy.pcg_version";
2250 $sql .= " AND aa.account_number = '".$this->db->escape($account)."'";
2251 $sql .= " AND asy.rowid = ".((int) $pcgver);
2252 $sql .= " AND aa.active = 1";
2253 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_accounting_category as cat ON aa.fk_accounting_category = cat.rowid";
2254 $sql .= " WHERE aa.entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
2255
2256 dol_syslog(get_class($this)."::select_account", LOG_DEBUG);
2257 $resql = $this->db->query($sql);
2258 if ($resql) {
2259 $obj = '';
2260 if ($this->db->num_rows($resql)) {
2261 $obj = $this->db->fetch_object($resql);
2262 }
2263 if (empty($obj->category)) {
2264 return $obj->label;
2265 } else {
2266 return $obj->label.' ('.$obj->category.')';
2267 }
2268 } else {
2269 $this->error = "Error ".$this->db->lasterror();
2270 dol_syslog(__METHOD__." ".$this->error, LOG_ERR);
2271 return -1;
2272 }
2273 }
2274
2282 public function getCanModifyBookkeepingSQL($alias = '', $force = false)
2283 {
2284 global $conf;
2285
2286 $alias = trim($alias);
2287 $alias = !empty($alias) && strpos($alias, '.') < 0 ? $alias . "." : $alias;
2288
2289 if (!isset(self::$can_modify_bookkeeping_sql_cached[$alias]) || $force) {
2290 $result = $this->loadFiscalPeriods($force, 'active');
2291 if ($result < 0) {
2292 return null;
2293 }
2294
2295 $sql_list = array();
2296 if (!empty($conf->cache['active_fiscal_period_cached']) && is_array($conf->cache['active_fiscal_period_cached'])) {
2297 foreach ($conf->cache['active_fiscal_period_cached'] as $fiscal_period) {
2298 $sql_list[] = "('" . $this->db->idate($fiscal_period['date_start']) . "' <= {$alias}doc_date AND {$alias}doc_date <= '" . $this->db->idate($fiscal_period['date_end']) . "')";
2299 }
2300 }
2301 self::$can_modify_bookkeeping_sql_cached[$alias] = !empty($sql_list) ? ' AND (' . implode(' OR ', $sql_list) . ')' : '';
2302 }
2303
2304 return self::$can_modify_bookkeeping_sql_cached[$alias];
2305 }
2306
2314 public function canModifyBookkeeping($id, $mode = '')
2315 {
2316 global $conf;
2317
2318 if (getDolGlobalString('ACCOUNTANCY_FISCAL_PERIOD_MODE') == 'blockedonclosed') {
2319 $result = $this->loadFiscalPeriods(false, 'closed');
2320
2321 if ($result < 0) {
2322 return -1;
2323 }
2324
2325 $bookkeeping = new BookKeeping($this->db);
2326 $result = $bookkeeping->fetch($id, null, $mode);
2327 if ($result <= 0) {
2328 return $result;
2329 }
2330
2331 if (!empty($conf->cache['closed_fiscal_period_cached']) && is_array($conf->cache['closed_fiscal_period_cached'])) {
2332 foreach ($conf->cache['closed_fiscal_period_cached'] as $fiscal_period) {
2333 if ($fiscal_period['date_start'] <= $bookkeeping->doc_date && $bookkeeping->doc_date <= $fiscal_period['date_end']) {
2334 return 0;
2335 }
2336 }
2337 }
2338
2339 return 1;
2340 } else {
2341 $result = $this->loadFiscalPeriods(false, 'active');
2342 if ($result < 0) {
2343 return -1;
2344 }
2345
2346 $bookkeeping = new BookKeeping($this->db);
2347 $result = $bookkeeping->fetch($id, null, $mode);
2348 if ($result <= 0) {
2349 return $result;
2350 }
2351
2352 if (!empty($conf->cache['active_fiscal_period_cached']) && is_array($conf->cache['active_fiscal_period_cached'])) {
2353 foreach ($conf->cache['active_fiscal_period_cached'] as $fiscal_period) {
2354 if ($fiscal_period['date_start'] <= $bookkeeping->doc_date && $bookkeeping->doc_date <= $fiscal_period['date_end']) {
2355 return 1;
2356 }
2357 }
2358 }
2359
2360 return 0;
2361 }
2362 }
2363
2370 public function validBookkeepingDate($date)
2371 {
2372 global $conf;
2373
2374 if (getDolGlobalString('ACCOUNTANCY_FISCAL_PERIOD_MODE') == 'blockedonclosed') {
2375 $result = $this->loadFiscalPeriods(false, 'closed');
2376
2377 if ($result < 0) {
2378 return -1;
2379 }
2380
2381 if (!empty($conf->cache['closed_fiscal_period_cached']) && is_array($conf->cache['closed_fiscal_period_cached'])) {
2382 foreach ($conf->cache['closed_fiscal_period_cached'] as $fiscal_period) {
2383 if ($fiscal_period['date_start'] <= $date && $date <= $fiscal_period['date_end']) {
2384 return 0;
2385 }
2386 }
2387 }
2388
2389 return 1;
2390 } else {
2391 $result = $this->loadFiscalPeriods(false, 'active');
2392 if ($result < 0) {
2393 return -1;
2394 }
2395
2396 if (!empty($conf->cache['active_fiscal_period_cached']) && is_array($conf->cache['active_fiscal_period_cached'])) {
2397 foreach ($conf->cache['active_fiscal_period_cached'] as $fiscal_period) {
2398 if ($fiscal_period['date_start'] <= $date && $date <= $fiscal_period['date_end']) {
2399 return 1;
2400 }
2401 }
2402 }
2403
2404 return 0;
2405 }
2406 }
2407
2415 public function loadFiscalPeriods($force = false, $mode = 'active')
2416 {
2417 global $conf;
2418
2419 if ($mode == 'active') {
2420 if (!isset($conf->cache['active_fiscal_period_cached']) || $force) {
2421 $sql = "SELECT date_start, date_end";
2422 $sql .= " FROM " . $this->db->prefix() . "accounting_fiscalyear";
2423 $sql .= " WHERE entity = " . ((int) $conf->entity);
2424 $sql .= " AND statut = 0";
2425
2426 $resql = $this->db->query($sql);
2427 if (!$resql) {
2428 $this->errors[] = $this->db->lasterror();
2429 return -1;
2430 }
2431
2432 $list = array();
2433 while ($obj = $this->db->fetch_object($resql)) {
2434 $list[] = array(
2435 'date_start' => $this->db->jdate($obj->date_start),
2436 'date_end' => $this->db->jdate($obj->date_end),
2437 );
2438 }
2439 $conf->cache['active_fiscal_period_cached'] = $list;
2440 }
2441 }
2442 if ($mode == 'closed') {
2443 if (!isset($conf->cache['closed_fiscal_period_cached']) || $force) {
2444 $sql = "SELECT date_start, date_end";
2445 $sql .= " FROM " . $this->db->prefix() . "accounting_fiscalyear";
2446 $sql .= " WHERE entity = " . ((int) $conf->entity);
2447 $sql .= " AND statut = 1";
2448
2449 $resql = $this->db->query($sql);
2450 if (!$resql) {
2451 $this->errors[] = $this->db->lasterror();
2452 return -1;
2453 }
2454
2455 $list = array();
2456 while ($obj = $this->db->fetch_object($resql)) {
2457 $list[] = array(
2458 'date_start' => $this->db->jdate($obj->date_start),
2459 'date_end' => $this->db->jdate($obj->date_end),
2460 );
2461 }
2462 $conf->cache['closed_fiscal_period_cached'] = $list;
2463 }
2464 }
2465
2466 return 1;
2467 }
2468
2475 public function getFiscalPeriods($filter = '')
2476 {
2477 global $conf;
2478 $list = array();
2479
2480 $sql = "SELECT rowid, label, date_start, date_end, statut";
2481 $sql .= " FROM " . $this->db->prefix() . "accounting_fiscalyear";
2482 $sql .= " WHERE entity = " . ((int) $conf->entity);
2483 if (!empty($filter)) {
2484 $sql .= " AND (" . $filter . ')';
2485 }
2486 $sql .= $this->db->order('date_start', 'ASC');
2487
2488 $resql = $this->db->query($sql);
2489 if (!$resql) {
2490 $this->errors[] = $this->db->lasterror();
2491 return -1;
2492 }
2493
2494 while ($obj = $this->db->fetch_object($resql)) {
2495 $list[$obj->rowid] = array(
2496 'id' => $obj->rowid,
2497 'label' => $obj->label,
2498 'date_start' => $this->db->jdate($obj->date_start),
2499 'date_end' => $this->db->jdate($obj->date_end),
2500 'status' => $obj->statut,
2501 );
2502 }
2503
2504 return $list;
2505 }
2506
2514 public function getCountByMonthForFiscalPeriod($date_start, $date_end)
2515 {
2516 $total = 0;
2517 $list = array();
2518
2519 $sql = "SELECT YEAR(b.doc_date) as year";
2520 for ($i = 1; $i <= 12; $i++) {
2521 $sql .= ", SUM(" . $this->db->ifsql("MONTH(b.doc_date)=" . $i, "1", "0") . ") AS month" . $i;
2522 }
2523 $sql .= ", COUNT(b.rowid) as total";
2524 $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping as b";
2525 $sql .= " WHERE b.doc_date >= '" . $this->db->idate($date_start) . "'";
2526 $sql .= " AND b.doc_date <= '" . $this->db->idate($date_end) . "'";
2527 $sql .= " AND b.entity IN (" . getEntity('bookkeeping', 0) . ")"; // We don't share object for accountancy
2528
2529 // Get count for each month into the fiscal period
2530 if (getDolGlobalString("ACCOUNTANCY_DISABLE_CLOSURE_LINE_BY_LINE")) {
2531 // TODO Analyse is done by finding record not into a closed period
2532 // Loop on each closed period
2533 $sql .= " AND b.doc_date BETWEEN 0 AND 0";
2534 } else {
2535 // Analyse closed record using the unitary flag/date on each record
2536 $sql .= " AND date_validated IS NULL";
2537 }
2538
2539 $sql .= " GROUP BY YEAR(b.doc_date)";
2540 $sql .= $this->db->order("year", 'ASC');
2541
2542 dol_syslog(__METHOD__, LOG_DEBUG);
2543 $resql = $this->db->query($sql);
2544 if (!$resql) {
2545 $this->errors[] = $this->db->lasterror();
2546 return -1;
2547 }
2548
2549 while ($obj = $this->db->fetch_object($resql)) {
2550 $total += (int) $obj->total;
2551 $year_list = array(
2552 'year' => (int) $obj->year,
2553 'count' => array(),
2554 'total' => (int) $obj->total,
2555 );
2556 for ($i = 1; $i <= 12; $i++) {
2557 $year_list['count'][$i] = (int) $obj->{'month' . $i};
2558 }
2559
2560 $list[] = $year_list;
2561 }
2562
2563 $this->db->free($resql);
2564
2565 return array(
2566 'total' => $total,
2567 'list' => $list,
2568 );
2569 }
2570
2578 public function validateMovementForFiscalPeriod($date_start, $date_end)
2579 {
2580 global $conf;
2581
2582 $now = dol_now();
2583
2584 // Specify as export : update field date_validated on selected month/year
2585 $sql = " UPDATE " . MAIN_DB_PREFIX . "accounting_bookkeeping";
2586 $sql .= " SET date_validated = '" . $this->db->idate($now) . "'";
2587 $sql .= " WHERE entity = " . ((int) $conf->entity);
2588 $sql .= " AND DATE(doc_date) >= '" . $this->db->idate($date_start) . "'";
2589 $sql .= " AND DATE(doc_date) <= '" . $this->db->idate($date_end) . "'";
2590 $sql .= " AND date_validated IS NULL";
2591
2592 dol_syslog(__METHOD__, LOG_DEBUG);
2593 $resql = $this->db->query($sql);
2594 if (!$resql) {
2595 $this->errors[] = $this->db->lasterror();
2596 return -1;
2597 }
2598
2599 return 1;
2600 }
2601
2611 public function closeFiscalPeriod($fiscal_period_id, $new_fiscal_period_id, $separate_auxiliary_account = false, $generate_bookkeeping_records = true)
2612 {
2613 global $conf, $langs, $user;
2614
2615 // Current fiscal period
2616 $fiscal_period_id = max(0, $fiscal_period_id);
2617 if (empty($fiscal_period_id)) {
2618 $langs->load('errors');
2619 $this->errors[] = $langs->trans('ErrorBadParameters');
2620 return -1;
2621 }
2622 $fiscal_period = new Fiscalyear($this->db);
2623 $result = $fiscal_period->fetch($fiscal_period_id);
2624 if ($result < 0) {
2625 $this->error = $fiscal_period->error;
2626 $this->errors = $fiscal_period->errors;
2627 return -1;
2628 } elseif (empty($fiscal_period->id)) {
2629 $langs->loadLangs(array('errors', 'compta'));
2630 $this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('FiscalPeriod') . ' (' . $fiscal_period_id . ')';
2631 return -1;
2632 }
2633
2634 // New fiscal period
2635 $new_fiscal_period_id = max(0, $new_fiscal_period_id);
2636 if (empty($new_fiscal_period_id)) {
2637 $langs->load('errors');
2638 $this->errors[] = $langs->trans('ErrorBadParameters');
2639 return -1;
2640 }
2641 $new_fiscal_period = new Fiscalyear($this->db);
2642 $result = $new_fiscal_period->fetch($new_fiscal_period_id);
2643 if ($result < 0) {
2644 $this->error = $new_fiscal_period->error;
2645 $this->errors = $new_fiscal_period->errors;
2646 return -1;
2647 } elseif (empty($new_fiscal_period->id)) {
2648 $langs->loadLangs(array('errors', 'compta'));
2649 $this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('FiscalPeriod') . ' (' . $new_fiscal_period_id . ')';
2650 return -1;
2651 }
2652
2653 $error = 0;
2654 $this->db->begin();
2655
2656 $fiscal_period->statut = Fiscalyear::STATUS_CLOSED;
2657 $fiscal_period->status = Fiscalyear::STATUS_CLOSED; // Actually not used
2658 $result = $fiscal_period->update($user);
2659 if ($result < 0) {
2660 $this->error = $fiscal_period->error;
2661 $this->errors = $fiscal_period->errors;
2662 $error++;
2663 }
2664
2665 if (!$error && !empty($generate_bookkeeping_records)) {
2666 $journal_id = max(0, getDolGlobalString('ACCOUNTING_CLOSURE_DEFAULT_JOURNAL'));
2667 if (empty($journal_id)) {
2668 $langs->loadLangs(array('errors', 'accountancy'));
2669 $this->errors[] = $langs->trans('ErrorBadParameters') . ' - ' . $langs->trans('Codejournal') . ' (' . $langs->trans('AccountingJournalType9') . ')';
2670 $error++;
2671 }
2672
2673 // Fetch journal
2674 if (!$error) {
2675 $journal = new AccountingJournal($this->db);
2676 $result = $journal->fetch($journal_id);
2677 if ($result < 0) {
2678 $this->error = $journal->error;
2679 $this->errors = $journal->errors;
2680 $error++;
2681 } elseif ($result == 0) {
2682 $langs->loadLangs(array('errors', 'accountancy'));
2683 $this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('Codejournal') . ' (' . $langs->trans('AccountingJournalType9') . ')';
2684 $error++;
2685 }
2686 }
2687
2688 if (!$error) {
2689 $accounting_groups_used_for_balance_sheet_account = array_filter(array_map('trim', explode(',', getDolGlobalString('ACCOUNTING_CLOSURE_ACCOUNTING_GROUPS_USED_FOR_BALANCE_SHEET_ACCOUNT'))), 'strlen');
2690 $accounting_groups_used_for_income_statement = array_filter(array_map('trim', explode(',', getDolGlobalString('ACCOUNTING_CLOSURE_ACCOUNTING_GROUPS_USED_FOR_INCOME_STATEMENT'))), 'strlen');
2691
2692 $pcg_type_filter = array();
2693 $tmp = array_merge($accounting_groups_used_for_balance_sheet_account, $accounting_groups_used_for_income_statement);
2694 foreach ($tmp as $item) {
2695 $pcg_type_filter[] = "'" . $this->db->escape($item) . "'";
2696 }
2697
2698 $sql = 'SELECT';
2699 $sql .= " t.numero_compte,";
2700 if ($separate_auxiliary_account) {
2701 $sql .= " NULLIF(t.subledger_account, '') as subledger_account,"; // fix db issues with Null or "" values
2702 }
2703 $sql .= " aa.pcg_type,";
2704 $sql .= " (SUM(t.credit) - SUM(t.debit)) as opening_balance";
2705 $sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . ' as t';
2706 $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'accounting_account as aa ON aa.account_number = t.numero_compte';
2707 $sql .= ' WHERE t.entity = ' . ((int) $conf->entity); // Do not use getEntity for accounting features
2708 $sql .= " AND aa.entity = ". ((int) $conf->entity);
2709 $sql .= ' AND aa.fk_pcg_version IN (SELECT pcg_version FROM '.MAIN_DB_PREFIX.'accounting_system WHERE rowid = '.((int) getDolGlobalInt('CHARTOFACCOUNTS')).')';
2710 $sql .= ' AND aa.pcg_type IN (' . $this->db->sanitize(implode(',', $pcg_type_filter), 1) . ')';
2711 $sql .= " AND DATE(t.doc_date) >= '" . $this->db->idate($fiscal_period->date_start) . "'";
2712 $sql .= " AND DATE(t.doc_date) <= '" . $this->db->idate($fiscal_period->date_end) . "'";
2713 $sql .= ' GROUP BY t.numero_compte, aa.pcg_type';
2714 if ($separate_auxiliary_account) {
2715 $sql .= " , NULLIF(t.subledger_account, '')";
2716 }
2717 $sql .= ' HAVING (SUM(t.credit) - SUM(t.debit)) != 0 '; // Exclude rows with opening_balance = 0
2718 $sql .= $this->db->order("t.numero_compte", "ASC");
2719
2720 $resql = $this->db->query($sql);
2721 if (!$resql) {
2722 $this->errors[] = 'Error ' . $this->db->lasterror();
2723 dol_syslog(__METHOD__ . ' ' . join(',', $this->errors), LOG_ERR);
2724
2725 $error++;
2726 } else {
2727 $now = dol_now();
2728 $income_statement_amount = 0;
2729 while ($obj = $this->db->fetch_object($resql)) {
2730 if (in_array($obj->pcg_type, $accounting_groups_used_for_income_statement)) {
2731 $income_statement_amount += $obj->opening_balance;
2732 } else {
2733 // Insert bookkeeping record for balance sheet account
2734 $mt = $obj->opening_balance;
2735
2736 $bookkeeping = new BookKeeping($this->db);
2737 $bookkeeping->doc_date = $new_fiscal_period->date_start;
2738 $bookkeeping->date_lim_reglement = '';
2739 $bookkeeping->doc_ref = $fiscal_period->label;
2740 $bookkeeping->date_creation = $now;
2741 $bookkeeping->doc_type = 'closure';
2742 $bookkeeping->fk_doc = $fiscal_period->id;
2743 $bookkeeping->fk_docdet = 0; // Useless, can be several lines that are source of this record to add
2744 $bookkeeping->thirdparty_code = '';
2745
2746 if ($separate_auxiliary_account) {
2747 $bookkeeping->subledger_account = $obj->subledger_account;
2748 $sql = 'SELECT';
2749 $sql .= " subledger_label";
2750 $sql .= " FROM " . MAIN_DB_PREFIX . $this->table_element;
2751 $sql .= " WHERE subledger_account = '" . $this->db->escape($obj->subledger_account) . "'";
2752 $sql .= " ORDER BY doc_date DESC";
2753 $sql .= " LIMIT 1";
2754 $result = $this->db->query($sql);
2755 if (!$result) {
2756 $this->errors[] = 'Error: ' . $this->db->lasterror();
2757 dol_syslog(__METHOD__ . ' ' . join(',', $this->errors), LOG_ERR);
2758 $error++;
2759 }
2760 $objtmp = $this->db->fetch_object($result);
2761 $bookkeeping->subledger_label = $objtmp->subledger_label; // latest subledger label used
2762 } else {
2763 $bookkeeping->subledger_account = null;
2764 $bookkeeping->subledger_label = null;
2765 }
2766
2767 $bookkeeping->numero_compte = $obj->numero_compte;
2768 $accountingaccount = new AccountingAccount($this->db);
2769 $accountingaccount->fetch('', $obj->numero_compte);
2770 $bookkeeping->label_compte = $accountingaccount->label; // latest account label used
2771
2772 $bookkeeping->label_operation = $new_fiscal_period->label;
2773 $bookkeeping->montant = $mt;
2774 $bookkeeping->sens = ($mt >= 0) ? 'C' : 'D';
2775 $bookkeeping->debit = ($mt < 0) ? -$mt : 0;
2776 $bookkeeping->credit = ($mt >= 0) ? $mt : 0;
2777 $bookkeeping->code_journal = $journal->code;
2778 $bookkeeping->journal_label = $langs->transnoentities($journal->label);
2779 $bookkeeping->fk_user_author = $user->id;
2780 $bookkeeping->entity = $conf->entity;
2781
2782 $result = $bookkeeping->create($user);
2783 if ($result < 0) {
2784 $this->error = $bookkeeping->error;
2785 $this->errors = $bookkeeping->errors;
2786 $error++;
2787 break;
2788 }
2789 }
2790 }
2791
2792 // Insert bookkeeping record for income statement
2793 if (!$error && $income_statement_amount != 0) {
2794 $mt = $income_statement_amount;
2795 $accountingaccount = new AccountingAccount($this->db);
2796 $accountingaccount->fetch(null, getDolGlobalString($income_statement_amount < 0 ? 'ACCOUNTING_RESULT_LOSS' : 'ACCOUNTING_RESULT_PROFIT'), true);
2797
2798 $bookkeeping = new BookKeeping($this->db);
2799 $bookkeeping->doc_date = $new_fiscal_period->date_start;
2800 $bookkeeping->date_lim_reglement = '';
2801 $bookkeeping->doc_ref = $fiscal_period->label;
2802 $bookkeeping->date_creation = $now;
2803 $bookkeeping->doc_type = 'closure';
2804 $bookkeeping->fk_doc = $fiscal_period->id;
2805 $bookkeeping->fk_docdet = 0; // Useless, can be several lines that are source of this record to add
2806 $bookkeeping->thirdparty_code = '';
2807
2808 if ($separate_auxiliary_account) {
2809 $bookkeeping->subledger_account = $obj->subledger_account;
2810 $sql = 'SELECT';
2811 $sql .= " subledger_label";
2812 $sql .= " FROM " . MAIN_DB_PREFIX . $this->table_element;
2813 $sql .= " WHERE subledger_account = '" . $this->db->escape($obj->subledger_account) . "'";
2814 $sql .= " ORDER BY doc_date DESC";
2815 $sql .= " LIMIT 1";
2816 $result = $this->db->query($sql);
2817 if (!$result) {
2818 $this->errors[] = 'Error: ' . $this->db->lasterror();
2819 dol_syslog(__METHOD__ . ' ' . join(',', $this->errors), LOG_ERR);
2820 $error++;
2821 }
2822 $objtmp = $this->db->fetch_object($result);
2823 $bookkeeping->subledger_label = $objtmp->subledger_label; // latest subledger label used
2824 } else {
2825 $bookkeeping->subledger_account = null;
2826 $bookkeeping->subledger_label = null;
2827 }
2828
2829 $bookkeeping->numero_compte = $accountingaccount->account_number;
2830 $bookkeeping->label_compte = $accountingaccount->label;
2831
2832 $bookkeeping->label_operation = $new_fiscal_period->label;
2833 $bookkeeping->montant = $mt;
2834 $bookkeeping->sens = ($mt >= 0) ? 'C' : 'D';
2835 $bookkeeping->debit = ($mt < 0) ? -$mt : 0;
2836 $bookkeeping->credit = ($mt >= 0) ? $mt : 0;
2837 $bookkeeping->code_journal = $journal->code;
2838 $bookkeeping->journal_label = $langs->transnoentities($journal->label);
2839 $bookkeeping->fk_user_author = $user->id;
2840 $bookkeeping->entity = $conf->entity;
2841
2842 $result = $bookkeeping->create($user);
2843 if ($result < 0) {
2844 $this->error = $bookkeeping->error;
2845 $this->errors = $bookkeeping->errors;
2846 $error++;
2847 }
2848 }
2849 $this->db->free($resql);
2850 }
2851 }
2852 }
2853
2854 if ($error) {
2855 $this->db->rollback();
2856 return -1;
2857 } else {
2858 $this->db->commit();
2859 return 1;
2860 }
2861 }
2862
2873 public function insertAccountingReversal($fiscal_period_id, $inventory_journal_id, $new_fiscal_period_id, $date_start, $date_end)
2874 {
2875 global $conf, $langs, $user;
2876
2877 // Current fiscal period
2878 $fiscal_period_id = max(0, $fiscal_period_id);
2879 if (empty($fiscal_period_id)) {
2880 $langs->load('errors');
2881 $this->errors[] = $langs->trans('ErrorBadParameters');
2882 return -1;
2883 }
2884 $fiscal_period = new Fiscalyear($this->db);
2885 $result = $fiscal_period->fetch($fiscal_period_id);
2886 if ($result < 0) {
2887 $this->error = $fiscal_period->error;
2888 $this->errors = $fiscal_period->errors;
2889 return -1;
2890 } elseif (empty($fiscal_period->id)) {
2891 $langs->loadLangs(array('errors', 'compta'));
2892 $this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('FiscalPeriod') . ' (' . $fiscal_period_id . ')';
2893 return -1;
2894 }
2895
2896 // New fiscal period
2897 $new_fiscal_period_id = max(0, $new_fiscal_period_id);
2898 if (empty($new_fiscal_period_id)) {
2899 $langs->load('errors');
2900 $this->errors[] = $langs->trans('ErrorBadParameters');
2901 return -1;
2902 }
2903 $new_fiscal_period = new Fiscalyear($this->db);
2904 $result = $new_fiscal_period->fetch($new_fiscal_period_id);
2905 if ($result < 0) {
2906 $this->error = $new_fiscal_period->error;
2907 $this->errors = $new_fiscal_period->errors;
2908 return -1;
2909 } elseif (empty($new_fiscal_period->id)) {
2910 $langs->loadLangs(array('errors', 'compta'));
2911 $this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('FiscalPeriod') . ' (' . $new_fiscal_period_id . ')';
2912 return -1;
2913 }
2914
2915 // Inventory journal
2916 $inventory_journal_id = max(0, $inventory_journal_id);
2917 if (empty($inventory_journal_id)) {
2918 $langs->load('errors');
2919 $this->errors[] = $langs->trans('ErrorBadParameters');
2920 return -1;
2921 }
2922 // Fetch journal
2923 $inventory_journal = new AccountingJournal($this->db);
2924 $result = $inventory_journal->fetch($inventory_journal_id);
2925 if ($result < 0) {
2926 $this->error = $inventory_journal->error;
2927 $this->errors = $inventory_journal->errors;
2928 return -1;
2929 } elseif ($result == 0) {
2930 $langs->loadLangs(array('errors', 'accountancy'));
2931 $this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('InventoryJournal');
2932 return -1;
2933 }
2934
2935 $error = 0;
2936 $this->db->begin();
2937
2938 $sql = 'SELECT t.rowid';
2939 $sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . ' as t';
2940 $sql .= ' WHERE t.entity = ' . ((int) $conf->entity); // Do not use getEntity for accounting features
2941 $sql .= " AND code_journal = '" . $this->db->escape($inventory_journal->code) . "'";
2942 $sql .= " AND DATE(t.doc_date) >= '" . $this->db->idate($date_start) . "'";
2943 $sql .= " AND DATE(t.doc_date) <= '" . $this->db->idate($date_end) . "'";
2944 $sql .= " AND DATE(t.doc_date) >= '" . $this->db->idate($fiscal_period->date_start) . "'";
2945 $sql .= " AND DATE(t.doc_date) <= '" . $this->db->idate($fiscal_period->date_end) . "'";
2946
2947 $resql = $this->db->query($sql);
2948 if (!$resql) {
2949 $this->errors[] = 'Error ' . $this->db->lasterror();
2950 dol_syslog(__METHOD__ . ' ' . join(',', $this->errors), LOG_ERR);
2951
2952 $error++;
2953 } else {
2954 $now = dol_now();
2955 while ($obj = $this->db->fetch_object($resql)) {
2956 $bookkeeping = new BookKeeping($this->db);
2957 $result = $bookkeeping->fetch($obj->rowid);
2958 if ($result < 0) {
2959 $this->error = $inventory_journal->error;
2960 $this->errors = $inventory_journal->errors;
2961 $error++;
2962 break;
2963 } elseif ($result == 0) {
2964 $langs->loadLangs(array('errors', 'accountancy'));
2965 $this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('LineId') . ': ' . $obj->rowid;
2966 $error++;
2967 break;
2968 }
2969
2970 $bookkeeping->id = 0;
2971 $bookkeeping->doc_date = $new_fiscal_period->date_start;
2972 $bookkeeping->doc_ref = $new_fiscal_period->label;
2973 $bookkeeping->date_creation = $now;
2974 $bookkeeping->doc_type = 'accounting_reversal';
2975 $bookkeeping->fk_doc = $new_fiscal_period->id;
2976 $bookkeeping->fk_docdet = 0; // Useless, can be several lines that are source of this record to add
2977
2978 $bookkeeping->montant = -$bookkeeping->montant;
2979 $bookkeeping->sens = ($bookkeeping->montant >= 0) ? 'C' : 'D';
2980 $old_debit = $bookkeeping->debit;
2981 $bookkeeping->debit = $bookkeeping->credit;
2982 $bookkeeping->credit = $old_debit;
2983
2984 $bookkeeping->fk_user_author = $user->id;
2985 $bookkeeping->entity = $conf->entity;
2986
2987 $result = $bookkeeping->create($user);
2988 if ($result < 0) {
2989 $this->error = $bookkeeping->error;
2990 $this->errors = $bookkeeping->errors;
2991 $error++;
2992 break;
2993 }
2994 }
2995 $this->db->free($resql);
2996 }
2997
2998 if ($error) {
2999 $this->db->rollback();
3000 return -1;
3001 } else {
3002 $this->db->commit();
3003 return 1;
3004 }
3005 }
3006}
3007
3012{
3016 public $id;
3017
3018 public $doc_date = '';
3019 public $doc_type;
3020 public $doc_ref;
3021
3025 public $fk_doc;
3026
3030 public $fk_docdet;
3031
3032 public $thirdparty_code;
3033 public $subledger_account;
3034 public $subledger_label;
3035 public $numero_compte;
3036 public $label_compte;
3037 public $label_operation;
3038 public $debit;
3039 public $credit;
3040
3045 public $montant;
3046
3050 public $amount;
3051
3055 public $multicurrency_amount;
3056
3060 public $multicurrency_code;
3061
3065 public $sens;
3066 public $lettering_code;
3067 public $date_lettering;
3068
3072 public $fk_user_author;
3073
3074 public $import_key;
3075 public $code_journal;
3076 public $journal_label;
3077 public $piece_num;
3078
3082 public $date_creation;
3083
3087 public $date_modification;
3088
3092 public $date_export;
3093
3097 public $date_validation;
3098
3102 public $date_lim_reglement;
3103}
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.