dolibarr  19.0.0-dev
asset.class.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2017 Laurent Destailleur <eldy@users.sourceforge.net>
3  * Copyright (C) 2018 Alexandre Spangaro <aspangaro@open-dsi.fr>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <https://www.gnu.org/licenses/>.
17  */
18 
25 require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
26 
30 class Asset extends CommonObject
31 {
35  public $module = 'asset';
36 
40  public $element = 'asset';
41 
45  public $table_element = 'asset';
46 
51  public $ismultientitymanaged = 1;
52 
56  public $isextrafieldmanaged = 1;
57 
61  public $picto = 'asset';
62 
63  const STATUS_DRAFT = 0; // In progress
64  const STATUS_DISPOSED = 9; // Disposed
65 
97  public $fields=array(
98  'rowid' => array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>'1', 'position'=>1, 'notnull'=>1, 'visible'=>0, 'noteditable'=>'1', 'index'=>1, 'css'=>'left', 'comment'=>"Id"),
99  'ref' => array('type'=>'varchar(128)', 'label'=>'Ref', 'enabled'=>'1', 'position'=>20, 'notnull'=>1, 'visible'=>1, 'noteditable'=>'0', 'index'=>1, 'searchall'=>1, 'showoncombobox'=>'1', 'validate'=>'1', 'comment'=>"Reference of object"),
100  'label' => array('type'=>'varchar(255)', 'label'=>'Label', 'enabled'=>'1', 'position'=>30, 'notnull'=>1, 'visible'=>1, 'searchall'=>1, 'css'=>'minwidth300', 'cssview'=>'wordbreak', 'showoncombobox'=>'2', 'validate'=>'1',),
101  'fk_asset_model' => array('type'=>'integer:AssetModel:asset/class/assetmodel.class.php:1:((status:=:1) and (entity:IN:__SHARED_ENTITIES__))', 'label'=>'AssetModel', 'enabled'=>'1', 'position'=>40, 'notnull'=>0, 'visible'=>1, 'index'=>1, 'validate'=>'1',),
102  'qty' => array('type'=>'real', 'label'=>'Qty', 'enabled'=>'1', 'position'=>50, 'notnull'=>1, 'visible'=>0, 'default'=>'1', 'isameasure'=>'1', 'css'=>'maxwidth75imp', 'validate'=>'1',),
103  'acquisition_type' => array('type'=>'smallint', 'label'=>'AssetAcquisitionType', 'enabled'=>'1', 'position'=>60, 'notnull'=>1, 'visible'=>1, 'arrayofkeyval'=>array('0'=>'AssetAcquisitionTypeNew', '1'=>'AssetAcquisitionTypeOccasion'), 'validate'=>'1',),
104  'asset_type' => array('type'=>'smallint', 'label'=>'AssetType', 'enabled'=>'1', 'position'=>70, 'notnull'=>1, 'visible'=>1, 'arrayofkeyval'=>array('0'=>'AssetTypeIntangible', '1'=>'AssetTypeTangible', '2'=>'AssetTypeInProgress', '3'=>'AssetTypeFinancial'), 'validate'=>'1',),
105  'not_depreciated' => array('type'=>'boolean', 'label'=>'AssetNotDepreciated', 'enabled'=>'1', 'position'=>80, 'notnull'=>0, 'default'=>'0', 'visible'=>1, 'validate'=>'1',),
106  'date_acquisition' => array('type'=>'date', 'label'=>'AssetDateAcquisition', 'enabled'=>'1', 'position'=>90, 'notnull'=>1, 'visible'=>1,),
107  'date_start' => array('type'=>'date', 'label'=>'AssetDateStart', 'enabled'=>'1', 'position'=>100, 'notnull'=>0, 'visible'=>-1,),
108  'acquisition_value_ht' => array('type'=>'price', 'label'=>'AssetAcquisitionValueHT', 'enabled'=>'1', 'position'=>110, 'notnull'=>1, 'visible'=>1, 'isameasure'=>'1', 'validate'=>'1',),
109  'recovered_vat' => array('type'=>'price', 'label'=>'AssetRecoveredVAT', 'enabled'=>'1', 'position'=>120, 'notnull'=>0, 'visible'=>1, 'isameasure'=>'1', 'validate'=>'1',),
110  'reversal_date' => array('type'=>'date', 'label'=>'AssetReversalDate', 'enabled'=>'1', 'position'=>130, 'notnull'=>0, 'visible'=>1,),
111  'reversal_amount_ht' => array('type'=>'price', 'label'=>'AssetReversalAmountHT', 'enabled'=>'1', 'position'=>140, 'notnull'=>0, 'visible'=>1, 'isameasure'=>'1', 'validate'=>'1',),
112  'disposal_date' => array('type'=>'date', 'label'=>'AssetDisposalDate', 'enabled'=>'1', 'position'=>200, 'notnull'=>0, 'visible'=>-2,),
113  'disposal_amount_ht' => array('type'=>'price', 'label'=>'AssetDisposalAmount', 'enabled'=>'1', 'position'=>210, 'notnull'=>0, 'visible'=>-2, 'default'=>'0', 'isameasure'=>'1', 'validate'=>'1',),
114  'fk_disposal_type' => array('type'=>'sellist:c_asset_disposal_type:label:rowid::active=1', 'label'=>'AssetDisposalType', 'enabled'=>'1', 'position'=>220, 'notnull'=>0, 'visible'=>-2, 'index'=>1, 'validate'=>'1',),
115  'disposal_depreciated' => array('type'=>'boolean', 'label'=>'AssetDisposalDepreciated', 'enabled'=>'1', 'position'=>230, 'notnull'=>0, 'default'=>'0', 'visible'=>-2, 'validate'=>'1',),
116  'disposal_subject_to_vat' => array('type'=>'boolean', 'label'=>'AssetDisposalSubjectToVat', 'enabled'=>'1', 'position'=>240, 'notnull'=>0, 'default'=>'0', 'visible'=>-2, 'validate'=>'1',),
117  'note_public' => array('type'=>'html', 'label'=>'NotePublic', 'enabled'=>'1', 'position'=>300, 'notnull'=>0, 'visible'=>0, 'validate'=>'1',),
118  'note_private' => array('type'=>'html', 'label'=>'NotePrivate', 'enabled'=>'1', 'position'=>301, 'notnull'=>0, 'visible'=>0, 'validate'=>'1',),
119  'date_creation' => array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>'1', 'position'=>500, 'notnull'=>1, 'visible'=>-2,),
120  'tms' => array('type'=>'timestamp', 'label'=>'DateModification', 'enabled'=>'1', 'position'=>501, 'notnull'=>0, 'visible'=>-2,),
121  'fk_user_creat' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserAuthor', 'enabled'=>'1', 'position'=>510, 'notnull'=>1, 'visible'=>-2, 'foreignkey'=>'user.rowid',),
122  'fk_user_modif' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserModif', 'enabled'=>'1', 'position'=>511, 'notnull'=>-1, 'visible'=>-2,),
123  'last_main_doc' => array('type'=>'varchar(255)', 'label'=>'LastMainDoc', 'enabled'=>'1', 'position'=>600, 'notnull'=>0, 'visible'=>0,),
124  'import_key' => array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>'1', 'position'=>1000, 'notnull'=>-1, 'visible'=>-2,),
125  'model_pdf' => array('type'=>'varchar(255)', 'label'=>'Model pdf', 'enabled'=>'1', 'position'=>1010, 'notnull'=>-1, 'visible'=>0,),
126  'status' => array('type'=>'smallint', 'label'=>'Status', 'enabled'=>'1', 'position'=>1000, 'notnull'=>1, 'default'=>'0', 'visible'=>2, 'index'=>1, 'arrayofkeyval'=>array('0'=>'Draft', '1'=>'Validated', '9'=>'Canceled'), 'validate'=>'1',),
127  );
128  public $rowid;
129  public $ref;
130  public $label;
131  public $fk_asset_model;
132  public $reversal_amount_ht;
133  public $acquisition_value_ht;
134  public $recovered_vat;
135  public $reversal_date;
136  public $date_acquisition;
137  public $date_start;
138  public $qty;
139  public $acquisition_type;
140  public $asset_type;
141  public $not_depreciated;
142  public $disposal_date;
143  public $disposal_amount_ht;
144  public $fk_disposal_type;
145  public $disposal_depreciated;
146  public $disposal_subject_to_vat;
147  public $supplier_invoice_id;
148  public $note_public;
149  public $note_private;
150  public $date_creation;
151  public $tms;
152  public $fk_user_creat;
153  public $fk_user_modif;
154  public $last_main_doc;
155  public $import_key;
156  public $model_pdf;
157  public $status;
158  public $user_cloture_id;
159 
163  public $oldcopy;
164 
165 
169  public $asset_depreciation_options;
173  public $depreciation_lines = array();
174 
180  public function __construct(DoliDB $db)
181  {
182  global $conf, $langs;
183 
184  $this->db = $db;
185 
186  if (empty($conf->global->MAIN_SHOW_TECHNICAL_ID) && isset($this->fields['rowid'])) {
187  $this->fields['rowid']['visible'] = 0;
188  }
189  if (!isModEnabled('multicompany') && isset($this->fields['entity'])) {
190  $this->fields['entity']['enabled'] = 0;
191  }
192 
193  // Unset fields that are disabled
194  foreach ($this->fields as $key => $val) {
195  if (isset($val['enabled']) && empty($val['enabled'])) {
196  unset($this->fields[$key]);
197  }
198  }
199 
200  // Translate some data of arrayofkeyval
201  if (is_object($langs)) {
202  foreach ($this->fields as $key => $val) {
203  if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
204  foreach ($val['arrayofkeyval'] as $key2 => $val2) {
205  $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2);
206  }
207  }
208  }
209  }
210  }
211 
219  public function create(User $user, $notrigger = false)
220  {
221  if (!isset($this->date_start) || $this->date_start === "") $this->date_start = $this->date_acquisition;
222 
223  $this->db->begin();
224 
225  $result = $result_create = $this->createCommon($user, $notrigger);
226  if ($result > 0 && $this->fk_asset_model > 0) $result = $this->setDataFromAssetModel($user, $notrigger);
227  if ($result > 0) {
228  if ($this->supplier_invoice_id > 0) $this->add_object_linked('invoice_supplier', $this->supplier_invoice_id);
229  }
230 
231  if ($result < 0) {
232  $this->db->rollback();
233  } else {
234  $this->db->commit();
235  }
236 
237  return $result > 0 ? $result_create : $result;
238  }
239 
247  public function createFromClone(User $user, $fromid)
248  {
249  global $langs, $extrafields;
250  $error = 0;
251 
252  dol_syslog(__METHOD__, LOG_DEBUG);
253 
254  // $object = new self($this->db);
255  //
256  // $this->db->begin();
257  //
258  // // Load source object
259  // $result = $object->fetchCommon($fromid);
260  // if ($result > 0 && !empty($object->table_element_line)) {
261  // $object->fetchLines();
262  // }
263  //
264  // // get lines so they will be clone
265  // //foreach($this->lines as $line)
266  // // $line->fetch_optionals();
267  //
268  // // Reset some properties
269  // unset($object->id);
270  // unset($object->fk_user_creat);
271  // unset($object->import_key);
272  //
273  // // Clear fields
274  // if (property_exists($object, 'ref')) {
275  // $object->ref = empty($this->fields['ref']['default']) ? "Copy_Of_".$object->ref : $this->fields['ref']['default'];
276  // }
277  // if (property_exists($object, 'label')) {
278  // $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf")." ".$object->label : $this->fields['label']['default'];
279  // }
280  // if (property_exists($object, 'status')) {
281  // $object->status = self::STATUS_DRAFT;
282  // }
283  // if (property_exists($object, 'date_creation')) {
284  // $object->date_creation = dol_now();
285  // }
286  // if (property_exists($object, 'date_modification')) {
287  // $object->date_modification = null;
288  // }
289  // // ...
290  // // Clear extrafields that are unique
291  // if (is_array($object->array_options) && count($object->array_options) > 0) {
292  // $extrafields->fetch_name_optionals_label($this->table_element);
293  // foreach ($object->array_options as $key => $option) {
294  // $shortkey = preg_replace('/options_/', '', $key);
295  // if (!empty($extrafields->attributes[$this->table_element]['unique'][$shortkey])) {
296  // //var_dump($key); var_dump($clonedObj->array_options[$key]); exit;
297  // unset($object->array_options[$key]);
298  // }
299  // }
300  // }
301  //
302  // // Create clone
303  // $object->context['createfromclone'] = 'createfromclone';
304  // $result = $object->createCommon($user);
305  // if ($result < 0) {
306  // $error++;
307  // $this->error = $object->error;
308  // $this->errors = $object->errors;
309  // }
310  //
311  // if (!$error) {
312  // // copy internal contacts
313  // if ($this->copy_linked_contact($object, 'internal') < 0) {
314  // $error++;
315  // }
316  // }
317  //
318  // if (!$error) {
319  // // copy external contacts if same company
320  // if (property_exists($this, 'fk_soc') && $this->fk_soc == $object->socid) {
321  // if ($this->copy_linked_contact($object, 'external') < 0) {
322  // $error++;
323  // }
324  // }
325  // }
326  //
327  // unset($object->context['createfromclone']);
328  //
329  // // End
330  // if (!$error) {
331  // $this->db->commit();
332  // return $object;
333  // } else {
334  // $this->db->rollback();
335  // return -1;
336  // }
337  return -1;
338  }
339 
347  public function fetch($id, $ref = null)
348  {
349  $result = $this->fetchCommon($id, $ref);
350  if ($result > 0) {
351  if (!empty($this->table_element_line)) $this->fetchLines();
352 
353  $res = $this->hasDepreciationLinesInBookkeeping();
354  if ($res < 0) {
355  return -1;
356  } elseif ($res > 0) {
357  $this->fields['date_acquisition']['noteditable'] = '1';
358  $this->fields['date_start']['noteditable'] = '1';
359  $this->fields['acquisition_value_ht']['noteditable'] = '1';
360  $this->fields['recovered_vat']['noteditable'] = '1';
361  $this->fields['reversal_date']['noteditable'] = '1';
362  $this->fields['reversal_amount_ht']['noteditable'] = '1';
363  }
364  }
365  return $result;
366  }
367 
373  public function fetchLines()
374  {
375  $this->lines = array();
376 
377  return 1;
378  }
379 
380 
392  public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND')
393  {
394  global $conf;
395 
396  dol_syslog(__METHOD__, LOG_DEBUG);
397 
398  $records = array();
399 
400  $sql = "SELECT ";
401  $sql .= $this->getFieldList('t');
402  $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as t";
403  if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
404  $sql .= " WHERE t.entity IN (".getEntity($this->element).")";
405  } else {
406  $sql .= " WHERE 1 = 1";
407  }
408  // Manage filter
409  $sqlwhere = array();
410  if (count($filter) > 0) {
411  foreach ($filter as $key => $value) {
412  if ($key == 't.rowid') {
413  $sqlwhere[] = $key." = ".((int) $value);
414  } elseif (in_array($this->fields[$key]['type'], array('date', 'datetime', 'timestamp'))) {
415  $sqlwhere[] = $key." = '".$this->db->idate($value)."'";
416  } elseif ($key == 'customsql') {
417  $sqlwhere[] = $value;
418  } elseif (strpos($value, '%') === false) {
419  $sqlwhere[] = $key." IN (".$this->db->sanitize($this->db->escape($value)).")";
420  } else {
421  $sqlwhere[] = $key." LIKE '%".$this->db->escape($value)."%'";
422  }
423  }
424  }
425  if (count($sqlwhere) > 0) {
426  $sql .= " AND (".implode(" ".$filtermode." ", $sqlwhere).")";
427  }
428 
429  if (!empty($sortfield)) {
430  $sql .= $this->db->order($sortfield, $sortorder);
431  }
432  if (!empty($limit)) {
433  $sql .= $this->db->plimit($limit, $offset);
434  }
435 
436  $resql = $this->db->query($sql);
437  if ($resql) {
438  $num = $this->db->num_rows($resql);
439  $i = 0;
440  while ($i < ($limit ? min($limit, $num) : $num)) {
441  $obj = $this->db->fetch_object($resql);
442 
443  $record = new self($this->db);
444  $record->setVarsFromFetchObj($obj);
445 
446  $records[$record->id] = $record;
447 
448  $i++;
449  }
450  $this->db->free($resql);
451 
452  return $records;
453  } else {
454  $this->errors[] = 'Error '.$this->db->lasterror();
455  dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
456 
457  return -1;
458  }
459  }
460 
468  public function update(User $user, $notrigger = false)
469  {
470  if (!isset($this->date_start) || $this->date_start === "") $this->date_start = $this->date_acquisition;
471 
472  $this->db->begin();
473 
474  $result = $this->updateCommon($user, $notrigger);
475  if ($result > 0 && $this->fk_asset_model > 0 && $this->fk_asset_model != $this->oldcopy->fk_asset_model) {
476  $result = $this->setDataFromAssetModel($user, $notrigger);
477  }
478  if ($result > 0 && (
479  $this->date_start != $this->oldcopy->date_start ||
480  $this->acquisition_value_ht != $this->oldcopy->acquisition_value_ht ||
481  $this->reversal_date != $this->oldcopy->reversal_date ||
482  $this->reversal_amount_ht != $this->oldcopy->reversal_amount_ht ||
483  ($this->fk_asset_model > 0 && $this->fk_asset_model != $this->oldcopy->fk_asset_model)
484  )
485  ) {
486  $result = $this->calculationDepreciation();
487  }
488 
489  if ($result < 0) {
490  $this->db->rollback();
491  } else {
492  $this->db->commit();
493  }
494 
495  return $result;
496  }
497 
505  public function delete(User $user, $notrigger = false)
506  {
507  return $this->deleteCommon($user, $notrigger);
508  //return $this->deleteCommon($user, $notrigger, 1);
509  }
510 
518  public function setDataFromAssetModel(User $user, $notrigger = false)
519  {
520  global $langs;
521  $langs->load('assets');
522 
523  // Clean parameters
524  $this->id = $this->id > 0 ? $this->id : 0;
525  $this->fk_asset_model = $this->fk_asset_model > 0 ? $this->fk_asset_model : 0;
526 
527  // Check parameters
528  $error = 0;
529  if (empty($this->id)) {
530  $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Asset") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
531  $error++;
532  }
533  if (empty($this->fk_asset_model)) {
534  $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("AssetModel") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
535  $error++;
536  }
537  if ($error) {
538  return -1;
539  }
540 
541  $this->db->begin();
542 
543  // Get depreciation options
544  //---------------------------
545  require_once DOL_DOCUMENT_ROOT . '/asset/class/assetdepreciationoptions.class.php';
546  $options_model = new AssetDepreciationOptions($this->db);
547  $result = $options_model->fetchDeprecationOptions(0, $this->fk_asset_model);
548  if ($result < 0) {
549  $this->error = $options_model->error;
550  $this->errors = $options_model->errors;
551  $error++;
552  } elseif ($result > 0) {
553  $options = new AssetDepreciationOptions($this->db);
554  $result = $options->fetchDeprecationOptions($this->id);
555  if ($result < 0) {
556  $this->error = $options->error;
557  $this->errors = $options->errors;
558  $error++;
559  }
560 
561  if (!$error) {
562  foreach ($options_model->deprecation_options as $mode_key => $fields) {
563  foreach ($fields as $field_key => $value) {
564  $options->deprecation_options[$mode_key][$field_key] = $value;
565  }
566  }
567 
568  $result = $options->updateDeprecationOptions($user, $this->id, 0, $notrigger);
569  if ($result < 0) {
570  $this->error = $options->error;
571  $this->errors = $options->errors;
572  $error++;
573  }
574  }
575  }
576 
577  // Get accountancy codes
578  //---------------------------
579  if (!$error) {
580  require_once DOL_DOCUMENT_ROOT . '/asset/class/assetaccountancycodes.class.php';
581  $accountancy_codes_model = new AssetAccountancyCodes($this->db);
582  $result = $accountancy_codes_model->fetchAccountancyCodes(0, $this->fk_asset_model);
583  if ($result < 0) {
584  $this->error = $accountancy_codes_model->error;
585  $this->errors = $accountancy_codes_model->errors;
586  $error++;
587  } elseif ($result > 0) {
588  $accountancy_codes = new AssetAccountancyCodes($this->db);
589  $result = $accountancy_codes->fetchAccountancyCodes($this->id);
590  if ($result < 0) {
591  $this->error = $accountancy_codes->error;
592  $this->errors = $accountancy_codes->errors;
593  $error++;
594  }
595 
596  if (!$error) {
597  foreach ($accountancy_codes_model->accountancy_codes as $mode_key => $fields) {
598  foreach ($fields as $field_key => $value) {
599  $accountancy_codes->accountancy_codes[$mode_key][$field_key] = $value;
600  }
601  }
602 
603  $result = $accountancy_codes->updateAccountancyCodes($user, $this->id, 0, $notrigger);
604  if ($result < 0) {
605  $this->error = $accountancy_codes->error;
606  $this->errors = $accountancy_codes->errors;
607  $error++;
608  }
609  }
610  }
611  }
612 
613  if ($error) {
614  $this->db->rollback();
615  return -1;
616  } else {
617  $this->db->commit();
618  return 1;
619  }
620  }
621 
627  public function fetchDepreciationLines()
628  {
629  global $langs;
630  $langs->load('assets');
631  $this->depreciation_lines = array();
632 
633  // Clean parameters
634  $this->id = $this->id > 0 ? $this->id : 0;
635 
636  // Check parameters
637  $error = 0;
638  if (empty($this->id)) {
639  $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Asset") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
640  $error++;
641  }
642  if ($error) {
643  return -1;
644  }
645 
646  // Old request with 'WITH'
647  /*
648  $sql = "WITH in_accounting_bookkeeping(fk_docdet) AS (";
649  $sql .= " SELECT DISTINCT fk_docdet";
650  $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping";
651  $sql .= " WHERE doc_type = 'asset'";
652  $sql .= ")";
653  $sql .= "SELECT ad.rowid, ad.depreciation_mode, ad.ref, ad.depreciation_date, ad.depreciation_ht, ad.cumulative_depreciation_ht";
654  $sql .= ", " . $this->db->ifsql('iab.fk_docdet IS NOT NULL', 1, 0) . " AS bookkeeping";
655  $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
656  $sql .= " LEFT JOIN in_accounting_bookkeeping as iab ON iab.fk_docdet = ad.rowid";
657  $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
658  $sql .= " ORDER BY ad.depreciation_date ASC";
659  */
660 
661  $sql = "SELECT ad.rowid, ad.depreciation_mode, ad.ref, ad.depreciation_date, ad.depreciation_ht, ad.cumulative_depreciation_ht";
662  $sql .= ", " . $this->db->ifsql('iab.fk_docdet IS NOT NULL', 1, 0) . " AS bookkeeping";
663  $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
664  $sql .= " LEFT JOIN (SELECT DISTINCT fk_docdet FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping WHERE doc_type = 'asset') AS iab ON iab.fk_docdet = ad.rowid";
665  $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
666  $sql .= " ORDER BY ad.depreciation_date ASC";
667 
668  $resql = $this->db->query($sql);
669  if (!$resql) {
670  $this->errors[] = $langs->trans('AssetErrorFetchDepreciationLines') . ': ' . $this->db->lasterror();
671  return -1;
672  }
673 
674  while ($obj = $this->db->fetch_object($resql)) {
675  if (!isset($this->depreciation_lines[$obj->depreciation_mode])) $this->depreciation_lines[$obj->depreciation_mode] = array();
676  $this->depreciation_lines[$obj->depreciation_mode][] = array(
677  'id' => $obj->rowid,
678  'ref' => $obj->ref,
679  'depreciation_date' => $this->db->jdate($obj->depreciation_date),
680  'depreciation_ht' => $obj->depreciation_ht,
681  'cumulative_depreciation_ht' => $obj->cumulative_depreciation_ht,
682  'bookkeeping' => $obj->bookkeeping,
683  );
684  }
685 
686  return 1;
687  }
688 
695  {
696  global $langs;
697  $langs->load('assets');
698 
699  // Clean parameters
700  $this->id = $this->id > 0 ? $this->id : 0;
701 
702  // Check parameters
703  $error = 0;
704  if (empty($this->id)) {
705  $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Asset") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
706  $error++;
707  }
708  if ($error) {
709  return -1;
710  }
711 
712  // Old request with 'WITH'
713  /*
714  $sql = "WITH in_accounting_bookkeeping(fk_docdet) AS (";
715  $sql .= " SELECT DISTINCT fk_docdet";
716  $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping";
717  $sql .= " WHERE doc_type = 'asset'";
718  $sql .= ")";
719  $sql .= "SELECT COUNT(*) AS has_bookkeeping";
720  $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
721  $sql .= " LEFT JOIN in_accounting_bookkeeping as iab ON iab.fk_docdet = ad.rowid";
722  $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
723  $sql .= " AND iab.fk_docdet IS NOT NULL";
724  */
725 
726  $sql = "SELECT COUNT(*) AS has_bookkeeping";
727  $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
728  $sql .= " LEFT JOIN (SELECT DISTINCT fk_docdet FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping WHERE doc_type = 'asset') AS iab ON iab.fk_docdet = ad.rowid";
729  $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
730  $sql .= " AND iab.fk_docdet IS NOT NULL";
731 
732  $resql = $this->db->query($sql);
733  if (!$resql) {
734  $this->errors[] = $langs->trans('AssetErrorFetchDepreciationLines') . ': ' . $this->db->lasterror();
735  return -1;
736  }
737 
738  if ($obj = $this->db->fetch_object($resql)) {
739  return $obj->has_bookkeeping > 0 ? 1 : 0;
740  }
741 
742  return 0;
743  }
744 
757  public function addDepreciationLine($mode, $ref, $depreciation_date, $depreciation_ht, $cumulative_depreciation_ht, $accountancy_code_debit, $accountancy_code_credit)
758  {
759  global $langs;
760  $langs->load('assets');
761 
762  // Clean parameters
763  $this->id = $this->id > 0 ? $this->id : 0;
764  $mode = strtolower(trim($mode));
765  $ref = trim($ref);
766  $accountancy_code_debit = trim($accountancy_code_debit);
767  $accountancy_code_credit = trim($accountancy_code_credit);
768 
769  // Check parameters
770  $error = 0;
771  if (empty($this->id)) {
772  $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Asset") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
773  $error++;
774  }
775  if ($error) {
776  return -1;
777  }
778 
779  $sql = "INSERT INTO " . MAIN_DB_PREFIX . "asset_depreciation(fk_asset, depreciation_mode, ref, depreciation_date, depreciation_ht, cumulative_depreciation_ht, accountancy_code_debit, accountancy_code_credit)";
780  $sql .= " VALUES ( ";
781  $sql .= " " . (int) $this->id;
782  $sql .= ", '" . $this->db->escape($mode) . "'";
783  $sql .= ", '" . $this->db->escape($ref) . "'";
784  $sql .= ", '" . $this->db->idate($depreciation_date) . "'";
785  $sql .= ", " . (double) $depreciation_ht;
786  $sql .= ", " . (double) $cumulative_depreciation_ht;
787  $sql .= ", '" . $this->db->escape($accountancy_code_debit) . "'";
788  $sql .= ", '" . $this->db->escape($accountancy_code_credit) . "'";
789  $sql .= ")";
790 
791  $resql = $this->db->query($sql);
792  if (!$resql) {
793  $this->errors[] = $langs->trans('AssetErrorAddDepreciationLine') . ': ' . $this->db->lasterror();
794  return -1;
795  }
796 
797  return 1;
798  }
799 
805  public function calculationDepreciation()
806  {
807  global $conf, $langs;
808  $langs->load('assets');
809 
810  // Clean parameters
811  $this->id = $this->id > 0 ? $this->id : 0;
812 
813  // Check parameters
814  $error = 0;
815  if (empty($this->id)) {
816  $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Asset") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
817  $error++;
818  }
819  if ($error) {
820  return -1;
821  }
822 
823  // Get depreciation options
824  //---------------------------
825  require_once DOL_DOCUMENT_ROOT . '/asset/class/assetdepreciationoptions.class.php';
826  $options = new AssetDepreciationOptions($this->db);
827  $result = $options->fetchDeprecationOptions($this->id);
828  if ($result < 0) {
829  $this->error = $options->error;
830  $this->errors = $options->errors;
831  return -1;
832  }
833 
834  // Get accountancy codes
835  //---------------------------
836  require_once DOL_DOCUMENT_ROOT . '/asset/class/assetaccountancycodes.class.php';
837  $accountancy_codes = new AssetAccountancyCodes($this->db);
838  $result = $accountancy_codes->fetchAccountancyCodes($this->id);
839  if ($result < 0) {
840  $this->error = $accountancy_codes->error;
841  $this->errors = $accountancy_codes->errors;
842  return -1;
843  }
844 
845  $this->db->begin();
846 
847  // Delete old lines
848  $modes = array();
849  foreach ($options->deprecation_options as $mode_key => $fields) {
850  $modes[$mode_key] = $this->db->escape($mode_key);
851  }
852  $sql = "DELETE FROM " . MAIN_DB_PREFIX . "asset_depreciation";
853  $sql .= " WHERE fk_asset = " . (int) $this->id;
854  $sql .= " AND depreciation_mode NOT IN ('" . $this->db->sanitize(implode("', '", $modes)) . "')";
855 
856  $resql = $this->db->query($sql);
857  if (!$resql) {
858  $this->errors[] = $langs->trans('AssetErrorClearDepreciationLines') . ': ' . $this->db->lasterror();
859  $error++;
860  }
861 
862  if (!$error) {
863  // Get fiscal period
864  require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
865  require_once DOL_DOCUMENT_ROOT . '/core/lib/accounting.lib.php';
866  $dates = getDefaultDatesForTransfer();
867  $init_fiscal_period_start = $dates['date_start'];
868  $init_fiscal_period_end = $dates['date_end'];
869  if (empty($init_fiscal_period_start) || empty($init_fiscal_period_end)) {
870  $pastmonthyear = $dates['pastmonthyear'];
871  $pastmonth = $dates['pastmonth'];
872  $init_fiscal_period_start = dol_get_first_day($pastmonthyear, $pastmonth, false);
873  $init_fiscal_period_end = dol_get_last_day($pastmonthyear, $pastmonth, false);
874  }
875 
876  foreach ($options->deprecation_options as $mode_key => $fields) {
877  // Get last depreciation lines save in bookkeeping
878  //-----------------------------------------------------
879 
880  // Old request with 'WITH'
881  /*
882  $sql = "WITH in_accounting_bookkeeping(fk_docdet) AS (";
883  $sql .= " SELECT fk_docdet";
884  $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping";
885  $sql .= " WHERE doc_type = 'asset'";
886  $sql .= ")";
887  $sql .= "SELECT ad.depreciation_date, ad.cumulative_depreciation_ht";
888  $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
889  $sql .= " LEFT JOIN in_accounting_bookkeeping as iab ON iab.fk_docdet = ad.rowid";
890  $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
891  $sql .= " AND ad.depreciation_mode = '" . $this->db->escape($mode_key) . "'";
892  $sql .= " AND iab.fk_docdet IS NOT NULL";
893  $sql .= " ORDER BY ad.depreciation_date DESC";
894  $sql .= " LIMIT 1";
895  */
896 
897  $sql = "SELECT ad.depreciation_date, ad.cumulative_depreciation_ht";
898  $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
899  $sql .= " LEFT JOIN (SELECT DISTINCT fk_docdet FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping WHERE doc_type = 'asset') AS iab ON iab.fk_docdet = ad.rowid";
900  $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
901  $sql .= " AND ad.depreciation_mode = '" . $this->db->escape($mode_key) . "'";
902  $sql .= " AND iab.fk_docdet IS NOT NULL";
903  $sql .= " ORDER BY ad.depreciation_date DESC";
904  $sql .= " LIMIT 1";
905 
906  $resql = $this->db->query($sql);
907  if (!$resql) {
908  $this->errors[] = $langs->trans('AssetErrorFetchMaxDepreciationDateForMode', $mode_key) . ': ' . $this->db->lasterror();
909  $error++;
910  break;
911  }
912  $last_depreciation_date = '';
913  $last_cumulative_depreciation_ht = $this->reversal_amount_ht;
914  if ($obj = $this->db->fetch_object($resql)) {
915  $last_depreciation_date = $this->db->jdate($obj->depreciation_date);
916  $last_cumulative_depreciation_ht = $obj->cumulative_depreciation_ht;
917  }
918 
919  // Set last cumulative depreciation
920  $sql = "UPDATE " . MAIN_DB_PREFIX . $options->deprecation_options_fields[$mode_key]['table'];
921  $sql .= " SET total_amount_last_depreciation_ht = " . (empty($last_cumulative_depreciation_ht) ? 0 : $last_cumulative_depreciation_ht);
922  $sql .= " WHERE fk_asset = " . (int) $this->id;
923  $resql = $this->db->query($sql);
924  if (!$resql) {
925  $this->errors[] = $langs->trans('AssetErrorSetLastCumulativeDepreciation') . ': ' . $this->db->lasterror();
926  $error++;
927  break;
928  }
929 
930  // Delete old lines
931  $sql = "DELETE " . MAIN_DB_PREFIX . "asset_depreciation FROM " . MAIN_DB_PREFIX . "asset_depreciation";
932  $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "accounting_bookkeeping as ab ON ab.doc_type = 'asset' AND ab.fk_docdet = " . MAIN_DB_PREFIX . "asset_depreciation.rowid";
933  $sql .= " WHERE " . MAIN_DB_PREFIX . "asset_depreciation.fk_asset = " . (int) $this->id;
934  $sql .= " AND " . MAIN_DB_PREFIX . "asset_depreciation.depreciation_mode = '" . $this->db->escape($mode_key) . "'";
935  $sql .= " AND ab.fk_docdet IS NULL";
936  if ($last_depreciation_date !== "") $sql .= " AND " . MAIN_DB_PREFIX . "asset_depreciation.ref != ''";
937  $resql = $this->db->query($sql);
938  if (!$resql) {
939  $this->errors[] = $langs->trans('AssetErrorClearDepreciationLines') . ': ' . $this->db->lasterror();
940  $error++;
941  break;
942  }
943 
944  // Get depreciation period
945  $depreciation_date_start = $this->date_start > $this->date_acquisition ? $this->date_start : $this->date_acquisition;
946  $depreciation_date_end = dol_time_plus_duree($depreciation_date_start, $fields['duration'], $fields['duration_type'] == 1 ? 'm' : ($fields['duration_type'] == 2 ? 'd' : 'y'));
947  $depreciation_amount = $fields['amount_base_depreciation_ht'];
948  if ($fields['duration_type'] == 2) { // Daily
949  $fiscal_period_start = $depreciation_date_start;
950  $fiscal_period_end = $depreciation_date_start;
951  } elseif ($fields['duration_type'] == 1) { // Monthly
952  $date_temp = dol_getdate($depreciation_date_start);
953  $fiscal_period_start = dol_get_first_day($date_temp['year'], $date_temp['mon'], false);
954  $fiscal_period_end = dol_get_last_day($date_temp['year'], $date_temp['mon'], false);
955  } else { // Annually
956  $fiscal_period_start = $init_fiscal_period_start;
957  $fiscal_period_end = $init_fiscal_period_end;
958  }
959  $cumulative_depreciation_ht = $last_cumulative_depreciation_ht;
960  $depreciation_period_amount = $depreciation_amount - $this->reversal_amount_ht;
961  $start_date = $depreciation_date_start;
962  $disposal_date = isset($this->disposal_date) && $this->disposal_date !== "" ? $this->disposal_date : "";
963  $finish_date = $disposal_date !== "" ? $disposal_date : $depreciation_date_end;
964  $accountancy_code_depreciation_debit_key = $accountancy_codes->accountancy_codes_fields[$mode_key]['depreciation_debit'];
965  $accountancy_code_depreciation_debit = $accountancy_codes->accountancy_codes[$mode_key][$accountancy_code_depreciation_debit_key];
966  $accountancy_code_depreciation_credit_key = $accountancy_codes->accountancy_codes_fields[$mode_key]['depreciation_credit'];
967  $accountancy_code_credit = $accountancy_codes->accountancy_codes[$mode_key][$accountancy_code_depreciation_credit_key];
968 
969  // Reversal depreciation line
970  //-----------------------------------------------------
971  if ($last_depreciation_date === "" && ($depreciation_date_start < $fiscal_period_start || is_numeric($this->reversal_date))) {
972  if (is_numeric($this->reversal_date)) {
973  if ($this->reversal_date < $fiscal_period_start) {
974  $this->errors[] = $langs->trans('AssetErrorReversalDateNotGreaterThanCurrentBeginFiscalDateForMode', $mode_key);
975  $error++;
976  break;
977  }
978 
979  if (empty($this->reversal_amount_ht)) {
980  $this->errors[] = $langs->trans('AssetErrorReversalAmountNotProvidedForMode', $mode_key);
981  $error++;
982  break;
983  }
984 
985  $start_date = $this->reversal_date;
986  $result = $this->addDepreciationLine($mode_key, '', $start_date, $this->reversal_amount_ht, $this->reversal_amount_ht, $accountancy_code_depreciation_debit, $accountancy_code_credit);
987  if ($result < 0) {
988  $error++;
989  break;
990  }
991  } else {
992  $this->errors[] = $langs->trans('AssetErrorReversalDateNotProvidedForMode', $mode_key);
993  $error++;
994  break;
995  }
996  }
997 
998  // futures depreciation lines
999  //-----------------------------------------------------
1000  $nb_days_in_year = !empty($conf->global->ASSET_DEPRECIATION_DURATION_PER_YEAR) ? $conf->global->ASSET_DEPRECIATION_DURATION_PER_YEAR : 365;
1001  $nb_days_in_month = !empty($conf->global->ASSET_DEPRECIATION_DURATION_PER_MONTH) ? $conf->global->ASSET_DEPRECIATION_DURATION_PER_MONTH : 30;
1002  $period_amount = (double) price2num($depreciation_period_amount / $fields['duration'], 'MT');
1003  $first_period_found = false;
1004  $first_period_date = isset($begin_period) && $begin_period > $fiscal_period_start ? $begin_period : $fiscal_period_start;
1005 
1006  $ref_date_format = "%Y" . ($fields['duration_type'] == 1 || $fields['duration_type'] == 2 ? '-%m' : '') . ($fields['duration_type'] == 2 ? '-%d' : '');
1007 
1008  // Loop security
1009  $idx_loop = 0;
1010  $max_loop = $fields['duration'] + 2;
1011  do {
1012  // Loop security
1013  $idx_loop++;
1014  if ($idx_loop > $max_loop) break;
1015 
1016  if ($last_depreciation_date < $fiscal_period_end && ($first_period_date <= $start_date || $first_period_found)) {
1017  // Disposal not depreciated
1018  if ($fiscal_period_start <= $disposal_date && $disposal_date <= $fiscal_period_end && empty($this->disposal_depreciated)) {
1019  break;
1020  }
1021 
1022  $first_period_found = true;
1023 
1024  $period_begin = dol_print_date($fiscal_period_start, $ref_date_format);
1025  $period_end = dol_print_date($fiscal_period_end, $ref_date_format);
1026  $ref = $period_begin . ($period_begin != $period_end ? ' - ' . $period_end : '');
1027  if ($fiscal_period_start <= $disposal_date && $disposal_date <= $fiscal_period_end) {
1028  $ref .= ' - ' . $langs->transnoentitiesnoconv('AssetDisposal');
1029  }
1030 
1031  $begin_date = $fiscal_period_start < $start_date && $start_date <= $fiscal_period_end ? $start_date : $fiscal_period_start;
1032  $end_date = $fiscal_period_start < $finish_date && $finish_date <= $fiscal_period_end ? $finish_date : $fiscal_period_end;
1033  if ($fields['duration_type'] == 2) { // Daily
1034  $depreciation_ht = $period_amount;
1035  } elseif ($fields['duration_type'] == 1) { // Monthly
1036  $nb_days = min($nb_days_in_month, num_between_day($begin_date, $end_date, 1));
1037  if ($nb_days >= 28) {
1038  $date_temp = dol_getdate($begin_date);
1039  if ($date_temp['mon'] == 2) {
1040  $nb_days = 30;
1041  }
1042  }
1043  $depreciation_ht = (double) price2num($period_amount * $nb_days / $nb_days_in_month, 'MT');
1044  } else { // Annually
1045  $nb_days = min($nb_days_in_year, num_between_day($begin_date, $end_date, 1));
1046  $depreciation_ht = (double) price2num($period_amount * $nb_days / $nb_days_in_year, 'MT');
1047  }
1048 
1049  if ($fiscal_period_start <= $depreciation_date_end && $depreciation_date_end <= $fiscal_period_end) { // last period
1050  $depreciation_ht = (double) price2num($depreciation_amount - $cumulative_depreciation_ht, 'MT');
1051  $cumulative_depreciation_ht = $depreciation_amount;
1052  } else {
1053  $cumulative_depreciation_ht += $depreciation_ht;
1054  }
1055 
1056  $result = $this->addDepreciationLine($mode_key, $ref, $fiscal_period_end, $depreciation_ht, $cumulative_depreciation_ht, $accountancy_code_depreciation_debit, $accountancy_code_credit);
1057  if ($result < 0) {
1058  $error++;
1059  break;
1060  }
1061  }
1062 
1063  // Next fiscal period (+1 day/month/year)
1064  $fiscal_period_start = dol_time_plus_duree($fiscal_period_end, 1, 'd');
1065  if ($fields['duration_type'] == 2) { // Daily
1066  $fiscal_period_end = $fiscal_period_start;
1067  } elseif ($fields['duration_type'] == 1) { // Monthly
1068  $fiscal_period_end = dol_time_plus_duree(dol_time_plus_duree($fiscal_period_start, 1, 'm'), -1, 'd');
1069  } else { // Annually
1070  $fiscal_period_end = dol_time_plus_duree(dol_time_plus_duree($fiscal_period_start, 1, 'y'), -1, 'd');
1071  }
1072  $last_period_date = $disposal_date !== "" && $disposal_date < $depreciation_date_end ? $disposal_date : $depreciation_date_end;
1073  } while ($fiscal_period_start < $last_period_date);
1074 
1075  if ($error) {
1076  break;
1077  }
1078  }
1079  }
1080 
1081  if ($error) {
1082  $this->db->rollback();
1083  return -1;
1084  } else {
1085  $this->db->commit();
1086  return 1;
1087  }
1088  }
1089 
1096  public function setLastCumulativeDepreciation($asset_depreciation_id)
1097  {
1098  global $langs;
1099  $langs->load('assets');
1100 
1101  // Clean parameters
1102  $asset_depreciation_id = $asset_depreciation_id > 0 ? $asset_depreciation_id : 0;
1103 
1104  // Check parameters
1105  $error = 0;
1106  if (empty($asset_depreciation_id)) {
1107  $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("AssetDepreciation") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
1108  $error++;
1109  }
1110  if ($error) {
1111  return -1;
1112  }
1113 
1114  $this->db->begin();
1115 
1116  require_once DOL_DOCUMENT_ROOT . '/asset/class/assetdepreciationoptions.class.php';
1117  $options = new AssetDepreciationOptions($this->db);
1118 
1119  // Get last depreciation lines save in bookkeeping
1120  //-----------------------------------------------------
1121  $sql = "SELECT fk_asset, depreciation_mode, cumulative_depreciation_ht";
1122  $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation";
1123  $sql .= " WHERE rowid = " . (int) $asset_depreciation_id;
1124  $resql = $this->db->query($sql);
1125  if (!$resql) {
1126  $this->errors[] = $langs->trans('AssetErrorFetchCumulativeDepreciation') . ': ' . $this->db->lasterror();
1127  $error++;
1128  } else {
1129  if ($obj = $this->db->fetch_object($resql)) {
1130  $mode_key = $obj->depreciation_mode;
1131  if (!empty($options->deprecation_options_fields[$mode_key])) {
1132  $sql = "UPDATE " . MAIN_DB_PREFIX . $options->deprecation_options_fields[$mode_key]['table'];
1133  $sql .= " SET total_amount_last_depreciation_ht = " . $obj->cumulative_depreciation_ht;
1134  $sql .= " WHERE fk_asset = " . (int) $obj->fk_asset;
1135  $resql = $this->db->query($sql);
1136  if (!$resql) {
1137  $this->errors[] = $langs->trans('AssetErrorSetLastCumulativeDepreciation') . ': ' . $this->db->lasterror();
1138  $error++;
1139  }
1140  }
1141  }
1142  }
1143 
1144  if ($error) {
1145  $this->db->rollback();
1146  return -1;
1147  } else {
1148  $this->db->commit();
1149  return 1;
1150  }
1151  }
1152 
1161  public function dispose($user, $disposal_invoice_id, $notrigger = 0)
1162  {
1163  global $conf, $langs;
1164 
1165  // Protection
1166  if ($this->status != self::STATUS_DRAFT || $this->status == self::STATUS_DISPOSED) {
1167  return 0;
1168  }
1169 
1170  $this->db->begin();
1171 
1172  $required_fields = array('disposal_date', 'disposal_date', 'fk_disposal_type');
1173  foreach ($required_fields as $field) {
1174  $this->fields[$field]['notnull'] = 1;
1175  }
1176  $result = $this->update($user, 1);
1177  foreach ($required_fields as $field) {
1178  $this->fields[$field]['notnull'] = 0;
1179  }
1180  if ($result > 0) {
1181  if ($disposal_invoice_id > 0) $this->add_object_linked('facture', $disposal_invoice_id);
1182  $result = $this->setStatusCommon($user, self::STATUS_DISPOSED, $notrigger, 'ASSET_DISPOSED');
1183  }
1184  if ($result > 0) $result = $this->calculationDepreciation();
1185 
1186  if ($result < 0) {
1187  $this->db->rollback();
1188  } else {
1189  $this->db->commit();
1190  }
1191 
1192  // Define output language
1193  if ($result > 0 && empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) {
1194  if (method_exists($this, 'generateDocument')) {
1195  global $hidedetails, $hidedesc, $hideref;
1196  $outputlangs = $langs;
1197  $newlang = '';
1198  if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
1199  $newlang = GETPOST('lang_id', 'aZ09');
1200  }
1201  if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
1202  $newlang = $this->thirdparty->default_lang;
1203  }
1204  if (!empty($newlang)) {
1205  $outputlangs = new Translate("", $conf);
1206  $outputlangs->setDefaultLang($newlang);
1207  }
1208  $model = $this->model_pdf;
1209  $ret = $this->fetch($this->id); // Reload to get new records
1210 
1211  $this->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
1212  }
1213  }
1214 
1215  return $result;
1216  }
1217 
1225  public function reopen($user, $notrigger = 0)
1226  {
1227  global $conf, $langs;
1228 
1229  // Protection
1230  if ($this->status != self::STATUS_DISPOSED || $this->status == self::STATUS_DRAFT) {
1231  return 0;
1232  }
1233 
1234 
1235  $this->db->begin();
1236 
1237  $this->disposal_date = null;
1238  $this->disposal_amount_ht = null;
1239  $this->fk_disposal_type = null;
1240  $this->disposal_depreciated = null;
1241  $this->disposal_subject_to_vat = null;
1242  $result = $this->update($user, 1);
1243  if ($result > 0) {
1244  $this->deleteObjectLinked(null, 'facture');
1245  $result = $this->setStatusCommon($user, self::STATUS_DRAFT, $notrigger, 'ASSET_REOPEN');
1246  }
1247  if ($result > 0) $result = $this->calculationDepreciation();
1248 
1249  if ($result < 0) {
1250  $this->db->rollback();
1251  } else {
1252  $this->db->commit();
1253  }
1254 
1255  // Define output language
1256  if ($result > 0 && empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) {
1257  if (method_exists($this, 'generateDocument')) {
1258  global $hidedetails, $hidedesc, $hideref;
1259  $outputlangs = $langs;
1260  $newlang = '';
1261  if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
1262  $newlang = GETPOST('lang_id', 'aZ09');
1263  }
1264  if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
1265  $newlang = $this->thirdparty->default_lang;
1266  }
1267  if (!empty($newlang)) {
1268  $outputlangs = new Translate("", $conf);
1269  $outputlangs->setDefaultLang($newlang);
1270  }
1271  $model = $this->model_pdf;
1272  $ret = $this->fetch($this->id); // Reload to get new records
1273 
1274  $this->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
1275  }
1276  }
1277 
1278  return $result;
1279  }
1280 
1292  public function getNomUrl($withpicto = 0, $option = '', $maxlen = 0, $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
1293  {
1294  global $db, $conf, $langs, $hookmanager;
1295  global $dolibarr_main_authentication, $dolibarr_main_demo;
1296  global $menumanager;
1297 
1298  if (!empty($conf->dol_no_mouse_hover)) {
1299  $notooltip = 1; // Force disable tooltips
1300  }
1301 
1302  $result = '';
1303 
1304  $label = img_picto('', $this->picto).' <u>'.$langs->trans("Asset").'</u>';
1305  if (isset($this->status)) {
1306  $label .= ' '.$this->getLibStatut(5);
1307  }
1308  $label .= '<br>';
1309  $label .= '<b>'.$langs->trans('Ref').':</b> '.$this->ref;
1310 
1311  $url = dol_buildpath('/asset/card.php', 1).'?id='.$this->id;
1312 
1313  if ($option != 'nolink') {
1314  // Add param to save lastsearch_values or not
1315  $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1316  if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
1317  $add_save_lastsearch_values = 1;
1318  }
1319  if ($add_save_lastsearch_values) {
1320  $url .= '&save_lastsearch_values=1';
1321  }
1322  }
1323 
1324  $linkclose = '';
1325  if (empty($notooltip)) {
1326  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
1327  $label = $langs->trans("ShowAsset");
1328  $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
1329  }
1330  $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
1331  $linkclose .= ' class="classfortooltip'.($morecss ? ' '.$morecss : '').'"';
1332  } else {
1333  $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
1334  }
1335 
1336  if ($option == 'nolink') {
1337  $linkstart = '<span';
1338  } else {
1339  $linkstart = '<a href="'.$url.'"';
1340  }
1341  $linkstart .= $linkclose.'>';
1342  if ($option == 'nolink') {
1343  $linkend = '</span>';
1344  } else {
1345  $linkend = '</a>';
1346  }
1347 
1348  $result .= $linkstart;
1349 
1350  if (empty($this->showphoto_on_popup)) {
1351  if ($withpicto) {
1352  $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);
1353  }
1354  } else {
1355  if ($withpicto) {
1356  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1357 
1358  list($class, $module) = explode('@', $this->picto);
1359  $upload_dir = $conf->$module->multidir_output[$conf->entity]."/$class/".dol_sanitizeFileName($this->ref);
1360  $filearray = dol_dir_list($upload_dir, "files");
1361  $filename = $filearray[0]['name'];
1362  if (!empty($filename)) {
1363  $pospoint = strpos($filearray[0]['name'], '.');
1364 
1365  $pathtophoto = $class.'/'.$this->ref.'/thumbs/'.substr($filename, 0, $pospoint).'_mini'.substr($filename, $pospoint);
1366  if (!getDolGlobalString(strtoupper($module.'_'.$class).'_FORMATLISTPHOTOSASUSERS')) {
1367  $result .= '<div class="floatleft inline-block valignmiddle divphotoref"><div class="photoref"><img class="photo'.$module.'" alt="No photo" border="0" src="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$module.'&entity='.$conf->entity.'&file='.urlencode($pathtophoto).'"></div></div>';
1368  } else {
1369  $result .= '<div class="floatleft inline-block valignmiddle divphotoref"><img class="photouserphoto userphoto" alt="No photo" border="0" src="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$module.'&entity='.$conf->entity.'&file='.urlencode($pathtophoto).'"></div>';
1370  }
1371 
1372  $result .= '</div>';
1373  } else {
1374  $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);
1375  }
1376  }
1377  }
1378 
1379  if ($withpicto != 2) {
1380  $name = $this->ref;
1381  if ($option == 'label') $name = $this->label;
1382  elseif ($option == 'with_label') $name .= ' - ' . $this->label;
1383  $result .= dol_escape_htmltag($maxlen ? dol_trunc($name, $maxlen) : $name);
1384  }
1385 
1386  $result .= $linkend;
1387  //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
1388 
1389  global $action;
1390  $hookmanager->initHooks(array($this->element . 'dao'));
1391  $parameters = array('id'=>$this->id, 'getnomurl' => &$result);
1392  $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1393  if ($reshook > 0) {
1394  $result = $hookmanager->resPrint;
1395  } else {
1396  $result .= $hookmanager->resPrint;
1397  }
1398  return $result;
1399  }
1400 
1407  public function getLabelStatus($mode = 0)
1408  {
1409  return $this->LibStatut($this->status, $mode);
1410  }
1411 
1418  public function getLibStatut($mode = 0)
1419  {
1420  return $this->LibStatut($this->status, $mode);
1421  }
1422 
1423  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1431  public function LibStatut($status, $mode = 0)
1432  {
1433  // phpcs:enable
1434  if (empty($this->labelStatus) || empty($this->labelStatusShort)) {
1435  global $langs;
1436  //$langs->load("asset@asset");
1437  $this->labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('AssetInProgress');
1438  $this->labelStatus[self::STATUS_DISPOSED] = $langs->transnoentitiesnoconv('AssetDisposed');
1439  $this->labelStatusShort[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('AssetInProgress');
1440  $this->labelStatusShort[self::STATUS_DISPOSED] = $langs->transnoentitiesnoconv('AssetDisposed');
1441  }
1442 
1443  $statusType = 'status4';
1444  if ($status == self::STATUS_DISPOSED) {
1445  $statusType = 'status6';
1446  }
1447 
1448  return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode);
1449  }
1450 
1457  public function info($id)
1458  {
1459  $sql = "SELECT rowid, date_creation as datec, tms as datem,";
1460  $sql .= " fk_user_creat, fk_user_modif";
1461  $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as t";
1462  $sql .= " WHERE t.rowid = ".((int) $id);
1463 
1464  $result = $this->db->query($sql);
1465  if ($result) {
1466  if ($this->db->num_rows($result)) {
1467  $obj = $this->db->fetch_object($result);
1468  $this->id = $obj->rowid;
1469 
1470  $this->user_creation_id = $obj->fk_user_author;
1471  $this->user_validation_id = $obj->fk_user_valid;
1472  $this->user_cloture_id = $obj->fk_user_cloture;
1473  $this->date_creation = $this->db->jdate($obj->datec);
1474  $this->date_modification = $this->db->jdate($obj->datem);
1475  $this->date_validation = $this->db->jdate($obj->datev);
1476  }
1477 
1478  $this->db->free($result);
1479  } else {
1480  dol_print_error($this->db);
1481  }
1482  }
1483 
1490  public function initAsSpecimen()
1491  {
1492  // Set here init that are not commonf fields
1493  // $this->property1 = ...
1494  // $this->property2 = ...
1495 
1496  $this->initAsSpecimenCommon();
1497  }
1498 
1504  public function getLinesArray()
1505  {
1506  $this->lines = array();
1507 
1508  return $this->lines;
1509  }
1510 
1516  public function getNextNumRef()
1517  {
1518  global $langs, $conf;
1519  $langs->load("asset@asset");
1520 
1521  if (empty($conf->global->ASSET_ASSET_ADDON)) {
1522  $conf->global->ASSET_ASSET_ADDON = 'mod_asset_standard';
1523  }
1524 
1525  if (!empty($conf->global->ASSET_ASSET_ADDON)) {
1526  $mybool = false;
1527 
1528  $file = $conf->global->ASSET_ASSET_ADDON.".php";
1529  $classname = $conf->global->ASSET_ASSET_ADDON;
1530 
1531  // Include file with class
1532  $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
1533  foreach ($dirmodels as $reldir) {
1534  $dir = dol_buildpath($reldir."core/modules/asset/");
1535 
1536  // Load file with numbering class (if found)
1537  $mybool |= @include_once $dir.$file;
1538  }
1539 
1540  if ($mybool === false) {
1541  dol_print_error('', "Failed to include file ".$file);
1542  return '';
1543  }
1544 
1545  if (class_exists($classname)) {
1546  $obj = new $classname();
1547  $numref = $obj->getNextValue($this);
1548 
1549  if ($numref != '' && $numref != '-1') {
1550  return $numref;
1551  } else {
1552  $this->error = $obj->error;
1553  //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error);
1554  return "";
1555  }
1556  } else {
1557  print $langs->trans("Error")." ".$langs->trans("ClassNotFound").' '.$classname;
1558  return "";
1559  }
1560  } else {
1561  print $langs->trans("ErrorNumberingModuleNotSetup", $this->element);
1562  return "";
1563  }
1564  }
1565 
1577  // public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
1578  // {
1579  // global $conf, $langs;
1580  //
1581  // $result = 0;
1582  // $includedocgeneration = 1;
1583  //
1584  // $langs->load("asset@asset");
1585  //
1586  // if (!dol_strlen($modele)) {
1587  // $modele = 'standard_asset';
1588  //
1589  // if (!empty($this->model_pdf)) {
1590  // $modele = $this->model_pdf;
1591  // } elseif (!empty($conf->global->ASSET_ADDON_PDF)) {
1592  // $modele = $conf->global->ASSET_ADDON_PDF;
1593  // }
1594  // }
1595  //
1596  // $modelpath = "core/modules/asset/doc/";
1597  //
1598  // if ($includedocgeneration && !empty($modele)) {
1599  // $result = $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
1600  // }
1601  //
1602  // return $result;
1603  // }
1604 }
getDefaultDatesForTransfer()
Return Default dates for transfer based on periodicity option in accountancy setup.
$object ref
Definition: info.php:78
Class for AssetAccountancyCodes.
Class for AssetDepreciationOptions.
Class for Asset.
Definition: asset.class.php:31
create(User $user, $notrigger=false)
Create object into database.
getNomUrl($withpicto=0, $option='', $maxlen=0, $notooltip=0, $morecss='', $save_lastsearch_value=-1)
Return a link to the object card (with optionaly the picto)
fetchAll($sortorder='', $sortfield='', $limit=0, $offset=0, array $filter=array(), $filtermode='AND')
Load list of objects in memory from the database.
hasDepreciationLinesInBookkeeping()
If has depreciation lines in bookkeeping.
getLinesArray()
Create an array of lines.
dispose($user, $disposal_invoice_id, $notrigger=0)
Set dispose status.
createFromClone(User $user, $fromid)
Clone an object into another one.
calculationDepreciation()
Calculation depreciation lines (reversal and future) for each mode.
fetchLines()
Load object lines in memory from the database.
__construct(DoliDB $db)
Constructor.
info($id)
Load the info information in the object.
getLabelStatus($mode=0)
Return the label of the status.
update(User $user, $notrigger=false)
Update object into database.
fetch($id, $ref=null)
Load object in memory from the database.
LibStatut($status, $mode=0)
Return the status.
reopen($user, $notrigger=0)
Set back to validated status.
getLibStatut($mode=0)
Return the label of the status.
initAsSpecimen()
Initialise object with example values Id must be 0 if object instance is a specimen.
addDepreciationLine($mode, $ref, $depreciation_date, $depreciation_ht, $cumulative_depreciation_ht, $accountancy_code_debit, $accountancy_code_credit)
Add depreciation line for a mode.
fetchDepreciationLines()
Fetch depreciation lines for each mode in $this->depreciation_lines (sort by depreciation date)
setLastCumulativeDepreciation($asset_depreciation_id)
Set last cumulative depreciation for each mode.
setDataFromAssetModel(User $user, $notrigger=false)
Set asset model.
getNextNumRef()
Returns the reference to the following non used object depending on the active numbering module.
Parent class of all other business classes (invoices, contracts, proposals, orders,...
add_object_linked($origin=null, $origin_id=null, $f_user=null, $notrigger=0)
Add an object link into llx_element_element.
getFieldList($alias='')
Function to concat keys of fields.
fetchCommon($id, $ref=null, $morewhere='')
Load object in memory from the database.
createCommon(User $user, $notrigger=false)
Create object into database.
deleteObjectLinked($sourceid=null, $sourcetype='', $targetid=null, $targettype='', $rowid='', $f_user=null, $notrigger=0)
Delete all links between an object $this.
deleteCommon(User $user, $notrigger=false, $forcechilddeletion=0)
Delete object in database.
setStatusCommon($user, $status, $notrigger=0, $triggercode='')
Set to a status.
initAsSpecimenCommon()
Initialise object with example values Id must be 0 if object instance is a specimen.
updateCommon(User $user, $notrigger=false)
Update object into database.
Class to manage Dolibarr database access.
Class to manage translations.
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
dol_get_first_day($year, $month=1, $gm=false)
Return GMT time for first day of a month or year.
Definition: date.lib.php:576
num_between_day($timestampStart, $timestampEnd, $lastday=0)
Function to return number of days between two dates (date must be UTC date !) Example: 2012-01-01 201...
Definition: date.lib.php:989
dol_time_plus_duree($time, $duration_value, $duration_unit, $ruleforendofmonth=0)
Add a delay to a date.
Definition: date.lib.php:122
dol_get_last_day($year, $month=12, $gm=false)
Return GMT time for last day of a month or year.
Definition: date.lib.php:595
dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0, $nbsecondsold=0)
Scan a directory and return a list of files/directories.
Definition: files.lib.php:62
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
getDolGlobalInt($key, $default=0)
Return dolibarr global constant int value.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
dolGetStatus($statusLabel='', $statusLabelShort='', $html='', $statusType='status0', $displayMode=0, $url='', $params=array())
Output the badge of a status.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_getdate($timestamp, $fast=false, $forcetimezone='')
Return an array with locale date info.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...