dolibarr 22.0.5
accountingjournal.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2017-2022 OpenDSI <support@open-dsi.fr>
3 * Copyright (C) 2024-2025 MDW <mdeweerd@users.noreply.github.com>
4 * Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
5 * Copyright (C) 2024 Alexandre Janniaux <alexandre.janniaux@gmail.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
31{
35 public $element = 'accounting_journal';
36
40 public $table_element = 'accounting_journal';
41
45 public $fk_element = '';
46
50 public $picto = 'generic';
51
55 public $rowid;
56
60 public $code;
61
65 public $label;
66
70 public $nature;
71
75 public $active;
76
80 public static $accounting_account_cached = array();
81
85 public static $nature_maps = array(
86 1 => 'variousoperations',
87 2 => 'sells',
88 3 => 'purchases',
89 4 => 'bank',
90 5 => 'expensereports',
91 8 => 'inventories',
92 9 => 'hasnew',
93 );
94
100 public function __construct($db)
101 {
102 $this->db = $db;
103
104 $this->ismultientitymanaged = 0;
105 }
106
113 public function create($user)
114 {
115 $valid_nature = array(1, 2, 3, 4, 5, 8, 9);
116 if (!in_array((int) $this->nature, $valid_nature)) {
117 $this->error = get_class($this)."::Create Error invalid field nature '" . strval($this->nature) . "'";
118 dol_syslog($this->error, LOG_ERR);
119 return -1;
120 }
121
122 $sql = "INSERT INTO ".MAIN_DB_PREFIX."accounting_journal";
123 $sql .= " (entity, code, label, nature, active)";
124 $sql .= " VALUES ("
125 . ((int) $this->entity) .",'"
126 . $this->db->escape($this->code) ."','"
127 . $this->db->escape($this->label) ."',"
128 . ((int) $this->nature) .","
129 . ((int) $this->active) .")";
130
131 dol_syslog(get_class($this)."::create", LOG_DEBUG);
132 $resql = $this->db->query($sql);
133 if (!$resql) {
134 $this->error = get_class($this)."::Create Error: " . $this->db->lasterror();
135 dol_syslog($this->error, LOG_ERR);
136 return -1;
137 }
138
139 $id = $this->db->last_insert_id(MAIN_DB_PREFIX."accounting_journal");
140 if ($id <= 0) {
141 $this->error = get_class($this)."::Create Error " . $id . ": " . $this->db->lasterror();
142 dol_syslog($this->error, LOG_ERR);
143 return -2;
144 }
145
146 $this->id = $id;
147 $this->rowid = $id;
148 return $id;
149 }
150
158 public function fetch($rowid = 0, $journal_code = null)
159 {
160 global $conf;
161
162 if ($rowid || $journal_code) {
163 $sql = "SELECT rowid, code, label, nature, active";
164 $sql .= " FROM ".MAIN_DB_PREFIX."accounting_journal";
165 $sql .= " WHERE";
166 if ($rowid) {
167 $sql .= " rowid = ".((int) $rowid);
168 } elseif ($journal_code) {
169 $sql .= " code = '".$this->db->escape($journal_code)."'";
170 $sql .= " AND entity = ".$conf->entity;
171 }
172
173 dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
174 $result = $this->db->query($sql);
175 if ($result) {
176 $obj = $this->db->fetch_object($result);
177
178 if ($obj) {
179 $this->id = $obj->rowid;
180 $this->rowid = $obj->rowid;
181
182 $this->code = $obj->code;
183 $this->ref = $obj->code;
184 $this->label = $obj->label;
185 $this->nature = $obj->nature;
186 $this->active = $obj->active;
187
188 return $this->id;
189 } else {
190 return 0;
191 }
192 } else {
193 $this->error = "Error ".$this->db->lasterror();
194 $this->errors[] = "Error ".$this->db->lasterror();
195 }
196 }
197 return -1;
198 }
199
210 public function getNomUrl($withpicto = 0, $withlabel = 0, $nourl = 0, $moretitle = '', $notooltip = 0)
211 {
212 global $langs, $conf, $hookmanager;
213
214 if (!empty($conf->dol_no_mouse_hover)) {
215 $notooltip = 1; // Force disable tooltips
216 }
217
218 $result = '';
219
220 $url = DOL_URL_ROOT.'/accountancy/admin/journals_list.php?id=35';
221
222 $label = '<u>'.$langs->trans("ShowAccountingJournal").'</u>';
223 if (!empty($this->code)) {
224 $label .= '<br><b>'.$langs->trans('Code').':</b> '.$this->code;
225 }
226 if (!empty($this->label)) {
227 $label .= '<br><b>'.$langs->trans('Label').':</b> '.$langs->transnoentities($this->label);
228 }
229 if ($moretitle) {
230 $label .= ' - '.$moretitle;
231 }
232
233 $linkclose = '';
234 if (empty($notooltip)) {
235 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
236 $label = $langs->trans("ShowAccountingJournal");
237 $linkclose .= ' alt="'.dolPrintHTMLForAttribute($label).'"';
238 }
239 $linkclose .= ' title="'.dolPrintHTMLForAttribute($label).'"';
240 $linkclose .= ' class="classfortooltip"';
241 }
242
243 $linkstart = '<a href="'.$url.'"';
244 $linkstart .= $linkclose.'>';
245 $linkend = '</a>';
246
247 if ($nourl) {
248 $linkstart = '';
249 $linkclose = '';
250 $linkend = '';
251 }
252
253 $label_link = $this->code;
254 if ($withlabel == 1 && !empty($this->label)) {
255 $label_link .= ' - '.($nourl ? '<span class="opacitymedium">' : '').$langs->transnoentities($this->label).($nourl ? '</span>' : '');
256 }
257 if ($withlabel == 2 && !empty($this->nature)) {
258 $key = $langs->trans("AccountingJournalType".$this->nature);
259 $transferlabel = ($key != "AccountingJournalType".strtoupper($langs->trans((string) $this->nature)) ? $key : $this->label);
260 $label_link .= ' - '.($nourl ? '<span class="opacitymedium">' : '').$transferlabel.($nourl ? '</span>' : '');
261 }
262
263 $result .= $linkstart;
264 if ($withpicto) {
265 $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);
266 }
267 if ($withpicto != 2) {
268 $result .= $label_link;
269 }
270 $result .= $linkend;
271
272 global $action;
273 $hookmanager->initHooks(array('accountingjournaldao'));
274 $parameters = array('id' => $this->id, 'getnomurl' => &$result);
275 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
276 if ($reshook > 0) {
277 $result = $hookmanager->resPrint;
278 } else {
279 $result .= $hookmanager->resPrint;
280 }
281 return $result;
282 }
283
290 public function getLibType($mode = 0)
291 {
292 return $this->LibType($this->nature, $mode);
293 }
294
295 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
303 public function LibType($nature, $mode = 0)
304 {
305 // phpcs:enable
306 global $langs;
307
308 $langs->loadLangs(array("accountancy"));
309
310 if ($mode == 0) {
311 $prefix = '';
312 if ($nature == 9) {
313 return $langs->trans('AccountingJournalType9');
314 } elseif ($nature == 5) {
315 return $langs->trans('AccountingJournalType5');
316 } elseif ($nature == 4) {
317 return $langs->trans('AccountingJournalType4');
318 } elseif ($nature == 3) {
319 return $langs->trans('AccountingJournalType3');
320 } elseif ($nature == 2) {
321 return $langs->trans('AccountingJournalType2');
322 } elseif ($nature == 1) {
323 return $langs->trans('AccountingJournalType1');
324 }
325 } elseif ($mode == 1) {
326 if ($nature == 9) {
327 return $langs->trans('AccountingJournalType9');
328 } elseif ($nature == 5) {
329 return $langs->trans('AccountingJournalType5');
330 } elseif ($nature == 4) {
331 return $langs->trans('AccountingJournalType4');
332 } elseif ($nature == 3) {
333 return $langs->trans('AccountingJournalType3');
334 } elseif ($nature == 2) {
335 return $langs->trans('AccountingJournalType2');
336 } elseif ($nature == 1) {
337 return $langs->trans('AccountingJournalType1');
338 }
339 }
340 return "";
341 }
342
343
354 public function getData(User $user, $type = 'view', $date_start = null, $date_end = null, $in_bookkeeping = 'notyet')
355 {
356 global $hookmanager;
357
358 // Clean parameters
359 if (empty($type)) {
360 $type = 'view';
361 }
362 if (empty($in_bookkeeping)) {
363 $in_bookkeeping = 'notyet';
364 }
365
366 $data = array();
367
368 $hookmanager->initHooks(array('accountingjournaldao'));
369 $parameters = array('data' => &$data, 'user' => $user, 'type' => $type, 'date_start' => $date_start, 'date_end' => $date_end, 'in_bookkeeping' => $in_bookkeeping);
370 $reshook = $hookmanager->executeHooks('getData', $parameters, $this); // Note that $action and $object may have been
371 if ($reshook < 0) {
372 $this->error = $hookmanager->error;
373 $this->errors = $hookmanager->errors;
374 return -1;
375 } elseif (empty($reshook)) {
376 switch ($this->nature) {
377 case 1: // Various Journal
378 $data = $this->getAssetData($user, $type, $date_start, $date_end, $in_bookkeeping);
379 break;
380 // case 2: // Sells Journal
381 // case 3: // Purchases Journal
382 // case 4: // Bank Journal
383 // case 5: // Expense reports Journal
384 // case 8: // Inventory Journal
385 // case 9: // hasnew Journal
386 }
387 }
388
389 return $data;
390 }
391
402 public function getAssetData(User $user, $type = 'view', $date_start = null, $date_end = null, $in_bookkeeping = 'notyet')
403 {
404 global $conf, $langs;
405
406 if (!isModEnabled('asset')) {
407 return array();
408 }
409
410 require_once DOL_DOCUMENT_ROOT . '/core/lib/accounting.lib.php';
411 require_once DOL_DOCUMENT_ROOT . '/asset/class/asset.class.php';
412 require_once DOL_DOCUMENT_ROOT . '/asset/class/assetaccountancycodes.class.php';
413 require_once DOL_DOCUMENT_ROOT . '/asset/class/assetdepreciationoptions.class.php';
414
415 $langs->loadLangs(array("assets"));
416
417 // Clean parameters
418 if (empty($type)) {
419 $type = 'view';
420 }
421 if (empty($in_bookkeeping)) {
422 $in_bookkeeping = 'notyet';
423 }
424
425 $sql = "";
426 $sql .= "SELECT ad.fk_asset AS rowid, a.ref AS asset_ref, a.label AS asset_label, a.acquisition_value_ht AS asset_acquisition_value_ht";
427 $sql .= ", a.disposal_date AS asset_disposal_date, a.disposal_amount_ht AS asset_disposal_amount_ht, a.disposal_subject_to_vat AS asset_disposal_subject_to_vat";
428 $sql .= ", ad.rowid AS depreciation_id, ad.depreciation_mode, ad.ref AS depreciation_ref, ad.depreciation_date, ad.depreciation_ht, ad.accountancy_code_debit, ad.accountancy_code_credit";
429 $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation as ad";
430 $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "asset as a ON a.rowid = ad.fk_asset";
431 $sql .= " WHERE a.entity IN (" . getEntity('asset', 0) . ')'; // We don't share object for accountancy, we use source object sharing
432 $sql .= " AND a.status > 0";
433 if ($in_bookkeeping == 'already') {
434 $sql .= " AND EXISTS (SELECT iab.fk_docdet FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping AS iab WHERE iab.fk_docdet = ad.rowid AND doc_type = 'asset')";
435 } elseif ($in_bookkeeping == 'notyet') {
436 $sql .= " AND NOT EXISTS (SELECT iab.fk_docdet FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping AS iab WHERE iab.fk_docdet = ad.rowid AND doc_type = 'asset')";
437 }
438 $sql .= " AND ad.ref != ''"; // not reversal lines
439 if ($date_start && $date_end) {
440 $sql .= " AND ad.depreciation_date >= '" . $this->db->idate($date_start) . "' AND ad.depreciation_date <= '" . $this->db->idate($date_end) . "'";
441 }
442 // Define begin binding date
443 if (getDolGlobalString('ACCOUNTING_DATE_START_BINDING')) {
444 $sql .= " AND ad.depreciation_date >= '" . $this->db->idate(getDolGlobalInt('ACCOUNTING_DATE_START_BINDING')) . "'";
445 }
446 $sql .= " ORDER BY ad.depreciation_date";
447
448 dol_syslog(__METHOD__, LOG_DEBUG);
449 $resql = $this->db->query($sql);
450 if (!$resql) {
451 $this->errors[] = $this->db->lasterror();
452 return -1;
453 }
454
455 $pre_data = array(
456 'elements' => array(),
457 );
458 while ($obj = $this->db->fetch_object($resql)) {
459 if (!isset($pre_data['elements'][$obj->rowid])) {
460 $pre_data['elements'][$obj->rowid] = array(
461 'ref' => $obj->asset_ref,
462 'label' => $obj->asset_label,
463 'acquisition_value_ht' => $obj->asset_acquisition_value_ht,
464 'depreciation' => array(),
465 );
466
467 // Disposal infos
468 if (isset($obj->asset_disposal_date)) {
469 $pre_data['elements'][$obj->rowid]['disposal'] = array(
470 'date' => $this->db->jdate($obj->asset_disposal_date),
471 'amount' => $obj->asset_disposal_amount_ht,
472 'subject_to_vat' => !empty($obj->asset_disposal_subject_to_vat),
473 );
474 }
475 }
476
477 $compta_debit = empty($obj->accountancy_code_debit) ? 'NotDefined' : $obj->accountancy_code_debit;
478 $compta_credit = empty($obj->accountancy_code_credit) ? 'NotDefined' : $obj->accountancy_code_credit;
479
480 $pre_data['elements'][$obj->rowid]['depreciation'][$obj->depreciation_id] = array(
481 'date' => $this->db->jdate($obj->depreciation_date),
482 'ref' => $obj->depreciation_ref,
483 'lines' => array(
484 $compta_debit => -$obj->depreciation_ht,
485 $compta_credit => $obj->depreciation_ht,
486 ),
487 );
488 }
489
490 $disposal_ref = $langs->transnoentitiesnoconv('AssetDisposal');
491 $journal = $this->code;
492 $journal_label = $this->label;
493 $journal_label_formatted = $langs->transnoentities($journal_label);
494 $now = dol_now();
495
496 $element_static = new Asset($this->db);
497
498 $journal_data = array();
499 foreach ($pre_data['elements'] as $pre_data_id => $pre_data_info) {
500 $element_static->id = $pre_data_id;
501 $element_static->ref = (string) $pre_data_info["ref"];
502 $element_static->label = (string) $pre_data_info["label"];
503 $element_static->acquisition_value_ht = $pre_data_info["acquisition_value_ht"];
504 $element_link = $element_static->getNomUrl(1, 'with_label');
505
506 $element_name_formatted_0 = dol_trunc($element_static->label, 16);
507 $label_operation = $element_static->getNomUrl(0, 'label', 16);
508
509 $element = array(
510 'ref' => dol_trunc($element_static->ref, 16, 'right', 'UTF-8', 1),
511 'error' => array_key_exists('error', $pre_data_info) ? $pre_data_info['error'] : '',
512 'blocks' => array(),
513 );
514
515 // Depreciation lines
516 //--------------------
517 foreach ($pre_data_info['depreciation'] as $depreciation_id => $line) {
518 $depreciation_ref = $line["ref"];
519 $depreciation_date = $line["date"];
520 $depreciation_date_formatted = dol_print_date($depreciation_date, 'day');
521
522 // lines
523 $blocks = array();
524 foreach ($line['lines'] as $account => $mt) {
525 $account_infos = $this->getAccountingAccountInfos($account);
526
527 if ($type == 'view') {
528 $account_to_show = length_accounta($account);
529 if (($account_to_show == "") || $account_to_show == 'NotDefined') {
530 $account_to_show = '<span class="error">' . $langs->trans("AssetInAccountNotDefined") . '</span>';
531 }
532
533 $blocks[] = array(
534 'date' => $depreciation_date_formatted,
535 'piece' => $element_link,
536 'account_accounting' => $account_to_show,
537 'subledger_account' => '',
538 'label_operation' => $label_operation . ' - ' . $depreciation_ref,
539 'debit' => $mt < 0 ? price(-$mt) : '',
540 'credit' => $mt >= 0 ? price($mt) : '',
541 );
542 } elseif ($type == 'bookkeeping') {
543 if ($account_infos['found']) {
544 $blocks[] = array(
545 'doc_date' => $depreciation_date,
546 'date_lim_reglement' => '',
547 'doc_ref' => $element_static->ref,
548 'date_creation' => $now,
549 'doc_type' => 'asset',
550 'fk_doc' => $element_static->id,
551 'fk_docdet' => $depreciation_id, // Useless, can be several lines that are source of this record to add
552 'thirdparty_code' => '',
553 'subledger_account' => '',
554 'subledger_label' => '',
555 'numero_compte' => $account,
556 'label_compte' => $account_infos['label'],
557 'label_operation' => $element_name_formatted_0 . ' - ' . $depreciation_ref,
558 'montant' => $mt,
559 'sens' => $mt < 0 ? 'D' : 'C',
560 'debit' => $mt < 0 ? -$mt : 0,
561 'credit' => $mt >= 0 ? $mt : 0,
562 'code_journal' => $journal,
563 'journal_label' => $journal_label_formatted,
564 'piece_num' => '',
565 'import_key' => '',
566 'fk_user_author' => $user->id,
567 'entity' => $conf->entity,
568 );
569 }
570 } else { // $type == 'csv'
571 $blocks[] = array(
572 $depreciation_date, // Date
573 $element_static->ref, // Piece
574 $account_infos['code_formatted_1'], // AccountAccounting
575 $element_name_formatted_0 . ' - ' . $depreciation_ref, // LabelOperation
576 $mt < 0 ? price(-$mt) : '', // Debit
577 $mt >= 0 ? price($mt) : '', // Credit
578 );
579 }
580 }
581 $element['blocks'][] = $blocks;
582 }
583
584 // Disposal line
585 //--------------------
586 if (!empty($pre_data_info['disposal'])) {
587 $disposal_date = $pre_data_info['disposal']['date'];
588
589 if ((!($date_start && $date_end) || ($date_start <= $disposal_date && $disposal_date <= $date_end)) &&
590 (!getDolGlobalString('ACCOUNTING_DATE_START_BINDING') || getDolGlobalInt('ACCOUNTING_DATE_START_BINDING') <= $disposal_date)
591 ) {
592 $disposal_amount = $pre_data_info['disposal']['amount'];
593 $disposal_subject_to_vat = $pre_data_info['disposal']['subject_to_vat'];
594 $disposal_date_formatted = dol_print_date($disposal_date, 'day');
595 $disposal_vat = getDolGlobalInt('ASSET_DISPOSAL_VAT') > 0 ? getDolGlobalInt('ASSET_DISPOSAL_VAT') : 20;
596
597 // Get accountancy codes
598 //---------------------------
599 require_once DOL_DOCUMENT_ROOT . '/asset/class/assetaccountancycodes.class.php';
600 $accountancy_codes = new AssetAccountancyCodes($this->db);
601 $result = $accountancy_codes->fetchAccountancyCodes($element_static->id);
602 if ($result < 0) {
603 $element['error'] = $accountancy_codes->errorsToString();
604 } else {
605 // Get last depreciation cumulative amount
606 $element_static->fetchDepreciationLines();
607 foreach ($element_static->depreciation_lines as $mode_key => $depreciation_lines) {
608 $accountancy_codes_list = $accountancy_codes->accountancy_codes[$mode_key];
609
610 if (!isset($accountancy_codes_list['value_asset_sold'])) {
611 continue;
612 }
613
614 $accountancy_code_value_asset_sold = empty($accountancy_codes_list['value_asset_sold']) ? 'NotDefined' : $accountancy_codes_list['value_asset_sold'];
615 $accountancy_code_depreciation_asset = empty($accountancy_codes_list['depreciation_asset']) ? 'NotDefined' : $accountancy_codes_list['depreciation_asset'];
616 $accountancy_code_asset = empty($accountancy_codes_list['asset']) ? 'NotDefined' : $accountancy_codes_list['asset'];
617 $accountancy_code_receivable_on_assignment = empty($accountancy_codes_list['receivable_on_assignment']) ? 'NotDefined' : $accountancy_codes_list['receivable_on_assignment'];
618 $accountancy_code_vat_collected = empty($accountancy_codes_list['vat_collected']) ? 'NotDefined' : $accountancy_codes_list['vat_collected'];
619 $accountancy_code_proceeds_from_sales = empty($accountancy_codes_list['proceeds_from_sales']) ? 'NotDefined' : $accountancy_codes_list['proceeds_from_sales'];
620
621 $last_cumulative_amount_ht = 0;
622 $depreciated_ids = array_keys($pre_data_info['depreciation']);
623 foreach ($depreciation_lines as $line) {
624 $last_cumulative_amount_ht = $line['cumulative_depreciation_ht'];
625 if (!in_array($line['id'], $depreciated_ids) && empty($line['bookkeeping']) && !empty($line['ref'])) {
626 break;
627 }
628 }
629
630 $lines = array();
631 $lines[0][$accountancy_code_value_asset_sold] = -((float) $element_static->acquisition_value_ht - $last_cumulative_amount_ht);
632 $lines[0][$accountancy_code_depreciation_asset] = - (float) $last_cumulative_amount_ht;
633 $lines[0][$accountancy_code_asset] = $element_static->acquisition_value_ht;
634
635 $disposal_amount_vat = $disposal_subject_to_vat ? (float) price2num($disposal_amount * $disposal_vat / 100, 'MT') : 0;
636 $lines[1][$accountancy_code_receivable_on_assignment] = -($disposal_amount + $disposal_amount_vat);
637 if ($disposal_subject_to_vat) {
638 $lines[1][$accountancy_code_vat_collected] = $disposal_amount_vat;
639 }
640 $lines[1][$accountancy_code_proceeds_from_sales] = $disposal_amount;
641
642 foreach ($lines as $lines_block) {
643 $blocks = array();
644 foreach ($lines_block as $account => $mt) {
645 $account_infos = $this->getAccountingAccountInfos($account);
646
647 if ($type == 'view') {
648 $account_to_show = length_accounta($account);
649 if (($account_to_show == "") || $account_to_show == 'NotDefined') {
650 $account_to_show = '<span class="error">' . $langs->trans("AssetInAccountNotDefined") . '</span>';
651 }
652
653 $blocks[] = array(
654 'date' => $disposal_date_formatted,
655 'piece' => $element_link,
656 'account_accounting' => $account_to_show,
657 'subledger_account' => '',
658 'label_operation' => $label_operation . ' - ' . $disposal_ref,
659 'debit' => $mt < 0 ? price(-$mt) : '',
660 'credit' => $mt >= 0 ? price($mt) : '',
661 );
662 } elseif ($type == 'bookkeeping') {
663 if ($account_infos['found']) {
664 $blocks[] = array(
665 'doc_date' => $disposal_date,
666 'date_lim_reglement' => '',
667 'doc_ref' => $element_static->ref,
668 'date_creation' => $now,
669 'doc_type' => 'asset',
670 'fk_doc' => $element_static->id,
671 'fk_docdet' => 0, // Useless, can be several lines that are source of this record to add
672 'thirdparty_code' => '',
673 'subledger_account' => '',
674 'subledger_label' => '',
675 'numero_compte' => $account,
676 'label_compte' => $account_infos['label'],
677 'label_operation' => $element_name_formatted_0 . ' - ' . $disposal_ref,
678 'montant' => $mt,
679 'sens' => $mt < 0 ? 'D' : 'C',
680 'debit' => $mt < 0 ? -$mt : 0,
681 'credit' => $mt >= 0 ? $mt : 0,
682 'code_journal' => $journal,
683 'journal_label' => $journal_label_formatted,
684 'piece_num' => '',
685 'import_key' => '',
686 'fk_user_author' => $user->id,
687 'entity' => $conf->entity,
688 );
689 }
690 } else { // $type == 'csv'
691 $blocks[] = array(
692 $disposal_date, // Date
693 $element_static->ref, // Piece
694 $account_infos['code_formatted_1'], // AccountAccounting
695 $element_name_formatted_0 . ' - ' . $disposal_ref, // LabelOperation
696 $mt < 0 ? price(-$mt) : '', // Debit
697 $mt >= 0 ? price($mt) : '', // Credit
698 );
699 }
700 }
701 $element['blocks'][] = $blocks;
702 }
703 }
704 }
705 }
706 }
707
708 $journal_data[(int) $pre_data_id] = $element;
709 }
710 unset($pre_data);
711
712 return $journal_data;
713 }
714
758 public function writeIntoBookkeeping(User $user, &$journal_data = array(), $max_nb_errors = 10)
759 {
760 global $conf, $langs, $hookmanager;
761 require_once DOL_DOCUMENT_ROOT . '/accountancy/class/bookkeeping.class.php';
762
763 $error = 0;
764
765 $hookmanager->initHooks(array('accountingjournaldao'));
766 $parameters = array('journal_data' => &$journal_data);
767 $reshook = $hookmanager->executeHooks('writeBookkeeping', $parameters, $this); // Note that $action and $object may have been
768 if ($reshook < 0) {
769 $this->error = $hookmanager->error;
770 $this->errors = $hookmanager->errors;
771 return -1;
772 } elseif (empty($reshook)) {
773 // Clean parameters
774 if (!is_array($journal_data)) {
775 $journal_data = array();
776 }
777
778 foreach ($journal_data as $element_id => $element) {
779 $error_for_line = 0;
780 $total_credit = 0;
781 $total_debit = 0;
782
783 $this->db->begin();
784
785 if ($element['error'] == 'somelinesarenotbound') {
786 $error++;
787 $error_for_line++;
788 $this->errors[] = $langs->trans('ErrorInvoiceContainsLinesNotYetBounded', $element['ref']);
789 }
790
791 if (!$error_for_line) {
792 foreach ($element['blocks'] as $lines) {
793 foreach ($lines as $line) {
794 $bookkeeping = new BookKeeping($this->db);
795 $bookkeeping->doc_date = (int) $line['doc_date'];
796 $bookkeeping->date_lim_reglement = (int) $line['date_lim_reglement'];
797 $bookkeeping->doc_ref = $line['doc_ref'];
798 $bookkeeping->date_creation = $line['date_creation']; // not used
799 $bookkeeping->doc_type = $line['doc_type'];
800 $bookkeeping->fk_doc = $line['fk_doc'];
801 $bookkeeping->fk_docdet = $line['fk_docdet'];
802 $bookkeeping->thirdparty_code = $line['thirdparty_code'];
803 $bookkeeping->subledger_account = $line['subledger_account'];
804 $bookkeeping->subledger_label = $line['subledger_label'];
805 $bookkeeping->numero_compte = $line['numero_compte'];
806 $bookkeeping->label_compte = $line['label_compte'];
807 $bookkeeping->label_operation = $line['label_operation'];
808 $bookkeeping->montant = $line['montant']; // Deprecated: sens/debit/credit (and deprecated amount...)
809 $bookkeeping->sens = $line['sens'];
810 $bookkeeping->debit = (float) $line['debit'];
811 $bookkeeping->credit = (float) $line['credit'];
812 $bookkeeping->code_journal = $line['code_journal'];
813 $bookkeeping->journal_label = $line['journal_label'];
814 $bookkeeping->piece_num = (int) $line['piece_num'];
815 $bookkeeping->import_key = $line['import_key'];
816 $bookkeeping->fk_user_author = $user->id;
817 $bookkeeping->entity = $conf->entity;
818
819 $total_debit += $bookkeeping->debit;
820 $total_credit += $bookkeeping->credit;
821
822 $result = $bookkeeping->create($user);
823 if ($result < 0) {
824 if ($bookkeeping->error == 'BookkeepingRecordAlreadyExists') { // Already exists
825 $error++;
826 $error_for_line++;
827 $journal_data[$element_id]['error'] = 'alreadyjournalized';
828 } else {
829 $error++;
830 $error_for_line++;
831 $journal_data[$element_id]['error'] = 'other';
832 $this->errors[] = $bookkeeping->errorsToString();
833 }
834 }
835 //
836 // if (!$error_for_line && isModEnabled('asset') && $this->nature == 1 && $bookkeeping->fk_doc > 0) {
837 // // Set last cumulative depreciation
838 // require_once DOL_DOCUMENT_ROOT . '/asset/class/asset.class.php';
839 // $asset = new Asset($this->db);
840 // $result = $asset->setLastCumulativeDepreciation($bookkeeping->fk_doc);
841 // if ($result < 0) {
842 // $error++;
843 // $error_for_line++;
844 // $journal_data[$element_id]['error'] = 'other';
845 // $this->errors[] = $asset->errorsToString();
846 // }
847 // }
848 }
849
850 if ($error_for_line) {
851 break;
852 }
853 }
854 }
855
856 // Protection against a bug on lines before
857 if (!$error_for_line && (price2num($total_debit, 'MT') != price2num($total_credit, 'MT'))) {
858 $error++;
859 $error_for_line++;
860 $journal_data[$element_id]['error'] = 'amountsnotbalanced';
861 $this->errors[] = 'Try to insert a non balanced transaction in book for ' . json_encode($element['blocks']) . '. Canceled. Surely a bug.';
862 }
863
864 if (!$error_for_line) {
865 $this->db->commit();
866 } else {
867 $this->db->rollback();
868
869 if ($error >= $max_nb_errors) {
870 $this->errors[] = $langs->trans("ErrorTooManyErrorsProcessStopped");
871 break; // Break in the foreach
872 }
873 }
874 }
875 }
876
877 return $error ? -$error : 1;
878 }
879
901 public function exportCsv(&$journal_data = array(), $search_date_end = 0, $sep = '')
902 {
903 global $conf, $langs, $hookmanager;
904
905 if (empty($sep)) {
906 $sep = getDolGlobalString('ACCOUNTING_EXPORT_SEPARATORCSV');
907 }
908 $out = '';
909
910 // Hook
911 $hookmanager->initHooks(array('accountingjournaldao'));
912 $parameters = array('journal_data' => &$journal_data, 'search_date_end' => &$search_date_end, 'sep' => &$sep, 'out' => &$out);
913 $reshook = $hookmanager->executeHooks('exportCsv', $parameters, $this); // Note that $action and $object may have been
914 if ($reshook < 0) {
915 $this->error = $hookmanager->error;
916 $this->errors = $hookmanager->errors;
917 return -1;
918 } elseif (empty($reshook)) {
919 // Clean parameters
920 $journal_data = is_array($journal_data) ? $journal_data : array();
921
922 // CSV header line
923 $header = array();
924 if ($this->nature == 4) {
925 $header = array(
926 $langs->transnoentitiesnoconv("BankId"),
927 $langs->transnoentitiesnoconv("Date"),
928 $langs->transnoentitiesnoconv("PaymentMode"),
929 $langs->transnoentitiesnoconv("AccountAccounting"),
930 $langs->transnoentitiesnoconv("LedgerAccount"),
931 $langs->transnoentitiesnoconv("SubledgerAccount"),
932 $langs->transnoentitiesnoconv("Label"),
933 $langs->transnoentitiesnoconv("AccountingDebit"),
934 $langs->transnoentitiesnoconv("AccountingCredit"),
935 $langs->transnoentitiesnoconv("Journal"),
936 $langs->transnoentitiesnoconv("Note"),
937 );
938 } elseif ($this->nature == 5) {
939 $header = array(
940 $langs->transnoentitiesnoconv("Date"),
941 $langs->transnoentitiesnoconv("Piece"),
942 $langs->transnoentitiesnoconv("AccountAccounting"),
943 $langs->transnoentitiesnoconv("LabelOperation"),
944 $langs->transnoentitiesnoconv("AccountingDebit"),
945 $langs->transnoentitiesnoconv("AccountingCredit"),
946 );
947 } elseif ($this->nature == 1) {
948 $header = array(
949 $langs->transnoentitiesnoconv("Date"),
950 $langs->transnoentitiesnoconv("Piece"),
951 $langs->transnoentitiesnoconv("AccountAccounting"),
952 $langs->transnoentitiesnoconv("LabelOperation"),
953 $langs->transnoentitiesnoconv("AccountingDebit"),
954 $langs->transnoentitiesnoconv("AccountingCredit"),
955 );
956 }
957
958 if (!empty($header)) {
959 $out .= '"' . implode('"' . $sep . '"', $header) . '"' . "\n";
960 }
961 foreach ($journal_data as $element_id => $element) {
962 foreach ($element['blocks'] as $lines) {
963 foreach ($lines as $line) {
964 $out .= '"' . implode('"' . $sep . '"', $line) . '"' . "\n";
965 }
966 }
967 }
968 }
969
970 return $out;
971 }
972
979 public function getAccountingAccountInfos($account)
980 {
981 if (!isset(self::$accounting_account_cached[$account])) {
982 require_once DOL_DOCUMENT_ROOT . '/core/lib/accounting.lib.php';
983 require_once DOL_DOCUMENT_ROOT . '/accountancy/class/accountingaccount.class.php';
984 $accountingaccount = new AccountingAccount($this->db);
985 $result = $accountingaccount->fetch(0, $account, true);
986 if ($result > 0) {
987 self::$accounting_account_cached[$account] = array(
988 'found' => true,
989 'label' => $accountingaccount->label,
990 'code_formatted_1' => length_accounta(html_entity_decode($account)),
991 'label_formatted_1' => mb_convert_encoding(dol_trunc($accountingaccount->label, 32), 'ISO-8859-1'),
992 'label_formatted_2' => dol_trunc($accountingaccount->label, 32),
993 );
994 } else {
995 self::$accounting_account_cached[$account] = array(
996 'found' => false,
997 'label' => '',
998 'code_formatted_1' => length_accounta(html_entity_decode($account)),
999 'label_formatted_1' => '',
1000 'label_formatted_2' => '',
1001 );
1002 }
1003 }
1004
1005 return self::$accounting_account_cached[$account];
1006 }
1007}
length_accounta($accounta)
Return Auxiliary accounting account of thirdparties with defined length.
$object ref
Definition info.php:90
Class to manage accounting accounts.
Class to manage accounting journals.
writeIntoBookkeeping(User $user, &$journal_data=array(), $max_nb_errors=10)
Write bookkeeping.
getData(User $user, $type='view', $date_start=null, $date_end=null, $in_bookkeeping='notyet')
Get journal data.
exportCsv(&$journal_data=array(), $search_date_end=0, $sep='')
Export journal CSV ISO and not UTF8 !
getNomUrl($withpicto=0, $withlabel=0, $nourl=0, $moretitle='', $notooltip=0)
Return clickable name (with picto eventually)
fetch($rowid=0, $journal_code=null)
Load an object from database.
LibType($nature, $mode=0)
Return type of an accounting journal.
getAccountingAccountInfos($account)
Get accounting account info.
create($user)
Create a new Accounting Journal.
getAssetData(User $user, $type='view', $date_start=null, $date_end=null, $in_bookkeeping='notyet')
Get asset data for various journal.
getLibType($mode=0)
Return the label of the status.
Class for AssetAccountancyCodes.
Class for Asset.
Class to manage Ledger (General Ledger and Subledger)
Parent class of all other business classes (invoices, contracts, proposals, orders,...
Class to manage Dolibarr users.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $allowothertags=array())
Show a picto called object_picto (generic function)
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
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.
global $conf
The following vars must be defined: $type2label $form $conf, $lang, The following vars may also be de...
Definition member.php:79