dolibarr 20.0.0
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-2024 Frédéric France <frederic.france@free.fr>
6 * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.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 = 0)
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 = (int) $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' 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 $sql .= " AND entity = ".$conf->entity; // Do not use getEntity for accounting features
347
348 $resql = $this->db->query($sql);
349
350 if ($resql) {
351 $row = $this->db->fetch_object($resql);
352 if ($row->nb == 0) { // Not already into bookkeeping
353 // Check to know if piece_num already exists for data we try to insert to reuse the same value
354 $sqlnum = "SELECT piece_num";
355 $sqlnum .= " FROM ".MAIN_DB_PREFIX.$this->table_element;
356 $sqlnum .= " WHERE doc_type = '".$this->db->escape($this->doc_type)."'"; // For example doc_type = 'bank'
357 $sqlnum .= " AND fk_doc = ".((int) $this->fk_doc);
358 if (getDolGlobalString('ACCOUNTANCY_ENABLE_FKDOCDET')) {
359 // fk_docdet is rowid into llx_bank or llx_facturedet or llx_facturefourndet, or ...
360 $sqlnum .= " AND fk_docdet = ".((int) $this->fk_docdet);
361 }
362 $sqlnum .= " AND doc_ref = '".$this->db->escape($this->doc_ref)."'"; // ref of source object
363 $sqlnum .= " AND entity = ".$conf->entity; // Do not use getEntity for accounting features
364
365 dol_syslog(get_class($this).":: create sqlnum=".$sqlnum, LOG_DEBUG);
366 $resqlnum = $this->db->query($sqlnum);
367 if ($resqlnum) {
368 $objnum = $this->db->fetch_object($resqlnum);
369 $this->piece_num = $objnum->piece_num;
370 }
371
372 dol_syslog(get_class($this)."::create this->piece_num=".$this->piece_num, LOG_DEBUG);
373 if (empty($this->piece_num)) {
374 $sqlnum = "SELECT MAX(piece_num)+1 as maxpiecenum";
375 $sqlnum .= " FROM ".MAIN_DB_PREFIX.$this->table_element;
376 $sqlnum .= " WHERE entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
377
378 $resqlnum = $this->db->query($sqlnum);
379 if ($resqlnum) {
380 $objnum = $this->db->fetch_object($resqlnum);
381 $this->piece_num = $objnum->maxpiecenum;
382 }
383 dol_syslog(get_class($this).":: create now this->piece_num=".$this->piece_num, LOG_DEBUG);
384 }
385 if (empty($this->piece_num)) {
386 $this->piece_num = 1;
387 }
388
389 $now = dol_now();
390
391 $sql = "INSERT INTO ".MAIN_DB_PREFIX.$this->table_element." (";
392 $sql .= "doc_date";
393 $sql .= ", date_lim_reglement";
394 $sql .= ", doc_type";
395 $sql .= ", doc_ref";
396 $sql .= ", fk_doc";
397 $sql .= ", fk_docdet";
398 $sql .= ", thirdparty_code";
399 $sql .= ", subledger_account";
400 $sql .= ", subledger_label";
401 $sql .= ", numero_compte";
402 $sql .= ", label_compte";
403 $sql .= ", label_operation";
404 $sql .= ", debit";
405 $sql .= ", credit";
406 $sql .= ", montant";
407 $sql .= ", sens";
408 $sql .= ", fk_user_author";
409 $sql .= ", date_creation";
410 $sql .= ", code_journal";
411 $sql .= ", journal_label";
412 $sql .= ", piece_num";
413 $sql .= ', entity';
414 $sql .= ") VALUES (";
415 $sql .= "'".$this->db->idate($this->doc_date)."'";
416 $sql .= ", ".(!isset($this->date_lim_reglement) || dol_strlen($this->date_lim_reglement) == 0 ? 'NULL' : "'".$this->db->idate($this->date_lim_reglement)."'");
417 $sql .= ", '".$this->db->escape($this->doc_type)."'";
418 $sql .= ", '".$this->db->escape($this->doc_ref)."'";
419 $sql .= ", ".((int) $this->fk_doc);
420 $sql .= ", ".((int) $this->fk_docdet);
421 $sql .= ", ".(!empty($this->thirdparty_code) ? ("'".$this->db->escape($this->thirdparty_code)."'") : "NULL");
422 $sql .= ", ".(!empty($this->subledger_account) ? ("'".$this->db->escape($this->subledger_account)."'") : "NULL");
423 $sql .= ", ".(!empty($this->subledger_label) ? ("'".$this->db->escape($this->subledger_label)."'") : "NULL");
424 $sql .= ", '".$this->db->escape($this->numero_compte)."'";
425 $sql .= ", ".(!empty($this->label_compte) ? ("'".$this->db->escape($this->label_compte)."'") : "NULL");
426 $sql .= ", '".$this->db->escape($this->label_operation)."'";
427 $sql .= ", ".((float) $this->debit);
428 $sql .= ", ".((float) $this->credit);
429 $sql .= ", ".((float) $this->montant);
430 $sql .= ", ".(!empty($this->sens) ? ("'".$this->db->escape($this->sens)."'") : "NULL");
431 $sql .= ", '".$this->db->escape($this->fk_user_author)."'";
432 $sql .= ", '".$this->db->idate($now)."'";
433 $sql .= ", '".$this->db->escape($this->code_journal)."'";
434 $sql .= ", ".(!empty($this->journal_label) ? ("'".$this->db->escape($this->journal_label)."'") : "NULL");
435 $sql .= ", ".((int) $this->piece_num);
436 $sql .= ", ".(!isset($this->entity) ? $conf->entity : $this->entity);
437 $sql .= ")";
438
439 $resql = $this->db->query($sql);
440 if ($resql) {
441 $id = $this->db->last_insert_id(MAIN_DB_PREFIX.$this->table_element);
442
443 if ($id > 0) {
444 $this->id = $id;
445 $result = 0;
446 } else {
447 $result = -2;
448 $error++;
449 $this->errors[] = 'Error Create Error '.$result.' lecture ID';
450 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
451 }
452 } else {
453 $result = -1;
454 $error++;
455 $this->errors[] = 'Error '.$this->db->lasterror();
456 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
457 }
458 } else { // Already exists
459 $result = -3;
460 $error++;
461 $this->error = 'BookkeepingRecordAlreadyExists';
462 dol_syslog(__METHOD__.' '.$this->error, LOG_WARNING);
463 }
464 } else {
465 $result = -5;
466 $error++;
467 $this->errors[] = 'Error '.$this->db->lasterror();
468 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
469 }
470
471 // Uncomment this and change MYOBJECT to your own tag if you
472 // want this action to call a trigger.
473 //if (! $error && ! $notrigger) {
474
475 // // Call triggers
476 // $result=$this->call_trigger('MYOBJECT_CREATE',$user);
477 // if ($result < 0) $error++;
478 // // End call triggers
479 //}
480
481 // Commit or rollback
482 if ($error) {
483 $this->db->rollback();
484 return -1 * $error;
485 } else {
486 $this->db->commit();
487 return $result;
488 }
489 }
490
501 public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
502 {
503 global $db, $conf, $langs;
504 global $dolibarr_main_authentication, $dolibarr_main_demo;
505 global $menumanager, $hookmanager;
506
507 if (!empty($conf->dol_no_mouse_hover)) {
508 $notooltip = 1; // Force disable tooltips
509 }
510
511 $result = '';
512 $companylink = '';
513
514 $label = '<u>'.$langs->trans("Transaction").'</u>';
515 $label .= '<br>';
516 $label .= '<b>'.$langs->trans('Ref').':</b> '.$this->piece_num;
517
518 $url = DOL_URL_ROOT.'/accountancy/bookkeeping/card.php?piece_num='.$this->piece_num;
519
520 if ($option != 'nolink') {
521 // Add param to save lastsearch_values or not
522 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
523 if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
524 $add_save_lastsearch_values = 1;
525 }
526 if ($add_save_lastsearch_values) {
527 $url .= '&save_lastsearch_values=1';
528 }
529 }
530
531 $linkclose = '';
532 if (empty($notooltip)) {
533 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
534 $label = $langs->trans("ShowTransaction");
535 $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
536 }
537 $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
538 $linkclose .= ' class="classfortooltip'.($morecss ? ' '.$morecss : '').'"';
539 } else {
540 $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
541 }
542
543 $linkstart = '<a href="'.$url.'"';
544 $linkstart .= $linkclose.'>';
545 $linkend = '</a>';
546
547 $result .= $linkstart;
548 if ($withpicto) {
549 $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);
550 }
551 if ($withpicto != 2) {
552 $result .= $this->piece_num;
553 }
554 $result .= $linkend;
555 //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
556
557 global $action;
558 $hookmanager->initHooks(array($this->element . 'dao'));
559 $parameters = array('id' => $this->id, 'getnomurl' => &$result);
560 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
561 if ($reshook > 0) {
562 $result = $hookmanager->resPrint;
563 } else {
564 $result .= $hookmanager->resPrint;
565 }
566 return $result;
567 }
568
577 public function createStd(User $user, $notrigger = 0, $mode = '')
578 {
579 global $conf, $langs;
580
581 $langs->loadLangs(array("accountancy", "bills", "compta"));
582
583 dol_syslog(__METHOD__, LOG_DEBUG);
584
585 $error = 0;
586
587 // Clean parameters
588 if (isset($this->doc_type)) {
589 $this->doc_type = trim($this->doc_type);
590 }
591 if (isset($this->doc_ref)) {
592 $this->doc_ref = trim($this->doc_ref);
593 }
594 if (isset($this->fk_doc)) {
595 $this->fk_doc = (int) $this->fk_doc;
596 }
597 if (isset($this->fk_docdet)) {
598 $this->fk_docdet = (int) $this->fk_docdet;
599 }
600 if (isset($this->thirdparty_code)) {
601 $this->thirdparty_code = trim($this->thirdparty_code);
602 }
603 if (isset($this->subledger_account)) {
604 $this->subledger_account = trim($this->subledger_account);
605 }
606 if (isset($this->subledger_label)) {
607 $this->subledger_label = trim($this->subledger_label);
608 }
609 if (isset($this->numero_compte)) {
610 $this->numero_compte = trim($this->numero_compte);
611 }
612 if (isset($this->label_compte)) {
613 $this->label_compte = trim($this->label_compte);
614 }
615 if (isset($this->label_operation)) {
616 $this->label_operation = trim($this->label_operation);
617 }
618 if (isset($this->sens)) {
619 $this->sens = trim($this->sens);
620 }
621 if (isset($this->import_key)) {
622 $this->import_key = trim($this->import_key);
623 }
624 if (isset($this->code_journal)) {
625 $this->code_journal = trim($this->code_journal);
626 }
627 if (isset($this->journal_label)) {
628 $this->journal_label = trim($this->journal_label);
629 }
630 if (isset($this->piece_num)) {
631 $this->piece_num = (int) $this->piece_num;
632 }
633 if (empty($this->debit)) {
634 $this->debit = 0;
635 }
636 if (empty($this->credit)) {
637 $this->credit = 0;
638 }
639 if (empty($this->montant)) {
640 $this->montant = 0;
641 }
642
643 $result = $this->validBookkeepingDate($this->doc_date);
644 if ($result < 0) {
645 return -1;
646 } elseif ($result == 0) {
647 if (getDolGlobalString('ACCOUNTANCY_FISCAL_PERIOD_MODE') == 'blockedonclosed') {
648 $this->errors[] = $langs->trans('ErrorBookkeepingDocDateIsOnAClosedFiscalPeriod');
649 } else {
650 $this->errors[] = $langs->trans('ErrorBookkeepingDocDateNotOnActiveFiscalPeriod');
651 }
652 return -1;
653 }
654
655 $this->debit = (float) price2num($this->debit, 'MT');
656 $this->credit = (float) price2num($this->credit, 'MT');
657 $this->montant = (float) price2num($this->montant, 'MT');
658
659 $now = dol_now();
660
661 // Check parameters
662 $this->journal_label = $langs->trans($this->journal_label);
663
664 // Insert request
665 $sql = 'INSERT INTO '.MAIN_DB_PREFIX.$this->table_element.$mode.' (';
666 $sql .= 'doc_date,';
667 $sql .= 'date_lim_reglement,';
668 $sql .= 'doc_type,';
669 $sql .= 'doc_ref,';
670 $sql .= 'fk_doc,';
671 $sql .= 'fk_docdet,';
672 $sql .= 'thirdparty_code,';
673 $sql .= 'subledger_account,';
674 $sql .= 'subledger_label,';
675 $sql .= 'numero_compte,';
676 $sql .= 'label_compte,';
677 $sql .= 'label_operation,';
678 $sql .= 'debit,';
679 $sql .= 'credit,';
680 $sql .= 'montant,';
681 $sql .= 'sens,';
682 $sql .= 'fk_user_author,';
683 $sql .= 'date_creation,';
684 $sql .= 'code_journal,';
685 $sql .= 'journal_label,';
686 $sql .= 'piece_num,';
687 $sql .= 'entity';
688 $sql .= ') VALUES (';
689 $sql .= ' '.(!isset($this->doc_date) || dol_strlen($this->doc_date) == 0 ? 'NULL' : "'".$this->db->idate($this->doc_date)."'").',';
690 $sql .= ' '.(!isset($this->date_lim_reglement) || dol_strlen($this->date_lim_reglement) == 0 ? 'NULL' : "'".$this->db->idate($this->date_lim_reglement)."'").',';
691 $sql .= ' '.(!isset($this->doc_type) ? 'NULL' : "'".$this->db->escape($this->doc_type)."'").',';
692 $sql .= ' '.(!isset($this->doc_ref) ? 'NULL' : "'".$this->db->escape($this->doc_ref)."'").',';
693 $sql .= ' '.(empty($this->fk_doc) ? '0' : (int) $this->fk_doc).',';
694 $sql .= ' '.(empty($this->fk_docdet) ? '0' : (int) $this->fk_docdet).',';
695 $sql .= ' '.(!isset($this->thirdparty_code) ? 'NULL' : "'".$this->db->escape($this->thirdparty_code)."'").',';
696 $sql .= ' '.(!isset($this->subledger_account) ? 'NULL' : "'".$this->db->escape($this->subledger_account)."'").',';
697 $sql .= ' '.(!isset($this->subledger_label) ? 'NULL' : "'".$this->db->escape($this->subledger_label)."'").',';
698 $sql .= ' '.(!isset($this->numero_compte) ? 'NULL' : "'".$this->db->escape($this->numero_compte)."'").',';
699 $sql .= ' '.(!isset($this->label_compte) ? 'NULL' : "'".$this->db->escape($this->label_compte)."'").',';
700 $sql .= ' '.(!isset($this->label_operation) ? 'NULL' : "'".$this->db->escape($this->label_operation)."'").',';
701 $sql .= ' '.(!isset($this->debit) ? 'NULL' : $this->debit).',';
702 $sql .= ' '.(!isset($this->credit) ? 'NULL' : $this->credit).',';
703 $sql .= ' '.(!isset($this->montant) ? 'NULL' : $this->montant).',';
704 $sql .= ' '.(!isset($this->sens) ? 'NULL' : "'".$this->db->escape($this->sens)."'").',';
705 $sql .= ' '.((int) $user->id).',';
706 $sql .= ' '."'".$this->db->idate($now)."',";
707 $sql .= ' '.(empty($this->code_journal) ? 'NULL' : "'".$this->db->escape($this->code_journal)."'").',';
708 $sql .= ' '.(empty($this->journal_label) ? 'NULL' : "'".$this->db->escape($this->journal_label)."'").',';
709 $sql .= ' '.(empty($this->piece_num) ? 'NULL' : $this->db->escape($this->piece_num)).',';
710 $sql .= ' '.(!isset($this->entity) ? $conf->entity : $this->entity);
711 $sql .= ')';
712
713 $this->db->begin();
714
715 $resql = $this->db->query($sql);
716 if (!$resql) {
717 $error++;
718 $this->errors[] = 'Error '.$this->db->lasterror();
719 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
720 }
721
722 if (!$error) {
723 $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.$this->table_element.$mode);
724 }
725
726 // Commit or rollback
727 if ($error) {
728 $this->db->rollback();
729
730 return -1 * $error;
731 } else {
732 $this->db->commit();
733
734 return $this->id;
735 }
736 }
737
746 public function fetch($id, $ref = null, $mode = '')
747 {
748 global $conf;
749
750 dol_syslog(__METHOD__, LOG_DEBUG);
751
752 $sql = 'SELECT';
753 $sql .= ' t.rowid,';
754 $sql .= " t.doc_date,";
755 $sql .= " t.date_lim_reglement,";
756 $sql .= " t.doc_type,";
757 $sql .= " t.doc_ref,";
758 $sql .= " t.fk_doc,";
759 $sql .= " t.fk_docdet,";
760 $sql .= " t.thirdparty_code,";
761 $sql .= " t.subledger_account,";
762 $sql .= " t.subledger_label,";
763 $sql .= " t.numero_compte,";
764 $sql .= " t.label_compte,";
765 $sql .= " t.label_operation,";
766 $sql .= " t.debit,";
767 $sql .= " t.credit,";
768 $sql .= " t.montant as amount,";
769 $sql .= " t.sens,";
770 $sql .= " t.fk_user_author,";
771 $sql .= " t.import_key,";
772 $sql .= " t.code_journal,";
773 $sql .= " t.journal_label,";
774 $sql .= " t.piece_num,";
775 $sql .= " t.date_creation,";
776 // In llx_accounting_bookkeeping_tmp, field date_export doesn't exist
777 if ($mode != "_tmp") {
778 $sql .= " t.date_export,";
779 }
780 $sql .= " t.date_validated as date_validation";
781 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.$mode.' as t';
782 $sql .= ' WHERE 1 = 1';
783 $sql .= " AND entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
784 if (null !== $ref) {
785 $sql .= " AND t.rowid = ".((int) $ref);
786 } else {
787 $sql .= " AND t.rowid = ".((int) $id);
788 }
789
790 $resql = $this->db->query($sql);
791 if ($resql) {
792 $numrows = $this->db->num_rows($resql);
793 if ($numrows) {
794 $obj = $this->db->fetch_object($resql);
795
796 $this->id = $obj->rowid;
797
798 $this->doc_date = $this->db->jdate($obj->doc_date);
799 $this->date_lim_reglement = $this->db->jdate($obj->date_lim_reglement);
800 $this->doc_type = $obj->doc_type;
801 $this->doc_ref = $obj->doc_ref;
802 $this->fk_doc = $obj->fk_doc;
803 $this->fk_docdet = $obj->fk_docdet;
804 $this->thirdparty_code = $obj->thirdparty_code;
805 $this->subledger_account = $obj->subledger_account;
806 $this->subledger_label = $obj->subledger_label;
807 $this->numero_compte = $obj->numero_compte;
808 $this->label_compte = $obj->label_compte;
809 $this->label_operation = $obj->label_operation;
810 $this->debit = $obj->debit;
811 $this->credit = $obj->credit;
812 $this->montant = $obj->amount;
813 $this->amount = $obj->amount;
814 $this->sens = $obj->sens;
815 $this->fk_user_author = $obj->fk_user_author;
816 $this->import_key = $obj->import_key;
817 $this->code_journal = $obj->code_journal;
818 $this->journal_label = $obj->journal_label;
819 $this->piece_num = $obj->piece_num;
820 $this->date_creation = $this->db->jdate($obj->date_creation);
821 $this->date_export = $this->db->jdate($obj->date_export);
822 $this->date_validation = isset($obj->date_validation) ? $this->db->jdate($obj->date_validation) : '';
823 }
824 $this->db->free($resql);
825
826 if ($numrows) {
827 return 1;
828 } else {
829 return 0;
830 }
831 } else {
832 $this->errors[] = 'Error '.$this->db->lasterror();
833 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
834
835 return -1;
836 }
837 }
838
839
853 public function fetchAllByAccount($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND', $option = 0, $countonly = 0)
854 {
855 global $conf;
856
857 dol_syslog(__METHOD__, LOG_DEBUG);
858
859 $this->lines = array();
860 $num = 0;
861
862 $sql = 'SELECT';
863 if ($countonly) {
864 $sql .= ' COUNT(t.rowid) as nb';
865 } else {
866 $sql .= ' t.rowid,';
867 $sql .= " t.doc_date,";
868 $sql .= " t.doc_type,";
869 $sql .= " t.doc_ref,";
870 $sql .= " t.fk_doc,";
871 $sql .= " t.fk_docdet,";
872 $sql .= " t.thirdparty_code,";
873 $sql .= " t.subledger_account,";
874 $sql .= " t.subledger_label,";
875 $sql .= " t.numero_compte,";
876 $sql .= " t.label_compte,";
877 $sql .= " t.label_operation,";
878 $sql .= " t.debit,";
879 $sql .= " t.credit,";
880 $sql .= " t.montant as amount,";
881 $sql .= " t.sens,";
882 $sql .= " t.multicurrency_amount,";
883 $sql .= " t.multicurrency_code,";
884 $sql .= " t.lettering_code,";
885 $sql .= " t.date_lettering,";
886 $sql .= " t.fk_user_author,";
887 $sql .= " t.import_key,";
888 $sql .= " t.code_journal,";
889 $sql .= " t.journal_label,";
890 $sql .= " t.piece_num,";
891 $sql .= " t.date_creation,";
892 $sql .= " t.date_export,";
893 $sql .= " t.date_validated as date_validation,";
894 $sql .= " t.import_key";
895 }
896 // Manage filter
897 $sqlwhere = array();
898 if (count($filter) > 0) {
899 foreach ($filter as $key => $value) {
900 if ($key == 't.doc_date>=') {
901 $sqlwhere[] = "t.doc_date >= '".$this->db->idate($value)."'";
902 } elseif ($key == 't.doc_date<=') {
903 $sqlwhere[] = "t.doc_date <= '".$this->db->idate($value)."'";
904 } elseif ($key == 't.doc_date>') {
905 $sqlwhere[] = "t.doc_date > '".$this->db->idate($value)."'";
906 } elseif ($key == 't.doc_date<') {
907 $sqlwhere[] = "t.doc_date < '".$this->db->idate($value)."'";
908 } elseif ($key == 't.numero_compte>=') {
909 $sqlwhere[] = "t.numero_compte >= '".$this->db->escape($value)."'";
910 } elseif ($key == 't.numero_compte<=') {
911 $sqlwhere[] = "t.numero_compte <= '".$this->db->escape($value)."'";
912 } elseif ($key == 't.subledger_account>=') {
913 $sqlwhere[] = "t.subledger_account >= '".$this->db->escape($value)."'";
914 } elseif ($key == 't.subledger_account<=') {
915 $sqlwhere[] = "t.subledger_account <= '".$this->db->escape($value)."'";
916 } elseif ($key == 't.fk_doc' || $key == 't.fk_docdet' || $key == 't.piece_num') {
917 $sqlwhere[] = $this->db->sanitize($key).' = '.((int) $value);
918 } elseif ($key == 't.subledger_account' || $key == 't.numero_compte') {
919 $sqlwhere[] = $this->db->sanitize($key).' LIKE \''.$this->db->escape($this->db->escapeforlike($value)).'%\'';
920 } elseif ($key == 't.date_creation>=') {
921 $sqlwhere[] = 't.date_creation >= \''.$this->db->idate($value).'\'';
922 } elseif ($key == 't.date_creation<=') {
923 $sqlwhere[] = 't.date_creation <= \''.$this->db->idate($value).'\'';
924 } elseif ($key == 't.date_export>=') {
925 $sqlwhere[] = 't.date_export >= \''.$this->db->idate($value).'\'';
926 } elseif ($key == 't.date_export<=') {
927 $sqlwhere[] = 't.date_export <= \''.$this->db->idate($value).'\'';
928 } elseif ($key == 't.date_validated>=') {
929 $sqlwhere[] = 't.date_validated >= \''.$this->db->idate($value).'\'';
930 } elseif ($key == 't.date_validated<=') {
931 $sqlwhere[] = 't.date_validated <= \''.$this->db->idate($value).'\'';
932 } elseif ($key == 't.credit' || $key == 't.debit') {
933 $sqlwhere[] = natural_search($key, $value, 1, 1);
934 } elseif ($key == 't.reconciled_option') {
935 $sqlwhere[] = 't.lettering_code IS NULL';
936 } elseif ($key == 't.code_journal' && !empty($value)) {
937 if (is_array($value)) {
938 $sqlwhere[] = natural_search("t.code_journal", implode(',', $value), 3, 1);
939 } else {
940 $sqlwhere[] = natural_search("t.code_journal", $value, 3, 1);
941 }
942 } elseif ($key == 't.search_accounting_code_in' && !empty($value)) {
943 $sqlwhere[] = 't.numero_compte IN ('.$this->db->sanitize($value, 1).')';
944 } else {
945 $sqlwhere[] = natural_search($key, $value, 0, 1);
946 }
947 }
948 }
949 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
950 $sql .= ' WHERE entity = ' . ((int) $conf->entity); // Do not use getEntity for accounting features
951 if (count($sqlwhere) > 0) {
952 $sql .= " AND ".implode(" ".$this->db->sanitize($filtermode)." ", $sqlwhere);
953 }
954 // Filter by ledger account or subledger account
955 if (!empty($option)) {
956 $sql .= " AND t.subledger_account IS NOT NULL";
957 $sql .= " AND t.subledger_account <> ''";
958 $sortfield = 't.subledger_account'.($sortfield ? ','.$sortfield : '');
959 $sortorder = 'ASC'.($sortfield ? ','.$sortfield : '');
960 } else {
961 $sortfield = 't.numero_compte'.($sortfield ? ','.$sortfield : '');
962 $sortorder = 'ASC'.($sortorder ? ','.$sortorder : '');
963 }
964
965 if (!$countonly) {
966 $sql .= $this->db->order($sortfield, $sortorder);
967 if (!empty($limit)) {
968 $sql .= $this->db->plimit($limit + 1, $offset);
969 }
970 }
971
972 $resql = $this->db->query($sql);
973 if ($resql) {
974 if ($countonly) {
975 $obj = $this->db->fetch_object($resql);
976 if ($obj) {
977 $num = $obj->nb;
978 }
979 } else {
980 $num = $this->db->num_rows($resql);
981
982 $i = 0;
983 while (($obj = $this->db->fetch_object($resql)) && (empty($limit) || $i < min($limit, $num))) {
984 $line = new BookKeepingLine($this->db);
985
986 $line->id = $obj->rowid;
987
988 $line->doc_date = $this->db->jdate($obj->doc_date);
989 $line->doc_type = $obj->doc_type;
990 $line->doc_ref = $obj->doc_ref;
991 $line->fk_doc = $obj->fk_doc;
992 $line->fk_docdet = $obj->fk_docdet;
993 $line->thirdparty_code = $obj->thirdparty_code;
994 $line->subledger_account = $obj->subledger_account;
995 $line->subledger_label = $obj->subledger_label;
996 $line->numero_compte = $obj->numero_compte;
997 $line->label_compte = $obj->label_compte;
998 $line->label_operation = $obj->label_operation;
999 $line->debit = $obj->debit;
1000 $line->credit = $obj->credit;
1001 $line->montant = $obj->amount; // deprecated
1002 $line->amount = $obj->amount;
1003 $line->sens = $obj->sens;
1004 $line->multicurrency_amount = $obj->multicurrency_amount;
1005 $line->multicurrency_code = $obj->multicurrency_code;
1006 $line->lettering_code = $obj->lettering_code;
1007 $line->date_lettering = $obj->date_lettering;
1008 $line->fk_user_author = $obj->fk_user_author;
1009 $line->import_key = $obj->import_key;
1010 $line->code_journal = $obj->code_journal;
1011 $line->journal_label = $obj->journal_label;
1012 $line->piece_num = $obj->piece_num;
1013 $line->date_creation = $this->db->jdate($obj->date_creation);
1014 $line->date_export = $this->db->jdate($obj->date_export);
1015 $line->date_validation = $this->db->jdate($obj->date_validation);
1016 $line->import_key = $obj->import_key;
1017
1018 $this->lines[] = $line;
1019
1020 $i++;
1021 }
1022 }
1023 $this->db->free($resql);
1024
1025 return $num;
1026 } else {
1027 $this->errors[] = 'Error '.$this->db->lasterror();
1028 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
1029
1030 return -1;
1031 }
1032 }
1033
1046 public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, $filter = '', $filtermode = 'AND', $showAlreadyExportMovements = 1)
1047 {
1048 global $conf;
1049
1050 dol_syslog(__METHOD__, LOG_DEBUG);
1051
1052 $sql = 'SELECT';
1053 $sql .= ' t.rowid,';
1054 $sql .= " t.doc_date,";
1055 $sql .= " t.doc_type,";
1056 $sql .= " t.doc_ref,";
1057 $sql .= " t.fk_doc,";
1058 $sql .= " t.fk_docdet,";
1059 $sql .= " t.thirdparty_code,";
1060 $sql .= " t.subledger_account,";
1061 $sql .= " t.subledger_label,";
1062 $sql .= " t.numero_compte,";
1063 $sql .= " t.label_compte,";
1064 $sql .= " t.label_operation,";
1065 $sql .= " t.debit,";
1066 $sql .= " t.credit,";
1067 $sql .= " t.lettering_code,";
1068 $sql .= " t.date_lettering,";
1069 $sql .= " t.montant as amount,";
1070 $sql .= " t.sens,";
1071 $sql .= " t.fk_user_author,";
1072 $sql .= " t.import_key,";
1073 $sql .= " t.code_journal,";
1074 $sql .= " t.journal_label,";
1075 $sql .= " t.piece_num,";
1076 $sql .= " t.date_creation,";
1077 $sql .= " t.date_lim_reglement,";
1078 $sql .= " t.tms as date_modification,";
1079 $sql .= " t.date_export,";
1080 $sql .= " t.date_validated as date_validation";
1081 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
1082
1083 $sql .= ' WHERE t.entity = ' . ((int) $conf->entity); // Do not use getEntity for accounting features
1084 if ($showAlreadyExportMovements == 0) {
1085 $sql .= " AND t.date_export IS NULL";
1086 }
1087
1088 // Manage filter
1089 if (is_array($filter)) { // deprecated, use $filter = USF syntax
1090 dol_syslog("You are using a deprecated use of fetchAll. filter parameter mus be an USF string now.", LOG_WARNING);
1091 $sqlwhere = array();
1092 if (count($filter) > 0) {
1093 foreach ($filter as $key => $value) {
1094 if ($key == 't.doc_date') {
1095 $sqlwhere[] = $this->db->sanitize($key).' = \''.$this->db->idate($value).'\'';
1096 } elseif ($key == 't.doc_date>=') {
1097 $sqlwhere[] = "t.doc_date >= '".$this->db->idate($value)."'";
1098 } elseif ($key == 't.doc_date<=') {
1099 $sqlwhere[] = "t.doc_date <= '".$this->db->idate($value)."'";
1100 } elseif ($key == 't.doc_date>') {
1101 $sqlwhere[] = "t.doc_date > '".$this->db->idate($value)."'";
1102 } elseif ($key == 't.doc_date<') {
1103 $sqlwhere[] = "t.doc_date < '".$this->db->idate($value)."'";
1104 } elseif ($key == 't.numero_compte>=') {
1105 $sqlwhere[] = "t.numero_compte >= '".$this->db->escape($value)."'";
1106 } elseif ($key == 't.numero_compte<=') {
1107 $sqlwhere[] = "t.numero_compte <= '".$this->db->escape($value)."'";
1108 } elseif ($key == 't.subledger_account>=') {
1109 $sqlwhere[] = "t.subledger_account >= '".$this->db->escape($value)."'";
1110 } elseif ($key == 't.subledger_account<=') {
1111 $sqlwhere[] = "t.subledger_account <= '".$this->db->escape($value)."'";
1112 } elseif ($key == 't.fk_doc' || $key == 't.fk_docdet' || $key == 't.piece_num') {
1113 $sqlwhere[] = $this->db->sanitize($key).' = '.((int) $value);
1114 } elseif ($key == 't.subledger_account' || $key == 't.numero_compte') {
1115 $sqlwhere[] = $this->db->sanitize($key).' LIKE \''.$this->db->escape($value).'%\'';
1116 } elseif ($key == 't.date_creation>=') {
1117 $sqlwhere[] = 't.date_creation >= \''.$this->db->idate($value).'\'';
1118 } elseif ($key == 't.date_creation<=') {
1119 $sqlwhere[] = 't.date_creation <= \''.$this->db->idate($value).'\'';
1120 } elseif ($key == 't.tms>=') {
1121 $sqlwhere[] = 't.tms >= \''.$this->db->idate($value).'\'';
1122 } elseif ($key == 't.tms<=') {
1123 $sqlwhere[] = 't.tms <= \''.$this->db->idate($value).'\'';
1124 } elseif ($key == 't.date_export>=') {
1125 $sqlwhere[] = 't.date_export >= \''.$this->db->idate($value).'\'';
1126 } elseif ($key == 't.date_export<=') {
1127 $sqlwhere[] = 't.date_export <= \''.$this->db->idate($value).'\'';
1128 } elseif ($key == 't.date_validated>=') {
1129 $sqlwhere[] = 't.date_validated >= \''.$this->db->idate($value).'\'';
1130 } elseif ($key == 't.date_validated<=') {
1131 $sqlwhere[] = 't.date_validated <= \''.$this->db->idate($value).'\'';
1132 } elseif ($key == 't.credit' || $key == 't.debit') {
1133 $sqlwhere[] = natural_search($key, $value, 1, 1);
1134 } elseif ($key == 't.code_journal' && !empty($value)) {
1135 if (is_array($value)) {
1136 $sqlwhere[] = natural_search("t.code_journal", implode(',', $value), 3, 1);
1137 } else {
1138 $sqlwhere[] = natural_search("t.code_journal", $value, 3, 1);
1139 }
1140 } else {
1141 $sqlwhere[] = natural_search($key, $value, 0, 1);
1142 }
1143 }
1144 }
1145 if (count($sqlwhere) > 0) {
1146 $sql .= ' AND '.implode(" ".$this->db->sanitize($filtermode)." ", $sqlwhere);
1147 }
1148
1149 $filter = '';
1150 }
1151
1152 // Manage filter
1153 $errormessage = '';
1154 $sql .= forgeSQLFromUniversalSearchCriteria($filter, $errormessage);
1155 if ($errormessage) {
1156 $this->errors[] = $errormessage;
1157 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
1158 return -1;
1159 }
1160
1161 if (!empty($sortfield)) {
1162 $sql .= $this->db->order($sortfield, $sortorder);
1163 }
1164 if (!empty($limit)) {
1165 $sql .= $this->db->plimit($limit + 1, $offset);
1166 }
1167 $this->lines = array();
1168
1169 $resql = $this->db->query($sql);
1170 if ($resql) {
1171 $num = $this->db->num_rows($resql);
1172
1173 $i = 0;
1174 while (($obj = $this->db->fetch_object($resql)) && (empty($limit) || $i < min($limit, $num))) {
1175 $line = new BookKeepingLine($this->db);
1176
1177 $line->id = $obj->rowid;
1178
1179 $line->doc_date = $this->db->jdate($obj->doc_date);
1180 $line->doc_type = $obj->doc_type;
1181 $line->doc_ref = $obj->doc_ref;
1182 $line->fk_doc = $obj->fk_doc;
1183 $line->fk_docdet = $obj->fk_docdet;
1184 $line->thirdparty_code = $obj->thirdparty_code;
1185 $line->subledger_account = $obj->subledger_account;
1186 $line->subledger_label = $obj->subledger_label;
1187 $line->numero_compte = $obj->numero_compte;
1188 $line->label_compte = $obj->label_compte;
1189 $line->label_operation = $obj->label_operation;
1190 $line->debit = $obj->debit;
1191 $line->credit = $obj->credit;
1192 $line->montant = $obj->amount; // deprecated
1193 $line->amount = $obj->amount;
1194 $line->sens = $obj->sens;
1195 $line->lettering_code = $obj->lettering_code;
1196 $line->date_lettering = $obj->date_lettering;
1197 $line->fk_user_author = $obj->fk_user_author;
1198 $line->import_key = $obj->import_key;
1199 $line->code_journal = $obj->code_journal;
1200 $line->journal_label = $obj->journal_label;
1201 $line->piece_num = $obj->piece_num;
1202 $line->date_creation = $this->db->jdate($obj->date_creation);
1203 $line->date_lim_reglement = $this->db->jdate($obj->date_lim_reglement);
1204 $line->date_modification = $this->db->jdate($obj->date_modification);
1205 $line->date_export = $this->db->jdate($obj->date_export);
1206 $line->date_validation = $this->db->jdate($obj->date_validation);
1207
1208 $this->lines[] = $line;
1209
1210 $i++;
1211 }
1212 $this->db->free($resql);
1213
1214 return $num;
1215 } else {
1216 $this->errors[] = 'Error '.$this->db->lasterror();
1217 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
1218 return -1;
1219 }
1220 }
1221
1234 public function fetchAllBalance($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, $filter = '', $filtermode = 'AND', $option = 0)
1235 {
1236 global $conf;
1237
1238 $this->lines = array();
1239
1240 dol_syslog(__METHOD__, LOG_DEBUG);
1241
1242 $sql = 'SELECT';
1243 $sql .= " t.numero_compte,";
1244 if (!empty($option)) {
1245 $sql .= " t.subledger_account,";
1246 $sql .= " t.subledger_label,";
1247 }
1248 $sql .= " SUM(t.debit) as debit,";
1249 $sql .= " SUM(t.credit) as credit";
1250 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
1251 $sql .= ' WHERE entity = ' . ((int) $conf->entity); // Do not use getEntity for accounting features
1252
1253 // Manage filter
1254 if (is_array($filter)) {
1255 $sqlwhere = array();
1256 if (count($filter) > 0) {
1257 foreach ($filter as $key => $value) {
1258 if ($key == 't.doc_date') {
1259 $sqlwhere[] = $this->db->sanitize($key)." = '".$this->db->idate($value)."'";
1260 } elseif ($key == 't.doc_date>=') {
1261 $sqlwhere[] = "t.doc_date >= '".$this->db->idate($value)."'";
1262 } elseif ($key == 't.doc_date<=') {
1263 $sqlwhere[] = "t.doc_date <= '".$this->db->idate($value)."'";
1264 } elseif ($key == 't.doc_date>') {
1265 $sqlwhere[] = "t.doc_date > '".$this->db->idate($value)."'";
1266 } elseif ($key == 't.doc_date<') {
1267 $sqlwhere[] = "t.doc_date < '".$this->db->idate($value)."'";
1268 } elseif ($key == 't.numero_compte>=') {
1269 $sqlwhere[] = "t.numero_compte >= '".$this->db->escape($value)."'";
1270 } elseif ($key == 't.numero_compte<=') {
1271 $sqlwhere[] = "t.numero_compte <= '".$this->db->escape($value)."'";
1272 } elseif ($key == 't.subledger_account>=') {
1273 $sqlwhere[] = "t.subledger_account >= '".$this->db->escape($value)."'";
1274 } elseif ($key == 't.subledger_account<=') {
1275 $sqlwhere[] = "t.subledger_account <= '".$this->db->escape($value)."'";
1276 } elseif ($key == 't.fk_doc' || $key == 't.fk_docdet' || $key == 't.piece_num') {
1277 $sqlwhere[] = $this->db->sanitize($key)." = ".((int) $value);
1278 } elseif ($key == 't.subledger_account' || $key == 't.numero_compte') {
1279 $sqlwhere[] = $this->db->sanitize($key)." LIKE '".$this->db->escape($value)."%'";
1280 } elseif ($key == 't.subledger_label') {
1281 $sqlwhere[] = $this->db->sanitize($key)." LIKE '".$this->db->escape($value)."%'";
1282 } elseif ($key == 't.code_journal' && !empty($value)) {
1283 if (is_array($value)) {
1284 $sqlwhere[] = natural_search("t.code_journal", implode(',', $value), 3, 1);
1285 } else {
1286 $sqlwhere[] = natural_search("t.code_journal", $value, 3, 1);
1287 }
1288 } elseif ($key == 't.reconciled_option') {
1289 $sqlwhere[] = 't.lettering_code IS NULL';
1290 } else {
1291 $sqlwhere[] = $this->db->sanitize($key)." LIKE '%".$this->db->escape($this->db->escapeforlike($value))."%'";
1292 }
1293 }
1294 }
1295 if (count($sqlwhere) > 0) {
1296 $sql .= " AND ".implode(" ".$this->db->sanitize($filtermode)." ", $sqlwhere);
1297 }
1298
1299 $filter = '';
1300 }
1301
1302 // Manage filter
1303 $errormessage = '';
1304 $sql .= forgeSQLFromUniversalSearchCriteria($filter, $errormessage);
1305 if ($errormessage) {
1306 $this->errors[] = $errormessage;
1307 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
1308 return -1;
1309 }
1310
1311 if (!empty($option)) {
1312 $sql .= " AND t.subledger_account IS NOT NULL";
1313 $sql .= " AND t.subledger_account <> ''";
1314 $sql .= " GROUP BY t.numero_compte, t.subledger_account, t.subledger_label";
1315 $sortfield = 't.subledger_account'.($sortfield ? ','.$sortfield : '');
1316 $sortorder = 'ASC'.($sortfield ? ','.$sortfield : '');
1317 } else {
1318 $sql .= ' GROUP BY t.numero_compte';
1319 $sortfield = 't.numero_compte'.($sortfield ? ','.$sortfield : '');
1320 $sortorder = 'ASC'.($sortorder ? ','.$sortorder : '');
1321 }
1322
1323 if (!empty($sortfield)) {
1324 $sql .= $this->db->order($sortfield, $sortorder);
1325 }
1326 if (!empty($limit)) {
1327 $sql .= $this->db->plimit($limit + 1, $offset);
1328 }
1329
1330 //print $sql;
1331 $resql = $this->db->query($sql);
1332
1333 if ($resql) {
1334 $num = $this->db->num_rows($resql);
1335
1336 $i = 0;
1337 while (($obj = $this->db->fetch_object($resql)) && (empty($limit) || $i < min($limit, $num))) {
1338 $line = new BookKeepingLine($this->db);
1339
1340 $line->numero_compte = $obj->numero_compte;
1341 //$line->label_compte = $obj->label_compte;
1342 if (!empty($option)) {
1343 $line->subledger_account = $obj->subledger_account;
1344 $line->subledger_label = $obj->subledger_label;
1345 }
1346 $line->debit = $obj->debit;
1347 $line->credit = $obj->credit;
1348
1349 $this->lines[] = $line;
1350
1351 $i++;
1352 }
1353 $this->db->free($resql);
1354
1355 return $num;
1356 } else {
1357 $this->errors[] = 'Error '.$this->db->lasterror();
1358 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
1359
1360 return -1;
1361 }
1362 }
1363
1372 public function update(User $user, $notrigger = 0, $mode = '')
1373 {
1374 global $langs;
1375 $error = 0;
1376
1377 dol_syslog(__METHOD__, LOG_DEBUG);
1378
1379 // Clean parameters
1380 if (isset($this->doc_type)) {
1381 $this->doc_type = trim($this->doc_type);
1382 }
1383 if (isset($this->doc_ref)) {
1384 $this->doc_ref = trim($this->doc_ref);
1385 }
1386 if (isset($this->fk_doc)) {
1387 $this->fk_doc = (int) $this->fk_doc;
1388 }
1389 if (isset($this->fk_docdet)) {
1390 $this->fk_docdet = (int) $this->fk_docdet;
1391 }
1392 if (isset($this->thirdparty_code)) {
1393 $this->thirdparty_code = trim($this->thirdparty_code);
1394 }
1395 if (isset($this->subledger_account)) {
1396 $this->subledger_account = trim($this->subledger_account);
1397 }
1398 if (isset($this->subledger_label)) {
1399 $this->subledger_label = trim($this->subledger_label);
1400 }
1401 if (isset($this->numero_compte)) {
1402 $this->numero_compte = trim($this->numero_compte);
1403 }
1404 if (isset($this->label_compte)) {
1405 $this->label_compte = trim($this->label_compte);
1406 }
1407 if (isset($this->label_operation)) {
1408 $this->label_operation = trim($this->label_operation);
1409 }
1410 if (isset($this->sens)) {
1411 $this->sens = trim($this->sens);
1412 }
1413 if (isset($this->import_key)) {
1414 $this->import_key = trim($this->import_key);
1415 }
1416 if (isset($this->code_journal)) {
1417 $this->code_journal = trim($this->code_journal);
1418 }
1419 if (isset($this->journal_label)) {
1420 $this->journal_label = trim($this->journal_label);
1421 }
1422 if (isset($this->piece_num)) {
1423 $this->piece_num = (int) $this->piece_num;
1424 }
1425
1426 $result = $this->canModifyBookkeeping($this->id, $mode);
1427 if ($result < 0) {
1428 return -1;
1429 } elseif ($result == 0) {
1430 if (getDolGlobalString('ACCOUNTANCY_FISCAL_PERIOD_MODE') == 'blockedonclosed') {
1431 $this->errors[] = $langs->trans('ErrorBookkeepingDocDateIsOnAClosedFiscalPeriod');
1432 } else {
1433 $this->errors[] = $langs->trans('ErrorBookkeepingDocDateNotOnActiveFiscalPeriod');
1434 }
1435 return -1;
1436 }
1437
1438 $this->debit = (float) price2num($this->debit, 'MT');
1439 $this->credit = (float) price2num($this->credit, 'MT');
1440 $this->montant = (float) price2num($this->montant, 'MT');
1441
1442 // Check parameters
1443 // Put here code to add a control on parameters values
1444
1445 // Update request
1446 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element.$mode.' SET';
1447 $sql .= ' doc_date = '.(!isset($this->doc_date) || dol_strlen($this->doc_date) != 0 ? "'".$this->db->idate($this->doc_date)."'" : 'null').',';
1448 $sql .= ' doc_type = '.(isset($this->doc_type) ? "'".$this->db->escape($this->doc_type)."'" : "null").',';
1449 $sql .= ' doc_ref = '.(isset($this->doc_ref) ? "'".$this->db->escape($this->doc_ref)."'" : "null").',';
1450 $sql .= ' fk_doc = '.(isset($this->fk_doc) ? $this->fk_doc : "null").',';
1451 $sql .= ' fk_docdet = '.(isset($this->fk_docdet) ? $this->fk_docdet : "null").',';
1452 $sql .= ' thirdparty_code = '.(isset($this->thirdparty_code) ? "'".$this->db->escape($this->thirdparty_code)."'" : "null").',';
1453 $sql .= ' subledger_account = '.(isset($this->subledger_account) ? "'".$this->db->escape($this->subledger_account)."'" : "null").',';
1454 $sql .= ' subledger_label = '.(isset($this->subledger_label) ? "'".$this->db->escape($this->subledger_label)."'" : "null").',';
1455 $sql .= ' numero_compte = '.(isset($this->numero_compte) ? "'".$this->db->escape($this->numero_compte)."'" : "null").',';
1456 $sql .= ' label_compte = '.(isset($this->label_compte) ? "'".$this->db->escape($this->label_compte)."'" : "null").',';
1457 $sql .= ' label_operation = '.(isset($this->label_operation) ? "'".$this->db->escape($this->label_operation)."'" : "null").',';
1458 $sql .= ' debit = '.(isset($this->debit) ? $this->debit : "null").',';
1459 $sql .= ' credit = '.(isset($this->credit) ? $this->credit : "null").',';
1460 $sql .= ' montant = '.(isset($this->montant) ? $this->montant : "null").',';
1461 $sql .= ' sens = '.(isset($this->sens) ? "'".$this->db->escape($this->sens)."'" : "null").',';
1462 $sql .= ' fk_user_author = '.(isset($this->fk_user_author) ? $this->fk_user_author : "null").',';
1463 $sql .= ' import_key = '.(isset($this->import_key) ? "'".$this->db->escape($this->import_key)."'" : "null").',';
1464 $sql .= ' code_journal = '.(isset($this->code_journal) ? "'".$this->db->escape($this->code_journal)."'" : "null").',';
1465 $sql .= ' journal_label = '.(isset($this->journal_label) ? "'".$this->db->escape($this->journal_label)."'" : "null").',';
1466 $sql .= ' piece_num = '.(isset($this->piece_num) ? $this->piece_num : "null");
1467 $sql .= ' WHERE rowid='.((int) $this->id);
1468
1469 $this->db->begin();
1470
1471 $resql = $this->db->query($sql);
1472 if (!$resql) {
1473 $error++;
1474 $this->errors[] = 'Error '.$this->db->lasterror();
1475 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
1476 }
1477
1478 // Uncomment this and change MYOBJECT to your own tag if you
1479 // want this action calls a trigger.
1480 //if (! $error && ! $notrigger) {
1481
1482 // // Call triggers
1483 // $result=$this->call_trigger('MYOBJECT_MODIFY',$user);
1484 // if ($result < 0) { $error++; //Do also what you must do to rollback action if trigger fail}
1485 // // End call triggers
1486 //}
1487
1488 // Commit or rollback
1489 if ($error) {
1490 $this->db->rollback();
1491
1492 return -1 * $error;
1493 } else {
1494 $this->db->commit();
1495
1496 return 1;
1497 }
1498 }
1499
1509 public function updateByMvt($piece_num = '', $field = '', $value = '', $mode = '')
1510 {
1511 $error = 0;
1512
1513 $sql_filter = $this->getCanModifyBookkeepingSQL();
1514 if (!isset($sql_filter)) {
1515 return -1;
1516 }
1517
1518 $this->db->begin();
1519
1520 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element.$mode;
1521 $sql .= " SET ".$this->db->sanitize($field)." = ".(is_numeric($value) ? ((float) $value) : "'".$this->db->escape($value)."'");
1522 $sql .= " WHERE piece_num = ".((int) $piece_num);
1523 $sql .= $sql_filter;
1524
1525 $resql = $this->db->query($sql);
1526
1527 if (!$resql) {
1528 $error++;
1529 $this->errors[] = 'Error '.$this->db->lasterror();
1530 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
1531 }
1532 if ($error) {
1533 $this->db->rollback();
1534
1535 return -1 * $error;
1536 } else {
1537 $this->db->commit();
1538
1539 return 1;
1540 }
1541 }
1542
1551 public function delete(User $user, $notrigger = 0, $mode = '')
1552 {
1553 global $langs;
1554
1555 dol_syslog(__METHOD__, LOG_DEBUG);
1556
1557 $result = $this->canModifyBookkeeping($this->id, $mode);
1558 if ($result < 0) {
1559 return -1;
1560 } elseif ($result == 0) {
1561 if (getDolGlobalString('ACCOUNTANCY_FISCAL_PERIOD_MODE') == 'blockedonclosed') {
1562 $this->errors[] = $langs->trans('ErrorBookkeepingDocDateIsOnAClosedFiscalPeriod');
1563 } else {
1564 $this->errors[] = $langs->trans('ErrorBookkeepingDocDateNotOnActiveFiscalPeriod');
1565 }
1566 return -1;
1567 }
1568
1569 $error = 0;
1570
1571 $this->db->begin();
1572
1573 // Uncomment this and change MYOBJECT to your own tag if you
1574 // want this action calls a trigger.
1575 //if (! $error && ! $notrigger) {
1576
1577 // // Call triggers
1578 // $result=$this->call_trigger('MYOBJECT_DELETE',$user);
1579 // if ($result < 0) { $error++; //Do also what you must do to rollback action if trigger fail}
1580 // // End call triggers
1581 //}
1582
1583 if (!$error) {
1584 $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.$mode;
1585 $sql .= ' WHERE rowid='.((int) $this->id);
1586
1587 $resql = $this->db->query($sql);
1588 if (!$resql) {
1589 $error++;
1590 $this->errors[] = 'Error '.$this->db->lasterror();
1591 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
1592 }
1593 }
1594
1595 // Commit or rollback
1596 if ($error) {
1597 $this->db->rollback();
1598
1599 return -1 * $error;
1600 } else {
1601 $this->db->commit();
1602
1603 return 1;
1604 }
1605 }
1606
1614 public function deleteByImportkey($importkey, $mode = '')
1615 {
1616 $this->db->begin();
1617
1618 $sql_filter = $this->getCanModifyBookkeepingSQL();
1619 if (!isset($sql_filter)) {
1620 return -1;
1621 }
1622
1623 // first check if line not yet in bookkeeping
1624 $sql = "DELETE";
1625 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element.$mode;
1626 $sql .= " WHERE import_key = '".$this->db->escape($importkey)."'";
1627 $sql .= $sql_filter;
1628
1629 $resql = $this->db->query($sql);
1630
1631 if (!$resql) {
1632 $this->errors[] = "Error ".$this->db->lasterror();
1633 dol_syslog(get_class($this)."::delete Error ".$this->db->lasterror(), LOG_ERR);
1634 $this->db->rollback();
1635 return -1;
1636 }
1637
1638 $this->db->commit();
1639 return 1;
1640 }
1641
1651 public function deleteByYearAndJournal($delyear = 0, $journal = '', $mode = '', $delmonth = 0)
1652 {
1653 global $conf, $langs;
1654
1655 if (empty($delyear) && empty($journal)) {
1656 $this->error = 'ErrorOneFieldRequired';
1657 return -1;
1658 }
1659 if (!empty($delmonth) && empty($delyear)) {
1660 $this->error = 'YearRequiredIfMonthDefined';
1661 return -2;
1662 }
1663
1664 $sql_filter = $this->getCanModifyBookkeepingSQL();
1665 if (!isset($sql_filter)) {
1666 return -1;
1667 }
1668
1669 $this->db->begin();
1670
1671 // Delete record in bookkeeping
1672 $sql = "DELETE";
1673 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element.$mode;
1674 $sql .= " WHERE 1 = 1";
1675 $sql .= dolSqlDateFilter('doc_date', 0, $delmonth, $delyear);
1676 if (!empty($journal)) {
1677 $sql .= " AND code_journal = '".$this->db->escape($journal)."'";
1678 }
1679 $sql .= " AND entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
1680 // Exclusion of validated entries at the time of deletion
1681 $sql .= " AND date_validated IS NULL";
1682 $sql .= $sql_filter;
1683
1684 // TODO: In a future we must forbid deletion if record is inside a closed fiscal period.
1685
1686 $resql = $this->db->query($sql);
1687
1688 if (!$resql) {
1689 $this->errors[] = "Error ".$this->db->lasterror();
1690 foreach ($this->errors as $errmsg) {
1691 dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR);
1692 $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
1693 }
1694 $this->db->rollback();
1695 return -1;
1696 }
1697
1698 $this->db->commit();
1699 return 1;
1700 }
1701
1709 public function deleteMvtNum($piecenum, $mode = '')
1710 {
1711 global $conf;
1712
1713 $sql_filter = $this->getCanModifyBookkeepingSQL();
1714 if (!isset($sql_filter)) {
1715 return -1;
1716 }
1717
1718 $nbprocessed = 0;
1719
1720 $this->db->begin();
1721
1722 // first check if line not yet in bookkeeping
1723 $sql = "DELETE";
1724 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element.$mode;
1725 $sql .= " WHERE piece_num = ".(int) $piecenum;
1726 $sql .= " AND date_validated IS NULL"; // For security, exclusion of validated entries at the time of deletion
1727 $sql .= " AND entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
1728 $sql .= $sql_filter;
1729
1730 $resql = $this->db->query($sql);
1731
1732 if (!$resql) {
1733 $this->errors[] = "Error ".$this->db->lasterror();
1734 foreach ($this->errors as $errmsg) {
1735 dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR);
1736 $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
1737 }
1738 $this->db->rollback();
1739 return -1;
1740 } else {
1741 $nbprocessed = $this->db->affected_rows($resql);
1742 }
1743
1744 $this->db->commit();
1745
1746 return $nbprocessed;
1747 }
1748
1756 public function createFromClone(User $user, $fromid)
1757 {
1758 dol_syslog(__METHOD__, LOG_DEBUG);
1759
1760 $error = 0;
1761 $object = new BookKeeping($this->db);
1762
1763 $this->db->begin();
1764
1765 // Load source object
1766 $object->fetch($fromid);
1767 // Reset object
1768 $object->id = 0;
1769
1770 // Clear fields
1771 // ...
1772
1773 // Create clone
1774 $object->context['createfromclone'] = 'createfromclone';
1775 $result = $object->create($user);
1776
1777 // Other options
1778 if ($result < 0) {
1779 $error++;
1780 $this->errors = $object->errors;
1781 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
1782 }
1783
1784 unset($object->context['createfromclone']);
1785
1786 // End
1787 if (!$error) {
1788 $this->db->commit();
1789
1790 return $object->id;
1791 } else {
1792 $this->db->rollback();
1793
1794 return -1;
1795 }
1796 }
1797
1804 public function initAsSpecimen()
1805 {
1806 global $user;
1807
1808 $now = dol_now();
1809
1810 $this->id = 0;
1811 $this->doc_date = $now;
1812 $this->doc_type = '';
1813 $this->doc_ref = '';
1814 $this->fk_doc = 0;
1815 $this->fk_docdet = 0;
1816 $this->thirdparty_code = 'CU001';
1817 $this->subledger_account = '41100001';
1818 $this->subledger_label = 'My customer company';
1819 $this->numero_compte = '411';
1820 $this->label_compte = 'Customer';
1821 $this->label_operation = 'Sales of pea';
1822 $this->debit = 99.9;
1823 $this->credit = 0.0;
1824 $this->amount = 0.0;
1825 $this->sens = 'D';
1826 $this->fk_user_author = $user->id;
1827 $this->import_key = '20201027';
1828 $this->code_journal = 'VT';
1829 $this->journal_label = 'Journal de vente';
1830 $this->piece_num = 1234;
1831 $this->date_creation = $now;
1832
1833 return 1;
1834 }
1835
1843 public function fetchPerMvt($piecenum, $mode = '')
1844 {
1845 global $conf;
1846
1847 $sql = "SELECT piece_num, doc_date, code_journal, journal_label, doc_ref, doc_type,";
1848 $sql .= " date_creation, tms as date_modification, date_validated as date_validation, import_key";
1849 // In llx_accounting_bookkeeping_tmp, field date_export doesn't exist
1850 if ($mode != "_tmp") {
1851 $sql .= ", date_export";
1852 }
1853 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element.$mode;
1854 $sql .= " WHERE piece_num = ".((int) $piecenum);
1855 $sql .= " AND entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
1856
1857 dol_syslog(__METHOD__, LOG_DEBUG);
1858 $result = $this->db->query($sql);
1859 if ($result) {
1860 $obj = $this->db->fetch_object($result);
1861
1862 $this->piece_num = $obj->piece_num;
1863 $this->code_journal = $obj->code_journal;
1864 $this->journal_label = $obj->journal_label;
1865 $this->doc_date = $this->db->jdate($obj->doc_date);
1866 $this->doc_ref = $obj->doc_ref;
1867 $this->doc_type = $obj->doc_type;
1868 $this->date_creation = $this->db->jdate($obj->date_creation);
1869 $this->date_modification = $this->db->jdate($obj->date_modification);
1870 if ($mode != "_tmp") {
1871 $this->date_export = $this->db->jdate($obj->date_export);
1872 }
1873 $this->date_validation = $this->db->jdate($obj->date_validation);
1874 $this->import_key = $obj->import_key;
1875 } else {
1876 $this->error = "Error ".$this->db->lasterror();
1877 dol_syslog(__METHOD__.$this->error, LOG_ERR);
1878 return -1;
1879 }
1880
1881 return 1;
1882 }
1883
1890 public function getNextNumMvt($mode = '')
1891 {
1892 global $conf;
1893
1894 $sql = "SELECT MAX(piece_num)+1 as max FROM ".MAIN_DB_PREFIX.$this->table_element.$mode;
1895 $sql .= " WHERE entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
1896
1897 dol_syslog(get_class($this)."::getNextNumMvt", LOG_DEBUG);
1898
1899 $result = $this->db->query($sql);
1900
1901 if ($result) {
1902 $obj = $this->db->fetch_object($result);
1903 if ($obj) {
1904 $result = $obj->max;
1905 }
1906 if (empty($result)) {
1907 $result = 1;
1908 }
1909 return $result;
1910 } else {
1911 $this->error = "Error ".$this->db->lasterror();
1912 dol_syslog(get_class($this)."::getNextNumMvt ".$this->error, LOG_ERR);
1913 return -1;
1914 }
1915 }
1916
1924 public function fetchAllPerMvt($piecenum, $mode = '')
1925 {
1926 global $conf;
1927
1928 $sql = "SELECT rowid, doc_date, doc_type,";
1929 $sql .= " doc_ref, fk_doc, fk_docdet, thirdparty_code, subledger_account, subledger_label,";
1930 $sql .= " numero_compte, label_compte, label_operation, debit, credit,";
1931 $sql .= " montant as amount, sens, fk_user_author, import_key, code_journal, journal_label, piece_num,";
1932 $sql .= " date_creation, tms as date_modification, date_validated as date_validation";
1933 // In llx_accounting_bookkeeping_tmp, field date_export doesn't exist
1934 if ($mode != "_tmp") {
1935 $sql .= ", date_export";
1936 }
1937 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element.$mode;
1938 $sql .= " WHERE piece_num = ".((int) $piecenum);
1939 $sql .= " AND entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
1940
1941 dol_syslog(__METHOD__, LOG_DEBUG);
1942 $result = $this->db->query($sql);
1943 if ($result) {
1944 while ($obj = $this->db->fetch_object($result)) {
1945 $line = new BookKeepingLine($this->db);
1946
1947 $line->id = $obj->rowid;
1948
1949 $line->doc_date = $this->db->jdate($obj->doc_date);
1950 $line->doc_type = $obj->doc_type;
1951 $line->doc_ref = $obj->doc_ref;
1952 $line->fk_doc = $obj->fk_doc;
1953 $line->fk_docdet = $obj->fk_docdet;
1954 $line->thirdparty_code = $obj->thirdparty_code;
1955 $line->subledger_account = $obj->subledger_account;
1956 $line->subledger_label = $obj->subledger_label;
1957 $line->numero_compte = $obj->numero_compte;
1958 $line->label_compte = $obj->label_compte;
1959 $line->label_operation = $obj->label_operation;
1960 $line->debit = $obj->debit;
1961 $line->credit = $obj->credit;
1962 $line->montant = $obj->amount;
1963 $line->amount = $obj->amount;
1964 $line->sens = $obj->sens;
1965 $line->code_journal = $obj->code_journal;
1966 $line->journal_label = $obj->journal_label;
1967 $line->piece_num = $obj->piece_num;
1968 $line->date_creation = $obj->date_creation;
1969 $line->date_modification = $obj->date_modification;
1970 if ($mode != "_tmp") {
1971 $line->date_export = $obj->date_export;
1972 }
1973 $line->date_validation = $obj->date_validation;
1974
1975 $this->linesmvt[] = $line;
1976 }
1977 } else {
1978 $this->error = "Error ".$this->db->lasterror();
1979 dol_syslog(__METHOD__.$this->error, LOG_ERR);
1980 return -1;
1981 }
1982
1983 return 1;
1984 }
1985
1986 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1993 public function export_bookkeeping($model = 'ebp')
1994 {
1995 // phpcs:enable
1996 global $conf;
1997
1998 $sql = "SELECT rowid, doc_date, doc_type,";
1999 $sql .= " doc_ref, fk_doc, fk_docdet, thirdparty_code, subledger_account, subledger_label,";
2000 $sql .= " numero_compte, label_compte, label_operation, debit, credit,";
2001 $sql .= " montant as amount, sens, fk_user_author, import_key, code_journal, piece_num,";
2002 $sql .= " date_validated as date_validation";
2003 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element;
2004 $sql .= " WHERE entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
2005
2006 dol_syslog(get_class($this)."::export_bookkeeping", LOG_DEBUG);
2007
2008 $resql = $this->db->query($sql);
2009
2010 if ($resql) {
2011 $this->linesexport = array();
2012
2013 $num = $this->db->num_rows($resql);
2014 while ($obj = $this->db->fetch_object($resql)) {
2015 $line = new BookKeepingLine($this->db);
2016
2017 $line->id = $obj->rowid;
2018
2019 $line->doc_date = $this->db->jdate($obj->doc_date);
2020 $line->doc_type = $obj->doc_type;
2021 $line->doc_ref = $obj->doc_ref;
2022 $line->fk_doc = $obj->fk_doc;
2023 $line->fk_docdet = $obj->fk_docdet;
2024 $line->thirdparty_code = $obj->thirdparty_code;
2025 $line->subledger_account = $obj->subledger_account;
2026 $line->subledger_label = $obj->subledger_label;
2027 $line->numero_compte = $obj->numero_compte;
2028 $line->label_compte = $obj->label_compte;
2029 $line->label_operation = $obj->label_operation;
2030 $line->debit = $obj->debit;
2031 $line->credit = $obj->credit;
2032 $line->montant = $obj->amount;
2033 $line->amount = $obj->amount;
2034 $line->sens = $obj->sens;
2035 $line->code_journal = $obj->code_journal;
2036 $line->piece_num = $obj->piece_num;
2037 $line->date_validation = $obj->date_validation;
2038
2039 $this->linesexport[] = $line;
2040 }
2041 $this->db->free($resql);
2042
2043 return $num;
2044 } else {
2045 $this->error = "Error ".$this->db->lasterror();
2046 dol_syslog(get_class($this)."::export_bookkeeping ".$this->error, LOG_ERR);
2047 return -1;
2048 }
2049 }
2050
2058 public function transformTransaction($direction = 0, $piece_num = '')
2059 {
2060 global $conf;
2061
2062 $error = 0;
2063
2064 $sql_filter = $this->getCanModifyBookkeepingSQL();
2065
2066 if (!isset($sql_filter)) {
2067 return -1;
2068 }
2069
2070 $this->db->begin();
2071
2072 if ($direction == 0) {
2073 $next_piecenum = $this->getNextNumMvt();
2074 $now = dol_now();
2075
2076 if ($next_piecenum < 0) {
2077 $error++;
2078 }
2079
2080 if (!$error) {
2081 // Delete if there is an empty line
2082 $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";
2083 $resql = $this->db->query($sql);
2084 if (!$resql) {
2085 $error++;
2086 $this->errors[] = 'Error '.$this->db->lasterror();
2087 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
2088 }
2089 }
2090
2091 if (!$error) {
2092 $sql = 'INSERT INTO '.MAIN_DB_PREFIX.$this->table_element.' (doc_date, doc_type,';
2093 $sql .= ' doc_ref, fk_doc, fk_docdet, entity, thirdparty_code, subledger_account, subledger_label,';
2094 $sql .= ' numero_compte, label_compte, label_operation, debit, credit,';
2095 $sql .= ' montant, sens, fk_user_author, import_key, code_journal, journal_label, piece_num, date_creation)';
2096 $sql .= ' SELECT doc_date, doc_type,';
2097 $sql .= ' doc_ref, fk_doc, fk_docdet, entity, thirdparty_code, subledger_account, subledger_label,';
2098 $sql .= ' numero_compte, label_compte, label_operation, debit, credit,';
2099 $sql .= ' montant, sens, fk_user_author, import_key, code_journal, journal_label, '.((int) $next_piecenum).", '".$this->db->idate($now)."'";
2100 $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);
2101 $sql .= $sql_filter;
2102 $resql = $this->db->query($sql);
2103 if (!$resql) {
2104 $error++;
2105 $this->errors[] = 'Error '.$this->db->lasterror();
2106 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
2107 }
2108 }
2109
2110 if (!$error) {
2111 $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.'_tmp WHERE piece_num = '.((int) $piece_num).' AND entity = ' .((int) $conf->entity);
2112 $resql = $this->db->query($sql);
2113 if (!$resql) {
2114 $error++;
2115 $this->errors[] = 'Error '.$this->db->lasterror();
2116 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
2117 }
2118 }
2119 } elseif ($direction == 1) {
2120 if (!$error) {
2121 $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.'_tmp WHERE piece_num = '.((int) $piece_num).' AND entity = ' .((int) $conf->entity);
2122 $resql = $this->db->query($sql);
2123 if (!$resql) {
2124 $error++;
2125 $this->errors[] = 'Error '.$this->db->lasterror();
2126 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
2127 }
2128 }
2129
2130 if (!$error) {
2131 $sql = 'INSERT INTO '.MAIN_DB_PREFIX.$this->table_element.'_tmp (doc_date, doc_type,';
2132 $sql .= ' doc_ref, fk_doc, fk_docdet, thirdparty_code, subledger_account, subledger_label,';
2133 $sql .= ' numero_compte, label_compte, label_operation, debit, credit,';
2134 $sql .= ' montant, sens, fk_user_author, import_key, code_journal, journal_label, piece_num)';
2135 $sql .= ' SELECT doc_date, doc_type,';
2136 $sql .= ' doc_ref, fk_doc, fk_docdet, thirdparty_code, subledger_account, subledger_label,';
2137 $sql .= ' numero_compte, label_compte, label_operation, debit, credit,';
2138 $sql .= ' montant, sens, fk_user_author, import_key, code_journal, journal_label, piece_num';
2139 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' WHERE piece_num = '.((int) $piece_num).' AND entity = ' .((int) $conf->entity);
2140 $sql .= $sql_filter;
2141 $resql = $this->db->query($sql);
2142 if (!$resql) {
2143 $error++;
2144 $this->errors[] = 'Error '.$this->db->lasterror();
2145 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
2146 }
2147 }
2148
2149 if (!$error) {
2150 $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.'_tmp WHERE piece_num = '.((int) $piece_num).' AND entity = ' .((int) $conf->entity);
2151 $sql .= $sql_filter;
2152 $resql = $this->db->query($sql);
2153 if (!$resql) {
2154 $error++;
2155 $this->errors[] = 'Error '.$this->db->lasterror();
2156 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
2157 }
2158 }
2159 }
2160 if (!$error) {
2161 $this->db->commit();
2162 return 1;
2163 } else {
2164 $this->db->rollback();
2165 return -1;
2166 }
2167 /*
2168 $sql = "DELETE FROM ";
2169 $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping as ab";
2170 $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "accounting_account as aa ON aa.account_number = ab.numero_compte";
2171 $sql .= " AND aa.active = 1";
2172 $sql .= " INNER JOIN " . MAIN_DB_PREFIX . "accounting_system as asy ON aa.fk_pcg_version = asy.pcg_version";
2173 $sql .= " AND asy.rowid = " . ((int) $pcgver);
2174 $sql .= " AND ab.entity IN (" . getEntity('accountancy') . ")";
2175 $sql .= " ORDER BY account_number ASC";
2176 */
2177 }
2178
2179 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2192 public function select_account($selectid, $htmlname = 'account', $showempty = 0, $event = array(), $select_in = 0, $select_out = 0, $aabase = '')
2193 {
2194 // phpcs:enable
2195 global $conf;
2196
2197 require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php';
2198
2199 $pcgver = getDolGlobalInt('CHARTOFACCOUNTS');
2200
2201 $sql = "SELECT DISTINCT ab.numero_compte as account_number, aa.label as label, aa.rowid as rowid, aa.fk_pcg_version";
2202 $sql .= " FROM ".MAIN_DB_PREFIX."accounting_bookkeeping as ab";
2203 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."accounting_account as aa ON aa.account_number = ab.numero_compte";
2204 $sql .= " AND aa.active = 1";
2205 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."accounting_system as asy ON aa.fk_pcg_version = asy.pcg_version";
2206 $sql .= " AND asy.rowid = ".((int) $pcgver);
2207 $sql .= " AND ab.entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
2208 $sql .= " ORDER BY account_number ASC";
2209
2210 dol_syslog(get_class($this)."::select_account", LOG_DEBUG);
2211 $resql = $this->db->query($sql);
2212
2213 if (!$resql) {
2214 $this->error = "Error ".$this->db->lasterror();
2215 dol_syslog(get_class($this)."::select_account ".$this->error, LOG_ERR);
2216 return "-1";
2217 }
2218
2219 $out = ajax_combobox($htmlname, $event);
2220
2221 $options = array();
2222 $selected = null;
2223
2224 while ($obj = $this->db->fetch_object($resql)) {
2225 $label = length_accountg($obj->account_number).' - '.$obj->label;
2226
2227 $select_value_in = $obj->rowid;
2228 $select_value_out = $obj->rowid;
2229
2230 if ($select_in == 1) {
2231 $select_value_in = $obj->account_number;
2232 }
2233 if ($select_out == 1) {
2234 $select_value_out = $obj->account_number;
2235 }
2236
2237 // Remember guy's we store in database llx_facturedet the rowid of accounting_account and not the account_number
2238 // Because same account_number can be share between different accounting_system and do have the same meaning
2239 if (($selectid != '') && $selectid == $select_value_in) {
2240 $selected = $select_value_out;
2241 }
2242
2243 $options[$select_value_out] = $label;
2244 }
2245
2246 $out .= Form::selectarray($htmlname, $options, $selected, $showempty, 0, 0, '', 0, 0, 0, '', 'maxwidth300');
2247 $this->db->free($resql);
2248 return $out;
2249 }
2250
2258 public function getRootAccount($account = null)
2259 {
2260 global $conf;
2261 $pcgver = getDolGlobalInt('CHARTOFACCOUNTS');
2262
2263 $sql = "SELECT root.rowid, root.account_number, root.label as label,";
2264 $sql .= " parent.rowid as parent_rowid, parent.account_number as parent_account_number, parent.label as parent_label";
2265 $sql .= " FROM ".MAIN_DB_PREFIX."accounting_account as aa";
2266 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."accounting_system as asy ON aa.fk_pcg_version = asy.pcg_version";
2267 $sql .= " AND asy.rowid = ".((int) $pcgver);
2268 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."accounting_account as parent ON aa.account_parent = parent.rowid AND parent.active = 1";
2269 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."accounting_account as root ON parent.account_parent = root.rowid AND root.active = 1";
2270 $sql .= " WHERE aa.account_number = '".$this->db->escape($account)."'";
2271 $sql .= " AND aa.entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
2272
2273 dol_syslog(get_class($this)."::select_account", LOG_DEBUG);
2274 $resql = $this->db->query($sql);
2275 if ($resql) {
2276 $obj = '';
2277 if ($this->db->num_rows($resql)) {
2278 $obj = $this->db->fetch_object($resql);
2279 }
2280
2281 $result = array('id' => $obj->rowid, 'account_number' => $obj->account_number, 'label' => $obj->label);
2282 return $result;
2283 } else {
2284 $this->error = "Error ".$this->db->lasterror();
2285 dol_syslog(__METHOD__." ".$this->error, LOG_ERR);
2286
2287 return -1;
2288 }
2289 }
2290
2291 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2298 public function get_compte_desc($account = null)
2299 {
2300 // phpcs:enable
2301 global $conf;
2302
2303 $pcgver = getDolGlobalInt('CHARTOFACCOUNTS');
2304 $sql = "SELECT aa.account_number, aa.label, aa.rowid, aa.fk_pcg_version, cat.label as category";
2305 $sql .= " FROM ".MAIN_DB_PREFIX."accounting_account as aa ";
2306 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."accounting_system as asy ON aa.fk_pcg_version = asy.pcg_version";
2307 $sql .= " AND aa.account_number = '".$this->db->escape($account)."'";
2308 $sql .= " AND asy.rowid = ".((int) $pcgver);
2309 $sql .= " AND aa.active = 1";
2310 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_accounting_category as cat ON aa.fk_accounting_category = cat.rowid";
2311 $sql .= " WHERE aa.entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
2312
2313 dol_syslog(get_class($this)."::select_account", LOG_DEBUG);
2314 $resql = $this->db->query($sql);
2315 if ($resql) {
2316 $obj = '';
2317 if ($this->db->num_rows($resql)) {
2318 $obj = $this->db->fetch_object($resql);
2319 }
2320 if (empty($obj->category)) {
2321 return $obj->label;
2322 } else {
2323 return $obj->label.' ('.$obj->category.')';
2324 }
2325 } else {
2326 $this->error = "Error ".$this->db->lasterror();
2327 dol_syslog(__METHOD__." ".$this->error, LOG_ERR);
2328 return "-1";
2329 }
2330 }
2331
2339 public function getCanModifyBookkeepingSQL($alias = '', $force = false)
2340 {
2341 global $conf;
2342
2343 $alias = trim($alias);
2344 $alias = !empty($alias) && strpos($alias, '.') < 0 ? $alias . "." : $alias;
2345
2346 if (!isset(self::$can_modify_bookkeeping_sql_cached[$alias]) || $force) {
2347 $result = $this->loadFiscalPeriods($force, 'active');
2348 if ($result < 0) {
2349 return null;
2350 }
2351
2352 $sql_list = array();
2353 if (!empty($conf->cache['active_fiscal_period_cached']) && is_array($conf->cache['active_fiscal_period_cached'])) {
2354 $i = 0;
2355 foreach ($conf->cache['active_fiscal_period_cached'] as $fiscal_period) {
2356 $sql_list[$i] = "(";
2357 $sql_list[$i] .= "'".$this->db->idate($fiscal_period['date_start']) . "' <= ".$this->db->sanitize($alias)."doc_date";
2358 if (!empty($fiscal_period['date_end'])) {
2359 $sql_list[$i] .= " AND ";
2360 $sql_list[$i] .= $this->db->sanitize($alias)."doc_date <= '" . $this->db->idate($fiscal_period['date_end'])."'";
2361 }
2362 $sql_list[$i] .= ")";
2363 $i++;
2364 }
2365 }
2366 $sqlsanitized = implode(' OR ', $sql_list);
2367 self::$can_modify_bookkeeping_sql_cached[$alias] = empty($sql_list) ? "" : " AND (".$sqlsanitized.")";
2368 }
2369
2370 return self::$can_modify_bookkeeping_sql_cached[$alias];
2371 }
2372
2380 public function canModifyBookkeeping($id, $mode = '')
2381 {
2382 global $conf;
2383
2384 if (getDolGlobalString('ACCOUNTANCY_FISCAL_PERIOD_MODE') == 'blockedonclosed') {
2385 $result = $this->loadFiscalPeriods(false, 'closed');
2386
2387 if ($result < 0) {
2388 return -1;
2389 }
2390
2391 $bookkeeping = new BookKeeping($this->db);
2392 $result = $bookkeeping->fetch($id, null, $mode);
2393 if ($result <= 0) {
2394 return $result;
2395 }
2396
2397 if (!empty($conf->cache['closed_fiscal_period_cached']) && is_array($conf->cache['closed_fiscal_period_cached'])) {
2398 foreach ($conf->cache['closed_fiscal_period_cached'] as $fiscal_period) {
2399 if ($fiscal_period['date_start'] <= $bookkeeping->doc_date && $bookkeeping->doc_date <= $fiscal_period['date_end']) {
2400 return 0;
2401 }
2402 }
2403 }
2404
2405 return 1;
2406 } else {
2407 $result = $this->loadFiscalPeriods(false, 'active');
2408 if ($result < 0) {
2409 return -1;
2410 }
2411
2412 $bookkeeping = new BookKeeping($this->db);
2413 $result = $bookkeeping->fetch($id, null, $mode);
2414
2415 if ($result <= 0) {
2416 return $result;
2417 }
2418 if (!empty($conf->cache['active_fiscal_period_cached']) && is_array($conf->cache['active_fiscal_period_cached'])) {
2419 foreach ($conf->cache['active_fiscal_period_cached'] as $fiscal_period) {
2420 if (!empty($fiscal_period['date_start']) && $fiscal_period['date_start'] <= $bookkeeping->doc_date && (empty($fiscal_period['date_end']) || $bookkeeping->doc_date <= $fiscal_period['date_end'])) {
2421 return 1;
2422 }
2423 }
2424 }
2425
2426 return 0;
2427 }
2428 }
2429
2436 public function validBookkeepingDate($date)
2437 {
2438 global $conf;
2439
2440 if (getDolGlobalString('ACCOUNTANCY_FISCAL_PERIOD_MODE') == 'blockedonclosed') {
2441 $result = $this->loadFiscalPeriods(false, 'closed');
2442
2443 if ($result < 0) {
2444 return -1;
2445 }
2446
2447 if (!empty($conf->cache['closed_fiscal_period_cached']) && is_array($conf->cache['closed_fiscal_period_cached'])) {
2448 foreach ($conf->cache['closed_fiscal_period_cached'] as $fiscal_period) {
2449 if ($fiscal_period['date_start'] <= $date && $date <= $fiscal_period['date_end']) {
2450 return 0;
2451 }
2452 }
2453 }
2454
2455 return 1;
2456 } else {
2457 $result = $this->loadFiscalPeriods(false, 'active');
2458 if ($result < 0) {
2459 return -1;
2460 }
2461
2462 if (!empty($conf->cache['active_fiscal_period_cached']) && is_array($conf->cache['active_fiscal_period_cached'])) {
2463 foreach ($conf->cache['active_fiscal_period_cached'] as $fiscal_period) {
2464 if (!empty($fiscal_period['date_start']) && $fiscal_period['date_start'] <= $date && (empty($fiscal_period['date_end']) || $date <= $fiscal_period['date_end'])) {
2465 return 1;
2466 }
2467 }
2468 }
2469
2470 return 0;
2471 }
2472 }
2473
2481 public function loadFiscalPeriods($force = false, $mode = 'active')
2482 {
2483 global $conf;
2484
2485 if ($mode == 'active') {
2486 if (!isset($conf->cache['active_fiscal_period_cached']) || $force) {
2487 $sql = "SELECT date_start, date_end";
2488 $sql .= " FROM " . $this->db->prefix() . "accounting_fiscalyear";
2489 $sql .= " WHERE entity = " . ((int) $conf->entity);
2490 $sql .= " AND statut = 0";
2491
2492 $resql = $this->db->query($sql);
2493 if (!$resql) {
2494 $this->errors[] = $this->db->lasterror();
2495 return -1;
2496 }
2497
2498 $list = array();
2499 while ($obj = $this->db->fetch_object($resql)) {
2500 $list[] = array(
2501 'date_start' => $this->db->jdate($obj->date_start),
2502 'date_end' => $this->db->jdate($obj->date_end),
2503 );
2504 }
2505 $conf->cache['active_fiscal_period_cached'] = $list;
2506 }
2507 }
2508 if ($mode == 'closed') {
2509 if (!isset($conf->cache['closed_fiscal_period_cached']) || $force) {
2510 $sql = "SELECT date_start, date_end";
2511 $sql .= " FROM " . $this->db->prefix() . "accounting_fiscalyear";
2512 $sql .= " WHERE entity = " . ((int) $conf->entity);
2513 $sql .= " AND statut = 1";
2514
2515 $resql = $this->db->query($sql);
2516 if (!$resql) {
2517 $this->errors[] = $this->db->lasterror();
2518 return -1;
2519 }
2520
2521 $list = array();
2522 while ($obj = $this->db->fetch_object($resql)) {
2523 $list[] = array(
2524 'date_start' => $this->db->jdate($obj->date_start),
2525 'date_end' => $this->db->jdate($obj->date_end),
2526 );
2527 }
2528 $conf->cache['closed_fiscal_period_cached'] = $list;
2529 }
2530 }
2531
2532 return 1;
2533 }
2534
2541 public function getFiscalPeriods($filter = '')
2542 {
2543 global $conf;
2544 $list = array();
2545
2546 $sql = "SELECT rowid, label, date_start, date_end, statut";
2547 $sql .= " FROM " . $this->db->prefix() . "accounting_fiscalyear";
2548 $sql .= " WHERE entity = " . ((int) $conf->entity);
2549 if (!empty($filter)) {
2550 $sql .= " AND (" . $this->db->sanitize($filter, 1, 1, 1) . ')';
2551 }
2552 $sql .= $this->db->order('date_start', 'ASC');
2553
2554 $resql = $this->db->query($sql);
2555 if (!$resql) {
2556 $this->errors[] = $this->db->lasterror();
2557 return -1;
2558 }
2559
2560 while ($obj = $this->db->fetch_object($resql)) {
2561 $list[$obj->rowid] = array(
2562 'id' => (int) $obj->rowid,
2563 'label' => $obj->label,
2564 'date_start' => $this->db->jdate($obj->date_start),
2565 'date_end' => $this->db->jdate($obj->date_end),
2566 'status' => (int) $obj->statut,
2567 );
2568 }
2569
2570 return $list;
2571 }
2572
2580 public function getCountByMonthForFiscalPeriod($date_start, $date_end)
2581 {
2582 $total = 0;
2583 $list = array();
2584
2585 $sql = "SELECT YEAR(b.doc_date) as year";
2586 for ($i = 1; $i <= 12; $i++) {
2587 $sql .= ", SUM(".$this->db->ifsql("MONTH(b.doc_date) = ".((int) $i), "1", "0") . ") AS month".((int) $i);
2588 }
2589 $sql .= ", COUNT(b.rowid) as total";
2590 $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping as b";
2591 $sql .= " WHERE b.doc_date >= '" . $this->db->idate($date_start) . "'";
2592 $sql .= " AND b.doc_date <= '" . $this->db->idate($date_end) . "'";
2593 $sql .= " AND b.entity IN (" . getEntity('bookkeeping', 0) . ")"; // We don't share object for accountancy
2594
2595 // Get count for each month into the fiscal period
2596 if (getDolGlobalString("ACCOUNTANCY_DISABLE_CLOSURE_LINE_BY_LINE")) {
2597 // TODO Analyse is done by finding record not into a closed period
2598 // Loop on each closed period
2599 $sql .= " AND b.doc_date BETWEEN 0 AND 0";
2600 } else {
2601 // Analyse closed record using the unitary flag/date on each record
2602 $sql .= " AND date_validated IS NULL";
2603 }
2604
2605 $sql .= " GROUP BY YEAR(b.doc_date)";
2606 $sql .= $this->db->order("year", 'ASC');
2607
2608 dol_syslog(__METHOD__, LOG_DEBUG);
2609 $resql = $this->db->query($sql);
2610 if (!$resql) {
2611 $this->errors[] = $this->db->lasterror();
2612 return -1;
2613 }
2614
2615 while ($obj = $this->db->fetch_object($resql)) {
2616 $total += (int) $obj->total;
2617 $year_list = array(
2618 'year' => (int) $obj->year,
2619 'count' => array(),
2620 'total' => (int) $obj->total,
2621 );
2622 for ($i = 1; $i <= 12; $i++) {
2623 $year_list['count'][$i] = (int) $obj->{'month' . $i};
2624 }
2625
2626 $list[] = $year_list;
2627 }
2628
2629 $this->db->free($resql);
2630
2631 return array(
2632 'total' => $total,
2633 'list' => $list,
2634 );
2635 }
2636
2644 public function validateMovementForFiscalPeriod($date_start, $date_end)
2645 {
2646 global $conf;
2647
2648 $now = dol_now();
2649
2650 // Specify as export : update field date_validated on selected month/year
2651 $sql = " UPDATE " . MAIN_DB_PREFIX . "accounting_bookkeeping";
2652 $sql .= " SET date_validated = '" . $this->db->idate($now) . "'";
2653 $sql .= " WHERE entity = " . ((int) $conf->entity);
2654 $sql .= " AND DATE(doc_date) >= '" . $this->db->idate($date_start) . "'";
2655 $sql .= " AND DATE(doc_date) <= '" . $this->db->idate($date_end) . "'";
2656 $sql .= " AND date_validated IS NULL";
2657
2658 dol_syslog(__METHOD__, LOG_DEBUG);
2659 $resql = $this->db->query($sql);
2660 if (!$resql) {
2661 $this->errors[] = $this->db->lasterror();
2662 return -1;
2663 }
2664
2665 return 1;
2666 }
2667
2675 public function accountingResult($date_start, $date_end)
2676 {
2677 global $conf;
2678
2679 $this->db->begin();
2680
2681 $income_statement_amount = 0;
2682
2683 if (getDolGlobalString('ACCOUNTING_CLOSURE_ACCOUNTING_GROUPS_USED_FOR_INCOME_STATEMENT')) {
2684 $accounting_groups_used_for_income_statement = array_filter(array_map('trim', explode(',', getDolGlobalString('ACCOUNTING_CLOSURE_ACCOUNTING_GROUPS_USED_FOR_INCOME_STATEMENT'))), 'strlen');
2685
2686 $pcg_type_filter = array();
2687 foreach ($accounting_groups_used_for_income_statement as $item) {
2688 $pcg_type_filter[] = "'" . $this->db->escape($item) . "'";
2689 }
2690
2691 $sql = 'SELECT';
2692 $sql .= " t.numero_compte,";
2693 $sql .= " aa.pcg_type,";
2694 $sql .= " (SUM(t.credit) - SUM(t.debit)) as accounting_result";
2695 $sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . ' as t';
2696 $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'accounting_account as aa ON aa.account_number = t.numero_compte';
2697 $sql .= ' WHERE t.entity = ' . ((int) $conf->entity); // Do not use getEntity for accounting features
2698 $sql .= " AND aa.entity = " . ((int) $conf->entity);
2699 $sql .= ' AND aa.fk_pcg_version IN (SELECT pcg_version FROM ' . MAIN_DB_PREFIX . 'accounting_system WHERE rowid = ' . ((int) getDolGlobalInt('CHARTOFACCOUNTS')) . ')';
2700 $sql .= ' AND aa.pcg_type IN (' . $this->db->sanitize(implode(',', $pcg_type_filter), 1) . ')';
2701 $sql .= " AND DATE(t.doc_date) >= '" . $this->db->idate($date_start) . "'";
2702 $sql .= " AND DATE(t.doc_date) <= '" . $this->db->idate($date_end) . "'";
2703 $sql .= ' GROUP BY t.numero_compte, aa.pcg_type';
2704
2705 $resql = $this->db->query($sql);
2706 if (!$resql) {
2707 $this->errors[] = 'Error ' . $this->db->lasterror();
2708 dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
2709 } else {
2710 while ($obj = $this->db->fetch_object($resql)) {
2711 $income_statement_amount += $obj->accounting_result;
2712 }
2713 }
2714 }
2715
2716 return (string) $income_statement_amount;
2717 }
2718
2728 public function closeFiscalPeriod($fiscal_period_id, $new_fiscal_period_id, $separate_auxiliary_account = false, $generate_bookkeeping_records = true)
2729 {
2730 global $conf, $langs, $user;
2731
2732 // Current fiscal period
2733 $fiscal_period_id = max(0, $fiscal_period_id);
2734 if (empty($fiscal_period_id)) {
2735 $langs->load('errors');
2736 $this->errors[] = $langs->trans('ErrorBadParameters');
2737 return -1;
2738 }
2739 $fiscal_period = new Fiscalyear($this->db);
2740 $result = $fiscal_period->fetch($fiscal_period_id);
2741 if ($result < 0) {
2742 $this->error = $fiscal_period->error;
2743 $this->errors = $fiscal_period->errors;
2744 return -1;
2745 } elseif (empty($fiscal_period->id)) {
2746 $langs->loadLangs(array('errors', 'compta'));
2747 $this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('FiscalPeriod') . ' (' . $fiscal_period_id . ')';
2748 return -1;
2749 }
2750
2751 // New fiscal period
2752 $new_fiscal_period_id = max(0, $new_fiscal_period_id);
2753 if (empty($new_fiscal_period_id)) {
2754 $langs->load('errors');
2755 $this->errors[] = $langs->trans('ErrorBadParameters');
2756 return -1;
2757 }
2758 $new_fiscal_period = new Fiscalyear($this->db);
2759 $result = $new_fiscal_period->fetch($new_fiscal_period_id);
2760 if ($result < 0) {
2761 $this->error = $new_fiscal_period->error;
2762 $this->errors = $new_fiscal_period->errors;
2763 return -1;
2764 } elseif (empty($new_fiscal_period->id)) {
2765 $langs->loadLangs(array('errors', 'compta'));
2766 $this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('FiscalPeriod') . ' (' . $new_fiscal_period_id . ')';
2767 return -1;
2768 }
2769
2770 $error = 0;
2771 $this->db->begin();
2772
2773 $fiscal_period->statut = Fiscalyear::STATUS_CLOSED;
2774 $fiscal_period->status = Fiscalyear::STATUS_CLOSED; // Actually not used
2775 $result = $fiscal_period->update($user);
2776 if ($result < 0) {
2777 $this->error = $fiscal_period->error;
2778 $this->errors = $fiscal_period->errors;
2779 $error++;
2780 }
2781
2782 if (!$error && !empty($generate_bookkeeping_records)) {
2783 $journal_id = max(0, getDolGlobalString('ACCOUNTING_CLOSURE_DEFAULT_JOURNAL'));
2784 if (empty($journal_id)) {
2785 $langs->loadLangs(array('errors', 'accountancy'));
2786 $this->errors[] = $langs->trans('ErrorBadParameters') . ' - ' . $langs->trans('Codejournal') . ' (' . $langs->trans('AccountingJournalType9') . ')';
2787 $error++;
2788 }
2789
2790 // Fetch journal
2791 if (!$error) {
2792 $journal = new AccountingJournal($this->db);
2793 $result = $journal->fetch($journal_id);
2794 if ($result < 0) {
2795 $this->error = $journal->error;
2796 $this->errors = $journal->errors;
2797 $error++;
2798 } elseif ($result == 0) {
2799 $langs->loadLangs(array('errors', 'accountancy'));
2800 $this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('Codejournal') . ' (' . $langs->trans('AccountingJournalType9') . ')';
2801 $error++;
2802 }
2803 }
2804
2805 if (!$error) {
2806 $accounting_groups_used_for_balance_sheet_account = array_filter(array_map('trim', explode(',', getDolGlobalString('ACCOUNTING_CLOSURE_ACCOUNTING_GROUPS_USED_FOR_BALANCE_SHEET_ACCOUNT'))), 'strlen');
2807 $accounting_groups_used_for_income_statement = array_filter(array_map('trim', explode(',', getDolGlobalString('ACCOUNTING_CLOSURE_ACCOUNTING_GROUPS_USED_FOR_INCOME_STATEMENT'))), 'strlen');
2808
2809 $pcg_type_filter = array();
2810 $tmp = array_merge($accounting_groups_used_for_balance_sheet_account, $accounting_groups_used_for_income_statement);
2811 foreach ($tmp as $item) {
2812 $pcg_type_filter[] = "'" . $this->db->escape($item) . "'";
2813 }
2814
2815 $sql = 'SELECT';
2816 $sql .= " t.numero_compte,";
2817 $sql .= " t.label_compte,";
2818 if ($separate_auxiliary_account) {
2819 $sql .= " t.subledger_account,";
2820 $sql .= " t.subledger_label,";
2821 }
2822 $sql .= " aa.pcg_type,";
2823 $sql .= " (SUM(t.credit) - SUM(t.debit)) as opening_balance";
2824 $sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . ' as t';
2825 $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'accounting_account as aa ON aa.account_number = t.numero_compte';
2826 $sql .= ' WHERE t.entity = ' . ((int) $conf->entity); // Do not use getEntity for accounting features
2827 $sql .= " AND aa.entity = ". ((int) $conf->entity);
2828 $sql .= ' AND aa.fk_pcg_version IN (SELECT pcg_version FROM '.MAIN_DB_PREFIX.'accounting_system WHERE rowid = '.((int) getDolGlobalInt('CHARTOFACCOUNTS')).')';
2829 $sql .= ' AND aa.pcg_type IN (' . $this->db->sanitize(implode(',', $pcg_type_filter), 1) . ')';
2830 $sql .= " AND DATE(t.doc_date) >= '" . $this->db->idate($fiscal_period->date_start) . "'";
2831 $sql .= " AND DATE(t.doc_date) <= '" . $this->db->idate($fiscal_period->date_end) . "'";
2832 $sql .= ' GROUP BY t.numero_compte, t.label_compte, aa.pcg_type';
2833 if ($separate_auxiliary_account) {
2834 $sql .= ' ,t.subledger_account, t.subledger_label';
2835 }
2836 $sql .= $this->db->order("t.numero_compte", "ASC");
2837
2838 $resql = $this->db->query($sql);
2839 if (!$resql) {
2840 $this->errors[] = 'Error ' . $this->db->lasterror();
2841 dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
2842
2843 $error++;
2844 } else {
2845 $now = dol_now();
2846 $income_statement_amount = 0;
2847 while ($obj = $this->db->fetch_object($resql)) {
2848 if (in_array($obj->pcg_type, $accounting_groups_used_for_income_statement)) {
2849 $income_statement_amount += $obj->opening_balance;
2850 } else {
2851 // Insert bookkeeping record for balance sheet account
2852 $mt = $obj->opening_balance;
2853
2854 $bookkeeping = new BookKeeping($this->db);
2855 $bookkeeping->doc_date = $new_fiscal_period->date_start;
2856 $bookkeeping->date_lim_reglement = 0;
2857 $bookkeeping->doc_ref = $new_fiscal_period->label;
2858 $bookkeeping->date_creation = $now;
2859 $bookkeeping->doc_type = 'closure';
2860 $bookkeeping->fk_doc = $new_fiscal_period->id;
2861 $bookkeeping->fk_docdet = 0; // Useless, can be several lines that are source of this record to add
2862 $bookkeeping->thirdparty_code = '';
2863
2864 if ($separate_auxiliary_account) {
2865 $bookkeeping->subledger_account = $obj->subledger_account;
2866 $bookkeeping->subledger_label = $obj->subledger_label;
2867 } else {
2868 $bookkeeping->subledger_account = '';
2869 $bookkeeping->subledger_label = '';
2870 }
2871
2872 $bookkeeping->numero_compte = $obj->numero_compte;
2873 $bookkeeping->label_compte = $obj->label_compte;
2874
2875 $bookkeeping->label_operation = $new_fiscal_period->label;
2876 $bookkeeping->montant = $mt;
2877 $bookkeeping->sens = ($mt >= 0) ? 'C' : 'D';
2878 $bookkeeping->debit = ($mt < 0) ? -$mt : 0;
2879 $bookkeeping->credit = ($mt >= 0) ? $mt : 0;
2880 $bookkeeping->code_journal = $journal->code;
2881 $bookkeeping->journal_label = $langs->transnoentities($journal->label);
2882 $bookkeeping->fk_user_author = $user->id;
2883 $bookkeeping->entity = $conf->entity;
2884
2885 $result = $bookkeeping->create($user);
2886 if ($result < 0) {
2887 $this->error = $bookkeeping->error;
2888 $this->errors = $bookkeeping->errors;
2889 $error++;
2890 break;
2891 }
2892 }
2893 }
2894
2895 // Insert bookkeeping record for income statement
2896 if (!$error && $income_statement_amount != 0) {
2897 $mt = $income_statement_amount;
2898 $accountingaccount = new AccountingAccount($this->db);
2899 $accountingaccount->fetch(null, getDolGlobalString($income_statement_amount < 0 ? 'ACCOUNTING_RESULT_LOSS' : 'ACCOUNTING_RESULT_PROFIT'), true);
2900
2901 $bookkeeping = new BookKeeping($this->db);
2902 $bookkeeping->doc_date = $new_fiscal_period->date_start;
2903 $bookkeeping->date_lim_reglement = 0;
2904 $bookkeeping->doc_ref = $new_fiscal_period->label;
2905 $bookkeeping->date_creation = $now;
2906 $bookkeeping->doc_type = 'closure';
2907 $bookkeeping->fk_doc = $new_fiscal_period->id;
2908 $bookkeeping->fk_docdet = 0; // Useless, can be several lines that are source of this record to add
2909 $bookkeeping->thirdparty_code = '';
2910
2911 if ($separate_auxiliary_account) {
2912 $bookkeeping->subledger_label = '';
2913 $bookkeeping->subledger_account = $obj->subledger_account;
2914 $bookkeeping->subledger_label = $obj->subledger_label;
2915 } else {
2916 $bookkeeping->subledger_account = '';
2917 $bookkeeping->subledger_label = '';
2918 }
2919
2920 $bookkeeping->numero_compte = $accountingaccount->account_number;
2921 $bookkeeping->label_compte = $accountingaccount->label;
2922
2923 $bookkeeping->label_operation = $new_fiscal_period->label;
2924 $bookkeeping->montant = $mt;
2925 $bookkeeping->sens = ($mt >= 0) ? 'C' : 'D';
2926 $bookkeeping->debit = ($mt < 0) ? -$mt : 0;
2927 $bookkeeping->credit = ($mt >= 0) ? $mt : 0;
2928 $bookkeeping->code_journal = $journal->code;
2929 $bookkeeping->journal_label = $langs->transnoentities($journal->label);
2930 $bookkeeping->fk_user_author = $user->id;
2931 $bookkeeping->entity = $conf->entity;
2932
2933 $result = $bookkeeping->create($user);
2934 if ($result < 0) {
2935 $this->error = $bookkeeping->error;
2936 $this->errors = $bookkeeping->errors;
2937 $error++;
2938 }
2939 }
2940 $this->db->free($resql);
2941 }
2942 }
2943 }
2944
2945 if ($error) {
2946 $this->db->rollback();
2947 return -1;
2948 } else {
2949 $this->db->commit();
2950 return 1;
2951 }
2952 }
2953
2964 public function insertAccountingReversal($fiscal_period_id, $inventory_journal_id, $new_fiscal_period_id, $date_start, $date_end)
2965 {
2966 global $conf, $langs, $user;
2967
2968 // Current fiscal period
2969 $fiscal_period_id = max(0, $fiscal_period_id);
2970 if (empty($fiscal_period_id)) {
2971 $langs->load('errors');
2972 $this->errors[] = $langs->trans('ErrorBadParameters');
2973 return -1;
2974 }
2975 $fiscal_period = new Fiscalyear($this->db);
2976 $result = $fiscal_period->fetch($fiscal_period_id);
2977 if ($result < 0) {
2978 $this->error = $fiscal_period->error;
2979 $this->errors = $fiscal_period->errors;
2980 return -1;
2981 } elseif (empty($fiscal_period->id)) {
2982 $langs->loadLangs(array('errors', 'compta'));
2983 $this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('FiscalPeriod') . ' (' . $fiscal_period_id . ')';
2984 return -1;
2985 }
2986
2987 // New fiscal period
2988 $new_fiscal_period_id = max(0, $new_fiscal_period_id);
2989 if (empty($new_fiscal_period_id)) {
2990 $langs->load('errors');
2991 $this->errors[] = $langs->trans('ErrorBadParameters');
2992 return -1;
2993 }
2994 $new_fiscal_period = new Fiscalyear($this->db);
2995 $result = $new_fiscal_period->fetch($new_fiscal_period_id);
2996 if ($result < 0) {
2997 $this->error = $new_fiscal_period->error;
2998 $this->errors = $new_fiscal_period->errors;
2999 return -1;
3000 } elseif (empty($new_fiscal_period->id)) {
3001 $langs->loadLangs(array('errors', 'compta'));
3002 $this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('FiscalPeriod') . ' (' . $new_fiscal_period_id . ')';
3003 return -1;
3004 }
3005
3006 // Inventory journal
3007 $inventory_journal_id = max(0, $inventory_journal_id);
3008 if (empty($inventory_journal_id)) {
3009 $langs->load('errors');
3010 $this->errors[] = $langs->trans('ErrorBadParameters');
3011 return -1;
3012 }
3013 // Fetch journal
3014 $inventory_journal = new AccountingJournal($this->db);
3015 $result = $inventory_journal->fetch($inventory_journal_id);
3016 if ($result < 0) {
3017 $this->error = $inventory_journal->error;
3018 $this->errors = $inventory_journal->errors;
3019 return -1;
3020 } elseif ($result == 0) {
3021 $langs->loadLangs(array('errors', 'accountancy'));
3022 $this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('InventoryJournal');
3023 return -1;
3024 }
3025
3026 $error = 0;
3027 $this->db->begin();
3028
3029 $sql = 'SELECT t.rowid';
3030 $sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . ' as t';
3031 $sql .= ' WHERE t.entity = ' . ((int) $conf->entity); // Do not use getEntity for accounting features
3032 $sql .= " AND code_journal = '" . $this->db->escape($inventory_journal->code) . "'";
3033 $sql .= " AND DATE(t.doc_date) >= '" . $this->db->idate($date_start) . "'";
3034 $sql .= " AND DATE(t.doc_date) <= '" . $this->db->idate($date_end) . "'";
3035 $sql .= " AND DATE(t.doc_date) >= '" . $this->db->idate($fiscal_period->date_start) . "'";
3036 $sql .= " AND DATE(t.doc_date) <= '" . $this->db->idate($fiscal_period->date_end) . "'";
3037
3038 $resql = $this->db->query($sql);
3039 if (!$resql) {
3040 $this->errors[] = 'Error ' . $this->db->lasterror();
3041 dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
3042
3043 $error++;
3044 } else {
3045 $now = dol_now();
3046 while ($obj = $this->db->fetch_object($resql)) {
3047 $bookkeeping = new BookKeeping($this->db);
3048 $result = $bookkeeping->fetch($obj->rowid);
3049 if ($result < 0) {
3050 $this->error = $inventory_journal->error;
3051 $this->errors = $inventory_journal->errors;
3052 $error++;
3053 break;
3054 } elseif ($result == 0) {
3055 $langs->loadLangs(array('errors', 'accountancy'));
3056 $this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('LineId') . ': ' . $obj->rowid;
3057 $error++;
3058 break;
3059 }
3060
3061 $bookkeeping->id = 0;
3062 $bookkeeping->doc_date = $new_fiscal_period->date_start;
3063 $bookkeeping->doc_ref = $new_fiscal_period->label;
3064 $bookkeeping->date_creation = $now;
3065 $bookkeeping->doc_type = 'accounting_reversal';
3066 $bookkeeping->fk_doc = $new_fiscal_period->id;
3067 $bookkeeping->fk_docdet = 0; // Useless, can be several lines that are source of this record to add
3068
3069 $bookkeeping->montant = -$bookkeeping->montant;
3070 $bookkeeping->sens = ($bookkeeping->montant >= 0) ? 'C' : 'D';
3071 $old_debit = $bookkeeping->debit;
3072 $bookkeeping->debit = $bookkeeping->credit;
3073 $bookkeeping->credit = $old_debit;
3074
3075 $bookkeeping->fk_user_author = $user->id;
3076 $bookkeeping->entity = $conf->entity;
3077
3078 $result = $bookkeeping->create($user);
3079 if ($result < 0) {
3080 $this->error = $bookkeeping->error;
3081 $this->errors = $bookkeeping->errors;
3082 $error++;
3083 break;
3084 }
3085 }
3086 $this->db->free($resql);
3087 }
3088
3089 if ($error) {
3090 $this->db->rollback();
3091 return -1;
3092 } else {
3093 $this->db->commit();
3094 return 1;
3095 }
3096 }
3097}
3098
3103{
3107 public $id;
3108
3109 public $doc_date = null;
3110 public $doc_type;
3111 public $doc_ref;
3112
3116 public $fk_doc;
3117
3121 public $fk_docdet;
3122
3123 public $thirdparty_code;
3124 public $subledger_account;
3125 public $subledger_label;
3126 public $numero_compte;
3127 public $label_compte;
3128 public $label_operation;
3129 public $debit;
3130 public $credit;
3131
3136 public $montant;
3137
3141 public $amount;
3142
3146 public $multicurrency_amount;
3147
3151 public $multicurrency_code;
3152
3156 public $sens;
3157 public $lettering_code;
3158 public $date_lettering;
3159
3163 public $fk_user_author;
3164
3165 public $import_key;
3166 public $code_journal;
3167 public $journal_label;
3171 public $piece_num;
3172
3176 public $date_creation;
3177
3181 public $date_modification;
3182
3186 public $date_export;
3187
3191 public $date_validation;
3192
3196 public $date_lim_reglement;
3197}
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition card.php:58
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:456
Class to manage accounting accounts.
Class to manage accounting journals.
Class to manage Ledger (General Ledger and Subledger)
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.
fetchAllBalance($sortorder='', $sortfield='', $limit=0, $offset=0, $filter='', $filtermode='AND', $option=0)
Load object in memory from the 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.
getNextNumMvt($mode='')
Return next movement number.
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.
create(User $user, $notrigger=0)
Create object into database.
updateByMvt($piece_num='', $field='', $value='', $mode='')
Update accounting movement.
createStd(User $user, $notrigger=0, $mode='')
Create object into database.
update(User $user, $notrigger=0, $mode='')
Update object into database.
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.
fetchAll($sortorder='', $sortfield='', $limit=0, $offset=0, $filter='', $filtermode='AND', $showAlreadyExportMovements=1)
Load object in memory from the database.
accountingResult($date_start, $date_end)
Define accounting result.
canModifyBookkeeping($id, $mode='')
Is the bookkeeping can be modified or deleted ?
fetchAllPerMvt($piecenum, $mode='')
Load all accounting lines related to a given transaction ID $piecenum.
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,...
Parent class for class inheritance lines of business objects This class is useless for the moment so ...
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:378
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
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.
forgeSQLFromUniversalSearchCriteria($filter, &$errorstr='', $noand=0, $nopar=0, $noerror=0)
forgeSQLFromUniversalSearchCriteria
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.