dolibarr 19.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
25require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
26
30class 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
162 public $oldcopy;
163
164
168 public $asset_depreciation_options;
172 public $depreciation_lines = array();
173
179 public function __construct(DoliDB $db)
180 {
181 global $conf, $langs;
182
183 $this->db = $db;
184
185 if (!getDolGlobalString('MAIN_SHOW_TECHNICAL_ID') && isset($this->fields['rowid'])) {
186 $this->fields['rowid']['visible'] = 0;
187 }
188 if (!isModEnabled('multicompany') && isset($this->fields['entity'])) {
189 $this->fields['entity']['enabled'] = 0;
190 }
191
192 // Unset fields that are disabled
193 foreach ($this->fields as $key => $val) {
194 if (isset($val['enabled']) && empty($val['enabled'])) {
195 unset($this->fields[$key]);
196 }
197 }
198
199 // Translate some data of arrayofkeyval
200 if (is_object($langs)) {
201 foreach ($this->fields as $key => $val) {
202 if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
203 foreach ($val['arrayofkeyval'] as $key2 => $val2) {
204 $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2);
205 }
206 }
207 }
208 }
209 }
210
218 public function create(User $user, $notrigger = false)
219 {
220 if (!isset($this->date_start) || $this->date_start === "") {
221 $this->date_start = $this->date_acquisition;
222 }
223
224 $this->db->begin();
225
226 $result = $result_create = $this->createCommon($user, $notrigger);
227 if ($result > 0 && $this->fk_asset_model > 0) {
228 $result = $this->setDataFromAssetModel($user, $notrigger);
229 }
230 if ($result > 0) {
231 if ($this->supplier_invoice_id > 0) {
232 $this->add_object_linked('invoice_supplier', $this->supplier_invoice_id);
233 }
234 }
235
236 if ($result < 0) {
237 $this->db->rollback();
238 } else {
239 $this->db->commit();
240 }
241
242 return $result > 0 ? $result_create : $result;
243 }
244
252 public function createFromClone(User $user, $fromid)
253 {
254 global $langs, $extrafields;
255 $error = 0;
256
257 dol_syslog(__METHOD__, LOG_DEBUG);
258
259 // $object = new self($this->db);
260 //
261 // $this->db->begin();
262 //
263 // // Load source object
264 // $result = $object->fetchCommon($fromid);
265 // if ($result > 0 && !empty($object->table_element_line)) {
266 // $object->fetchLines();
267 // }
268 //
269 // // get lines so they will be clone
270 // //foreach($this->lines as $line)
271 // // $line->fetch_optionals();
272 //
273 // // Reset some properties
274 // unset($object->id);
275 // unset($object->fk_user_creat);
276 // unset($object->import_key);
277 //
278 // // Clear fields
279 // if (property_exists($object, 'ref')) {
280 // $object->ref = empty($this->fields['ref']['default']) ? "Copy_Of_".$object->ref : $this->fields['ref']['default'];
281 // }
282 // if (property_exists($object, 'label')) {
283 // $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf")." ".$object->label : $this->fields['label']['default'];
284 // }
285 // if (property_exists($object, 'status')) {
286 // $object->status = self::STATUS_DRAFT;
287 // }
288 // if (property_exists($object, 'date_creation')) {
289 // $object->date_creation = dol_now();
290 // }
291 // if (property_exists($object, 'date_modification')) {
292 // $object->date_modification = null;
293 // }
294 // // ...
295 // // Clear extrafields that are unique
296 // if (is_array($object->array_options) && count($object->array_options) > 0) {
297 // $extrafields->fetch_name_optionals_label($this->table_element);
298 // foreach ($object->array_options as $key => $option) {
299 // $shortkey = preg_replace('/options_/', '', $key);
300 // if (!empty($extrafields->attributes[$this->table_element]['unique'][$shortkey])) {
301 // //var_dump($key); var_dump($clonedObj->array_options[$key]); exit;
302 // unset($object->array_options[$key]);
303 // }
304 // }
305 // }
306 //
307 // // Create clone
308 // $object->context['createfromclone'] = 'createfromclone';
309 // $result = $object->createCommon($user);
310 // if ($result < 0) {
311 // $error++;
312 // $this->error = $object->error;
313 // $this->errors = $object->errors;
314 // }
315 //
316 // if (!$error) {
317 // // copy internal contacts
318 // if ($this->copy_linked_contact($object, 'internal') < 0) {
319 // $error++;
320 // }
321 // }
322 //
323 // if (!$error) {
324 // // copy external contacts if same company
325 // if (property_exists($this, 'fk_soc') && $this->fk_soc == $object->socid) {
326 // if ($this->copy_linked_contact($object, 'external') < 0) {
327 // $error++;
328 // }
329 // }
330 // }
331 //
332 // unset($object->context['createfromclone']);
333 //
334 // // End
335 // if (!$error) {
336 // $this->db->commit();
337 // return $object;
338 // } else {
339 // $this->db->rollback();
340 // return -1;
341 // }
342 return -1;
343 }
344
352 public function fetch($id, $ref = null)
353 {
354 $result = $this->fetchCommon($id, $ref);
355 if ($result > 0) {
356 if (!empty($this->table_element_line)) {
357 $this->fetchLines();
358 }
359
360 $res = $this->hasDepreciationLinesInBookkeeping();
361 if ($res < 0) {
362 return -1;
363 } elseif ($res > 0) {
364 $this->fields['date_acquisition']['noteditable'] = '1';
365 $this->fields['date_start']['noteditable'] = '1';
366 $this->fields['acquisition_value_ht']['noteditable'] = '1';
367 $this->fields['recovered_vat']['noteditable'] = '1';
368 $this->fields['reversal_date']['noteditable'] = '1';
369 $this->fields['reversal_amount_ht']['noteditable'] = '1';
370 }
371 }
372 return $result;
373 }
374
380 public function fetchLines()
381 {
382 $this->lines = array();
383
384 return 1;
385 }
386
387
399 public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND')
400 {
401 global $conf;
402
403 dol_syslog(__METHOD__, LOG_DEBUG);
404
405 $records = array();
406
407 $sql = "SELECT ";
408 $sql .= $this->getFieldList('t');
409 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as t";
410 if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
411 $sql .= " WHERE t.entity IN (".getEntity($this->element).")";
412 } else {
413 $sql .= " WHERE 1 = 1";
414 }
415 // Manage filter
416 $sqlwhere = array();
417 if (count($filter) > 0) {
418 foreach ($filter as $key => $value) {
419 if ($key == 't.rowid') {
420 $sqlwhere[] = $key." = ".((int) $value);
421 } elseif (array_key_exists($key, $this->fields) && in_array($this->fields[$key]['type'], array('date', 'datetime', 'timestamp'))) {
422 $sqlwhere[] = $key." = '".$this->db->idate($value)."'";
423 } elseif ($key == 'customsql') {
424 $sqlwhere[] = $value;
425 } elseif (strpos($value, '%') === false) {
426 $sqlwhere[] = $key." IN (".$this->db->sanitize($this->db->escape($value)).")";
427 } else {
428 $sqlwhere[] = $key." LIKE '%".$this->db->escape($value)."%'";
429 }
430 }
431 }
432 if (count($sqlwhere) > 0) {
433 $sql .= " AND (".implode(" ".$filtermode." ", $sqlwhere).")";
434 }
435
436 if (!empty($sortfield)) {
437 $sql .= $this->db->order($sortfield, $sortorder);
438 }
439 if (!empty($limit)) {
440 $sql .= $this->db->plimit($limit, $offset);
441 }
442
443 $resql = $this->db->query($sql);
444 if ($resql) {
445 $num = $this->db->num_rows($resql);
446 $i = 0;
447 while ($i < ($limit ? min($limit, $num) : $num)) {
448 $obj = $this->db->fetch_object($resql);
449
450 $record = new self($this->db);
451 $record->setVarsFromFetchObj($obj);
452
453 $records[$record->id] = $record;
454
455 $i++;
456 }
457 $this->db->free($resql);
458
459 return $records;
460 } else {
461 $this->errors[] = 'Error '.$this->db->lasterror();
462 dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
463
464 return -1;
465 }
466 }
467
475 public function update(User $user, $notrigger = false)
476 {
477 if (!isset($this->date_start) || $this->date_start === "") {
478 $this->date_start = $this->date_acquisition;
479 }
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])) {
685 $this->depreciation_lines[$obj->depreciation_mode] = array();
686 }
687 $this->depreciation_lines[$obj->depreciation_mode][] = array(
688 'id' => $obj->rowid,
689 'ref' => $obj->ref,
690 'depreciation_date' => $this->db->jdate($obj->depreciation_date),
691 'depreciation_ht' => $obj->depreciation_ht,
692 'cumulative_depreciation_ht' => $obj->cumulative_depreciation_ht,
693 'bookkeeping' => $obj->bookkeeping,
694 );
695 }
696
697 return 1;
698 }
699
706 {
707 global $langs;
708 $langs->load('assets');
709
710 // Clean parameters
711 $this->id = $this->id > 0 ? $this->id : 0;
712
713 // Check parameters
714 $error = 0;
715 if (empty($this->id)) {
716 $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Asset") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
717 $error++;
718 }
719 if ($error) {
720 return -1;
721 }
722
723 // Old request with 'WITH'
724 /*
725 $sql = "WITH in_accounting_bookkeeping(fk_docdet) AS (";
726 $sql .= " SELECT DISTINCT fk_docdet";
727 $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping";
728 $sql .= " WHERE doc_type = 'asset'";
729 $sql .= ")";
730 $sql .= "SELECT COUNT(*) AS has_bookkeeping";
731 $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
732 $sql .= " LEFT JOIN in_accounting_bookkeeping as iab ON iab.fk_docdet = ad.rowid";
733 $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
734 $sql .= " AND iab.fk_docdet IS NOT NULL";
735 */
736
737 $sql = "SELECT COUNT(*) AS has_bookkeeping";
738 $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
739 $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";
740 $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
741 $sql .= " AND iab.fk_docdet IS NOT NULL";
742
743 $resql = $this->db->query($sql);
744 if (!$resql) {
745 $this->errors[] = $langs->trans('AssetErrorFetchDepreciationLines') . ': ' . $this->db->lasterror();
746 return -1;
747 }
748
749 if ($obj = $this->db->fetch_object($resql)) {
750 return $obj->has_bookkeeping > 0 ? 1 : 0;
751 }
752
753 return 0;
754 }
755
768 public function addDepreciationLine($mode, $ref, $depreciation_date, $depreciation_ht, $cumulative_depreciation_ht, $accountancy_code_debit, $accountancy_code_credit)
769 {
770 global $langs;
771 $langs->load('assets');
772
773 // Clean parameters
774 $this->id = $this->id > 0 ? $this->id : 0;
775 $mode = strtolower(trim($mode));
776 $ref = trim($ref);
777 $accountancy_code_debit = trim($accountancy_code_debit);
778 $accountancy_code_credit = trim($accountancy_code_credit);
779
780 // Check parameters
781 $error = 0;
782 if (empty($this->id)) {
783 $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Asset") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
784 $error++;
785 }
786 if ($error) {
787 return -1;
788 }
789
790 $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)";
791 $sql .= " VALUES ( ";
792 $sql .= " " . (int) $this->id;
793 $sql .= ", '" . $this->db->escape($mode) . "'";
794 $sql .= ", '" . $this->db->escape($ref) . "'";
795 $sql .= ", '" . $this->db->idate($depreciation_date) . "'";
796 $sql .= ", " . (float) $depreciation_ht;
797 $sql .= ", " . (float) $cumulative_depreciation_ht;
798 $sql .= ", '" . $this->db->escape($accountancy_code_debit) . "'";
799 $sql .= ", '" . $this->db->escape($accountancy_code_credit) . "'";
800 $sql .= ")";
801
802 $resql = $this->db->query($sql);
803 if (!$resql) {
804 $this->errors[] = $langs->trans('AssetErrorAddDepreciationLine') . ': ' . $this->db->lasterror();
805 return -1;
806 }
807
808 return 1;
809 }
810
816 public function calculationDepreciation()
817 {
818 global $conf, $langs;
819 $langs->load('assets');
820
821 // Clean parameters
822 $this->id = $this->id > 0 ? $this->id : 0;
823
824 // Check parameters
825 $error = 0;
826 if (empty($this->id)) {
827 $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Asset") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
828 $error++;
829 }
830 if ($error) {
831 return -1;
832 }
833
834 // Get depreciation options
835 //---------------------------
836 require_once DOL_DOCUMENT_ROOT . '/asset/class/assetdepreciationoptions.class.php';
837 $options = new AssetDepreciationOptions($this->db);
838 $result = $options->fetchDeprecationOptions($this->id);
839 if ($result < 0) {
840 $this->error = $options->error;
841 $this->errors = $options->errors;
842 return -1;
843 }
844
845 // Get accountancy codes
846 //---------------------------
847 require_once DOL_DOCUMENT_ROOT . '/asset/class/assetaccountancycodes.class.php';
848 $accountancy_codes = new AssetAccountancyCodes($this->db);
849 $result = $accountancy_codes->fetchAccountancyCodes($this->id);
850 if ($result < 0) {
851 $this->error = $accountancy_codes->error;
852 $this->errors = $accountancy_codes->errors;
853 return -1;
854 }
855
856 $this->db->begin();
857
858 // Delete old lines
859 $modes = array();
860 foreach ($options->deprecation_options as $mode_key => $fields) {
861 $modes[$mode_key] = $this->db->escape($mode_key);
862 }
863 $sql = "DELETE FROM " . MAIN_DB_PREFIX . "asset_depreciation";
864 $sql .= " WHERE fk_asset = " . (int) $this->id;
865 $sql .= " AND depreciation_mode NOT IN ('" . $this->db->sanitize(implode("', '", $modes)) . "')";
866
867 $resql = $this->db->query($sql);
868 if (!$resql) {
869 $this->errors[] = $langs->trans('AssetErrorClearDepreciationLines') . ': ' . $this->db->lasterror();
870 $error++;
871 }
872
873 if (!$error) {
874 // Get fiscal period
875 require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
876 require_once DOL_DOCUMENT_ROOT . '/core/lib/accounting.lib.php';
877 $dates = getCurrentPeriodOfFiscalYear($this->db, $conf, $this->date_start > $this->date_acquisition ? $this->date_start : $this->date_acquisition);
878 $init_fiscal_period_start = $dates['date_start'];
879 $init_fiscal_period_end = $dates['date_end'];
880 if (empty($init_fiscal_period_start) || empty($init_fiscal_period_end)) {
881 $pastmonthyear = $dates['pastmonthyear'];
882 $pastmonth = $dates['pastmonth'];
883 $init_fiscal_period_start = dol_get_first_day($pastmonthyear, $pastmonth, false);
884 $init_fiscal_period_end = dol_get_last_day($pastmonthyear, $pastmonth, false);
885 }
886
887 foreach ($options->deprecation_options as $mode_key => $fields) {
888 // Get last depreciation lines save in bookkeeping
889 //-----------------------------------------------------
890
891 // Old request with 'WITH'
892 /*
893 $sql = "WITH in_accounting_bookkeeping(fk_docdet) AS (";
894 $sql .= " SELECT fk_docdet";
895 $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping";
896 $sql .= " WHERE doc_type = 'asset'";
897 $sql .= ")";
898 $sql .= "SELECT ad.depreciation_date, ad.cumulative_depreciation_ht";
899 $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
900 $sql .= " LEFT JOIN in_accounting_bookkeeping as iab ON iab.fk_docdet = ad.rowid";
901 $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
902 $sql .= " AND ad.depreciation_mode = '" . $this->db->escape($mode_key) . "'";
903 $sql .= " AND iab.fk_docdet IS NOT NULL";
904 $sql .= " ORDER BY ad.depreciation_date DESC";
905 $sql .= " LIMIT 1";
906 */
907
908 $sql = "SELECT ad.depreciation_date, ad.cumulative_depreciation_ht";
909 $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
910 $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";
911 $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
912 $sql .= " AND ad.depreciation_mode = '" . $this->db->escape($mode_key) . "'";
913 $sql .= " AND iab.fk_docdet IS NOT NULL";
914 $sql .= " ORDER BY ad.depreciation_date DESC";
915 $sql .= " LIMIT 1";
916
917 $resql = $this->db->query($sql);
918 if (!$resql) {
919 $this->errors[] = $langs->trans('AssetErrorFetchMaxDepreciationDateForMode', $mode_key) . ': ' . $this->db->lasterror();
920 $error++;
921 break;
922 }
923 $last_depreciation_date = '';
924 $last_cumulative_depreciation_ht = $this->reversal_amount_ht;
925 if ($obj = $this->db->fetch_object($resql)) {
926 $last_depreciation_date = $this->db->jdate($obj->depreciation_date);
927 $last_cumulative_depreciation_ht = $obj->cumulative_depreciation_ht;
928 }
929
930 // Set last cumulative depreciation
931 $sql = "UPDATE " . MAIN_DB_PREFIX . $options->deprecation_options_fields[$mode_key]['table'];
932 $sql .= " SET total_amount_last_depreciation_ht = " . (empty($last_cumulative_depreciation_ht) ? 0 : $last_cumulative_depreciation_ht);
933 $sql .= " WHERE fk_asset = " . (int) $this->id;
934 $resql = $this->db->query($sql);
935 if (!$resql) {
936 $this->errors[] = $langs->trans('AssetErrorSetLastCumulativeDepreciation') . ': ' . $this->db->lasterror();
937 $error++;
938 break;
939 }
940
941 // Delete old lines
942 $sql = "DELETE FROM " . MAIN_DB_PREFIX . "asset_depreciation";
943 $sql .= " WHERE fk_asset = " . (int) $this->id;
944 $sql .= " AND depreciation_mode = '" . $this->db->escape($mode_key) . "'";
945 $sql .= " AND NOT EXISTS (SELECT fk_docdet FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping WHERE doc_type = 'asset' AND fk_docdet = " . MAIN_DB_PREFIX . "asset_depreciation.rowid)";
946 if ($last_depreciation_date !== "") {
947 $sql .= " AND ref <> ''";
948 }
949 $resql = $this->db->query($sql);
950 if (!$resql) {
951 $this->errors[] = $langs->trans('AssetErrorClearDepreciationLines') . ': ' . $this->db->lasterror();
952 $error++;
953 break;
954 }
955
956 // Get depreciation period
957 $depreciation_date_start = $this->date_start > $this->date_acquisition ? $this->date_start : $this->date_acquisition;
958 $depreciation_date_end = dol_time_plus_duree($depreciation_date_start, $fields['duration'], $fields['duration_type'] == 1 ? 'm' : ($fields['duration_type'] == 2 ? 'd' : 'y'));
959 $depreciation_amount = $fields['amount_base_depreciation_ht'];
960 if ($fields['duration_type'] == 2) { // Daily
961 $fiscal_period_start = $depreciation_date_start;
962 $fiscal_period_end = $depreciation_date_start;
963 } elseif ($fields['duration_type'] == 1) { // Monthly
964 $date_temp = dol_getdate($depreciation_date_start);
965 $fiscal_period_start = dol_get_first_day($date_temp['year'], $date_temp['mon'], false);
966 $fiscal_period_end = dol_get_last_day($date_temp['year'], $date_temp['mon'], false);
967 } else { // Annually
968 $fiscal_period_start = $init_fiscal_period_start;
969 $fiscal_period_end = $init_fiscal_period_end;
970 }
971 $cumulative_depreciation_ht = $last_cumulative_depreciation_ht;
972 $depreciation_period_amount = $depreciation_amount - $this->reversal_amount_ht;
973 $start_date = $depreciation_date_start;
974 $disposal_date = isset($this->disposal_date) && $this->disposal_date !== "" ? $this->disposal_date : "";
975 $finish_date = $disposal_date !== "" ? $disposal_date : $depreciation_date_end;
976 $accountancy_code_depreciation_debit_key = $accountancy_codes->accountancy_codes_fields[$mode_key]['depreciation_debit'];
977 $accountancy_code_depreciation_debit = $accountancy_codes->accountancy_codes[$mode_key][$accountancy_code_depreciation_debit_key];
978 $accountancy_code_depreciation_credit_key = $accountancy_codes->accountancy_codes_fields[$mode_key]['depreciation_credit'];
979 $accountancy_code_credit = $accountancy_codes->accountancy_codes[$mode_key][$accountancy_code_depreciation_credit_key];
980
981 // Reversal depreciation line
982 //-----------------------------------------------------
983 if ($last_depreciation_date === "" && ($depreciation_date_start < $fiscal_period_start || is_numeric($this->reversal_date))) {
984 if (is_numeric($this->reversal_date)) {
985 if ($this->reversal_date < $fiscal_period_start) {
986 $this->errors[] = $langs->trans('AssetErrorReversalDateNotGreaterThanCurrentBeginFiscalDateForMode', $mode_key);
987 $error++;
988 break;
989 }
990
991 if (empty($this->reversal_amount_ht)) {
992 $this->errors[] = $langs->trans('AssetErrorReversalAmountNotProvidedForMode', $mode_key);
993 $error++;
994 break;
995 }
996
997 $start_date = $this->reversal_date;
998 $result = $this->addDepreciationLine($mode_key, '', $start_date, $this->reversal_amount_ht, $this->reversal_amount_ht, $accountancy_code_depreciation_debit, $accountancy_code_credit);
999 if ($result < 0) {
1000 $error++;
1001 break;
1002 }
1003 } else {
1004 $this->errors[] = $langs->trans('AssetErrorReversalDateNotProvidedForMode', $mode_key);
1005 $error++;
1006 break;
1007 }
1008 }
1009
1010 // futures depreciation lines
1011 //-----------------------------------------------------
1012 $nb_days_in_year = getDolGlobalInt('ASSET_DEPRECIATION_DURATION_PER_YEAR', 365);
1013 $nb_days_in_month = getDolGlobalInt('ASSET_DEPRECIATION_DURATION_PER_MONTH', 30);
1014 $period_amount = (float) ($fields['duration'] > 0 ? price2num($depreciation_period_amount / $fields['duration'], 'MT') : 0);
1015 $first_period_found = false;
1016 // TODO fix declaration of $begin_period
1017 // @phpstan-ignore-next-line
1018 $first_period_date = isset($begin_period) && $begin_period > $fiscal_period_start ? $begin_period : $fiscal_period_start;
1019
1020 $ref_date_format = "%Y" . ($fields['duration_type'] == 1 || $fields['duration_type'] == 2 ? '-%m' : '') . ($fields['duration_type'] == 2 ? '-%d' : '');
1021
1022 // Loop security
1023 $idx_loop = 0;
1024 $max_loop = $fields['duration'] + 2;
1025 do {
1026 // Loop security
1027 $idx_loop++;
1028 if ($idx_loop > $max_loop) {
1029 break;
1030 }
1031
1032 if ($last_depreciation_date < $fiscal_period_end && ($first_period_date <= $start_date || $first_period_found)) {
1033 // Disposal not depreciated
1034 if ($fiscal_period_start <= $disposal_date && $disposal_date <= $fiscal_period_end && empty($this->disposal_depreciated)) {
1035 break;
1036 }
1037
1038 $first_period_found = true;
1039
1040 $period_begin = dol_print_date($fiscal_period_start, $ref_date_format);
1041 $period_end = dol_print_date($fiscal_period_end, $ref_date_format);
1042 $ref = $period_begin . ($period_begin != $period_end ? ' - ' . $period_end : '');
1043 if ($fiscal_period_start <= $disposal_date && $disposal_date <= $fiscal_period_end) {
1044 $ref .= ' - ' . $langs->transnoentitiesnoconv('AssetDisposal');
1045 }
1046
1047 $begin_date = $fiscal_period_start < $start_date && $start_date <= $fiscal_period_end ? $start_date : $fiscal_period_start;
1048 $end_date = $fiscal_period_start < $finish_date && $finish_date <= $fiscal_period_end ? $finish_date : $fiscal_period_end;
1049 if ($fields['duration_type'] == 2) { // Daily
1050 $depreciation_ht = $period_amount;
1051 } elseif ($fields['duration_type'] == 1) { // Monthly
1052 $nb_days = min($nb_days_in_month, num_between_day($begin_date, $end_date, 1));
1053 if ($nb_days >= 28) {
1054 $date_temp = dol_getdate($begin_date);
1055 if ($date_temp['mon'] == 2) {
1056 $nb_days = 30;
1057 }
1058 }
1059 $depreciation_ht = (float) price2num($period_amount * $nb_days / $nb_days_in_month, 'MT');
1060 } else { // Annually
1061 $nb_days = min($nb_days_in_year, num_between_day($begin_date, $end_date, 1));
1062 $depreciation_ht = (float) price2num($period_amount * $nb_days / $nb_days_in_year, 'MT');
1063 }
1064
1065 if ($fiscal_period_start <= $depreciation_date_end && $depreciation_date_end <= $fiscal_period_end) { // last period
1066 $depreciation_ht = (float) price2num($depreciation_amount - $cumulative_depreciation_ht, 'MT');
1067 $cumulative_depreciation_ht = $depreciation_amount;
1068 } else {
1069 $cumulative_depreciation_ht += $depreciation_ht;
1070 }
1071
1072 $result = $this->addDepreciationLine($mode_key, $ref, $fiscal_period_end, $depreciation_ht, $cumulative_depreciation_ht, $accountancy_code_depreciation_debit, $accountancy_code_credit);
1073 if ($result < 0) {
1074 $error++;
1075 break;
1076 }
1077 }
1078
1079 // Next fiscal period (+1 day/month/year)
1080 $fiscal_period_start = dol_time_plus_duree($fiscal_period_end, 1, 'd');
1081 if ($fields['duration_type'] == 2) { // Daily
1082 $fiscal_period_end = $fiscal_period_start;
1083 } elseif ($fields['duration_type'] == 1) { // Monthly
1084 $fiscal_period_end = dol_time_plus_duree(dol_time_plus_duree($fiscal_period_start, 1, 'm'), -1, 'd');
1085 } else { // Annually
1086 $fiscal_period_end = dol_time_plus_duree(dol_time_plus_duree($fiscal_period_start, 1, 'y'), -1, 'd');
1087 }
1088 $last_period_date = $disposal_date !== "" && $disposal_date < $depreciation_date_end ? $disposal_date : $depreciation_date_end;
1089 } while ($fiscal_period_start < $last_period_date);
1090
1091 if ($error) {
1092 break;
1093 }
1094 }
1095 }
1096
1097 if ($error) {
1098 $this->db->rollback();
1099 return -1;
1100 } else {
1101 $this->db->commit();
1102 return 1;
1103 }
1104 }
1105
1112 public function setLastCumulativeDepreciation($asset_depreciation_id)
1113 {
1114 global $langs;
1115 $langs->load('assets');
1116
1117 // Clean parameters
1118 $asset_depreciation_id = $asset_depreciation_id > 0 ? $asset_depreciation_id : 0;
1119
1120 // Check parameters
1121 $error = 0;
1122 if (empty($asset_depreciation_id)) {
1123 $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("AssetDepreciation") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
1124 $error++;
1125 }
1126 if ($error) {
1127 return -1;
1128 }
1129
1130 $this->db->begin();
1131
1132 require_once DOL_DOCUMENT_ROOT . '/asset/class/assetdepreciationoptions.class.php';
1133 $options = new AssetDepreciationOptions($this->db);
1134
1135 // Get last depreciation lines save in bookkeeping
1136 //-----------------------------------------------------
1137 $sql = "SELECT fk_asset, depreciation_mode, cumulative_depreciation_ht";
1138 $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation";
1139 $sql .= " WHERE rowid = " . (int) $asset_depreciation_id;
1140 $resql = $this->db->query($sql);
1141 if (!$resql) {
1142 $this->errors[] = $langs->trans('AssetErrorFetchCumulativeDepreciation') . ': ' . $this->db->lasterror();
1143 $error++;
1144 } else {
1145 if ($obj = $this->db->fetch_object($resql)) {
1146 $mode_key = $obj->depreciation_mode;
1147 if (!empty($options->deprecation_options_fields[$mode_key])) {
1148 $sql = "UPDATE " . MAIN_DB_PREFIX . $options->deprecation_options_fields[$mode_key]['table'];
1149 $sql .= " SET total_amount_last_depreciation_ht = " . $obj->cumulative_depreciation_ht;
1150 $sql .= " WHERE fk_asset = " . (int) $obj->fk_asset;
1151 $resql = $this->db->query($sql);
1152 if (!$resql) {
1153 $this->errors[] = $langs->trans('AssetErrorSetLastCumulativeDepreciation') . ': ' . $this->db->lasterror();
1154 $error++;
1155 }
1156 }
1157 }
1158 }
1159
1160 if ($error) {
1161 $this->db->rollback();
1162 return -1;
1163 } else {
1164 $this->db->commit();
1165 return 1;
1166 }
1167 }
1168
1177 public function dispose($user, $disposal_invoice_id, $notrigger = 0)
1178 {
1179 global $conf, $langs;
1180
1181 // Protection
1182 if ($this->status != self::STATUS_DRAFT || $this->status == self::STATUS_DISPOSED) {
1183 return 0;
1184 }
1185
1186 $this->db->begin();
1187
1188 $required_fields = array('disposal_date', 'disposal_date', 'fk_disposal_type');
1189 foreach ($required_fields as $field) {
1190 $this->fields[$field]['notnull'] = 1;
1191 }
1192 $result = $this->update($user, 1);
1193 foreach ($required_fields as $field) {
1194 $this->fields[$field]['notnull'] = 0;
1195 }
1196 if ($result > 0) {
1197 if ($disposal_invoice_id > 0) {
1198 $this->add_object_linked('facture', $disposal_invoice_id);
1199 }
1200 $result = $this->setStatusCommon($user, self::STATUS_DISPOSED, $notrigger, 'ASSET_DISPOSED');
1201 }
1202 if ($result > 0) {
1203 $result = $this->calculationDepreciation();
1204 }
1205
1206 if ($result < 0) {
1207 $this->db->rollback();
1208 } else {
1209 $this->db->commit();
1210 }
1211
1212 // Define output language
1213 if ($result > 0 && !getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
1214 if (method_exists($this, 'generateDocument')) {
1215 global $hidedetails, $hidedesc, $hideref;
1216 $outputlangs = $langs;
1217 $newlang = '';
1218 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
1219 $newlang = GETPOST('lang_id', 'aZ09');
1220 }
1221 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
1222 $newlang = $this->thirdparty->default_lang;
1223 }
1224 if (!empty($newlang)) {
1225 $outputlangs = new Translate("", $conf);
1226 $outputlangs->setDefaultLang($newlang);
1227 }
1228 $model = $this->model_pdf;
1229 $ret = $this->fetch($this->id); // Reload to get new records
1230
1231 $this->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
1232 }
1233 }
1234
1235 return $result;
1236 }
1237
1245 public function reopen($user, $notrigger = 0)
1246 {
1247 global $conf, $langs;
1248
1249 // Protection
1250 if ($this->status != self::STATUS_DISPOSED || $this->status == self::STATUS_DRAFT) {
1251 return 0;
1252 }
1253
1254
1255 $this->db->begin();
1256
1257 $this->disposal_date = null;
1258 $this->disposal_amount_ht = null;
1259 $this->fk_disposal_type = null;
1260 $this->disposal_depreciated = null;
1261 $this->disposal_subject_to_vat = null;
1262 $result = $this->update($user, 1);
1263 if ($result > 0) {
1264 $this->deleteObjectLinked(null, 'facture');
1265 $result = $this->setStatusCommon($user, self::STATUS_DRAFT, $notrigger, 'ASSET_REOPEN');
1266 }
1267 if ($result > 0) {
1268 $result = $this->calculationDepreciation();
1269 }
1270
1271 if ($result < 0) {
1272 $this->db->rollback();
1273 } else {
1274 $this->db->commit();
1275 }
1276
1277 // Define output language
1278 if ($result > 0 && !getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
1279 if (method_exists($this, 'generateDocument')) {
1280 global $hidedetails, $hidedesc, $hideref;
1281 $outputlangs = $langs;
1282 $newlang = '';
1283 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
1284 $newlang = GETPOST('lang_id', 'aZ09');
1285 }
1286 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
1287 $newlang = $this->thirdparty->default_lang;
1288 }
1289 if (!empty($newlang)) {
1290 $outputlangs = new Translate("", $conf);
1291 $outputlangs->setDefaultLang($newlang);
1292 }
1293 $model = $this->model_pdf;
1294 $ret = $this->fetch($this->id); // Reload to get new records
1295
1296 $this->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
1297 }
1298 }
1299
1300 return $result;
1301 }
1302
1314 public function getNomUrl($withpicto = 0, $option = '', $maxlen = 0, $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
1315 {
1316 global $db, $conf, $langs, $hookmanager;
1317 global $dolibarr_main_authentication, $dolibarr_main_demo;
1318 global $menumanager;
1319
1320 if (!empty($conf->dol_no_mouse_hover)) {
1321 $notooltip = 1; // Force disable tooltips
1322 }
1323
1324 $result = '';
1325
1326 $label = img_picto('', $this->picto).' <u>'.$langs->trans("Asset").'</u>';
1327 if (isset($this->status)) {
1328 $label .= ' '.$this->getLibStatut(5);
1329 }
1330 $label .= '<br>';
1331 $label .= '<b>'.$langs->trans('Ref').':</b> '.$this->ref;
1332
1333 $url = dol_buildpath('/asset/card.php', 1).'?id='.$this->id;
1334
1335 if ($option != 'nolink') {
1336 // Add param to save lastsearch_values or not
1337 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1338 if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
1339 $add_save_lastsearch_values = 1;
1340 }
1341 if ($add_save_lastsearch_values) {
1342 $url .= '&save_lastsearch_values=1';
1343 }
1344 }
1345
1346 $linkclose = '';
1347 if (empty($notooltip)) {
1348 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
1349 $label = $langs->trans("ShowAsset");
1350 $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
1351 }
1352 $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
1353 $linkclose .= ' class="classfortooltip'.($morecss ? ' '.$morecss : '').'"';
1354 } else {
1355 $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
1356 }
1357
1358 if ($option == 'nolink') {
1359 $linkstart = '<span';
1360 } else {
1361 $linkstart = '<a href="'.$url.'"';
1362 }
1363 $linkstart .= $linkclose.'>';
1364 if ($option == 'nolink') {
1365 $linkend = '</span>';
1366 } else {
1367 $linkend = '</a>';
1368 }
1369
1370 $result .= $linkstart;
1371
1372 if (empty($this->showphoto_on_popup)) {
1373 if ($withpicto) {
1374 $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip ? 0 : 1);
1375 }
1376 } else {
1377 if ($withpicto) {
1378 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1379
1380 list($class, $module) = explode('@', $this->picto);
1381 $upload_dir = $conf->$module->multidir_output[$conf->entity]."/$class/".dol_sanitizeFileName($this->ref);
1382 $filearray = dol_dir_list($upload_dir, "files");
1383 $filename = $filearray[0]['name'];
1384 if (!empty($filename)) {
1385 $pospoint = strpos($filearray[0]['name'], '.');
1386
1387 $pathtophoto = $class.'/'.$this->ref.'/thumbs/'.substr($filename, 0, $pospoint).'_mini'.substr($filename, $pospoint);
1388 if (!getDolGlobalString(strtoupper($module.'_'.$class).'_FORMATLISTPHOTOSASUSERS')) {
1389 $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>';
1390 } else {
1391 $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>';
1392 }
1393
1394 $result .= '</div>';
1395 } else {
1396 $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);
1397 }
1398 }
1399 }
1400
1401 if ($withpicto != 2) {
1402 $name = $this->ref;
1403 if ($option == 'label') {
1404 $name = $this->label;
1405 } elseif ($option == 'with_label') {
1406 $name .= ' - ' . $this->label;
1407 }
1408 $result .= dol_escape_htmltag($maxlen ? dol_trunc($name, $maxlen) : $name);
1409 }
1410
1411 $result .= $linkend;
1412 //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
1413
1414 global $action;
1415 $hookmanager->initHooks(array($this->element . 'dao'));
1416 $parameters = array('id'=>$this->id, 'getnomurl' => &$result);
1417 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1418 if ($reshook > 0) {
1419 $result = $hookmanager->resPrint;
1420 } else {
1421 $result .= $hookmanager->resPrint;
1422 }
1423 return $result;
1424 }
1425
1432 public function getLabelStatus($mode = 0)
1433 {
1434 return $this->LibStatut($this->status, $mode);
1435 }
1436
1443 public function getLibStatut($mode = 0)
1444 {
1445 return $this->LibStatut($this->status, $mode);
1446 }
1447
1448 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1456 public function LibStatut($status, $mode = 0)
1457 {
1458 // phpcs:enable
1459 if (empty($this->labelStatus) || empty($this->labelStatusShort)) {
1460 global $langs;
1461 //$langs->load("assets");
1462 $this->labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('AssetInProgress');
1463 $this->labelStatus[self::STATUS_DISPOSED] = $langs->transnoentitiesnoconv('AssetDisposed');
1464 $this->labelStatusShort[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('AssetInProgress');
1465 $this->labelStatusShort[self::STATUS_DISPOSED] = $langs->transnoentitiesnoconv('AssetDisposed');
1466 }
1467
1468 $statusType = 'status4';
1469 if ($status == self::STATUS_DISPOSED) {
1470 $statusType = 'status6';
1471 }
1472
1473 return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode);
1474 }
1475
1482 public function info($id)
1483 {
1484 $sql = "SELECT rowid, date_creation as datec, tms as datem,";
1485 $sql .= " fk_user_creat, fk_user_modif";
1486 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as t";
1487 $sql .= " WHERE t.rowid = ".((int) $id);
1488
1489 $result = $this->db->query($sql);
1490 if ($result) {
1491 if ($this->db->num_rows($result)) {
1492 $obj = $this->db->fetch_object($result);
1493 $this->id = $obj->rowid;
1494
1495 $this->user_creation_id = $obj->fk_user_creat;
1496 $this->user_modification_id = $obj->fk_user_modif;
1497 $this->date_creation = $this->db->jdate($obj->datec);
1498 $this->date_modification = $this->db->jdate($obj->datem);
1499 }
1500
1501 $this->db->free($result);
1502 } else {
1503 dol_print_error($this->db);
1504 }
1505 }
1506
1513 public function initAsSpecimen()
1514 {
1515 // Set here init that are not commonf fields
1516 // $this->property1 = ...
1517 // $this->property2 = ...
1518
1519 $this->initAsSpecimenCommon();
1520 }
1521
1527 public function getLinesArray()
1528 {
1529 $this->lines = array();
1530
1531 return $this->lines;
1532 }
1533
1539 public function getNextNumRef()
1540 {
1541 global $langs, $conf;
1542 $langs->load("assets");
1543
1544 if (!getDolGlobalString('ASSET_ASSET_ADDON')) {
1545 $conf->global->ASSET_ASSET_ADDON = 'mod_asset_standard';
1546 }
1547
1548 if (getDolGlobalString('ASSET_ASSET_ADDON')) {
1549 $mybool = false;
1550
1551 $file = getDolGlobalString('ASSET_ASSET_ADDON') . ".php";
1552 $classname = $conf->global->ASSET_ASSET_ADDON;
1553
1554 // Include file with class
1555 $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
1556 foreach ($dirmodels as $reldir) {
1557 $dir = dol_buildpath($reldir."core/modules/asset/");
1558
1559 // Load file with numbering class (if found)
1560 $mybool |= @include_once $dir.$file;
1561 }
1562
1563 if ($mybool === false) {
1564 dol_print_error('', "Failed to include file ".$file);
1565 return '';
1566 }
1567
1568 if (class_exists($classname)) {
1569 $obj = new $classname();
1570 $numref = $obj->getNextValue($this);
1571
1572 if ($numref != '' && $numref != '-1') {
1573 return $numref;
1574 } else {
1575 $this->error = $obj->error;
1576 //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error);
1577 return "";
1578 }
1579 } else {
1580 print $langs->trans("Error")." ".$langs->trans("ClassNotFound").' '.$classname;
1581 return "";
1582 }
1583 } else {
1584 print $langs->trans("ErrorNumberingModuleNotSetup", $this->element);
1585 return "";
1586 }
1587 }
1588
1600 // public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
1601 // {
1602 // global $conf, $langs;
1603 //
1604 // $result = 0;
1605 // $includedocgeneration = 1;
1606 //
1607 // $langs->load("assets");
1608 //
1609 // if (!dol_strlen($modele)) {
1610 // $modele = 'standard_asset';
1611 //
1612 // if (!empty($this->model_pdf)) {
1613 // $modele = $this->model_pdf;
1614 // } elseif (!empty($conf->global->ASSET_ADDON_PDF)) {
1615 // $modele = $conf->global->ASSET_ADDON_PDF;
1616 // }
1617 // }
1618 //
1619 // $modelpath = "core/modules/asset/doc/";
1620 //
1621 // if ($includedocgeneration && !empty($modele)) {
1622 // $result = $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
1623 // }
1624 //
1625 // return $result;
1626 // }
1627}
getCurrentPeriodOfFiscalYear($db, $conf, $from_time=null)
Get current period of fiscal year.
print $langs trans("AuditedSecurityEvents").'</strong >< span class="opacitymedium"></span >< br > status
Definition security.php:604
$object ref
Definition info.php:79
Class for AssetAccountancyCodes.
Class for AssetDepreciationOptions.
Class for Asset.
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.
deleteObjectLinked($sourceid=null, $sourcetype='', $targetid=null, $targettype='', $rowid=0, $f_user=null, $notrigger=0)
Delete all links between an object $this.
createCommon(User $user, $notrigger=false)
Create object into database.
deleteCommon(User $user, $notrigger=false, $forcechilddeletion=0)
Delete object in database.
getFieldList($alias='', $excludefields=array())
Function to concat keys of fields.
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.
fetchCommon($id, $ref=null, $morewhere='', $noextrafields=0)
Load object in memory from the database.
Class to manage Dolibarr database access.
Class to manage translations.
Class to manage Dolibarr users.
dol_get_first_day($year, $month=1, $gm=false)
Return GMT time for first day of a month or year.
Definition date.lib.php:594
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...
dol_time_plus_duree($time, $duration_value, $duration_unit, $ruleforendofmonth=0)
Add a delay to a date.
Definition date.lib.php:125
dol_get_last_day($year, $month=12, $gm=false)
Return GMT time for last day of a month or year.
Definition date.lib.php:613
dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0, $nbsecondsold=0)
Scan a directory and return a list of files/directories.
Definition files.lib.php:62
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
getDolGlobalInt($key, $default=0)
Return a 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)
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_getdate($timestamp, $fast=false, $forcetimezone='')
Return an array with locale date info.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...