dolibarr  16.0.5
accountingjournal.class.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2017-2022 OpenDSI <support@open-dsi.fr>
3  *
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 && !empty($this->label)) {
285  $label_link .= ' - '.($nourl ? '<span class="opacitymedium">' : '').$langs->transnoentities($this->label).($nourl ? '</span>' : '');
286  }
287 
288  $result .= $linkstart;
289  if ($withpicto) {
290  $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);
291  }
292  if ($withpicto != 2) {
293  $result .= $label_link;
294  }
295  $result .= $linkend;
296 
297  global $action;
298  $hookmanager->initHooks(array('accountingjournaldao'));
299  $parameters = array('id'=>$this->id, 'getnomurl' => &$result);
300  $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
301  if ($reshook > 0) {
302  $result = $hookmanager->resPrint;
303  } else {
304  $result .= $hookmanager->resPrint;
305  }
306  return $result;
307  }
308 
315  public function getLibType($mode = 0)
316  {
317  return $this->LibType($this->nature, $mode);
318  }
319 
320  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
328  public function LibType($nature, $mode = 0)
329  {
330  // phpcs:enable
331  global $langs;
332 
333  $langs->loadLangs(array("accountancy"));
334 
335  if ($mode == 0) {
336  $prefix = '';
337  if ($nature == 9) {
338  return $langs->trans('AccountingJournalType9');
339  } elseif ($nature == 5) {
340  return $langs->trans('AccountingJournalType5');
341  } elseif ($nature == 4) {
342  return $langs->trans('AccountingJournalType4');
343  } elseif ($nature == 3) {
344  return $langs->trans('AccountingJournalType3');
345  } elseif ($nature == 2) {
346  return $langs->trans('AccountingJournalType2');
347  } elseif ($nature == 1) {
348  return $langs->trans('AccountingJournalType1');
349  }
350  } elseif ($mode == 1) {
351  if ($nature == 9) {
352  return $langs->trans('AccountingJournalType9');
353  } elseif ($nature == 5) {
354  return $langs->trans('AccountingJournalType5');
355  } elseif ($nature == 4) {
356  return $langs->trans('AccountingJournalType4');
357  } elseif ($nature == 3) {
358  return $langs->trans('AccountingJournalType3');
359  } elseif ($nature == 2) {
360  return $langs->trans('AccountingJournalType2');
361  } elseif ($nature == 1) {
362  return $langs->trans('AccountingJournalType1');
363  }
364  }
365  }
366 
367 
378  public function getData(User $user, $type = 'view', $date_start = null, $date_end = null, $in_bookkeeping = 'notyet')
379  {
380  global $hookmanager;
381 
382  // Clean parameters
383  if (empty($type)) $type = 'view';
384  if (empty($in_bookkeeping)) $in_bookkeeping = 'notyet';
385 
386  // Hook
387  if (!is_object($hookmanager)) {
388  include_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php';
389  $hookmanager = new HookManager($this->db);
390  }
391 
392  $data = array();
393 
394  $hookmanager->initHooks(array('accountingjournaldao'));
395  $parameters = array('data' => &$data, 'user' => $user, 'type' => $type, 'date_start' => $date_start, 'date_end' => $date_end, 'in_bookkeeping' => $in_bookkeeping);
396  $reshook = $hookmanager->executeHooks('getData', $parameters, $this); // Note that $action and $object may have been
397  if ($reshook < 0) {
398  $this->error = $hookmanager->error;
399  $this->errors = $hookmanager->errors;
400  return -1;
401  } elseif (empty($reshook)) {
402  switch ($this->nature) {
403  case 1: // Various Journal
404  $data = $this->getAssetData($user, $type, $date_start, $date_end, $in_bookkeeping);
405  break;
406  // case 2: // Sells Journal
407  // case 3: // Purchases Journal
408  // case 4: // Bank Journal
409  // case 5: // Expense reports Journal
410  // case 8: // Inventory Journal
411  // case 9: // hasnew Journal
412  }
413  }
414 
415  return $data;
416  }
417 
428  public function getAssetData(User $user, $type = 'view', $date_start = null, $date_end = null, $in_bookkeeping = 'notyet')
429  {
430  global $conf, $langs;
431 
432  if (!isModEnabled('asset')) {
433  return array();
434  }
435 
436  require_once DOL_DOCUMENT_ROOT . '/core/lib/accounting.lib.php';
437  require_once DOL_DOCUMENT_ROOT . '/asset/class/asset.class.php';
438  require_once DOL_DOCUMENT_ROOT . '/asset/class/assetaccountancycodes.class.php';
439  require_once DOL_DOCUMENT_ROOT . '/asset/class/assetdepreciationoptions.class.php';
440 
441  $langs->loadLangs(array("assets"));
442 
443  // Clean parameters
444  if (empty($type)) {
445  $type = 'view';
446  }
447  if (empty($in_bookkeeping)) {
448  $in_bookkeeping = 'notyet';
449  }
450 
451  $sql = "";
452 
453  // FIXME sql error with Mysql 5.7
454  /*if ($in_bookkeeping == 'already' || $in_bookkeeping == 'notyet') {
455  $sql .= "WITH in_accounting_bookkeeping(fk_docdet) AS (";
456  $sql .= " SELECT DISTINCT fk_docdet";
457  $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping";
458  $sql .= " WHERE doc_type = 'asset'";
459  $sql .= ") ";
460  }*/
461 
462  $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";
463  $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";
464  $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";
465  $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation as ad";
466  $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "asset as a ON a.rowid = ad.fk_asset";
467  // FIXME sql error with Mysql 5.7
468  /*if ($in_bookkeeping == 'already' || $in_bookkeeping == 'notyet') {
469  $sql .= " LEFT JOIN in_accounting_bookkeeping as iab ON iab.fk_docdet = ad.rowid";
470  }*/
471  $sql .= " WHERE a.entity IN (" . getEntity('asset', 0) . ')'; // We don't share object for accountancy, we use source object sharing
472  // Compatibility with Mysql 5.7
473  if ($in_bookkeeping == 'already') {
474  $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')";
475  } elseif ($in_bookkeeping == 'notyet') {
476  $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')";
477  }
478  $sql .= " AND ad.ref != ''"; // not reversal lines
479  if ($date_start && $date_end) {
480  $sql .= " AND ad.depreciation_date >= '" . $this->db->idate($date_start) . "' AND ad.depreciation_date <= '" . $this->db->idate($date_end) . "'";
481  }
482  // Define begin binding date
483  if (!empty($conf->global->ACCOUNTING_DATE_START_BINDING)) {
484  $sql .= " AND ad.depreciation_date >= '" . $this->db->idate($conf->global->ACCOUNTING_DATE_START_BINDING) . "'";
485  }
486  // Already in bookkeeping or not
487  // FIXME sql error with Mysql 5.7
488  /*if ($in_bookkeeping == 'already' || $in_bookkeeping == 'notyet') {
489  $sql .= " AND iab.fk_docdet IS" . ($in_bookkeeping == 'already' ? " NOT" : "") . " NULL";
490  }*/
491  $sql .= " ORDER BY ad.depreciation_date";
492 
493  dol_syslog(__METHOD__, LOG_DEBUG);
494  $resql = $this->db->query($sql);
495  if (!$resql) {
496  $this->errors[] = $this->db->lasterror();
497  return -1;
498  }
499 
500  $pre_data = array(
501  'elements' => array(),
502  );
503  while ($obj = $this->db->fetch_object($resql)) {
504  if (!isset($pre_data['elements'][$obj->rowid])) {
505  $pre_data['elements'][$obj->rowid] = array(
506  'ref' => $obj->asset_ref,
507  'label' => $obj->asset_label,
508  'acquisition_value_ht' => $obj->asset_acquisition_value_ht,
509  'depreciation' => array(),
510  );
511 
512  // Disposal infos
513  if (isset($obj->asset_disposal_date)) {
514  $pre_data['elements'][$obj->rowid]['disposal'] = array(
515  'date' => $this->db->jdate($obj->asset_disposal_date),
516  'amount' => $obj->asset_disposal_amount_ht,
517  'subject_to_vat' => !empty($obj->asset_disposal_subject_to_vat),
518  );
519  }
520  }
521 
522  $compta_debit = empty($obj->accountancy_code_debit) ? 'NotDefined' : $obj->accountancy_code_debit;
523  $compta_credit = empty($obj->accountancy_code_credit) ? 'NotDefined' : $obj->accountancy_code_credit;
524 
525  $pre_data['elements'][$obj->rowid]['depreciation'][$obj->depreciation_id] = array(
526  'date' => $this->db->jdate($obj->depreciation_date),
527  'ref' => $obj->depreciation_ref,
528  'lines' => array(
529  $compta_debit => -$obj->depreciation_ht,
530  $compta_credit => $obj->depreciation_ht,
531  ),
532  );
533  }
534 
535  $disposal_ref = $langs->transnoentitiesnoconv('AssetDisposal');
536  $journal = $this->code;
537  $journal_label = $this->label;
538  $journal_label_formatted = $langs->transnoentities($journal_label);
539  $now = dol_now();
540 
541  $element_static = new Asset($this->db);
542 
543  $journal_data = array();
544  foreach ($pre_data['elements'] as $pre_data_id => $pre_data_info) {
545  $element_static->id = $pre_data_id;
546  $element_static->ref = (string) $pre_data_info["ref"];
547  $element_static->label = (string) $pre_data_info["label"];
548  $element_static->acquisition_value_ht = $pre_data_info["acquisition_value_ht"];
549  $element_link = $element_static->getNomUrl(1, 'with_label');
550 
551  $element_name_formatted_0 = dol_trunc($element_static->label, 16);
552  $element_name_formatted_1 = utf8_decode(dol_trunc($element_static->label, 32));
553  $element_name_formatted_2 = utf8_decode(dol_trunc($element_static->label, 16));
554  $label_operation = $element_static->getNomUrl(0, 'label', 16);
555 
556  $element = array(
557  'ref' => dol_trunc($element_static->ref, 16, 'right', 'UTF-8', 1),
558  'error' => $pre_data_info['error'],
559  'blocks' => array(),
560  );
561 
562  // Depreciation lines
563  //--------------------
564  foreach ($pre_data_info['depreciation'] as $depreciation_id => $line) {
565  $depreciation_ref = $line["ref"];
566  $depreciation_date = $line["date"];
567  $depreciation_date_formatted = dol_print_date($depreciation_date, 'day');
568 
569  // lines
570  $blocks = array();
571  foreach ($line['lines'] as $account => $mt) {
572  $account_infos = $this->getAccountingAccountInfos($account);
573 
574  if ($type == 'view') {
575  $account_to_show = length_accounta($account);
576  if (($account_to_show == "") || $account_to_show == 'NotDefined') {
577  $account_to_show = '<span class="error">' . $langs->trans("AssetInAccountNotDefined") . '</span>';
578  }
579 
580  $blocks[] = array(
581  'date' => $depreciation_date_formatted,
582  'piece' => $element_link,
583  'account_accounting' => $account_to_show,
584  'subledger_account' => '',
585  'label_operation' => $label_operation . ' - ' . $depreciation_ref,
586  'debit' => $mt < 0 ? price(-$mt) : '',
587  'credit' => $mt >= 0 ? price($mt) : '',
588  );
589  } elseif ($type == 'bookkeeping') {
590  if ($account_infos['found']) {
591  $blocks[] = array(
592  'doc_date' => $depreciation_date,
593  'date_lim_reglement' => '',
594  'doc_ref' => $element_static->ref,
595  'date_creation' => $now,
596  'doc_type' => 'asset',
597  'fk_doc' => $element_static->id,
598  'fk_docdet' => $depreciation_id, // Useless, can be several lines that are source of this record to add
599  'thirdparty_code' => '',
600  'subledger_account' => '',
601  'subledger_label' => '',
602  'numero_compte' => $account,
603  'label_compte' => $account_infos['label'],
604  'label_operation' => $element_name_formatted_0 . ' - ' . $depreciation_ref,
605  'montant' => $mt,
606  'sens' => $mt < 0 ? 'D' : 'C',
607  'debit' => $mt < 0 ? -$mt : 0,
608  'credit' => $mt >= 0 ? $mt : 0,
609  'code_journal' => $journal,
610  'journal_label' => $journal_label_formatted,
611  'piece_num' => '',
612  'import_key' => '',
613  'fk_user_author' => $user->id,
614  'entity' => $conf->entity,
615  );
616  }
617  } else { // $type == 'csv'
618  $blocks[] = array(
619  $depreciation_date, // Date
620  $element_static->ref, // Piece
621  $account_infos['code_formatted_1'], // AccountAccounting
622  $element_name_formatted_0 . ' - ' . $depreciation_ref, // LabelOperation
623  $mt < 0 ? price(-$mt) : '', // Debit
624  $mt >= 0 ? price($mt) : '', // Credit
625  );
626  }
627  }
628  $element['blocks'][] = $blocks;
629  }
630 
631  // Disposal line
632  //--------------------
633  if (!empty($pre_data_info['disposal'])) {
634  $disposal_date = $pre_data_info['disposal']['date'];
635 
636  if ((!($date_start && $date_end) || ($date_start <= $disposal_date && $disposal_date <= $date_end)) &&
637  (empty($conf->global->ACCOUNTING_DATE_START_BINDING) || $conf->global->ACCOUNTING_DATE_START_BINDING <= $disposal_date)
638  ) {
639  $disposal_amount = $pre_data_info['disposal']['amount'];
640  $disposal_subject_to_vat = $pre_data_info['disposal']['subject_to_vat'];
641  $disposal_date_formatted = dol_print_date($disposal_date, 'day');
642  $disposal_vat = $conf->global->ASSET_DISPOSAL_VAT > 0 ? $conf->global->ASSET_DISPOSAL_VAT : 20;
643 
644  // Get accountancy codes
645  //---------------------------
646  require_once DOL_DOCUMENT_ROOT . '/asset/class/assetaccountancycodes.class.php';
647  $accountancy_codes = new AssetAccountancyCodes($this->db);
648  $result = $accountancy_codes->fetchAccountancyCodes($element_static->id);
649  if ($result < 0) {
650  $element['error'] = $accountancy_codes->errorsToString();
651  } else {
652  // Get last depreciation cumulative amount
653  $element_static->fetchDepreciationLines();
654  foreach ($element_static->depreciation_lines as $mode_key => $depreciation_lines) {
655  $accountancy_codes_list = $accountancy_codes->accountancy_codes[$mode_key];
656 
657  if (!isset($accountancy_codes_list['value_asset_sold'])) {
658  continue;
659  }
660 
661  $accountancy_code_value_asset_sold = empty($accountancy_codes_list['value_asset_sold']) ? 'NotDefined' : $accountancy_codes_list['value_asset_sold'];
662  $accountancy_code_depreciation_asset = empty($accountancy_codes_list['depreciation_asset']) ? 'NotDefined' : $accountancy_codes_list['depreciation_asset'];
663  $accountancy_code_asset = empty($accountancy_codes_list['asset']) ? 'NotDefined' : $accountancy_codes_list['asset'];
664  $accountancy_code_receivable_on_assignment = empty($accountancy_codes_list['receivable_on_assignment']) ? 'NotDefined' : $accountancy_codes_list['receivable_on_assignment'];
665  $accountancy_code_vat_collected = empty($accountancy_codes_list['vat_collected']) ? 'NotDefined' : $accountancy_codes_list['vat_collected'];
666  $accountancy_code_proceeds_from_sales = empty($accountancy_codes_list['proceeds_from_sales']) ? 'NotDefined' : $accountancy_codes_list['proceeds_from_sales'];
667 
668  $last_cumulative_amount_ht = 0;
669  $depreciated_ids = array_keys($pre_data_info['depreciation']);
670  foreach ($depreciation_lines as $line) {
671  $last_cumulative_amount_ht = $line['cumulative_depreciation_ht'];
672  if (!in_array($line['id'], $depreciated_ids) && empty($line['bookkeeping']) && !empty($line['ref'])) {
673  break;
674  }
675  }
676 
677  $lines = array();
678  $lines[0][$accountancy_code_value_asset_sold] = -($element_static->acquisition_value_ht - $last_cumulative_amount_ht);
679  $lines[0][$accountancy_code_depreciation_asset] = -$last_cumulative_amount_ht;
680  $lines[0][$accountancy_code_asset] = $element_static->acquisition_value_ht;
681 
682  $disposal_amount_vat = $disposal_subject_to_vat ? (double) price2num($disposal_amount * $disposal_vat / 100, 'MT') : 0;
683  $lines[1][$accountancy_code_receivable_on_assignment] = -($disposal_amount + $disposal_amount_vat);
684  if ($disposal_subject_to_vat) $lines[1][$accountancy_code_vat_collected] = $disposal_amount_vat;
685  $lines[1][$accountancy_code_proceeds_from_sales] = $disposal_amount;
686 
687  foreach ($lines as $lines_block) {
688  $blocks = array();
689  foreach ($lines_block as $account => $mt) {
690  $account_infos = $this->getAccountingAccountInfos($account);
691 
692  if ($type == 'view') {
693  $account_to_show = length_accounta($account);
694  if (($account_to_show == "") || $account_to_show == 'NotDefined') {
695  $account_to_show = '<span class="error">' . $langs->trans("AssetInAccountNotDefined") . '</span>';
696  }
697 
698  $blocks[] = array(
699  'date' => $disposal_date_formatted,
700  'piece' => $element_link,
701  'account_accounting' => $account_to_show,
702  'subledger_account' => '',
703  'label_operation' => $label_operation . ' - ' . $disposal_ref,
704  'debit' => $mt < 0 ? price(-$mt) : '',
705  'credit' => $mt >= 0 ? price($mt) : '',
706  );
707  } elseif ($type == 'bookkeeping') {
708  if ($account_infos['found']) {
709  $blocks[] = array(
710  'doc_date' => $disposal_date,
711  'date_lim_reglement' => '',
712  'doc_ref' => $element_static->ref,
713  'date_creation' => $now,
714  'doc_type' => 'asset',
715  'fk_doc' => $element_static->id,
716  'fk_docdet' => 0, // Useless, can be several lines that are source of this record to add
717  'thirdparty_code' => '',
718  'subledger_account' => '',
719  'subledger_label' => '',
720  'numero_compte' => $account,
721  'label_compte' => $account_infos['label'],
722  'label_operation' => $element_name_formatted_0 . ' - ' . $disposal_ref,
723  'montant' => $mt,
724  'sens' => $mt < 0 ? 'D' : 'C',
725  'debit' => $mt < 0 ? -$mt : 0,
726  'credit' => $mt >= 0 ? $mt : 0,
727  'code_journal' => $journal,
728  'journal_label' => $journal_label_formatted,
729  'piece_num' => '',
730  'import_key' => '',
731  'fk_user_author' => $user->id,
732  'entity' => $conf->entity,
733  );
734  }
735  } else { // $type == 'csv'
736  $blocks[] = array(
737  $disposal_date, // Date
738  $element_static->ref, // Piece
739  $account_infos['code_formatted_1'], // AccountAccounting
740  $element_name_formatted_0 . ' - ' . $disposal_ref, // LabelOperation
741  $mt < 0 ? price(-$mt) : '', // Debit
742  $mt >= 0 ? price($mt) : '', // Credit
743  );
744  }
745  }
746  $element['blocks'][] = $blocks;
747  }
748  }
749  }
750  }
751  }
752 
753  $journal_data[$pre_data_id] = $element;
754  }
755  unset($pre_data);
756 
757  return $journal_data;
758  }
759 
803  public function writeIntoBookkeeping(User $user, &$journal_data = array(), $max_nb_errors = 10)
804  {
805  global $conf, $langs, $hookmanager;
806  require_once DOL_DOCUMENT_ROOT . '/accountancy/class/bookkeeping.class.php';
807 
808  // Hook
809  if (!is_object($hookmanager)) {
810  include_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php';
811  $hookmanager = new HookManager($this->db);
812  }
813 
814  $error = 0;
815 
816  $hookmanager->initHooks(array('accountingjournaldao'));
817  $parameters = array('journal_data' => &$journal_data);
818  $reshook = $hookmanager->executeHooks('writeBookkeeping', $parameters, $this); // Note that $action and $object may have been
819  if ($reshook < 0) {
820  $this->error = $hookmanager->error;
821  $this->errors = $hookmanager->errors;
822  return -1;
823  } elseif (empty($reshook)) {
824  // Clean parameters
825  $journal_data = is_array($journal_data) ? $journal_data : array();
826 
827  foreach ($journal_data as $element_id => $element) {
828  $error_for_line = 0;
829  $total_credit = 0;
830  $total_debit = 0;
831 
832  $this->db->begin();
833 
834  if ($element['error'] == 'somelinesarenotbound') {
835  $error++;
836  $error_for_line++;
837  $this->errors[] = $langs->trans('ErrorInvoiceContainsLinesNotYetBounded', $element['ref']);
838  }
839 
840  if (!$error_for_line) {
841  foreach ($element['blocks'] as $lines) {
842  foreach ($lines as $line) {
843  $bookkeeping = new BookKeeping($this->db);
844  $bookkeeping->doc_date = $line['doc_date'];
845  $bookkeeping->date_lim_reglement = $line['date_lim_reglement'];
846  $bookkeeping->doc_ref = $line['doc_ref'];
847  $bookkeeping->date_creation = $line['date_creation']; // not used
848  $bookkeeping->doc_type = $line['doc_type'];
849  $bookkeeping->fk_doc = $line['fk_doc'];
850  $bookkeeping->fk_docdet = $line['fk_docdet'];
851  $bookkeeping->thirdparty_code = $line['thirdparty_code'];
852  $bookkeeping->subledger_account = $line['subledger_account'];
853  $bookkeeping->subledger_label = $line['subledger_label'];
854  $bookkeeping->numero_compte = $line['numero_compte'];
855  $bookkeeping->label_compte = $line['label_compte'];
856  $bookkeeping->label_operation = $line['label_operation'];
857  $bookkeeping->montant = $line['montant'];
858  $bookkeeping->sens = $line['sens'];
859  $bookkeeping->debit = $line['debit'];
860  $bookkeeping->credit = $line['credit'];
861  $bookkeeping->code_journal = $line['code_journal'];
862  $bookkeeping->journal_label = $line['journal_label'];
863  $bookkeeping->piece_num = $line['piece_num'];
864  $bookkeeping->import_key = $line['import_key'];
865  $bookkeeping->fk_user_author = $user->id;
866  $bookkeeping->entity = $conf->entity;
867 
868  $total_debit += $bookkeeping->debit;
869  $total_credit += $bookkeeping->credit;
870 
871  $result = $bookkeeping->create($user);
872  if ($result < 0) {
873  if ($bookkeeping->error == 'BookkeepingRecordAlreadyExists') { // Already exists
874  $error++;
875  $error_for_line++;
876  $journal_data[$element_id]['error'] = 'alreadyjournalized';
877  } else {
878  $error++;
879  $error_for_line++;
880  $journal_data[$element_id]['error'] = 'other';
881  $this->errors[] = $bookkeeping->errorsToString();
882  }
883  }
884  //
885  // if (!$error_for_line && isModEnabled('asset') && $this->nature == 1 && $bookkeeping->fk_doc > 0) {
886  // // Set last cumulative depreciation
887  // require_once DOL_DOCUMENT_ROOT . '/asset/class/asset.class.php';
888  // $asset = new Asset($this->db);
889  // $result = $asset->setLastCumulativeDepreciation($bookkeeping->fk_doc);
890  // if ($result < 0) {
891  // $error++;
892  // $error_for_line++;
893  // $journal_data[$element_id]['error'] = 'other';
894  // $this->errors[] = $asset->errorsToString();
895  // }
896  // }
897  }
898 
899  if ($error_for_line) {
900  break;
901  }
902  }
903  }
904 
905  // Protection against a bug on lines before
906  if (!$error_for_line && (price2num($total_debit, 'MT') != price2num($total_credit, 'MT'))) {
907  $error++;
908  $error_for_line++;
909  $journal_data[$element_id]['error'] = 'amountsnotbalanced';
910  $this->errors[] = 'Try to insert a non balanced transaction in book for ' . $element['blocks'] . '. Canceled. Surely a bug.';
911  }
912 
913  if (!$error_for_line) {
914  $this->db->commit();
915  } else {
916  $this->db->rollback();
917 
918  if ($error >= $max_nb_errors) {
919  $this->errors[] = $langs->trans("ErrorTooManyErrorsProcessStopped");
920  break; // Break in the foreach
921  }
922  }
923  }
924  }
925 
926  return $error ? -$error : 1;
927  }
928 
950  public function exportCsv(&$journal_data = array(), $search_date_end = 0, $sep = '')
951  {
952  global $conf, $langs, $hookmanager;
953 
954  if (empty($sep)) $sep = $conf->global->ACCOUNTING_EXPORT_SEPARATORCSV;
955  $out = '';
956 
957  // Hook
958  if (!is_object($hookmanager)) {
959  include_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php';
960  $hookmanager = new HookManager($this->db);
961  }
962 
963  $hookmanager->initHooks(array('accountingjournaldao'));
964  $parameters = array('journal_data' => &$journal_data, 'search_date_end' => &$search_date_end, 'sep' => &$sep, 'out' => &$out);
965  $reshook = $hookmanager->executeHooks('exportCsv', $parameters, $this); // Note that $action and $object may have been
966  if ($reshook < 0) {
967  $this->error = $hookmanager->error;
968  $this->errors = $hookmanager->errors;
969  return -1;
970  } elseif (empty($reshook)) {
971  // Clean parameters
972  $journal_data = is_array($journal_data) ? $journal_data : array();
973 
974  // CSV header line
975  $header = array();
976  if ($this->nature == 4) {
977  $header = array(
978  $langs->transnoentitiesnoconv("BankId"),
979  $langs->transnoentitiesnoconv("Date"),
980  $langs->transnoentitiesnoconv("PaymentMode"),
981  $langs->transnoentitiesnoconv("AccountAccounting"),
982  $langs->transnoentitiesnoconv("LedgerAccount"),
983  $langs->transnoentitiesnoconv("SubledgerAccount"),
984  $langs->transnoentitiesnoconv("Label"),
985  $langs->transnoentitiesnoconv("Debit"),
986  $langs->transnoentitiesnoconv("Credit"),
987  $langs->transnoentitiesnoconv("Journal"),
988  $langs->transnoentitiesnoconv("Note"),
989  );
990  } elseif ($this->nature == 5) {
991  $header = array(
992  $langs->transnoentitiesnoconv("Date"),
993  $langs->transnoentitiesnoconv("Piece"),
994  $langs->transnoentitiesnoconv("AccountAccounting"),
995  $langs->transnoentitiesnoconv("LabelOperation"),
996  $langs->transnoentitiesnoconv("Debit"),
997  $langs->transnoentitiesnoconv("Credit"),
998  );
999  } elseif ($this->nature == 1) {
1000  $header = array(
1001  $langs->transnoentitiesnoconv("Date"),
1002  $langs->transnoentitiesnoconv("Piece"),
1003  $langs->transnoentitiesnoconv("AccountAccounting"),
1004  $langs->transnoentitiesnoconv("LabelOperation"),
1005  $langs->transnoentitiesnoconv("Debit"),
1006  $langs->transnoentitiesnoconv("Credit"),
1007  );
1008  }
1009 
1010  if (!empty($header)) $out .= '"' . implode('"' . $sep . '"', $header) . '"' . "\n";
1011  foreach ($journal_data as $element_id => $element) {
1012  foreach ($element['blocks'] as $lines) {
1013  foreach ($lines as $line) {
1014  $out .= '"' . implode('"' . $sep . '"', $line) . '"' . "\n";
1015  }
1016  }
1017  }
1018  }
1019 
1020  return $out;
1021  }
1022 
1029  public function getAccountingAccountInfos($account)
1030  {
1031  if (!isset(self::$accounting_account_cached[$account])) {
1032  require_once DOL_DOCUMENT_ROOT . '/core/lib/accounting.lib.php';
1033  require_once DOL_DOCUMENT_ROOT . '/accountancy/class/accountingaccount.class.php';
1034  $accountingaccount = new AccountingAccount($this->db);
1035  $result = $accountingaccount->fetch(null, $account, true);
1036  if ($result > 0) {
1037  self::$accounting_account_cached[$account] = array(
1038  'found' => true,
1039  'label' => $accountingaccount->label,
1040  'code_formatted_1' => length_accounta(html_entity_decode($account)),
1041  'label_formatted_1' => utf8_decode(dol_trunc($accountingaccount->label, 32)),
1042  'label_formatted_2' => dol_trunc($accountingaccount->label, 32),
1043  );
1044  } else {
1045  self::$accounting_account_cached[$account] = array(
1046  'found' => false,
1047  'label' => '',
1048  'code_formatted_1' => length_accounta(html_entity_decode($account)),
1049  'label_formatted_1' => '',
1050  'label_formatted_2' => '',
1051  );
1052  }
1053  }
1054 
1055  return self::$accounting_account_cached[$account];
1056  }
1057 }
length_accounta
length_accounta($accounta)
Return Auxiliary accounting account of thirdparties with defined length.
Definition: accounting.lib.php:133
Asset
Class for Asset.
Definition: asset.class.php:30
AccountingJournal\__construct
__construct($db)
Constructor.
Definition: accountingjournal.class.php:107
db
$conf db
API class for accounts.
Definition: inc.php:41
dol_trunc
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.
Definition: functions.lib.php:3805
AssetAccountancyCodes
Class for AssetAccountancyCodes.
Definition: assetaccountancycodes.class.php:29
ref
$object ref
Definition: info.php:77
rowid
print *****$script_file(".$version.") pid c cd cd cd description as p label as s rowid
Definition: email_expire_services_to_representatives.php:79
AccountingJournal\writeIntoBookkeeping
writeIntoBookkeeping(User $user, &$journal_data=array(), $max_nb_errors=10)
Write bookkeeping.
Definition: accountingjournal.class.php:803
CommonObject
Parent class of all other business classes (invoices, contracts, proposals, orders,...
Definition: commonobject.class.php:44
AccountingJournal\fetch
fetch($rowid=null, $journal_code=null)
Load an object from database.
Definition: accountingjournal.class.php:119
price2num
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
Definition: functions.lib.php:5661
dol_print_date
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
Definition: functions.lib.php:2514
getEntity
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
Definition: functions.lib.php:148
code
print *****$script_file(".$version.") pid code
! Closing after partial payment: discount_vat, badcustomer or badsupplier, bankcharge,...
Definition: sync_members_ldap2dolibarr.php:60
AccountingJournal
Class to manage accounting accounts.
Definition: accountingjournal.class.php:27
AccountingJournal\exportCsv
exportCsv(&$journal_data=array(), $search_date_end=0, $sep='')
Export journal CSV ISO and not UTF8 !
Definition: accountingjournal.class.php:950
AccountingJournal\LibType
LibType($nature, $mode=0)
Return type of an accounting journal.
Definition: accountingjournal.class.php:328
dol_syslog
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
Definition: functions.lib.php:1603
AccountingJournal\fetchAll
fetchAll($sortorder='', $sortfield='', $limit=0, $offset=0, array $filter=array(), $filtermode='AND')
Load object in memory from the database.
Definition: accountingjournal.class.php:173
AccountingJournal\getAccountingAccountInfos
getAccountingAccountInfos($account)
Get accounting account infos.
Definition: accountingjournal.class.php:1029
isModEnabled
isModEnabled($module)
Is Dolibarr module enabled.
Definition: functions.lib.php:105
BookKeeping
Class to manage Ledger (General Ledger and Subledger)
Definition: bookkeeping.class.php:33
AccountingAccount
Class to manage accounting accounts.
Definition: accountingaccount.class.php:36
User
Class to manage Dolibarr users.
Definition: user.class.php:44
img_object
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
Definition: functions.lib.php:4211
dol_now
dol_now($mode='auto')
Return date for now.
Definition: functions.lib.php:2845
$resql
if(isModEnabled('facture') &&!empty($user->rights->facture->lire)) if((isModEnabled('fournisseur') &&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->rights->fournisseur->facture->lire)||(isModEnabled('supplier_invoice') && $user->rights->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->rights->commande->lire &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $resql
Social contributions to pay.
Definition: index.php:742
AccountingJournal\getData
getData(User $user, $type='view', $date_start=null, $date_end=null, $in_bookkeeping='notyet')
Get journal data.
Definition: accountingjournal.class.php:378
price
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.
Definition: functions.lib.php:5541
AccountingJournal\getAssetData
getAssetData(User $user, $type='view', $date_start=null, $date_end=null, $in_bookkeeping='notyet')
Get asset data for various journal.
Definition: accountingjournal.class.php:428
AccountingJournal\getLibType
getLibType($mode=0)
Retourne le libelle du statut d'un user (actif, inactif)
Definition: accountingjournal.class.php:315
HookManager
Class to manage hooks.
Definition: hookmanager.class.php:30
AccountingJournal\getNomUrl
getNomUrl($withpicto=0, $withlabel=0, $nourl=0, $moretitle='', $notooltip=0)
Return clicable name (with picto eventually)
Definition: accountingjournal.class.php:240