dolibarr  19.0.0-dev
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  return "";
371  }
372 
373 
384  public function getData(User $user, $type = 'view', $date_start = null, $date_end = null, $in_bookkeeping = 'notyet')
385  {
386  global $hookmanager;
387 
388  // Clean parameters
389  if (empty($type)) $type = 'view';
390  if (empty($in_bookkeeping)) $in_bookkeeping = 'notyet';
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  $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";
453  $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";
454  $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";
455  $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation as ad";
456  $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "asset as a ON a.rowid = ad.fk_asset";
457  $sql .= " WHERE a.entity IN (" . getEntity('asset', 0) . ')'; // We don't share object for accountancy, we use source object sharing
458  if ($in_bookkeeping == 'already') {
459  $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')";
460  } elseif ($in_bookkeeping == 'notyet') {
461  $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')";
462  }
463  $sql .= " AND ad.ref != ''"; // not reversal lines
464  if ($date_start && $date_end) {
465  $sql .= " AND ad.depreciation_date >= '" . $this->db->idate($date_start) . "' AND ad.depreciation_date <= '" . $this->db->idate($date_end) . "'";
466  }
467  // Define begin binding date
468  if (!empty($conf->global->ACCOUNTING_DATE_START_BINDING)) {
469  $sql .= " AND ad.depreciation_date >= '" . $this->db->idate($conf->global->ACCOUNTING_DATE_START_BINDING) . "'";
470  }
471  $sql .= " ORDER BY ad.depreciation_date";
472 
473  dol_syslog(__METHOD__, LOG_DEBUG);
474  $resql = $this->db->query($sql);
475  if (!$resql) {
476  $this->errors[] = $this->db->lasterror();
477  return -1;
478  }
479 
480  $pre_data = array(
481  'elements' => array(),
482  );
483  while ($obj = $this->db->fetch_object($resql)) {
484  if (!isset($pre_data['elements'][$obj->rowid])) {
485  $pre_data['elements'][$obj->rowid] = array(
486  'ref' => $obj->asset_ref,
487  'label' => $obj->asset_label,
488  'acquisition_value_ht' => $obj->asset_acquisition_value_ht,
489  'depreciation' => array(),
490  );
491 
492  // Disposal infos
493  if (isset($obj->asset_disposal_date)) {
494  $pre_data['elements'][$obj->rowid]['disposal'] = array(
495  'date' => $this->db->jdate($obj->asset_disposal_date),
496  'amount' => $obj->asset_disposal_amount_ht,
497  'subject_to_vat' => !empty($obj->asset_disposal_subject_to_vat),
498  );
499  }
500  }
501 
502  $compta_debit = empty($obj->accountancy_code_debit) ? 'NotDefined' : $obj->accountancy_code_debit;
503  $compta_credit = empty($obj->accountancy_code_credit) ? 'NotDefined' : $obj->accountancy_code_credit;
504 
505  $pre_data['elements'][$obj->rowid]['depreciation'][$obj->depreciation_id] = array(
506  'date' => $this->db->jdate($obj->depreciation_date),
507  'ref' => $obj->depreciation_ref,
508  'lines' => array(
509  $compta_debit => -$obj->depreciation_ht,
510  $compta_credit => $obj->depreciation_ht,
511  ),
512  );
513  }
514 
515  $disposal_ref = $langs->transnoentitiesnoconv('AssetDisposal');
516  $journal = $this->code;
517  $journal_label = $this->label;
518  $journal_label_formatted = $langs->transnoentities($journal_label);
519  $now = dol_now();
520 
521  $element_static = new Asset($this->db);
522 
523  $journal_data = array();
524  foreach ($pre_data['elements'] as $pre_data_id => $pre_data_info) {
525  $element_static->id = $pre_data_id;
526  $element_static->ref = (string) $pre_data_info["ref"];
527  $element_static->label = (string) $pre_data_info["label"];
528  $element_static->acquisition_value_ht = $pre_data_info["acquisition_value_ht"];
529  $element_link = $element_static->getNomUrl(1, 'with_label');
530 
531  $element_name_formatted_0 = dol_trunc($element_static->label, 16);
532  $element_name_formatted_1 = utf8_decode(dol_trunc($element_static->label, 32));
533  $element_name_formatted_2 = utf8_decode(dol_trunc($element_static->label, 16));
534  $label_operation = $element_static->getNomUrl(0, 'label', 16);
535 
536  $element = array(
537  'ref' => dol_trunc($element_static->ref, 16, 'right', 'UTF-8', 1),
538  'error' => $pre_data_info['error'],
539  'blocks' => array(),
540  );
541 
542  // Depreciation lines
543  //--------------------
544  foreach ($pre_data_info['depreciation'] as $depreciation_id => $line) {
545  $depreciation_ref = $line["ref"];
546  $depreciation_date = $line["date"];
547  $depreciation_date_formatted = dol_print_date($depreciation_date, 'day');
548 
549  // lines
550  $blocks = array();
551  foreach ($line['lines'] as $account => $mt) {
552  $account_infos = $this->getAccountingAccountInfos($account);
553 
554  if ($type == 'view') {
555  $account_to_show = length_accounta($account);
556  if (($account_to_show == "") || $account_to_show == 'NotDefined') {
557  $account_to_show = '<span class="error">' . $langs->trans("AssetInAccountNotDefined") . '</span>';
558  }
559 
560  $blocks[] = array(
561  'date' => $depreciation_date_formatted,
562  'piece' => $element_link,
563  'account_accounting' => $account_to_show,
564  'subledger_account' => '',
565  'label_operation' => $label_operation . ' - ' . $depreciation_ref,
566  'debit' => $mt < 0 ? price(-$mt) : '',
567  'credit' => $mt >= 0 ? price($mt) : '',
568  );
569  } elseif ($type == 'bookkeeping') {
570  if ($account_infos['found']) {
571  $blocks[] = array(
572  'doc_date' => $depreciation_date,
573  'date_lim_reglement' => '',
574  'doc_ref' => $element_static->ref,
575  'date_creation' => $now,
576  'doc_type' => 'asset',
577  'fk_doc' => $element_static->id,
578  'fk_docdet' => $depreciation_id, // Useless, can be several lines that are source of this record to add
579  'thirdparty_code' => '',
580  'subledger_account' => '',
581  'subledger_label' => '',
582  'numero_compte' => $account,
583  'label_compte' => $account_infos['label'],
584  'label_operation' => $element_name_formatted_0 . ' - ' . $depreciation_ref,
585  'montant' => $mt,
586  'sens' => $mt < 0 ? 'D' : 'C',
587  'debit' => $mt < 0 ? -$mt : 0,
588  'credit' => $mt >= 0 ? $mt : 0,
589  'code_journal' => $journal,
590  'journal_label' => $journal_label_formatted,
591  'piece_num' => '',
592  'import_key' => '',
593  'fk_user_author' => $user->id,
594  'entity' => $conf->entity,
595  );
596  }
597  } else { // $type == 'csv'
598  $blocks[] = array(
599  $depreciation_date, // Date
600  $element_static->ref, // Piece
601  $account_infos['code_formatted_1'], // AccountAccounting
602  $element_name_formatted_0 . ' - ' . $depreciation_ref, // LabelOperation
603  $mt < 0 ? price(-$mt) : '', // Debit
604  $mt >= 0 ? price($mt) : '', // Credit
605  );
606  }
607  }
608  $element['blocks'][] = $blocks;
609  }
610 
611  // Disposal line
612  //--------------------
613  if (!empty($pre_data_info['disposal'])) {
614  $disposal_date = $pre_data_info['disposal']['date'];
615 
616  if ((!($date_start && $date_end) || ($date_start <= $disposal_date && $disposal_date <= $date_end)) &&
617  (empty($conf->global->ACCOUNTING_DATE_START_BINDING) || $conf->global->ACCOUNTING_DATE_START_BINDING <= $disposal_date)
618  ) {
619  $disposal_amount = $pre_data_info['disposal']['amount'];
620  $disposal_subject_to_vat = $pre_data_info['disposal']['subject_to_vat'];
621  $disposal_date_formatted = dol_print_date($disposal_date, 'day');
622  $disposal_vat = $conf->global->ASSET_DISPOSAL_VAT > 0 ? $conf->global->ASSET_DISPOSAL_VAT : 20;
623 
624  // Get accountancy codes
625  //---------------------------
626  require_once DOL_DOCUMENT_ROOT . '/asset/class/assetaccountancycodes.class.php';
627  $accountancy_codes = new AssetAccountancyCodes($this->db);
628  $result = $accountancy_codes->fetchAccountancyCodes($element_static->id);
629  if ($result < 0) {
630  $element['error'] = $accountancy_codes->errorsToString();
631  } else {
632  // Get last depreciation cumulative amount
633  $element_static->fetchDepreciationLines();
634  foreach ($element_static->depreciation_lines as $mode_key => $depreciation_lines) {
635  $accountancy_codes_list = $accountancy_codes->accountancy_codes[$mode_key];
636 
637  if (!isset($accountancy_codes_list['value_asset_sold'])) {
638  continue;
639  }
640 
641  $accountancy_code_value_asset_sold = empty($accountancy_codes_list['value_asset_sold']) ? 'NotDefined' : $accountancy_codes_list['value_asset_sold'];
642  $accountancy_code_depreciation_asset = empty($accountancy_codes_list['depreciation_asset']) ? 'NotDefined' : $accountancy_codes_list['depreciation_asset'];
643  $accountancy_code_asset = empty($accountancy_codes_list['asset']) ? 'NotDefined' : $accountancy_codes_list['asset'];
644  $accountancy_code_receivable_on_assignment = empty($accountancy_codes_list['receivable_on_assignment']) ? 'NotDefined' : $accountancy_codes_list['receivable_on_assignment'];
645  $accountancy_code_vat_collected = empty($accountancy_codes_list['vat_collected']) ? 'NotDefined' : $accountancy_codes_list['vat_collected'];
646  $accountancy_code_proceeds_from_sales = empty($accountancy_codes_list['proceeds_from_sales']) ? 'NotDefined' : $accountancy_codes_list['proceeds_from_sales'];
647 
648  $last_cumulative_amount_ht = 0;
649  $depreciated_ids = array_keys($pre_data_info['depreciation']);
650  foreach ($depreciation_lines as $line) {
651  $last_cumulative_amount_ht = $line['cumulative_depreciation_ht'];
652  if (!in_array($line['id'], $depreciated_ids) && empty($line['bookkeeping']) && !empty($line['ref'])) {
653  break;
654  }
655  }
656 
657  $lines = array();
658  $lines[0][$accountancy_code_value_asset_sold] = -($element_static->acquisition_value_ht - $last_cumulative_amount_ht);
659  $lines[0][$accountancy_code_depreciation_asset] = -$last_cumulative_amount_ht;
660  $lines[0][$accountancy_code_asset] = $element_static->acquisition_value_ht;
661 
662  $disposal_amount_vat = $disposal_subject_to_vat ? (double) price2num($disposal_amount * $disposal_vat / 100, 'MT') : 0;
663  $lines[1][$accountancy_code_receivable_on_assignment] = -($disposal_amount + $disposal_amount_vat);
664  if ($disposal_subject_to_vat) $lines[1][$accountancy_code_vat_collected] = $disposal_amount_vat;
665  $lines[1][$accountancy_code_proceeds_from_sales] = $disposal_amount;
666 
667  foreach ($lines as $lines_block) {
668  $blocks = array();
669  foreach ($lines_block as $account => $mt) {
670  $account_infos = $this->getAccountingAccountInfos($account);
671 
672  if ($type == 'view') {
673  $account_to_show = length_accounta($account);
674  if (($account_to_show == "") || $account_to_show == 'NotDefined') {
675  $account_to_show = '<span class="error">' . $langs->trans("AssetInAccountNotDefined") . '</span>';
676  }
677 
678  $blocks[] = array(
679  'date' => $disposal_date_formatted,
680  'piece' => $element_link,
681  'account_accounting' => $account_to_show,
682  'subledger_account' => '',
683  'label_operation' => $label_operation . ' - ' . $disposal_ref,
684  'debit' => $mt < 0 ? price(-$mt) : '',
685  'credit' => $mt >= 0 ? price($mt) : '',
686  );
687  } elseif ($type == 'bookkeeping') {
688  if ($account_infos['found']) {
689  $blocks[] = array(
690  'doc_date' => $disposal_date,
691  'date_lim_reglement' => '',
692  'doc_ref' => $element_static->ref,
693  'date_creation' => $now,
694  'doc_type' => 'asset',
695  'fk_doc' => $element_static->id,
696  'fk_docdet' => 0, // Useless, can be several lines that are source of this record to add
697  'thirdparty_code' => '',
698  'subledger_account' => '',
699  'subledger_label' => '',
700  'numero_compte' => $account,
701  'label_compte' => $account_infos['label'],
702  'label_operation' => $element_name_formatted_0 . ' - ' . $disposal_ref,
703  'montant' => $mt,
704  'sens' => $mt < 0 ? 'D' : 'C',
705  'debit' => $mt < 0 ? -$mt : 0,
706  'credit' => $mt >= 0 ? $mt : 0,
707  'code_journal' => $journal,
708  'journal_label' => $journal_label_formatted,
709  'piece_num' => '',
710  'import_key' => '',
711  'fk_user_author' => $user->id,
712  'entity' => $conf->entity,
713  );
714  }
715  } else { // $type == 'csv'
716  $blocks[] = array(
717  $disposal_date, // Date
718  $element_static->ref, // Piece
719  $account_infos['code_formatted_1'], // AccountAccounting
720  $element_name_formatted_0 . ' - ' . $disposal_ref, // LabelOperation
721  $mt < 0 ? price(-$mt) : '', // Debit
722  $mt >= 0 ? price($mt) : '', // Credit
723  );
724  }
725  }
726  $element['blocks'][] = $blocks;
727  }
728  }
729  }
730  }
731  }
732 
733  $journal_data[(int) $pre_data_id] = $element;
734  }
735  unset($pre_data);
736 
737  return $journal_data;
738  }
739 
783  public function writeIntoBookkeeping(User $user, &$journal_data = array(), $max_nb_errors = 10)
784  {
785  global $conf, $langs, $hookmanager;
786  require_once DOL_DOCUMENT_ROOT . '/accountancy/class/bookkeeping.class.php';
787 
788  $error = 0;
789 
790  $hookmanager->initHooks(array('accountingjournaldao'));
791  $parameters = array('journal_data' => &$journal_data);
792  $reshook = $hookmanager->executeHooks('writeBookkeeping', $parameters, $this); // Note that $action and $object may have been
793  if ($reshook < 0) {
794  $this->error = $hookmanager->error;
795  $this->errors = $hookmanager->errors;
796  return -1;
797  } elseif (empty($reshook)) {
798  // Clean parameters
799  $journal_data = is_array($journal_data) ? $journal_data : array();
800 
801  foreach ($journal_data as $element_id => $element) {
802  $error_for_line = 0;
803  $total_credit = 0;
804  $total_debit = 0;
805 
806  $this->db->begin();
807 
808  if ($element['error'] == 'somelinesarenotbound') {
809  $error++;
810  $error_for_line++;
811  $this->errors[] = $langs->trans('ErrorInvoiceContainsLinesNotYetBounded', $element['ref']);
812  }
813 
814  if (!$error_for_line) {
815  foreach ($element['blocks'] as $lines) {
816  foreach ($lines as $line) {
817  $bookkeeping = new BookKeeping($this->db);
818  $bookkeeping->doc_date = $line['doc_date'];
819  $bookkeeping->date_lim_reglement = $line['date_lim_reglement'];
820  $bookkeeping->doc_ref = $line['doc_ref'];
821  $bookkeeping->date_creation = $line['date_creation']; // not used
822  $bookkeeping->doc_type = $line['doc_type'];
823  $bookkeeping->fk_doc = $line['fk_doc'];
824  $bookkeeping->fk_docdet = $line['fk_docdet'];
825  $bookkeeping->thirdparty_code = $line['thirdparty_code'];
826  $bookkeeping->subledger_account = $line['subledger_account'];
827  $bookkeeping->subledger_label = $line['subledger_label'];
828  $bookkeeping->numero_compte = $line['numero_compte'];
829  $bookkeeping->label_compte = $line['label_compte'];
830  $bookkeeping->label_operation = $line['label_operation'];
831  $bookkeeping->montant = $line['montant'];
832  $bookkeeping->sens = $line['sens'];
833  $bookkeeping->debit = $line['debit'];
834  $bookkeeping->credit = $line['credit'];
835  $bookkeeping->code_journal = $line['code_journal'];
836  $bookkeeping->journal_label = $line['journal_label'];
837  $bookkeeping->piece_num = $line['piece_num'];
838  $bookkeeping->import_key = $line['import_key'];
839  $bookkeeping->fk_user_author = $user->id;
840  $bookkeeping->entity = $conf->entity;
841 
842  $total_debit += $bookkeeping->debit;
843  $total_credit += $bookkeeping->credit;
844 
845  $result = $bookkeeping->create($user);
846  if ($result < 0) {
847  if ($bookkeeping->error == 'BookkeepingRecordAlreadyExists') { // Already exists
848  $error++;
849  $error_for_line++;
850  $journal_data[$element_id]['error'] = 'alreadyjournalized';
851  } else {
852  $error++;
853  $error_for_line++;
854  $journal_data[$element_id]['error'] = 'other';
855  $this->errors[] = $bookkeeping->errorsToString();
856  }
857  }
858  //
859  // if (!$error_for_line && isModEnabled('asset') && $this->nature == 1 && $bookkeeping->fk_doc > 0) {
860  // // Set last cumulative depreciation
861  // require_once DOL_DOCUMENT_ROOT . '/asset/class/asset.class.php';
862  // $asset = new Asset($this->db);
863  // $result = $asset->setLastCumulativeDepreciation($bookkeeping->fk_doc);
864  // if ($result < 0) {
865  // $error++;
866  // $error_for_line++;
867  // $journal_data[$element_id]['error'] = 'other';
868  // $this->errors[] = $asset->errorsToString();
869  // }
870  // }
871  }
872 
873  if ($error_for_line) {
874  break;
875  }
876  }
877  }
878 
879  // Protection against a bug on lines before
880  if (!$error_for_line && (price2num($total_debit, 'MT') != price2num($total_credit, 'MT'))) {
881  $error++;
882  $error_for_line++;
883  $journal_data[$element_id]['error'] = 'amountsnotbalanced';
884  $this->errors[] = 'Try to insert a non balanced transaction in book for ' . $element['blocks'] . '. Canceled. Surely a bug.';
885  }
886 
887  if (!$error_for_line) {
888  $this->db->commit();
889  } else {
890  $this->db->rollback();
891 
892  if ($error >= $max_nb_errors) {
893  $this->errors[] = $langs->trans("ErrorTooManyErrorsProcessStopped");
894  break; // Break in the foreach
895  }
896  }
897  }
898  }
899 
900  return $error ? -$error : 1;
901  }
902 
924  public function exportCsv(&$journal_data = array(), $search_date_end = 0, $sep = '')
925  {
926  global $conf, $langs, $hookmanager;
927 
928  if (empty($sep)) $sep = $conf->global->ACCOUNTING_EXPORT_SEPARATORCSV;
929  $out = '';
930 
931  // Hook
932  $hookmanager->initHooks(array('accountingjournaldao'));
933  $parameters = array('journal_data' => &$journal_data, 'search_date_end' => &$search_date_end, 'sep' => &$sep, 'out' => &$out);
934  $reshook = $hookmanager->executeHooks('exportCsv', $parameters, $this); // Note that $action and $object may have been
935  if ($reshook < 0) {
936  $this->error = $hookmanager->error;
937  $this->errors = $hookmanager->errors;
938  return -1;
939  } elseif (empty($reshook)) {
940  // Clean parameters
941  $journal_data = is_array($journal_data) ? $journal_data : array();
942 
943  // CSV header line
944  $header = array();
945  if ($this->nature == 4) {
946  $header = array(
947  $langs->transnoentitiesnoconv("BankId"),
948  $langs->transnoentitiesnoconv("Date"),
949  $langs->transnoentitiesnoconv("PaymentMode"),
950  $langs->transnoentitiesnoconv("AccountAccounting"),
951  $langs->transnoentitiesnoconv("LedgerAccount"),
952  $langs->transnoentitiesnoconv("SubledgerAccount"),
953  $langs->transnoentitiesnoconv("Label"),
954  $langs->transnoentitiesnoconv("AccountingDebit"),
955  $langs->transnoentitiesnoconv("AccountingCredit"),
956  $langs->transnoentitiesnoconv("Journal"),
957  $langs->transnoentitiesnoconv("Note"),
958  );
959  } elseif ($this->nature == 5) {
960  $header = array(
961  $langs->transnoentitiesnoconv("Date"),
962  $langs->transnoentitiesnoconv("Piece"),
963  $langs->transnoentitiesnoconv("AccountAccounting"),
964  $langs->transnoentitiesnoconv("LabelOperation"),
965  $langs->transnoentitiesnoconv("AccountingDebit"),
966  $langs->transnoentitiesnoconv("AccountingCredit"),
967  );
968  } elseif ($this->nature == 1) {
969  $header = array(
970  $langs->transnoentitiesnoconv("Date"),
971  $langs->transnoentitiesnoconv("Piece"),
972  $langs->transnoentitiesnoconv("AccountAccounting"),
973  $langs->transnoentitiesnoconv("LabelOperation"),
974  $langs->transnoentitiesnoconv("AccountingDebit"),
975  $langs->transnoentitiesnoconv("AccountingCredit"),
976  );
977  }
978 
979  if (!empty($header)) $out .= '"' . implode('"' . $sep . '"', $header) . '"' . "\n";
980  foreach ($journal_data as $element_id => $element) {
981  foreach ($element['blocks'] as $lines) {
982  foreach ($lines as $line) {
983  $out .= '"' . implode('"' . $sep . '"', $line) . '"' . "\n";
984  }
985  }
986  }
987  }
988 
989  return $out;
990  }
991 
998  public function getAccountingAccountInfos($account)
999  {
1000  if (!isset(self::$accounting_account_cached[$account])) {
1001  require_once DOL_DOCUMENT_ROOT . '/core/lib/accounting.lib.php';
1002  require_once DOL_DOCUMENT_ROOT . '/accountancy/class/accountingaccount.class.php';
1003  $accountingaccount = new AccountingAccount($this->db);
1004  $result = $accountingaccount->fetch(null, $account, true);
1005  if ($result > 0) {
1006  self::$accounting_account_cached[$account] = array(
1007  'found' => true,
1008  'label' => $accountingaccount->label,
1009  'code_formatted_1' => length_accounta(html_entity_decode($account)),
1010  'label_formatted_1' => utf8_decode(dol_trunc($accountingaccount->label, 32)),
1011  'label_formatted_2' => dol_trunc($accountingaccount->label, 32),
1012  );
1013  } else {
1014  self::$accounting_account_cached[$account] = array(
1015  'found' => false,
1016  'label' => '',
1017  'code_formatted_1' => length_accounta(html_entity_decode($account)),
1018  'label_formatted_1' => '',
1019  'label_formatted_2' => '',
1020  );
1021  }
1022  }
1023 
1024  return self::$accounting_account_cached[$account];
1025  }
1026 }
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 journals.
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)
Return the label of the status.
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 Dolibarr users.
Definition: user.class.php:48
if(isModEnabled('facture') && $user->hasRight('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') && $user->hasRight('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)) $sql
Social contributions to pay.
Definition: index.php:746
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.
print *****$script_file(".$version.") pid code
! Closing after partial payment: discount_vat, badcustomer or badsupplier, bankcharge,...