dolibarr 21.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-2024 Alexandre Spangaro <alexandre@inovea-conseil.com>
4 * Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
5 * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
6 * Copyright (C) 2024 Jose MARTINEZ <jose.martinez@pichinov.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
28require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
29
33class Asset extends CommonObject
34{
38 public $module = 'asset';
39
43 public $element = 'asset';
44
48 public $table_element = 'asset';
49
53 public $picto = 'asset';
54
55 const STATUS_DRAFT = 0; // In progress
56 const STATUS_DISPOSED = 9; // Disposed
57
89 public $fields = array(
90 'rowid' => array('type' => 'integer', 'label' => 'TechnicalID', 'enabled' => 1, 'position' => 1, 'notnull' => 1, 'visible' => 0, 'noteditable' => 1, 'index' => 1, 'css' => 'left', 'comment' => "Id"),
91 '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", "css" => "maxwidth150"),
92 'label' => array('type' => 'varchar(255)', 'label' => 'Label', 'enabled' => 1, 'position' => 30, 'notnull' => 1, 'visible' => 1, 'searchall' => 1, 'csslist' => 'tdoverflowmax125', 'css' => 'minwidth300', 'cssview' => 'wordbreak', 'showoncombobox' => 2, 'validate' => 1,),
93 '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, 'csslist' => 'tdoverflowmax75', 'css' => 'maxwidth300'),
94 'qty' => array('type' => 'real', 'label' => 'Qty', 'enabled' => 1, 'position' => 50, 'notnull' => 1, 'visible' => 0, 'default' => '1', 'isameasure' => 1, 'css' => 'maxwidth75imp', 'validate' => 1,),
95 'acquisition_type' => array('type' => 'smallint', 'label' => 'AssetAcquisitionType', 'enabled' => 1, 'position' => 60, 'notnull' => 1, 'visible' => 1, 'arrayofkeyval' => array(0 => 'AssetAcquisitionTypeNew', 1 => 'AssetAcquisitionTypeOccasion'), 'validate' => 1, 'csslist' => 'tdoverflowmax75'),
96 '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, 'csslist' => 'tdoverflowmax75'),
97 'not_depreciated' => array('type' => 'boolean', 'label' => 'AssetNotDepreciated', 'enabled' => 1, 'position' => 80, 'notnull' => 0, 'default' => '0', 'visible' => 1, 'validate' => 1, 'csslist' => 'maxwidth50 tdoverflowmax50', 'css' => 'maxwidth50imp'),
98 'date_acquisition' => array('type' => 'date', 'label' => 'AssetDateAcquisition', 'enabled' => 1, 'position' => 90, 'notnull' => 1, 'visible' => 1,),
99 'date_start' => array('type' => 'date', 'label' => 'AssetDateStart', 'enabled' => 1, 'position' => 100, 'notnull' => 0, 'visible' => -1,),
100 'acquisition_value_ht' => array('type' => 'price', 'label' => 'AssetAcquisitionValueHT', 'enabled' => 1, 'position' => 110, 'notnull' => 1, 'visible' => 1, 'isameasure' => 1, 'validate' => 1,),
101 'recovered_vat' => array('type' => 'price', 'label' => 'AssetRecoveredVAT', 'enabled' => 1, 'position' => 120, 'notnull' => 0, 'visible' => 1, 'isameasure' => 1, 'validate' => 1,),
102 'reversal_date' => array('type' => 'date', 'label' => 'AssetReversalDate', 'enabled' => 1, 'position' => 130, 'notnull' => 0, 'visible' => 1,),
103 'reversal_amount_ht' => array('type' => 'price', 'label' => 'AssetReversalAmountHT', 'enabled' => 1, 'position' => 140, 'notnull' => 0, 'visible' => 1, 'isameasure' => 1, 'validate' => 1, 'csslist' => 'maxwidth50'),
104 'disposal_date' => array('type' => 'date', 'label' => 'AssetDisposalDate', 'enabled' => 1, 'position' => 200, 'notnull' => 0, 'visible' => -2,),
105 'disposal_amount_ht' => array('type' => 'price', 'label' => 'AssetDisposalAmount', 'enabled' => 1, 'position' => 210, 'notnull' => 0, 'visible' => -2, 'default' => '0', 'isameasure' => 1, 'validate' => 1,),
106 '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,),
107 'disposal_depreciated' => array('type' => 'boolean', 'label' => 'AssetDisposalDepreciated', 'enabled' => 1, 'position' => 230, 'notnull' => 0, 'default' => '0', 'visible' => -2, 'validate' => 1,),
108 'disposal_subject_to_vat' => array('type' => 'boolean', 'label' => 'AssetDisposalSubjectToVat', 'enabled' => 1, 'position' => 240, 'notnull' => 0, 'default' => '0', 'visible' => -2, 'validate' => 1,),
109 'note_public' => array('type' => 'html', 'label' => 'NotePublic', 'enabled' => 1, 'position' => 300, 'notnull' => 0, 'visible' => 0, 'validate' => 1,),
110 'note_private' => array('type' => 'html', 'label' => 'NotePrivate', 'enabled' => 1, 'position' => 301, 'notnull' => 0, 'visible' => 0, 'validate' => 1,),
111 'date_creation' => array('type' => 'datetime', 'label' => 'DateCreation', 'enabled' => 1, 'position' => 500, 'notnull' => 1, 'visible' => -2,),
112 'tms' => array('type' => 'timestamp', 'label' => 'DateModification', 'enabled' => 1, 'position' => 501, 'notnull' => 0, 'visible' => -2,),
113 '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',),
114 'fk_user_modif' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserModif', 'enabled' => 1, 'position' => 511, 'notnull' => -1, 'visible' => -2,),
115 'last_main_doc' => array('type' => 'varchar(255)', 'label' => 'LastMainDoc', 'enabled' => 1, 'position' => 600, 'notnull' => 0, 'visible' => 0,),
116 'import_key' => array('type' => 'varchar(14)', 'label' => 'ImportId', 'enabled' => 1, 'position' => 1000, 'notnull' => -1, 'visible' => -2,),
117 'model_pdf' => array('type' => 'varchar(255)', 'label' => 'Model pdf', 'enabled' => 1, 'position' => 1010, 'notnull' => -1, 'visible' => 0,),
118 '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,),
119 );
120
124 public $rowid;
128 public $ref;
132 public $label;
136 public $fk_asset_model;
140 public $reversal_amount_ht;
144 public $acquisition_value_ht;
148 public $recovered_vat;
152 public $reversal_date;
156 public $date_acquisition;
160 public $date_start;
164 public $qty;
168 public $acquisition_type;
172 public $asset_type;
176 public $not_depreciated;
180 public $disposal_date;
184 public $disposal_amount_ht;
188 public $fk_disposal_type;
192 public $disposal_depreciated;
196 public $disposal_subject_to_vat;
200 public $supplier_invoice_id;
204 public $note_public;
208 public $note_private;
212 public $fk_user_creat;
216 public $fk_user_modif;
220 public $last_main_doc;
224 public $import_key;
228 public $model_pdf;
232 public $status;
233
237 public $asset_depreciation_options;
241 public $asset_accountancy_codes;
245 public $depreciation_lines = array();
246
252 public function __construct(DoliDB $db)
253 {
254 global $langs;
255
256 $this->db = $db;
257
258 $this->ismultientitymanaged = 1;
259 $this->isextrafieldmanaged = 1;
260
261 if (!getDolGlobalString('MAIN_SHOW_TECHNICAL_ID') && isset($this->fields['rowid'])) {
262 $this->fields['rowid']['visible'] = 0;
263 }
264 if (!isModEnabled('multicompany') && isset($this->fields['entity'])) {
265 $this->fields['entity']['enabled'] = 0;
266 }
267
268 // Unset fields that are disabled
269 foreach ($this->fields as $key => $val) {
270 if (isset($val['enabled']) && empty($val['enabled'])) {
271 unset($this->fields[$key]);
272 }
273 }
274
275 // Translate some data of arrayofkeyval
276 if (is_object($langs)) {
277 foreach ($this->fields as $key => $val) {
278 if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
279 foreach ($val['arrayofkeyval'] as $key2 => $val2) {
280 $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2);
281 }
282 }
283 }
284 }
285 }
286
294 public function create(User $user, $notrigger = 0)
295 {
296 if (!isset($this->date_start) || $this->date_start === "") {
297 $this->date_start = $this->date_acquisition;
298 }
299
300 $this->db->begin();
301
302 $result = $result_create = $this->createCommon($user, $notrigger);
303 if ($result > 0 && $this->fk_asset_model > 0) {
304 $result = $this->setDataFromAssetModel($user, $notrigger);
305 }
306 if ($result > 0) {
307 if ($this->supplier_invoice_id > 0) {
308 $this->add_object_linked('invoice_supplier', $this->supplier_invoice_id);
309 }
310 }
311
312 if ($result < 0) {
313 $this->db->rollback();
314 } else {
315 $this->db->commit();
316 }
317
318 return $result > 0 ? $result_create : $result;
319 }
320
328 public function createFromClone(User $user, $fromid)
329 {
330 global $langs, $extrafields;
331 $error = 0;
332
333 dol_syslog(__METHOD__, LOG_DEBUG);
334
335 // $object = new self($this->db);
336 //
337 // $this->db->begin();
338 //
339 // // Load source object
340 // $result = $object->fetchCommon($fromid);
341 //
342 //
343 // // Reset some properties
344 // unset($object->id);
345 // unset($object->fk_user_creat);
346 // unset($object->import_key);
347 //
348 // // Clear fields
349 // if (property_exists($object, 'ref')) {
350 // $object->ref = empty($this->fields['ref']['default']) ? "Copy_Of_".$object->ref : $this->fields['ref']['default'];
351 // }
352 // if (property_exists($object, 'label')) {
353 // $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf")." ".$object->label : $this->fields['label']['default'];
354 // }
355 // if (property_exists($object, 'status')) {
356 // $object->status = self::STATUS_DRAFT;
357 // }
358 // if (property_exists($object, 'date_creation')) {
359 // $object->date_creation = dol_now();
360 // }
361 // if (property_exists($object, 'date_modification')) {
362 // $object->date_modification = null;
363 // }
364 // // ...
365 // // Clear extrafields that are unique
366 // if (is_array($object->array_options) && count($object->array_options) > 0) {
367 // $extrafields->fetch_name_optionals_label($this->table_element);
368 // foreach ($object->array_options as $key => $option) {
369 // $shortkey = preg_replace('/options_/', '', $key);
370 // if (!empty($extrafields->attributes[$this->table_element]['unique'][$shortkey])) {
371 // //var_dump($key); var_dump($clonedObj->array_options[$key]); exit;
372 // unset($object->array_options[$key]);
373 // }
374 // }
375 // }
376 //
377 // // Create clone
378 // $object->context['createfromclone'] = 'createfromclone';
379 // $result = $object->createCommon($user);
380 // if ($result < 0) {
381 // $error++;
382 // $this->error = $object->error;
383 // $this->errors = $object->errors;
384 // }
385 //
386 // if (!$error) {
387 // // copy internal contacts
388 // if ($this->copy_linked_contact($object, 'internal') < 0) {
389 // $error++;
390 // }
391 // }
392 //
393 // if (!$error) {
394 // // copy external contacts if same company
395 // if (property_exists($this, 'fk_soc') && $this->fk_soc == $object->socid) {
396 // if ($this->copy_linked_contact($object, 'external') < 0) {
397 // $error++;
398 // }
399 // }
400 // }
401 //
402 // unset($object->context['createfromclone']);
403 //
404 // // End
405 // if (!$error) {
406 // $this->db->commit();
407 // return $object;
408 // } else {
409 // $this->db->rollback();
410 // return -1;
411 // }
412
413 return -1;
414 }
415
423 public function fetch($id, $ref = null)
424 {
425 $result = $this->fetchCommon($id, $ref);
426 if ($result > 0) {
427 $res = $this->hasDepreciationLinesInBookkeeping();
428 if ($res < 0) {
429 return -1;
430 } elseif ($res > 0) {
431 $this->fields['date_acquisition']['noteditable'] = 1;
432 $this->fields['date_start']['noteditable'] = 1;
433 $this->fields['acquisition_value_ht']['noteditable'] = 1;
434 $this->fields['recovered_vat']['noteditable'] = 1;
435 $this->fields['reversal_date']['noteditable'] = 1;
436 $this->fields['reversal_amount_ht']['noteditable'] = 1;
437 }
438 }
439
440 return $result;
441 }
442
443
456 public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, $filter = '', $filtermode = 'AND')
457 {
458 dol_syslog(__METHOD__, LOG_DEBUG);
459
460 $records = array();
461
462 $sql = "SELECT ";
463 $sql .= $this->getFieldList('t');
464 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as t";
465 if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
466 $sql .= " WHERE t.entity IN (".getEntity($this->element).")";
467 } else {
468 $sql .= " WHERE 1 = 1";
469 }
470
471 // Manage filter
472 $errormessage = '';
473 $sql .= forgeSQLFromUniversalSearchCriteria($filter, $errormessage);
474 if ($errormessage) {
475 $this->errors[] = $errormessage;
476 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
477
478 return -1;
479 }
480
481 if (!empty($sortfield)) {
482 $sql .= $this->db->order($sortfield, $sortorder);
483 }
484 if (!empty($limit)) {
485 $sql .= $this->db->plimit($limit, $offset);
486 }
487
488 $resql = $this->db->query($sql);
489 if ($resql) {
490 $num = $this->db->num_rows($resql);
491 $i = 0;
492 while ($i < ($limit ? min($limit, $num) : $num)) {
493 $obj = $this->db->fetch_object($resql);
494
495 $record = new self($this->db);
496 $record->setVarsFromFetchObj($obj);
497
498 $records[$record->id] = $record;
499
500 $i++;
501 }
502 $this->db->free($resql);
503
504 return $records;
505 } else {
506 $this->errors[] = 'Error '.$this->db->lasterror();
507 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
508
509 return -1;
510 }
511 }
512
520 public function update(User $user, $notrigger = 0)
521 {
522 if (!isset($this->date_start) || $this->date_start === "") {
523 $this->date_start = $this->date_acquisition;
524 }
525
526 $this->db->begin();
527
528 $result = $this->updateCommon($user, $notrigger);
529 if ($result > 0 && $this->fk_asset_model > 0 && $this->fk_asset_model != $this->oldcopy->fk_asset_model) {
530 $result = $this->setDataFromAssetModel($user, $notrigger);
531 }
532 if ($result > 0 && (
533 $this->date_start != $this->oldcopy->date_start ||
534 $this->acquisition_value_ht != $this->oldcopy->acquisition_value_ht ||
535 $this->reversal_date != $this->oldcopy->reversal_date ||
536 $this->reversal_amount_ht != $this->oldcopy->reversal_amount_ht ||
537 ($this->fk_asset_model > 0 && $this->fk_asset_model != $this->oldcopy->fk_asset_model)
538 )
539 ) {
540 $result = $this->calculationDepreciation();
541 }
542
543 if ($result < 0) {
544 $this->db->rollback();
545 } else {
546 $this->db->commit();
547 }
548
549 return $result;
550 }
551
559 public function delete(User $user, $notrigger = 0)
560 {
561 return $this->deleteCommon($user, $notrigger);
562 //return $this->deleteCommon($user, $notrigger, 1);
563 }
564
572 public function setDataFromAssetModel(User $user, $notrigger = 0)
573 {
574 global $langs;
575 $langs->load('assets');
576
577 // Clean parameters
578 $this->id = $this->id > 0 ? $this->id : 0;
579 $this->fk_asset_model = $this->fk_asset_model > 0 ? $this->fk_asset_model : 0;
580
581 // Check parameters
582 $error = 0;
583 if (empty($this->id)) {
584 $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Asset") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
585 $error++;
586 }
587 if (empty($this->fk_asset_model)) {
588 $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("AssetModel") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
589 $error++;
590 }
591 if ($error) {
592 return -1;
593 }
594
595 $this->db->begin();
596
597 // Get depreciation options
598 //---------------------------
599 require_once DOL_DOCUMENT_ROOT . '/asset/class/assetdepreciationoptions.class.php';
600 $options_model = new AssetDepreciationOptions($this->db);
601 $result = $options_model->fetchDeprecationOptions(0, $this->fk_asset_model);
602 if ($result < 0) {
603 $this->error = $options_model->error;
604 $this->errors = $options_model->errors;
605 $error++;
606 } elseif ($result > 0) {
607 $options = new AssetDepreciationOptions($this->db);
608 $result = $options->fetchDeprecationOptions($this->id);
609 if ($result < 0) {
610 $this->error = $options->error;
611 $this->errors = $options->errors;
612 $error++;
613 }
614
615 if (!$error) {
616 foreach ($options_model->deprecation_options as $mode_key => $fields) {
617 foreach ($fields as $field_key => $value) {
618 $options->deprecation_options[$mode_key][$field_key] = $value;
619 }
620 }
621
622 $result = $options->updateDeprecationOptions($user, $this->id, 0, $notrigger);
623 if ($result < 0) {
624 $this->error = $options->error;
625 $this->errors = $options->errors;
626 $error++;
627 }
628 }
629 }
630
631 // Get accountancy codes
632 //---------------------------
633 if (!$error) {
634 require_once DOL_DOCUMENT_ROOT . '/asset/class/assetaccountancycodes.class.php';
635 $accountancy_codes_model = new AssetAccountancyCodes($this->db);
636 $result = $accountancy_codes_model->fetchAccountancyCodes(0, $this->fk_asset_model);
637 if ($result < 0) {
638 $this->error = $accountancy_codes_model->error;
639 $this->errors = $accountancy_codes_model->errors;
640 $error++;
641 } elseif ($result > 0) {
642 $accountancy_codes = new AssetAccountancyCodes($this->db);
643 $result = $accountancy_codes->fetchAccountancyCodes($this->id);
644 if ($result < 0) {
645 $this->error = $accountancy_codes->error;
646 $this->errors = $accountancy_codes->errors;
647 $error++;
648 }
649
650 if (!$error) {
651 foreach ($accountancy_codes_model->accountancy_codes as $mode_key => $fields) {
652 foreach ($fields as $field_key => $value) {
653 $accountancy_codes->accountancy_codes[$mode_key][$field_key] = $value;
654 }
655 }
656
657 $result = $accountancy_codes->updateAccountancyCodes($user, $this->id, 0, $notrigger);
658 if ($result < 0) {
659 $this->error = $accountancy_codes->error;
660 $this->errors = $accountancy_codes->errors;
661 $error++;
662 }
663 }
664 }
665 }
666
667 if ($error) {
668 $this->db->rollback();
669 return -1;
670 } else {
671 $this->db->commit();
672 return 1;
673 }
674 }
675
681 public function fetchDepreciationLines()
682 {
683 global $langs;
684 $langs->load('assets');
685 $this->depreciation_lines = array();
686
687 // Clean parameters
688 $this->id = $this->id > 0 ? $this->id : 0;
689
690 // Check parameters
691 $error = 0;
692 if (empty($this->id)) {
693 $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Asset") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
694 $error++;
695 }
696 if ($error) {
697 return -1;
698 }
699
700 // Old request with 'WITH'
701 /*
702 $sql = "WITH in_accounting_bookkeeping(fk_docdet) AS (";
703 $sql .= " SELECT DISTINCT fk_docdet";
704 $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping";
705 $sql .= " WHERE doc_type = 'asset'";
706 $sql .= ")";
707 $sql .= "SELECT ad.rowid, ad.depreciation_mode, ad.ref, ad.depreciation_date, ad.depreciation_ht, ad.cumulative_depreciation_ht";
708 $sql .= ", " . $this->db->ifsql('iab.fk_docdet IS NOT NULL', 1, 0) . " AS bookkeeping";
709 $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
710 $sql .= " LEFT JOIN in_accounting_bookkeeping as iab ON iab.fk_docdet = ad.rowid";
711 $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
712 $sql .= " ORDER BY ad.depreciation_date ASC";
713 */
714
715 $sql = "SELECT ad.rowid, ad.depreciation_mode, ad.ref, ad.depreciation_date, ad.depreciation_ht, ad.cumulative_depreciation_ht";
716 $sql .= ", " . $this->db->ifsql('iab.fk_docdet IS NOT NULL', 1, 0) . " AS bookkeeping";
717 $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
718 $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";
719 $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
720 $sql .= " ORDER BY ad.depreciation_date ASC";
721
722 $resql = $this->db->query($sql);
723 if (!$resql) {
724 $this->errors[] = $langs->trans('AssetErrorFetchDepreciationLines') . ': ' . $this->db->lasterror();
725 return -1;
726 }
727
728 while ($obj = $this->db->fetch_object($resql)) {
729 if (!isset($this->depreciation_lines[$obj->depreciation_mode])) {
730 $this->depreciation_lines[$obj->depreciation_mode] = array();
731 }
732 $this->depreciation_lines[$obj->depreciation_mode][] = array(
733 'id' => $obj->rowid,
734 'ref' => $obj->ref,
735 'depreciation_date' => $this->db->jdate($obj->depreciation_date),
736 'depreciation_ht' => $obj->depreciation_ht,
737 'cumulative_depreciation_ht' => $obj->cumulative_depreciation_ht,
738 'bookkeeping' => $obj->bookkeeping,
739 );
740 }
741
742 return 1;
743 }
744
751 {
752 global $langs;
753 $langs->load('assets');
754
755 // Clean parameters
756 $this->id = $this->id > 0 ? $this->id : 0;
757
758 // Check parameters
759 $error = 0;
760 if (empty($this->id)) {
761 $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Asset") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
762 $error++;
763 }
764 if ($error) {
765 return -1;
766 }
767
768 // Old request with 'WITH'
769 /*
770 $sql = "WITH in_accounting_bookkeeping(fk_docdet) AS (";
771 $sql .= " SELECT DISTINCT fk_docdet";
772 $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping";
773 $sql .= " WHERE doc_type = 'asset'";
774 $sql .= ")";
775 $sql .= "SELECT COUNT(*) AS has_bookkeeping";
776 $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
777 $sql .= " LEFT JOIN in_accounting_bookkeeping as iab ON iab.fk_docdet = ad.rowid";
778 $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
779 $sql .= " AND iab.fk_docdet IS NOT NULL";
780 */
781
782 $sql = "SELECT COUNT(*) AS has_bookkeeping";
783 $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
784 $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";
785 $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
786 $sql .= " AND iab.fk_docdet IS NOT NULL";
787
788 $resql = $this->db->query($sql);
789 if (!$resql) {
790 $this->errors[] = $langs->trans('AssetErrorFetchDepreciationLines') . ': ' . $this->db->lasterror();
791 return -1;
792 }
793
794 if ($obj = $this->db->fetch_object($resql)) {
795 return $obj->has_bookkeeping > 0 ? 1 : 0;
796 }
797
798 return 0;
799 }
800
813 public function addDepreciationLine($mode, $ref, $depreciation_date, $depreciation_ht, $cumulative_depreciation_ht, $accountancy_code_debit, $accountancy_code_credit)
814 {
815 global $langs;
816 $langs->load('assets');
817
818 // Clean parameters
819 $this->id = $this->id > 0 ? $this->id : 0;
820 $mode = strtolower(trim($mode));
821 $ref = trim($ref);
822 $accountancy_code_debit = trim($accountancy_code_debit);
823 $accountancy_code_credit = trim($accountancy_code_credit);
824
825 // Check parameters
826 $error = 0;
827 if (empty($this->id)) {
828 $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Asset") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
829 $error++;
830 }
831 if ($error) {
832 return -1;
833 }
834
835 $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)";
836 $sql .= " VALUES ( ";
837 $sql .= " " . (int) $this->id;
838 $sql .= ", '" . $this->db->escape($mode) . "'";
839 $sql .= ", '" . $this->db->escape($ref) . "'";
840 $sql .= ", '" . $this->db->idate($depreciation_date) . "'";
841 $sql .= ", " . (float) $depreciation_ht;
842 $sql .= ", " . (float) $cumulative_depreciation_ht;
843 $sql .= ", '" . $this->db->escape($accountancy_code_debit) . "'";
844 $sql .= ", '" . $this->db->escape($accountancy_code_credit) . "'";
845 $sql .= ")";
846
847 $resql = $this->db->query($sql);
848 if (!$resql) {
849 $this->errors[] = $langs->trans('AssetErrorAddDepreciationLine') . ': ' . $this->db->lasterror();
850 return -1;
851 }
852
853 return 1;
854 }
855
861 public function calculationDepreciation()
862 {
863 global $conf, $langs;
864 $langs->load('assets');
865
866 // Clean parameters
867 $this->id = $this->id > 0 ? $this->id : 0;
868
869 // Check parameters
870 $error = 0;
871 if (empty($this->id)) {
872 $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Asset") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
873 $error++;
874 }
875 if ($error) {
876 return -1;
877 }
878
879 if (! empty($this->not_depreciated)) {
880 return 1;
881 }
882
883 // Get depreciation options
884 //---------------------------
885 require_once DOL_DOCUMENT_ROOT . '/asset/class/assetdepreciationoptions.class.php';
886 $options = new AssetDepreciationOptions($this->db);
887 $result = $options->fetchDeprecationOptions($this->id);
888 if ($result < 0) {
889 $this->error = $options->error;
890 $this->errors = $options->errors;
891 return -1;
892 }
893
894 // Get accountancy codes
895 //---------------------------
896 require_once DOL_DOCUMENT_ROOT . '/asset/class/assetaccountancycodes.class.php';
897 $accountancy_codes = new AssetAccountancyCodes($this->db);
898 $result = $accountancy_codes->fetchAccountancyCodes($this->id);
899 if ($result < 0) {
900 $this->error = $accountancy_codes->error;
901 $this->errors = $accountancy_codes->errors;
902 return -1;
903 }
904
905 $this->db->begin();
906
907 // Delete old lines
908 $modes = array();
909 foreach ($options->deprecation_options as $mode_key => $fields) {
910 $modes[$mode_key] = $this->db->escape($mode_key);
911 }
912 $sql = "DELETE FROM " . MAIN_DB_PREFIX . "asset_depreciation";
913 $sql .= " WHERE fk_asset = " . (int) $this->id;
914 $sql .= " AND depreciation_mode NOT IN ('" . $this->db->sanitize(implode("', '", $modes)) . "')";
915
916 $resql = $this->db->query($sql);
917 if (!$resql) {
918 $this->errors[] = $langs->trans('AssetErrorClearDepreciationLines') . ': ' . $this->db->lasterror();
919 $error++;
920 }
921
922 if (!$error) {
923 // Get fiscal period
924 require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
925 require_once DOL_DOCUMENT_ROOT . '/core/lib/accounting.lib.php';
926 // @FIXME getCurrentPeriodOfFiscalYear return the first period found. What if there is several ? And what if not closed ? And what if end date not yet defined.
927 $dates = getCurrentPeriodOfFiscalYear($this->db, $conf, $this->date_start > $this->date_acquisition ? $this->date_start : $this->date_acquisition);
928 $init_fiscal_period_start = $dates['date_start'];
929 $init_fiscal_period_end = $dates['date_end'];
930 if (empty($init_fiscal_period_start) || empty($init_fiscal_period_end)) {
931 $pastmonthyear = $dates['pastmonthyear'];
932 $pastmonth = $dates['pastmonth'];
933 $init_fiscal_period_start = dol_get_first_day($pastmonthyear, $pastmonth, false);
934 $init_fiscal_period_end = dol_get_last_day($pastmonthyear, $pastmonth, false);
935 }
936
937 foreach ($options->deprecation_options as $mode_key => $fields) {
938 // Get last depreciation lines save in bookkeeping
939 //-----------------------------------------------------
940
941 // Old request with 'WITH'
942 /*
943 $sql = "WITH in_accounting_bookkeeping(fk_docdet) AS (";
944 $sql .= " SELECT fk_docdet";
945 $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping";
946 $sql .= " WHERE doc_type = 'asset'";
947 $sql .= ")";
948 $sql .= "SELECT ad.depreciation_date, ad.cumulative_depreciation_ht";
949 $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
950 $sql .= " LEFT JOIN in_accounting_bookkeeping as iab ON iab.fk_docdet = ad.rowid";
951 $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
952 $sql .= " AND ad.depreciation_mode = '" . $this->db->escape($mode_key) . "'";
953 $sql .= " AND iab.fk_docdet IS NOT NULL";
954 $sql .= " ORDER BY ad.depreciation_date DESC";
955 $sql .= " LIMIT 1";
956 */
957
958 $sql = "SELECT ad.depreciation_date, ad.cumulative_depreciation_ht";
959 $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
960 $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";
961 $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
962 $sql .= " AND ad.depreciation_mode = '" . $this->db->escape($mode_key) . "'";
963 $sql .= " AND iab.fk_docdet IS NOT NULL";
964 $sql .= " ORDER BY ad.depreciation_date DESC";
965 $sql .= " LIMIT 1";
966
967 $resql = $this->db->query($sql);
968 if (!$resql) {
969 $this->errors[] = $langs->trans('AssetErrorFetchMaxDepreciationDateForMode', $mode_key) . ': ' . $this->db->lasterror();
970 $error++;
971 break;
972 }
973 $last_depreciation_date = '';
974 $last_cumulative_depreciation_ht = $this->reversal_amount_ht;
975 if ($obj = $this->db->fetch_object($resql)) {
976 $last_depreciation_date = $this->db->jdate($obj->depreciation_date);
977 $last_cumulative_depreciation_ht = $obj->cumulative_depreciation_ht;
978 }
979
980 // Set last cumulative depreciation
981 $sql = "UPDATE " . MAIN_DB_PREFIX . $options->deprecation_options_fields[$mode_key]['table'];
982 $sql .= " SET total_amount_last_depreciation_ht = " . (empty($last_cumulative_depreciation_ht) ? 0 : $last_cumulative_depreciation_ht);
983 $sql .= " WHERE fk_asset = " . (int) $this->id;
984 $resql = $this->db->query($sql);
985 if (!$resql) {
986 $this->errors[] = $langs->trans('AssetErrorSetLastCumulativeDepreciation') . ': ' . $this->db->lasterror();
987 $error++;
988 break;
989 }
990
991 // Delete old lines
992 $sql = "DELETE FROM " . MAIN_DB_PREFIX . "asset_depreciation";
993 $sql .= " WHERE fk_asset = " . (int) $this->id;
994 $sql .= " AND depreciation_mode = '" . $this->db->escape($mode_key) . "'";
995 $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)";
996 if ($last_depreciation_date !== "") {
997 $sql .= " AND ref <> ''";
998 }
999 $resql = $this->db->query($sql);
1000 if (!$resql) {
1001 $this->errors[] = $langs->trans('AssetErrorClearDepreciationLines') . ': ' . $this->db->lasterror();
1002 $error++;
1003 break;
1004 }
1005
1006 // Get depreciation period
1007 $depreciation_date_start = $this->date_start > $this->date_acquisition ? $this->date_start : $this->date_acquisition;
1008 $depreciation_date_end = dol_time_plus_duree(dol_time_plus_duree((int) $depreciation_date_start, $fields['duration'], $fields['duration_type'] == 1 ? 'm' : ($fields['duration_type'] == 2 ? 'd' : 'y')), -1, 'd');
1009 $depreciation_amount = $fields['amount_base_depreciation_ht'];
1010 if ($fields['duration_type'] == 2) { // Daily
1011 $fiscal_period_start = $depreciation_date_start;
1012 $fiscal_period_end = $depreciation_date_start;
1013 } elseif ($fields['duration_type'] == 1) { // Monthly
1014 $date_temp = dol_getdate((int) $depreciation_date_start);
1015 $fiscal_period_start = dol_get_first_day($date_temp['year'], $date_temp['mon'], false);
1016 $fiscal_period_end = dol_get_last_day($date_temp['year'], $date_temp['mon'], false);
1017 } else { // Annually
1018 $fiscal_period_start = $init_fiscal_period_start;
1019 $fiscal_period_end = $init_fiscal_period_end;
1020 }
1021 $cumulative_depreciation_ht = (float) $last_cumulative_depreciation_ht;
1022 $depreciation_period_amount = $depreciation_amount - (float) $this->reversal_amount_ht;
1023 $start_date = $depreciation_date_start;
1024 $disposal_date = isset($this->disposal_date) && $this->disposal_date !== "" ? $this->disposal_date : "";
1025 $finish_date = $disposal_date !== "" ? $disposal_date : $depreciation_date_end;
1026 $accountancy_code_depreciation_debit_key = $accountancy_codes->accountancy_codes_fields[$mode_key]['depreciation_debit'];
1027 $accountancy_code_depreciation_debit = $accountancy_codes->accountancy_codes[$mode_key][$accountancy_code_depreciation_debit_key];
1028 $accountancy_code_depreciation_credit_key = $accountancy_codes->accountancy_codes_fields[$mode_key]['depreciation_credit'];
1029 $accountancy_code_credit = $accountancy_codes->accountancy_codes[$mode_key][$accountancy_code_depreciation_credit_key];
1030
1031 // Reversal depreciation line
1032 //-----------------------------------------------------
1033 if ($last_depreciation_date === "" && ($depreciation_date_start < $fiscal_period_start || is_numeric($this->reversal_date))) {
1034 if (is_numeric($this->reversal_date)) {
1035 if ($this->reversal_date < $fiscal_period_start) {
1036 $this->errors[] = $langs->trans('AssetErrorReversalDateNotGreaterThanCurrentBeginFiscalDateForMode', $mode_key);
1037 $error++;
1038 break;
1039 }
1040
1041 if (empty($this->reversal_amount_ht)) {
1042 $this->errors[] = $langs->trans('AssetErrorReversalAmountNotProvidedForMode', $mode_key);
1043 $error++;
1044 break;
1045 }
1046
1047 $start_date = $this->reversal_date;
1048 $result = $this->addDepreciationLine($mode_key, '', $start_date, $this->reversal_amount_ht, $this->reversal_amount_ht, $accountancy_code_depreciation_debit, $accountancy_code_credit);
1049 if ($result < 0) {
1050 $error++;
1051 break;
1052 }
1053 } else {
1054 $this->errors[] = $langs->trans('AssetErrorReversalDateNotProvidedForMode', $mode_key);
1055 $error++;
1056 break;
1057 }
1058 }
1059
1060 // futures depreciation lines
1061 //-----------------------------------------------------
1062 $nb_days_in_year = getDolGlobalInt('ASSET_DEPRECIATION_DURATION_PER_YEAR', 360);
1063 $nb_days_in_month = getDolGlobalInt('ASSET_DEPRECIATION_DURATION_PER_MONTH', 30);
1064 $period_amount = (float) ($fields['duration'] > 0 ? price2num($depreciation_period_amount / $fields['duration'], 'MT') : 0);
1065 $first_period_found = false;
1066 // TODO fix declaration of $begin_period
1067 $first_period_date = isset($begin_period) && $begin_period > $fiscal_period_start ? $begin_period : $fiscal_period_start;
1068
1069 $ref_date_format = "%Y" . ($fields['duration_type'] == 1 || $fields['duration_type'] == 2 ? '-%m' : '') . ($fields['duration_type'] == 2 ? '-%d' : '');
1070
1071 // Loop security
1072 $idx_loop = 0;
1073 $max_loop = $fields['duration'] + 2;
1074 do {
1075 // Loop security
1076 $idx_loop++;
1077 if ($idx_loop > $max_loop) {
1078 break;
1079 }
1080
1081 if ($last_depreciation_date < $fiscal_period_end && ($first_period_date <= $start_date || $first_period_found)) {
1082 // Disposal not depreciated
1083 if ($fiscal_period_start <= $disposal_date && $disposal_date <= $fiscal_period_end && empty($this->disposal_depreciated)) {
1084 break;
1085 }
1086
1087 $first_period_found = true;
1088
1089 $period_begin = dol_print_date($fiscal_period_start, $ref_date_format);
1090 $period_end = dol_print_date($fiscal_period_end, $ref_date_format);
1091 $ref = $period_begin . ($period_begin != $period_end ? ' - ' . $period_end : '');
1092 if ($fiscal_period_start <= $disposal_date && $disposal_date <= $fiscal_period_end) {
1093 $ref .= ' - ' . $langs->transnoentitiesnoconv('AssetDisposal');
1094 }
1095
1096 $begin_date = $fiscal_period_start < $start_date && $start_date <= $fiscal_period_end ? $start_date : $fiscal_period_start;
1097 $end_date = $fiscal_period_start < $finish_date && $finish_date <= $fiscal_period_end ? $finish_date : $fiscal_period_end;
1098 if ($fields['duration_type'] == 2) { // Daily
1099 $depreciation_ht = $period_amount;
1100 } elseif ($fields['duration_type'] == 1) { // Monthly
1101 $nb_days = min($nb_days_in_month, num_between_day($begin_date, $end_date, 1));
1102 if ($nb_days >= 28) {
1103 $date_temp = dol_getdate($begin_date);
1104 if ($date_temp['mon'] == 2) {
1105 $nb_days = 30;
1106 }
1107 }
1108 $depreciation_ht = (float) price2num($period_amount * $nb_days / $nb_days_in_month, 'MT');
1109 } else { // Annually, taking care for adjustments to shortened or extended periods (e.g., fiscal years of 9 or 15 months)
1110 $nb_days_real = num_between_day($begin_date, $end_date, 1);
1111 if (($nb_days_real > 366) || (num_between_day($fiscal_period_start, $fiscal_period_end, 1) < $nb_days_in_year)) { // FY Period changed
1112 $nb_days = $nb_days_real;
1113 } else {
1114 $nb_days = min($nb_days_in_year, $nb_days_real);
1115 }
1116 $depreciation_ht = (float) price2num($period_amount * $nb_days / $nb_days_in_year, 'MT');
1117 }
1118 if (getDolGlobalInt('ASSET_ROUND_INTEGER_NUMBER_UPWARDS') == 1) {
1119 if ($idx_loop < $max_loop) { // avoid last depreciation value
1120 $depreciation_ht = ceil($depreciation_ht);
1121 }
1122 }
1123
1124 if ($fiscal_period_start <= $depreciation_date_end && $depreciation_date_end <= $fiscal_period_end) { // last period
1125 $depreciation_ht = (float) price2num($depreciation_amount - (float) $cumulative_depreciation_ht, 'MT');
1126 $cumulative_depreciation_ht = $depreciation_amount;
1127 } else {
1128 $cumulative_depreciation_ht += $depreciation_ht;
1129 }
1130
1131 $result = $this->addDepreciationLine($mode_key, $ref, $fiscal_period_end, $depreciation_ht, $cumulative_depreciation_ht, $accountancy_code_depreciation_debit, $accountancy_code_credit);
1132 if ($result < 0) {
1133 $error++;
1134 break;
1135 }
1136 }
1137
1138 // Next fiscal period (+1 day/month/year)
1139 $fiscal_period_start = dol_time_plus_duree($fiscal_period_end, 1, 'd');
1140 $dates_fiscal_period = getCurrentPeriodOfFiscalYear($this->db, $conf, $fiscal_period_start, 'gmt');
1141 if ($fields['duration_type'] == 2) { // Daily
1142 $fiscal_period_end = $fiscal_period_start;
1143 } elseif ($fields['duration_type'] == 1) { // Monthly
1144 $fiscal_period_end = dol_time_plus_duree(dol_time_plus_duree($fiscal_period_start, 1, 'm'), -1, 'd');
1145 } else { // Annually
1146 $fiscal_period_end = $dates_fiscal_period['date_end'];
1147 }
1148 $last_period_date = $disposal_date !== "" && $disposal_date < $depreciation_date_end ? $disposal_date : $depreciation_date_end;
1149 } while ($fiscal_period_start < $last_period_date);
1150
1151 if ($error) {
1152 break;
1153 }
1154 }
1155 }
1156
1157 if ($error) {
1158 $this->db->rollback();
1159 return -1;
1160 } else {
1161 $this->db->commit();
1162 return 1;
1163 }
1164 }
1165
1172 public function setLastCumulativeDepreciation($asset_depreciation_id)
1173 {
1174 global $langs;
1175 $langs->load('assets');
1176
1177 // Clean parameters
1178 $asset_depreciation_id = $asset_depreciation_id > 0 ? $asset_depreciation_id : 0;
1179
1180 // Check parameters
1181 $error = 0;
1182 if (empty($asset_depreciation_id)) {
1183 $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("AssetDepreciation") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
1184 $error++;
1185 }
1186 if ($error) {
1187 return -1;
1188 }
1189
1190 $this->db->begin();
1191
1192 require_once DOL_DOCUMENT_ROOT . '/asset/class/assetdepreciationoptions.class.php';
1193 $options = new AssetDepreciationOptions($this->db);
1194
1195 // Get last depreciation lines save in bookkeeping
1196 //-----------------------------------------------------
1197 $sql = "SELECT fk_asset, depreciation_mode, cumulative_depreciation_ht";
1198 $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation";
1199 $sql .= " WHERE rowid = " . (int) $asset_depreciation_id;
1200 $resql = $this->db->query($sql);
1201 if (!$resql) {
1202 $this->errors[] = $langs->trans('AssetErrorFetchCumulativeDepreciation') . ': ' . $this->db->lasterror();
1203 $error++;
1204 } else {
1205 if ($obj = $this->db->fetch_object($resql)) {
1206 $mode_key = $obj->depreciation_mode;
1207 if (!empty($options->deprecation_options_fields[$mode_key])) {
1208 $sql = "UPDATE " . MAIN_DB_PREFIX . $options->deprecation_options_fields[$mode_key]['table'];
1209 $sql .= " SET total_amount_last_depreciation_ht = " . $obj->cumulative_depreciation_ht;
1210 $sql .= " WHERE fk_asset = " . (int) $obj->fk_asset;
1211 $resql = $this->db->query($sql);
1212 if (!$resql) {
1213 $this->errors[] = $langs->trans('AssetErrorSetLastCumulativeDepreciation') . ': ' . $this->db->lasterror();
1214 $error++;
1215 }
1216 }
1217 }
1218 }
1219
1220 if ($error) {
1221 $this->db->rollback();
1222 return -1;
1223 } else {
1224 $this->db->commit();
1225 return 1;
1226 }
1227 }
1228
1237 public function dispose($user, $disposal_invoice_id, $notrigger = 0)
1238 {
1239 global $conf, $langs;
1240
1241 // Protection
1242 if ($this->status != self::STATUS_DRAFT || $this->status == self::STATUS_DISPOSED) {
1243 return 0;
1244 }
1245
1246 $this->db->begin();
1247
1248 $required_fields = array('disposal_date', 'disposal_date', 'fk_disposal_type');
1249 foreach ($required_fields as $field) {
1250 $this->fields[$field]['notnull'] = 1;
1251 }
1252 $result = $this->update($user, 1);
1253 foreach ($required_fields as $field) {
1254 $this->fields[$field]['notnull'] = 0;
1255 }
1256 if ($result > 0) {
1257 if ($disposal_invoice_id > 0) {
1258 $this->add_object_linked('facture', $disposal_invoice_id);
1259 }
1260 $result = $this->setStatusCommon($user, self::STATUS_DISPOSED, $notrigger, 'ASSET_DISPOSED');
1261 }
1262 if ($result > 0) {
1263 $result = $this->calculationDepreciation();
1264 }
1265
1266 if ($result < 0) {
1267 $this->db->rollback();
1268 } else {
1269 $this->db->commit();
1270 }
1271
1272 // Define output language
1273 if ($result > 0 && !getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
1274 if (method_exists($this, 'generateDocument')) {
1275 global $hidedetails, $hidedesc, $hideref;
1276 $outputlangs = $langs;
1277 $newlang = '';
1278 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
1279 $newlang = GETPOST('lang_id', 'aZ09');
1280 }
1281 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
1282 $newlang = $this->thirdparty->default_lang;
1283 }
1284 if (!empty($newlang)) {
1285 $outputlangs = new Translate("", $conf);
1286 $outputlangs->setDefaultLang($newlang);
1287 }
1288 $model = $this->model_pdf;
1289 $ret = $this->fetch($this->id); // Reload to get new records
1290
1291 $this->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
1292 }
1293 }
1294
1295 return $result;
1296 }
1297
1305 public function reopen($user, $notrigger = 0)
1306 {
1307 global $conf, $langs;
1308
1309 // Protection
1310 if ($this->status != self::STATUS_DISPOSED || $this->status == self::STATUS_DRAFT) {
1311 return 0;
1312 }
1313
1314
1315 $this->db->begin();
1316
1317 $this->disposal_date = null;
1318 $this->disposal_amount_ht = null;
1319 $this->fk_disposal_type = null;
1320 $this->disposal_depreciated = 0;
1321 $this->disposal_subject_to_vat = 0;
1322 $result = $this->update($user, 1);
1323 if ($result > 0) {
1324 $this->deleteObjectLinked(null, 'facture');
1325 $result = $this->setStatusCommon($user, self::STATUS_DRAFT, $notrigger, 'ASSET_REOPEN');
1326 }
1327 if ($result > 0) {
1328 $result = $this->calculationDepreciation();
1329 }
1330
1331 if ($result < 0) {
1332 $this->db->rollback();
1333 } else {
1334 $this->db->commit();
1335 }
1336
1337 // Define output language
1338 if ($result > 0 && !getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
1339 if (method_exists($this, 'generateDocument')) {
1340 global $hidedetails, $hidedesc, $hideref;
1341 $outputlangs = $langs;
1342 $newlang = '';
1343 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
1344 $newlang = GETPOST('lang_id', 'aZ09');
1345 }
1346 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
1347 $newlang = $this->thirdparty->default_lang;
1348 }
1349 if (!empty($newlang)) {
1350 $outputlangs = new Translate("", $conf);
1351 $outputlangs->setDefaultLang($newlang);
1352 }
1353 $model = $this->model_pdf;
1354 $ret = $this->fetch($this->id); // Reload to get new records
1355
1356 $this->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
1357 }
1358 }
1359
1360 return $result;
1361 }
1362
1374 public function getNomUrl($withpicto = 0, $option = '', $maxlen = 0, $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
1375 {
1376 global $db, $conf, $langs, $hookmanager;
1377 global $dolibarr_main_authentication, $dolibarr_main_demo;
1378 global $menumanager;
1379
1380 if (!empty($conf->dol_no_mouse_hover)) {
1381 $notooltip = 1; // Force disable tooltips
1382 }
1383
1384 $result = '';
1385
1386 $label = img_picto('', $this->picto).' <u>'.$langs->trans("Asset").'</u>';
1387 if (isset($this->status)) {
1388 $label .= ' '.$this->getLibStatut(5);
1389 }
1390 $label .= '<br>';
1391 $label .= '<b>'.$langs->trans('Ref').':</b> '.$this->ref;
1392
1393 $url = dol_buildpath('/asset/card.php', 1).'?id='.$this->id;
1394
1395 if ($option != 'nolink') {
1396 // Add param to save lastsearch_values or not
1397 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1398 if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
1399 $add_save_lastsearch_values = 1;
1400 }
1401 if ($add_save_lastsearch_values) {
1402 $url .= '&save_lastsearch_values=1';
1403 }
1404 }
1405
1406 $linkclose = '';
1407 if (empty($notooltip)) {
1408 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
1409 $label = $langs->trans("ShowAsset");
1410 $linkclose .= ' alt="'.dolPrintHTMLForAttribute($label).'"';
1411 }
1412 $linkclose .= ' title="'.dolPrintHTMLForAttribute($label).'"';
1413 $linkclose .= ' class="classfortooltip'.($morecss ? ' '.$morecss : '').'"';
1414 } else {
1415 $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
1416 }
1417
1418 if ($option == 'nolink') {
1419 $linkstart = '<span';
1420 } else {
1421 $linkstart = '<a href="'.$url.'"';
1422 }
1423 $linkstart .= $linkclose.'>';
1424 if ($option == 'nolink') {
1425 $linkend = '</span>';
1426 } else {
1427 $linkend = '</a>';
1428 }
1429
1430 $result .= $linkstart;
1431
1432 if (empty($this->showphoto_on_popup)) {
1433 if ($withpicto) {
1434 $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);
1435 }
1436 } else {
1437 if ($withpicto) {
1438 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1439
1440 list($class, $module) = explode('@', $this->picto);
1441 $upload_dir = $conf->$module->multidir_output[$conf->entity]."/$class/".dol_sanitizeFileName($this->ref);
1442 $filearray = dol_dir_list($upload_dir, "files");
1443 $filename = $filearray[0]['name'];
1444 if (!empty($filename)) {
1445 $pospoint = strpos($filearray[0]['name'], '.');
1446
1447 $pathtophoto = $class.'/'.$this->ref.'/thumbs/'.substr($filename, 0, $pospoint).'_mini'.substr($filename, $pospoint);
1448 if (!getDolGlobalString(strtoupper($module.'_'.$class).'_FORMATLISTPHOTOSASUSERS')) {
1449 $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>';
1450 } else {
1451 $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>';
1452 }
1453
1454 $result .= '</div>';
1455 } else {
1456 $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);
1457 }
1458 }
1459 }
1460
1461 if ($withpicto != 2) {
1462 $name = $this->ref;
1463 if ($option == 'label') {
1464 $name = $this->label;
1465 } elseif ($option == 'with_label') {
1466 $name .= ' - ' . $this->label;
1467 }
1468 $result .= dol_escape_htmltag($maxlen ? dol_trunc($name, $maxlen) : $name);
1469 }
1470
1471 $result .= $linkend;
1472 //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
1473
1474 global $action;
1475 $hookmanager->initHooks(array($this->element . 'dao'));
1476 $parameters = array('id' => $this->id, 'getnomurl' => &$result);
1477 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1478 if ($reshook > 0) {
1479 $result = $hookmanager->resPrint;
1480 } else {
1481 $result .= $hookmanager->resPrint;
1482 }
1483 return $result;
1484 }
1485
1492 public function getLabelStatus($mode = 0)
1493 {
1494 return $this->LibStatut($this->status, $mode);
1495 }
1496
1503 public function getLibStatut($mode = 0)
1504 {
1505 return $this->LibStatut($this->status, $mode);
1506 }
1507
1508 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1516 public function LibStatut($status, $mode = 0)
1517 {
1518 // phpcs:enable
1519 if (empty($this->labelStatus) || empty($this->labelStatusShort)) {
1520 global $langs;
1521 //$langs->load("assets");
1522 $this->labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('AssetInProgress');
1523 $this->labelStatus[self::STATUS_DISPOSED] = $langs->transnoentitiesnoconv('AssetDisposed');
1524 $this->labelStatusShort[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('AssetInProgress');
1525 $this->labelStatusShort[self::STATUS_DISPOSED] = $langs->transnoentitiesnoconv('AssetDisposed');
1526 }
1527
1528 $statusType = 'status4';
1529 if ($status == self::STATUS_DISPOSED) {
1530 $statusType = 'status6';
1531 }
1532
1533 return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode);
1534 }
1535
1542 public function info($id)
1543 {
1544 $sql = "SELECT rowid, date_creation as datec, tms as datem,";
1545 $sql .= " fk_user_creat, fk_user_modif";
1546 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as t";
1547 $sql .= " WHERE t.rowid = ".((int) $id);
1548
1549 $result = $this->db->query($sql);
1550 if ($result) {
1551 if ($this->db->num_rows($result)) {
1552 $obj = $this->db->fetch_object($result);
1553 $this->id = $obj->rowid;
1554
1555 $this->user_creation_id = $obj->fk_user_creat;
1556 $this->user_modification_id = $obj->fk_user_modif;
1557 $this->date_creation = $this->db->jdate($obj->datec);
1558 $this->date_modification = $this->db->jdate($obj->datem);
1559 }
1560
1561 $this->db->free($result);
1562 } else {
1563 dol_print_error($this->db);
1564 }
1565 }
1566
1573 public function initAsSpecimen()
1574 {
1575 // Set here init that are not commonf fields
1576 // $this->property1 = ...
1577 // $this->property2 = ...
1578
1579 return $this->initAsSpecimenCommon();
1580 }
1581
1587 public function getNextNumRef()
1588 {
1589 global $langs, $conf;
1590 $langs->load("assets");
1591
1592 if (!getDolGlobalString('ASSET_ASSET_ADDON')) {
1593 $conf->global->ASSET_ASSET_ADDON = 'mod_asset_standard';
1594 }
1595
1596 if (getDolGlobalString('ASSET_ASSET_ADDON')) {
1597 $mybool = false;
1598
1599 $file = getDolGlobalString('ASSET_ASSET_ADDON') . ".php";
1600 $classname = getDolGlobalString('ASSET_ASSET_ADDON');
1601
1602 // Include file with class
1603 $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
1604 foreach ($dirmodels as $reldir) {
1605 $dir = dol_buildpath($reldir."core/modules/asset/");
1606
1607 // Load file with numbering class (if found)
1608 $mybool = ((bool) @include_once $dir.$file) || $mybool;
1609 }
1610
1611 if (!$mybool) {
1612 dol_print_error(null, "Failed to include file ".$file);
1613 return '';
1614 }
1615
1616 if (class_exists($classname)) {
1617 $obj = new $classname();
1618
1619 '@phan-var-force ModeleNumRefAsset $obj';
1620
1621 $numref = $obj->getNextValue($this);
1622
1623 if ($numref != '' && $numref != '-1') {
1624 return $numref;
1625 } else {
1626 $this->error = $obj->error;
1627 //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error);
1628 return "";
1629 }
1630 } else {
1631 print $langs->trans("Error")." ".$langs->trans("ClassNotFound").' '.$classname;
1632 return "";
1633 }
1634 } else {
1635 print $langs->trans("ErrorNumberingModuleNotSetup", $this->element);
1636 return "";
1637 }
1638 }
1639}
getCurrentPeriodOfFiscalYear($db, $conf, $from_time=null, $gm='tzserver', $withenddateonly=1)
Get current period of fiscal year?
$object ref
Definition info.php:89
Class for AssetAccountancyCodes.
Class for AssetDepreciationOptions.
Class for Asset.
getNomUrl($withpicto=0, $option='', $maxlen=0, $notooltip=0, $morecss='', $save_lastsearch_value=-1)
Return a link to the object card (with optionally the picto)
hasDepreciationLinesInBookkeeping()
If has depreciation lines in bookkeeping.
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.
__construct(DoliDB $db)
Constructor.
create(User $user, $notrigger=0)
Create object into database.
info($id)
Load the info information in the object.
getLabelStatus($mode=0)
Return the label of the status.
fetchAll($sortorder='', $sortfield='', $limit=0, $offset=0, $filter='', $filtermode='AND')
Load list of objects in memory from the 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.
update(User $user, $notrigger=0)
Update object into database.
setDataFromAssetModel(User $user, $notrigger=0)
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=0)
Create object in the database.
getFieldList($alias='', $excludefields=array())
Function to concat keys of fields.
updateCommon(User $user, $notrigger=0)
Update object into 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.
fetchCommon($id, $ref=null, $morewhere='', $noextrafields=0)
Load object in memory from the database.
deleteCommon(User $user, $notrigger=0, $forcechilddeletion=0)
Delete object in database.
Class to manage Dolibarr database access.
Class to manage translations.
Class to manage Dolibarr users.
print $langs trans("Ref").' m titre as m m statut as status
Or an array listing all the potential status of the object: array: int of the status => translated la...
Definition index.php:171
dol_get_first_day($year, $month=1, $gm=false)
Return GMT time for first day of a month or year.
Definition date.lib.php:600
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:619
dol_dir_list($utf8_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:63
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2, $allowothertags=array())
Show picto whatever it's its name (generic function)
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $allowothertags=array())
Show a picto called object_picto (generic function)
forgeSQLFromUniversalSearchCriteria($filter, &$errorstr='', $noand=0, $nopar=0, $noerror=0)
forgeSQLFromUniversalSearchCriteria
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
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_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
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.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1, $includequotes=0)
Clean a string to use it as a file name.
getDolGlobalString($key, $default='')
Return a 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...
global $conf
The following vars must be defined: $type2label $form $conf, $lang, The following vars may also be de...
Definition member.php:79