dolibarr  17.0.4
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 (!isModEnabled('multicompany') && 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->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  // Old request with 'WITH'
656  /*
657  $sql = "WITH in_accounting_bookkeeping(fk_docdet) AS (";
658  $sql .= " SELECT DISTINCT fk_docdet";
659  $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping";
660  $sql .= " WHERE doc_type = 'asset'";
661  $sql .= ")";
662  $sql .= "SELECT ad.rowid, ad.depreciation_mode, ad.ref, ad.depreciation_date, ad.depreciation_ht, ad.cumulative_depreciation_ht";
663  $sql .= ", " . $this->db->ifsql('iab.fk_docdet IS NOT NULL', 1, 0) . " AS bookkeeping";
664  $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
665  $sql .= " LEFT JOIN in_accounting_bookkeeping as iab ON iab.fk_docdet = ad.rowid";
666  $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
667  $sql .= " ORDER BY ad.depreciation_date ASC";
668  */
669 
670  $sql = "SELECT ad.rowid, ad.depreciation_mode, ad.ref, ad.depreciation_date, ad.depreciation_ht, ad.cumulative_depreciation_ht";
671  $sql .= ", " . $this->db->ifsql('iab.fk_docdet IS NOT NULL', 1, 0) . " AS bookkeeping";
672  $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
673  $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";
674  $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
675  $sql .= " ORDER BY ad.depreciation_date ASC";
676 
677  $resql = $this->db->query($sql);
678  if (!$resql) {
679  $this->errors[] = $langs->trans('AssetErrorFetchDepreciationLines') . ': ' . $this->db->lasterror();
680  return -1;
681  }
682 
683  while ($obj = $this->db->fetch_object($resql)) {
684  if (!isset($this->depreciation_lines[$obj->depreciation_mode])) $this->depreciation_lines[$obj->depreciation_mode] = array();
685  $this->depreciation_lines[$obj->depreciation_mode][] = array(
686  'id' => $obj->rowid,
687  'ref' => $obj->ref,
688  'depreciation_date' => $this->db->jdate($obj->depreciation_date),
689  'depreciation_ht' => $obj->depreciation_ht,
690  'cumulative_depreciation_ht' => $obj->cumulative_depreciation_ht,
691  'bookkeeping' => $obj->bookkeeping,
692  );
693  }
694 
695  return 1;
696  }
697 
704  {
705  global $langs;
706  $langs->load('assets');
707 
708  // Clean parameters
709  $this->id = $this->id > 0 ? $this->id : 0;
710 
711  // Check parameters
712  $error = 0;
713  if (empty($this->id)) {
714  $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Asset") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
715  $error++;
716  }
717  if ($error) {
718  return -1;
719  }
720 
721  // Old request with 'WITH'
722  /*
723  $sql = "WITH in_accounting_bookkeeping(fk_docdet) AS (";
724  $sql .= " SELECT DISTINCT fk_docdet";
725  $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping";
726  $sql .= " WHERE doc_type = 'asset'";
727  $sql .= ")";
728  $sql .= "SELECT COUNT(*) AS has_bookkeeping";
729  $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
730  $sql .= " LEFT JOIN in_accounting_bookkeeping as iab ON iab.fk_docdet = ad.rowid";
731  $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
732  $sql .= " AND iab.fk_docdet IS NOT NULL";
733  */
734 
735  $sql = "SELECT COUNT(*) AS has_bookkeeping";
736  $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
737  $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";
738  $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
739  $sql .= " AND iab.fk_docdet IS NOT NULL";
740 
741  $resql = $this->db->query($sql);
742  if (!$resql) {
743  $this->errors[] = $langs->trans('AssetErrorFetchDepreciationLines') . ': ' . $this->db->lasterror();
744  return -1;
745  }
746 
747  if ($obj = $this->db->fetch_object($resql)) {
748  return $obj->has_bookkeeping > 0 ? 1 : 0;
749  }
750 
751  return 0;
752  }
753 
766  public function addDepreciationLine($mode, $ref, $depreciation_date, $depreciation_ht, $cumulative_depreciation_ht, $accountancy_code_debit, $accountancy_code_credit)
767  {
768  global $langs;
769  $langs->load('assets');
770 
771  // Clean parameters
772  $this->id = $this->id > 0 ? $this->id : 0;
773  $mode = strtolower(trim($mode));
774  $ref = trim($ref);
775  $accountancy_code_debit = trim($accountancy_code_debit);
776  $accountancy_code_credit = trim($accountancy_code_credit);
777 
778  // Check parameters
779  $error = 0;
780  if (empty($this->id)) {
781  $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Asset") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
782  $error++;
783  }
784  if ($error) {
785  return -1;
786  }
787 
788  $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)";
789  $sql .= " VALUES ( ";
790  $sql .= " " . (int) $this->id;
791  $sql .= ", '" . $this->db->escape($mode) . "'";
792  $sql .= ", '" . $this->db->escape($ref) . "'";
793  $sql .= ", '" . $this->db->idate($depreciation_date) . "'";
794  $sql .= ", " . (double) $depreciation_ht;
795  $sql .= ", " . (double) $cumulative_depreciation_ht;
796  $sql .= ", '" . $this->db->escape($accountancy_code_debit) . "'";
797  $sql .= ", '" . $this->db->escape($accountancy_code_credit) . "'";
798  $sql .= ")";
799 
800  $resql = $this->db->query($sql);
801  if (!$resql) {
802  $this->errors[] = $langs->trans('AssetErrorAddDepreciationLine') . ': ' . $this->db->lasterror();
803  return -1;
804  }
805 
806  return 1;
807  }
808 
814  public function calculationDepreciation()
815  {
816  global $conf, $langs;
817  $langs->load('assets');
818 
819  // Clean parameters
820  $this->id = $this->id > 0 ? $this->id : 0;
821 
822  // Check parameters
823  $error = 0;
824  if (empty($this->id)) {
825  $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Asset") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
826  $error++;
827  }
828  if ($error) {
829  return -1;
830  }
831 
832  // Get depreciation options
833  //---------------------------
834  require_once DOL_DOCUMENT_ROOT . '/asset/class/assetdepreciationoptions.class.php';
835  $options = new AssetDepreciationOptions($this->db);
836  $result = $options->fetchDeprecationOptions($this->id);
837  if ($result < 0) {
838  $this->error = $options->error;
839  $this->errors = $options->errors;
840  return -1;
841  }
842 
843  // Get accountancy codes
844  //---------------------------
845  require_once DOL_DOCUMENT_ROOT . '/asset/class/assetaccountancycodes.class.php';
846  $accountancy_codes = new AssetAccountancyCodes($this->db);
847  $result = $accountancy_codes->fetchAccountancyCodes($this->id);
848  if ($result < 0) {
849  $this->error = $accountancy_codes->error;
850  $this->errors = $accountancy_codes->errors;
851  return -1;
852  }
853 
854  $this->db->begin();
855 
856  // Delete old lines
857  $modes = array();
858  foreach ($options->deprecation_options as $mode_key => $fields) {
859  $modes[$mode_key] = $this->db->escape($mode_key);
860  }
861  $sql = "DELETE FROM " . MAIN_DB_PREFIX . "asset_depreciation";
862  $sql .= " WHERE fk_asset = " . (int) $this->id;
863  $sql .= " AND depreciation_mode NOT IN ('" . $this->db->sanitize(implode("', '", $modes)) . "')";
864 
865  $resql = $this->db->query($sql);
866  if (!$resql) {
867  $this->errors[] = $langs->trans('AssetErrorClearDepreciationLines') . ': ' . $this->db->lasterror();
868  $error++;
869  }
870 
871  if (!$error) {
872  // Get fiscal period
873  require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
874  require_once DOL_DOCUMENT_ROOT . '/core/lib/accounting.lib.php';
875  $dates = getDefaultDatesForTransfer();
876  $init_fiscal_period_start = $dates['date_start'];
877  $init_fiscal_period_end = $dates['date_end'];
878  if (empty($init_fiscal_period_start) || empty($init_fiscal_period_end)) {
879  $pastmonthyear = $dates['pastmonthyear'];
880  $pastmonth = $dates['pastmonth'];
881  $init_fiscal_period_start = dol_get_first_day($pastmonthyear, $pastmonth, false);
882  $init_fiscal_period_end = dol_get_last_day($pastmonthyear, $pastmonth, false);
883  }
884 
885  foreach ($options->deprecation_options as $mode_key => $fields) {
886  // Get last depreciation lines save in bookkeeping
887  //-----------------------------------------------------
888 
889  // Old request with 'WITH'
890  /*
891  $sql = "WITH in_accounting_bookkeeping(fk_docdet) AS (";
892  $sql .= " SELECT fk_docdet";
893  $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping";
894  $sql .= " WHERE doc_type = 'asset'";
895  $sql .= ")";
896  $sql .= "SELECT ad.depreciation_date, ad.cumulative_depreciation_ht";
897  $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
898  $sql .= " LEFT JOIN in_accounting_bookkeeping as iab ON iab.fk_docdet = ad.rowid";
899  $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
900  $sql .= " AND ad.depreciation_mode = '" . $this->db->escape($mode_key) . "'";
901  $sql .= " AND iab.fk_docdet IS NOT NULL";
902  $sql .= " ORDER BY ad.depreciation_date DESC";
903  $sql .= " LIMIT 1";
904  */
905 
906  $sql = "SELECT ad.depreciation_date, ad.cumulative_depreciation_ht";
907  $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
908  $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";
909  $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
910  $sql .= " AND ad.depreciation_mode = '" . $this->db->escape($mode_key) . "'";
911  $sql .= " AND iab.fk_docdet IS NOT NULL";
912  $sql .= " ORDER BY ad.depreciation_date DESC";
913  $sql .= " LIMIT 1";
914 
915  $resql = $this->db->query($sql);
916  if (!$resql) {
917  $this->errors[] = $langs->trans('AssetErrorFetchMaxDepreciationDateForMode', $mode_key) . ': ' . $this->db->lasterror();
918  $error++;
919  break;
920  }
921  $last_depreciation_date = '';
922  $last_cumulative_depreciation_ht = $this->reversal_amount_ht;
923  if ($obj = $this->db->fetch_object($resql)) {
924  $last_depreciation_date = $this->db->jdate($obj->depreciation_date);
925  $last_cumulative_depreciation_ht = $obj->cumulative_depreciation_ht;
926  }
927 
928  // Set last cumulative depreciation
929  $sql = "UPDATE " . MAIN_DB_PREFIX . $options->deprecation_options_fields[$mode_key]['table'];
930  $sql .= " SET total_amount_last_depreciation_ht = " . (empty($last_cumulative_depreciation_ht) ? 0 : $last_cumulative_depreciation_ht);
931  $sql .= " WHERE fk_asset = " . (int) $this->id;
932  $resql = $this->db->query($sql);
933  if (!$resql) {
934  $this->errors[] = $langs->trans('AssetErrorSetLastCumulativeDepreciation') . ': ' . $this->db->lasterror();
935  $error++;
936  break;
937  }
938 
939  // Delete old lines
940  $sql = "DELETE " . MAIN_DB_PREFIX . "asset_depreciation FROM " . MAIN_DB_PREFIX . "asset_depreciation";
941  $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";
942  $sql .= " WHERE " . MAIN_DB_PREFIX . "asset_depreciation.fk_asset = " . (int) $this->id;
943  $sql .= " AND " . MAIN_DB_PREFIX . "asset_depreciation.depreciation_mode = '" . $this->db->escape($mode_key) . "'";
944  $sql .= " AND ab.fk_docdet IS NULL";
945  if ($last_depreciation_date !== "") $sql .= " AND " . MAIN_DB_PREFIX . "asset_depreciation.ref != ''";
946  $resql = $this->db->query($sql);
947  if (!$resql) {
948  $this->errors[] = $langs->trans('AssetErrorClearDepreciationLines') . ': ' . $this->db->lasterror();
949  $error++;
950  break;
951  }
952 
953  // Get depreciation period
954  $depreciation_date_start = $this->date_start > $this->date_acquisition ? $this->date_start : $this->date_acquisition;
955  $depreciation_date_end = dol_time_plus_duree($depreciation_date_start, $fields['duration'], $fields['duration_type'] == 1 ? 'm' : ($fields['duration_type'] == 2 ? 'd' : 'y'));
956  $depreciation_amount = $fields['amount_base_depreciation_ht'];
957  if ($fields['duration_type'] == 2) { // Daily
958  $fiscal_period_start = $depreciation_date_start;
959  $fiscal_period_end = $depreciation_date_start;
960  } elseif ($fields['duration_type'] == 1) { // Monthly
961  $date_temp = dol_getdate($depreciation_date_start);
962  $fiscal_period_start = dol_get_first_day($date_temp['year'], $date_temp['mon'], false);
963  $fiscal_period_end = dol_get_last_day($date_temp['year'], $date_temp['mon'], false);
964  } else { // Annually
965  $fiscal_period_start = $init_fiscal_period_start;
966  $fiscal_period_end = $init_fiscal_period_end;
967  }
968  $cumulative_depreciation_ht = $last_cumulative_depreciation_ht;
969  $depreciation_period_amount = $depreciation_amount - $this->reversal_amount_ht;
970  $start_date = $depreciation_date_start;
971  $disposal_date = isset($this->disposal_date) && $this->disposal_date !== "" ? $this->disposal_date : "";
972  $finish_date = $disposal_date !== "" ? $disposal_date : $depreciation_date_end;
973  $accountancy_code_depreciation_debit_key = $accountancy_codes->accountancy_codes_fields[$mode_key]['depreciation_debit'];
974  $accountancy_code_depreciation_debit = $accountancy_codes->accountancy_codes[$mode_key][$accountancy_code_depreciation_debit_key];
975  $accountancy_code_depreciation_credit_key = $accountancy_codes->accountancy_codes_fields[$mode_key]['depreciation_credit'];
976  $accountancy_code_credit = $accountancy_codes->accountancy_codes[$mode_key][$accountancy_code_depreciation_credit_key];
977 
978  // Reversal depreciation line
979  //-----------------------------------------------------
980  if ($last_depreciation_date === "" && ($depreciation_date_start < $fiscal_period_start || is_numeric($this->reversal_date))) {
981  if (is_numeric($this->reversal_date)) {
982  if ($this->reversal_date < $fiscal_period_start) {
983  $this->errors[] = $langs->trans('AssetErrorReversalDateNotGreaterThanCurrentBeginFiscalDateForMode', $mode_key);
984  $error++;
985  break;
986  }
987 
988  if (empty($this->reversal_amount_ht)) {
989  $this->errors[] = $langs->trans('AssetErrorReversalAmountNotProvidedForMode', $mode_key);
990  $error++;
991  break;
992  }
993 
994  $start_date = $this->reversal_date;
995  $result = $this->addDepreciationLine($mode_key, '', $start_date, $this->reversal_amount_ht, $this->reversal_amount_ht, $accountancy_code_depreciation_debit, $accountancy_code_credit);
996  if ($result < 0) {
997  $error++;
998  break;
999  }
1000  } else {
1001  $this->errors[] = $langs->trans('AssetErrorReversalDateNotProvidedForMode', $mode_key);
1002  $error++;
1003  break;
1004  }
1005  }
1006 
1007  // futures depreciation lines
1008  //-----------------------------------------------------
1009  $nb_days_in_year = !empty($conf->global->ASSET_DEPRECIATION_DURATION_PER_YEAR) ? $conf->global->ASSET_DEPRECIATION_DURATION_PER_YEAR : 365;
1010  $nb_days_in_month = !empty($conf->global->ASSET_DEPRECIATION_DURATION_PER_MONTH) ? $conf->global->ASSET_DEPRECIATION_DURATION_PER_MONTH : 30;
1011  $period_amount = (double) price2num($depreciation_period_amount / $fields['duration'], 'MT');
1012  $first_period_found = false;
1013  $first_period_date = isset($begin_period) && $begin_period > $fiscal_period_start ? $begin_period : $fiscal_period_start;
1014 
1015  $ref_date_format = "%Y" . ($fields['duration_type'] == 1 || $fields['duration_type'] == 2 ? '-%m' : '') . ($fields['duration_type'] == 2 ? '-%d' : '');
1016 
1017  // Loop security
1018  $idx_loop = 0;
1019  $max_loop = $fields['duration'] + 2;
1020  do {
1021  // Loop security
1022  $idx_loop++;
1023  if ($idx_loop > $max_loop) break;
1024 
1025  if ($last_depreciation_date < $fiscal_period_end && ($first_period_date <= $start_date || $first_period_found)) {
1026  // Disposal not depreciated
1027  if ($fiscal_period_start <= $disposal_date && $disposal_date <= $fiscal_period_end && empty($this->disposal_depreciated)) {
1028  break;
1029  }
1030 
1031  $first_period_found = true;
1032 
1033  $period_begin = dol_print_date($fiscal_period_start, $ref_date_format);
1034  $period_end = dol_print_date($fiscal_period_end, $ref_date_format);
1035  $ref = $period_begin . ($period_begin != $period_end ? ' - ' . $period_end : '');
1036  if ($fiscal_period_start <= $disposal_date && $disposal_date <= $fiscal_period_end) {
1037  $ref .= ' - ' . $langs->transnoentitiesnoconv('AssetDisposal');
1038  }
1039 
1040  $begin_date = $fiscal_period_start < $start_date && $start_date <= $fiscal_period_end ? $start_date : $fiscal_period_start;
1041  $end_date = $fiscal_period_start < $finish_date && $finish_date <= $fiscal_period_end ? $finish_date : $fiscal_period_end;
1042  if ($fields['duration_type'] == 2) { // Daily
1043  $depreciation_ht = $period_amount;
1044  } elseif ($fields['duration_type'] == 1) { // Monthly
1045  $nb_days = min($nb_days_in_month, num_between_day($begin_date, $end_date, 1));
1046  if ($nb_days >= 28) {
1047  $date_temp = dol_getdate($begin_date);
1048  if ($date_temp['mon'] == 2) {
1049  $nb_days = 30;
1050  }
1051  }
1052  $depreciation_ht = (double) price2num($period_amount * $nb_days / $nb_days_in_month, 'MT');
1053  } else { // Annually
1054  $nb_days = min($nb_days_in_year, num_between_day($begin_date, $end_date, 1));
1055  $depreciation_ht = (double) price2num($period_amount * $nb_days / $nb_days_in_year, 'MT');
1056  }
1057 
1058  if ($fiscal_period_start <= $depreciation_date_end && $depreciation_date_end <= $fiscal_period_end) { // last period
1059  $depreciation_ht = (double) price2num($depreciation_amount - $cumulative_depreciation_ht, 'MT');
1060  $cumulative_depreciation_ht = $depreciation_amount;
1061  } else {
1062  $cumulative_depreciation_ht += $depreciation_ht;
1063  }
1064 
1065  $result = $this->addDepreciationLine($mode_key, $ref, $fiscal_period_end, $depreciation_ht, $cumulative_depreciation_ht, $accountancy_code_depreciation_debit, $accountancy_code_credit);
1066  if ($result < 0) {
1067  $error++;
1068  break;
1069  }
1070  }
1071 
1072  // Next fiscal period (+1 day/month/year)
1073  $fiscal_period_start = dol_time_plus_duree($fiscal_period_end, 1, 'd');
1074  if ($fields['duration_type'] == 2) { // Daily
1075  $fiscal_period_end = $fiscal_period_start;
1076  } elseif ($fields['duration_type'] == 1) { // Monthly
1077  $fiscal_period_end = dol_time_plus_duree(dol_time_plus_duree($fiscal_period_start, 1, 'm'), -1, 'd');
1078  } else { // Annually
1079  $fiscal_period_end = dol_time_plus_duree(dol_time_plus_duree($fiscal_period_start, 1, 'y'), -1, 'd');
1080  }
1081  $last_period_date = $disposal_date !== "" && $disposal_date < $depreciation_date_end ? $disposal_date : $depreciation_date_end;
1082  } while ($fiscal_period_start < $last_period_date);
1083 
1084  if ($error) {
1085  break;
1086  }
1087  }
1088  }
1089 
1090  if ($error) {
1091  $this->db->rollback();
1092  return -1;
1093  } else {
1094  $this->db->commit();
1095  return 1;
1096  }
1097  }
1098 
1105  public function setLastCumulativeDepreciation($asset_depreciation_id)
1106  {
1107  global $langs;
1108  $langs->load('assets');
1109 
1110  // Clean parameters
1111  $asset_depreciation_id = $asset_depreciation_id > 0 ? $asset_depreciation_id : 0;
1112 
1113  // Check parameters
1114  $error = 0;
1115  if (empty($asset_depreciation_id)) {
1116  $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("AssetDepreciation") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
1117  $error++;
1118  }
1119  if ($error) {
1120  return -1;
1121  }
1122 
1123  $this->db->begin();
1124 
1125  require_once DOL_DOCUMENT_ROOT . '/asset/class/assetdepreciationoptions.class.php';
1126  $options = new AssetDepreciationOptions($this->db);
1127 
1128  // Get last depreciation lines save in bookkeeping
1129  //-----------------------------------------------------
1130  $sql = "SELECT fk_asset, depreciation_mode, cumulative_depreciation_ht";
1131  $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation";
1132  $sql .= " WHERE rowid = " . (int) $asset_depreciation_id;
1133  $resql = $this->db->query($sql);
1134  if (!$resql) {
1135  $this->errors[] = $langs->trans('AssetErrorFetchCumulativeDepreciation') . ': ' . $this->db->lasterror();
1136  $error++;
1137  } else {
1138  if ($obj = $this->db->fetch_object($resql)) {
1139  $mode_key = $obj->depreciation_mode;
1140  if (!empty($options->deprecation_options_fields[$mode_key])) {
1141  $sql = "UPDATE " . MAIN_DB_PREFIX . $options->deprecation_options_fields[$mode_key]['table'];
1142  $sql .= " SET total_amount_last_depreciation_ht = " . $obj->cumulative_depreciation_ht;
1143  $sql .= " WHERE fk_asset = " . (int) $obj->fk_asset;
1144  $resql = $this->db->query($sql);
1145  if (!$resql) {
1146  $this->errors[] = $langs->trans('AssetErrorSetLastCumulativeDepreciation') . ': ' . $this->db->lasterror();
1147  $error++;
1148  }
1149  }
1150  }
1151  }
1152 
1153  if ($error) {
1154  $this->db->rollback();
1155  return -1;
1156  } else {
1157  $this->db->commit();
1158  return 1;
1159  }
1160  }
1161 
1170  public function dispose($user, $disposal_invoice_id, $notrigger = 0)
1171  {
1172  global $conf, $langs;
1173 
1174  // Protection
1175  if ($this->status != self::STATUS_DRAFT || $this->status == self::STATUS_DISPOSED) {
1176  return 0;
1177  }
1178 
1179  $this->db->begin();
1180 
1181  $required_fields = array('disposal_date', 'disposal_date', 'fk_disposal_type');
1182  foreach ($required_fields as $field) {
1183  $this->fields[$field]['notnull'] = 1;
1184  }
1185  $result = $this->update($user, 1);
1186  foreach ($required_fields as $field) {
1187  $this->fields[$field]['notnull'] = 0;
1188  }
1189  if ($result > 0) {
1190  if ($disposal_invoice_id > 0) $this->add_object_linked('facture', $disposal_invoice_id);
1191  $result = $this->setStatusCommon($user, self::STATUS_DISPOSED, $notrigger, 'ASSET_DISPOSED');
1192  }
1193  if ($result > 0) $result = $this->calculationDepreciation();
1194 
1195  if ($result < 0) {
1196  $this->db->rollback();
1197  } else {
1198  $this->db->commit();
1199  }
1200 
1201  // Define output language
1202  if ($result > 0 && empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) {
1203  if (method_exists($this, 'generateDocument')) {
1204  global $hidedetails, $hidedesc, $hideref;
1205  $outputlangs = $langs;
1206  $newlang = '';
1207  if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
1208  $newlang = GETPOST('lang_id', 'aZ09');
1209  }
1210  if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
1211  $newlang = $this->thirdparty->default_lang;
1212  }
1213  if (!empty($newlang)) {
1214  $outputlangs = new Translate("", $conf);
1215  $outputlangs->setDefaultLang($newlang);
1216  }
1217  $model = $this->model_pdf;
1218  $ret = $this->fetch($this->id); // Reload to get new records
1219 
1220  $this->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
1221  }
1222  }
1223 
1224  return $result;
1225  }
1226 
1234  public function reopen($user, $notrigger = 0)
1235  {
1236  global $conf, $langs;
1237 
1238  // Protection
1239  if ($this->status != self::STATUS_DISPOSED || $this->status == self::STATUS_DRAFT) {
1240  return 0;
1241  }
1242 
1243 
1244  $this->db->begin();
1245 
1246  $this->disposal_date = null;
1247  $this->disposal_amount_ht = null;
1248  $this->fk_disposal_type = null;
1249  $this->disposal_depreciated = null;
1250  $this->disposal_subject_to_vat = null;
1251  $result = $this->update($user, 1);
1252  if ($result > 0) {
1253  $this->deleteObjectLinked(null, 'facture');
1254  $result = $this->setStatusCommon($user, self::STATUS_DRAFT, $notrigger, 'ASSET_REOPEN');
1255  }
1256  if ($result > 0) $result = $this->calculationDepreciation();
1257 
1258  if ($result < 0) {
1259  $this->db->rollback();
1260  } else {
1261  $this->db->commit();
1262  }
1263 
1264  // Define output language
1265  if ($result > 0 && empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) {
1266  if (method_exists($this, 'generateDocument')) {
1267  global $hidedetails, $hidedesc, $hideref;
1268  $outputlangs = $langs;
1269  $newlang = '';
1270  if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
1271  $newlang = GETPOST('lang_id', 'aZ09');
1272  }
1273  if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
1274  $newlang = $this->thirdparty->default_lang;
1275  }
1276  if (!empty($newlang)) {
1277  $outputlangs = new Translate("", $conf);
1278  $outputlangs->setDefaultLang($newlang);
1279  }
1280  $model = $this->model_pdf;
1281  $ret = $this->fetch($this->id); // Reload to get new records
1282 
1283  $this->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
1284  }
1285  }
1286 
1287  return $result;
1288  }
1289 
1301  public function getNomUrl($withpicto = 0, $option = '', $maxlen = 0, $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
1302  {
1303  global $db, $conf, $langs, $hookmanager;
1304  global $dolibarr_main_authentication, $dolibarr_main_demo;
1305  global $menumanager;
1306 
1307  if (!empty($conf->dol_no_mouse_hover)) {
1308  $notooltip = 1; // Force disable tooltips
1309  }
1310 
1311  $result = '';
1312 
1313  $label = img_picto('', $this->picto).' <u>'.$langs->trans("Asset").'</u>';
1314  if (isset($this->status)) {
1315  $label .= ' '.$this->getLibStatut(5);
1316  }
1317  $label .= '<br>';
1318  $label .= '<b>'.$langs->trans('Ref').':</b> '.$this->ref;
1319 
1320  $url = dol_buildpath('/asset/card.php', 1).'?id='.$this->id;
1321 
1322  if ($option != 'nolink') {
1323  // Add param to save lastsearch_values or not
1324  $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1325  if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
1326  $add_save_lastsearch_values = 1;
1327  }
1328  if ($add_save_lastsearch_values) {
1329  $url .= '&save_lastsearch_values=1';
1330  }
1331  }
1332 
1333  $linkclose = '';
1334  if (empty($notooltip)) {
1335  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
1336  $label = $langs->trans("ShowAsset");
1337  $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
1338  }
1339  $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
1340  $linkclose .= ' class="classfortooltip'.($morecss ? ' '.$morecss : '').'"';
1341  } else {
1342  $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
1343  }
1344 
1345  if ($option == 'nolink') {
1346  $linkstart = '<span';
1347  } else {
1348  $linkstart = '<a href="'.$url.'"';
1349  }
1350  $linkstart .= $linkclose.'>';
1351  if ($option == 'nolink') {
1352  $linkend = '</span>';
1353  } else {
1354  $linkend = '</a>';
1355  }
1356 
1357  $result .= $linkstart;
1358 
1359  if (empty($this->showphoto_on_popup)) {
1360  if ($withpicto) {
1361  $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);
1362  }
1363  } else {
1364  if ($withpicto) {
1365  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1366 
1367  list($class, $module) = explode('@', $this->picto);
1368  $upload_dir = $conf->$module->multidir_output[$conf->entity]."/$class/".dol_sanitizeFileName($this->ref);
1369  $filearray = dol_dir_list($upload_dir, "files");
1370  $filename = $filearray[0]['name'];
1371  if (!empty($filename)) {
1372  $pospoint = strpos($filearray[0]['name'], '.');
1373 
1374  $pathtophoto = $class.'/'.$this->ref.'/thumbs/'.substr($filename, 0, $pospoint).'_mini'.substr($filename, $pospoint);
1375  if (empty($conf->global->{strtoupper($module.'_'.$class).'_FORMATLISTPHOTOSASUSERS'})) {
1376  $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>';
1377  } else {
1378  $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>';
1379  }
1380 
1381  $result .= '</div>';
1382  } else {
1383  $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);
1384  }
1385  }
1386  }
1387 
1388  if ($withpicto != 2) {
1389  $name = $this->ref;
1390  if ($option == 'label') $name = $this->label;
1391  elseif ($option == 'with_label') $name .= ' - ' . $this->label;
1392  $result .= dol_escape_htmltag($maxlen ? dol_trunc($name, $maxlen) : $name);
1393  }
1394 
1395  $result .= $linkend;
1396  //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
1397 
1398  global $action;
1399  $hookmanager->initHooks(array($this->element . 'dao'));
1400  $parameters = array('id'=>$this->id, 'getnomurl' => &$result);
1401  $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1402  if ($reshook > 0) {
1403  $result = $hookmanager->resPrint;
1404  } else {
1405  $result .= $hookmanager->resPrint;
1406  }
1407  return $result;
1408  }
1409 
1416  public function getLabelStatus($mode = 0)
1417  {
1418  return $this->LibStatut($this->status, $mode);
1419  }
1420 
1427  public function getLibStatut($mode = 0)
1428  {
1429  return $this->LibStatut($this->status, $mode);
1430  }
1431 
1432  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1440  public function LibStatut($status, $mode = 0)
1441  {
1442  // phpcs:enable
1443  if (empty($this->labelStatus) || empty($this->labelStatusShort)) {
1444  global $langs;
1445  //$langs->load("asset@asset");
1446  $this->labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('AssetInProgress');
1447  $this->labelStatus[self::STATUS_DISPOSED] = $langs->transnoentitiesnoconv('AssetDisposed');
1448  $this->labelStatusShort[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('AssetInProgress');
1449  $this->labelStatusShort[self::STATUS_DISPOSED] = $langs->transnoentitiesnoconv('AssetDisposed');
1450  }
1451 
1452  $statusType = 'status4';
1453  if ($status == self::STATUS_DISPOSED) {
1454  $statusType = 'status6';
1455  }
1456 
1457  return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode);
1458  }
1459 
1466  public function info($id)
1467  {
1468  $sql = "SELECT rowid, date_creation as datec, tms as datem,";
1469  $sql .= " fk_user_creat, fk_user_modif";
1470  $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as t";
1471  $sql .= " WHERE t.rowid = ".((int) $id);
1472 
1473  $result = $this->db->query($sql);
1474  if ($result) {
1475  if ($this->db->num_rows($result)) {
1476  $obj = $this->db->fetch_object($result);
1477  $this->id = $obj->rowid;
1478 
1479  $this->user_creation_id = $obj->fk_user_author;
1480  $this->user_validation_id = $obj->fk_user_valid;
1481  $this->user_cloture_id = $obj->fk_user_cloture;
1482  $this->date_creation = $this->db->jdate($obj->datec);
1483  $this->date_modification = $this->db->jdate($obj->datem);
1484  $this->date_validation = $this->db->jdate($obj->datev);
1485  }
1486 
1487  $this->db->free($result);
1488  } else {
1489  dol_print_error($this->db);
1490  }
1491  }
1492 
1499  public function initAsSpecimen()
1500  {
1501  // Set here init that are not commonf fields
1502  // $this->property1 = ...
1503  // $this->property2 = ...
1504 
1505  $this->initAsSpecimenCommon();
1506  }
1507 
1513  public function getLinesArray()
1514  {
1515  $this->lines = array();
1516 
1517  return $this->lines;
1518  }
1519 
1525  public function getNextNumRef()
1526  {
1527  global $langs, $conf;
1528  $langs->load("asset@asset");
1529 
1530  if (empty($conf->global->ASSET_ASSET_ADDON)) {
1531  $conf->global->ASSET_ASSET_ADDON = 'mod_asset_standard';
1532  }
1533 
1534  if (!empty($conf->global->ASSET_ASSET_ADDON)) {
1535  $mybool = false;
1536 
1537  $file = $conf->global->ASSET_ASSET_ADDON.".php";
1538  $classname = $conf->global->ASSET_ASSET_ADDON;
1539 
1540  // Include file with class
1541  $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
1542  foreach ($dirmodels as $reldir) {
1543  $dir = dol_buildpath($reldir."core/modules/asset/");
1544 
1545  // Load file with numbering class (if found)
1546  $mybool |= @include_once $dir.$file;
1547  }
1548 
1549  if ($mybool === false) {
1550  dol_print_error('', "Failed to include file ".$file);
1551  return '';
1552  }
1553 
1554  if (class_exists($classname)) {
1555  $obj = new $classname();
1556  $numref = $obj->getNextValue($this);
1557 
1558  if ($numref != '' && $numref != '-1') {
1559  return $numref;
1560  } else {
1561  $this->error = $obj->error;
1562  //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error);
1563  return "";
1564  }
1565  } else {
1566  print $langs->trans("Error")." ".$langs->trans("ClassNotFound").' '.$classname;
1567  return "";
1568  }
1569  } else {
1570  print $langs->trans("ErrorNumberingModuleNotSetup", $this->element);
1571  return "";
1572  }
1573  }
1574 
1586  // public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
1587  // {
1588  // global $conf, $langs;
1589  //
1590  // $result = 0;
1591  // $includedocgeneration = 1;
1592  //
1593  // $langs->load("asset@asset");
1594  //
1595  // if (!dol_strlen($modele)) {
1596  // $modele = 'standard_asset';
1597  //
1598  // if (!empty($this->model_pdf)) {
1599  // $modele = $this->model_pdf;
1600  // } elseif (!empty($conf->global->ASSET_ADDON_PDF)) {
1601  // $modele = $conf->global->ASSET_ADDON_PDF;
1602  // }
1603  // }
1604  //
1605  // $modelpath = "core/modules/asset/doc/";
1606  //
1607  // if ($includedocgeneration && !empty($modele)) {
1608  // $result = $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
1609  // }
1610  //
1611  // return $result;
1612  // }
1613 }
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:47
if(isModEnabled('facture') &&!empty($user->rights->facture->lire)) if((isModEnabled('fournisseur') &&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->hasRight("fournisseur", "facture", "lire"))||(isModEnabled('supplier_invoice') && $user->hasRight("supplier_invoice", "lire"))) if(isModEnabled('don') &&!empty($user->rights->don->lire)) if(isModEnabled('tax') &&!empty($user->rights->tax->charges->lire)) if(isModEnabled('facture') &&isModEnabled('commande') && $user->hasRight("commande", "lire") &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $resql
Social contributions to pay.
Definition: index.php:745
dol_get_first_day($year, $month=1, $gm=false)
Return GMT time for first day of a month or year.
Definition: date.lib.php:575
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:121
dol_get_last_day($year, $month=12, $gm=false)
Return GMT time for last day of a month or year.
Definition: date.lib.php:594
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:61
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.
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.
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.
if(!defined( 'CSRFCHECK_WITH_TOKEN'))
$conf db
API class for accounts.
Definition: inc.php:41