dolibarr 20.0.5
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 * Copyright (C) 2024 Jose MARTINEZ <jose.martinez@pichinov.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 */
22
29// Class
30require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
31require_once DOL_DOCUMENT_ROOT.'/core/class/commonobjectline.class.php';
32require_once DOL_DOCUMENT_ROOT.'/core/class/fiscalyear.class.php';
33require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingjournal.class.php';
34require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingaccount.class.php';
35
40{
44 public $element = 'accountingbookkeeping';
45
49 public $table_element = 'accounting_bookkeeping';
50
54 public $entity;
55
59 public $lines = array();
60
64 public $id;
65
69 public $doc_date;
70
74 public $date_lim_reglement;
75
79 public $doc_type;
80
84 public $doc_ref;
85
89 public $fk_doc;
90
94 public $fk_docdet;
95
99 public $thirdparty_code;
100
104 public $subledger_account;
105
109 public $subledger_label;
110
114 public $numero_compte;
115
119 public $label_compte;
120
124 public $label_operation;
125
129 public $debit;
130
134 public $credit;
135
140 public $montant;
141
146 public $amount;
147
151 public $sens;
152
156 public $fk_user_author;
157
161 public $import_key;
162
166 public $code_journal;
167
171 public $journal_label;
172
176 public $piece_num;
177
181 public $linesmvt = array();
182
186 public $linesexport = array();
187
191 public $date_validation;
192
196 public $date_export;
197
201 public $picto = 'generic';
202
206 public static $can_modify_bookkeeping_sql_cached;
207
208
214 public function __construct(DoliDB $db)
215 {
216 $this->db = $db;
217 }
218
226 public function create(User $user, $notrigger = 0)
227 {
228 global $conf, $langs;
229
230 dol_syslog(__METHOD__, LOG_DEBUG);
231
232 $error = 0;
233
234 // Clean parameters</center>
235 if (isset($this->doc_type)) {
236 $this->doc_type = trim($this->doc_type);
237 }
238 if (isset($this->doc_ref)) {
239 $this->doc_ref = trim($this->doc_ref);
240 }
241 if (isset($this->fk_doc)) {
242 $this->fk_doc = (int) $this->fk_doc;
243 }
244 if (isset($this->fk_docdet)) {
245 $this->fk_docdet = (int) $this->fk_docdet;
246 }
247 if (isset($this->thirdparty_code)) {
248 $this->thirdparty_code = trim($this->thirdparty_code);
249 }
250 if (isset($this->subledger_account)) {
251 $this->subledger_account = trim($this->subledger_account);
252 }
253 if (isset($this->subledger_label)) {
254 $this->subledger_label = trim($this->subledger_label);
255 }
256 if (isset($this->numero_compte)) {
257 $this->numero_compte = trim($this->numero_compte);
258 }
259 if (isset($this->label_compte)) {
260 $this->label_compte = trim($this->label_compte);
261 }
262 if (isset($this->label_operation)) {
263 $this->label_operation = trim($this->label_operation);
264 }
265 if (isset($this->debit)) {
266 $this->debit = (float) $this->debit;
267 }
268 if (isset($this->credit)) {
269 $this->credit = (float) $this->credit;
270 }
271 if (isset($this->montant)) {
272 $this->montant = (float) $this->montant;
273 }
274 if (isset($this->amount)) {
275 $this->amount = (float) $this->amount;
276 }
277 if (isset($this->sens)) {
278 $this->sens = trim($this->sens);
279 }
280 if (isset($this->import_key)) {
281 $this->import_key = trim($this->import_key);
282 }
283 if (isset($this->code_journal)) {
284 $this->code_journal = trim($this->code_journal);
285 }
286 if (isset($this->journal_label)) {
287 $this->journal_label = trim($this->journal_label);
288 }
289 if (isset($this->piece_num)) {
290 $this->piece_num = (int) $this->piece_num;
291 }
292 if (empty($this->debit)) {
293 $this->debit = 0.0;
294 }
295 if (empty($this->credit)) {
296 $this->credit = 0.0;
297 }
298
299 $result = $this->validBookkeepingDate($this->doc_date);
300 if ($result < 0) {
301 return -1;
302 } elseif ($result == 0) {
303 if (getDolGlobalString('ACCOUNTANCY_FISCAL_PERIOD_MODE') == 'blockedonclosed') {
304 $this->errors[] = $langs->trans('ErrorBookkeepingDocDateIsOnAClosedFiscalPeriod');
305 } else {
306 $this->errors[] = $langs->trans('ErrorBookkeepingDocDateNotOnActiveFiscalPeriod');
307 }
308 return -1;
309 }
310
311 // Check parameters
312 if (($this->numero_compte == "") || $this->numero_compte == '-1' || $this->numero_compte == 'NotDefined') {
313 $langs->loadLangs(array("errors"));
314 if (in_array($this->doc_type, array('bank', 'expense_report'))) {
315 $this->errors[] = $langs->trans('ErrorFieldAccountNotDefinedForBankLine', $this->fk_docdet, $this->doc_type);
316 } else {
317 //$this->errors[]=$langs->trans('ErrorFieldAccountNotDefinedForInvoiceLine', $this->doc_ref, $this->label_compte);
318 $mesg = $this->doc_ref.', '.$langs->trans("AccountAccounting").': '.($this->numero_compte != -1 ? $this->numero_compte : $langs->trans("Unknown"));
319 if ($this->subledger_account && $this->subledger_account != $this->numero_compte) {
320 $mesg .= ', '.$langs->trans("SubledgerAccount").': '.$this->subledger_account;
321 }
322 $this->errors[] = $langs->trans('ErrorFieldAccountNotDefinedForLine', $mesg);
323 }
324
325 return -1;
326 }
327
328 $this->db->begin();
329
330 $this->piece_num = 0;
331
332 // First check if line not yet already in bookkeeping.
333 // Note that we must include 'doc_type - fk_doc - numero_compte - label - subledger_account (if not empty)' to be sure to have unicity of line (because we may have several lines
334 // with same doc_type, fk_doc, numero_compte for 1 invoice line when using localtaxes with same account)
335 // WARNING: This is not reliable, label may have been modified. This is just a small protection.
336 // The page that make transfer make the test on couple (doc_type - fk_doc) only.
337 $sql = "SELECT count(*) as nb";
338 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element;
339 $sql .= " WHERE doc_type = '".$this->db->escape($this->doc_type)."'";
340 $sql .= " AND fk_doc = ".((int) $this->fk_doc);
341 if (getDolGlobalString('ACCOUNTANCY_ENABLE_FKDOCDET')) {
342 // DO NOT USE THIS IN PRODUCTION. This will generate a lot of trouble into reports and will corrupt database (by generating duplicate entries.
343 $sql .= " AND fk_docdet = ".((int) $this->fk_docdet); // This field can be 0 if record is for several lines
344 }
345 $sql .= " AND numero_compte = '".$this->db->escape($this->numero_compte)."'";
346 $sql .= " AND label_operation = '".$this->db->escape($this->label_operation)."'";
347 if (!empty($this->subledger_account)) {
348 $sql .= " AND subledger_account = '".$this->db->escape($this->subledger_account)."'";
349 }
350 $sql .= " AND entity = ".$conf->entity; // Do not use getEntity for accounting features
351
352 $resql = $this->db->query($sql);
353
354 if ($resql) {
355 $row = $this->db->fetch_object($resql);
356 if ($row->nb == 0) { // Not already into bookkeeping
357 // Check to know if piece_num already exists for data we try to insert to reuse the same value
358 $sqlnum = "SELECT piece_num";
359 $sqlnum .= " FROM ".MAIN_DB_PREFIX.$this->table_element;
360 $sqlnum .= " WHERE doc_type = '".$this->db->escape($this->doc_type)."'"; // For example doc_type = 'bank'
361 $sqlnum .= " AND fk_doc = ".((int) $this->fk_doc);
362 if (getDolGlobalString('ACCOUNTANCY_ENABLE_FKDOCDET')) {
363 // fk_docdet is rowid into llx_bank or llx_facturedet or llx_facturefourndet, or ...
364 $sqlnum .= " AND fk_docdet = ".((int) $this->fk_docdet);
365 }
366 $sqlnum .= " AND doc_ref = '".$this->db->escape($this->doc_ref)."'"; // ref of source object
367 $sqlnum .= " AND entity = ".$conf->entity; // Do not use getEntity for accounting features
368
369 dol_syslog(get_class($this).":: create sqlnum=".$sqlnum, LOG_DEBUG);
370 $resqlnum = $this->db->query($sqlnum);
371 if ($resqlnum) {
372 $num = $this->db->num_rows($resqlnum);
373 if ($num > 0) {
374 $objnum = $this->db->fetch_object($resqlnum);
375 $this->piece_num = $objnum->piece_num;
376 } else {
377 $this->piece_num = 0;
378 }
379 }
380
381 dol_syslog(get_class($this)."::create this->piece_num=".$this->piece_num, LOG_DEBUG);
382 if (empty($this->piece_num)) {
383 $sqlnum = "SELECT MAX(piece_num)+1 as maxpiecenum";
384 $sqlnum .= " FROM ".MAIN_DB_PREFIX.$this->table_element;
385 $sqlnum .= " WHERE entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
386
387 $resqlnum = $this->db->query($sqlnum);
388 if ($resqlnum) {
389 $objnum = $this->db->fetch_object($resqlnum);
390 $this->piece_num = $objnum->maxpiecenum;
391 }
392 dol_syslog(get_class($this).":: create now this->piece_num=".$this->piece_num, LOG_DEBUG);
393 }
394 if (empty($this->piece_num)) {
395 $this->piece_num = 1;
396 }
397
398 $now = dol_now();
399
400 $sql = "INSERT INTO ".MAIN_DB_PREFIX.$this->table_element." (";
401 $sql .= "doc_date";
402 $sql .= ", date_lim_reglement";
403 $sql .= ", doc_type";
404 $sql .= ", doc_ref";
405 $sql .= ", fk_doc";
406 $sql .= ", fk_docdet";
407 $sql .= ", thirdparty_code";
408 $sql .= ", subledger_account";
409 $sql .= ", subledger_label";
410 $sql .= ", numero_compte";
411 $sql .= ", label_compte";
412 $sql .= ", label_operation";
413 $sql .= ", debit";
414 $sql .= ", credit";
415 $sql .= ", montant";
416 $sql .= ", sens";
417 $sql .= ", fk_user_author";
418 $sql .= ", date_creation";
419 $sql .= ", code_journal";
420 $sql .= ", journal_label";
421 $sql .= ", piece_num";
422 $sql .= ', entity';
423 $sql .= ") VALUES (";
424 $sql .= "'".$this->db->idate($this->doc_date)."'";
425 $sql .= ", ".(!isset($this->date_lim_reglement) || dol_strlen($this->date_lim_reglement) == 0 ? 'NULL' : "'".$this->db->idate($this->date_lim_reglement)."'");
426 $sql .= ", '".$this->db->escape($this->doc_type)."'";
427 $sql .= ", '".$this->db->escape($this->doc_ref)."'";
428 $sql .= ", ".((int) $this->fk_doc);
429 $sql .= ", ".((int) $this->fk_docdet);
430 $sql .= ", ".(!empty($this->thirdparty_code) ? ("'".$this->db->escape($this->thirdparty_code)."'") : "NULL");
431 $sql .= ", ".(!empty($this->subledger_account) ? ("'".$this->db->escape($this->subledger_account)."'") : "NULL");
432 $sql .= ", ".(!empty($this->subledger_label) ? ("'".$this->db->escape($this->subledger_label)."'") : "NULL");
433 $sql .= ", '".$this->db->escape($this->numero_compte)."'";
434 $sql .= ", ".(!empty($this->label_compte) ? ("'".$this->db->escape($this->label_compte)."'") : "NULL");
435 $sql .= ", '".$this->db->escape($this->label_operation)."'";
436 $sql .= ", ".((float) $this->debit);
437 $sql .= ", ".((float) $this->credit);
438 $sql .= ", ".((float) $this->montant);
439 $sql .= ", ".(!empty($this->sens) ? ("'".$this->db->escape($this->sens)."'") : "NULL");
440 $sql .= ", '".$this->db->escape($this->fk_user_author)."'";
441 $sql .= ", '".$this->db->idate($now)."'";
442 $sql .= ", '".$this->db->escape($this->code_journal)."'";
443 $sql .= ", ".(!empty($this->journal_label) ? ("'".$this->db->escape($this->journal_label)."'") : "NULL");
444 $sql .= ", ".((int) $this->piece_num);
445 $sql .= ", ".(!isset($this->entity) ? $conf->entity : $this->entity);
446 $sql .= ")";
447
448 $resql = $this->db->query($sql);
449 if ($resql) {
450 $id = $this->db->last_insert_id(MAIN_DB_PREFIX.$this->table_element);
451
452 if ($id > 0) {
453 $this->id = $id;
454 $result = 0;
455 } else {
456 $result = -2;
457 $error++;
458 $this->errors[] = 'Error Create Error '.$result.' lecture ID';
459 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
460 }
461 } else {
462 $result = -1;
463 $error++;
464 $this->errors[] = 'Error '.$this->db->lasterror();
465 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
466 }
467 } else { // Already exists
468 $result = -3;
469 $error++;
470 $this->error = 'BookkeepingRecordAlreadyExists';
471 dol_syslog(__METHOD__.' '.$this->error, LOG_WARNING);
472 }
473 } else {
474 $result = -5;
475 $error++;
476 $this->errors[] = 'Error '.$this->db->lasterror();
477 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
478 }
479
480 // Uncomment this and change MYOBJECT to your own tag if you
481 // want this action to call a trigger.
482 //if (! $error && ! $notrigger) {
483
484 // // Call triggers
485 // $result=$this->call_trigger('MYOBJECT_CREATE',$user);
486 // if ($result < 0) $error++;
487 // // End call triggers
488 //}
489
490 // Commit or rollback
491 if ($error) {
492 $this->db->rollback();
493 return -1 * $error;
494 } else {
495 $this->db->commit();
496 return $result;
497 }
498 }
499
510 public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
511 {
512 global $db, $conf, $langs;
513 global $dolibarr_main_authentication, $dolibarr_main_demo;
514 global $menumanager, $hookmanager;
515
516 if (!empty($conf->dol_no_mouse_hover)) {
517 $notooltip = 1; // Force disable tooltips
518 }
519
520 $result = '';
521 $companylink = '';
522
523 $label = '<u>'.$langs->trans("Transaction").'</u>';
524 $label .= '<br>';
525 $label .= '<b>'.$langs->trans('Ref').':</b> '.$this->piece_num;
526
527 $url = DOL_URL_ROOT.'/accountancy/bookkeeping/card.php?piece_num='.$this->piece_num;
528
529 if ($option != 'nolink') {
530 // Add param to save lastsearch_values or not
531 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
532 if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
533 $add_save_lastsearch_values = 1;
534 }
535 if ($add_save_lastsearch_values) {
536 $url .= '&save_lastsearch_values=1';
537 }
538 }
539
540 $linkclose = '';
541 if (empty($notooltip)) {
542 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
543 $label = $langs->trans("ShowTransaction");
544 $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
545 }
546 $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
547 $linkclose .= ' class="classfortooltip'.($morecss ? ' '.$morecss : '').'"';
548 } else {
549 $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
550 }
551
552 $linkstart = '<a href="'.$url.'"';
553 $linkstart .= $linkclose.'>';
554 $linkend = '</a>';
555
556 $result .= $linkstart;
557 if ($withpicto) {
558 $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);
559 }
560 if ($withpicto != 2) {
561 $result .= $this->piece_num;
562 }
563 $result .= $linkend;
564 //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
565
566 global $action;
567 $hookmanager->initHooks(array($this->element . 'dao'));
568 $parameters = array('id' => $this->id, 'getnomurl' => &$result);
569 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
570 if ($reshook > 0) {
571 $result = $hookmanager->resPrint;
572 } else {
573 $result .= $hookmanager->resPrint;
574 }
575 return $result;
576 }
577
586 public function createStd(User $user, $notrigger = 0, $mode = '')
587 {
588 global $conf, $langs;
589
590 $langs->loadLangs(array("accountancy", "bills", "compta"));
591
592 dol_syslog(__METHOD__, LOG_DEBUG);
593
594 $error = 0;
595
596 // Clean parameters
597 if (isset($this->doc_type)) {
598 $this->doc_type = trim($this->doc_type);
599 }
600 if (isset($this->doc_ref)) {
601 $this->doc_ref = trim($this->doc_ref);
602 }
603 if (isset($this->fk_doc)) {
604 $this->fk_doc = (int) $this->fk_doc;
605 }
606 if (isset($this->fk_docdet)) {
607 $this->fk_docdet = (int) $this->fk_docdet;
608 }
609 if (isset($this->thirdparty_code)) {
610 $this->thirdparty_code = trim($this->thirdparty_code);
611 }
612 if (isset($this->subledger_account)) {
613 $this->subledger_account = trim($this->subledger_account);
614 }
615 if (isset($this->subledger_label)) {
616 $this->subledger_label = trim($this->subledger_label);
617 }
618 if (isset($this->numero_compte)) {
619 $this->numero_compte = trim($this->numero_compte);
620 }
621 if (isset($this->label_compte)) {
622 $this->label_compte = trim($this->label_compte);
623 }
624 if (isset($this->label_operation)) {
625 $this->label_operation = trim($this->label_operation);
626 }
627 if (isset($this->sens)) {
628 $this->sens = trim($this->sens);
629 }
630 if (isset($this->import_key)) {
631 $this->import_key = trim($this->import_key);
632 }
633 if (isset($this->code_journal)) {
634 $this->code_journal = trim($this->code_journal);
635 }
636 if (isset($this->journal_label)) {
637 $this->journal_label = trim($this->journal_label);
638 }
639 if (isset($this->piece_num)) {
640 $this->piece_num = (int) $this->piece_num;
641 }
642 if (empty($this->debit)) {
643 $this->debit = 0;
644 }
645 if (empty($this->credit)) {
646 $this->credit = 0;
647 }
648 if (empty($this->montant)) {
649 $this->montant = 0;
650 }
651
652 $result = $this->validBookkeepingDate($this->doc_date);
653 if ($result < 0) {
654 return -1;
655 } elseif ($result == 0) {
656 if (getDolGlobalString('ACCOUNTANCY_FISCAL_PERIOD_MODE') == 'blockedonclosed') {
657 $this->errors[] = $langs->trans('ErrorBookkeepingDocDateIsOnAClosedFiscalPeriod');
658 } else {
659 $this->errors[] = $langs->trans('ErrorBookkeepingDocDateNotOnActiveFiscalPeriod');
660 }
661 return -1;
662 }
663
664 $this->debit = (float) price2num($this->debit, 'MT');
665 $this->credit = (float) price2num($this->credit, 'MT');
666 $this->montant = (float) price2num($this->montant, 'MT');
667
668 $now = dol_now();
669
670 // Check parameters
671 $this->journal_label = $langs->trans($this->journal_label);
672
673 // Insert request
674 $sql = 'INSERT INTO '.MAIN_DB_PREFIX.$this->table_element.$mode.' (';
675 $sql .= 'doc_date,';
676 $sql .= 'date_lim_reglement,';
677 $sql .= 'doc_type,';
678 $sql .= 'doc_ref,';
679 $sql .= 'fk_doc,';
680 $sql .= 'fk_docdet,';
681 $sql .= 'thirdparty_code,';
682 $sql .= 'subledger_account,';
683 $sql .= 'subledger_label,';
684 $sql .= 'numero_compte,';
685 $sql .= 'label_compte,';
686 $sql .= 'label_operation,';
687 $sql .= 'debit,';
688 $sql .= 'credit,';
689 $sql .= 'montant,';
690 $sql .= 'sens,';
691 $sql .= 'fk_user_author,';
692 $sql .= 'date_creation,';
693 $sql .= 'code_journal,';
694 $sql .= 'journal_label,';
695 $sql .= 'piece_num,';
696 $sql .= 'entity';
697 $sql .= ') VALUES (';
698 $sql .= ' '.(!isset($this->doc_date) || dol_strlen($this->doc_date) == 0 ? 'NULL' : "'".$this->db->idate($this->doc_date)."'").',';
699 $sql .= ' '.(!isset($this->date_lim_reglement) || dol_strlen($this->date_lim_reglement) == 0 ? 'NULL' : "'".$this->db->idate($this->date_lim_reglement)."'").',';
700 $sql .= ' '.(!isset($this->doc_type) ? 'NULL' : "'".$this->db->escape($this->doc_type)."'").',';
701 $sql .= ' '.(!isset($this->doc_ref) ? 'NULL' : "'".$this->db->escape($this->doc_ref)."'").',';
702 $sql .= ' '.(empty($this->fk_doc) ? '0' : (int) $this->fk_doc).',';
703 $sql .= ' '.(empty($this->fk_docdet) ? '0' : (int) $this->fk_docdet).',';
704 $sql .= ' '.(!isset($this->thirdparty_code) ? 'NULL' : "'".$this->db->escape($this->thirdparty_code)."'").',';
705 $sql .= ' '.(!isset($this->subledger_account) ? 'NULL' : "'".$this->db->escape($this->subledger_account)."'").',';
706 $sql .= ' '.(!isset($this->subledger_label) ? 'NULL' : "'".$this->db->escape($this->subledger_label)."'").',';
707 $sql .= ' '.(!isset($this->numero_compte) ? 'NULL' : "'".$this->db->escape($this->numero_compte)."'").',';
708 $sql .= ' '.(!isset($this->label_compte) ? 'NULL' : "'".$this->db->escape($this->label_compte)."'").',';
709 $sql .= ' '.(!isset($this->label_operation) ? 'NULL' : "'".$this->db->escape($this->label_operation)."'").',';
710 $sql .= ' '.(!isset($this->debit) ? 'NULL' : $this->debit).',';
711 $sql .= ' '.(!isset($this->credit) ? 'NULL' : $this->credit).',';
712 $sql .= ' '.(!isset($this->montant) ? 'NULL' : $this->montant).',';
713 $sql .= ' '.(!isset($this->sens) ? 'NULL' : "'".$this->db->escape($this->sens)."'").',';
714 $sql .= ' '.((int) $user->id).',';
715 $sql .= ' '."'".$this->db->idate($now)."',";
716 $sql .= ' '.(empty($this->code_journal) ? 'NULL' : "'".$this->db->escape($this->code_journal)."'").',';
717 $sql .= ' '.(empty($this->journal_label) ? 'NULL' : "'".$this->db->escape($this->journal_label)."'").',';
718 $sql .= ' '.(empty($this->piece_num) ? 'NULL' : $this->db->escape($this->piece_num)).',';
719 $sql .= ' '.(!isset($this->entity) ? $conf->entity : $this->entity);
720 $sql .= ')';
721
722 $this->db->begin();
723
724 $resql = $this->db->query($sql);
725 if (!$resql) {
726 $error++;
727 $this->errors[] = 'Error '.$this->db->lasterror();
728 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
729 }
730
731 if (!$error) {
732 $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.$this->table_element.$mode);
733 }
734
735 // Commit or rollback
736 if ($error) {
737 $this->db->rollback();
738
739 return -1 * $error;
740 } else {
741 $this->db->commit();
742
743 return $this->id;
744 }
745 }
746
755 public function fetch($id, $ref = null, $mode = '')
756 {
757 global $conf;
758
759 dol_syslog(__METHOD__, LOG_DEBUG);
760
761 $sql = 'SELECT';
762 $sql .= ' t.rowid,';
763 $sql .= " t.doc_date,";
764 $sql .= " t.date_lim_reglement,";
765 $sql .= " t.doc_type,";
766 $sql .= " t.doc_ref,";
767 $sql .= " t.fk_doc,";
768 $sql .= " t.fk_docdet,";
769 $sql .= " t.thirdparty_code,";
770 $sql .= " t.subledger_account,";
771 $sql .= " t.subledger_label,";
772 $sql .= " t.numero_compte,";
773 $sql .= " t.label_compte,";
774 $sql .= " t.label_operation,";
775 $sql .= " t.debit,";
776 $sql .= " t.credit,";
777 $sql .= " t.montant as amount,";
778 $sql .= " t.sens,";
779 $sql .= " t.fk_user_author,";
780 $sql .= " t.import_key,";
781 $sql .= " t.code_journal,";
782 $sql .= " t.journal_label,";
783 $sql .= " t.piece_num,";
784 $sql .= " t.date_creation,";
785 // In llx_accounting_bookkeeping_tmp, field date_export doesn't exist
786 if ($mode != "_tmp") {
787 $sql .= " t.date_export,";
788 }
789 $sql .= " t.date_validated as date_validation";
790 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.$mode.' as t';
791 $sql .= ' WHERE 1 = 1';
792 $sql .= " AND entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
793 if (null !== $ref) {
794 $sql .= " AND t.rowid = ".((int) $ref);
795 } else {
796 $sql .= " AND t.rowid = ".((int) $id);
797 }
798
799 $resql = $this->db->query($sql);
800 if ($resql) {
801 $numrows = $this->db->num_rows($resql);
802 if ($numrows) {
803 $obj = $this->db->fetch_object($resql);
804
805 $this->id = $obj->rowid;
806
807 $this->doc_date = $this->db->jdate($obj->doc_date);
808 $this->date_lim_reglement = $this->db->jdate($obj->date_lim_reglement);
809 $this->doc_type = $obj->doc_type;
810 $this->doc_ref = $obj->doc_ref;
811 $this->fk_doc = $obj->fk_doc;
812 $this->fk_docdet = $obj->fk_docdet;
813 $this->thirdparty_code = $obj->thirdparty_code;
814 $this->subledger_account = $obj->subledger_account;
815 $this->subledger_label = $obj->subledger_label;
816 $this->numero_compte = $obj->numero_compte;
817 $this->label_compte = $obj->label_compte;
818 $this->label_operation = $obj->label_operation;
819 $this->debit = $obj->debit;
820 $this->credit = $obj->credit;
821 $this->montant = $obj->amount;
822 $this->amount = $obj->amount;
823 $this->sens = $obj->sens;
824 $this->fk_user_author = $obj->fk_user_author;
825 $this->import_key = $obj->import_key;
826 $this->code_journal = $obj->code_journal;
827 $this->journal_label = $obj->journal_label;
828 $this->piece_num = $obj->piece_num;
829 $this->date_creation = $this->db->jdate($obj->date_creation);
830 $this->date_export = $this->db->jdate($obj->date_export);
831 $this->date_validation = isset($obj->date_validation) ? $this->db->jdate($obj->date_validation) : '';
832 }
833 $this->db->free($resql);
834
835 if ($numrows) {
836 return 1;
837 } else {
838 return 0;
839 }
840 } else {
841 $this->errors[] = 'Error '.$this->db->lasterror();
842 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
843
844 return -1;
845 }
846 }
847
848
862 public function fetchAllByAccount($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND', $option = 0, $countonly = 0)
863 {
864 global $conf;
865
866 dol_syslog(__METHOD__, LOG_DEBUG);
867
868 $this->lines = array();
869 $num = 0;
870
871 $sql = 'SELECT';
872 if ($countonly) {
873 $sql .= ' COUNT(t.rowid) as nb';
874 } else {
875 $sql .= ' t.rowid,';
876 $sql .= " t.doc_date,";
877 $sql .= " t.doc_type,";
878 $sql .= " t.doc_ref,";
879 $sql .= " t.fk_doc,";
880 $sql .= " t.fk_docdet,";
881 $sql .= " t.thirdparty_code,";
882 $sql .= " t.subledger_account,";
883 $sql .= " t.subledger_label,";
884 $sql .= " t.numero_compte,";
885 $sql .= " t.label_compte,";
886 $sql .= " t.label_operation,";
887 $sql .= " t.debit,";
888 $sql .= " t.credit,";
889 $sql .= " t.montant as amount,";
890 $sql .= " t.sens,";
891 $sql .= " t.multicurrency_amount,";
892 $sql .= " t.multicurrency_code,";
893 $sql .= " t.lettering_code,";
894 $sql .= " t.date_lettering,";
895 $sql .= " t.fk_user_author,";
896 $sql .= " t.import_key,";
897 $sql .= " t.code_journal,";
898 $sql .= " t.journal_label,";
899 $sql .= " t.piece_num,";
900 $sql .= " t.date_creation,";
901 $sql .= " t.date_export,";
902 $sql .= " t.date_validated as date_validation,";
903 $sql .= " t.import_key";
904 }
905 // Manage filter
906 $sqlwhere = array();
907 if (count($filter) > 0) {
908 foreach ($filter as $key => $value) {
909 if ($key == 't.doc_date>=') {
910 $sqlwhere[] = "t.doc_date >= '".$this->db->idate($value)."'";
911 } elseif ($key == 't.doc_date<=') {
912 $sqlwhere[] = "t.doc_date <= '".$this->db->idate($value)."'";
913 } elseif ($key == 't.doc_date>') {
914 $sqlwhere[] = "t.doc_date > '".$this->db->idate($value)."'";
915 } elseif ($key == 't.doc_date<') {
916 $sqlwhere[] = "t.doc_date < '".$this->db->idate($value)."'";
917 } elseif ($key == 't.numero_compte>=') {
918 $sqlwhere[] = "t.numero_compte >= '".$this->db->escape($value)."'";
919 } elseif ($key == 't.numero_compte<=') {
920 $sqlwhere[] = "t.numero_compte <= '".$this->db->escape($value)."'";
921 } elseif ($key == 't.subledger_account>=') {
922 $sqlwhere[] = "t.subledger_account >= '".$this->db->escape($value)."'";
923 } elseif ($key == 't.subledger_account<=') {
924 $sqlwhere[] = "t.subledger_account <= '".$this->db->escape($value)."'";
925 } elseif ($key == 't.fk_doc' || $key == 't.fk_docdet' || $key == 't.piece_num') {
926 $sqlwhere[] = $this->db->sanitize($key).' = '.((int) $value);
927 } elseif ($key == 't.subledger_account' || $key == 't.numero_compte') {
928 $sqlwhere[] = $this->db->sanitize($key).' LIKE \''.$this->db->escape($this->db->escapeforlike($value)).'%\'';
929 } elseif ($key == 't.date_creation>=') {
930 $sqlwhere[] = 't.date_creation >= \''.$this->db->idate($value).'\'';
931 } elseif ($key == 't.date_creation<=') {
932 $sqlwhere[] = 't.date_creation <= \''.$this->db->idate($value).'\'';
933 } elseif ($key == 't.date_export>=') {
934 $sqlwhere[] = 't.date_export >= \''.$this->db->idate($value).'\'';
935 } elseif ($key == 't.date_export<=') {
936 $sqlwhere[] = 't.date_export <= \''.$this->db->idate($value).'\'';
937 } elseif ($key == 't.date_validated>=') {
938 $sqlwhere[] = 't.date_validated >= \''.$this->db->idate($value).'\'';
939 } elseif ($key == 't.date_validated<=') {
940 $sqlwhere[] = 't.date_validated <= \''.$this->db->idate($value).'\'';
941 } elseif ($key == 't.credit' || $key == 't.debit') {
942 $sqlwhere[] = natural_search($key, $value, 1, 1);
943 } elseif ($key == 't.reconciled_option') {
944 $sqlwhere[] = 't.lettering_code IS NULL';
945 } elseif ($key == 't.code_journal' && !empty($value)) {
946 if (is_array($value)) {
947 $sqlwhere[] = natural_search("t.code_journal", implode(',', $value), 3, 1);
948 } else {
949 $sqlwhere[] = natural_search("t.code_journal", $value, 3, 1);
950 }
951 } elseif ($key == 't.search_accounting_code_in' && !empty($value)) {
952 $sqlwhere[] = 't.numero_compte IN ('.$this->db->sanitize($value, 1).')';
953 } else {
954 $sqlwhere[] = natural_search($key, $value, 0, 1);
955 }
956 }
957 }
958 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
959 $sql .= ' WHERE entity = ' . ((int) $conf->entity); // Do not use getEntity for accounting features
960 if (count($sqlwhere) > 0) {
961 $sql .= " AND ".implode(" ".$this->db->sanitize($filtermode)." ", $sqlwhere);
962 }
963 // Filter by ledger account or subledger account
964 if (!empty($option)) {
965 $sql .= " AND t.subledger_account IS NOT NULL";
966 $sql .= " AND t.subledger_account <> ''";
967 $sortfield = 't.subledger_account'.($sortfield ? ','.$sortfield : '');
968 $sortorder = 'ASC'.($sortfield ? ','.$sortfield : '');
969 } else {
970 $sortfield = 't.numero_compte'.($sortfield ? ','.$sortfield : '');
971 $sortorder = 'ASC'.($sortorder ? ','.$sortorder : '');
972 }
973
974 if (!$countonly) {
975 $sql .= $this->db->order($sortfield, $sortorder);
976 if (!empty($limit)) {
977 $sql .= $this->db->plimit($limit + 1, $offset);
978 }
979 }
980
981 $resql = $this->db->query($sql);
982 if ($resql) {
983 if ($countonly) {
984 $obj = $this->db->fetch_object($resql);
985 if ($obj) {
986 $num = $obj->nb;
987 }
988 } else {
989 $num = $this->db->num_rows($resql);
990
991 $i = 0;
992 while (($obj = $this->db->fetch_object($resql)) && (empty($limit) || $i < min($limit, $num))) {
993 $line = new BookKeepingLine($this->db);
994
995 $line->id = $obj->rowid;
996
997 $line->doc_date = $this->db->jdate($obj->doc_date);
998 $line->doc_type = $obj->doc_type;
999 $line->doc_ref = $obj->doc_ref;
1000 $line->fk_doc = $obj->fk_doc;
1001 $line->fk_docdet = $obj->fk_docdet;
1002 $line->thirdparty_code = $obj->thirdparty_code;
1003 $line->subledger_account = $obj->subledger_account;
1004 $line->subledger_label = $obj->subledger_label;
1005 $line->numero_compte = $obj->numero_compte;
1006 $line->label_compte = $obj->label_compte;
1007 $line->label_operation = $obj->label_operation;
1008 $line->debit = $obj->debit;
1009 $line->credit = $obj->credit;
1010 $line->montant = $obj->amount; // deprecated
1011 $line->amount = $obj->amount;
1012 $line->sens = $obj->sens;
1013 $line->multicurrency_amount = $obj->multicurrency_amount;
1014 $line->multicurrency_code = $obj->multicurrency_code;
1015 $line->lettering_code = $obj->lettering_code;
1016 $line->date_lettering = $obj->date_lettering;
1017 $line->fk_user_author = $obj->fk_user_author;
1018 $line->import_key = $obj->import_key;
1019 $line->code_journal = $obj->code_journal;
1020 $line->journal_label = $obj->journal_label;
1021 $line->piece_num = $obj->piece_num;
1022 $line->date_creation = $this->db->jdate($obj->date_creation);
1023 $line->date_export = $this->db->jdate($obj->date_export);
1024 $line->date_validation = $this->db->jdate($obj->date_validation);
1025 $line->import_key = $obj->import_key;
1026
1027 $this->lines[] = $line;
1028
1029 $i++;
1030 }
1031 }
1032 $this->db->free($resql);
1033
1034 return $num;
1035 } else {
1036 $this->errors[] = 'Error '.$this->db->lasterror();
1037 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
1038
1039 return -1;
1040 }
1041 }
1042
1055 public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, $filter = '', $filtermode = 'AND', $showAlreadyExportMovements = 1)
1056 {
1057 global $conf;
1058
1059 dol_syslog(__METHOD__, LOG_DEBUG);
1060
1061 $sql = 'SELECT';
1062 $sql .= ' t.rowid,';
1063 $sql .= " t.doc_date,";
1064 $sql .= " t.doc_type,";
1065 $sql .= " t.doc_ref,";
1066 $sql .= " t.fk_doc,";
1067 $sql .= " t.fk_docdet,";
1068 $sql .= " t.thirdparty_code,";
1069 $sql .= " t.subledger_account,";
1070 $sql .= " t.subledger_label,";
1071 $sql .= " t.numero_compte,";
1072 $sql .= " t.label_compte,";
1073 $sql .= " t.label_operation,";
1074 $sql .= " t.debit,";
1075 $sql .= " t.credit,";
1076 $sql .= " t.lettering_code,";
1077 $sql .= " t.date_lettering,";
1078 $sql .= " t.montant as amount,";
1079 $sql .= " t.sens,";
1080 $sql .= " t.fk_user_author,";
1081 $sql .= " t.import_key,";
1082 $sql .= " t.code_journal,";
1083 $sql .= " t.journal_label,";
1084 $sql .= " t.piece_num,";
1085 $sql .= " t.date_creation,";
1086 $sql .= " t.date_lim_reglement,";
1087 $sql .= " t.tms as date_modification,";
1088 $sql .= " t.date_export,";
1089 $sql .= " t.date_validated as date_validation";
1090 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
1091 $sql .= ' WHERE t.entity = ' . ((int) $conf->entity); // Do not use getEntity for accounting features
1092 if ($showAlreadyExportMovements == 0) {
1093 $sql .= " AND t.date_export IS NULL";
1094 }
1095
1096 // Manage filter
1097 if (is_array($filter)) { // deprecated, use $filter = USF syntax
1098 dol_syslog("You are using a deprecated use of fetchAll. filter parameter mus be an USF string now.", LOG_WARNING);
1099 $sqlwhere = array();
1100 if (count($filter) > 0) {
1101 foreach ($filter as $key => $value) {
1102 if ($key == 't.doc_date') {
1103 $sqlwhere[] = $this->db->sanitize($key).' = \''.$this->db->idate($value).'\'';
1104 } elseif ($key == 't.doc_date>=') {
1105 $sqlwhere[] = "t.doc_date >= '".$this->db->idate($value)."'";
1106 } elseif ($key == 't.doc_date<=') {
1107 $sqlwhere[] = "t.doc_date <= '".$this->db->idate($value)."'";
1108 } elseif ($key == 't.doc_date>') {
1109 $sqlwhere[] = "t.doc_date > '".$this->db->idate($value)."'";
1110 } elseif ($key == 't.doc_date<') {
1111 $sqlwhere[] = "t.doc_date < '".$this->db->idate($value)."'";
1112 } elseif ($key == 't.numero_compte>=') {
1113 $sqlwhere[] = "t.numero_compte >= '".$this->db->escape($value)."'";
1114 } elseif ($key == 't.numero_compte<=') {
1115 $sqlwhere[] = "t.numero_compte <= '".$this->db->escape($value)."'";
1116 } elseif ($key == 't.subledger_account>=') {
1117 $sqlwhere[] = "t.subledger_account >= '".$this->db->escape($value)."'";
1118 } elseif ($key == 't.subledger_account<=') {
1119 $sqlwhere[] = "t.subledger_account <= '".$this->db->escape($value)."'";
1120 } elseif ($key == 't.fk_doc' || $key == 't.fk_docdet' || $key == 't.piece_num') {
1121 $sqlwhere[] = $this->db->sanitize($key).' = '.((int) $value);
1122 } elseif ($key == 't.subledger_account' || $key == 't.numero_compte') {
1123 $sqlwhere[] = $this->db->sanitize($key).' LIKE \''.$this->db->escape($value).'%\'';
1124 } elseif ($key == 't.date_creation>=') {
1125 $sqlwhere[] = 't.date_creation >= \''.$this->db->idate($value).'\'';
1126 } elseif ($key == 't.date_creation<=') {
1127 $sqlwhere[] = 't.date_creation <= \''.$this->db->idate($value).'\'';
1128 } elseif ($key == 't.tms>=') {
1129 $sqlwhere[] = 't.tms >= \''.$this->db->idate($value).'\'';
1130 } elseif ($key == 't.tms<=') {
1131 $sqlwhere[] = 't.tms <= \''.$this->db->idate($value).'\'';
1132 } elseif ($key == 't.date_export>=') {
1133 $sqlwhere[] = 't.date_export >= \''.$this->db->idate($value).'\'';
1134 } elseif ($key == 't.date_export<=') {
1135 $sqlwhere[] = 't.date_export <= \''.$this->db->idate($value).'\'';
1136 } elseif ($key == 't.date_validated>=') {
1137 $sqlwhere[] = 't.date_validated >= \''.$this->db->idate($value).'\'';
1138 } elseif ($key == 't.date_validated<=') {
1139 $sqlwhere[] = 't.date_validated <= \''.$this->db->idate($value).'\'';
1140 } elseif ($key == 't.credit' || $key == 't.debit') {
1141 $sqlwhere[] = natural_search($key, $value, 1, 1);
1142 } elseif ($key == 't.code_journal' && !empty($value)) {
1143 if (is_array($value)) {
1144 $sqlwhere[] = natural_search("t.code_journal", implode(',', $value), 3, 1);
1145 } else {
1146 $sqlwhere[] = natural_search("t.code_journal", $value, 3, 1);
1147 }
1148 } else {
1149 $sqlwhere[] = natural_search($key, $value, 0, 1);
1150 }
1151 }
1152 }
1153 if (count($sqlwhere) > 0) {
1154 $sql .= ' AND '.implode(" ".$this->db->sanitize($filtermode)." ", $sqlwhere);
1155 }
1156
1157 $filter = '';
1158 }
1159
1160 // Manage filter
1161 $errormessage = '';
1162 $sql .= forgeSQLFromUniversalSearchCriteria($filter, $errormessage);
1163 if ($errormessage) {
1164 $this->errors[] = $errormessage;
1165 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
1166 return -1;
1167 }
1168
1169 if (!empty($sortfield)) {
1170 $sql .= $this->db->order($sortfield, $sortorder);
1171 }
1172 if (!empty($limit)) {
1173 $sql .= $this->db->plimit($limit + 1, $offset);
1174 }
1175 $this->lines = array();
1176
1177 $resql = $this->db->query($sql);
1178 if ($resql) {
1179 $num = $this->db->num_rows($resql);
1180
1181 $i = 0;
1182 while (($obj = $this->db->fetch_object($resql)) && (empty($limit) || $i < min($limit, $num))) {
1183 $line = new BookKeepingLine($this->db);
1184
1185 $line->id = $obj->rowid;
1186
1187 $line->doc_date = $this->db->jdate($obj->doc_date);
1188 $line->doc_type = $obj->doc_type;
1189 $line->doc_ref = $obj->doc_ref;
1190 $line->fk_doc = $obj->fk_doc;
1191 $line->fk_docdet = $obj->fk_docdet;
1192 $line->thirdparty_code = $obj->thirdparty_code;
1193 $line->subledger_account = $obj->subledger_account;
1194 $line->subledger_label = $obj->subledger_label;
1195 $line->numero_compte = $obj->numero_compte;
1196 $line->label_compte = $obj->label_compte;
1197 $line->label_operation = $obj->label_operation;
1198 $line->debit = $obj->debit;
1199 $line->credit = $obj->credit;
1200 $line->montant = $obj->amount; // deprecated
1201 $line->amount = $obj->amount;
1202 $line->sens = $obj->sens;
1203 $line->lettering_code = $obj->lettering_code;
1204 $line->date_lettering = $obj->date_lettering;
1205 $line->fk_user_author = $obj->fk_user_author;
1206 $line->import_key = $obj->import_key;
1207 $line->code_journal = $obj->code_journal;
1208 $line->journal_label = $obj->journal_label;
1209 $line->piece_num = $obj->piece_num;
1210 $line->date_creation = $this->db->jdate($obj->date_creation);
1211 $line->date_lim_reglement = $this->db->jdate($obj->date_lim_reglement);
1212 $line->date_modification = $this->db->jdate($obj->date_modification);
1213 $line->date_export = $this->db->jdate($obj->date_export);
1214 $line->date_validation = $this->db->jdate($obj->date_validation);
1215
1216 $this->lines[] = $line;
1217
1218 $i++;
1219 }
1220 $this->db->free($resql);
1221
1222 return $num;
1223 } else {
1224 $this->errors[] = 'Error '.$this->db->lasterror();
1225 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
1226 return -1;
1227 }
1228 }
1229
1242 public function fetchAllBalance($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, $filter = '', $filtermode = 'AND', $option = 0)
1243 {
1244 global $conf;
1245
1246 $this->lines = array();
1247
1248 dol_syslog(__METHOD__, LOG_DEBUG);
1249
1250 $sql = 'SELECT';
1251 $sql .= " t.numero_compte,";
1252 if (!empty($option)) {
1253 $sql .= " t.subledger_account,";
1254 $sql .= " t.subledger_label,";
1255 }
1256 $sql .= " SUM(t.debit) as debit,";
1257 $sql .= " SUM(t.credit) as credit";
1258 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
1259 $sql .= ' WHERE entity = ' . ((int) $conf->entity); // Do not use getEntity for accounting features
1260
1261 // Manage filter
1262 if (is_array($filter)) {
1263 $sqlwhere = array();
1264 if (count($filter) > 0) {
1265 foreach ($filter as $key => $value) {
1266 if ($key == 't.doc_date') {
1267 $sqlwhere[] = $this->db->sanitize($key)." = '".$this->db->idate($value)."'";
1268 } elseif ($key == 't.doc_date>=') {
1269 $sqlwhere[] = "t.doc_date >= '".$this->db->idate($value)."'";
1270 } elseif ($key == 't.doc_date<=') {
1271 $sqlwhere[] = "t.doc_date <= '".$this->db->idate($value)."'";
1272 } elseif ($key == 't.doc_date>') {
1273 $sqlwhere[] = "t.doc_date > '".$this->db->idate($value)."'";
1274 } elseif ($key == 't.doc_date<') {
1275 $sqlwhere[] = "t.doc_date < '".$this->db->idate($value)."'";
1276 } elseif ($key == 't.numero_compte>=') {
1277 $sqlwhere[] = "t.numero_compte >= '".$this->db->escape($value)."'";
1278 } elseif ($key == 't.numero_compte<=') {
1279 $sqlwhere[] = "t.numero_compte <= '".$this->db->escape($value)."'";
1280 } elseif ($key == 't.subledger_account>=') {
1281 $sqlwhere[] = "t.subledger_account >= '".$this->db->escape($value)."'";
1282 } elseif ($key == 't.subledger_account<=') {
1283 $sqlwhere[] = "t.subledger_account <= '".$this->db->escape($value)."'";
1284 } elseif ($key == 't.fk_doc' || $key == 't.fk_docdet' || $key == 't.piece_num') {
1285 $sqlwhere[] = $this->db->sanitize($key)." = ".((int) $value);
1286 } elseif ($key == 't.subledger_account' || $key == 't.numero_compte') {
1287 $sqlwhere[] = $this->db->sanitize($key)." LIKE '".$this->db->escape($value)."%'";
1288 } elseif ($key == 't.subledger_label') {
1289 $sqlwhere[] = $this->db->sanitize($key)." LIKE '".$this->db->escape($value)."%'";
1290 } elseif ($key == 't.code_journal' && !empty($value)) {
1291 if (is_array($value)) {
1292 $sqlwhere[] = natural_search("t.code_journal", implode(',', $value), 3, 1);
1293 } else {
1294 $sqlwhere[] = natural_search("t.code_journal", $value, 3, 1);
1295 }
1296 } elseif ($key == 't.reconciled_option') {
1297 $sqlwhere[] = 't.lettering_code IS NULL';
1298 } else {
1299 $sqlwhere[] = $this->db->sanitize($key)." LIKE '%".$this->db->escape($this->db->escapeforlike($value))."%'";
1300 }
1301 }
1302 }
1303 if (count($sqlwhere) > 0) {
1304 $sql .= " AND ".implode(" ".$this->db->sanitize($filtermode)." ", $sqlwhere);
1305 }
1306
1307 $filter = '';
1308 }
1309
1310 // Manage filter
1311 $errormessage = '';
1312 $sql .= forgeSQLFromUniversalSearchCriteria($filter, $errormessage);
1313 if ($errormessage) {
1314 $this->errors[] = $errormessage;
1315 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
1316 return -1;
1317 }
1318
1319 if (!empty($option)) {
1320 $sql .= " AND t.subledger_account IS NOT NULL";
1321 $sql .= " AND t.subledger_account <> ''";
1322 $sql .= " GROUP BY t.numero_compte, t.subledger_account, t.subledger_label";
1323 $sortfield = 't.subledger_account'.($sortfield ? ','.$sortfield : '');
1324 $sortorder = 'ASC'.($sortfield ? ','.$sortfield : '');
1325 } else {
1326 $sql .= ' GROUP BY t.numero_compte';
1327 $sortfield = 't.numero_compte'.($sortfield ? ','.$sortfield : '');
1328 $sortorder = 'ASC'.($sortorder ? ','.$sortorder : '');
1329 }
1330
1331 if (!empty($sortfield)) {
1332 $sql .= $this->db->order($sortfield, $sortorder);
1333 }
1334 if (!empty($limit)) {
1335 $sql .= $this->db->plimit($limit + 1, $offset);
1336 }
1337
1338 //print $sql;
1339 $resql = $this->db->query($sql);
1340
1341 if ($resql) {
1342 $num = $this->db->num_rows($resql);
1343
1344 $i = 0;
1345 while (($obj = $this->db->fetch_object($resql)) && (empty($limit) || $i < min($limit, $num))) {
1346 $line = new BookKeepingLine($this->db);
1347
1348 $line->numero_compte = $obj->numero_compte;
1349 //$line->label_compte = $obj->label_compte;
1350 if (!empty($option)) {
1351 $line->subledger_account = $obj->subledger_account;
1352 $line->subledger_label = $obj->subledger_label;
1353 }
1354 $line->debit = $obj->debit;
1355 $line->credit = $obj->credit;
1356
1357 $this->lines[] = $line;
1358
1359 $i++;
1360 }
1361 $this->db->free($resql);
1362
1363 return $num;
1364 } else {
1365 $this->errors[] = 'Error '.$this->db->lasterror();
1366 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
1367
1368 return -1;
1369 }
1370 }
1371
1380 public function update(User $user, $notrigger = 0, $mode = '')
1381 {
1382 global $langs;
1383 $error = 0;
1384
1385 dol_syslog(__METHOD__, LOG_DEBUG);
1386
1387 // Clean parameters
1388 if (isset($this->doc_type)) {
1389 $this->doc_type = trim($this->doc_type);
1390 }
1391 if (isset($this->doc_ref)) {
1392 $this->doc_ref = trim($this->doc_ref);
1393 }
1394 if (isset($this->fk_doc)) {
1395 $this->fk_doc = (int) $this->fk_doc;
1396 }
1397 if (isset($this->fk_docdet)) {
1398 $this->fk_docdet = (int) $this->fk_docdet;
1399 }
1400 if (isset($this->thirdparty_code)) {
1401 $this->thirdparty_code = trim($this->thirdparty_code);
1402 }
1403 if (isset($this->subledger_account)) {
1404 $this->subledger_account = trim($this->subledger_account);
1405 }
1406 if (isset($this->subledger_label)) {
1407 $this->subledger_label = trim($this->subledger_label);
1408 }
1409 if (isset($this->numero_compte)) {
1410 $this->numero_compte = trim($this->numero_compte);
1411 }
1412 if (isset($this->label_compte)) {
1413 $this->label_compte = trim($this->label_compte);
1414 }
1415 if (isset($this->label_operation)) {
1416 $this->label_operation = trim($this->label_operation);
1417 }
1418 if (isset($this->sens)) {
1419 $this->sens = trim($this->sens);
1420 }
1421 if (isset($this->import_key)) {
1422 $this->import_key = trim($this->import_key);
1423 }
1424 if (isset($this->code_journal)) {
1425 $this->code_journal = trim($this->code_journal);
1426 }
1427 if (isset($this->journal_label)) {
1428 $this->journal_label = trim($this->journal_label);
1429 }
1430 if (isset($this->piece_num)) {
1431 $this->piece_num = (int) $this->piece_num;
1432 }
1433
1434 $result = $this->canModifyBookkeeping($this->id, $mode);
1435 if ($result < 0) {
1436 return -1;
1437 } elseif ($result == 0) {
1438 if (getDolGlobalString('ACCOUNTANCY_FISCAL_PERIOD_MODE') == 'blockedonclosed') {
1439 $this->errors[] = $langs->trans('ErrorBookkeepingDocDateIsOnAClosedFiscalPeriod');
1440 } else {
1441 $this->errors[] = $langs->trans('ErrorBookkeepingDocDateNotOnActiveFiscalPeriod');
1442 }
1443 return -1;
1444 }
1445
1446 $this->debit = (float) price2num($this->debit, 'MT');
1447 $this->credit = (float) price2num($this->credit, 'MT');
1448 $this->montant = (float) price2num($this->montant, 'MT');
1449
1450 // Check parameters
1451 // Put here code to add a control on parameters values
1452
1453 // Update request
1454 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element.$mode.' SET';
1455 $sql .= ' doc_date = '.(!isset($this->doc_date) || dol_strlen($this->doc_date) != 0 ? "'".$this->db->idate($this->doc_date)."'" : 'null').',';
1456 $sql .= ' doc_type = '.(isset($this->doc_type) ? "'".$this->db->escape($this->doc_type)."'" : "null").',';
1457 $sql .= ' doc_ref = '.(isset($this->doc_ref) ? "'".$this->db->escape($this->doc_ref)."'" : "null").',';
1458 $sql .= ' fk_doc = '.(isset($this->fk_doc) ? $this->fk_doc : "null").',';
1459 $sql .= ' fk_docdet = '.(isset($this->fk_docdet) ? $this->fk_docdet : "null").',';
1460 $sql .= ' thirdparty_code = '.(isset($this->thirdparty_code) ? "'".$this->db->escape($this->thirdparty_code)."'" : "null").',';
1461 $sql .= ' subledger_account = '.(isset($this->subledger_account) ? "'".$this->db->escape($this->subledger_account)."'" : "null").',';
1462 $sql .= ' subledger_label = '.(isset($this->subledger_label) ? "'".$this->db->escape($this->subledger_label)."'" : "null").',';
1463 $sql .= ' numero_compte = '.(isset($this->numero_compte) ? "'".$this->db->escape($this->numero_compte)."'" : "null").',';
1464 $sql .= ' label_compte = '.(isset($this->label_compte) ? "'".$this->db->escape($this->label_compte)."'" : "null").',';
1465 $sql .= ' label_operation = '.(isset($this->label_operation) ? "'".$this->db->escape($this->label_operation)."'" : "null").',';
1466 $sql .= ' debit = '.(isset($this->debit) ? $this->debit : "null").',';
1467 $sql .= ' credit = '.(isset($this->credit) ? $this->credit : "null").',';
1468 $sql .= ' montant = '.(isset($this->montant) ? $this->montant : "null").',';
1469 $sql .= ' sens = '.(isset($this->sens) ? "'".$this->db->escape($this->sens)."'" : "null").',';
1470 $sql .= ' fk_user_author = '.(isset($this->fk_user_author) ? $this->fk_user_author : "null").',';
1471 $sql .= ' import_key = '.(isset($this->import_key) ? "'".$this->db->escape($this->import_key)."'" : "null").',';
1472 $sql .= ' code_journal = '.(isset($this->code_journal) ? "'".$this->db->escape($this->code_journal)."'" : "null").',';
1473 $sql .= ' journal_label = '.(isset($this->journal_label) ? "'".$this->db->escape($this->journal_label)."'" : "null").',';
1474 $sql .= ' piece_num = '.(isset($this->piece_num) ? $this->piece_num : "null");
1475 $sql .= ' WHERE rowid='.((int) $this->id);
1476
1477 $this->db->begin();
1478
1479 $resql = $this->db->query($sql);
1480 if (!$resql) {
1481 $error++;
1482 $this->errors[] = 'Error '.$this->db->lasterror();
1483 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
1484 }
1485
1486 // Uncomment this and change MYOBJECT to your own tag if you
1487 // want this action calls a trigger.
1488 //if (! $error && ! $notrigger) {
1489
1490 // // Call triggers
1491 // $result=$this->call_trigger('MYOBJECT_MODIFY',$user);
1492 // if ($result < 0) { $error++; //Do also what you must do to rollback action if trigger fail}
1493 // // End call triggers
1494 //}
1495
1496 // Commit or rollback
1497 if ($error) {
1498 $this->db->rollback();
1499
1500 return -1 * $error;
1501 } else {
1502 $this->db->commit();
1503
1504 return 1;
1505 }
1506 }
1507
1517 public function updateByMvt($piece_num = '', $field = '', $value = '', $mode = '')
1518 {
1519 global $conf;
1520 $error = 0;
1521
1522 $sql_filter = $this->getCanModifyBookkeepingSQL();
1523 if (!isset($sql_filter)) {
1524 return -1;
1525 }
1526
1527 $this->db->begin();
1528
1529 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element.$mode;
1530 $sql .= " SET ".$this->db->sanitize($field)." = ".(is_numeric($value) ? ((float) $value) : "'".$this->db->escape($value)."'");
1531 $sql .= " WHERE piece_num = ".((int) $piece_num);
1532 $sql .= " AND entity = " . ((int) $conf->entity);
1533 $sql .= $sql_filter;
1534
1535 $resql = $this->db->query($sql);
1536
1537 if (!$resql) {
1538 $error++;
1539 $this->errors[] = 'Error '.$this->db->lasterror();
1540 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
1541 }
1542 if ($error) {
1543 $this->db->rollback();
1544
1545 return -1 * $error;
1546 } else {
1547 $this->db->commit();
1548
1549 return 1;
1550 }
1551 }
1552
1561 public function delete(User $user, $notrigger = 0, $mode = '')
1562 {
1563 global $langs;
1564
1565 dol_syslog(__METHOD__, LOG_DEBUG);
1566
1567 $result = $this->canModifyBookkeeping($this->id, $mode);
1568 if ($result < 0) {
1569 return -1;
1570 } elseif ($result == 0) {
1571 if (getDolGlobalString('ACCOUNTANCY_FISCAL_PERIOD_MODE') == 'blockedonclosed') {
1572 $this->errors[] = $langs->trans('ErrorBookkeepingDocDateIsOnAClosedFiscalPeriod');
1573 } else {
1574 $this->errors[] = $langs->trans('ErrorBookkeepingDocDateNotOnActiveFiscalPeriod');
1575 }
1576 return -1;
1577 }
1578
1579 $error = 0;
1580
1581 $this->db->begin();
1582
1583 // Uncomment this and change MYOBJECT to your own tag if you
1584 // want this action calls a trigger.
1585 //if (! $error && ! $notrigger) {
1586
1587 // // Call triggers
1588 // $result=$this->call_trigger('MYOBJECT_DELETE',$user);
1589 // if ($result < 0) { $error++; //Do also what you must do to rollback action if trigger fail}
1590 // // End call triggers
1591 //}
1592
1593 if (!$error) {
1594 $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.$mode;
1595 $sql .= ' WHERE rowid='.((int) $this->id);
1596
1597 $resql = $this->db->query($sql);
1598 if (!$resql) {
1599 $error++;
1600 $this->errors[] = 'Error '.$this->db->lasterror();
1601 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
1602 }
1603 }
1604
1605 // Commit or rollback
1606 if ($error) {
1607 $this->db->rollback();
1608
1609 return -1 * $error;
1610 } else {
1611 $this->db->commit();
1612
1613 return 1;
1614 }
1615 }
1616
1624 public function deleteByImportkey($importkey, $mode = '')
1625 {
1626 $this->db->begin();
1627
1628 $sql_filter = $this->getCanModifyBookkeepingSQL();
1629 if (!isset($sql_filter)) {
1630 return -1;
1631 }
1632
1633 // first check if line not yet in bookkeeping
1634 $sql = "DELETE";
1635 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element.$mode;
1636 $sql .= " WHERE import_key = '".$this->db->escape($importkey)."'";
1637 $sql .= $sql_filter;
1638
1639 $resql = $this->db->query($sql);
1640
1641 if (!$resql) {
1642 $this->errors[] = "Error ".$this->db->lasterror();
1643 dol_syslog(get_class($this)."::delete Error ".$this->db->lasterror(), LOG_ERR);
1644 $this->db->rollback();
1645 return -1;
1646 }
1647
1648 $this->db->commit();
1649 return 1;
1650 }
1651
1661 public function deleteByYearAndJournal($delyear = 0, $journal = '', $mode = '', $delmonth = 0)
1662 {
1663 global $conf, $langs;
1664
1665 if (empty($delyear) && empty($journal)) {
1666 $this->error = 'ErrorOneFieldRequired';
1667 return -1;
1668 }
1669 if (!empty($delmonth) && empty($delyear)) {
1670 $this->error = 'YearRequiredIfMonthDefined';
1671 return -2;
1672 }
1673
1674 $sql_filter = $this->getCanModifyBookkeepingSQL();
1675 if (!isset($sql_filter)) {
1676 return -1;
1677 }
1678
1679 $this->db->begin();
1680
1681 // Delete record in bookkeeping
1682 $sql = "DELETE";
1683 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element.$mode;
1684 $sql .= " WHERE 1 = 1";
1685 $sql .= dolSqlDateFilter('doc_date', 0, $delmonth, $delyear);
1686 if (!empty($journal)) {
1687 $sql .= " AND code_journal = '".$this->db->escape($journal)."'";
1688 }
1689 $sql .= " AND entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
1690 // Exclusion of validated entries at the time of deletion
1691 $sql .= " AND date_validated IS NULL";
1692 $sql .= $sql_filter;
1693
1694 // TODO: In a future we must forbid deletion if record is inside a closed fiscal period.
1695
1696 $resql = $this->db->query($sql);
1697
1698 if (!$resql) {
1699 $this->errors[] = "Error ".$this->db->lasterror();
1700 foreach ($this->errors as $errmsg) {
1701 dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR);
1702 $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
1703 }
1704 $this->db->rollback();
1705 return -1;
1706 }
1707
1708 $this->db->commit();
1709 return 1;
1710 }
1711
1719 public function deleteMvtNum($piecenum, $mode = '')
1720 {
1721 global $conf;
1722
1723 $sql_filter = $this->getCanModifyBookkeepingSQL();
1724 if (!isset($sql_filter)) {
1725 return -1;
1726 }
1727
1728 $nbprocessed = 0;
1729
1730 $this->db->begin();
1731
1732 // first check if line not yet in bookkeeping
1733 $sql = "DELETE";
1734 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element.$mode;
1735 $sql .= " WHERE piece_num = ".(int) $piecenum;
1736 $sql .= " AND date_validated IS NULL"; // For security, exclusion of validated entries at the time of deletion
1737 $sql .= " AND entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
1738 $sql .= $sql_filter;
1739
1740 $resql = $this->db->query($sql);
1741
1742 if (!$resql) {
1743 $this->errors[] = "Error ".$this->db->lasterror();
1744 foreach ($this->errors as $errmsg) {
1745 dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR);
1746 $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
1747 }
1748 $this->db->rollback();
1749 return -1;
1750 } else {
1751 $nbprocessed = $this->db->affected_rows($resql);
1752 }
1753
1754 $this->db->commit();
1755
1756 return $nbprocessed;
1757 }
1758
1766 public function createFromClone(User $user, $fromid)
1767 {
1768 dol_syslog(__METHOD__, LOG_DEBUG);
1769
1770 $error = 0;
1771 $object = new BookKeeping($this->db);
1772
1773 $this->db->begin();
1774
1775 // Load source object
1776 $object->fetch($fromid);
1777 // Reset object
1778 $object->id = 0;
1779
1780 // Clear fields
1781 // ...
1782
1783 // Create clone
1784 $object->context['createfromclone'] = 'createfromclone';
1785 $result = $object->create($user);
1786
1787 // Other options
1788 if ($result < 0) {
1789 $error++;
1790 $this->errors = $object->errors;
1791 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
1792 }
1793
1794 unset($object->context['createfromclone']);
1795
1796 // End
1797 if (!$error) {
1798 $this->db->commit();
1799
1800 return $object->id;
1801 } else {
1802 $this->db->rollback();
1803
1804 return -1;
1805 }
1806 }
1807
1814 public function initAsSpecimen()
1815 {
1816 global $user;
1817
1818 $now = dol_now();
1819
1820 $this->id = 0;
1821 $this->doc_date = $now;
1822 $this->doc_type = '';
1823 $this->doc_ref = '';
1824 $this->fk_doc = 0;
1825 $this->fk_docdet = 0;
1826 $this->thirdparty_code = 'CU001';
1827 $this->subledger_account = '41100001';
1828 $this->subledger_label = 'My customer company';
1829 $this->numero_compte = '411';
1830 $this->label_compte = 'Customer';
1831 $this->label_operation = 'Sales of pea';
1832 $this->debit = 99.9;
1833 $this->credit = 0.0;
1834 $this->amount = 0.0;
1835 $this->sens = 'D';
1836 $this->fk_user_author = $user->id;
1837 $this->import_key = '20201027';
1838 $this->code_journal = 'VT';
1839 $this->journal_label = 'Journal de vente';
1840 $this->piece_num = 1234;
1841 $this->date_creation = $now;
1842
1843 return 1;
1844 }
1845
1853 public function fetchPerMvt($piecenum, $mode = '')
1854 {
1855 global $conf;
1856
1857 $sql = "SELECT piece_num, doc_date, code_journal, journal_label, doc_ref, doc_type,";
1858 $sql .= " date_creation, tms as date_modification, date_validated as date_validation, import_key";
1859 // In llx_accounting_bookkeeping_tmp, field date_export doesn't exist
1860 if ($mode != "_tmp") {
1861 $sql .= ", date_export";
1862 }
1863 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element.$mode;
1864 $sql .= " WHERE piece_num = ".((int) $piecenum);
1865 $sql .= " AND entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
1866
1867 dol_syslog(__METHOD__, LOG_DEBUG);
1868 $result = $this->db->query($sql);
1869 if ($result) {
1870 $obj = $this->db->fetch_object($result);
1871
1872 $this->piece_num = $obj->piece_num;
1873 $this->code_journal = $obj->code_journal;
1874 $this->journal_label = $obj->journal_label;
1875 $this->doc_date = $this->db->jdate($obj->doc_date);
1876 $this->doc_ref = $obj->doc_ref;
1877 $this->doc_type = $obj->doc_type;
1878 $this->date_creation = $this->db->jdate($obj->date_creation);
1879 $this->date_modification = $this->db->jdate($obj->date_modification);
1880 if ($mode != "_tmp") {
1881 $this->date_export = $this->db->jdate($obj->date_export);
1882 }
1883 $this->date_validation = $this->db->jdate($obj->date_validation);
1884 $this->import_key = $obj->import_key;
1885 } else {
1886 $this->error = "Error ".$this->db->lasterror();
1887 dol_syslog(__METHOD__.$this->error, LOG_ERR);
1888 return -1;
1889 }
1890
1891 return 1;
1892 }
1893
1900 public function getNextNumMvt($mode = '')
1901 {
1902 global $conf;
1903
1904 $sql = "SELECT MAX(piece_num)+1 as max FROM ".MAIN_DB_PREFIX.$this->table_element.$mode;
1905 $sql .= " WHERE entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
1906
1907 dol_syslog(get_class($this)."::getNextNumMvt", LOG_DEBUG);
1908
1909 $result = $this->db->query($sql);
1910
1911 if ($result) {
1912 $obj = $this->db->fetch_object($result);
1913 if ($obj) {
1914 $result = $obj->max;
1915 }
1916 if (empty($result)) {
1917 $result = 1;
1918 }
1919 return $result;
1920 } else {
1921 $this->error = "Error ".$this->db->lasterror();
1922 dol_syslog(get_class($this)."::getNextNumMvt ".$this->error, LOG_ERR);
1923 return -1;
1924 }
1925 }
1926
1934 public function fetchAllPerMvt($piecenum, $mode = '')
1935 {
1936 global $conf;
1937
1938 $sql = "SELECT rowid, doc_date, doc_type,";
1939 $sql .= " doc_ref, fk_doc, fk_docdet, thirdparty_code, subledger_account, subledger_label,";
1940 $sql .= " numero_compte, label_compte, label_operation, debit, credit,";
1941 $sql .= " montant as amount, sens, fk_user_author, import_key, code_journal, journal_label, piece_num,";
1942 $sql .= " date_creation, tms as date_modification, date_validated as date_validation";
1943 // In llx_accounting_bookkeeping_tmp, field date_export doesn't exist
1944 if ($mode != "_tmp") {
1945 $sql .= ", date_export";
1946 }
1947 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element.$mode;
1948 $sql .= " WHERE piece_num = ".((int) $piecenum);
1949 $sql .= " AND entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
1950
1951 dol_syslog(__METHOD__, LOG_DEBUG);
1952 $result = $this->db->query($sql);
1953 if ($result) {
1954 while ($obj = $this->db->fetch_object($result)) {
1955 $line = new BookKeepingLine($this->db);
1956
1957 $line->id = $obj->rowid;
1958
1959 $line->doc_date = $this->db->jdate($obj->doc_date);
1960 $line->doc_type = $obj->doc_type;
1961 $line->doc_ref = $obj->doc_ref;
1962 $line->fk_doc = $obj->fk_doc;
1963 $line->fk_docdet = $obj->fk_docdet;
1964 $line->thirdparty_code = $obj->thirdparty_code;
1965 $line->subledger_account = $obj->subledger_account;
1966 $line->subledger_label = $obj->subledger_label;
1967 $line->numero_compte = $obj->numero_compte;
1968 $line->label_compte = $obj->label_compte;
1969 $line->label_operation = $obj->label_operation;
1970 $line->debit = $obj->debit;
1971 $line->credit = $obj->credit;
1972 $line->montant = $obj->amount;
1973 $line->amount = $obj->amount;
1974 $line->sens = $obj->sens;
1975 $line->code_journal = $obj->code_journal;
1976 $line->journal_label = $obj->journal_label;
1977 $line->piece_num = $obj->piece_num;
1978 $line->date_creation = $obj->date_creation;
1979 $line->date_modification = $obj->date_modification;
1980 if ($mode != "_tmp") {
1981 $line->date_export = $obj->date_export;
1982 }
1983 $line->date_validation = $obj->date_validation;
1984
1985 $this->linesmvt[] = $line;
1986 }
1987 } else {
1988 $this->error = "Error ".$this->db->lasterror();
1989 dol_syslog(__METHOD__.$this->error, LOG_ERR);
1990 return -1;
1991 }
1992
1993 return 1;
1994 }
1995
1996 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2003 public function export_bookkeeping($model = 'ebp')
2004 {
2005 // phpcs:enable
2006 global $conf;
2007
2008 $sql = "SELECT rowid, doc_date, doc_type,";
2009 $sql .= " doc_ref, fk_doc, fk_docdet, thirdparty_code, subledger_account, subledger_label,";
2010 $sql .= " numero_compte, label_compte, label_operation, debit, credit,";
2011 $sql .= " montant as amount, sens, fk_user_author, import_key, code_journal, piece_num,";
2012 $sql .= " date_validated as date_validation";
2013 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element;
2014 $sql .= " WHERE entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
2015
2016 dol_syslog(get_class($this)."::export_bookkeeping", LOG_DEBUG);
2017
2018 $resql = $this->db->query($sql);
2019
2020 if ($resql) {
2021 $this->linesexport = array();
2022
2023 $num = $this->db->num_rows($resql);
2024 while ($obj = $this->db->fetch_object($resql)) {
2025 $line = new BookKeepingLine($this->db);
2026
2027 $line->id = $obj->rowid;
2028
2029 $line->doc_date = $this->db->jdate($obj->doc_date);
2030 $line->doc_type = $obj->doc_type;
2031 $line->doc_ref = $obj->doc_ref;
2032 $line->fk_doc = $obj->fk_doc;
2033 $line->fk_docdet = $obj->fk_docdet;
2034 $line->thirdparty_code = $obj->thirdparty_code;
2035 $line->subledger_account = $obj->subledger_account;
2036 $line->subledger_label = $obj->subledger_label;
2037 $line->numero_compte = $obj->numero_compte;
2038 $line->label_compte = $obj->label_compte;
2039 $line->label_operation = $obj->label_operation;
2040 $line->debit = $obj->debit;
2041 $line->credit = $obj->credit;
2042 $line->montant = $obj->amount;
2043 $line->amount = $obj->amount;
2044 $line->sens = $obj->sens;
2045 $line->code_journal = $obj->code_journal;
2046 $line->piece_num = $obj->piece_num;
2047 $line->date_validation = $obj->date_validation;
2048
2049 $this->linesexport[] = $line;
2050 }
2051 $this->db->free($resql);
2052
2053 return $num;
2054 } else {
2055 $this->error = "Error ".$this->db->lasterror();
2056 dol_syslog(get_class($this)."::export_bookkeeping ".$this->error, LOG_ERR);
2057 return -1;
2058 }
2059 }
2060
2068 public function transformTransaction($direction = 0, $piece_num = '')
2069 {
2070 global $conf;
2071
2072 $error = 0;
2073
2074 $sql_filter = $this->getCanModifyBookkeepingSQL();
2075
2076 if (!isset($sql_filter)) {
2077 return -1;
2078 }
2079
2080 $this->db->begin();
2081
2082 if ($direction == 0) {
2083 $next_piecenum = $this->getNextNumMvt();
2084 $now = dol_now();
2085
2086 if ($next_piecenum < 0) {
2087 $error++;
2088 }
2089
2090 if (!$error) {
2091 // Delete if there is an empty line
2092 $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";
2093 $resql = $this->db->query($sql);
2094 if (!$resql) {
2095 $error++;
2096 $this->errors[] = 'Error '.$this->db->lasterror();
2097 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
2098 }
2099 }
2100
2101 if (!$error) {
2102 $sql = 'INSERT INTO '.MAIN_DB_PREFIX.$this->table_element.' (doc_date, doc_type,';
2103 $sql .= ' doc_ref, fk_doc, fk_docdet, entity, thirdparty_code, subledger_account, subledger_label,';
2104 $sql .= ' numero_compte, label_compte, label_operation, debit, credit,';
2105 $sql .= ' montant, sens, fk_user_author, import_key, code_journal, journal_label, piece_num, date_creation)';
2106 $sql .= ' SELECT doc_date, doc_type,';
2107 $sql .= ' doc_ref, fk_doc, fk_docdet, entity, thirdparty_code, subledger_account, subledger_label,';
2108 $sql .= ' numero_compte, label_compte, label_operation, debit, credit,';
2109 $sql .= ' montant, sens, fk_user_author, import_key, code_journal, journal_label, '.((int) $next_piecenum).", '".$this->db->idate($now)."'";
2110 $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);
2111 $sql .= $sql_filter;
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
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 } elseif ($direction == 1) {
2130 if (!$error) {
2131 $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.'_tmp WHERE piece_num = '.((int) $piece_num).' AND entity = ' .((int) $conf->entity);
2132 $resql = $this->db->query($sql);
2133 if (!$resql) {
2134 $error++;
2135 $this->errors[] = 'Error '.$this->db->lasterror();
2136 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
2137 }
2138 }
2139
2140 if (!$error) {
2141 $sql = 'INSERT INTO '.MAIN_DB_PREFIX.$this->table_element.'_tmp (doc_date, doc_type,';
2142 $sql .= ' doc_ref, fk_doc, fk_docdet, thirdparty_code, subledger_account, subledger_label,';
2143 $sql .= ' numero_compte, label_compte, label_operation, debit, credit,';
2144 $sql .= ' montant, sens, fk_user_author, import_key, code_journal, journal_label, piece_num)';
2145 $sql .= ' SELECT doc_date, doc_type,';
2146 $sql .= ' doc_ref, fk_doc, fk_docdet, thirdparty_code, subledger_account, subledger_label,';
2147 $sql .= ' numero_compte, label_compte, label_operation, debit, credit,';
2148 $sql .= ' montant, sens, fk_user_author, import_key, code_journal, journal_label, piece_num';
2149 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' WHERE piece_num = '.((int) $piece_num).' AND entity = ' .((int) $conf->entity);
2150 $sql .= $sql_filter;
2151 $resql = $this->db->query($sql);
2152 if (!$resql) {
2153 $error++;
2154 $this->errors[] = 'Error '.$this->db->lasterror();
2155 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
2156 }
2157 }
2158
2159 if (!$error) {
2160 $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.'_tmp WHERE piece_num = '.((int) $piece_num).' AND entity = ' .((int) $conf->entity);
2161 $sql .= $sql_filter;
2162 $resql = $this->db->query($sql);
2163 if (!$resql) {
2164 $error++;
2165 $this->errors[] = 'Error '.$this->db->lasterror();
2166 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
2167 }
2168 }
2169 }
2170 if (!$error) {
2171 $this->db->commit();
2172 return 1;
2173 } else {
2174 $this->db->rollback();
2175 return -1;
2176 }
2177 /*
2178 $sql = "DELETE FROM ";
2179 $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping as ab";
2180 $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "accounting_account as aa ON aa.account_number = ab.numero_compte";
2181 $sql .= " AND aa.active = 1";
2182 $sql .= " INNER JOIN " . MAIN_DB_PREFIX . "accounting_system as asy ON aa.fk_pcg_version = asy.pcg_version";
2183 $sql .= " AND asy.rowid = " . ((int) $pcgver);
2184 $sql .= " AND ab.entity IN (" . getEntity('accountancy') . ")";
2185 $sql .= " ORDER BY account_number ASC";
2186 */
2187 }
2188
2189 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2202 public function select_account($selectid, $htmlname = 'account', $showempty = 0, $event = array(), $select_in = 0, $select_out = 0, $aabase = '')
2203 {
2204 // phpcs:enable
2205 global $conf;
2206
2207 require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php';
2208
2209 $pcgver = getDolGlobalInt('CHARTOFACCOUNTS');
2210
2211 $sql = "SELECT DISTINCT ab.numero_compte as account_number, aa.label as label, aa.rowid as rowid, aa.fk_pcg_version";
2212 $sql .= " FROM ".MAIN_DB_PREFIX."accounting_bookkeeping as ab";
2213 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."accounting_account as aa ON aa.account_number = ab.numero_compte";
2214 $sql .= " AND aa.active = 1";
2215 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."accounting_system as asy ON aa.fk_pcg_version = asy.pcg_version";
2216 $sql .= " AND asy.rowid = ".((int) $pcgver);
2217 $sql .= " AND ab.entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
2218 $sql .= " ORDER BY account_number ASC";
2219
2220 dol_syslog(get_class($this)."::select_account", LOG_DEBUG);
2221 $resql = $this->db->query($sql);
2222
2223 if (!$resql) {
2224 $this->error = "Error ".$this->db->lasterror();
2225 dol_syslog(get_class($this)."::select_account ".$this->error, LOG_ERR);
2226 return "-1";
2227 }
2228
2229 $out = ajax_combobox($htmlname, $event);
2230
2231 $options = array();
2232 $selected = null;
2233
2234 while ($obj = $this->db->fetch_object($resql)) {
2235 $label = length_accountg($obj->account_number).' - '.$obj->label;
2236
2237 $select_value_in = $obj->rowid;
2238 $select_value_out = $obj->rowid;
2239
2240 if ($select_in == 1) {
2241 $select_value_in = $obj->account_number;
2242 }
2243 if ($select_out == 1) {
2244 $select_value_out = $obj->account_number;
2245 }
2246
2247 // Remember guy's we store in database llx_facturedet the rowid of accounting_account and not the account_number
2248 // Because same account_number can be share between different accounting_system and do have the same meaning
2249 if (($selectid != '') && $selectid == $select_value_in) {
2250 $selected = $select_value_out;
2251 }
2252
2253 $options[$select_value_out] = $label;
2254 }
2255
2256 $out .= Form::selectarray($htmlname, $options, $selected, $showempty, 0, 0, '', 0, 0, 0, '', 'maxwidth300');
2257 $this->db->free($resql);
2258 return $out;
2259 }
2260
2268 public function getRootAccount($account = null)
2269 {
2270 global $conf;
2271 $pcgver = getDolGlobalInt('CHARTOFACCOUNTS');
2272
2273 $sql = "SELECT root.rowid, root.account_number, root.label as label,";
2274 $sql .= " parent.rowid as parent_rowid, parent.account_number as parent_account_number, parent.label as parent_label";
2275 $sql .= " FROM ".MAIN_DB_PREFIX."accounting_account as aa";
2276 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."accounting_system as asy ON aa.fk_pcg_version = asy.pcg_version";
2277 $sql .= " AND asy.rowid = ".((int) $pcgver);
2278 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."accounting_account as parent ON aa.account_parent = parent.rowid AND parent.active = 1";
2279 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."accounting_account as root ON parent.account_parent = root.rowid AND root.active = 1";
2280 $sql .= " WHERE aa.account_number = '".$this->db->escape($account)."'";
2281 $sql .= " AND aa.entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
2282
2283 dol_syslog(get_class($this)."::select_account", LOG_DEBUG);
2284 $resql = $this->db->query($sql);
2285 if ($resql) {
2286 $obj = '';
2287 if ($this->db->num_rows($resql)) {
2288 $obj = $this->db->fetch_object($resql);
2289 }
2290
2291 $result = array('id' => $obj->rowid, 'account_number' => $obj->account_number, 'label' => $obj->label);
2292 return $result;
2293 } else {
2294 $this->error = "Error ".$this->db->lasterror();
2295 dol_syslog(__METHOD__." ".$this->error, LOG_ERR);
2296
2297 return -1;
2298 }
2299 }
2300
2301 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2308 public function get_compte_desc($account = null)
2309 {
2310 // phpcs:enable
2311 global $conf;
2312
2313 $pcgver = getDolGlobalInt('CHARTOFACCOUNTS');
2314 $sql = "SELECT aa.account_number, aa.label, aa.rowid, aa.fk_pcg_version, cat.label as category";
2315 $sql .= " FROM ".MAIN_DB_PREFIX."accounting_account as aa ";
2316 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."accounting_system as asy ON aa.fk_pcg_version = asy.pcg_version";
2317 $sql .= " AND aa.account_number = '".$this->db->escape($account)."'";
2318 $sql .= " AND asy.rowid = ".((int) $pcgver);
2319 $sql .= " AND aa.active = 1";
2320 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_accounting_category as cat ON aa.fk_accounting_category = cat.rowid";
2321 $sql .= " WHERE aa.entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
2322
2323 dol_syslog(get_class($this)."::select_account", LOG_DEBUG);
2324 $resql = $this->db->query($sql);
2325 if ($resql) {
2326 $obj = (object) array('label' => '');
2327 if ($this->db->num_rows($resql)) {
2328 $obj = $this->db->fetch_object($resql);
2329 }
2330 if (empty($obj->category)) {
2331 return $obj->label;
2332 } else {
2333 return $obj->label.' ('.$obj->category.')';
2334 }
2335 } else {
2336 $this->error = "Error ".$this->db->lasterror();
2337 dol_syslog(__METHOD__." ".$this->error, LOG_ERR);
2338 return "-1";
2339 }
2340 }
2341
2349 public function getCanModifyBookkeepingSQL($alias = '', $force = false)
2350 {
2351 global $conf;
2352
2353 $alias = trim($alias);
2354 $alias = !empty($alias) && strpos($alias, '.') < 0 ? $alias . "." : $alias;
2355
2356 if (!isset(self::$can_modify_bookkeeping_sql_cached[$alias]) || $force) {
2357 $result = $this->loadFiscalPeriods($force, 'active');
2358 if ($result < 0) {
2359 return null;
2360 }
2361
2362 $sql_list = array();
2363 if (!empty($conf->cache['active_fiscal_period_cached']) && is_array($conf->cache['active_fiscal_period_cached'])) {
2364 $i = 0;
2365 foreach ($conf->cache['active_fiscal_period_cached'] as $fiscal_period) {
2366 $sql_list[$i] = "(";
2367 $sql_list[$i] .= "'".$this->db->idate($fiscal_period['date_start']) . "' <= ".$this->db->sanitize($alias)."doc_date";
2368 if (!empty($fiscal_period['date_end'])) {
2369 $sql_list[$i] .= " AND ";
2370 $sql_list[$i] .= $this->db->sanitize($alias)."doc_date <= '" . $this->db->idate($fiscal_period['date_end'])."'";
2371 }
2372 $sql_list[$i] .= ")";
2373 $i++;
2374 }
2375 }
2376 $sqlsanitized = implode(' OR ', $sql_list);
2377 self::$can_modify_bookkeeping_sql_cached[$alias] = empty($sql_list) ? "" : " AND (".$sqlsanitized.")";
2378 }
2379
2380 return self::$can_modify_bookkeeping_sql_cached[$alias];
2381 }
2382
2390 public function canModifyBookkeeping($id, $mode = '')
2391 {
2392 global $conf;
2393
2394 if (getDolGlobalString('ACCOUNTANCY_FISCAL_PERIOD_MODE') == 'blockedonclosed') {
2395 $result = $this->loadFiscalPeriods(false, 'closed');
2396
2397 if ($result < 0) {
2398 return -1;
2399 }
2400
2401 $bookkeeping = new BookKeeping($this->db);
2402 $result = $bookkeeping->fetch($id, null, $mode);
2403 if ($result <= 0) {
2404 return $result;
2405 }
2406
2407 if (!empty($conf->cache['closed_fiscal_period_cached']) && is_array($conf->cache['closed_fiscal_period_cached'])) {
2408 foreach ($conf->cache['closed_fiscal_period_cached'] as $fiscal_period) {
2409 if ($fiscal_period['date_start'] <= $bookkeeping->doc_date && $bookkeeping->doc_date <= $fiscal_period['date_end']) {
2410 return 0;
2411 }
2412 }
2413 }
2414
2415 return 1;
2416 } else {
2417 $result = $this->loadFiscalPeriods(false, 'active');
2418 if ($result < 0) {
2419 return -1;
2420 }
2421
2422 $bookkeeping = new BookKeeping($this->db);
2423 $result = $bookkeeping->fetch($id, null, $mode);
2424
2425 if ($result <= 0) {
2426 return $result;
2427 }
2428 if (!empty($conf->cache['active_fiscal_period_cached']) && is_array($conf->cache['active_fiscal_period_cached'])) {
2429 foreach ($conf->cache['active_fiscal_period_cached'] as $fiscal_period) {
2430 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'])) {
2431 return 1;
2432 }
2433 }
2434 }
2435
2436 return 0;
2437 }
2438 }
2439
2446 public function validBookkeepingDate($date)
2447 {
2448 global $conf;
2449
2450 if (getDolGlobalString('ACCOUNTANCY_FISCAL_PERIOD_MODE') == 'blockedonclosed') {
2451 $result = $this->loadFiscalPeriods(false, 'closed');
2452
2453 if ($result < 0) {
2454 return -1;
2455 }
2456
2457 if (!empty($conf->cache['closed_fiscal_period_cached']) && is_array($conf->cache['closed_fiscal_period_cached'])) {
2458 foreach ($conf->cache['closed_fiscal_period_cached'] as $fiscal_period) {
2459 if ($fiscal_period['date_start'] <= $date && $date <= $fiscal_period['date_end']) {
2460 return 0;
2461 }
2462 }
2463 }
2464
2465 return 1;
2466 } else {
2467 $result = $this->loadFiscalPeriods(false, 'active');
2468 if ($result < 0) {
2469 return -1;
2470 }
2471
2472 if (!empty($conf->cache['active_fiscal_period_cached']) && is_array($conf->cache['active_fiscal_period_cached'])) {
2473 foreach ($conf->cache['active_fiscal_period_cached'] as $fiscal_period) {
2474 if (!empty($fiscal_period['date_start']) && $fiscal_period['date_start'] <= $date && (empty($fiscal_period['date_end']) || $date <= $fiscal_period['date_end'])) {
2475 return 1;
2476 }
2477 }
2478 }
2479
2480 return 0;
2481 }
2482 }
2483
2491 public function loadFiscalPeriods($force = false, $mode = 'active')
2492 {
2493 global $conf;
2494
2495 if ($mode == 'active') {
2496 if (!isset($conf->cache['active_fiscal_period_cached']) || $force) {
2497 $sql = "SELECT date_start, date_end";
2498 $sql .= " FROM " . $this->db->prefix() . "accounting_fiscalyear";
2499 $sql .= " WHERE entity = " . ((int) $conf->entity);
2500 $sql .= " AND statut = 0";
2501
2502 $resql = $this->db->query($sql);
2503 if (!$resql) {
2504 $this->errors[] = $this->db->lasterror();
2505 return -1;
2506 }
2507
2508 $list = array();
2509 while ($obj = $this->db->fetch_object($resql)) {
2510 $list[] = array(
2511 'date_start' => $this->db->jdate($obj->date_start),
2512 'date_end' => $this->db->jdate($obj->date_end),
2513 );
2514 }
2515 $conf->cache['active_fiscal_period_cached'] = $list;
2516 }
2517 }
2518 if ($mode == 'closed') {
2519 if (!isset($conf->cache['closed_fiscal_period_cached']) || $force) {
2520 $sql = "SELECT date_start, date_end";
2521 $sql .= " FROM " . $this->db->prefix() . "accounting_fiscalyear";
2522 $sql .= " WHERE entity = " . ((int) $conf->entity);
2523 $sql .= " AND statut = 1";
2524
2525 $resql = $this->db->query($sql);
2526 if (!$resql) {
2527 $this->errors[] = $this->db->lasterror();
2528 return -1;
2529 }
2530
2531 $list = array();
2532 while ($obj = $this->db->fetch_object($resql)) {
2533 $list[] = array(
2534 'date_start' => $this->db->jdate($obj->date_start),
2535 'date_end' => $this->db->jdate($obj->date_end),
2536 );
2537 }
2538 $conf->cache['closed_fiscal_period_cached'] = $list;
2539 }
2540 }
2541
2542 return 1;
2543 }
2544
2551 public function getFiscalPeriods($filter = '')
2552 {
2553 global $conf;
2554 $list = array();
2555
2556 $sql = "SELECT rowid, label, date_start, date_end, statut";
2557 $sql .= " FROM " . $this->db->prefix() . "accounting_fiscalyear";
2558 $sql .= " WHERE entity = " . ((int) $conf->entity);
2559 if (!empty($filter)) {
2560 $sql .= " AND (" . $this->db->sanitize($filter, 1, 1, 1) . ')';
2561 }
2562 $sql .= $this->db->order('date_start', 'ASC');
2563
2564 $resql = $this->db->query($sql);
2565 if (!$resql) {
2566 $this->errors[] = $this->db->lasterror();
2567 return -1;
2568 }
2569
2570 while ($obj = $this->db->fetch_object($resql)) {
2571 $list[$obj->rowid] = array(
2572 'id' => (int) $obj->rowid,
2573 'label' => $obj->label,
2574 'date_start' => $this->db->jdate($obj->date_start),
2575 'date_end' => $this->db->jdate($obj->date_end),
2576 'status' => (int) $obj->statut,
2577 );
2578 }
2579
2580 return $list;
2581 }
2582
2590 public function getCountByMonthForFiscalPeriod($date_start, $date_end)
2591 {
2592 $total = 0;
2593 $list = array();
2594
2595 $sql = "SELECT YEAR(b.doc_date) as year";
2596 for ($i = 1; $i <= 12; $i++) {
2597 $sql .= ", SUM(".$this->db->ifsql("MONTH(b.doc_date) = ".((int) $i), "1", "0") . ") AS month".((int) $i);
2598 }
2599 $sql .= ", COUNT(b.rowid) as total";
2600 $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping as b";
2601 $sql .= " WHERE b.doc_date >= '" . $this->db->idate($date_start) . "'";
2602 $sql .= " AND b.doc_date <= '" . $this->db->idate($date_end) . "'";
2603 $sql .= " AND b.entity IN (" . getEntity('bookkeeping', 0) . ")"; // We don't share object for accountancy
2604
2605 // Get count for each month into the fiscal period
2606 if (getDolGlobalString("ACCOUNTANCY_DISABLE_CLOSURE_LINE_BY_LINE")) {
2607 // TODO Analyse is done by finding record not into a closed period
2608 // Loop on each closed period
2609 $sql .= " AND b.doc_date BETWEEN 0 AND 0";
2610 } else {
2611 // Analyse closed record using the unitary flag/date on each record
2612 $sql .= " AND date_validated IS NULL";
2613 }
2614
2615 $sql .= " GROUP BY YEAR(b.doc_date)";
2616 $sql .= $this->db->order("year", 'ASC');
2617
2618 dol_syslog(__METHOD__, LOG_DEBUG);
2619 $resql = $this->db->query($sql);
2620 if (!$resql) {
2621 $this->errors[] = $this->db->lasterror();
2622 return -1;
2623 }
2624
2625 while ($obj = $this->db->fetch_object($resql)) {
2626 $total += (int) $obj->total;
2627 $year_list = array(
2628 'year' => (int) $obj->year,
2629 'count' => array(),
2630 'total' => (int) $obj->total,
2631 );
2632 for ($i = 1; $i <= 12; $i++) {
2633 $year_list['count'][$i] = (int) $obj->{'month' . $i};
2634 }
2635
2636 $list[] = $year_list;
2637 }
2638
2639 $this->db->free($resql);
2640
2641 return array(
2642 'total' => $total,
2643 'list' => $list,
2644 );
2645 }
2646
2654 public function validateMovementForFiscalPeriod($date_start, $date_end)
2655 {
2656 global $conf;
2657
2658 $now = dol_now();
2659
2660 // Specify as export : update field date_validated on selected month/year
2661 $sql = " UPDATE " . MAIN_DB_PREFIX . "accounting_bookkeeping";
2662 $sql .= " SET date_validated = '" . $this->db->idate($now) . "'";
2663 $sql .= " WHERE entity = " . ((int) $conf->entity);
2664 $sql .= " AND DATE(doc_date) >= '" . $this->db->idate($date_start) . "'";
2665 $sql .= " AND DATE(doc_date) <= '" . $this->db->idate($date_end) . "'";
2666 $sql .= " AND date_validated IS NULL";
2667
2668 dol_syslog(__METHOD__, LOG_DEBUG);
2669 $resql = $this->db->query($sql);
2670 if (!$resql) {
2671 $this->errors[] = $this->db->lasterror();
2672 return -1;
2673 }
2674
2675 return 1;
2676 }
2677
2685 public function accountingResult($date_start, $date_end)
2686 {
2687 global $conf;
2688
2689 $this->db->begin();
2690
2691 $income_statement_amount = 0;
2692
2693 if (getDolGlobalString('ACCOUNTING_CLOSURE_ACCOUNTING_GROUPS_USED_FOR_INCOME_STATEMENT')) {
2694 $accounting_groups_used_for_income_statement = array_filter(array_map('trim', explode(',', getDolGlobalString('ACCOUNTING_CLOSURE_ACCOUNTING_GROUPS_USED_FOR_INCOME_STATEMENT'))), 'strlen');
2695
2696 $pcg_type_filter = array();
2697 foreach ($accounting_groups_used_for_income_statement as $item) {
2698 $pcg_type_filter[] = "'" . $this->db->escape($item) . "'";
2699 }
2700
2701 $sql = 'SELECT';
2702 $sql .= " t.numero_compte,";
2703 $sql .= " aa.pcg_type,";
2704 $sql .= " (SUM(t.credit) - SUM(t.debit)) as accounting_result";
2705 $sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . ' as t';
2706 $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'accounting_account as aa ON aa.account_number = t.numero_compte';
2707 $sql .= ' WHERE t.entity = ' . ((int) $conf->entity); // Do not use getEntity for accounting features
2708 $sql .= " AND aa.entity = " . ((int) $conf->entity);
2709 $sql .= ' AND aa.fk_pcg_version IN (SELECT pcg_version FROM ' . MAIN_DB_PREFIX . 'accounting_system WHERE rowid = ' . ((int) getDolGlobalInt('CHARTOFACCOUNTS')) . ')';
2710 $sql .= ' AND aa.pcg_type IN (' . $this->db->sanitize(implode(',', $pcg_type_filter), 1) . ')';
2711 $sql .= " AND DATE(t.doc_date) >= '" . $this->db->idate($date_start) . "'";
2712 $sql .= " AND DATE(t.doc_date) <= '" . $this->db->idate($date_end) . "'";
2713 $sql .= ' GROUP BY t.numero_compte, aa.pcg_type';
2714
2715 $resql = $this->db->query($sql);
2716 if (!$resql) {
2717 $this->errors[] = 'Error ' . $this->db->lasterror();
2718 dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
2719 } else {
2720 while ($obj = $this->db->fetch_object($resql)) {
2721 $income_statement_amount += $obj->accounting_result;
2722 }
2723 }
2724 }
2725
2726 return (string) $income_statement_amount;
2727 }
2728
2738 public function closeFiscalPeriod($fiscal_period_id, $new_fiscal_period_id, $separate_auxiliary_account = false, $generate_bookkeeping_records = true)
2739 {
2740 global $conf, $langs, $user;
2741
2742 // Current fiscal period
2743 $fiscal_period_id = max(0, $fiscal_period_id);
2744 if (empty($fiscal_period_id)) {
2745 $langs->load('errors');
2746 $this->errors[] = $langs->trans('ErrorBadParameters');
2747 return -1;
2748 }
2749 $fiscal_period = new Fiscalyear($this->db);
2750 $result = $fiscal_period->fetch($fiscal_period_id);
2751 if ($result < 0) {
2752 $this->error = $fiscal_period->error;
2753 $this->errors = $fiscal_period->errors;
2754 return -1;
2755 } elseif (empty($fiscal_period->id)) {
2756 $langs->loadLangs(array('errors', 'compta'));
2757 $this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('FiscalPeriod') . ' (' . $fiscal_period_id . ')';
2758 return -1;
2759 }
2760
2761 // New fiscal period
2762 $new_fiscal_period_id = max(0, $new_fiscal_period_id);
2763 if (empty($new_fiscal_period_id)) {
2764 $langs->load('errors');
2765 $this->errors[] = $langs->trans('ErrorBadParameters');
2766 return -1;
2767 }
2768 $new_fiscal_period = new Fiscalyear($this->db);
2769 $result = $new_fiscal_period->fetch($new_fiscal_period_id);
2770 if ($result < 0) {
2771 $this->error = $new_fiscal_period->error;
2772 $this->errors = $new_fiscal_period->errors;
2773 return -1;
2774 } elseif (empty($new_fiscal_period->id)) {
2775 $langs->loadLangs(array('errors', 'compta'));
2776 $this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('FiscalPeriod') . ' (' . $new_fiscal_period_id . ')';
2777 return -1;
2778 }
2779
2780 $error = 0;
2781 $this->db->begin();
2782
2783 $fiscal_period->statut = Fiscalyear::STATUS_CLOSED;
2784 $fiscal_period->status = Fiscalyear::STATUS_CLOSED; // Actually not used
2785 $result = $fiscal_period->update($user);
2786 if ($result < 0) {
2787 $this->error = $fiscal_period->error;
2788 $this->errors = $fiscal_period->errors;
2789 $error++;
2790 }
2791
2792 if (!$error && !empty($generate_bookkeeping_records)) {
2793 $journal_id = max(0, getDolGlobalString('ACCOUNTING_CLOSURE_DEFAULT_JOURNAL'));
2794 if (empty($journal_id)) {
2795 $langs->loadLangs(array('errors', 'accountancy'));
2796 $this->errors[] = $langs->trans('ErrorBadParameters') . ' - ' . $langs->trans('Codejournal') . ' (' . $langs->trans('AccountingJournalType9') . ')';
2797 $error++;
2798 }
2799
2800 // Fetch journal
2801 if (!$error) {
2802 $journal = new AccountingJournal($this->db);
2803 $result = $journal->fetch($journal_id);
2804 if ($result < 0) {
2805 $this->error = $journal->error;
2806 $this->errors = $journal->errors;
2807 $error++;
2808 } elseif ($result == 0) {
2809 $langs->loadLangs(array('errors', 'accountancy'));
2810 $this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('Codejournal') . ' (' . $langs->trans('AccountingJournalType9') . ')';
2811 $error++;
2812 }
2813 }
2814
2815 if (!$error) {
2816 $accounting_groups_used_for_balance_sheet_account = array_filter(array_map('trim', explode(',', getDolGlobalString('ACCOUNTING_CLOSURE_ACCOUNTING_GROUPS_USED_FOR_BALANCE_SHEET_ACCOUNT'))), 'strlen');
2817 $accounting_groups_used_for_income_statement = array_filter(array_map('trim', explode(',', getDolGlobalString('ACCOUNTING_CLOSURE_ACCOUNTING_GROUPS_USED_FOR_INCOME_STATEMENT'))), 'strlen');
2818
2819 $pcg_type_filter = array();
2820 $tmp = array_merge($accounting_groups_used_for_balance_sheet_account, $accounting_groups_used_for_income_statement);
2821 foreach ($tmp as $item) {
2822 $pcg_type_filter[] = "'" . $this->db->escape($item) . "'";
2823 }
2824
2825 $sql = 'SELECT';
2826 $sql .= " t.numero_compte,";
2827 if ($separate_auxiliary_account) {
2828 $sql .= " NULLIF(t.subledger_account, '') as subledger_account,"; // fix db issues with Null or "" values
2829 }
2830 $sql .= " aa.pcg_type,";
2831 $sql .= " (SUM(t.credit) - SUM(t.debit)) as opening_balance";
2832 $sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . ' as t';
2833 $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'accounting_account as aa ON aa.account_number = t.numero_compte';
2834 $sql .= ' WHERE t.entity = ' . ((int) $conf->entity); // Do not use getEntity for accounting features
2835 $sql .= " AND aa.entity = ". ((int) $conf->entity);
2836 $sql .= ' AND aa.fk_pcg_version IN (SELECT pcg_version FROM '.MAIN_DB_PREFIX.'accounting_system WHERE rowid = '.((int) getDolGlobalInt('CHARTOFACCOUNTS')).')';
2837 $sql .= ' AND aa.pcg_type IN (' . $this->db->sanitize(implode(',', $pcg_type_filter), 1) . ')';
2838 $sql .= " AND DATE(t.doc_date) >= '" . $this->db->idate($fiscal_period->date_start) . "'";
2839 $sql .= " AND DATE(t.doc_date) <= '" . $this->db->idate($fiscal_period->date_end) . "'";
2840 $sql .= ' GROUP BY t.numero_compte, aa.pcg_type';
2841 if ($separate_auxiliary_account) {
2842 $sql .= " , NULLIF(t.subledger_account, '')";
2843 }
2844 $sql .= ' HAVING (SUM(t.credit) - SUM(t.debit)) != 0 '; // Exclude rows with opening_balance = 0
2845 $sql .= $this->db->order("t.numero_compte", "ASC");
2846
2847 $resql = $this->db->query($sql);
2848 if (!$resql) {
2849 $this->errors[] = 'Error ' . $this->db->lasterror();
2850 dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
2851
2852 $error++;
2853 } else {
2854 $now = dol_now();
2855 $income_statement_amount = 0;
2856 while ($obj = $this->db->fetch_object($resql)) {
2857 if (in_array($obj->pcg_type, $accounting_groups_used_for_income_statement)) {
2858 $income_statement_amount += $obj->opening_balance;
2859 } else {
2860 // Insert bookkeeping record for balance sheet account
2861 $mt = $obj->opening_balance;
2862
2863 $bookkeeping = new BookKeeping($this->db);
2864 $bookkeeping->doc_date = $new_fiscal_period->date_start;
2865
2866 $bookkeeping->date_lim_reglement = '';
2867 $bookkeeping->doc_ref = $fiscal_period->label;
2868
2869 $bookkeeping->date_creation = $now;
2870 $bookkeeping->doc_type = 'closure';
2871 $bookkeeping->fk_doc = $fiscal_period->id;
2872 $bookkeeping->fk_docdet = 0; // Useless, can be several lines that are source of this record to add
2873 $bookkeeping->thirdparty_code = '';
2874
2875 if ($separate_auxiliary_account) {
2876 $bookkeeping->subledger_account = $obj->subledger_account;
2877 $sql = 'SELECT';
2878 $sql .= " subledger_label";
2879 $sql .= " FROM " . MAIN_DB_PREFIX . $this->table_element;
2880 $sql .= " WHERE subledger_account = '" . $this->db->escape($obj->subledger_account) . "'";
2881 $sql .= " ORDER BY doc_date DESC";
2882 $sql .= " LIMIT 1";
2883 $result = $this->db->query($sql);
2884 if (!$result) {
2885 $this->errors[] = 'Error: ' . $this->db->lasterror();
2886 dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
2887 $error++;
2888 }
2889 $objtmp = $this->db->fetch_object($result);
2890 $bookkeeping->subledger_label = $objtmp->subledger_label; // latest subledger label used
2891 } else {
2892 $bookkeeping->subledger_account = null;
2893 $bookkeeping->subledger_label = null;
2894 }
2895
2896 $bookkeeping->numero_compte = $obj->numero_compte;
2897 $accountingaccount = new AccountingAccount($this->db);
2898 $accountingaccount->fetch('', $obj->numero_compte);
2899 $bookkeeping->label_compte = $accountingaccount->label; // latest account label used
2900
2901 $bookkeeping->label_operation = $new_fiscal_period->label;
2902 $bookkeeping->montant = $mt;
2903 $bookkeeping->sens = ($mt >= 0) ? 'C' : 'D';
2904 $bookkeeping->debit = ($mt < 0) ? -$mt : 0;
2905 $bookkeeping->credit = ($mt >= 0) ? $mt : 0;
2906 $bookkeeping->code_journal = $journal->code;
2907 $bookkeeping->journal_label = $langs->transnoentities($journal->label);
2908 $bookkeeping->fk_user_author = $user->id;
2909 $bookkeeping->entity = $conf->entity;
2910
2911 $result = $bookkeeping->create($user);
2912 if ($result < 0) {
2913 $this->error = $bookkeeping->error;
2914 $this->errors = $bookkeeping->errors;
2915 $error++;
2916 break;
2917 }
2918 }
2919 }
2920
2921 // Insert bookkeeping record for income statement
2922 if (!$error && $income_statement_amount != 0) {
2923 $mt = $income_statement_amount;
2924 $accountingaccount = new AccountingAccount($this->db);
2925 $accountingaccount->fetch(null, getDolGlobalString($income_statement_amount < 0 ? 'ACCOUNTING_RESULT_LOSS' : 'ACCOUNTING_RESULT_PROFIT'), true);
2926
2927 $bookkeeping = new BookKeeping($this->db);
2928 $bookkeeping->doc_date = $new_fiscal_period->date_start;
2929
2930 $bookkeeping->date_lim_reglement = '';
2931 $bookkeeping->doc_ref = $fiscal_period->label;
2932
2933 $bookkeeping->date_creation = $now;
2934 $bookkeeping->doc_type = 'closure';
2935 $bookkeeping->fk_doc = $fiscal_period->id;
2936 $bookkeeping->fk_docdet = 0; // Useless, can be several lines that are source of this record to add
2937 $bookkeeping->thirdparty_code = '';
2938
2939 if ($separate_auxiliary_account) {
2940 $bookkeeping->subledger_account = $obj->subledger_account;
2941 $sql = 'SELECT';
2942 $sql .= " subledger_label";
2943 $sql .= " FROM " . MAIN_DB_PREFIX . $this->table_element;
2944 $sql .= " WHERE subledger_account = '" . $this->db->escape($obj->subledger_account) . "'";
2945 $sql .= " ORDER BY doc_date DESC";
2946 $sql .= " LIMIT 1";
2947 $result = $this->db->query($sql);
2948 if (!$result) {
2949 $this->errors[] = 'Error: ' . $this->db->lasterror();
2950 dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
2951 $error++;
2952 }
2953 $objtmp = $this->db->fetch_object($result);
2954 $bookkeeping->subledger_label = $objtmp->subledger_label; // latest subledger label used
2955 } else {
2956 $bookkeeping->subledger_account = null;
2957 $bookkeeping->subledger_label = null;
2958 }
2959
2960 $bookkeeping->numero_compte = $accountingaccount->account_number;
2961 $bookkeeping->label_compte = $accountingaccount->label;
2962
2963 $bookkeeping->label_operation = $new_fiscal_period->label;
2964 $bookkeeping->montant = $mt;
2965 $bookkeeping->sens = ($mt >= 0) ? 'C' : 'D';
2966 $bookkeeping->debit = ($mt < 0) ? -$mt : 0;
2967 $bookkeeping->credit = ($mt >= 0) ? $mt : 0;
2968 $bookkeeping->code_journal = $journal->code;
2969 $bookkeeping->journal_label = $langs->transnoentities($journal->label);
2970 $bookkeeping->fk_user_author = $user->id;
2971 $bookkeeping->entity = $conf->entity;
2972
2973 $result = $bookkeeping->create($user);
2974 if ($result < 0) {
2975 $this->error = $bookkeeping->error;
2976 $this->errors = $bookkeeping->errors;
2977 $error++;
2978 }
2979 }
2980 $this->db->free($resql);
2981 }
2982 }
2983 }
2984
2985 if ($error) {
2986 $this->db->rollback();
2987 return -1;
2988 } else {
2989 $this->db->commit();
2990 return 1;
2991 }
2992 }
2993
3004 public function insertAccountingReversal($fiscal_period_id, $inventory_journal_id, $new_fiscal_period_id, $date_start, $date_end)
3005 {
3006 global $conf, $langs, $user;
3007
3008 // Current fiscal period
3009 $fiscal_period_id = max(0, $fiscal_period_id);
3010 if (empty($fiscal_period_id)) {
3011 $langs->load('errors');
3012 $this->errors[] = $langs->trans('ErrorBadParameters');
3013 return -1;
3014 }
3015 $fiscal_period = new Fiscalyear($this->db);
3016 $result = $fiscal_period->fetch($fiscal_period_id);
3017 if ($result < 0) {
3018 $this->error = $fiscal_period->error;
3019 $this->errors = $fiscal_period->errors;
3020 return -1;
3021 } elseif (empty($fiscal_period->id)) {
3022 $langs->loadLangs(array('errors', 'compta'));
3023 $this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('FiscalPeriod') . ' (' . $fiscal_period_id . ')';
3024 return -1;
3025 }
3026
3027 // New fiscal period
3028 $new_fiscal_period_id = max(0, $new_fiscal_period_id);
3029 if (empty($new_fiscal_period_id)) {
3030 $langs->load('errors');
3031 $this->errors[] = $langs->trans('ErrorBadParameters');
3032 return -1;
3033 }
3034 $new_fiscal_period = new Fiscalyear($this->db);
3035 $result = $new_fiscal_period->fetch($new_fiscal_period_id);
3036 if ($result < 0) {
3037 $this->error = $new_fiscal_period->error;
3038 $this->errors = $new_fiscal_period->errors;
3039 return -1;
3040 } elseif (empty($new_fiscal_period->id)) {
3041 $langs->loadLangs(array('errors', 'compta'));
3042 $this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('FiscalPeriod') . ' (' . $new_fiscal_period_id . ')';
3043 return -1;
3044 }
3045
3046 // Inventory journal
3047 $inventory_journal_id = max(0, $inventory_journal_id);
3048 if (empty($inventory_journal_id)) {
3049 $langs->load('errors');
3050 $this->errors[] = $langs->trans('ErrorBadParameters');
3051 return -1;
3052 }
3053 // Fetch journal
3054 $inventory_journal = new AccountingJournal($this->db);
3055 $result = $inventory_journal->fetch($inventory_journal_id);
3056 if ($result < 0) {
3057 $this->error = $inventory_journal->error;
3058 $this->errors = $inventory_journal->errors;
3059 return -1;
3060 } elseif ($result == 0) {
3061 $langs->loadLangs(array('errors', 'accountancy'));
3062 $this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('InventoryJournal');
3063 return -1;
3064 }
3065
3066 $error = 0;
3067 $this->db->begin();
3068
3069 $sql = 'SELECT t.rowid';
3070 $sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . ' as t';
3071 $sql .= ' WHERE t.entity = ' . ((int) $conf->entity); // Do not use getEntity for accounting features
3072 $sql .= " AND code_journal = '" . $this->db->escape($inventory_journal->code) . "'";
3073 $sql .= " AND DATE(t.doc_date) >= '" . $this->db->idate($date_start) . "'";
3074 $sql .= " AND DATE(t.doc_date) <= '" . $this->db->idate($date_end) . "'";
3075 $sql .= " AND DATE(t.doc_date) >= '" . $this->db->idate($fiscal_period->date_start) . "'";
3076 $sql .= " AND DATE(t.doc_date) <= '" . $this->db->idate($fiscal_period->date_end) . "'";
3077
3078 $resql = $this->db->query($sql);
3079 if (!$resql) {
3080 $this->errors[] = 'Error ' . $this->db->lasterror();
3081 dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
3082
3083 $error++;
3084 } else {
3085 $now = dol_now();
3086 while ($obj = $this->db->fetch_object($resql)) {
3087 $bookkeeping = new BookKeeping($this->db);
3088 $result = $bookkeeping->fetch($obj->rowid);
3089 if ($result < 0) {
3090 $this->error = $inventory_journal->error;
3091 $this->errors = $inventory_journal->errors;
3092 $error++;
3093 break;
3094 } elseif ($result == 0) {
3095 $langs->loadLangs(array('errors', 'accountancy'));
3096 $this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('LineId') . ': ' . $obj->rowid;
3097 $error++;
3098 break;
3099 }
3100
3101 $bookkeeping->id = 0;
3102 $bookkeeping->doc_date = $new_fiscal_period->date_start;
3103 $bookkeeping->doc_ref = $new_fiscal_period->label;
3104 $bookkeeping->date_creation = $now;
3105 $bookkeeping->doc_type = 'accounting_reversal';
3106 $bookkeeping->fk_doc = $new_fiscal_period->id;
3107 $bookkeeping->fk_docdet = 0; // Useless, can be several lines that are source of this record to add
3108
3109 $bookkeeping->montant = -$bookkeeping->montant;
3110 $bookkeeping->sens = ($bookkeeping->montant >= 0) ? 'C' : 'D';
3111 $old_debit = $bookkeeping->debit;
3112 $bookkeeping->debit = $bookkeeping->credit;
3113 $bookkeeping->credit = $old_debit;
3114
3115 $bookkeeping->fk_user_author = $user->id;
3116 $bookkeeping->entity = $conf->entity;
3117
3118 $result = $bookkeeping->create($user);
3119 if ($result < 0) {
3120 $this->error = $bookkeeping->error;
3121 $this->errors = $bookkeeping->errors;
3122 $error++;
3123 break;
3124 }
3125 }
3126 $this->db->free($resql);
3127 }
3128
3129 if ($error) {
3130 $this->db->rollback();
3131 return -1;
3132 } else {
3133 $this->db->commit();
3134 return 1;
3135 }
3136 }
3137}
3138
3143{
3147 public $id;
3148
3149 public $doc_date = null;
3150 public $doc_type;
3151 public $doc_ref;
3152
3156 public $fk_doc;
3157
3161 public $fk_docdet;
3162
3163 public $thirdparty_code;
3164 public $subledger_account;
3165 public $subledger_label;
3166 public $numero_compte;
3167 public $label_compte;
3168 public $label_operation;
3169 public $debit;
3170 public $credit;
3171
3176 public $montant;
3177
3181 public $amount;
3182
3186 public $multicurrency_amount;
3187
3191 public $multicurrency_code;
3192
3196 public $sens;
3197 public $lettering_code;
3198 public $date_lettering;
3199
3203 public $fk_user_author;
3204
3205 public $import_key;
3206 public $code_journal;
3207 public $journal_label;
3211 public $piece_num;
3212
3216 public $date_creation;
3217
3221 public $date_modification;
3222
3226 public $date_export;
3227
3231 public $date_validation;
3232
3236 public $date_lim_reglement;
3237}
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.