dolibarr  x.y.z
accountingjournal.class.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2017-2022 OpenDSI <support@open-dsi.fr>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
28 {
32  public $element = 'accounting_journal';
33 
37  public $table_element = 'accounting_journal';
38 
42  public $fk_element = '';
43 
47  public $ismultientitymanaged = 0;
48 
52  public $picto = 'generic';
53 
57  public $rowid;
58 
62  public $code;
63 
67  public $label;
68 
72  public $nature;
73 
77  public $active;
78 
82  public $lines;
83 
87  static public $accounting_account_cached = array();
88 
92  static public $nature_maps = array(
93  1 => 'variousoperations',
94  2 => 'sells',
95  3 => 'purchases',
96  4 => 'bank',
97  5 => 'expensereports',
98  8 => 'inventories',
99  9 => 'hasnew',
100  );
101 
107  public function __construct($db)
108  {
109  $this->db = $db;
110  }
111 
119  public function fetch($rowid = null, $journal_code = null)
120  {
121  global $conf;
122 
123  if ($rowid || $journal_code) {
124  $sql = "SELECT rowid, code, label, nature, active";
125  $sql .= " FROM ".MAIN_DB_PREFIX."accounting_journal";
126  $sql .= " WHERE";
127  if ($rowid) {
128  $sql .= " rowid = ".((int) $rowid);
129  } elseif ($journal_code) {
130  $sql .= " code = '".$this->db->escape($journal_code)."'";
131  $sql .= " AND entity = ".$conf->entity;
132  }
133 
134  dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
135  $result = $this->db->query($sql);
136  if ($result) {
137  $obj = $this->db->fetch_object($result);
138 
139  if ($obj) {
140  $this->id = $obj->rowid;
141  $this->rowid = $obj->rowid;
142 
143  $this->code = $obj->code;
144  $this->ref = $obj->code;
145  $this->label = $obj->label;
146  $this->nature = $obj->nature;
147  $this->active = $obj->active;
148 
149  return $this->id;
150  } else {
151  return 0;
152  }
153  } else {
154  $this->error = "Error ".$this->db->lasterror();
155  $this->errors[] = "Error ".$this->db->lasterror();
156  }
157  }
158  return -1;
159  }
160 
173  public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND')
174  {
175  $sql = "SELECT rowid, code, label, nature, active";
176  $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
177  // Manage filter
178  $sqlwhere = array();
179  if (count($filter) > 0) {
180  foreach ($filter as $key => $value) {
181  if ($key == 't.code' || $key == 't.label' || $key == 't.nature') {
182  $sqlwhere[] = $key.'\''.$this->db->escape($value).'\'';
183  } elseif ($key == 't.rowid' || $key == 't.active') {
184  $sqlwhere[] = $key.'='.$value;
185  }
186  }
187  }
188  $sql .= ' WHERE 1 = 1';
189  $sql .= " AND entity IN (".getEntity('accountancy').")";
190  if (count($sqlwhere) > 0) {
191  $sql .= " AND ".implode(" ".$filtermode." ", $sqlwhere);
192  }
193 
194  if (!empty($sortfield)) {
195  $sql .= $this->db->order($sortfield, $sortorder);
196  }
197  if (!empty($limit)) {
198  $sql .= $this->db->plimit($limit + 1, $offset);
199  }
200  $this->lines = array();
201 
202  dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
203  $resql = $this->db->query($sql);
204  if ($resql) {
205  $num = $this->db->num_rows($resql);
206 
207  while ($obj = $this->db->fetch_object($resql)) {
208  $line = new self($this->db);
209 
210  $line->id = $obj->rowid;
211  $line->code = $obj->code;
212  $line->label = $obj->label;
213  $line->nature = $obj->nature;
214  $line->active = $obj->active;
215 
216  $this->lines[] = $line;
217  }
218 
219  $this->db->free($resql);
220 
221  return $num;
222  } else {
223  $this->errors[] = 'Error '.$this->db->lasterror();
224  dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
225 
226  return -1;
227  }
228  }
229 
240  public function getNomUrl($withpicto = 0, $withlabel = 0, $nourl = 0, $moretitle = '', $notooltip = 0)
241  {
242  global $langs, $conf, $user, $hookmanager;
243 
244  if (!empty($conf->dol_no_mouse_hover)) {
245  $notooltip = 1; // Force disable tooltips
246  }
247 
248  $result = '';
249 
250  $url = DOL_URL_ROOT.'/accountancy/admin/journals_list.php?id=35';
251 
252  $label = '<u>'.$langs->trans("ShowAccountingJournal").'</u>';
253  if (!empty($this->code)) {
254  $label .= '<br><b>'.$langs->trans('Code').':</b> '.$this->code;
255  }
256  if (!empty($this->label)) {
257  $label .= '<br><b>'.$langs->trans('Label').':</b> '.$langs->transnoentities($this->label);
258  }
259  if ($moretitle) {
260  $label .= ' - '.$moretitle;
261  }
262 
263  $linkclose = '';
264  if (empty($notooltip)) {
265  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
266  $label = $langs->trans("ShowAccountingJournal");
267  $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
268  }
269  $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
270  $linkclose .= ' class="classfortooltip"';
271  }
272 
273  $linkstart = '<a href="'.$url.'"';
274  $linkstart .= $linkclose.'>';
275  $linkend = '</a>';
276 
277  if ($nourl) {
278  $linkstart = '';
279  $linkclose = '';
280  $linkend = '';
281  }
282 
283  $label_link = $this->code;
284  if ($withlabel != 2 && !empty($this->label)) {
285  $label_link .= ' - '.($nourl ? '<span class="opacitymedium">' : '').$langs->transnoentities($this->label).($nourl ? '</span>' : '');
286  }
287  if ($withlabel == 2 && !empty($this->nature)) {
288  $key = $langs->trans("AccountingJournalType".strtoupper($this->nature));
289  $transferlabel = ($this->nature && $key != "AccountingJournalType".strtoupper($langs->trans($this->nature)) ? $key : $this->label);
290  $label_link .= ' - '.($nourl ? '<span class="opacitymedium">' : '').$transferlabel.($nourl ? '</span>' : '');
291  }
292 
293  $result .= $linkstart;
294  if ($withpicto) {
295  $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);
296  }
297  if ($withpicto != 2) {
298  $result .= $label_link;
299  }
300  $result .= $linkend;
301 
302  global $action;
303  $hookmanager->initHooks(array('accountingjournaldao'));
304  $parameters = array('id'=>$this->id, 'getnomurl' => &$result);
305  $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
306  if ($reshook > 0) {
307  $result = $hookmanager->resPrint;
308  } else {
309  $result .= $hookmanager->resPrint;
310  }
311  return $result;
312  }
313 
320  public function getLibType($mode = 0)
321  {
322  return $this->LibType($this->nature, $mode);
323  }
324 
325  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
333  public function LibType($nature, $mode = 0)
334  {
335  // phpcs:enable
336  global $langs;
337 
338  $langs->loadLangs(array("accountancy"));
339 
340  if ($mode == 0) {
341  $prefix = '';
342  if ($nature == 9) {
343  return $langs->trans('AccountingJournalType9');
344  } elseif ($nature == 5) {
345  return $langs->trans('AccountingJournalType5');
346  } elseif ($nature == 4) {
347  return $langs->trans('AccountingJournalType4');
348  } elseif ($nature == 3) {
349  return $langs->trans('AccountingJournalType3');
350  } elseif ($nature == 2) {
351  return $langs->trans('AccountingJournalType2');
352  } elseif ($nature == 1) {
353  return $langs->trans('AccountingJournalType1');
354  }
355  } elseif ($mode == 1) {
356  if ($nature == 9) {
357  return $langs->trans('AccountingJournalType9');
358  } elseif ($nature == 5) {
359  return $langs->trans('AccountingJournalType5');
360  } elseif ($nature == 4) {
361  return $langs->trans('AccountingJournalType4');
362  } elseif ($nature == 3) {
363  return $langs->trans('AccountingJournalType3');
364  } elseif ($nature == 2) {
365  return $langs->trans('AccountingJournalType2');
366  } elseif ($nature == 1) {
367  return $langs->trans('AccountingJournalType1');
368  }
369  }
370  }
371 
372 
383  public function getData(User $user, $type = 'view', $date_start = null, $date_end = null, $in_bookkeeping = 'notyet')
384  {
385  global $hookmanager;
386 
387  // Clean parameters
388  if (empty($type)) $type = 'view';
389  if (empty($in_bookkeeping)) $in_bookkeeping = 'notyet';
390 
391  // Hook
392  if (!is_object($hookmanager)) {
393  include_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php';
394  $hookmanager = new HookManager($this->db);
395  }
396 
397  $data = array();
398 
399  $hookmanager->initHooks(array('accountingjournaldao'));
400  $parameters = array('data' => &$data, 'user' => $user, 'type' => $type, 'date_start' => $date_start, 'date_end' => $date_end, 'in_bookkeeping' => $in_bookkeeping);
401  $reshook = $hookmanager->executeHooks('getData', $parameters, $this); // Note that $action and $object may have been
402  if ($reshook < 0) {
403  $this->error = $hookmanager->error;
404  $this->errors = $hookmanager->errors;
405  return -1;
406  } elseif (empty($reshook)) {
407  switch ($this->nature) {
408  case 1: // Various Journal
409  $data = $this->getAssetData($user, $type, $date_start, $date_end, $in_bookkeeping);
410  break;
411  // case 2: // Sells Journal
412  // case 3: // Purchases Journal
413  // case 4: // Bank Journal
414  // case 5: // Expense reports Journal
415  // case 8: // Inventory Journal
416  // case 9: // hasnew Journal
417  }
418  }
419 
420  return $data;
421  }
422 
433  public function getAssetData(User $user, $type = 'view', $date_start = null, $date_end = null, $in_bookkeeping = 'notyet')
434  {
435  global $conf, $langs;
436 
437  if (!isModEnabled('asset')) {
438  return array();
439  }
440 
441  require_once DOL_DOCUMENT_ROOT . '/core/lib/accounting.lib.php';
442  require_once DOL_DOCUMENT_ROOT . '/asset/class/asset.class.php';
443  require_once DOL_DOCUMENT_ROOT . '/asset/class/assetaccountancycodes.class.php';
444  require_once DOL_DOCUMENT_ROOT . '/asset/class/assetdepreciationoptions.class.php';
445 
446  $langs->loadLangs(array("assets"));
447 
448  // Clean parameters
449  if (empty($type)) {
450  $type = 'view';
451  }
452  if (empty($in_bookkeeping)) {
453  $in_bookkeeping = 'notyet';
454  }
455 
456  $sql = "";
457  $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";
458  $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";
459  $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";
460  $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation as ad";
461  $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "asset as a ON a.rowid = ad.fk_asset";
462  $sql .= " WHERE a.entity IN (" . getEntity('asset', 0) . ')'; // We don't share object for accountancy, we use source object sharing
463  if ($in_bookkeeping == 'already') {
464  $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')";
465  } elseif ($in_bookkeeping == 'notyet') {
466  $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')";
467  }
468  $sql .= " AND ad.ref != ''"; // not reversal lines
469  if ($date_start && $date_end) {
470  $sql .= " AND ad.depreciation_date >= '" . $this->db->idate($date_start) . "' AND ad.depreciation_date <= '" . $this->db->idate($date_end) . "'";
471  }
472  // Define begin binding date
473  if (!empty($conf->global->ACCOUNTING_DATE_START_BINDING)) {
474  $sql .= " AND ad.depreciation_date >= '" . $this->db->idate($conf->global->ACCOUNTING_DATE_START_BINDING) . "'";
475  }
476  $sql .= " ORDER BY ad.depreciation_date";
477 
478  dol_syslog(__METHOD__, LOG_DEBUG);
479  $resql = $this->db->query($sql);
480  if (!$resql) {
481  $this->errors[] = $this->db->lasterror();
482  return -1;
483  }
484 
485  $pre_data = array(
486  'elements' => array(),
487  );
488  while ($obj = $this->db->fetch_object($resql)) {
489  if (!isset($pre_data['elements'][$obj->rowid])) {
490  $pre_data['elements'][$obj->rowid] = array(
491  'ref' => $obj->asset_ref,
492  'label' => $obj->asset_label,
493  'acquisition_value_ht' => $obj->asset_acquisition_value_ht,
494  'depreciation' => array(),
495  );
496 
497  // Disposal infos
498  if (isset($obj->asset_disposal_date)) {
499  $pre_data['elements'][$obj->rowid]['disposal'] = array(
500  'date' => $this->db->jdate($obj->asset_disposal_date),
501  'amount' => $obj->asset_disposal_amount_ht,
502  'subject_to_vat' => !empty($obj->asset_disposal_subject_to_vat),
503  );
504  }
505  }
506 
507  $compta_debit = empty($obj->accountancy_code_debit) ? 'NotDefined' : $obj->accountancy_code_debit;
508  $compta_credit = empty($obj->accountancy_code_credit) ? 'NotDefined' : $obj->accountancy_code_credit;
509 
510  $pre_data['elements'][$obj->rowid]['depreciation'][$obj->depreciation_id] = array(
511  'date' => $this->db->jdate($obj->depreciation_date),
512  'ref' => $obj->depreciation_ref,
513  'lines' => array(
514  $compta_debit => -$obj->depreciation_ht,
515  $compta_credit => $obj->depreciation_ht,
516  ),
517  );
518  }
519 
520  $disposal_ref = $langs->transnoentitiesnoconv('AssetDisposal');
521  $journal = $this->code;
522  $journal_label = $this->label;
523  $journal_label_formatted = $langs->transnoentities($journal_label);
524  $now = dol_now();
525 
526  $element_static = new Asset($this->db);
527 
528  $journal_data = array();
529  foreach ($pre_data['elements'] as $pre_data_id => $pre_data_info) {
530  $element_static->id = $pre_data_id;
531  $element_static->ref = (string) $pre_data_info["ref"];
532  $element_static->label = (string) $pre_data_info["label"];
533  $element_static->acquisition_value_ht = $pre_data_info["acquisition_value_ht"];
534  $element_link = $element_static->getNomUrl(1, 'with_label');
535 
536  $element_name_formatted_0 = dol_trunc($element_static->label, 16);
537  $element_name_formatted_1 = utf8_decode(dol_trunc($element_static->label, 32));
538  $element_name_formatted_2 = utf8_decode(dol_trunc($element_static->label, 16));
539  $label_operation = $element_static->getNomUrl(0, 'label', 16);
540 
541  $element = array(
542  'ref' => dol_trunc($element_static->ref, 16, 'right', 'UTF-8', 1),
543  'error' => $pre_data_info['error'],
544  'blocks' => array(),
545  );
546 
547  // Depreciation lines
548  //--------------------
549  foreach ($pre_data_info['depreciation'] as $depreciation_id => $line) {
550  $depreciation_ref = $line["ref"];
551  $depreciation_date = $line["date"];
552  $depreciation_date_formatted = dol_print_date($depreciation_date, 'day');
553 
554  // lines
555  $blocks = array();
556  foreach ($line['lines'] as $account => $mt) {
557  $account_infos = $this->getAccountingAccountInfos($account);
558 
559  if ($type == 'view') {
560  $account_to_show = length_accounta($account);
561  if (($account_to_show == "") || $account_to_show == 'NotDefined') {
562  $account_to_show = '<span class="error">' . $langs->trans("AssetInAccountNotDefined") . '</span>';
563  }
564 
565  $blocks[] = array(
566  'date' => $depreciation_date_formatted,
567  'piece' => $element_link,
568  'account_accounting' => $account_to_show,
569  'subledger_account' => '',
570  'label_operation' => $label_operation . ' - ' . $depreciation_ref,
571  'debit' => $mt < 0 ? price(-$mt) : '',
572  'credit' => $mt >= 0 ? price($mt) : '',
573  );
574  } elseif ($type == 'bookkeeping') {
575  if ($account_infos['found']) {
576  $blocks[] = array(
577  'doc_date' => $depreciation_date,
578  'date_lim_reglement' => '',
579  'doc_ref' => $element_static->ref,
580  'date_creation' => $now,
581  'doc_type' => 'asset',
582  'fk_doc' => $element_static->id,
583  'fk_docdet' => $depreciation_id, // Useless, can be several lines that are source of this record to add
584  'thirdparty_code' => '',
585  'subledger_account' => '',
586  'subledger_label' => '',
587  'numero_compte' => $account,
588  'label_compte' => $account_infos['label'],
589  'label_operation' => $element_name_formatted_0 . ' - ' . $depreciation_ref,
590  'montant' => $mt,
591  'sens' => $mt < 0 ? 'D' : 'C',
592  'debit' => $mt < 0 ? -$mt : 0,
593  'credit' => $mt >= 0 ? $mt : 0,
594  'code_journal' => $journal,
595  'journal_label' => $journal_label_formatted,
596  'piece_num' => '',
597  'import_key' => '',
598  'fk_user_author' => $user->id,
599  'entity' => $conf->entity,
600  );
601  }
602  } else { // $type == 'csv'
603  $blocks[] = array(
604  $depreciation_date, // Date
605  $element_static->ref, // Piece
606  $account_infos['code_formatted_1'], // AccountAccounting
607  $element_name_formatted_0 . ' - ' . $depreciation_ref, // LabelOperation
608  $mt < 0 ? price(-$mt) : '', // Debit
609  $mt >= 0 ? price($mt) : '', // Credit
610  );
611  }
612  }
613  $element['blocks'][] = $blocks;
614  }
615 
616  // Disposal line
617  //--------------------
618  if (!empty($pre_data_info['disposal'])) {
619  $disposal_date = $pre_data_info['disposal']['date'];
620 
621  if ((!($date_start && $date_end) || ($date_start <= $disposal_date && $disposal_date <= $date_end)) &&
622  (empty($conf->global->ACCOUNTING_DATE_START_BINDING) || $conf->global->ACCOUNTING_DATE_START_BINDING <= $disposal_date)
623  ) {
624  $disposal_amount = $pre_data_info['disposal']['amount'];
625  $disposal_subject_to_vat = $pre_data_info['disposal']['subject_to_vat'];
626  $disposal_date_formatted = dol_print_date($disposal_date, 'day');
627  $disposal_vat = $conf->global->ASSET_DISPOSAL_VAT > 0 ? $conf->global->ASSET_DISPOSAL_VAT : 20;
628 
629  // Get accountancy codes
630  //---------------------------
631  require_once DOL_DOCUMENT_ROOT . '/asset/class/assetaccountancycodes.class.php';
632  $accountancy_codes = new AssetAccountancyCodes($this->db);
633  $result = $accountancy_codes->fetchAccountancyCodes($element_static->id);
634  if ($result < 0) {
635  $element['error'] = $accountancy_codes->errorsToString();
636  } else {
637  // Get last depreciation cumulative amount
638  $element_static->fetchDepreciationLines();
639  foreach ($element_static->depreciation_lines as $mode_key => $depreciation_lines) {
640  $accountancy_codes_list = $accountancy_codes->accountancy_codes[$mode_key];
641 
642  if (!isset($accountancy_codes_list['value_asset_sold'])) {
643  continue;
644  }
645 
646  $accountancy_code_value_asset_sold = empty($accountancy_codes_list['value_asset_sold']) ? 'NotDefined' : $accountancy_codes_list['value_asset_sold'];
647  $accountancy_code_depreciation_asset = empty($accountancy_codes_list['depreciation_asset']) ? 'NotDefined' : $accountancy_codes_list['depreciation_asset'];
648  $accountancy_code_asset = empty($accountancy_codes_list['asset']) ? 'NotDefined' : $accountancy_codes_list['asset'];
649  $accountancy_code_receivable_on_assignment = empty($accountancy_codes_list['receivable_on_assignment']) ? 'NotDefined' : $accountancy_codes_list['receivable_on_assignment'];
650  $accountancy_code_vat_collected = empty($accountancy_codes_list['vat_collected']) ? 'NotDefined' : $accountancy_codes_list['vat_collected'];
651  $accountancy_code_proceeds_from_sales = empty($accountancy_codes_list['proceeds_from_sales']) ? 'NotDefined' : $accountancy_codes_list['proceeds_from_sales'];
652 
653  $last_cumulative_amount_ht = 0;
654  $depreciated_ids = array_keys($pre_data_info['depreciation']);
655  foreach ($depreciation_lines as $line) {
656  $last_cumulative_amount_ht = $line['cumulative_depreciation_ht'];
657  if (!in_array($line['id'], $depreciated_ids) && empty($line['bookkeeping']) && !empty($line['ref'])) {
658  break;
659  }
660  }
661 
662  $lines = array();
663  $lines[0][$accountancy_code_value_asset_sold] = -($element_static->acquisition_value_ht - $last_cumulative_amount_ht);
664  $lines[0][$accountancy_code_depreciation_asset] = -$last_cumulative_amount_ht;
665  $lines[0][$accountancy_code_asset] = $element_static->acquisition_value_ht;
666 
667  $disposal_amount_vat = $disposal_subject_to_vat ? (double) price2num($disposal_amount * $disposal_vat / 100, 'MT') : 0;
668  $lines[1][$accountancy_code_receivable_on_assignment] = -($disposal_amount + $disposal_amount_vat);
669  if ($disposal_subject_to_vat) $lines[1][$accountancy_code_vat_collected] = $disposal_amount_vat;
670  $lines[1][$accountancy_code_proceeds_from_sales] = $disposal_amount;
671 
672  foreach ($lines as $lines_block) {
673  $blocks = array();
674  foreach ($lines_block as $account => $mt) {
675  $account_infos = $this->getAccountingAccountInfos($account);
676 
677  if ($type == 'view') {
678  $account_to_show = length_accounta($account);
679  if (($account_to_show == "") || $account_to_show == 'NotDefined') {
680  $account_to_show = '<span class="error">' . $langs->trans("AssetInAccountNotDefined") . '</span>';
681  }
682 
683  $blocks[] = array(
684  'date' => $disposal_date_formatted,
685  'piece' => $element_link,
686  'account_accounting' => $account_to_show,
687  'subledger_account' => '',
688  'label_operation' => $label_operation . ' - ' . $disposal_ref,
689  'debit' => $mt < 0 ? price(-$mt) : '',
690  'credit' => $mt >= 0 ? price($mt) : '',
691  );
692  } elseif ($type == 'bookkeeping') {
693  if ($account_infos['found']) {
694  $blocks[] = array(
695  'doc_date' => $disposal_date,
696  'date_lim_reglement' => '',
697  'doc_ref' => $element_static->ref,
698  'date_creation' => $now,
699  'doc_type' => 'asset',
700  'fk_doc' => $element_static->id,
701  'fk_docdet' => 0, // Useless, can be several lines that are source of this record to add
702  'thirdparty_code' => '',
703  'subledger_account' => '',
704  'subledger_label' => '',
705  'numero_compte' => $account,
706  'label_compte' => $account_infos['label'],
707  'label_operation' => $element_name_formatted_0 . ' - ' . $disposal_ref,
708  'montant' => $mt,
709  'sens' => $mt < 0 ? 'D' : 'C',
710  'debit' => $mt < 0 ? -$mt : 0,
711  'credit' => $mt >= 0 ? $mt : 0,
712  'code_journal' => $journal,
713  'journal_label' => $journal_label_formatted,
714  'piece_num' => '',
715  'import_key' => '',
716  'fk_user_author' => $user->id,
717  'entity' => $conf->entity,
718  );
719  }
720  } else { // $type == 'csv'
721  $blocks[] = array(
722  $disposal_date, // Date
723  $element_static->ref, // Piece
724  $account_infos['code_formatted_1'], // AccountAccounting
725  $element_name_formatted_0 . ' - ' . $disposal_ref, // LabelOperation
726  $mt < 0 ? price(-$mt) : '', // Debit
727  $mt >= 0 ? price($mt) : '', // Credit
728  );
729  }
730  }
731  $element['blocks'][] = $blocks;
732  }
733  }
734  }
735  }
736  }
737 
738  $journal_data[(int) $pre_data_id] = $element;
739  }
740  unset($pre_data);
741 
742  return $journal_data;
743  }
744 
788  public function writeIntoBookkeeping(User $user, &$journal_data = array(), $max_nb_errors = 10)
789  {
790  global $conf, $langs, $hookmanager;
791  require_once DOL_DOCUMENT_ROOT . '/accountancy/class/bookkeeping.class.php';
792 
793  // Hook
794  if (!is_object($hookmanager)) {
795  include_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php';
796  $hookmanager = new HookManager($this->db);
797  }
798 
799  $error = 0;
800 
801  $hookmanager->initHooks(array('accountingjournaldao'));
802  $parameters = array('journal_data' => &$journal_data);
803  $reshook = $hookmanager->executeHooks('writeBookkeeping', $parameters, $this); // Note that $action and $object may have been
804  if ($reshook < 0) {
805  $this->error = $hookmanager->error;
806  $this->errors = $hookmanager->errors;
807  return -1;
808  } elseif (empty($reshook)) {
809  // Clean parameters
810  $journal_data = is_array($journal_data) ? $journal_data : array();
811 
812  foreach ($journal_data as $element_id => $element) {
813  $error_for_line = 0;
814  $total_credit = 0;
815  $total_debit = 0;
816 
817  $this->db->begin();
818 
819  if ($element['error'] == 'somelinesarenotbound') {
820  $error++;
821  $error_for_line++;
822  $this->errors[] = $langs->trans('ErrorInvoiceContainsLinesNotYetBounded', $element['ref']);
823  }
824 
825  if (!$error_for_line) {
826  foreach ($element['blocks'] as $lines) {
827  foreach ($lines as $line) {
828  $bookkeeping = new BookKeeping($this->db);
829  $bookkeeping->doc_date = $line['doc_date'];
830  $bookkeeping->date_lim_reglement = $line['date_lim_reglement'];
831  $bookkeeping->doc_ref = $line['doc_ref'];
832  $bookkeeping->date_creation = $line['date_creation']; // not used
833  $bookkeeping->doc_type = $line['doc_type'];
834  $bookkeeping->fk_doc = $line['fk_doc'];
835  $bookkeeping->fk_docdet = $line['fk_docdet'];
836  $bookkeeping->thirdparty_code = $line['thirdparty_code'];
837  $bookkeeping->subledger_account = $line['subledger_account'];
838  $bookkeeping->subledger_label = $line['subledger_label'];
839  $bookkeeping->numero_compte = $line['numero_compte'];
840  $bookkeeping->label_compte = $line['label_compte'];
841  $bookkeeping->label_operation = $line['label_operation'];
842  $bookkeeping->montant = $line['montant'];
843  $bookkeeping->sens = $line['sens'];
844  $bookkeeping->debit = $line['debit'];
845  $bookkeeping->credit = $line['credit'];
846  $bookkeeping->code_journal = $line['code_journal'];
847  $bookkeeping->journal_label = $line['journal_label'];
848  $bookkeeping->piece_num = $line['piece_num'];
849  $bookkeeping->import_key = $line['import_key'];
850  $bookkeeping->fk_user_author = $user->id;
851  $bookkeeping->entity = $conf->entity;
852 
853  $total_debit += $bookkeeping->debit;
854  $total_credit += $bookkeeping->credit;
855 
856  $result = $bookkeeping->create($user);
857  if ($result < 0) {
858  if ($bookkeeping->error == 'BookkeepingRecordAlreadyExists') { // Already exists
859  $error++;
860  $error_for_line++;
861  $journal_data[$element_id]['error'] = 'alreadyjournalized';
862  } else {
863  $error++;
864  $error_for_line++;
865  $journal_data[$element_id]['error'] = 'other';
866  $this->errors[] = $bookkeeping->errorsToString();
867  }
868  }
869  //
870  // if (!$error_for_line && isModEnabled('asset') && $this->nature == 1 && $bookkeeping->fk_doc > 0) {
871  // // Set last cumulative depreciation
872  // require_once DOL_DOCUMENT_ROOT . '/asset/class/asset.class.php';
873  // $asset = new Asset($this->db);
874  // $result = $asset->setLastCumulativeDepreciation($bookkeeping->fk_doc);
875  // if ($result < 0) {
876  // $error++;
877  // $error_for_line++;
878  // $journal_data[$element_id]['error'] = 'other';
879  // $this->errors[] = $asset->errorsToString();
880  // }
881  // }
882  }
883 
884  if ($error_for_line) {
885  break;
886  }
887  }
888  }
889 
890  // Protection against a bug on lines before
891  if (!$error_for_line && (price2num($total_debit, 'MT') != price2num($total_credit, 'MT'))) {
892  $error++;
893  $error_for_line++;
894  $journal_data[$element_id]['error'] = 'amountsnotbalanced';
895  $this->errors[] = 'Try to insert a non balanced transaction in book for ' . $element['blocks'] . '. Canceled. Surely a bug.';
896  }
897 
898  if (!$error_for_line) {
899  $this->db->commit();
900  } else {
901  $this->db->rollback();
902 
903  if ($error >= $max_nb_errors) {
904  $this->errors[] = $langs->trans("ErrorTooManyErrorsProcessStopped");
905  break; // Break in the foreach
906  }
907  }
908  }
909  }
910 
911  return $error ? -$error : 1;
912  }
913 
935  public function exportCsv(&$journal_data = array(), $search_date_end = 0, $sep = '')
936  {
937  global $conf, $langs, $hookmanager;
938 
939  if (empty($sep)) $sep = $conf->global->ACCOUNTING_EXPORT_SEPARATORCSV;
940  $out = '';
941 
942  // Hook
943  if (!is_object($hookmanager)) {
944  include_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php';
945  $hookmanager = new HookManager($this->db);
946  }
947 
948  $hookmanager->initHooks(array('accountingjournaldao'));
949  $parameters = array('journal_data' => &$journal_data, 'search_date_end' => &$search_date_end, 'sep' => &$sep, 'out' => &$out);
950  $reshook = $hookmanager->executeHooks('exportCsv', $parameters, $this); // Note that $action and $object may have been
951  if ($reshook < 0) {
952  $this->error = $hookmanager->error;
953  $this->errors = $hookmanager->errors;
954  return -1;
955  } elseif (empty($reshook)) {
956  // Clean parameters
957  $journal_data = is_array($journal_data) ? $journal_data : array();
958 
959  // CSV header line
960  $header = array();
961  if ($this->nature == 4) {
962  $header = array(
963  $langs->transnoentitiesnoconv("BankId"),
964  $langs->transnoentitiesnoconv("Date"),
965  $langs->transnoentitiesnoconv("PaymentMode"),
966  $langs->transnoentitiesnoconv("AccountAccounting"),
967  $langs->transnoentitiesnoconv("LedgerAccount"),
968  $langs->transnoentitiesnoconv("SubledgerAccount"),
969  $langs->transnoentitiesnoconv("Label"),
970  $langs->transnoentitiesnoconv("AccountingDebit"),
971  $langs->transnoentitiesnoconv("AccountingCredit"),
972  $langs->transnoentitiesnoconv("Journal"),
973  $langs->transnoentitiesnoconv("Note"),
974  );
975  } elseif ($this->nature == 5) {
976  $header = array(
977  $langs->transnoentitiesnoconv("Date"),
978  $langs->transnoentitiesnoconv("Piece"),
979  $langs->transnoentitiesnoconv("AccountAccounting"),
980  $langs->transnoentitiesnoconv("LabelOperation"),
981  $langs->transnoentitiesnoconv("AccountingDebit"),
982  $langs->transnoentitiesnoconv("AccountingCredit"),
983  );
984  } elseif ($this->nature == 1) {
985  $header = array(
986  $langs->transnoentitiesnoconv("Date"),
987  $langs->transnoentitiesnoconv("Piece"),
988  $langs->transnoentitiesnoconv("AccountAccounting"),
989  $langs->transnoentitiesnoconv("LabelOperation"),
990  $langs->transnoentitiesnoconv("AccountingDebit"),
991  $langs->transnoentitiesnoconv("AccountingCredit"),
992  );
993  }
994 
995  if (!empty($header)) $out .= '"' . implode('"' . $sep . '"', $header) . '"' . "\n";
996  foreach ($journal_data as $element_id => $element) {
997  foreach ($element['blocks'] as $lines) {
998  foreach ($lines as $line) {
999  $out .= '"' . implode('"' . $sep . '"', $line) . '"' . "\n";
1000  }
1001  }
1002  }
1003  }
1004 
1005  return $out;
1006  }
1007 
1014  public function getAccountingAccountInfos($account)
1015  {
1016  if (!isset(self::$accounting_account_cached[$account])) {
1017  require_once DOL_DOCUMENT_ROOT . '/core/lib/accounting.lib.php';
1018  require_once DOL_DOCUMENT_ROOT . '/accountancy/class/accountingaccount.class.php';
1019  $accountingaccount = new AccountingAccount($this->db);
1020  $result = $accountingaccount->fetch(null, $account, true);
1021  if ($result > 0) {
1022  self::$accounting_account_cached[$account] = array(
1023  'found' => true,
1024  'label' => $accountingaccount->label,
1025  'code_formatted_1' => length_accounta(html_entity_decode($account)),
1026  'label_formatted_1' => utf8_decode(dol_trunc($accountingaccount->label, 32)),
1027  'label_formatted_2' => dol_trunc($accountingaccount->label, 32),
1028  );
1029  } else {
1030  self::$accounting_account_cached[$account] = array(
1031  'found' => false,
1032  'label' => '',
1033  'code_formatted_1' => length_accounta(html_entity_decode($account)),
1034  'label_formatted_1' => '',
1035  'label_formatted_2' => '',
1036  );
1037  }
1038  }
1039 
1040  return self::$accounting_account_cached[$account];
1041  }
1042 }
length_accounta($accounta)
Return Auxiliary accounting account of thirdparties with defined length.
$object ref
Definition: info.php:78
Class to manage accounting accounts.
Class to manage accounting accounts.
fetchAll($sortorder='', $sortfield='', $limit=0, $offset=0, array $filter=array(), $filtermode='AND')
Load object in memory from the database.
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 clicable name (with picto eventually)
__construct($db)
Constructor.
LibType($nature, $mode=0)
Return type of an accounting journal.
getAccountingAccountInfos($account)
Get accounting account infos.
fetch($rowid=null, $journal_code=null)
Load an object from database.
getAssetData(User $user, $type='view', $date_start=null, $date_end=null, $in_bookkeeping='notyet')
Get asset data for various journal.
getLibType($mode=0)
Retourne le libelle du statut d'un user (actif, inactif)
Class for AssetAccountancyCodes.
Class for Asset.
Definition: asset.class.php:31
Class to manage Ledger (General Ledger and Subledger)
Parent class of all other business classes (invoices, contracts, proposals, orders,...
Class to manage hooks.
Class to manage Dolibarr users.
Definition: user.class.php:45
if(isModEnabled('facture') &&!empty($user->rights->facture->lire)) if((isModEnabled('fournisseur') &&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->hasRight("fournisseur", "facture", "lire"))||(isModEnabled('supplier_invoice') && $user->hasRight("supplier_invoice", "lire"))) if(isModEnabled('don') &&!empty($user->rights->don->lire)) if(isModEnabled('tax') &&!empty($user->rights->tax->charges->lire)) if(isModEnabled('facture') &&isModEnabled('commande') && $user->hasRight("commande", "lire") &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $resql
Social contributions to pay.
Definition: index.php:745
print *****$script_file(".$version.") pid c cd cd cd description as p label as s rowid
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0)
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_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
dol_now($mode='auto')
Return date for now.
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.
isModEnabled($module)
Is Dolibarr module enabled.
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.
$conf db
API class for accounts.
Definition: inc.php:41
print *****$script_file(".$version.") pid code
! Closing after partial payment: discount_vat, badcustomer or badsupplier, bankcharge,...