dolibarr  16.0.5
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 
160  // /**
161  // * @var string Field with ID of parent key if this object has a parent
162  // */
163  // public $fk_element = 'fk_asset';
164  // /**
165  // * @var array List of child tables. To test if we can delete object.
166  // */
167  // protected $childtables = array();
168  // /**
169  // * @var array List of child tables. To know object to delete on cascade.
170  // * If name matches '@ClassNAme:FilePathClass;ParentFkFieldName' it will
171  // * call method deleteByParentField(parentId, ParentFkFieldName) to fetch and delete child object
172  // */
173  // protected $childtablesoncascade = array('asset_assetdet');
174 
178  public $asset_depreciation_options;
182  public $depreciation_lines = array();
183 
189  public function __construct(DoliDB $db)
190  {
191  global $conf, $langs;
192 
193  $this->db = $db;
194 
195  if (empty($conf->global->MAIN_SHOW_TECHNICAL_ID) && isset($this->fields['rowid'])) {
196  $this->fields['rowid']['visible'] = 0;
197  }
198  if (empty($conf->multicompany->enabled) && isset($this->fields['entity'])) {
199  $this->fields['entity']['enabled'] = 0;
200  }
201 
202  // Unset fields that are disabled
203  foreach ($this->fields as $key => $val) {
204  if (isset($val['enabled']) && empty($val['enabled'])) {
205  unset($this->fields[$key]);
206  }
207  }
208 
209  // Translate some data of arrayofkeyval
210  if (is_object($langs)) {
211  foreach ($this->fields as $key => $val) {
212  if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
213  foreach ($val['arrayofkeyval'] as $key2 => $val2) {
214  $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2);
215  }
216  }
217  }
218  }
219  }
220 
228  public function create(User $user, $notrigger = false)
229  {
230  if (!isset($this->date_start) || $this->date_start === "") $this->date_start = $this->date_acquisition;
231 
232  $this->db->begin();
233 
234  $result = $result_create = $this->createCommon($user, $notrigger);
235  if ($result > 0 && $this->fk_asset_model > 0) $result = $this->setDataFromAssetModel($user, $notrigger);
236  if ($result > 0) {
237  if ($this->supplier_invoice_id > 0) $this->add_object_linked('invoice_supplier', $this->supplier_invoice_id);
238  }
239 
240  if ($result < 0) {
241  $this->db->rollback();
242  } else {
243  $this->db->commit();
244  }
245 
246  return $result > 0 ? $result_create : $result;
247  }
248 
256  public function createFromClone(User $user, $fromid)
257  {
258  global $langs, $extrafields;
259  $error = 0;
260 
261  dol_syslog(__METHOD__, LOG_DEBUG);
262 
263  // $object = new self($this->db);
264  //
265  // $this->db->begin();
266  //
267  // // Load source object
268  // $result = $object->fetchCommon($fromid);
269  // if ($result > 0 && !empty($object->table_element_line)) {
270  // $object->fetchLines();
271  // }
272  //
273  // // get lines so they will be clone
274  // //foreach($this->lines as $line)
275  // // $line->fetch_optionals();
276  //
277  // // Reset some properties
278  // unset($object->id);
279  // unset($object->fk_user_creat);
280  // unset($object->import_key);
281  //
282  // // Clear fields
283  // if (property_exists($object, 'ref')) {
284  // $object->ref = empty($this->fields['ref']['default']) ? "Copy_Of_".$object->ref : $this->fields['ref']['default'];
285  // }
286  // if (property_exists($object, 'label')) {
287  // $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf")." ".$object->label : $this->fields['label']['default'];
288  // }
289  // if (property_exists($object, 'status')) {
290  // $object->status = self::STATUS_DRAFT;
291  // }
292  // if (property_exists($object, 'date_creation')) {
293  // $object->date_creation = dol_now();
294  // }
295  // if (property_exists($object, 'date_modification')) {
296  // $object->date_modification = null;
297  // }
298  // // ...
299  // // Clear extrafields that are unique
300  // if (is_array($object->array_options) && count($object->array_options) > 0) {
301  // $extrafields->fetch_name_optionals_label($this->table_element);
302  // foreach ($object->array_options as $key => $option) {
303  // $shortkey = preg_replace('/options_/', '', $key);
304  // if (!empty($extrafields->attributes[$this->table_element]['unique'][$shortkey])) {
305  // //var_dump($key); var_dump($clonedObj->array_options[$key]); exit;
306  // unset($object->array_options[$key]);
307  // }
308  // }
309  // }
310  //
311  // // Create clone
312  // $object->context['createfromclone'] = 'createfromclone';
313  // $result = $object->createCommon($user);
314  // if ($result < 0) {
315  // $error++;
316  // $this->error = $object->error;
317  // $this->errors = $object->errors;
318  // }
319  //
320  // if (!$error) {
321  // // copy internal contacts
322  // if ($this->copy_linked_contact($object, 'internal') < 0) {
323  // $error++;
324  // }
325  // }
326  //
327  // if (!$error) {
328  // // copy external contacts if same company
329  // if (property_exists($this, 'fk_soc') && $this->fk_soc == $object->socid) {
330  // if ($this->copy_linked_contact($object, 'external') < 0) {
331  // $error++;
332  // }
333  // }
334  // }
335  //
336  // unset($object->context['createfromclone']);
337  //
338  // // End
339  // if (!$error) {
340  // $this->db->commit();
341  // return $object;
342  // } else {
343  // $this->db->rollback();
344  // return -1;
345  // }
346  return -1;
347  }
348 
356  public function fetch($id, $ref = null)
357  {
358  $result = $this->fetchCommon($id, $ref);
359  if ($result > 0) {
360  if (!empty($this->table_element_line)) $this->fetchLines();
361 
362  $res = $this->hasDepreciationLinesInBookkeeping();
363  if ($res < 0) {
364  return -1;
365  } elseif ($res > 0) {
366  $this->fields['date_acquisition']['noteditable'] = '1';
367  $this->fields['date_start']['noteditable'] = '1';
368  $this->fields['acquisition_value_ht']['noteditable'] = '1';
369  $this->fields['recovered_vat']['noteditable'] = '1';
370  $this->fields['reversal_date']['noteditable'] = '1';
371  $this->fields['reversal_amount_ht']['noteditable'] = '1';
372  }
373  }
374  return $result;
375  }
376 
382  public function fetchLines()
383  {
384  $this->lines = array();
385 
386  return 1;
387  }
388 
389 
401  public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND')
402  {
403  global $conf;
404 
405  dol_syslog(__METHOD__, LOG_DEBUG);
406 
407  $records = array();
408 
409  $sql = "SELECT ";
410  $sql .= $this->getFieldList('t');
411  $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as t";
412  if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
413  $sql .= " WHERE t.entity IN (".getEntity($this->table_element).")";
414  } else {
415  $sql .= " WHERE 1 = 1";
416  }
417  // Manage filter
418  $sqlwhere = array();
419  if (count($filter) > 0) {
420  foreach ($filter as $key => $value) {
421  if ($key == 't.rowid') {
422  $sqlwhere[] = $key." = ".((int) $value);
423  } elseif (in_array($this->fields[$key]['type'], array('date', 'datetime', 'timestamp'))) {
424  $sqlwhere[] = $key." = '".$this->db->idate($value)."'";
425  } elseif ($key == 'customsql') {
426  $sqlwhere[] = $value;
427  } elseif (strpos($value, '%') === false) {
428  $sqlwhere[] = $key." IN (".$this->db->sanitize($this->db->escape($value)).")";
429  } else {
430  $sqlwhere[] = $key." LIKE '%".$this->db->escape($value)."%'";
431  }
432  }
433  }
434  if (count($sqlwhere) > 0) {
435  $sql .= " AND (".implode(" ".$filtermode." ", $sqlwhere).")";
436  }
437 
438  if (!empty($sortfield)) {
439  $sql .= $this->db->order($sortfield, $sortorder);
440  }
441  if (!empty($limit)) {
442  $sql .= $this->db->plimit($limit, $offset);
443  }
444 
445  $resql = $this->db->query($sql);
446  if ($resql) {
447  $num = $this->db->num_rows($resql);
448  $i = 0;
449  while ($i < ($limit ? min($limit, $num) : $num)) {
450  $obj = $this->db->fetch_object($resql);
451 
452  $record = new self($this->db);
453  $record->setVarsFromFetchObj($obj);
454 
455  $records[$record->id] = $record;
456 
457  $i++;
458  }
459  $this->db->free($resql);
460 
461  return $records;
462  } else {
463  $this->errors[] = 'Error '.$this->db->lasterror();
464  dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
465 
466  return -1;
467  }
468  }
469 
477  public function update(User $user, $notrigger = false)
478  {
479  if (!isset($this->date_start) || $this->date_start === "") $this->date_start = $this->date_acquisition;
480 
481  $this->db->begin();
482 
483  $result = $this->updateCommon($user, $notrigger);
484  if ($result > 0 && $this->fk_asset_model > 0 && $this->fk_asset_model != $this->oldcopy->fk_asset_model) {
485  $result = $this->setDataFromAssetModel($user, $notrigger);
486  }
487  if ($result > 0 && (
488  $this->date_start != $this->oldcopy->date_start ||
489  $this->acquisition_value_ht != $this->oldcopy->acquisition_value_ht ||
490  $this->reversal_date != $this->oldcopy->reversal_date ||
491  $this->reversal_amount_ht != $this->oldcopy->reversal_amount_ht ||
492  ($this->fk_asset_model > 0 && $this->fk_asset_model != $this->oldcopy->fk_asset_model)
493  )
494  ) {
495  $result = $this->calculationDepreciation();
496  }
497 
498  if ($result < 0) {
499  $this->db->rollback();
500  } else {
501  $this->db->commit();
502  }
503 
504  return $result;
505  }
506 
514  public function delete(User $user, $notrigger = false)
515  {
516  return $this->deleteCommon($user, $notrigger);
517  //return $this->deleteCommon($user, $notrigger, 1);
518  }
519 
527  public function setDataFromAssetModel(User $user, $notrigger = false)
528  {
529  global $langs;
530  $langs->load('assets');
531 
532  // Clean parameters
533  $this->id = $this->id > 0 ? $this->id : 0;
534  $this->fk_asset_model = $this->fk_asset_model > 0 ? $this->fk_asset_model : 0;
535 
536  // Check parameters
537  $error = 0;
538  if (empty($this->id)) {
539  $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Asset") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
540  $error++;
541  }
542  if (empty($this->fk_asset_model)) {
543  $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("AssetModel") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
544  $error++;
545  }
546  if ($error) {
547  return -1;
548  }
549 
550  $this->db->begin();
551 
552  // Get depreciation options
553  //---------------------------
554  require_once DOL_DOCUMENT_ROOT . '/asset/class/assetdepreciationoptions.class.php';
555  $options_model = new AssetDepreciationOptions($this->db);
556  $result = $options_model->fetchDeprecationOptions(0, $this->fk_asset_model);
557  if ($result < 0) {
558  $this->error = $options_model->error;
559  $this->errors = $options_model->errors;
560  $error++;
561  } elseif ($result > 0) {
562  $options = new AssetDepreciationOptions($this->db);
563  $result = $options->fetchDeprecationOptions($this->id);
564  if ($result < 0) {
565  $this->error = $options->error;
566  $this->errors = $options->errors;
567  $error++;
568  }
569 
570  if (!$error) {
571  foreach ($options_model->deprecation_options as $mode_key => $fields) {
572  foreach ($fields as $field_key => $value) {
573  $options->deprecation_options[$mode_key][$field_key] = $value;
574  }
575  }
576 
577  $result = $options->updateDeprecationOptions($user, $this->id, 0, $notrigger);
578  if ($result < 0) {
579  $this->error = $options->error;
580  $this->errors = $options->errors;
581  $error++;
582  }
583  }
584  }
585 
586  // Get accountancy codes
587  //---------------------------
588  if (!$error) {
589  require_once DOL_DOCUMENT_ROOT . '/asset/class/assetaccountancycodes.class.php';
590  $accountancy_codes_model = new AssetAccountancyCodes($this->db);
591  $result = $accountancy_codes_model->fetchAccountancyCodes(0, $this->fk_asset_model);
592  if ($result < 0) {
593  $this->error = $accountancy_codes_model->error;
594  $this->errors = $accountancy_codes_model->errors;
595  $error++;
596  } elseif ($result > 0) {
597  $accountancy_codes = new AssetAccountancyCodes($this->db);
598  $result = $accountancy_codes->fetchAccountancyCodes($this->id);
599  if ($result < 0) {
600  $this->error = $accountancy_codes->error;
601  $this->errors = $accountancy_codes->errors;
602  $error++;
603  }
604 
605  if (!$error) {
606  foreach ($accountancy_codes_model->accountancy_codes as $mode_key => $fields) {
607  foreach ($fields as $field_key => $value) {
608  $accountancy_codes->accountancy_codes[$mode_key][$field_key] = $value;
609  }
610  }
611 
612  $result = $accountancy_codes->updateAccountancyCodes($user, $this->id, 0, $notrigger);
613  if ($result < 0) {
614  $this->error = $accountancy_codes->error;
615  $this->errors = $accountancy_codes->errors;
616  $error++;
617  }
618  }
619  }
620  }
621 
622  if ($error) {
623  $this->db->rollback();
624  return -1;
625  } else {
626  $this->db->commit();
627  return 1;
628  }
629  }
630 
636  public function fetchDepreciationLines()
637  {
638  global $langs;
639  $langs->load('assets');
640  $this->depreciation_lines = array();
641 
642  // Clean parameters
643  $this->id = $this->id > 0 ? $this->id : 0;
644 
645  // Check parameters
646  $error = 0;
647  if (empty($this->id)) {
648  $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Asset") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
649  $error++;
650  }
651  if ($error) {
652  return -1;
653  }
654 
655  $sql = "WITH in_accounting_bookkeeping(fk_docdet) AS (";
656  $sql .= " SELECT DISTINCT fk_docdet";
657  $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping";
658  $sql .= " WHERE doc_type = 'asset'";
659  $sql .= ")";
660  $sql .= "SELECT ad.rowid, ad.depreciation_mode, ad.ref, ad.depreciation_date, ad.depreciation_ht, ad.cumulative_depreciation_ht";
661  $sql .= ", " . $this->db->ifsql('iab.fk_docdet IS NOT NULL', 1, 0) . " AS bookkeeping";
662  $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
663  $sql .= " LEFT JOIN in_accounting_bookkeeping as iab ON iab.fk_docdet = ad.rowid";
664  $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
665  $sql .= " ORDER BY ad.depreciation_date ASC";
666 
667  $resql = $this->db->query($sql);
668  if (!$resql) {
669  $this->errors[] = $langs->trans('AssetErrorFetchDepreciationLines') . ': ' . $this->db->lasterror();
670  return -1;
671  }
672 
673  while ($obj = $this->db->fetch_object($resql)) {
674  if (!isset($this->depreciation_lines[$obj->depreciation_mode])) $this->depreciation_lines[$obj->depreciation_mode] = array();
675  $this->depreciation_lines[$obj->depreciation_mode][] = array(
676  'id' => $obj->rowid,
677  'ref' => $obj->ref,
678  'depreciation_date' => $this->db->jdate($obj->depreciation_date),
679  'depreciation_ht' => $obj->depreciation_ht,
680  'cumulative_depreciation_ht' => $obj->cumulative_depreciation_ht,
681  'bookkeeping' => $obj->bookkeeping,
682  );
683  }
684 
685  return 1;
686  }
687 
694  {
695  global $langs;
696  $langs->load('assets');
697 
698  // Clean parameters
699  $this->id = $this->id > 0 ? $this->id : 0;
700 
701  // Check parameters
702  $error = 0;
703  if (empty($this->id)) {
704  $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Asset") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
705  $error++;
706  }
707  if ($error) {
708  return -1;
709  }
710 
711  $sql = "WITH in_accounting_bookkeeping(fk_docdet) AS (";
712  $sql .= " SELECT DISTINCT fk_docdet";
713  $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping";
714  $sql .= " WHERE doc_type = 'asset'";
715  $sql .= ")";
716  $sql .= "SELECT COUNT(*) AS has_bookkeeping";
717  $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
718  $sql .= " LEFT JOIN in_accounting_bookkeeping as iab ON iab.fk_docdet = ad.rowid";
719  $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
720  $sql .= " AND iab.fk_docdet IS NOT NULL";
721 
722  $resql = $this->db->query($sql);
723  if (!$resql) {
724  $this->errors[] = $langs->trans('AssetErrorFetchDepreciationLines') . ': ' . $this->db->lasterror();
725  return -1;
726  }
727 
728  if ($obj = $this->db->fetch_object($resql)) {
729  return $obj->has_bookkeeping > 0 ? 1 : 0;
730  }
731 
732  return 0;
733  }
734 
747  public function addDepreciationLine($mode, $ref, $depreciation_date, $depreciation_ht, $cumulative_depreciation_ht, $accountancy_code_debit, $accountancy_code_credit)
748  {
749  global $langs;
750  $langs->load('assets');
751 
752  // Clean parameters
753  $this->id = $this->id > 0 ? $this->id : 0;
754  $mode = strtolower(trim($mode));
755  $ref = trim($ref);
756  $accountancy_code_debit = trim($accountancy_code_debit);
757  $accountancy_code_credit = trim($accountancy_code_credit);
758 
759  // Check parameters
760  $error = 0;
761  if (empty($this->id)) {
762  $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Asset") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
763  $error++;
764  }
765  if ($error) {
766  return -1;
767  }
768 
769  $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)";
770  $sql .= " VALUES ( ";
771  $sql .= " " . (int) $this->id;
772  $sql .= ", '" . $this->db->escape($mode) . "'";
773  $sql .= ", '" . $this->db->escape($ref) . "'";
774  $sql .= ", '" . $this->db->idate($depreciation_date) . "'";
775  $sql .= ", " . (double) $depreciation_ht;
776  $sql .= ", " . (double) $cumulative_depreciation_ht;
777  $sql .= ", '" . $this->db->escape($accountancy_code_debit) . "'";
778  $sql .= ", '" . $this->db->escape($accountancy_code_credit) . "'";
779  $sql .= ")";
780 
781  $resql = $this->db->query($sql);
782  if (!$resql) {
783  $this->errors[] = $langs->trans('AssetErrorAddDepreciationLine') . ': ' . $this->db->lasterror();
784  return -1;
785  }
786 
787  return 1;
788  }
789 
795  public function calculationDepreciation()
796  {
797  global $conf, $langs;
798  $langs->load('assets');
799 
800  // Clean parameters
801  $this->id = $this->id > 0 ? $this->id : 0;
802 
803  // Check parameters
804  $error = 0;
805  if (empty($this->id)) {
806  $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Asset") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
807  $error++;
808  }
809  if ($error) {
810  return -1;
811  }
812 
813  // Get depreciation options
814  //---------------------------
815  require_once DOL_DOCUMENT_ROOT . '/asset/class/assetdepreciationoptions.class.php';
816  $options = new AssetDepreciationOptions($this->db);
817  $result = $options->fetchDeprecationOptions($this->id);
818  if ($result < 0) {
819  $this->error = $options->error;
820  $this->errors = $options->errors;
821  return -1;
822  }
823 
824  // Get accountancy codes
825  //---------------------------
826  require_once DOL_DOCUMENT_ROOT . '/asset/class/assetaccountancycodes.class.php';
827  $accountancy_codes = new AssetAccountancyCodes($this->db);
828  $result = $accountancy_codes->fetchAccountancyCodes($this->id);
829  if ($result < 0) {
830  $this->error = $accountancy_codes->error;
831  $this->errors = $accountancy_codes->errors;
832  return -1;
833  }
834 
835  $this->db->begin();
836 
837  // Delete old lines
838  $modes = array();
839  foreach ($options->deprecation_options as $mode_key => $fields) {
840  $modes[$mode_key] = $this->db->escape($mode_key);
841  }
842  $sql = "DELETE FROM " . MAIN_DB_PREFIX . "asset_depreciation";
843  $sql .= " WHERE fk_asset = " . (int) $this->id;
844  $sql .= " AND depreciation_mode NOT IN ('" . $this->db->sanitize(implode("', '", $modes)) . "')";
845 
846  $resql = $this->db->query($sql);
847  if (!$resql) {
848  $this->errors[] = $langs->trans('AssetErrorClearDepreciationLines') . ': ' . $this->db->lasterror();
849  $error++;
850  }
851 
852  if (!$error) {
853  // Get fiscal period
854  require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
855  require_once DOL_DOCUMENT_ROOT . '/core/lib/accounting.lib.php';
856  $dates = getDefaultDatesForTransfer();
857  $init_fiscal_period_start = $dates['date_start'];
858  $init_fiscal_period_end = $dates['date_end'];
859  if (empty($init_fiscal_period_start) || empty($init_fiscal_period_end)) {
860  $pastmonthyear = $dates['pastmonthyear'];
861  $pastmonth = $dates['pastmonth'];
862  $init_fiscal_period_start = dol_get_first_day($pastmonthyear, $pastmonth, false);
863  $init_fiscal_period_end = dol_get_last_day($pastmonthyear, $pastmonth, false);
864  }
865 
866  foreach ($options->deprecation_options as $mode_key => $fields) {
867  // Get last depreciation lines save in bookkeeping
868  //-----------------------------------------------------
869  $sql = "WITH in_accounting_bookkeeping(fk_docdet) AS (";
870  $sql .= " SELECT fk_docdet";
871  $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping";
872  $sql .= " WHERE doc_type = 'asset'";
873  $sql .= ")";
874  $sql .= "SELECT ad.depreciation_date, ad.cumulative_depreciation_ht";
875  $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
876  $sql .= " LEFT JOIN in_accounting_bookkeeping as iab ON iab.fk_docdet = ad.rowid";
877  $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
878  $sql .= " AND ad.depreciation_mode = '" . $this->db->escape($mode_key) . "'";
879  $sql .= " AND iab.fk_docdet IS NOT NULL";
880  $sql .= " ORDER BY ad.depreciation_date DESC";
881  $sql .= " LIMIT 1";
882  $resql = $this->db->query($sql);
883  if (!$resql) {
884  $this->errors[] = $langs->trans('AssetErrorFetchMaxDepreciationDateForMode', $mode_key) . ': ' . $this->db->lasterror();
885  $error++;
886  break;
887  }
888  $last_depreciation_date = '';
889  $last_cumulative_depreciation_ht = $this->reversal_amount_ht;
890  if ($obj = $this->db->fetch_object($resql)) {
891  $last_depreciation_date = $this->db->jdate($obj->depreciation_date);
892  $last_cumulative_depreciation_ht = $obj->cumulative_depreciation_ht;
893  }
894 
895  // Set last cumulative depreciation
896  $sql = "UPDATE " . MAIN_DB_PREFIX . $options->deprecation_options_fields[$mode_key]['table'];
897  $sql .= " SET total_amount_last_depreciation_ht = " . (empty($last_cumulative_depreciation_ht) ? 0 : $last_cumulative_depreciation_ht);
898  $sql .= " WHERE fk_asset = " . (int) $this->id;
899  $resql = $this->db->query($sql);
900  if (!$resql) {
901  $this->errors[] = $langs->trans('AssetErrorSetLastCumulativeDepreciation') . ': ' . $this->db->lasterror();
902  $error++;
903  break;
904  }
905 
906  // Delete old lines
907  $sql = "DELETE " . MAIN_DB_PREFIX . "asset_depreciation FROM " . MAIN_DB_PREFIX . "asset_depreciation";
908  $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";
909  $sql .= " WHERE " . MAIN_DB_PREFIX . "asset_depreciation.fk_asset = " . (int) $this->id;
910  $sql .= " AND " . MAIN_DB_PREFIX . "asset_depreciation.depreciation_mode = '" . $this->db->escape($mode_key) . "'";
911  $sql .= " AND ab.fk_docdet IS NULL";
912  if ($last_depreciation_date !== "") $sql .= " AND " . MAIN_DB_PREFIX . "asset_depreciation.ref != ''";
913  $resql = $this->db->query($sql);
914  if (!$resql) {
915  $this->errors[] = $langs->trans('AssetErrorClearDepreciationLines') . ': ' . $this->db->lasterror();
916  $error++;
917  break;
918  }
919 
920  // Get depreciation period
921  $depreciation_date_start = $this->date_start > $this->date_acquisition ? $this->date_start : $this->date_acquisition;
922  $depreciation_date_end = dol_time_plus_duree($depreciation_date_start, $fields['duration'], $fields['duration_type'] == 1 ? 'm' : ($fields['duration_type'] == 2 ? 'd' : 'y'));
923  $depreciation_amount = $fields['amount_base_depreciation_ht'];
924  if ($fields['duration_type'] == 2) { // Daily
925  $fiscal_period_start = $depreciation_date_start;
926  $fiscal_period_end = $depreciation_date_start;
927  } elseif ($fields['duration_type'] == 1) { // Monthly
928  $date_temp = dol_getdate($depreciation_date_start);
929  $fiscal_period_start = dol_get_first_day($date_temp['year'], $date_temp['mon'], false);
930  $fiscal_period_end = dol_get_last_day($date_temp['year'], $date_temp['mon'], false);
931  } else { // Annually
932  $fiscal_period_start = $init_fiscal_period_start;
933  $fiscal_period_end = $init_fiscal_period_end;
934  }
935  $cumulative_depreciation_ht = $last_cumulative_depreciation_ht;
936  $depreciation_period_amount = $depreciation_amount - $this->reversal_amount_ht;
937  $start_date = $depreciation_date_start;
938  $disposal_date = isset($this->disposal_date) && $this->disposal_date !== "" ? $this->disposal_date : "";
939  $finish_date = $disposal_date !== "" ? $disposal_date : $depreciation_date_end;
940  $accountancy_code_depreciation_debit_key = $accountancy_codes->accountancy_codes_fields[$mode_key]['depreciation_debit'];
941  $accountancy_code_depreciation_debit = $accountancy_codes->accountancy_codes[$mode_key][$accountancy_code_depreciation_debit_key];
942  $accountancy_code_depreciation_credit_key = $accountancy_codes->accountancy_codes_fields[$mode_key]['depreciation_credit'];
943  $accountancy_code_credit = $accountancy_codes->accountancy_codes[$mode_key][$accountancy_code_depreciation_credit_key];
944 
945  // Reversal depreciation line
946  //-----------------------------------------------------
947  if ($last_depreciation_date === "" && ($depreciation_date_start < $fiscal_period_start || is_numeric($this->reversal_date))) {
948  if (is_numeric($this->reversal_date)) {
949  if ($this->reversal_date < $fiscal_period_start) {
950  $this->errors[] = $langs->trans('AssetErrorReversalDateNotGreaterThanCurrentBeginFiscalDateForMode', $mode_key);
951  $error++;
952  break;
953  }
954 
955  if (empty($this->reversal_amount_ht)) {
956  $this->errors[] = $langs->trans('AssetErrorReversalAmountNotProvidedForMode', $mode_key);
957  $error++;
958  break;
959  }
960 
961  $start_date = $this->reversal_date;
962  $result = $this->addDepreciationLine($mode_key, '', $start_date, $this->reversal_amount_ht, $this->reversal_amount_ht, $accountancy_code_depreciation_debit, $accountancy_code_credit);
963  if ($result < 0) {
964  $error++;
965  break;
966  }
967  } else {
968  $this->errors[] = $langs->trans('AssetErrorReversalDateNotProvidedForMode', $mode_key);
969  $error++;
970  break;
971  }
972  }
973 
974  // futures depreciation lines
975  //-----------------------------------------------------
976  $nb_days_in_year = !empty($conf->global->ASSET_DEPRECIATION_DURATION_PER_YEAR) ? $conf->global->ASSET_DEPRECIATION_DURATION_PER_YEAR : 365;
977  $nb_days_in_month = !empty($conf->global->ASSET_DEPRECIATION_DURATION_PER_MONTH) ? $conf->global->ASSET_DEPRECIATION_DURATION_PER_MONTH : 30;
978  $period_amount = (double) price2num($depreciation_period_amount / $fields['duration'], 'MT');
979  $first_period_found = false;
980  $first_period_date = isset($begin_period) && $begin_period > $fiscal_period_start ? $begin_period : $fiscal_period_start;
981 
982  $ref_date_format = "%Y" . ($fields['duration_type'] == 1 || $fields['duration_type'] == 2 ? '-%m' : '') . ($fields['duration_type'] == 2 ? '-%d' : '');
983 
984  // Loop security
985  $idx_loop = 0;
986  $max_loop = $fields['duration'] + 2;
987  do {
988  // Loop security
989  $idx_loop++;
990  if ($idx_loop > $max_loop) break;
991 
992  if ($last_depreciation_date < $fiscal_period_end && ($first_period_date <= $start_date || $first_period_found)) {
993  // Disposal not depreciated
994  if ($fiscal_period_start <= $disposal_date && $disposal_date <= $fiscal_period_end && empty($this->disposal_depreciated)) {
995  break;
996  }
997 
998  $first_period_found = true;
999 
1000  $period_begin = dol_print_date($fiscal_period_start, $ref_date_format);
1001  $period_end = dol_print_date($fiscal_period_end, $ref_date_format);
1002  $ref = $period_begin . ($period_begin != $period_end ? ' - ' . $period_end : '');
1003  if ($fiscal_period_start <= $disposal_date && $disposal_date <= $fiscal_period_end) {
1004  $ref .= ' - ' . $langs->transnoentitiesnoconv('AssetDisposal');
1005  }
1006 
1007  $begin_date = $fiscal_period_start < $start_date && $start_date <= $fiscal_period_end ? $start_date : $fiscal_period_start;
1008  $end_date = $fiscal_period_start < $finish_date && $finish_date <= $fiscal_period_end ? $finish_date : $fiscal_period_end;
1009  if ($fields['duration_type'] == 2) { // Daily
1010  $depreciation_ht = $period_amount;
1011  } elseif ($fields['duration_type'] == 1) { // Monthly
1012  $nb_days = min($nb_days_in_month, num_between_day($begin_date, $end_date, 1));
1013  if ($nb_days >= 28) {
1014  $date_temp = dol_getdate($begin_date);
1015  if ($date_temp['mon'] == 2) {
1016  $nb_days = 30;
1017  }
1018  }
1019  $depreciation_ht = (double) price2num($period_amount * $nb_days / $nb_days_in_month, 'MT');
1020  } else { // Annually
1021  $nb_days = min($nb_days_in_year, num_between_day($begin_date, $end_date, 1));
1022  $depreciation_ht = (double) price2num($period_amount * $nb_days / $nb_days_in_year, 'MT');
1023  }
1024 
1025  if ($fiscal_period_start <= $depreciation_date_end && $depreciation_date_end <= $fiscal_period_end) { // last period
1026  $depreciation_ht = (double) price2num($depreciation_amount - $cumulative_depreciation_ht, 'MT');
1027  $cumulative_depreciation_ht = $depreciation_amount;
1028  } else {
1029  $cumulative_depreciation_ht += $depreciation_ht;
1030  }
1031 
1032  $result = $this->addDepreciationLine($mode_key, $ref, $fiscal_period_end, $depreciation_ht, $cumulative_depreciation_ht, $accountancy_code_depreciation_debit, $accountancy_code_credit);
1033  if ($result < 0) {
1034  $error++;
1035  break;
1036  }
1037  }
1038 
1039  // Next fiscal period (+1 day/month/year)
1040  $fiscal_period_start = dol_time_plus_duree($fiscal_period_end, 1, 'd');
1041  if ($fields['duration_type'] == 2) { // Daily
1042  $fiscal_period_end = $fiscal_period_start;
1043  } elseif ($fields['duration_type'] == 1) { // Monthly
1044  $fiscal_period_end = dol_time_plus_duree(dol_time_plus_duree($fiscal_period_start, 1, 'm'), -1, 'd');
1045  } else { // Annually
1046  $fiscal_period_end = dol_time_plus_duree(dol_time_plus_duree($fiscal_period_start, 1, 'y'), -1, 'd');
1047  }
1048  $last_period_date = $disposal_date !== "" && $disposal_date < $depreciation_date_end ? $disposal_date : $depreciation_date_end;
1049  } while ($fiscal_period_start < $last_period_date);
1050 
1051  if ($error) {
1052  break;
1053  }
1054  }
1055  }
1056 
1057  if ($error) {
1058  $this->db->rollback();
1059  return -1;
1060  } else {
1061  $this->db->commit();
1062  return 1;
1063  }
1064  }
1065 
1072  public function setLastCumulativeDepreciation($asset_depreciation_id)
1073  {
1074  global $langs;
1075  $langs->load('assets');
1076 
1077  // Clean parameters
1078  $asset_depreciation_id = $asset_depreciation_id > 0 ? $asset_depreciation_id : 0;
1079 
1080  // Check parameters
1081  $error = 0;
1082  if (empty($asset_depreciation_id)) {
1083  $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("AssetDepreciation") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
1084  $error++;
1085  }
1086  if ($error) {
1087  return -1;
1088  }
1089 
1090  $this->db->begin();
1091 
1092  require_once DOL_DOCUMENT_ROOT . '/asset/class/assetdepreciationoptions.class.php';
1093  $options = new AssetDepreciationOptions($this->db);
1094 
1095  // Get last depreciation lines save in bookkeeping
1096  //-----------------------------------------------------
1097  $sql = "SELECT fk_asset, depreciation_mode, cumulative_depreciation_ht";
1098  $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation";
1099  $sql .= " WHERE rowid = " . (int) $asset_depreciation_id;
1100  $resql = $this->db->query($sql);
1101  if (!$resql) {
1102  $this->errors[] = $langs->trans('AssetErrorFetchCumulativeDepreciation') . ': ' . $this->db->lasterror();
1103  $error++;
1104  } else {
1105  if ($obj = $this->db->fetch_object($resql)) {
1106  $mode_key = $obj->depreciation_mode;
1107  if (!empty($options->deprecation_options_fields[$mode_key])) {
1108  $sql = "UPDATE " . MAIN_DB_PREFIX . $options->deprecation_options_fields[$mode_key]['table'];
1109  $sql .= " SET total_amount_last_depreciation_ht = " . $obj->cumulative_depreciation_ht;
1110  $sql .= " WHERE fk_asset = " . (int) $obj->fk_asset;
1111  $resql = $this->db->query($sql);
1112  if (!$resql) {
1113  $this->errors[] = $langs->trans('AssetErrorSetLastCumulativeDepreciation') . ': ' . $this->db->lasterror();
1114  $error++;
1115  }
1116  }
1117  }
1118  }
1119 
1120  if ($error) {
1121  $this->db->rollback();
1122  return -1;
1123  } else {
1124  $this->db->commit();
1125  return 1;
1126  }
1127  }
1128 
1137  public function dispose($user, $disposal_invoice_id, $notrigger = 0)
1138  {
1139  global $conf, $langs;
1140 
1141  // Protection
1142  if ($this->status != self::STATUS_DRAFT || $this->status == self::STATUS_DISPOSED) {
1143  return 0;
1144  }
1145 
1146  $this->db->begin();
1147 
1148  $required_fields = array('disposal_date', 'disposal_date', 'fk_disposal_type');
1149  foreach ($required_fields as $field) {
1150  $this->fields[$field]['notnull'] = 1;
1151  }
1152  $result = $this->update($user, 1);
1153  foreach ($required_fields as $field) {
1154  $this->fields[$field]['notnull'] = 0;
1155  }
1156  if ($result > 0) {
1157  if ($disposal_invoice_id > 0) $this->add_object_linked('facture', $disposal_invoice_id);
1158  $result = $this->setStatusCommon($user, self::STATUS_DISPOSED, $notrigger, 'ASSET_DISPOSED');
1159  }
1160  if ($result > 0) $result = $this->calculationDepreciation();
1161 
1162  if ($result < 0) {
1163  $this->db->rollback();
1164  } else {
1165  $this->db->commit();
1166  }
1167 
1168  // Define output language
1169  if ($result > 0 && empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) {
1170  if (method_exists($this, 'generateDocument')) {
1171  global $hidedetails, $hidedesc, $hideref;
1172  $outputlangs = $langs;
1173  $newlang = '';
1174  if ($conf->global->MAIN_MULTILANGS && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
1175  $newlang = GETPOST('lang_id', 'aZ09');
1176  }
1177  if ($conf->global->MAIN_MULTILANGS && empty($newlang)) {
1178  $newlang = $this->thirdparty->default_lang;
1179  }
1180  if (!empty($newlang)) {
1181  $outputlangs = new Translate("", $conf);
1182  $outputlangs->setDefaultLang($newlang);
1183  }
1184  $model = $this->model_pdf;
1185  $ret = $this->fetch($this->id); // Reload to get new records
1186 
1187  $this->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
1188  }
1189  }
1190 
1191  return $result;
1192  }
1193 
1201  public function reopen($user, $notrigger = 0)
1202  {
1203  global $conf, $langs;
1204 
1205  // Protection
1206  if ($this->status != self::STATUS_DISPOSED || $this->status == self::STATUS_DRAFT) {
1207  return 0;
1208  }
1209 
1210 
1211  $this->db->begin();
1212 
1213  $this->disposal_date = null;
1214  $this->disposal_amount_ht = null;
1215  $this->fk_disposal_type = null;
1216  $this->disposal_depreciated = null;
1217  $this->disposal_subject_to_vat = null;
1218  $result = $this->update($user, 1);
1219  if ($result > 0) {
1220  $this->deleteObjectLinked(null, 'facture');
1221  $result = $this->setStatusCommon($user, self::STATUS_DRAFT, $notrigger, 'ASSET_REOPEN');
1222  }
1223  if ($result > 0) $result = $this->calculationDepreciation();
1224 
1225  if ($result < 0) {
1226  $this->db->rollback();
1227  } else {
1228  $this->db->commit();
1229  }
1230 
1231  // Define output language
1232  if ($result > 0 && empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) {
1233  if (method_exists($this, 'generateDocument')) {
1234  global $hidedetails, $hidedesc, $hideref;
1235  $outputlangs = $langs;
1236  $newlang = '';
1237  if ($conf->global->MAIN_MULTILANGS && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
1238  $newlang = GETPOST('lang_id', 'aZ09');
1239  }
1240  if ($conf->global->MAIN_MULTILANGS && empty($newlang)) {
1241  $newlang = $this->thirdparty->default_lang;
1242  }
1243  if (!empty($newlang)) {
1244  $outputlangs = new Translate("", $conf);
1245  $outputlangs->setDefaultLang($newlang);
1246  }
1247  $model = $this->model_pdf;
1248  $ret = $this->fetch($this->id); // Reload to get new records
1249 
1250  $this->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
1251  }
1252  }
1253 
1254  return $result;
1255  }
1256 
1268  public function getNomUrl($withpicto = 0, $option = '', $maxlen = 0, $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
1269  {
1270  global $db, $conf, $langs, $hookmanager;
1271  global $dolibarr_main_authentication, $dolibarr_main_demo;
1272  global $menumanager;
1273 
1274  if (!empty($conf->dol_no_mouse_hover)) {
1275  $notooltip = 1; // Force disable tooltips
1276  }
1277 
1278  $result = '';
1279 
1280  $label = img_picto('', $this->picto).' <u>'.$langs->trans("Asset").'</u>';
1281  if (isset($this->status)) {
1282  $label .= ' '.$this->getLibStatut(5);
1283  }
1284  $label .= '<br>';
1285  $label .= '<b>'.$langs->trans('Ref').':</b> '.$this->ref;
1286 
1287  $url = dol_buildpath('/asset/card.php', 1).'?id='.$this->id;
1288 
1289  if ($option != 'nolink') {
1290  // Add param to save lastsearch_values or not
1291  $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1292  if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
1293  $add_save_lastsearch_values = 1;
1294  }
1295  if ($add_save_lastsearch_values) {
1296  $url .= '&save_lastsearch_values=1';
1297  }
1298  }
1299 
1300  $linkclose = '';
1301  if (empty($notooltip)) {
1302  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
1303  $label = $langs->trans("ShowAsset");
1304  $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
1305  }
1306  $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
1307  $linkclose .= ' class="classfortooltip'.($morecss ? ' '.$morecss : '').'"';
1308  } else {
1309  $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
1310  }
1311 
1312  if ($option == 'nolink') {
1313  $linkstart = '<span';
1314  } else {
1315  $linkstart = '<a href="'.$url.'"';
1316  }
1317  $linkstart .= $linkclose.'>';
1318  if ($option == 'nolink') {
1319  $linkend = '</span>';
1320  } else {
1321  $linkend = '</a>';
1322  }
1323 
1324  $result .= $linkstart;
1325 
1326  if (empty($this->showphoto_on_popup)) {
1327  if ($withpicto) {
1328  $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);
1329  }
1330  } else {
1331  if ($withpicto) {
1332  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1333 
1334  list($class, $module) = explode('@', $this->picto);
1335  $upload_dir = $conf->$module->multidir_output[$conf->entity]."/$class/".dol_sanitizeFileName($this->ref);
1336  $filearray = dol_dir_list($upload_dir, "files");
1337  $filename = $filearray[0]['name'];
1338  if (!empty($filename)) {
1339  $pospoint = strpos($filearray[0]['name'], '.');
1340 
1341  $pathtophoto = $class.'/'.$this->ref.'/thumbs/'.substr($filename, 0, $pospoint).'_mini'.substr($filename, $pospoint);
1342  if (empty($conf->global->{strtoupper($module.'_'.$class).'_FORMATLISTPHOTOSASUSERS'})) {
1343  $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>';
1344  } else {
1345  $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>';
1346  }
1347 
1348  $result .= '</div>';
1349  } else {
1350  $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);
1351  }
1352  }
1353  }
1354 
1355  if ($withpicto != 2) {
1356  $name = $this->ref;
1357  if ($option == 'label') $name = $this->label;
1358  elseif ($option == 'with_label') $name .= ' - ' . $this->label;
1359  $result .= dol_escape_htmltag($maxlen ? dol_trunc($name, $maxlen) : $name);
1360  }
1361 
1362  $result .= $linkend;
1363  //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
1364 
1365  global $action;
1366  $hookmanager->initHooks(array($this->element . 'dao'));
1367  $parameters = array('id'=>$this->id, 'getnomurl' => &$result);
1368  $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1369  if ($reshook > 0) {
1370  $result = $hookmanager->resPrint;
1371  } else {
1372  $result .= $hookmanager->resPrint;
1373  }
1374  return $result;
1375  }
1376 
1383  public function getLabelStatus($mode = 0)
1384  {
1385  return $this->LibStatut($this->status, $mode);
1386  }
1387 
1394  public function getLibStatut($mode = 0)
1395  {
1396  return $this->LibStatut($this->status, $mode);
1397  }
1398 
1399  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1407  public function LibStatut($status, $mode = 0)
1408  {
1409  // phpcs:enable
1410  if (empty($this->labelStatus) || empty($this->labelStatusShort)) {
1411  global $langs;
1412  //$langs->load("asset@asset");
1413  $this->labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('AssetInProgress');
1414  $this->labelStatus[self::STATUS_DISPOSED] = $langs->transnoentitiesnoconv('AssetDisposed');
1415  $this->labelStatusShort[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('AssetInProgress');
1416  $this->labelStatusShort[self::STATUS_DISPOSED] = $langs->transnoentitiesnoconv('AssetDisposed');
1417  }
1418 
1419  $statusType = 'status4';
1420  if ($status == self::STATUS_DISPOSED) {
1421  $statusType = 'status6';
1422  }
1423 
1424  return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode);
1425  }
1426 
1433  public function info($id)
1434  {
1435  $sql = "SELECT rowid, date_creation as datec, tms as datem,";
1436  $sql .= " fk_user_creat, fk_user_modif";
1437  $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as t";
1438  $sql .= " WHERE t.rowid = ".((int) $id);
1439 
1440  $result = $this->db->query($sql);
1441  if ($result) {
1442  if ($this->db->num_rows($result)) {
1443  $obj = $this->db->fetch_object($result);
1444  $this->id = $obj->rowid;
1445 
1446  $this->user_creation_id = $obj->fk_user_author;
1447  $this->user_validation_id = $obj->fk_user_valid;
1448  $this->user_cloture_id = $obj->fk_user_cloture;
1449  $this->date_creation = $this->db->jdate($obj->datec);
1450  $this->date_modification = $this->db->jdate($obj->datem);
1451  $this->date_validation = $this->db->jdate($obj->datev);
1452  }
1453 
1454  $this->db->free($result);
1455  } else {
1456  dol_print_error($this->db);
1457  }
1458  }
1459 
1466  public function initAsSpecimen()
1467  {
1468  // Set here init that are not commonf fields
1469  // $this->property1 = ...
1470  // $this->property2 = ...
1471 
1472  $this->initAsSpecimenCommon();
1473  }
1474 
1480  public function getLinesArray()
1481  {
1482  $this->lines = array();
1483 
1484  return $this->lines;
1485  }
1486 
1492  public function getNextNumRef()
1493  {
1494  global $langs, $conf;
1495  $langs->load("asset@asset");
1496 
1497  if (empty($conf->global->ASSET_ASSET_ADDON)) {
1498  $conf->global->ASSET_ASSET_ADDON = 'mod_asset_standard';
1499  }
1500 
1501  if (!empty($conf->global->ASSET_ASSET_ADDON)) {
1502  $mybool = false;
1503 
1504  $file = $conf->global->ASSET_ASSET_ADDON.".php";
1505  $classname = $conf->global->ASSET_ASSET_ADDON;
1506 
1507  // Include file with class
1508  $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
1509  foreach ($dirmodels as $reldir) {
1510  $dir = dol_buildpath($reldir."core/modules/asset/");
1511 
1512  // Load file with numbering class (if found)
1513  $mybool |= @include_once $dir.$file;
1514  }
1515 
1516  if ($mybool === false) {
1517  dol_print_error('', "Failed to include file ".$file);
1518  return '';
1519  }
1520 
1521  if (class_exists($classname)) {
1522  $obj = new $classname();
1523  $numref = $obj->getNextValue($this);
1524 
1525  if ($numref != '' && $numref != '-1') {
1526  return $numref;
1527  } else {
1528  $this->error = $obj->error;
1529  //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error);
1530  return "";
1531  }
1532  } else {
1533  print $langs->trans("Error")." ".$langs->trans("ClassNotFound").' '.$classname;
1534  return "";
1535  }
1536  } else {
1537  print $langs->trans("ErrorNumberingModuleNotSetup", $this->element);
1538  return "";
1539  }
1540  }
1541 
1553  // public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
1554  // {
1555  // global $conf, $langs;
1556  //
1557  // $result = 0;
1558  // $includedocgeneration = 1;
1559  //
1560  // $langs->load("asset@asset");
1561  //
1562  // if (!dol_strlen($modele)) {
1563  // $modele = 'standard_asset';
1564  //
1565  // if (!empty($this->model_pdf)) {
1566  // $modele = $this->model_pdf;
1567  // } elseif (!empty($conf->global->ASSET_ADDON_PDF)) {
1568  // $modele = $conf->global->ASSET_ADDON_PDF;
1569  // }
1570  // }
1571  //
1572  // $modelpath = "core/modules/asset/doc/";
1573  //
1574  // if ($includedocgeneration && !empty($modele)) {
1575  // $result = $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
1576  // }
1577  //
1578  // return $result;
1579  // }
1580 }
Asset\fetchDepreciationLines
fetchDepreciationLines()
Fetch depreciation lines for each mode in $this->depreciation_lines (sort by depreciation date)
Definition: asset.class.php:636
CommonObject\deleteCommon
deleteCommon(User $user, $notrigger=false, $forcechilddeletion=0)
Delete object in database.
Definition: commonobject.class.php:9406
Asset
Class for Asset.
Definition: asset.class.php:30
dol_getdate
dol_getdate($timestamp, $fast=false, $forcetimezone='')
Return an array with locale date info.
Definition: functions.lib.php:2713
CommonObject\setStatusCommon
setStatusCommon($user, $status, $notrigger=0, $triggercode='')
Set to a status.
Definition: commonobject.class.php:9683
db
$conf db
API class for accounts.
Definition: inc.php:41
dol_escape_htmltag
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0)
Returns text escaped for inclusion in HTML alt or title tags, or into values of HTML input fields.
Definition: functions.lib.php:1468
CommonObject\fetchCommon
fetchCommon($id, $ref=null, $morewhere='')
Load object in memory from the database.
Definition: commonobject.class.php:9202
dol_trunc
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
Definition: functions.lib.php:3805
dol_sanitizeFileName
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
Definition: functions.lib.php:1226
Asset\getNomUrl
getNomUrl($withpicto=0, $option='', $maxlen=0, $notooltip=0, $morecss='', $save_lastsearch_value=-1)
Return a link to the object card (with optionaly the picto)
Definition: asset.class.php:1268
AssetAccountancyCodes
Class for AssetAccountancyCodes.
Definition: assetaccountancycodes.class.php:29
DoliDB
Class to manage Dolibarr database access.
Definition: DoliDB.class.php:30
GETPOST
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
Definition: functions.lib.php:484
Asset\info
info($id)
Load the info information in the object.
Definition: asset.class.php:1433
dol_print_error
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
Definition: functions.lib.php:4844
Translate
Class to manage translations.
Definition: translate.class.php:30
dol_buildpath
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
Definition: functions.lib.php:1062
Asset\update
update(User $user, $notrigger=false)
Update object into database.
Definition: asset.class.php:477
Asset\getLibStatut
getLibStatut($mode=0)
Return the label of the status.
Definition: asset.class.php:1394
CommonObject\deleteObjectLinked
deleteObjectLinked($sourceid=null, $sourcetype='', $targetid=null, $targettype='', $rowid='', $f_user=null, $notrigger=0)
Delete all links between an object $this.
Definition: commonobject.class.php:4228
ref
$object ref
Definition: info.php:77
Asset\createFromClone
createFromClone(User $user, $fromid)
Clone an object into another one.
Definition: asset.class.php:256
dol_dir_list
dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0)
Scan a directory and return a list of files/directories.
Definition: files.lib.php:60
CommonObject\initAsSpecimenCommon
initAsSpecimenCommon()
Initialise object with example values Id must be 0 if object instance is a specimen.
Definition: commonobject.class.php:9733
CommonObject
Parent class of all other business classes (invoices, contracts, proposals, orders,...
Definition: commonobject.class.php:44
price2num
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
Definition: functions.lib.php:5661
dol_print_date
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
Definition: functions.lib.php:2514
img_picto
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
Definition: functions.lib.php:3880
Asset\getLinesArray
getLinesArray()
Create an array of lines.
Definition: asset.class.php:1480
CommonObject\createCommon
createCommon(User $user, $notrigger=false)
Create object into database.
Definition: commonobject.class.php:9035
Asset\calculationDepreciation
calculationDepreciation()
Calculation depreciation lines (reversal and future) for each mode.
Definition: asset.class.php:795
Asset\initAsSpecimen
initAsSpecimen()
Initialise object with example values Id must be 0 if object instance is a specimen.
Definition: asset.class.php:1466
Asset\getLabelStatus
getLabelStatus($mode=0)
Return the label of the status.
Definition: asset.class.php:1383
Asset\dispose
dispose($user, $disposal_invoice_id, $notrigger=0)
Set dispose status.
Definition: asset.class.php:1137
AssetDepreciationOptions
Class for AssetDepreciationOptions.
Definition: assetdepreciationoptions.class.php:29
dol_syslog
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
Definition: functions.lib.php:1603
Asset\LibStatut
LibStatut($status, $mode=0)
Return the status.
Definition: asset.class.php:1407
dol_get_first_day
dol_get_first_day($year, $month=1, $gm=false)
Return GMT time for first day of a month or year.
Definition: date.lib.php:551
num_between_day
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:956
CommonObject\updateCommon
updateCommon(User $user, $notrigger=false)
Update object into database.
Definition: commonobject.class.php:9308
Asset\setLastCumulativeDepreciation
setLastCumulativeDepreciation($asset_depreciation_id)
Set last cumulative depreciation for each mode.
Definition: asset.class.php:1072
Asset\reopen
reopen($user, $notrigger=0)
Set back to validated status.
Definition: asset.class.php:1201
dol_get_last_day
dol_get_last_day($year, $month=12, $gm=false)
Return GMT time for last day of a month or year.
Definition: date.lib.php:570
Asset\addDepreciationLine
addDepreciationLine($mode, $ref, $depreciation_date, $depreciation_ht, $cumulative_depreciation_ht, $accountancy_code_debit, $accountancy_code_credit)
Add depreciation line for a mode.
Definition: asset.class.php:747
Asset\fetchAll
fetchAll($sortorder='', $sortfield='', $limit=0, $offset=0, array $filter=array(), $filtermode='AND')
Load list of objects in memory from the database.
Definition: asset.class.php:401
Asset\fetchLines
fetchLines()
Load object lines in memory from the database.
Definition: asset.class.php:382
dol_time_plus_duree
dol_time_plus_duree($time, $duration_value, $duration_unit, $ruleforendofmonth=0)
Add a delay to a date.
Definition: date.lib.php:121
User
Class to manage Dolibarr users.
Definition: user.class.php:44
Asset\__construct
__construct(DoliDB $db)
Constructor.
Definition: asset.class.php:189
CommonObject\add_object_linked
add_object_linked($origin=null, $origin_id=null, $f_user=null, $notrigger=0)
Add an object link into llx_element_element.
Definition: commonobject.class.php:3818
dolGetStatus
dolGetStatus($statusLabel='', $statusLabelShort='', $html='', $statusType='status0', $displayMode=0, $url='', $params=array())
Output the badge of a status.
Definition: functions.lib.php:10338
Asset\create
create(User $user, $notrigger=false)
Create object into database.
Definition: asset.class.php:228
img_object
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
Definition: functions.lib.php:4211
Asset\getNextNumRef
getNextNumRef()
Returns the reference to the following non used object depending on the active numbering module.
Definition: asset.class.php:1492
Asset\setDataFromAssetModel
setDataFromAssetModel(User $user, $notrigger=false)
Set asset model.
Definition: asset.class.php:527
$resql
if(isModEnabled('facture') &&!empty($user->rights->facture->lire)) if((isModEnabled('fournisseur') &&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->rights->fournisseur->facture->lire)||(isModEnabled('supplier_invoice') && $user->rights->supplier_invoice->lire)) if(isModEnabled('don') &&!empty($user->rights->don->lire)) if(isModEnabled('tax') &&!empty($user->rights->tax->charges->lire)) if(isModEnabled('facture') &&isModEnabled('commande') && $user->rights->commande->lire &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $resql
Social contributions to pay.
Definition: index.php:742
getDefaultDatesForTransfer
getDefaultDatesForTransfer()
Return Default dates for transfer based on periodicity option in accountancy setup.
Definition: accounting.lib.php:273
CommonObject\getFieldList
getFieldList($alias='')
Function to concat keys of fields.
Definition: commonobject.class.php:8987
Asset\fetch
fetch($id, $ref=null)
Load object in memory from the database.
Definition: asset.class.php:356
if
if(!defined( 'CSRFCHECK_WITH_TOKEN'))
Definition: journals_list.php:25
Asset\hasDepreciationLinesInBookkeeping
hasDepreciationLinesInBookkeeping()
If has depreciation lines in bookkeeping.
Definition: asset.class.php:693