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
1092 $sql .= ' WHERE t.entity = ' . ((int) $conf->entity); // Do not use getEntity for accounting features
1093 if ($showAlreadyExportMovements == 0) {
1094 $sql .= " AND t.date_export IS NULL";
1095 }
1096
1097 // Manage filter
1098 if (is_array($filter)) { // deprecated, use $filter = USF syntax
1099 dol_syslog("You are using a deprecated use of fetchAll. filter parameter mus be an USF string now.", LOG_WARNING);
1100 $sqlwhere = array();
1101 if (count($filter) > 0) {
1102 foreach ($filter as $key => $value) {
1103 if ($key == 't.doc_date') {
1104 $sqlwhere[] = $this->db->sanitize($key).' = \''.$this->db->idate($value).'\'';
1105 } elseif ($key == 't.doc_date>=') {
1106 $sqlwhere[] = "t.doc_date >= '".$this->db->idate($value)."'";
1107 } elseif ($key == 't.doc_date<=') {
1108 $sqlwhere[] = "t.doc_date <= '".$this->db->idate($value)."'";
1109 } elseif ($key == 't.doc_date>') {
1110 $sqlwhere[] = "t.doc_date > '".$this->db->idate($value)."'";
1111 } elseif ($key == 't.doc_date<') {
1112 $sqlwhere[] = "t.doc_date < '".$this->db->idate($value)."'";
1113 } elseif ($key == 't.numero_compte>=') {
1114 $sqlwhere[] = "t.numero_compte >= '".$this->db->escape($value)."'";
1115 } elseif ($key == 't.numero_compte<=') {
1116 $sqlwhere[] = "t.numero_compte <= '".$this->db->escape($value)."'";
1117 } elseif ($key == 't.subledger_account>=') {
1118 $sqlwhere[] = "t.subledger_account >= '".$this->db->escape($value)."'";
1119 } elseif ($key == 't.subledger_account<=') {
1120 $sqlwhere[] = "t.subledger_account <= '".$this->db->escape($value)."'";
1121 } elseif ($key == 't.fk_doc' || $key == 't.fk_docdet' || $key == 't.piece_num') {
1122 $sqlwhere[] = $this->db->sanitize($key).' = '.((int) $value);
1123 } elseif ($key == 't.subledger_account' || $key == 't.numero_compte') {
1124 $sqlwhere[] = $this->db->sanitize($key).' LIKE \''.$this->db->escape($value).'%\'';
1125 } elseif ($key == 't.date_creation>=') {
1126 $sqlwhere[] = 't.date_creation >= \''.$this->db->idate($value).'\'';
1127 } elseif ($key == 't.date_creation<=') {
1128 $sqlwhere[] = 't.date_creation <= \''.$this->db->idate($value).'\'';
1129 } elseif ($key == 't.tms>=') {
1130 $sqlwhere[] = 't.tms >= \''.$this->db->idate($value).'\'';
1131 } elseif ($key == 't.tms<=') {
1132 $sqlwhere[] = 't.tms <= \''.$this->db->idate($value).'\'';
1133 } elseif ($key == 't.date_export>=') {
1134 $sqlwhere[] = 't.date_export >= \''.$this->db->idate($value).'\'';
1135 } elseif ($key == 't.date_export<=') {
1136 $sqlwhere[] = 't.date_export <= \''.$this->db->idate($value).'\'';
1137 } elseif ($key == 't.date_validated>=') {
1138 $sqlwhere[] = 't.date_validated >= \''.$this->db->idate($value).'\'';
1139 } elseif ($key == 't.date_validated<=') {
1140 $sqlwhere[] = 't.date_validated <= \''.$this->db->idate($value).'\'';
1141 } elseif ($key == 't.credit' || $key == 't.debit') {
1142 $sqlwhere[] = natural_search($key, $value, 1, 1);
1143 } elseif ($key == 't.code_journal' && !empty($value)) {
1144 if (is_array($value)) {
1145 $sqlwhere[] = natural_search("t.code_journal", implode(',', $value), 3, 1);
1146 } else {
1147 $sqlwhere[] = natural_search("t.code_journal", $value, 3, 1);
1148 }
1149 } else {
1150 $sqlwhere[] = natural_search($key, $value, 0, 1);
1151 }
1152 }
1153 }
1154 if (count($sqlwhere) > 0) {
1155 $sql .= ' AND '.implode(" ".$this->db->sanitize($filtermode)." ", $sqlwhere);
1156 }
1157
1158 $filter = '';
1159 }
1160
1161 // Manage filter
1162 $errormessage = '';
1163 $sql .= forgeSQLFromUniversalSearchCriteria($filter, $errormessage);
1164 if ($errormessage) {
1165 $this->errors[] = $errormessage;
1166 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
1167 return -1;
1168 }
1169
1170 if (!empty($sortfield)) {
1171 $sql .= $this->db->order($sortfield, $sortorder);
1172 }
1173 if (!empty($limit)) {
1174 $sql .= $this->db->plimit($limit + 1, $offset);
1175 }
1176 $this->lines = array();
1177
1178 $resql = $this->db->query($sql);
1179 if ($resql) {
1180 $num = $this->db->num_rows($resql);
1181
1182 $i = 0;
1183 while (($obj = $this->db->fetch_object($resql)) && (empty($limit) || $i < min($limit, $num))) {
1184 $line = new BookKeepingLine($this->db);
1185
1186 $line->id = $obj->rowid;
1187
1188 $line->doc_date = $this->db->jdate($obj->doc_date);
1189 $line->doc_type = $obj->doc_type;
1190 $line->doc_ref = $obj->doc_ref;
1191 $line->fk_doc = $obj->fk_doc;
1192 $line->fk_docdet = $obj->fk_docdet;
1193 $line->thirdparty_code = $obj->thirdparty_code;
1194 $line->subledger_account = $obj->subledger_account;
1195 $line->subledger_label = $obj->subledger_label;
1196 $line->numero_compte = $obj->numero_compte;
1197 $line->label_compte = $obj->label_compte;
1198 $line->label_operation = $obj->label_operation;
1199 $line->debit = $obj->debit;
1200 $line->credit = $obj->credit;
1201 $line->montant = $obj->amount; // deprecated
1202 $line->amount = $obj->amount;
1203 $line->sens = $obj->sens;
1204 $line->lettering_code = $obj->lettering_code;
1205 $line->date_lettering = $obj->date_lettering;
1206 $line->fk_user_author = $obj->fk_user_author;
1207 $line->import_key = $obj->import_key;
1208 $line->code_journal = $obj->code_journal;
1209 $line->journal_label = $obj->journal_label;
1210 $line->piece_num = $obj->piece_num;
1211 $line->date_creation = $this->db->jdate($obj->date_creation);
1212 $line->date_lim_reglement = $this->db->jdate($obj->date_lim_reglement);
1213 $line->date_modification = $this->db->jdate($obj->date_modification);
1214 $line->date_export = $this->db->jdate($obj->date_export);
1215 $line->date_validation = $this->db->jdate($obj->date_validation);
1216
1217 $this->lines[] = $line;
1218
1219 $i++;
1220 }
1221 $this->db->free($resql);
1222
1223 return $num;
1224 } else {
1225 $this->errors[] = 'Error '.$this->db->lasterror();
1226 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
1227 return -1;
1228 }
1229 }
1230
1243 public function fetchAllBalance($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, $filter = '', $filtermode = 'AND', $option = 0)
1244 {
1245 global $conf;
1246
1247 $this->lines = array();
1248
1249 dol_syslog(__METHOD__, LOG_DEBUG);
1250
1251 $sql = 'SELECT';
1252 $sql .= " t.numero_compte,";
1253 if (!empty($option)) {
1254 $sql .= " t.subledger_account,";
1255 $sql .= " t.subledger_label,";
1256 }
1257 $sql .= " SUM(t.debit) as debit,";
1258 $sql .= " SUM(t.credit) as credit";
1259 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
1260 $sql .= ' WHERE entity = ' . ((int) $conf->entity); // Do not use getEntity for accounting features
1261
1262 // Manage filter
1263 if (is_array($filter)) {
1264 $sqlwhere = array();
1265 if (count($filter) > 0) {
1266 foreach ($filter as $key => $value) {
1267 if ($key == 't.doc_date') {
1268 $sqlwhere[] = $this->db->sanitize($key)." = '".$this->db->idate($value)."'";
1269 } elseif ($key == 't.doc_date>=') {
1270 $sqlwhere[] = "t.doc_date >= '".$this->db->idate($value)."'";
1271 } elseif ($key == 't.doc_date<=') {
1272 $sqlwhere[] = "t.doc_date <= '".$this->db->idate($value)."'";
1273 } elseif ($key == 't.doc_date>') {
1274 $sqlwhere[] = "t.doc_date > '".$this->db->idate($value)."'";
1275 } elseif ($key == 't.doc_date<') {
1276 $sqlwhere[] = "t.doc_date < '".$this->db->idate($value)."'";
1277 } elseif ($key == 't.numero_compte>=') {
1278 $sqlwhere[] = "t.numero_compte >= '".$this->db->escape($value)."'";
1279 } elseif ($key == 't.numero_compte<=') {
1280 $sqlwhere[] = "t.numero_compte <= '".$this->db->escape($value)."'";
1281 } elseif ($key == 't.subledger_account>=') {
1282 $sqlwhere[] = "t.subledger_account >= '".$this->db->escape($value)."'";
1283 } elseif ($key == 't.subledger_account<=') {
1284 $sqlwhere[] = "t.subledger_account <= '".$this->db->escape($value)."'";
1285 } elseif ($key == 't.fk_doc' || $key == 't.fk_docdet' || $key == 't.piece_num') {
1286 $sqlwhere[] = $this->db->sanitize($key)." = ".((int) $value);
1287 } elseif ($key == 't.subledger_account' || $key == 't.numero_compte') {
1288 $sqlwhere[] = $this->db->sanitize($key)." LIKE '".$this->db->escape($value)."%'";
1289 } elseif ($key == 't.subledger_label') {
1290 $sqlwhere[] = $this->db->sanitize($key)." LIKE '".$this->db->escape($value)."%'";
1291 } elseif ($key == 't.code_journal' && !empty($value)) {
1292 if (is_array($value)) {
1293 $sqlwhere[] = natural_search("t.code_journal", implode(',', $value), 3, 1);
1294 } else {
1295 $sqlwhere[] = natural_search("t.code_journal", $value, 3, 1);
1296 }
1297 } elseif ($key == 't.reconciled_option') {
1298 $sqlwhere[] = 't.lettering_code IS NULL';
1299 } else {
1300 $sqlwhere[] = $this->db->sanitize($key)." LIKE '%".$this->db->escape($this->db->escapeforlike($value))."%'";
1301 }
1302 }
1303 }
1304 if (count($sqlwhere) > 0) {
1305 $sql .= " AND ".implode(" ".$this->db->sanitize($filtermode)." ", $sqlwhere);
1306 }
1307
1308 $filter = '';
1309 }
1310
1311 // Manage filter
1312 $errormessage = '';
1313 $sql .= forgeSQLFromUniversalSearchCriteria($filter, $errormessage);
1314 if ($errormessage) {
1315 $this->errors[] = $errormessage;
1316 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
1317 return -1;
1318 }
1319
1320 if (!empty($option)) {
1321 $sql .= " AND t.subledger_account IS NOT NULL";
1322 $sql .= " AND t.subledger_account <> ''";
1323 $sql .= " GROUP BY t.numero_compte, t.subledger_account, t.subledger_label";
1324 $sortfield = 't.subledger_account'.($sortfield ? ','.$sortfield : '');
1325 $sortorder = 'ASC'.($sortfield ? ','.$sortfield : '');
1326 } else {
1327 $sql .= ' GROUP BY t.numero_compte';
1328 $sortfield = 't.numero_compte'.($sortfield ? ','.$sortfield : '');
1329 $sortorder = 'ASC'.($sortorder ? ','.$sortorder : '');
1330 }
1331
1332 if (!empty($sortfield)) {
1333 $sql .= $this->db->order($sortfield, $sortorder);
1334 }
1335 if (!empty($limit)) {
1336 $sql .= $this->db->plimit($limit + 1, $offset);
1337 }
1338
1339 //print $sql;
1340 $resql = $this->db->query($sql);
1341
1342 if ($resql) {
1343 $num = $this->db->num_rows($resql);
1344
1345 $i = 0;
1346 while (($obj = $this->db->fetch_object($resql)) && (empty($limit) || $i < min($limit, $num))) {
1347 $line = new BookKeepingLine($this->db);
1348
1349 $line->numero_compte = $obj->numero_compte;
1350 //$line->label_compte = $obj->label_compte;
1351 if (!empty($option)) {
1352 $line->subledger_account = $obj->subledger_account;
1353 $line->subledger_label = $obj->subledger_label;
1354 }
1355 $line->debit = $obj->debit;
1356 $line->credit = $obj->credit;
1357
1358 $this->lines[] = $line;
1359
1360 $i++;
1361 }
1362 $this->db->free($resql);
1363
1364 return $num;
1365 } else {
1366 $this->errors[] = 'Error '.$this->db->lasterror();
1367 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
1368
1369 return -1;
1370 }
1371 }
1372
1381 public function update(User $user, $notrigger = 0, $mode = '')
1382 {
1383 global $langs;
1384 $error = 0;
1385
1386 dol_syslog(__METHOD__, LOG_DEBUG);
1387
1388 // Clean parameters
1389 if (isset($this->doc_type)) {
1390 $this->doc_type = trim($this->doc_type);
1391 }
1392 if (isset($this->doc_ref)) {
1393 $this->doc_ref = trim($this->doc_ref);
1394 }
1395 if (isset($this->fk_doc)) {
1396 $this->fk_doc = (int) $this->fk_doc;
1397 }
1398 if (isset($this->fk_docdet)) {
1399 $this->fk_docdet = (int) $this->fk_docdet;
1400 }
1401 if (isset($this->thirdparty_code)) {
1402 $this->thirdparty_code = trim($this->thirdparty_code);
1403 }
1404 if (isset($this->subledger_account)) {
1405 $this->subledger_account = trim($this->subledger_account);
1406 }
1407 if (isset($this->subledger_label)) {
1408 $this->subledger_label = trim($this->subledger_label);
1409 }
1410 if (isset($this->numero_compte)) {
1411 $this->numero_compte = trim($this->numero_compte);
1412 }
1413 if (isset($this->label_compte)) {
1414 $this->label_compte = trim($this->label_compte);
1415 }
1416 if (isset($this->label_operation)) {
1417 $this->label_operation = trim($this->label_operation);
1418 }
1419 if (isset($this->sens)) {
1420 $this->sens = trim($this->sens);
1421 }
1422 if (isset($this->import_key)) {
1423 $this->import_key = trim($this->import_key);
1424 }
1425 if (isset($this->code_journal)) {
1426 $this->code_journal = trim($this->code_journal);
1427 }
1428 if (isset($this->journal_label)) {
1429 $this->journal_label = trim($this->journal_label);
1430 }
1431 if (isset($this->piece_num)) {
1432 $this->piece_num = (int) $this->piece_num;
1433 }
1434
1435 $result = $this->canModifyBookkeeping($this->id, $mode);
1436 if ($result < 0) {
1437 return -1;
1438 } elseif ($result == 0) {
1439 if (getDolGlobalString('ACCOUNTANCY_FISCAL_PERIOD_MODE') == 'blockedonclosed') {
1440 $this->errors[] = $langs->trans('ErrorBookkeepingDocDateIsOnAClosedFiscalPeriod');
1441 } else {
1442 $this->errors[] = $langs->trans('ErrorBookkeepingDocDateNotOnActiveFiscalPeriod');
1443 }
1444 return -1;
1445 }
1446
1447 $this->debit = (float) price2num($this->debit, 'MT');
1448 $this->credit = (float) price2num($this->credit, 'MT');
1449 $this->montant = (float) price2num($this->montant, 'MT');
1450
1451 // Check parameters
1452 // Put here code to add a control on parameters values
1453
1454 // Update request
1455 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element.$mode.' SET';
1456 $sql .= ' doc_date = '.(!isset($this->doc_date) || dol_strlen($this->doc_date) != 0 ? "'".$this->db->idate($this->doc_date)."'" : 'null').',';
1457 $sql .= ' doc_type = '.(isset($this->doc_type) ? "'".$this->db->escape($this->doc_type)."'" : "null").',';
1458 $sql .= ' doc_ref = '.(isset($this->doc_ref) ? "'".$this->db->escape($this->doc_ref)."'" : "null").',';
1459 $sql .= ' fk_doc = '.(isset($this->fk_doc) ? $this->fk_doc : "null").',';
1460 $sql .= ' fk_docdet = '.(isset($this->fk_docdet) ? $this->fk_docdet : "null").',';
1461 $sql .= ' thirdparty_code = '.(isset($this->thirdparty_code) ? "'".$this->db->escape($this->thirdparty_code)."'" : "null").',';
1462 $sql .= ' subledger_account = '.(isset($this->subledger_account) ? "'".$this->db->escape($this->subledger_account)."'" : "null").',';
1463 $sql .= ' subledger_label = '.(isset($this->subledger_label) ? "'".$this->db->escape($this->subledger_label)."'" : "null").',';
1464 $sql .= ' numero_compte = '.(isset($this->numero_compte) ? "'".$this->db->escape($this->numero_compte)."'" : "null").',';
1465 $sql .= ' label_compte = '.(isset($this->label_compte) ? "'".$this->db->escape($this->label_compte)."'" : "null").',';
1466 $sql .= ' label_operation = '.(isset($this->label_operation) ? "'".$this->db->escape($this->label_operation)."'" : "null").',';
1467 $sql .= ' debit = '.(isset($this->debit) ? $this->debit : "null").',';
1468 $sql .= ' credit = '.(isset($this->credit) ? $this->credit : "null").',';
1469 $sql .= ' montant = '.(isset($this->montant) ? $this->montant : "null").',';
1470 $sql .= ' sens = '.(isset($this->sens) ? "'".$this->db->escape($this->sens)."'" : "null").',';
1471 $sql .= ' fk_user_author = '.(isset($this->fk_user_author) ? $this->fk_user_author : "null").',';
1472 $sql .= ' import_key = '.(isset($this->import_key) ? "'".$this->db->escape($this->import_key)."'" : "null").',';
1473 $sql .= ' code_journal = '.(isset($this->code_journal) ? "'".$this->db->escape($this->code_journal)."'" : "null").',';
1474 $sql .= ' journal_label = '.(isset($this->journal_label) ? "'".$this->db->escape($this->journal_label)."'" : "null").',';
1475 $sql .= ' piece_num = '.(isset($this->piece_num) ? $this->piece_num : "null");
1476 $sql .= ' WHERE rowid='.((int) $this->id);
1477
1478 $this->db->begin();
1479
1480 $resql = $this->db->query($sql);
1481 if (!$resql) {
1482 $error++;
1483 $this->errors[] = 'Error '.$this->db->lasterror();
1484 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
1485 }
1486
1487 // Uncomment this and change MYOBJECT to your own tag if you
1488 // want this action calls a trigger.
1489 //if (! $error && ! $notrigger) {
1490
1491 // // Call triggers
1492 // $result=$this->call_trigger('MYOBJECT_MODIFY',$user);
1493 // if ($result < 0) { $error++; //Do also what you must do to rollback action if trigger fail}
1494 // // End call triggers
1495 //}
1496
1497 // Commit or rollback
1498 if ($error) {
1499 $this->db->rollback();
1500
1501 return -1 * $error;
1502 } else {
1503 $this->db->commit();
1504
1505 return 1;
1506 }
1507 }
1508
1518 public function updateByMvt($piece_num = '', $field = '', $value = '', $mode = '')
1519 {
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 .= $sql_filter;
1533
1534 $resql = $this->db->query($sql);
1535
1536 if (!$resql) {
1537 $error++;
1538 $this->errors[] = 'Error '.$this->db->lasterror();
1539 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
1540 }
1541 if ($error) {
1542 $this->db->rollback();
1543
1544 return -1 * $error;
1545 } else {
1546 $this->db->commit();
1547
1548 return 1;
1549 }
1550 }
1551
1560 public function delete(User $user, $notrigger = 0, $mode = '')
1561 {
1562 global $langs;
1563
1564 dol_syslog(__METHOD__, LOG_DEBUG);
1565
1566 $result = $this->canModifyBookkeeping($this->id, $mode);
1567 if ($result < 0) {
1568 return -1;
1569 } elseif ($result == 0) {
1570 if (getDolGlobalString('ACCOUNTANCY_FISCAL_PERIOD_MODE') == 'blockedonclosed') {
1571 $this->errors[] = $langs->trans('ErrorBookkeepingDocDateIsOnAClosedFiscalPeriod');
1572 } else {
1573 $this->errors[] = $langs->trans('ErrorBookkeepingDocDateNotOnActiveFiscalPeriod');
1574 }
1575 return -1;
1576 }
1577
1578 $error = 0;
1579
1580 $this->db->begin();
1581
1582 // Uncomment this and change MYOBJECT to your own tag if you
1583 // want this action calls a trigger.
1584 //if (! $error && ! $notrigger) {
1585
1586 // // Call triggers
1587 // $result=$this->call_trigger('MYOBJECT_DELETE',$user);
1588 // if ($result < 0) { $error++; //Do also what you must do to rollback action if trigger fail}
1589 // // End call triggers
1590 //}
1591
1592 if (!$error) {
1593 $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.$mode;
1594 $sql .= ' WHERE rowid='.((int) $this->id);
1595
1596 $resql = $this->db->query($sql);
1597 if (!$resql) {
1598 $error++;
1599 $this->errors[] = 'Error '.$this->db->lasterror();
1600 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
1601 }
1602 }
1603
1604 // Commit or rollback
1605 if ($error) {
1606 $this->db->rollback();
1607
1608 return -1 * $error;
1609 } else {
1610 $this->db->commit();
1611
1612 return 1;
1613 }
1614 }
1615
1623 public function deleteByImportkey($importkey, $mode = '')
1624 {
1625 $this->db->begin();
1626
1627 $sql_filter = $this->getCanModifyBookkeepingSQL();
1628 if (!isset($sql_filter)) {
1629 return -1;
1630 }
1631
1632 // first check if line not yet in bookkeeping
1633 $sql = "DELETE";
1634 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element.$mode;
1635 $sql .= " WHERE import_key = '".$this->db->escape($importkey)."'";
1636 $sql .= $sql_filter;
1637
1638 $resql = $this->db->query($sql);
1639
1640 if (!$resql) {
1641 $this->errors[] = "Error ".$this->db->lasterror();
1642 dol_syslog(get_class($this)."::delete Error ".$this->db->lasterror(), LOG_ERR);
1643 $this->db->rollback();
1644 return -1;
1645 }
1646
1647 $this->db->commit();
1648 return 1;
1649 }
1650
1660 public function deleteByYearAndJournal($delyear = 0, $journal = '', $mode = '', $delmonth = 0)
1661 {
1662 global $conf, $langs;
1663
1664 if (empty($delyear) && empty($journal)) {
1665 $this->error = 'ErrorOneFieldRequired';
1666 return -1;
1667 }
1668 if (!empty($delmonth) && empty($delyear)) {
1669 $this->error = 'YearRequiredIfMonthDefined';
1670 return -2;
1671 }
1672
1673 $sql_filter = $this->getCanModifyBookkeepingSQL();
1674 if (!isset($sql_filter)) {
1675 return -1;
1676 }
1677
1678 $this->db->begin();
1679
1680 // Delete record in bookkeeping
1681 $sql = "DELETE";
1682 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element.$mode;
1683 $sql .= " WHERE 1 = 1";
1684 $sql .= dolSqlDateFilter('doc_date', 0, $delmonth, $delyear);
1685 if (!empty($journal)) {
1686 $sql .= " AND code_journal = '".$this->db->escape($journal)."'";
1687 }
1688 $sql .= " AND entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
1689 // Exclusion of validated entries at the time of deletion
1690 $sql .= " AND date_validated IS NULL";
1691 $sql .= $sql_filter;
1692
1693 // TODO: In a future we must forbid deletion if record is inside a closed fiscal period.
1694
1695 $resql = $this->db->query($sql);
1696
1697 if (!$resql) {
1698 $this->errors[] = "Error ".$this->db->lasterror();
1699 foreach ($this->errors as $errmsg) {
1700 dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR);
1701 $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
1702 }
1703 $this->db->rollback();
1704 return -1;
1705 }
1706
1707 $this->db->commit();
1708 return 1;
1709 }
1710
1718 public function deleteMvtNum($piecenum, $mode = '')
1719 {
1720 global $conf;
1721
1722 $sql_filter = $this->getCanModifyBookkeepingSQL();
1723 if (!isset($sql_filter)) {
1724 return -1;
1725 }
1726
1727 $nbprocessed = 0;
1728
1729 $this->db->begin();
1730
1731 // first check if line not yet in bookkeeping
1732 $sql = "DELETE";
1733 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element.$mode;
1734 $sql .= " WHERE piece_num = ".(int) $piecenum;
1735 $sql .= " AND date_validated IS NULL"; // For security, exclusion of validated entries at the time of deletion
1736 $sql .= " AND entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
1737 $sql .= $sql_filter;
1738
1739 $resql = $this->db->query($sql);
1740
1741 if (!$resql) {
1742 $this->errors[] = "Error ".$this->db->lasterror();
1743 foreach ($this->errors as $errmsg) {
1744 dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR);
1745 $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
1746 }
1747 $this->db->rollback();
1748 return -1;
1749 } else {
1750 $nbprocessed = $this->db->affected_rows($resql);
1751 }
1752
1753 $this->db->commit();
1754
1755 return $nbprocessed;
1756 }
1757
1765 public function createFromClone(User $user, $fromid)
1766 {
1767 dol_syslog(__METHOD__, LOG_DEBUG);
1768
1769 $error = 0;
1770 $object = new BookKeeping($this->db);
1771
1772 $this->db->begin();
1773
1774 // Load source object
1775 $object->fetch($fromid);
1776 // Reset object
1777 $object->id = 0;
1778
1779 // Clear fields
1780 // ...
1781
1782 // Create clone
1783 $object->context['createfromclone'] = 'createfromclone';
1784 $result = $object->create($user);
1785
1786 // Other options
1787 if ($result < 0) {
1788 $error++;
1789 $this->errors = $object->errors;
1790 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
1791 }
1792
1793 unset($object->context['createfromclone']);
1794
1795 // End
1796 if (!$error) {
1797 $this->db->commit();
1798
1799 return $object->id;
1800 } else {
1801 $this->db->rollback();
1802
1803 return -1;
1804 }
1805 }
1806
1813 public function initAsSpecimen()
1814 {
1815 global $user;
1816
1817 $now = dol_now();
1818
1819 $this->id = 0;
1820 $this->doc_date = $now;
1821 $this->doc_type = '';
1822 $this->doc_ref = '';
1823 $this->fk_doc = 0;
1824 $this->fk_docdet = 0;
1825 $this->thirdparty_code = 'CU001';
1826 $this->subledger_account = '41100001';
1827 $this->subledger_label = 'My customer company';
1828 $this->numero_compte = '411';
1829 $this->label_compte = 'Customer';
1830 $this->label_operation = 'Sales of pea';
1831 $this->debit = 99.9;
1832 $this->credit = 0.0;
1833 $this->amount = 0.0;
1834 $this->sens = 'D';
1835 $this->fk_user_author = $user->id;
1836 $this->import_key = '20201027';
1837 $this->code_journal = 'VT';
1838 $this->journal_label = 'Journal de vente';
1839 $this->piece_num = 1234;
1840 $this->date_creation = $now;
1841
1842 return 1;
1843 }
1844
1852 public function fetchPerMvt($piecenum, $mode = '')
1853 {
1854 global $conf;
1855
1856 $sql = "SELECT piece_num, doc_date, code_journal, journal_label, doc_ref, doc_type,";
1857 $sql .= " date_creation, tms as date_modification, date_validated as date_validation, import_key";
1858 // In llx_accounting_bookkeeping_tmp, field date_export doesn't exist
1859 if ($mode != "_tmp") {
1860 $sql .= ", date_export";
1861 }
1862 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element.$mode;
1863 $sql .= " WHERE piece_num = ".((int) $piecenum);
1864 $sql .= " AND entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
1865
1866 dol_syslog(__METHOD__, LOG_DEBUG);
1867 $result = $this->db->query($sql);
1868 if ($result) {
1869 $obj = $this->db->fetch_object($result);
1870
1871 $this->piece_num = $obj->piece_num;
1872 $this->code_journal = $obj->code_journal;
1873 $this->journal_label = $obj->journal_label;
1874 $this->doc_date = $this->db->jdate($obj->doc_date);
1875 $this->doc_ref = $obj->doc_ref;
1876 $this->doc_type = $obj->doc_type;
1877 $this->date_creation = $this->db->jdate($obj->date_creation);
1878 $this->date_modification = $this->db->jdate($obj->date_modification);
1879 if ($mode != "_tmp") {
1880 $this->date_export = $this->db->jdate($obj->date_export);
1881 }
1882 $this->date_validation = $this->db->jdate($obj->date_validation);
1883 $this->import_key = $obj->import_key;
1884 } else {
1885 $this->error = "Error ".$this->db->lasterror();
1886 dol_syslog(__METHOD__.$this->error, LOG_ERR);
1887 return -1;
1888 }
1889
1890 return 1;
1891 }
1892
1899 public function getNextNumMvt($mode = '')
1900 {
1901 global $conf;
1902
1903 $sql = "SELECT MAX(piece_num)+1 as max FROM ".MAIN_DB_PREFIX.$this->table_element.$mode;
1904 $sql .= " WHERE entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
1905
1906 dol_syslog(get_class($this)."::getNextNumMvt", LOG_DEBUG);
1907
1908 $result = $this->db->query($sql);
1909
1910 if ($result) {
1911 $obj = $this->db->fetch_object($result);
1912 if ($obj) {
1913 $result = $obj->max;
1914 }
1915 if (empty($result)) {
1916 $result = 1;
1917 }
1918 return $result;
1919 } else {
1920 $this->error = "Error ".$this->db->lasterror();
1921 dol_syslog(get_class($this)."::getNextNumMvt ".$this->error, LOG_ERR);
1922 return -1;
1923 }
1924 }
1925
1933 public function fetchAllPerMvt($piecenum, $mode = '')
1934 {
1935 global $conf;
1936
1937 $sql = "SELECT rowid, doc_date, doc_type,";
1938 $sql .= " doc_ref, fk_doc, fk_docdet, thirdparty_code, subledger_account, subledger_label,";
1939 $sql .= " numero_compte, label_compte, label_operation, debit, credit,";
1940 $sql .= " montant as amount, sens, fk_user_author, import_key, code_journal, journal_label, piece_num,";
1941 $sql .= " date_creation, tms as date_modification, date_validated as date_validation";
1942 // In llx_accounting_bookkeeping_tmp, field date_export doesn't exist
1943 if ($mode != "_tmp") {
1944 $sql .= ", date_export";
1945 }
1946 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element.$mode;
1947 $sql .= " WHERE piece_num = ".((int) $piecenum);
1948 $sql .= " AND entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
1949
1950 dol_syslog(__METHOD__, LOG_DEBUG);
1951 $result = $this->db->query($sql);
1952 if ($result) {
1953 while ($obj = $this->db->fetch_object($result)) {
1954 $line = new BookKeepingLine($this->db);
1955
1956 $line->id = $obj->rowid;
1957
1958 $line->doc_date = $this->db->jdate($obj->doc_date);
1959 $line->doc_type = $obj->doc_type;
1960 $line->doc_ref = $obj->doc_ref;
1961 $line->fk_doc = $obj->fk_doc;
1962 $line->fk_docdet = $obj->fk_docdet;
1963 $line->thirdparty_code = $obj->thirdparty_code;
1964 $line->subledger_account = $obj->subledger_account;
1965 $line->subledger_label = $obj->subledger_label;
1966 $line->numero_compte = $obj->numero_compte;
1967 $line->label_compte = $obj->label_compte;
1968 $line->label_operation = $obj->label_operation;
1969 $line->debit = $obj->debit;
1970 $line->credit = $obj->credit;
1971 $line->montant = $obj->amount;
1972 $line->amount = $obj->amount;
1973 $line->sens = $obj->sens;
1974 $line->code_journal = $obj->code_journal;
1975 $line->journal_label = $obj->journal_label;
1976 $line->piece_num = $obj->piece_num;
1977 $line->date_creation = $obj->date_creation;
1978 $line->date_modification = $obj->date_modification;
1979 if ($mode != "_tmp") {
1980 $line->date_export = $obj->date_export;
1981 }
1982 $line->date_validation = $obj->date_validation;
1983
1984 $this->linesmvt[] = $line;
1985 }
1986 } else {
1987 $this->error = "Error ".$this->db->lasterror();
1988 dol_syslog(__METHOD__.$this->error, LOG_ERR);
1989 return -1;
1990 }
1991
1992 return 1;
1993 }
1994
1995 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2002 public function export_bookkeeping($model = 'ebp')
2003 {
2004 // phpcs:enable
2005 global $conf;
2006
2007 $sql = "SELECT rowid, doc_date, doc_type,";
2008 $sql .= " doc_ref, fk_doc, fk_docdet, thirdparty_code, subledger_account, subledger_label,";
2009 $sql .= " numero_compte, label_compte, label_operation, debit, credit,";
2010 $sql .= " montant as amount, sens, fk_user_author, import_key, code_journal, piece_num,";
2011 $sql .= " date_validated as date_validation";
2012 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element;
2013 $sql .= " WHERE entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
2014
2015 dol_syslog(get_class($this)."::export_bookkeeping", LOG_DEBUG);
2016
2017 $resql = $this->db->query($sql);
2018
2019 if ($resql) {
2020 $this->linesexport = array();
2021
2022 $num = $this->db->num_rows($resql);
2023 while ($obj = $this->db->fetch_object($resql)) {
2024 $line = new BookKeepingLine($this->db);
2025
2026 $line->id = $obj->rowid;
2027
2028 $line->doc_date = $this->db->jdate($obj->doc_date);
2029 $line->doc_type = $obj->doc_type;
2030 $line->doc_ref = $obj->doc_ref;
2031 $line->fk_doc = $obj->fk_doc;
2032 $line->fk_docdet = $obj->fk_docdet;
2033 $line->thirdparty_code = $obj->thirdparty_code;
2034 $line->subledger_account = $obj->subledger_account;
2035 $line->subledger_label = $obj->subledger_label;
2036 $line->numero_compte = $obj->numero_compte;
2037 $line->label_compte = $obj->label_compte;
2038 $line->label_operation = $obj->label_operation;
2039 $line->debit = $obj->debit;
2040 $line->credit = $obj->credit;
2041 $line->montant = $obj->amount;
2042 $line->amount = $obj->amount;
2043 $line->sens = $obj->sens;
2044 $line->code_journal = $obj->code_journal;
2045 $line->piece_num = $obj->piece_num;
2046 $line->date_validation = $obj->date_validation;
2047
2048 $this->linesexport[] = $line;
2049 }
2050 $this->db->free($resql);
2051
2052 return $num;
2053 } else {
2054 $this->error = "Error ".$this->db->lasterror();
2055 dol_syslog(get_class($this)."::export_bookkeeping ".$this->error, LOG_ERR);
2056 return -1;
2057 }
2058 }
2059
2067 public function transformTransaction($direction = 0, $piece_num = '')
2068 {
2069 global $conf;
2070
2071 $error = 0;
2072
2073 $sql_filter = $this->getCanModifyBookkeepingSQL();
2074
2075 if (!isset($sql_filter)) {
2076 return -1;
2077 }
2078
2079 $this->db->begin();
2080
2081 if ($direction == 0) {
2082 $next_piecenum = $this->getNextNumMvt();
2083 $now = dol_now();
2084
2085 if ($next_piecenum < 0) {
2086 $error++;
2087 }
2088
2089 if (!$error) {
2090 // Delete if there is an empty line
2091 $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";
2092 $resql = $this->db->query($sql);
2093 if (!$resql) {
2094 $error++;
2095 $this->errors[] = 'Error '.$this->db->lasterror();
2096 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
2097 }
2098 }
2099
2100 if (!$error) {
2101 $sql = 'INSERT INTO '.MAIN_DB_PREFIX.$this->table_element.' (doc_date, doc_type,';
2102 $sql .= ' doc_ref, fk_doc, fk_docdet, entity, thirdparty_code, subledger_account, subledger_label,';
2103 $sql .= ' numero_compte, label_compte, label_operation, debit, credit,';
2104 $sql .= ' montant, sens, fk_user_author, import_key, code_journal, journal_label, piece_num, date_creation)';
2105 $sql .= ' SELECT doc_date, doc_type,';
2106 $sql .= ' doc_ref, fk_doc, fk_docdet, entity, thirdparty_code, subledger_account, subledger_label,';
2107 $sql .= ' numero_compte, label_compte, label_operation, debit, credit,';
2108 $sql .= ' montant, sens, fk_user_author, import_key, code_journal, journal_label, '.((int) $next_piecenum).", '".$this->db->idate($now)."'";
2109 $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);
2110 $sql .= $sql_filter;
2111 $resql = $this->db->query($sql);
2112 if (!$resql) {
2113 $error++;
2114 $this->errors[] = 'Error '.$this->db->lasterror();
2115 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
2116 }
2117 }
2118
2119 if (!$error) {
2120 $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.'_tmp WHERE piece_num = '.((int) $piece_num).' AND entity = ' .((int) $conf->entity);
2121 $resql = $this->db->query($sql);
2122 if (!$resql) {
2123 $error++;
2124 $this->errors[] = 'Error '.$this->db->lasterror();
2125 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
2126 }
2127 }
2128 } elseif ($direction == 1) {
2129 if (!$error) {
2130 $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.'_tmp WHERE piece_num = '.((int) $piece_num).' AND entity = ' .((int) $conf->entity);
2131 $resql = $this->db->query($sql);
2132 if (!$resql) {
2133 $error++;
2134 $this->errors[] = 'Error '.$this->db->lasterror();
2135 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
2136 }
2137 }
2138
2139 if (!$error) {
2140 $sql = 'INSERT INTO '.MAIN_DB_PREFIX.$this->table_element.'_tmp (doc_date, doc_type,';
2141 $sql .= ' doc_ref, fk_doc, fk_docdet, thirdparty_code, subledger_account, subledger_label,';
2142 $sql .= ' numero_compte, label_compte, label_operation, debit, credit,';
2143 $sql .= ' montant, sens, fk_user_author, import_key, code_journal, journal_label, piece_num)';
2144 $sql .= ' SELECT doc_date, doc_type,';
2145 $sql .= ' doc_ref, fk_doc, fk_docdet, thirdparty_code, subledger_account, subledger_label,';
2146 $sql .= ' numero_compte, label_compte, label_operation, debit, credit,';
2147 $sql .= ' montant, sens, fk_user_author, import_key, code_journal, journal_label, piece_num';
2148 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' WHERE piece_num = '.((int) $piece_num).' AND entity = ' .((int) $conf->entity);
2149 $sql .= $sql_filter;
2150 $resql = $this->db->query($sql);
2151 if (!$resql) {
2152 $error++;
2153 $this->errors[] = 'Error '.$this->db->lasterror();
2154 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
2155 }
2156 }
2157
2158 if (!$error) {
2159 $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.'_tmp WHERE piece_num = '.((int) $piece_num).' AND entity = ' .((int) $conf->entity);
2160 $sql .= $sql_filter;
2161 $resql = $this->db->query($sql);
2162 if (!$resql) {
2163 $error++;
2164 $this->errors[] = 'Error '.$this->db->lasterror();
2165 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
2166 }
2167 }
2168 }
2169 if (!$error) {
2170 $this->db->commit();
2171 return 1;
2172 } else {
2173 $this->db->rollback();
2174 return -1;
2175 }
2176 /*
2177 $sql = "DELETE FROM ";
2178 $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping as ab";
2179 $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "accounting_account as aa ON aa.account_number = ab.numero_compte";
2180 $sql .= " AND aa.active = 1";
2181 $sql .= " INNER JOIN " . MAIN_DB_PREFIX . "accounting_system as asy ON aa.fk_pcg_version = asy.pcg_version";
2182 $sql .= " AND asy.rowid = " . ((int) $pcgver);
2183 $sql .= " AND ab.entity IN (" . getEntity('accountancy') . ")";
2184 $sql .= " ORDER BY account_number ASC";
2185 */
2186 }
2187
2188 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2201 public function select_account($selectid, $htmlname = 'account', $showempty = 0, $event = array(), $select_in = 0, $select_out = 0, $aabase = '')
2202 {
2203 // phpcs:enable
2204 global $conf;
2205
2206 require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php';
2207
2208 $pcgver = getDolGlobalInt('CHARTOFACCOUNTS');
2209
2210 $sql = "SELECT DISTINCT ab.numero_compte as account_number, aa.label as label, aa.rowid as rowid, aa.fk_pcg_version";
2211 $sql .= " FROM ".MAIN_DB_PREFIX."accounting_bookkeeping as ab";
2212 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."accounting_account as aa ON aa.account_number = ab.numero_compte";
2213 $sql .= " AND aa.active = 1";
2214 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."accounting_system as asy ON aa.fk_pcg_version = asy.pcg_version";
2215 $sql .= " AND asy.rowid = ".((int) $pcgver);
2216 $sql .= " AND ab.entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
2217 $sql .= " ORDER BY account_number ASC";
2218
2219 dol_syslog(get_class($this)."::select_account", LOG_DEBUG);
2220 $resql = $this->db->query($sql);
2221
2222 if (!$resql) {
2223 $this->error = "Error ".$this->db->lasterror();
2224 dol_syslog(get_class($this)."::select_account ".$this->error, LOG_ERR);
2225 return "-1";
2226 }
2227
2228 $out = ajax_combobox($htmlname, $event);
2229
2230 $options = array();
2231 $selected = null;
2232
2233 while ($obj = $this->db->fetch_object($resql)) {
2234 $label = length_accountg($obj->account_number).' - '.$obj->label;
2235
2236 $select_value_in = $obj->rowid;
2237 $select_value_out = $obj->rowid;
2238
2239 if ($select_in == 1) {
2240 $select_value_in = $obj->account_number;
2241 }
2242 if ($select_out == 1) {
2243 $select_value_out = $obj->account_number;
2244 }
2245
2246 // Remember guy's we store in database llx_facturedet the rowid of accounting_account and not the account_number
2247 // Because same account_number can be share between different accounting_system and do have the same meaning
2248 if (($selectid != '') && $selectid == $select_value_in) {
2249 $selected = $select_value_out;
2250 }
2251
2252 $options[$select_value_out] = $label;
2253 }
2254
2255 $out .= Form::selectarray($htmlname, $options, $selected, $showempty, 0, 0, '', 0, 0, 0, '', 'maxwidth300');
2256 $this->db->free($resql);
2257 return $out;
2258 }
2259
2267 public function getRootAccount($account = null)
2268 {
2269 global $conf;
2270 $pcgver = getDolGlobalInt('CHARTOFACCOUNTS');
2271
2272 $sql = "SELECT root.rowid, root.account_number, root.label as label,";
2273 $sql .= " parent.rowid as parent_rowid, parent.account_number as parent_account_number, parent.label as parent_label";
2274 $sql .= " FROM ".MAIN_DB_PREFIX."accounting_account as aa";
2275 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."accounting_system as asy ON aa.fk_pcg_version = asy.pcg_version";
2276 $sql .= " AND asy.rowid = ".((int) $pcgver);
2277 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."accounting_account as parent ON aa.account_parent = parent.rowid AND parent.active = 1";
2278 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."accounting_account as root ON parent.account_parent = root.rowid AND root.active = 1";
2279 $sql .= " WHERE aa.account_number = '".$this->db->escape($account)."'";
2280 $sql .= " AND aa.entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
2281
2282 dol_syslog(get_class($this)."::select_account", LOG_DEBUG);
2283 $resql = $this->db->query($sql);
2284 if ($resql) {
2285 $obj = '';
2286 if ($this->db->num_rows($resql)) {
2287 $obj = $this->db->fetch_object($resql);
2288 }
2289
2290 $result = array('id' => $obj->rowid, 'account_number' => $obj->account_number, 'label' => $obj->label);
2291 return $result;
2292 } else {
2293 $this->error = "Error ".$this->db->lasterror();
2294 dol_syslog(__METHOD__." ".$this->error, LOG_ERR);
2295
2296 return -1;
2297 }
2298 }
2299
2300 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2307 public function get_compte_desc($account = null)
2308 {
2309 // phpcs:enable
2310 global $conf;
2311
2312 $pcgver = getDolGlobalInt('CHARTOFACCOUNTS');
2313 $sql = "SELECT aa.account_number, aa.label, aa.rowid, aa.fk_pcg_version, cat.label as category";
2314 $sql .= " FROM ".MAIN_DB_PREFIX."accounting_account as aa ";
2315 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."accounting_system as asy ON aa.fk_pcg_version = asy.pcg_version";
2316 $sql .= " AND aa.account_number = '".$this->db->escape($account)."'";
2317 $sql .= " AND asy.rowid = ".((int) $pcgver);
2318 $sql .= " AND aa.active = 1";
2319 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_accounting_category as cat ON aa.fk_accounting_category = cat.rowid";
2320 $sql .= " WHERE aa.entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
2321
2322 dol_syslog(get_class($this)."::select_account", LOG_DEBUG);
2323 $resql = $this->db->query($sql);
2324 if ($resql) {
2325 $obj = '';
2326 if ($this->db->num_rows($resql)) {
2327 $obj = $this->db->fetch_object($resql);
2328 }
2329 if (empty($obj->category)) {
2330 return $obj->label;
2331 } else {
2332 return $obj->label.' ('.$obj->category.')';
2333 }
2334 } else {
2335 $this->error = "Error ".$this->db->lasterror();
2336 dol_syslog(__METHOD__." ".$this->error, LOG_ERR);
2337 return "-1";
2338 }
2339 }
2340
2348 public function getCanModifyBookkeepingSQL($alias = '', $force = false)
2349 {
2350 global $conf;
2351
2352 $alias = trim($alias);
2353 $alias = !empty($alias) && strpos($alias, '.') < 0 ? $alias . "." : $alias;
2354
2355 if (!isset(self::$can_modify_bookkeeping_sql_cached[$alias]) || $force) {
2356 $result = $this->loadFiscalPeriods($force, 'active');
2357 if ($result < 0) {
2358 return null;
2359 }
2360
2361 $sql_list = array();
2362 if (!empty($conf->cache['active_fiscal_period_cached']) && is_array($conf->cache['active_fiscal_period_cached'])) {
2363 $i = 0;
2364 foreach ($conf->cache['active_fiscal_period_cached'] as $fiscal_period) {
2365 $sql_list[$i] = "(";
2366 $sql_list[$i] .= "'".$this->db->idate($fiscal_period['date_start']) . "' <= ".$this->db->sanitize($alias)."doc_date";
2367 if (!empty($fiscal_period['date_end'])) {
2368 $sql_list[$i] .= " AND ";
2369 $sql_list[$i] .= $this->db->sanitize($alias)."doc_date <= '" . $this->db->idate($fiscal_period['date_end'])."'";
2370 }
2371 $sql_list[$i] .= ")";
2372 $i++;
2373 }
2374 }
2375 $sqlsanitized = implode(' OR ', $sql_list);
2376 self::$can_modify_bookkeeping_sql_cached[$alias] = empty($sql_list) ? "" : " AND (".$sqlsanitized.")";
2377 }
2378
2379 return self::$can_modify_bookkeeping_sql_cached[$alias];
2380 }
2381
2389 public function canModifyBookkeeping($id, $mode = '')
2390 {
2391 global $conf;
2392
2393 if (getDolGlobalString('ACCOUNTANCY_FISCAL_PERIOD_MODE') == 'blockedonclosed') {
2394 $result = $this->loadFiscalPeriods(false, 'closed');
2395
2396 if ($result < 0) {
2397 return -1;
2398 }
2399
2400 $bookkeeping = new BookKeeping($this->db);
2401 $result = $bookkeeping->fetch($id, null, $mode);
2402 if ($result <= 0) {
2403 return $result;
2404 }
2405
2406 if (!empty($conf->cache['closed_fiscal_period_cached']) && is_array($conf->cache['closed_fiscal_period_cached'])) {
2407 foreach ($conf->cache['closed_fiscal_period_cached'] as $fiscal_period) {
2408 if ($fiscal_period['date_start'] <= $bookkeeping->doc_date && $bookkeeping->doc_date <= $fiscal_period['date_end']) {
2409 return 0;
2410 }
2411 }
2412 }
2413
2414 return 1;
2415 } else {
2416 $result = $this->loadFiscalPeriods(false, 'active');
2417 if ($result < 0) {
2418 return -1;
2419 }
2420
2421 $bookkeeping = new BookKeeping($this->db);
2422 $result = $bookkeeping->fetch($id, null, $mode);
2423
2424 if ($result <= 0) {
2425 return $result;
2426 }
2427 if (!empty($conf->cache['active_fiscal_period_cached']) && is_array($conf->cache['active_fiscal_period_cached'])) {
2428 foreach ($conf->cache['active_fiscal_period_cached'] as $fiscal_period) {
2429 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'])) {
2430 return 1;
2431 }
2432 }
2433 }
2434
2435 return 0;
2436 }
2437 }
2438
2445 public function validBookkeepingDate($date)
2446 {
2447 global $conf;
2448
2449 if (getDolGlobalString('ACCOUNTANCY_FISCAL_PERIOD_MODE') == 'blockedonclosed') {
2450 $result = $this->loadFiscalPeriods(false, 'closed');
2451
2452 if ($result < 0) {
2453 return -1;
2454 }
2455
2456 if (!empty($conf->cache['closed_fiscal_period_cached']) && is_array($conf->cache['closed_fiscal_period_cached'])) {
2457 foreach ($conf->cache['closed_fiscal_period_cached'] as $fiscal_period) {
2458 if ($fiscal_period['date_start'] <= $date && $date <= $fiscal_period['date_end']) {
2459 return 0;
2460 }
2461 }
2462 }
2463
2464 return 1;
2465 } else {
2466 $result = $this->loadFiscalPeriods(false, 'active');
2467 if ($result < 0) {
2468 return -1;
2469 }
2470
2471 if (!empty($conf->cache['active_fiscal_period_cached']) && is_array($conf->cache['active_fiscal_period_cached'])) {
2472 foreach ($conf->cache['active_fiscal_period_cached'] as $fiscal_period) {
2473 if (!empty($fiscal_period['date_start']) && $fiscal_period['date_start'] <= $date && (empty($fiscal_period['date_end']) || $date <= $fiscal_period['date_end'])) {
2474 return 1;
2475 }
2476 }
2477 }
2478
2479 return 0;
2480 }
2481 }
2482
2490 public function loadFiscalPeriods($force = false, $mode = 'active')
2491 {
2492 global $conf;
2493
2494 if ($mode == 'active') {
2495 if (!isset($conf->cache['active_fiscal_period_cached']) || $force) {
2496 $sql = "SELECT date_start, date_end";
2497 $sql .= " FROM " . $this->db->prefix() . "accounting_fiscalyear";
2498 $sql .= " WHERE entity = " . ((int) $conf->entity);
2499 $sql .= " AND statut = 0";
2500
2501 $resql = $this->db->query($sql);
2502 if (!$resql) {
2503 $this->errors[] = $this->db->lasterror();
2504 return -1;
2505 }
2506
2507 $list = array();
2508 while ($obj = $this->db->fetch_object($resql)) {
2509 $list[] = array(
2510 'date_start' => $this->db->jdate($obj->date_start),
2511 'date_end' => $this->db->jdate($obj->date_end),
2512 );
2513 }
2514 $conf->cache['active_fiscal_period_cached'] = $list;
2515 }
2516 }
2517 if ($mode == 'closed') {
2518 if (!isset($conf->cache['closed_fiscal_period_cached']) || $force) {
2519 $sql = "SELECT date_start, date_end";
2520 $sql .= " FROM " . $this->db->prefix() . "accounting_fiscalyear";
2521 $sql .= " WHERE entity = " . ((int) $conf->entity);
2522 $sql .= " AND statut = 1";
2523
2524 $resql = $this->db->query($sql);
2525 if (!$resql) {
2526 $this->errors[] = $this->db->lasterror();
2527 return -1;
2528 }
2529
2530 $list = array();
2531 while ($obj = $this->db->fetch_object($resql)) {
2532 $list[] = array(
2533 'date_start' => $this->db->jdate($obj->date_start),
2534 'date_end' => $this->db->jdate($obj->date_end),
2535 );
2536 }
2537 $conf->cache['closed_fiscal_period_cached'] = $list;
2538 }
2539 }
2540
2541 return 1;
2542 }
2543
2550 public function getFiscalPeriods($filter = '')
2551 {
2552 global $conf;
2553 $list = array();
2554
2555 $sql = "SELECT rowid, label, date_start, date_end, statut";
2556 $sql .= " FROM " . $this->db->prefix() . "accounting_fiscalyear";
2557 $sql .= " WHERE entity = " . ((int) $conf->entity);
2558 if (!empty($filter)) {
2559 $sql .= " AND (" . $this->db->sanitize($filter, 1, 1, 1) . ')';
2560 }
2561 $sql .= $this->db->order('date_start', 'ASC');
2562
2563 $resql = $this->db->query($sql);
2564 if (!$resql) {
2565 $this->errors[] = $this->db->lasterror();
2566 return -1;
2567 }
2568
2569 while ($obj = $this->db->fetch_object($resql)) {
2570 $list[$obj->rowid] = array(
2571 'id' => (int) $obj->rowid,
2572 'label' => $obj->label,
2573 'date_start' => $this->db->jdate($obj->date_start),
2574 'date_end' => $this->db->jdate($obj->date_end),
2575 'status' => (int) $obj->statut,
2576 );
2577 }
2578
2579 return $list;
2580 }
2581
2589 public function getCountByMonthForFiscalPeriod($date_start, $date_end)
2590 {
2591 $total = 0;
2592 $list = array();
2593
2594 $sql = "SELECT YEAR(b.doc_date) as year";
2595 for ($i = 1; $i <= 12; $i++) {
2596 $sql .= ", SUM(".$this->db->ifsql("MONTH(b.doc_date) = ".((int) $i), "1", "0") . ") AS month".((int) $i);
2597 }
2598 $sql .= ", COUNT(b.rowid) as total";
2599 $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping as b";
2600 $sql .= " WHERE b.doc_date >= '" . $this->db->idate($date_start) . "'";
2601 $sql .= " AND b.doc_date <= '" . $this->db->idate($date_end) . "'";
2602 $sql .= " AND b.entity IN (" . getEntity('bookkeeping', 0) . ")"; // We don't share object for accountancy
2603
2604 // Get count for each month into the fiscal period
2605 if (getDolGlobalString("ACCOUNTANCY_DISABLE_CLOSURE_LINE_BY_LINE")) {
2606 // TODO Analyse is done by finding record not into a closed period
2607 // Loop on each closed period
2608 $sql .= " AND b.doc_date BETWEEN 0 AND 0";
2609 } else {
2610 // Analyse closed record using the unitary flag/date on each record
2611 $sql .= " AND date_validated IS NULL";
2612 }
2613
2614 $sql .= " GROUP BY YEAR(b.doc_date)";
2615 $sql .= $this->db->order("year", 'ASC');
2616
2617 dol_syslog(__METHOD__, LOG_DEBUG);
2618 $resql = $this->db->query($sql);
2619 if (!$resql) {
2620 $this->errors[] = $this->db->lasterror();
2621 return -1;
2622 }
2623
2624 while ($obj = $this->db->fetch_object($resql)) {
2625 $total += (int) $obj->total;
2626 $year_list = array(
2627 'year' => (int) $obj->year,
2628 'count' => array(),
2629 'total' => (int) $obj->total,
2630 );
2631 for ($i = 1; $i <= 12; $i++) {
2632 $year_list['count'][$i] = (int) $obj->{'month' . $i};
2633 }
2634
2635 $list[] = $year_list;
2636 }
2637
2638 $this->db->free($resql);
2639
2640 return array(
2641 'total' => $total,
2642 'list' => $list,
2643 );
2644 }
2645
2653 public function validateMovementForFiscalPeriod($date_start, $date_end)
2654 {
2655 global $conf;
2656
2657 $now = dol_now();
2658
2659 // Specify as export : update field date_validated on selected month/year
2660 $sql = " UPDATE " . MAIN_DB_PREFIX . "accounting_bookkeeping";
2661 $sql .= " SET date_validated = '" . $this->db->idate($now) . "'";
2662 $sql .= " WHERE entity = " . ((int) $conf->entity);
2663 $sql .= " AND DATE(doc_date) >= '" . $this->db->idate($date_start) . "'";
2664 $sql .= " AND DATE(doc_date) <= '" . $this->db->idate($date_end) . "'";
2665 $sql .= " AND date_validated IS NULL";
2666
2667 dol_syslog(__METHOD__, LOG_DEBUG);
2668 $resql = $this->db->query($sql);
2669 if (!$resql) {
2670 $this->errors[] = $this->db->lasterror();
2671 return -1;
2672 }
2673
2674 return 1;
2675 }
2676
2684 public function accountingResult($date_start, $date_end)
2685 {
2686 global $conf;
2687
2688 $this->db->begin();
2689
2690 $income_statement_amount = 0;
2691
2692 if (getDolGlobalString('ACCOUNTING_CLOSURE_ACCOUNTING_GROUPS_USED_FOR_INCOME_STATEMENT')) {
2693 $accounting_groups_used_for_income_statement = array_filter(array_map('trim', explode(',', getDolGlobalString('ACCOUNTING_CLOSURE_ACCOUNTING_GROUPS_USED_FOR_INCOME_STATEMENT'))), 'strlen');
2694
2695 $pcg_type_filter = array();
2696 foreach ($accounting_groups_used_for_income_statement as $item) {
2697 $pcg_type_filter[] = "'" . $this->db->escape($item) . "'";
2698 }
2699
2700 $sql = 'SELECT';
2701 $sql .= " t.numero_compte,";
2702 $sql .= " aa.pcg_type,";
2703 $sql .= " (SUM(t.credit) - SUM(t.debit)) as accounting_result";
2704 $sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . ' as t';
2705 $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'accounting_account as aa ON aa.account_number = t.numero_compte';
2706 $sql .= ' WHERE t.entity = ' . ((int) $conf->entity); // Do not use getEntity for accounting features
2707 $sql .= " AND aa.entity = " . ((int) $conf->entity);
2708 $sql .= ' AND aa.fk_pcg_version IN (SELECT pcg_version FROM ' . MAIN_DB_PREFIX . 'accounting_system WHERE rowid = ' . ((int) getDolGlobalInt('CHARTOFACCOUNTS')) . ')';
2709 $sql .= ' AND aa.pcg_type IN (' . $this->db->sanitize(implode(',', $pcg_type_filter), 1) . ')';
2710 $sql .= " AND DATE(t.doc_date) >= '" . $this->db->idate($date_start) . "'";
2711 $sql .= " AND DATE(t.doc_date) <= '" . $this->db->idate($date_end) . "'";
2712 $sql .= ' GROUP BY t.numero_compte, aa.pcg_type';
2713
2714 $resql = $this->db->query($sql);
2715 if (!$resql) {
2716 $this->errors[] = 'Error ' . $this->db->lasterror();
2717 dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
2718 } else {
2719 while ($obj = $this->db->fetch_object($resql)) {
2720 $income_statement_amount += $obj->accounting_result;
2721 }
2722 }
2723 }
2724
2725 return (string) $income_statement_amount;
2726 }
2727
2737 public function closeFiscalPeriod($fiscal_period_id, $new_fiscal_period_id, $separate_auxiliary_account = false, $generate_bookkeeping_records = true)
2738 {
2739 global $conf, $langs, $user;
2740
2741 // Current fiscal period
2742 $fiscal_period_id = max(0, $fiscal_period_id);
2743 if (empty($fiscal_period_id)) {
2744 $langs->load('errors');
2745 $this->errors[] = $langs->trans('ErrorBadParameters');
2746 return -1;
2747 }
2748 $fiscal_period = new Fiscalyear($this->db);
2749 $result = $fiscal_period->fetch($fiscal_period_id);
2750 if ($result < 0) {
2751 $this->error = $fiscal_period->error;
2752 $this->errors = $fiscal_period->errors;
2753 return -1;
2754 } elseif (empty($fiscal_period->id)) {
2755 $langs->loadLangs(array('errors', 'compta'));
2756 $this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('FiscalPeriod') . ' (' . $fiscal_period_id . ')';
2757 return -1;
2758 }
2759
2760 // New fiscal period
2761 $new_fiscal_period_id = max(0, $new_fiscal_period_id);
2762 if (empty($new_fiscal_period_id)) {
2763 $langs->load('errors');
2764 $this->errors[] = $langs->trans('ErrorBadParameters');
2765 return -1;
2766 }
2767 $new_fiscal_period = new Fiscalyear($this->db);
2768 $result = $new_fiscal_period->fetch($new_fiscal_period_id);
2769 if ($result < 0) {
2770 $this->error = $new_fiscal_period->error;
2771 $this->errors = $new_fiscal_period->errors;
2772 return -1;
2773 } elseif (empty($new_fiscal_period->id)) {
2774 $langs->loadLangs(array('errors', 'compta'));
2775 $this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('FiscalPeriod') . ' (' . $new_fiscal_period_id . ')';
2776 return -1;
2777 }
2778
2779 $error = 0;
2780 $this->db->begin();
2781
2782 $fiscal_period->statut = Fiscalyear::STATUS_CLOSED;
2783 $fiscal_period->status = Fiscalyear::STATUS_CLOSED; // Actually not used
2784 $result = $fiscal_period->update($user);
2785 if ($result < 0) {
2786 $this->error = $fiscal_period->error;
2787 $this->errors = $fiscal_period->errors;
2788 $error++;
2789 }
2790
2791 if (!$error && !empty($generate_bookkeeping_records)) {
2792 $journal_id = max(0, getDolGlobalString('ACCOUNTING_CLOSURE_DEFAULT_JOURNAL'));
2793 if (empty($journal_id)) {
2794 $langs->loadLangs(array('errors', 'accountancy'));
2795 $this->errors[] = $langs->trans('ErrorBadParameters') . ' - ' . $langs->trans('Codejournal') . ' (' . $langs->trans('AccountingJournalType9') . ')';
2796 $error++;
2797 }
2798
2799 // Fetch journal
2800 if (!$error) {
2801 $journal = new AccountingJournal($this->db);
2802 $result = $journal->fetch($journal_id);
2803 if ($result < 0) {
2804 $this->error = $journal->error;
2805 $this->errors = $journal->errors;
2806 $error++;
2807 } elseif ($result == 0) {
2808 $langs->loadLangs(array('errors', 'accountancy'));
2809 $this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('Codejournal') . ' (' . $langs->trans('AccountingJournalType9') . ')';
2810 $error++;
2811 }
2812 }
2813
2814 if (!$error) {
2815 $accounting_groups_used_for_balance_sheet_account = array_filter(array_map('trim', explode(',', getDolGlobalString('ACCOUNTING_CLOSURE_ACCOUNTING_GROUPS_USED_FOR_BALANCE_SHEET_ACCOUNT'))), 'strlen');
2816 $accounting_groups_used_for_income_statement = array_filter(array_map('trim', explode(',', getDolGlobalString('ACCOUNTING_CLOSURE_ACCOUNTING_GROUPS_USED_FOR_INCOME_STATEMENT'))), 'strlen');
2817
2818 $pcg_type_filter = array();
2819 $tmp = array_merge($accounting_groups_used_for_balance_sheet_account, $accounting_groups_used_for_income_statement);
2820 foreach ($tmp as $item) {
2821 $pcg_type_filter[] = "'" . $this->db->escape($item) . "'";
2822 }
2823
2824 $sql = 'SELECT';
2825 $sql .= " t.numero_compte,";
2826 if ($separate_auxiliary_account) {
2827 $sql .= " NULLIF(t.subledger_account, '') as subledger_account,"; // fix db issues with Null or "" values
2828 }
2829 $sql .= " aa.pcg_type,";
2830 $sql .= " (SUM(t.credit) - SUM(t.debit)) as opening_balance";
2831 $sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . ' as t';
2832 $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'accounting_account as aa ON aa.account_number = t.numero_compte';
2833 $sql .= ' WHERE t.entity = ' . ((int) $conf->entity); // Do not use getEntity for accounting features
2834 $sql .= " AND aa.entity = ". ((int) $conf->entity);
2835 $sql .= ' AND aa.fk_pcg_version IN (SELECT pcg_version FROM '.MAIN_DB_PREFIX.'accounting_system WHERE rowid = '.((int) getDolGlobalInt('CHARTOFACCOUNTS')).')';
2836 $sql .= ' AND aa.pcg_type IN (' . $this->db->sanitize(implode(',', $pcg_type_filter), 1) . ')';
2837 $sql .= " AND DATE(t.doc_date) >= '" . $this->db->idate($fiscal_period->date_start) . "'";
2838 $sql .= " AND DATE(t.doc_date) <= '" . $this->db->idate($fiscal_period->date_end) . "'";
2839 $sql .= ' GROUP BY t.numero_compte, aa.pcg_type';
2840 if ($separate_auxiliary_account) {
2841 $sql .= " , NULLIF(t.subledger_account, '')";
2842 }
2843 $sql .= ' HAVING (SUM(t.credit) - SUM(t.debit)) != 0 '; // Exclude rows with opening_balance = 0
2844 $sql .= $this->db->order("t.numero_compte", "ASC");
2845
2846 $resql = $this->db->query($sql);
2847 if (!$resql) {
2848 $this->errors[] = 'Error ' . $this->db->lasterror();
2849 dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
2850
2851 $error++;
2852 } else {
2853 $now = dol_now();
2854 $income_statement_amount = 0;
2855 while ($obj = $this->db->fetch_object($resql)) {
2856 if (in_array($obj->pcg_type, $accounting_groups_used_for_income_statement)) {
2857 $income_statement_amount += $obj->opening_balance;
2858 } else {
2859 // Insert bookkeeping record for balance sheet account
2860 $mt = $obj->opening_balance;
2861
2862 $bookkeeping = new BookKeeping($this->db);
2863 $bookkeeping->doc_date = $new_fiscal_period->date_start;
2864
2865 $bookkeeping->date_lim_reglement = '';
2866 $bookkeeping->doc_ref = $fiscal_period->label;
2867
2868 $bookkeeping->date_creation = $now;
2869 $bookkeeping->doc_type = 'closure';
2870 $bookkeeping->fk_doc = $fiscal_period->id;
2871 $bookkeeping->fk_docdet = 0; // Useless, can be several lines that are source of this record to add
2872 $bookkeeping->thirdparty_code = '';
2873
2874 if ($separate_auxiliary_account) {
2875 $bookkeeping->subledger_account = $obj->subledger_account;
2876 $sql = 'SELECT';
2877 $sql .= " subledger_label";
2878 $sql .= " FROM " . MAIN_DB_PREFIX . $this->table_element;
2879 $sql .= " WHERE subledger_account = '" . $this->db->escape($obj->subledger_account) . "'";
2880 $sql .= " ORDER BY doc_date DESC";
2881 $sql .= " LIMIT 1";
2882 $result = $this->db->query($sql);
2883 if (!$result) {
2884 $this->errors[] = 'Error: ' . $this->db->lasterror();
2885 dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
2886 $error++;
2887 }
2888 $objtmp = $this->db->fetch_object($result);
2889 $bookkeeping->subledger_label = $objtmp->subledger_label; // latest subledger label used
2890 } else {
2891 $bookkeeping->subledger_account = null;
2892 $bookkeeping->subledger_label = null;
2893 }
2894
2895 $bookkeeping->numero_compte = $obj->numero_compte;
2896 $accountingaccount = new AccountingAccount($this->db);
2897 $accountingaccount->fetch('', $obj->numero_compte);
2898 $bookkeeping->label_compte = $accountingaccount->label; // latest account label used
2899
2900 $bookkeeping->label_operation = $new_fiscal_period->label;
2901 $bookkeeping->montant = $mt;
2902 $bookkeeping->sens = ($mt >= 0) ? 'C' : 'D';
2903 $bookkeeping->debit = ($mt < 0) ? -$mt : 0;
2904 $bookkeeping->credit = ($mt >= 0) ? $mt : 0;
2905 $bookkeeping->code_journal = $journal->code;
2906 $bookkeeping->journal_label = $langs->transnoentities($journal->label);
2907 $bookkeeping->fk_user_author = $user->id;
2908 $bookkeeping->entity = $conf->entity;
2909
2910 $result = $bookkeeping->create($user);
2911 if ($result < 0) {
2912 $this->error = $bookkeeping->error;
2913 $this->errors = $bookkeeping->errors;
2914 $error++;
2915 break;
2916 }
2917 }
2918 }
2919
2920 // Insert bookkeeping record for income statement
2921 if (!$error && $income_statement_amount != 0) {
2922 $mt = $income_statement_amount;
2923 $accountingaccount = new AccountingAccount($this->db);
2924 $accountingaccount->fetch(null, getDolGlobalString($income_statement_amount < 0 ? 'ACCOUNTING_RESULT_LOSS' : 'ACCOUNTING_RESULT_PROFIT'), true);
2925
2926 $bookkeeping = new BookKeeping($this->db);
2927 $bookkeeping->doc_date = $new_fiscal_period->date_start;
2928
2929 $bookkeeping->date_lim_reglement = '';
2930 $bookkeeping->doc_ref = $fiscal_period->label;
2931
2932 $bookkeeping->date_creation = $now;
2933 $bookkeeping->doc_type = 'closure';
2934 $bookkeeping->fk_doc = $fiscal_period->id;
2935 $bookkeeping->fk_docdet = 0; // Useless, can be several lines that are source of this record to add
2936 $bookkeeping->thirdparty_code = '';
2937
2938 if ($separate_auxiliary_account) {
2939 $bookkeeping->subledger_account = $obj->subledger_account;
2940 $sql = 'SELECT';
2941 $sql .= " subledger_label";
2942 $sql .= " FROM " . MAIN_DB_PREFIX . $this->table_element;
2943 $sql .= " WHERE subledger_account = '" . $this->db->escape($obj->subledger_account) . "'";
2944 $sql .= " ORDER BY doc_date DESC";
2945 $sql .= " LIMIT 1";
2946 $result = $this->db->query($sql);
2947 if (!$result) {
2948 $this->errors[] = 'Error: ' . $this->db->lasterror();
2949 dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
2950 $error++;
2951 }
2952 $objtmp = $this->db->fetch_object($result);
2953 $bookkeeping->subledger_label = $objtmp->subledger_label; // latest subledger label used
2954 } else {
2955 $bookkeeping->subledger_account = null;
2956 $bookkeeping->subledger_label = null;
2957 }
2958
2959 $bookkeeping->numero_compte = $accountingaccount->account_number;
2960 $bookkeeping->label_compte = $accountingaccount->label;
2961
2962 $bookkeeping->label_operation = $new_fiscal_period->label;
2963 $bookkeeping->montant = $mt;
2964 $bookkeeping->sens = ($mt >= 0) ? 'C' : 'D';
2965 $bookkeeping->debit = ($mt < 0) ? -$mt : 0;
2966 $bookkeeping->credit = ($mt >= 0) ? $mt : 0;
2967 $bookkeeping->code_journal = $journal->code;
2968 $bookkeeping->journal_label = $langs->transnoentities($journal->label);
2969 $bookkeeping->fk_user_author = $user->id;
2970 $bookkeeping->entity = $conf->entity;
2971
2972 $result = $bookkeeping->create($user);
2973 if ($result < 0) {
2974 $this->error = $bookkeeping->error;
2975 $this->errors = $bookkeeping->errors;
2976 $error++;
2977 }
2978 }
2979 $this->db->free($resql);
2980 }
2981 }
2982 }
2983
2984 if ($error) {
2985 $this->db->rollback();
2986 return -1;
2987 } else {
2988 $this->db->commit();
2989 return 1;
2990 }
2991 }
2992
3003 public function insertAccountingReversal($fiscal_period_id, $inventory_journal_id, $new_fiscal_period_id, $date_start, $date_end)
3004 {
3005 global $conf, $langs, $user;
3006
3007 // Current fiscal period
3008 $fiscal_period_id = max(0, $fiscal_period_id);
3009 if (empty($fiscal_period_id)) {
3010 $langs->load('errors');
3011 $this->errors[] = $langs->trans('ErrorBadParameters');
3012 return -1;
3013 }
3014 $fiscal_period = new Fiscalyear($this->db);
3015 $result = $fiscal_period->fetch($fiscal_period_id);
3016 if ($result < 0) {
3017 $this->error = $fiscal_period->error;
3018 $this->errors = $fiscal_period->errors;
3019 return -1;
3020 } elseif (empty($fiscal_period->id)) {
3021 $langs->loadLangs(array('errors', 'compta'));
3022 $this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('FiscalPeriod') . ' (' . $fiscal_period_id . ')';
3023 return -1;
3024 }
3025
3026 // New fiscal period
3027 $new_fiscal_period_id = max(0, $new_fiscal_period_id);
3028 if (empty($new_fiscal_period_id)) {
3029 $langs->load('errors');
3030 $this->errors[] = $langs->trans('ErrorBadParameters');
3031 return -1;
3032 }
3033 $new_fiscal_period = new Fiscalyear($this->db);
3034 $result = $new_fiscal_period->fetch($new_fiscal_period_id);
3035 if ($result < 0) {
3036 $this->error = $new_fiscal_period->error;
3037 $this->errors = $new_fiscal_period->errors;
3038 return -1;
3039 } elseif (empty($new_fiscal_period->id)) {
3040 $langs->loadLangs(array('errors', 'compta'));
3041 $this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('FiscalPeriod') . ' (' . $new_fiscal_period_id . ')';
3042 return -1;
3043 }
3044
3045 // Inventory journal
3046 $inventory_journal_id = max(0, $inventory_journal_id);
3047 if (empty($inventory_journal_id)) {
3048 $langs->load('errors');
3049 $this->errors[] = $langs->trans('ErrorBadParameters');
3050 return -1;
3051 }
3052 // Fetch journal
3053 $inventory_journal = new AccountingJournal($this->db);
3054 $result = $inventory_journal->fetch($inventory_journal_id);
3055 if ($result < 0) {
3056 $this->error = $inventory_journal->error;
3057 $this->errors = $inventory_journal->errors;
3058 return -1;
3059 } elseif ($result == 0) {
3060 $langs->loadLangs(array('errors', 'accountancy'));
3061 $this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('InventoryJournal');
3062 return -1;
3063 }
3064
3065 $error = 0;
3066 $this->db->begin();
3067
3068 $sql = 'SELECT t.rowid';
3069 $sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . ' as t';
3070 $sql .= ' WHERE t.entity = ' . ((int) $conf->entity); // Do not use getEntity for accounting features
3071 $sql .= " AND code_journal = '" . $this->db->escape($inventory_journal->code) . "'";
3072 $sql .= " AND DATE(t.doc_date) >= '" . $this->db->idate($date_start) . "'";
3073 $sql .= " AND DATE(t.doc_date) <= '" . $this->db->idate($date_end) . "'";
3074 $sql .= " AND DATE(t.doc_date) >= '" . $this->db->idate($fiscal_period->date_start) . "'";
3075 $sql .= " AND DATE(t.doc_date) <= '" . $this->db->idate($fiscal_period->date_end) . "'";
3076
3077 $resql = $this->db->query($sql);
3078 if (!$resql) {
3079 $this->errors[] = 'Error ' . $this->db->lasterror();
3080 dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
3081
3082 $error++;
3083 } else {
3084 $now = dol_now();
3085 while ($obj = $this->db->fetch_object($resql)) {
3086 $bookkeeping = new BookKeeping($this->db);
3087 $result = $bookkeeping->fetch($obj->rowid);
3088 if ($result < 0) {
3089 $this->error = $inventory_journal->error;
3090 $this->errors = $inventory_journal->errors;
3091 $error++;
3092 break;
3093 } elseif ($result == 0) {
3094 $langs->loadLangs(array('errors', 'accountancy'));
3095 $this->errors[] = $langs->trans('ErrorRecordNotFound') . ' - ' . $langs->trans('LineId') . ': ' . $obj->rowid;
3096 $error++;
3097 break;
3098 }
3099
3100 $bookkeeping->id = 0;
3101 $bookkeeping->doc_date = $new_fiscal_period->date_start;
3102 $bookkeeping->doc_ref = $new_fiscal_period->label;
3103 $bookkeeping->date_creation = $now;
3104 $bookkeeping->doc_type = 'accounting_reversal';
3105 $bookkeeping->fk_doc = $new_fiscal_period->id;
3106 $bookkeeping->fk_docdet = 0; // Useless, can be several lines that are source of this record to add
3107
3108 $bookkeeping->montant = -$bookkeeping->montant;
3109 $bookkeeping->sens = ($bookkeeping->montant >= 0) ? 'C' : 'D';
3110 $old_debit = $bookkeeping->debit;
3111 $bookkeeping->debit = $bookkeeping->credit;
3112 $bookkeeping->credit = $old_debit;
3113
3114 $bookkeeping->fk_user_author = $user->id;
3115 $bookkeeping->entity = $conf->entity;
3116
3117 $result = $bookkeeping->create($user);
3118 if ($result < 0) {
3119 $this->error = $bookkeeping->error;
3120 $this->errors = $bookkeeping->errors;
3121 $error++;
3122 break;
3123 }
3124 }
3125 $this->db->free($resql);
3126 }
3127
3128 if ($error) {
3129 $this->db->rollback();
3130 return -1;
3131 } else {
3132 $this->db->commit();
3133 return 1;
3134 }
3135 }
3136}
3137
3142{
3146 public $id;
3147
3148 public $doc_date = null;
3149 public $doc_type;
3150 public $doc_ref;
3151
3155 public $fk_doc;
3156
3160 public $fk_docdet;
3161
3162 public $thirdparty_code;
3163 public $subledger_account;
3164 public $subledger_label;
3165 public $numero_compte;
3166 public $label_compte;
3167 public $label_operation;
3168 public $debit;
3169 public $credit;
3170
3175 public $montant;
3176
3180 public $amount;
3181
3185 public $multicurrency_amount;
3186
3190 public $multicurrency_code;
3191
3195 public $sens;
3196 public $lettering_code;
3197 public $date_lettering;
3198
3202 public $fk_user_author;
3203
3204 public $import_key;
3205 public $code_journal;
3206 public $journal_label;
3210 public $piece_num;
3211
3215 public $date_creation;
3216
3220 public $date_modification;
3221
3225 public $date_export;
3226
3230 public $date_validation;
3231
3235 public $date_lim_reglement;
3236}
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.