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