dolibarr 21.0.0-alpha
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 MDW <mdeweerd@users.noreply.github.com>
4 * Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
30{
34 public $element = 'accounting_journal';
35
39 public $table_element = 'accounting_journal';
40
44 public $fk_element = '';
45
49 public $picto = 'generic';
50
54 public $rowid;
55
59 public $code;
60
64 public $label;
65
69 public $nature;
70
74 public $active;
75
79 public static $accounting_account_cached = array();
80
84 public static $nature_maps = array(
85 1 => 'variousoperations',
86 2 => 'sells',
87 3 => 'purchases',
88 4 => 'bank',
89 5 => 'expensereports',
90 8 => 'inventories',
91 9 => 'hasnew',
92 );
93
99 public function __construct($db)
100 {
101 $this->db = $db;
102
103 $this->ismultientitymanaged = 0;
104 }
105
113 public function fetch($rowid = 0, $journal_code = null)
114 {
115 global $conf;
116
117 if ($rowid || $journal_code) {
118 $sql = "SELECT rowid, code, label, nature, active";
119 $sql .= " FROM ".MAIN_DB_PREFIX."accounting_journal";
120 $sql .= " WHERE";
121 if ($rowid) {
122 $sql .= " rowid = ".((int) $rowid);
123 } elseif ($journal_code) {
124 $sql .= " code = '".$this->db->escape($journal_code)."'";
125 $sql .= " AND entity = ".$conf->entity;
126 }
127
128 dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
129 $result = $this->db->query($sql);
130 if ($result) {
131 $obj = $this->db->fetch_object($result);
132
133 if ($obj) {
134 $this->id = $obj->rowid;
135 $this->rowid = $obj->rowid;
136
137 $this->code = $obj->code;
138 $this->ref = $obj->code;
139 $this->label = $obj->label;
140 $this->nature = $obj->nature;
141 $this->active = $obj->active;
142
143 return $this->id;
144 } else {
145 return 0;
146 }
147 } else {
148 $this->error = "Error ".$this->db->lasterror();
149 $this->errors[] = "Error ".$this->db->lasterror();
150 }
151 }
152 return -1;
153 }
154
165 public function getNomUrl($withpicto = 0, $withlabel = 0, $nourl = 0, $moretitle = '', $notooltip = 0)
166 {
167 global $langs, $conf, $hookmanager;
168
169 if (!empty($conf->dol_no_mouse_hover)) {
170 $notooltip = 1; // Force disable tooltips
171 }
172
173 $result = '';
174
175 $url = DOL_URL_ROOT.'/accountancy/admin/journals_list.php?id=35';
176
177 $label = '<u>'.$langs->trans("ShowAccountingJournal").'</u>';
178 if (!empty($this->code)) {
179 $label .= '<br><b>'.$langs->trans('Code').':</b> '.$this->code;
180 }
181 if (!empty($this->label)) {
182 $label .= '<br><b>'.$langs->trans('Label').':</b> '.$langs->transnoentities($this->label);
183 }
184 if ($moretitle) {
185 $label .= ' - '.$moretitle;
186 }
187
188 $linkclose = '';
189 if (empty($notooltip)) {
190 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
191 $label = $langs->trans("ShowAccountingJournal");
192 $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
193 }
194 $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
195 $linkclose .= ' class="classfortooltip"';
196 }
197
198 $linkstart = '<a href="'.$url.'"';
199 $linkstart .= $linkclose.'>';
200 $linkend = '</a>';
201
202 if ($nourl) {
203 $linkstart = '';
204 $linkclose = '';
205 $linkend = '';
206 }
207
208 $label_link = $this->code;
209 if ($withlabel == 1 && !empty($this->label)) {
210 $label_link .= ' - '.($nourl ? '<span class="opacitymedium">' : '').$langs->transnoentities($this->label).($nourl ? '</span>' : '');
211 }
212 if ($withlabel == 2 && !empty($this->nature)) {
213 $key = $langs->trans("AccountingJournalType".$this->nature);
214 $transferlabel = ($this->nature && $key != "AccountingJournalType".strtoupper($langs->trans($this->nature)) ? $key : $this->label);
215 $label_link .= ' - '.($nourl ? '<span class="opacitymedium">' : '').$transferlabel.($nourl ? '</span>' : '');
216 }
217
218 $result .= $linkstart;
219 if ($withpicto) {
220 $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);
221 }
222 if ($withpicto != 2) {
223 $result .= $label_link;
224 }
225 $result .= $linkend;
226
227 global $action;
228 $hookmanager->initHooks(array('accountingjournaldao'));
229 $parameters = array('id' => $this->id, 'getnomurl' => &$result);
230 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
231 if ($reshook > 0) {
232 $result = $hookmanager->resPrint;
233 } else {
234 $result .= $hookmanager->resPrint;
235 }
236 return $result;
237 }
238
245 public function getLibType($mode = 0)
246 {
247 return $this->LibType($this->nature, $mode);
248 }
249
250 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
258 public function LibType($nature, $mode = 0)
259 {
260 // phpcs:enable
261 global $langs;
262
263 $langs->loadLangs(array("accountancy"));
264
265 if ($mode == 0) {
266 $prefix = '';
267 if ($nature == 9) {
268 return $langs->trans('AccountingJournalType9');
269 } elseif ($nature == 5) {
270 return $langs->trans('AccountingJournalType5');
271 } elseif ($nature == 4) {
272 return $langs->trans('AccountingJournalType4');
273 } elseif ($nature == 3) {
274 return $langs->trans('AccountingJournalType3');
275 } elseif ($nature == 2) {
276 return $langs->trans('AccountingJournalType2');
277 } elseif ($nature == 1) {
278 return $langs->trans('AccountingJournalType1');
279 }
280 } elseif ($mode == 1) {
281 if ($nature == 9) {
282 return $langs->trans('AccountingJournalType9');
283 } elseif ($nature == 5) {
284 return $langs->trans('AccountingJournalType5');
285 } elseif ($nature == 4) {
286 return $langs->trans('AccountingJournalType4');
287 } elseif ($nature == 3) {
288 return $langs->trans('AccountingJournalType3');
289 } elseif ($nature == 2) {
290 return $langs->trans('AccountingJournalType2');
291 } elseif ($nature == 1) {
292 return $langs->trans('AccountingJournalType1');
293 }
294 }
295 return "";
296 }
297
298
309 public function getData(User $user, $type = 'view', $date_start = null, $date_end = null, $in_bookkeeping = 'notyet')
310 {
311 global $hookmanager;
312
313 // Clean parameters
314 if (empty($type)) {
315 $type = 'view';
316 }
317 if (empty($in_bookkeeping)) {
318 $in_bookkeeping = 'notyet';
319 }
320
321 $data = array();
322
323 $hookmanager->initHooks(array('accountingjournaldao'));
324 $parameters = array('data' => &$data, 'user' => $user, 'type' => $type, 'date_start' => $date_start, 'date_end' => $date_end, 'in_bookkeeping' => $in_bookkeeping);
325 $reshook = $hookmanager->executeHooks('getData', $parameters, $this); // Note that $action and $object may have been
326 if ($reshook < 0) {
327 $this->error = $hookmanager->error;
328 $this->errors = $hookmanager->errors;
329 return -1;
330 } elseif (empty($reshook)) {
331 switch ($this->nature) {
332 case 1: // Various Journal
333 $data = $this->getAssetData($user, $type, $date_start, $date_end, $in_bookkeeping);
334 break;
335 // case 2: // Sells Journal
336 // case 3: // Purchases Journal
337 // case 4: // Bank Journal
338 // case 5: // Expense reports Journal
339 // case 8: // Inventory Journal
340 // case 9: // hasnew Journal
341 }
342 }
343
344 return $data;
345 }
346
357 public function getAssetData(User $user, $type = 'view', $date_start = null, $date_end = null, $in_bookkeeping = 'notyet')
358 {
359 global $conf, $langs;
360
361 if (!isModEnabled('asset')) {
362 return array();
363 }
364
365 require_once DOL_DOCUMENT_ROOT . '/core/lib/accounting.lib.php';
366 require_once DOL_DOCUMENT_ROOT . '/asset/class/asset.class.php';
367 require_once DOL_DOCUMENT_ROOT . '/asset/class/assetaccountancycodes.class.php';
368 require_once DOL_DOCUMENT_ROOT . '/asset/class/assetdepreciationoptions.class.php';
369
370 $langs->loadLangs(array("assets"));
371
372 // Clean parameters
373 if (empty($type)) {
374 $type = 'view';
375 }
376 if (empty($in_bookkeeping)) {
377 $in_bookkeeping = 'notyet';
378 }
379
380 $sql = "";
381 $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";
382 $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";
383 $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";
384 $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation as ad";
385 $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "asset as a ON a.rowid = ad.fk_asset";
386 $sql .= " WHERE a.entity IN (" . getEntity('asset', 0) . ')'; // We don't share object for accountancy, we use source object sharing
387 if ($in_bookkeeping == 'already') {
388 $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')";
389 } elseif ($in_bookkeeping == 'notyet') {
390 $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')";
391 }
392 $sql .= " AND ad.ref != ''"; // not reversal lines
393 if ($date_start && $date_end) {
394 $sql .= " AND ad.depreciation_date >= '" . $this->db->idate($date_start) . "' AND ad.depreciation_date <= '" . $this->db->idate($date_end) . "'";
395 }
396 // Define begin binding date
397 if (getDolGlobalString('ACCOUNTING_DATE_START_BINDING')) {
398 $sql .= " AND ad.depreciation_date >= '" . $this->db->idate(getDolGlobalString('ACCOUNTING_DATE_START_BINDING')) . "'";
399 }
400 $sql .= " ORDER BY ad.depreciation_date";
401
402 dol_syslog(__METHOD__, LOG_DEBUG);
403 $resql = $this->db->query($sql);
404 if (!$resql) {
405 $this->errors[] = $this->db->lasterror();
406 return -1;
407 }
408
409 $pre_data = array(
410 'elements' => array(),
411 );
412 while ($obj = $this->db->fetch_object($resql)) {
413 if (!isset($pre_data['elements'][$obj->rowid])) {
414 $pre_data['elements'][$obj->rowid] = array(
415 'ref' => $obj->asset_ref,
416 'label' => $obj->asset_label,
417 'acquisition_value_ht' => $obj->asset_acquisition_value_ht,
418 'depreciation' => array(),
419 );
420
421 // Disposal infos
422 if (isset($obj->asset_disposal_date)) {
423 $pre_data['elements'][$obj->rowid]['disposal'] = array(
424 'date' => $this->db->jdate($obj->asset_disposal_date),
425 'amount' => $obj->asset_disposal_amount_ht,
426 'subject_to_vat' => !empty($obj->asset_disposal_subject_to_vat),
427 );
428 }
429 }
430
431 $compta_debit = empty($obj->accountancy_code_debit) ? 'NotDefined' : $obj->accountancy_code_debit;
432 $compta_credit = empty($obj->accountancy_code_credit) ? 'NotDefined' : $obj->accountancy_code_credit;
433
434 $pre_data['elements'][$obj->rowid]['depreciation'][$obj->depreciation_id] = array(
435 'date' => $this->db->jdate($obj->depreciation_date),
436 'ref' => $obj->depreciation_ref,
437 'lines' => array(
438 $compta_debit => -$obj->depreciation_ht,
439 $compta_credit => $obj->depreciation_ht,
440 ),
441 );
442 }
443
444 $disposal_ref = $langs->transnoentitiesnoconv('AssetDisposal');
445 $journal = $this->code;
446 $journal_label = $this->label;
447 $journal_label_formatted = $langs->transnoentities($journal_label);
448 $now = dol_now();
449
450 $element_static = new Asset($this->db);
451
452 $journal_data = array();
453 foreach ($pre_data['elements'] as $pre_data_id => $pre_data_info) {
454 $element_static->id = $pre_data_id;
455 $element_static->ref = (string) $pre_data_info["ref"];
456 $element_static->label = (string) $pre_data_info["label"];
457 $element_static->acquisition_value_ht = $pre_data_info["acquisition_value_ht"];
458 $element_link = $element_static->getNomUrl(1, 'with_label');
459
460 $element_name_formatted_0 = dol_trunc($element_static->label, 16);
461 $label_operation = $element_static->getNomUrl(0, 'label', 16);
462
463 $element = array(
464 'ref' => dol_trunc($element_static->ref, 16, 'right', 'UTF-8', 1),
465 'error' => array_key_exists('error', $pre_data_info) ? $pre_data_info['error'] : '',
466 'blocks' => array(),
467 );
468
469 // Depreciation lines
470 //--------------------
471 foreach ($pre_data_info['depreciation'] as $depreciation_id => $line) {
472 $depreciation_ref = $line["ref"];
473 $depreciation_date = $line["date"];
474 $depreciation_date_formatted = dol_print_date($depreciation_date, 'day');
475
476 // lines
477 $blocks = array();
478 foreach ($line['lines'] as $account => $mt) {
479 $account_infos = $this->getAccountingAccountInfos($account);
480
481 if ($type == 'view') {
482 $account_to_show = length_accounta($account);
483 if (($account_to_show == "") || $account_to_show == 'NotDefined') {
484 $account_to_show = '<span class="error">' . $langs->trans("AssetInAccountNotDefined") . '</span>';
485 }
486
487 $blocks[] = array(
488 'date' => $depreciation_date_formatted,
489 'piece' => $element_link,
490 'account_accounting' => $account_to_show,
491 'subledger_account' => '',
492 'label_operation' => $label_operation . ' - ' . $depreciation_ref,
493 'debit' => $mt < 0 ? price(-$mt) : '',
494 'credit' => $mt >= 0 ? price($mt) : '',
495 );
496 } elseif ($type == 'bookkeeping') {
497 if ($account_infos['found']) {
498 $blocks[] = array(
499 'doc_date' => $depreciation_date,
500 'date_lim_reglement' => '',
501 'doc_ref' => $element_static->ref,
502 'date_creation' => $now,
503 'doc_type' => 'asset',
504 'fk_doc' => $element_static->id,
505 'fk_docdet' => $depreciation_id, // Useless, can be several lines that are source of this record to add
506 'thirdparty_code' => '',
507 'subledger_account' => '',
508 'subledger_label' => '',
509 'numero_compte' => $account,
510 'label_compte' => $account_infos['label'],
511 'label_operation' => $element_name_formatted_0 . ' - ' . $depreciation_ref,
512 'montant' => $mt,
513 'sens' => $mt < 0 ? 'D' : 'C',
514 'debit' => $mt < 0 ? -$mt : 0,
515 'credit' => $mt >= 0 ? $mt : 0,
516 'code_journal' => $journal,
517 'journal_label' => $journal_label_formatted,
518 'piece_num' => '',
519 'import_key' => '',
520 'fk_user_author' => $user->id,
521 'entity' => $conf->entity,
522 );
523 }
524 } else { // $type == 'csv'
525 $blocks[] = array(
526 $depreciation_date, // Date
527 $element_static->ref, // Piece
528 $account_infos['code_formatted_1'], // AccountAccounting
529 $element_name_formatted_0 . ' - ' . $depreciation_ref, // LabelOperation
530 $mt < 0 ? price(-$mt) : '', // Debit
531 $mt >= 0 ? price($mt) : '', // Credit
532 );
533 }
534 }
535 $element['blocks'][] = $blocks;
536 }
537
538 // Disposal line
539 //--------------------
540 if (!empty($pre_data_info['disposal'])) {
541 $disposal_date = $pre_data_info['disposal']['date'];
542
543 if ((!($date_start && $date_end) || ($date_start <= $disposal_date && $disposal_date <= $date_end)) &&
544 (!getDolGlobalString('ACCOUNTING_DATE_START_BINDING') || getDolGlobalInt('ACCOUNTING_DATE_START_BINDING') <= $disposal_date)
545 ) {
546 $disposal_amount = $pre_data_info['disposal']['amount'];
547 $disposal_subject_to_vat = $pre_data_info['disposal']['subject_to_vat'];
548 $disposal_date_formatted = dol_print_date($disposal_date, 'day');
549 $disposal_vat = getDolGlobalInt('ASSET_DISPOSAL_VAT') > 0 ? getDolGlobalInt('ASSET_DISPOSAL_VAT') : 20;
550
551 // Get accountancy codes
552 //---------------------------
553 require_once DOL_DOCUMENT_ROOT . '/asset/class/assetaccountancycodes.class.php';
554 $accountancy_codes = new AssetAccountancyCodes($this->db);
555 $result = $accountancy_codes->fetchAccountancyCodes($element_static->id);
556 if ($result < 0) {
557 $element['error'] = $accountancy_codes->errorsToString();
558 } else {
559 // Get last depreciation cumulative amount
560 $element_static->fetchDepreciationLines();
561 foreach ($element_static->depreciation_lines as $mode_key => $depreciation_lines) {
562 $accountancy_codes_list = $accountancy_codes->accountancy_codes[$mode_key];
563
564 if (!isset($accountancy_codes_list['value_asset_sold'])) {
565 continue;
566 }
567
568 $accountancy_code_value_asset_sold = empty($accountancy_codes_list['value_asset_sold']) ? 'NotDefined' : $accountancy_codes_list['value_asset_sold'];
569 $accountancy_code_depreciation_asset = empty($accountancy_codes_list['depreciation_asset']) ? 'NotDefined' : $accountancy_codes_list['depreciation_asset'];
570 $accountancy_code_asset = empty($accountancy_codes_list['asset']) ? 'NotDefined' : $accountancy_codes_list['asset'];
571 $accountancy_code_receivable_on_assignment = empty($accountancy_codes_list['receivable_on_assignment']) ? 'NotDefined' : $accountancy_codes_list['receivable_on_assignment'];
572 $accountancy_code_vat_collected = empty($accountancy_codes_list['vat_collected']) ? 'NotDefined' : $accountancy_codes_list['vat_collected'];
573 $accountancy_code_proceeds_from_sales = empty($accountancy_codes_list['proceeds_from_sales']) ? 'NotDefined' : $accountancy_codes_list['proceeds_from_sales'];
574
575 $last_cumulative_amount_ht = 0;
576 $depreciated_ids = array_keys($pre_data_info['depreciation']);
577 foreach ($depreciation_lines as $line) {
578 $last_cumulative_amount_ht = $line['cumulative_depreciation_ht'];
579 if (!in_array($line['id'], $depreciated_ids) && empty($line['bookkeeping']) && !empty($line['ref'])) {
580 break;
581 }
582 }
583
584 $lines = array();
585 $lines[0][$accountancy_code_value_asset_sold] = -((float) $element_static->acquisition_value_ht - $last_cumulative_amount_ht);
586 $lines[0][$accountancy_code_depreciation_asset] = - (float) $last_cumulative_amount_ht;
587 $lines[0][$accountancy_code_asset] = $element_static->acquisition_value_ht;
588
589 $disposal_amount_vat = $disposal_subject_to_vat ? (float) price2num($disposal_amount * $disposal_vat / 100, 'MT') : 0;
590 $lines[1][$accountancy_code_receivable_on_assignment] = -($disposal_amount + $disposal_amount_vat);
591 if ($disposal_subject_to_vat) {
592 $lines[1][$accountancy_code_vat_collected] = $disposal_amount_vat;
593 }
594 $lines[1][$accountancy_code_proceeds_from_sales] = $disposal_amount;
595
596 foreach ($lines as $lines_block) {
597 $blocks = array();
598 foreach ($lines_block as $account => $mt) {
599 $account_infos = $this->getAccountingAccountInfos($account);
600
601 if ($type == 'view') {
602 $account_to_show = length_accounta($account);
603 if (($account_to_show == "") || $account_to_show == 'NotDefined') {
604 $account_to_show = '<span class="error">' . $langs->trans("AssetInAccountNotDefined") . '</span>';
605 }
606
607 $blocks[] = array(
608 'date' => $disposal_date_formatted,
609 'piece' => $element_link,
610 'account_accounting' => $account_to_show,
611 'subledger_account' => '',
612 'label_operation' => $label_operation . ' - ' . $disposal_ref,
613 'debit' => $mt < 0 ? price(-$mt) : '',
614 'credit' => $mt >= 0 ? price($mt) : '',
615 );
616 } elseif ($type == 'bookkeeping') {
617 if ($account_infos['found']) {
618 $blocks[] = array(
619 'doc_date' => $disposal_date,
620 'date_lim_reglement' => '',
621 'doc_ref' => $element_static->ref,
622 'date_creation' => $now,
623 'doc_type' => 'asset',
624 'fk_doc' => $element_static->id,
625 'fk_docdet' => 0, // Useless, can be several lines that are source of this record to add
626 'thirdparty_code' => '',
627 'subledger_account' => '',
628 'subledger_label' => '',
629 'numero_compte' => $account,
630 'label_compte' => $account_infos['label'],
631 'label_operation' => $element_name_formatted_0 . ' - ' . $disposal_ref,
632 'montant' => $mt,
633 'sens' => $mt < 0 ? 'D' : 'C',
634 'debit' => $mt < 0 ? -$mt : 0,
635 'credit' => $mt >= 0 ? $mt : 0,
636 'code_journal' => $journal,
637 'journal_label' => $journal_label_formatted,
638 'piece_num' => '',
639 'import_key' => '',
640 'fk_user_author' => $user->id,
641 'entity' => $conf->entity,
642 );
643 }
644 } else { // $type == 'csv'
645 $blocks[] = array(
646 $disposal_date, // Date
647 $element_static->ref, // Piece
648 $account_infos['code_formatted_1'], // AccountAccounting
649 $element_name_formatted_0 . ' - ' . $disposal_ref, // LabelOperation
650 $mt < 0 ? price(-$mt) : '', // Debit
651 $mt >= 0 ? price($mt) : '', // Credit
652 );
653 }
654 }
655 $element['blocks'][] = $blocks;
656 }
657 }
658 }
659 }
660 }
661
662 $journal_data[(int) $pre_data_id] = $element;
663 }
664 unset($pre_data);
665
666 return $journal_data;
667 }
668
712 public function writeIntoBookkeeping(User $user, &$journal_data = array(), $max_nb_errors = 10)
713 {
714 global $conf, $langs, $hookmanager;
715 require_once DOL_DOCUMENT_ROOT . '/accountancy/class/bookkeeping.class.php';
716
717 $error = 0;
718
719 $hookmanager->initHooks(array('accountingjournaldao'));
720 $parameters = array('journal_data' => &$journal_data);
721 $reshook = $hookmanager->executeHooks('writeBookkeeping', $parameters, $this); // Note that $action and $object may have been
722 if ($reshook < 0) {
723 $this->error = $hookmanager->error;
724 $this->errors = $hookmanager->errors;
725 return -1;
726 } elseif (empty($reshook)) {
727 // Clean parameters
728 if (!is_array($journal_data)) {
729 $journal_data = array();
730 }
731
732 foreach ($journal_data as $element_id => $element) {
733 $error_for_line = 0;
734 $total_credit = 0;
735 $total_debit = 0;
736
737 $this->db->begin();
738
739 if ($element['error'] == 'somelinesarenotbound') {
740 $error++;
741 $error_for_line++;
742 $this->errors[] = $langs->trans('ErrorInvoiceContainsLinesNotYetBounded', $element['ref']);
743 }
744
745 if (!$error_for_line) {
746 foreach ($element['blocks'] as $lines) {
747 foreach ($lines as $line) {
748 $bookkeeping = new BookKeeping($this->db);
749 $bookkeeping->doc_date = (int) $line['doc_date'];
750 $bookkeeping->date_lim_reglement = (int) $line['date_lim_reglement'];
751 $bookkeeping->doc_ref = $line['doc_ref'];
752 $bookkeeping->date_creation = $line['date_creation']; // not used
753 $bookkeeping->doc_type = $line['doc_type'];
754 $bookkeeping->fk_doc = $line['fk_doc'];
755 $bookkeeping->fk_docdet = $line['fk_docdet'];
756 $bookkeeping->thirdparty_code = $line['thirdparty_code'];
757 $bookkeeping->subledger_account = $line['subledger_account'];
758 $bookkeeping->subledger_label = $line['subledger_label'];
759 $bookkeeping->numero_compte = $line['numero_compte'];
760 $bookkeeping->label_compte = $line['label_compte'];
761 $bookkeeping->label_operation = $line['label_operation'];
762 $bookkeeping->montant = $line['montant']; // Deprecated: sens/debit/credit (and deprecated amount...)
763 $bookkeeping->sens = $line['sens'];
764 $bookkeeping->debit = (float) $line['debit'];
765 $bookkeeping->credit = (float) $line['credit'];
766 $bookkeeping->code_journal = $line['code_journal'];
767 $bookkeeping->journal_label = $line['journal_label'];
768 $bookkeeping->piece_num = (int) $line['piece_num'];
769 $bookkeeping->import_key = $line['import_key'];
770 $bookkeeping->fk_user_author = $user->id;
771 $bookkeeping->entity = $conf->entity;
772
773 $total_debit += $bookkeeping->debit;
774 $total_credit += $bookkeeping->credit;
775
776 $result = $bookkeeping->create($user);
777 if ($result < 0) {
778 if ($bookkeeping->error == 'BookkeepingRecordAlreadyExists') { // Already exists
779 $error++;
780 $error_for_line++;
781 $journal_data[$element_id]['error'] = 'alreadyjournalized';
782 } else {
783 $error++;
784 $error_for_line++;
785 $journal_data[$element_id]['error'] = 'other';
786 $this->errors[] = $bookkeeping->errorsToString();
787 }
788 }
789 //
790 // if (!$error_for_line && isModEnabled('asset') && $this->nature == 1 && $bookkeeping->fk_doc > 0) {
791 // // Set last cumulative depreciation
792 // require_once DOL_DOCUMENT_ROOT . '/asset/class/asset.class.php';
793 // $asset = new Asset($this->db);
794 // $result = $asset->setLastCumulativeDepreciation($bookkeeping->fk_doc);
795 // if ($result < 0) {
796 // $error++;
797 // $error_for_line++;
798 // $journal_data[$element_id]['error'] = 'other';
799 // $this->errors[] = $asset->errorsToString();
800 // }
801 // }
802 }
803
804 if ($error_for_line) {
805 break;
806 }
807 }
808 }
809
810 // Protection against a bug on lines before
811 if (!$error_for_line && (price2num($total_debit, 'MT') != price2num($total_credit, 'MT'))) {
812 $error++;
813 $error_for_line++;
814 $journal_data[$element_id]['error'] = 'amountsnotbalanced';
815 $this->errors[] = 'Try to insert a non balanced transaction in book for ' . json_encode($element['blocks']) . '. Canceled. Surely a bug.';
816 }
817
818 if (!$error_for_line) {
819 $this->db->commit();
820 } else {
821 $this->db->rollback();
822
823 if ($error >= $max_nb_errors) {
824 $this->errors[] = $langs->trans("ErrorTooManyErrorsProcessStopped");
825 break; // Break in the foreach
826 }
827 }
828 }
829 }
830
831 return $error ? -$error : 1;
832 }
833
855 public function exportCsv(&$journal_data = array(), $search_date_end = 0, $sep = '')
856 {
857 global $conf, $langs, $hookmanager;
858
859 if (empty($sep)) {
860 $sep = getDolGlobalString('ACCOUNTING_EXPORT_SEPARATORCSV');
861 }
862 $out = '';
863
864 // Hook
865 $hookmanager->initHooks(array('accountingjournaldao'));
866 $parameters = array('journal_data' => &$journal_data, 'search_date_end' => &$search_date_end, 'sep' => &$sep, 'out' => &$out);
867 $reshook = $hookmanager->executeHooks('exportCsv', $parameters, $this); // Note that $action and $object may have been
868 if ($reshook < 0) {
869 $this->error = $hookmanager->error;
870 $this->errors = $hookmanager->errors;
871 return -1;
872 } elseif (empty($reshook)) {
873 // Clean parameters
874 $journal_data = is_array($journal_data) ? $journal_data : array();
875
876 // CSV header line
877 $header = array();
878 if ($this->nature == 4) {
879 $header = array(
880 $langs->transnoentitiesnoconv("BankId"),
881 $langs->transnoentitiesnoconv("Date"),
882 $langs->transnoentitiesnoconv("PaymentMode"),
883 $langs->transnoentitiesnoconv("AccountAccounting"),
884 $langs->transnoentitiesnoconv("LedgerAccount"),
885 $langs->transnoentitiesnoconv("SubledgerAccount"),
886 $langs->transnoentitiesnoconv("Label"),
887 $langs->transnoentitiesnoconv("AccountingDebit"),
888 $langs->transnoentitiesnoconv("AccountingCredit"),
889 $langs->transnoentitiesnoconv("Journal"),
890 $langs->transnoentitiesnoconv("Note"),
891 );
892 } elseif ($this->nature == 5) {
893 $header = array(
894 $langs->transnoentitiesnoconv("Date"),
895 $langs->transnoentitiesnoconv("Piece"),
896 $langs->transnoentitiesnoconv("AccountAccounting"),
897 $langs->transnoentitiesnoconv("LabelOperation"),
898 $langs->transnoentitiesnoconv("AccountingDebit"),
899 $langs->transnoentitiesnoconv("AccountingCredit"),
900 );
901 } elseif ($this->nature == 1) {
902 $header = array(
903 $langs->transnoentitiesnoconv("Date"),
904 $langs->transnoentitiesnoconv("Piece"),
905 $langs->transnoentitiesnoconv("AccountAccounting"),
906 $langs->transnoentitiesnoconv("LabelOperation"),
907 $langs->transnoentitiesnoconv("AccountingDebit"),
908 $langs->transnoentitiesnoconv("AccountingCredit"),
909 );
910 }
911
912 if (!empty($header)) {
913 $out .= '"' . implode('"' . $sep . '"', $header) . '"' . "\n";
914 }
915 foreach ($journal_data as $element_id => $element) {
916 foreach ($element['blocks'] as $lines) {
917 foreach ($lines as $line) {
918 $out .= '"' . implode('"' . $sep . '"', $line) . '"' . "\n";
919 }
920 }
921 }
922 }
923
924 return $out;
925 }
926
933 public function getAccountingAccountInfos($account)
934 {
935 if (!isset(self::$accounting_account_cached[$account])) {
936 require_once DOL_DOCUMENT_ROOT . '/core/lib/accounting.lib.php';
937 require_once DOL_DOCUMENT_ROOT . '/accountancy/class/accountingaccount.class.php';
938 $accountingaccount = new AccountingAccount($this->db);
939 $result = $accountingaccount->fetch(0, $account, true);
940 if ($result > 0) {
941 self::$accounting_account_cached[$account] = array(
942 'found' => true,
943 'label' => $accountingaccount->label,
944 'code_formatted_1' => length_accounta(html_entity_decode($account)),
945 'label_formatted_1' => mb_convert_encoding(dol_trunc($accountingaccount->label, 32), 'ISO-8859-1'),
946 'label_formatted_2' => dol_trunc($accountingaccount->label, 32),
947 );
948 } else {
949 self::$accounting_account_cached[$account] = array(
950 'found' => false,
951 'label' => '',
952 'code_formatted_1' => length_accounta(html_entity_decode($account)),
953 'label_formatted_1' => '',
954 'label_formatted_2' => '',
955 );
956 }
957 }
958
959 return self::$accounting_account_cached[$account];
960 }
961}
length_accounta($accounta)
Return Auxiliary accounting account of thirdparties with defined length.
$object ref
Definition info.php:79
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.
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.
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 '.
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.