dolibarr 20.0.0
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' => $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] = -($element_static->acquisition_value_ht - $last_cumulative_amount_ht);
586 $lines[0][$accountancy_code_depreciation_asset] = -$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 $journal_data = is_array($journal_data) ? $journal_data : array();
729
730 foreach ($journal_data as $element_id => $element) {
731 $error_for_line = 0;
732 $total_credit = 0;
733 $total_debit = 0;
734
735 $this->db->begin();
736
737 if ($element['error'] == 'somelinesarenotbound') {
738 $error++;
739 $error_for_line++;
740 $this->errors[] = $langs->trans('ErrorInvoiceContainsLinesNotYetBounded', $element['ref']);
741 }
742
743 if (!$error_for_line) {
744 foreach ($element['blocks'] as $lines) {
745 foreach ($lines as $line) {
746 $bookkeeping = new BookKeeping($this->db);
747 $bookkeeping->doc_date = $line['doc_date'];
748 $bookkeeping->date_lim_reglement = $line['date_lim_reglement'];
749 $bookkeeping->doc_ref = $line['doc_ref'];
750 $bookkeeping->date_creation = $line['date_creation']; // not used
751 $bookkeeping->doc_type = $line['doc_type'];
752 $bookkeeping->fk_doc = $line['fk_doc'];
753 $bookkeeping->fk_docdet = $line['fk_docdet'];
754 $bookkeeping->thirdparty_code = $line['thirdparty_code'];
755 $bookkeeping->subledger_account = $line['subledger_account'];
756 $bookkeeping->subledger_label = $line['subledger_label'];
757 $bookkeeping->numero_compte = $line['numero_compte'];
758 $bookkeeping->label_compte = $line['label_compte'];
759 $bookkeeping->label_operation = $line['label_operation'];
760 $bookkeeping->montant = $line['montant'];
761 $bookkeeping->sens = $line['sens'];
762 $bookkeeping->debit = $line['debit'];
763 $bookkeeping->credit = $line['credit'];
764 $bookkeeping->code_journal = $line['code_journal'];
765 $bookkeeping->journal_label = $line['journal_label'];
766 $bookkeeping->piece_num = $line['piece_num'];
767 $bookkeeping->import_key = $line['import_key'];
768 $bookkeeping->fk_user_author = $user->id;
769 $bookkeeping->entity = $conf->entity;
770
771 $total_debit += $bookkeeping->debit;
772 $total_credit += $bookkeeping->credit;
773
774 $result = $bookkeeping->create($user);
775 if ($result < 0) {
776 if ($bookkeeping->error == 'BookkeepingRecordAlreadyExists') { // Already exists
777 $error++;
778 $error_for_line++;
779 $journal_data[$element_id]['error'] = 'alreadyjournalized';
780 } else {
781 $error++;
782 $error_for_line++;
783 $journal_data[$element_id]['error'] = 'other';
784 $this->errors[] = $bookkeeping->errorsToString();
785 }
786 }
787 //
788 // if (!$error_for_line && isModEnabled('asset') && $this->nature == 1 && $bookkeeping->fk_doc > 0) {
789 // // Set last cumulative depreciation
790 // require_once DOL_DOCUMENT_ROOT . '/asset/class/asset.class.php';
791 // $asset = new Asset($this->db);
792 // $result = $asset->setLastCumulativeDepreciation($bookkeeping->fk_doc);
793 // if ($result < 0) {
794 // $error++;
795 // $error_for_line++;
796 // $journal_data[$element_id]['error'] = 'other';
797 // $this->errors[] = $asset->errorsToString();
798 // }
799 // }
800 }
801
802 if ($error_for_line) {
803 break;
804 }
805 }
806 }
807
808 // Protection against a bug on lines before
809 if (!$error_for_line && (price2num($total_debit, 'MT') != price2num($total_credit, 'MT'))) {
810 $error++;
811 $error_for_line++;
812 $journal_data[$element_id]['error'] = 'amountsnotbalanced';
813 $this->errors[] = 'Try to insert a non balanced transaction in book for ' . $element['blocks'] . '. Canceled. Surely a bug.';
814 }
815
816 if (!$error_for_line) {
817 $this->db->commit();
818 } else {
819 $this->db->rollback();
820
821 if ($error >= $max_nb_errors) {
822 $this->errors[] = $langs->trans("ErrorTooManyErrorsProcessStopped");
823 break; // Break in the foreach
824 }
825 }
826 }
827 }
828
829 return $error ? -$error : 1;
830 }
831
853 public function exportCsv(&$journal_data = array(), $search_date_end = 0, $sep = '')
854 {
855 global $conf, $langs, $hookmanager;
856
857 if (empty($sep)) {
858 $sep = getDolGlobalString('ACCOUNTING_EXPORT_SEPARATORCSV');
859 }
860 $out = '';
861
862 // Hook
863 $hookmanager->initHooks(array('accountingjournaldao'));
864 $parameters = array('journal_data' => &$journal_data, 'search_date_end' => &$search_date_end, 'sep' => &$sep, 'out' => &$out);
865 $reshook = $hookmanager->executeHooks('exportCsv', $parameters, $this); // Note that $action and $object may have been
866 if ($reshook < 0) {
867 $this->error = $hookmanager->error;
868 $this->errors = $hookmanager->errors;
869 return -1;
870 } elseif (empty($reshook)) {
871 // Clean parameters
872 $journal_data = is_array($journal_data) ? $journal_data : array();
873
874 // CSV header line
875 $header = array();
876 if ($this->nature == 4) {
877 $header = array(
878 $langs->transnoentitiesnoconv("BankId"),
879 $langs->transnoentitiesnoconv("Date"),
880 $langs->transnoentitiesnoconv("PaymentMode"),
881 $langs->transnoentitiesnoconv("AccountAccounting"),
882 $langs->transnoentitiesnoconv("LedgerAccount"),
883 $langs->transnoentitiesnoconv("SubledgerAccount"),
884 $langs->transnoentitiesnoconv("Label"),
885 $langs->transnoentitiesnoconv("AccountingDebit"),
886 $langs->transnoentitiesnoconv("AccountingCredit"),
887 $langs->transnoentitiesnoconv("Journal"),
888 $langs->transnoentitiesnoconv("Note"),
889 );
890 } elseif ($this->nature == 5) {
891 $header = array(
892 $langs->transnoentitiesnoconv("Date"),
893 $langs->transnoentitiesnoconv("Piece"),
894 $langs->transnoentitiesnoconv("AccountAccounting"),
895 $langs->transnoentitiesnoconv("LabelOperation"),
896 $langs->transnoentitiesnoconv("AccountingDebit"),
897 $langs->transnoentitiesnoconv("AccountingCredit"),
898 );
899 } elseif ($this->nature == 1) {
900 $header = array(
901 $langs->transnoentitiesnoconv("Date"),
902 $langs->transnoentitiesnoconv("Piece"),
903 $langs->transnoentitiesnoconv("AccountAccounting"),
904 $langs->transnoentitiesnoconv("LabelOperation"),
905 $langs->transnoentitiesnoconv("AccountingDebit"),
906 $langs->transnoentitiesnoconv("AccountingCredit"),
907 );
908 }
909
910 if (!empty($header)) {
911 $out .= '"' . implode('"' . $sep . '"', $header) . '"' . "\n";
912 }
913 foreach ($journal_data as $element_id => $element) {
914 foreach ($element['blocks'] as $lines) {
915 foreach ($lines as $line) {
916 $out .= '"' . implode('"' . $sep . '"', $line) . '"' . "\n";
917 }
918 }
919 }
920 }
921
922 return $out;
923 }
924
931 public function getAccountingAccountInfos($account)
932 {
933 if (!isset(self::$accounting_account_cached[$account])) {
934 require_once DOL_DOCUMENT_ROOT . '/core/lib/accounting.lib.php';
935 require_once DOL_DOCUMENT_ROOT . '/accountancy/class/accountingaccount.class.php';
936 $accountingaccount = new AccountingAccount($this->db);
937 $result = $accountingaccount->fetch(null, $account, true);
938 if ($result > 0) {
939 self::$accounting_account_cached[$account] = array(
940 'found' => true,
941 'label' => $accountingaccount->label,
942 'code_formatted_1' => length_accounta(html_entity_decode($account)),
943 'label_formatted_1' => mb_convert_encoding(dol_trunc($accountingaccount->label, 32), 'ISO-8859-1'),
944 'label_formatted_2' => dol_trunc($accountingaccount->label, 32),
945 );
946 } else {
947 self::$accounting_account_cached[$account] = array(
948 'found' => false,
949 'label' => '',
950 'code_formatted_1' => length_accounta(html_entity_decode($account)),
951 'label_formatted_1' => '',
952 'label_formatted_2' => '',
953 );
954 }
955 }
956
957 return self::$accounting_account_cached[$account];
958 }
959}
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 infos.
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 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.
publicphonebutton2 phonegreen basiclayout basiclayout TotalHT VATCode TotalVAT TotalLT1 TotalLT2 TotalTTC TotalHT clearboth nowraponall TAKEPOS_SHOW_SUBPRICE right right right takeposterminal SELECT e rowid
Definition invoice.php:1991