dolibarr 21.0.0-beta
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"),
92 '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,),
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,),
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,),
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,),
97 'not_depreciated' => array('type' => 'boolean', 'label' => 'AssetNotDepreciated', 'enabled' => 1, 'position' => 80, 'notnull' => 0, 'default' => '0', 'visible' => 1, 'validate' => 1,),
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,),
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 " . MAIN_DB_PREFIX . "asset_depreciation FROM " . MAIN_DB_PREFIX . "asset_depreciation";
993 $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "accounting_bookkeeping as ab ON ab.doc_type = 'asset' AND ab.fk_docdet = " . MAIN_DB_PREFIX . "asset_depreciation.rowid";
994 $sql .= " WHERE " . MAIN_DB_PREFIX . "asset_depreciation.fk_asset = " . (int) $this->id;
995 $sql .= " AND " . MAIN_DB_PREFIX . "asset_depreciation.depreciation_mode = '" . $this->db->escape($mode_key) . "'";
996 $sql .= " AND ab.fk_docdet IS NULL";
997 if ($last_depreciation_date !== "") {
998 $sql .= " AND " . MAIN_DB_PREFIX . "asset_depreciation.ref != ''";
999 }
1000 $resql = $this->db->query($sql);
1001 if (!$resql) {
1002 $this->errors[] = $langs->trans('AssetErrorClearDepreciationLines') . ': ' . $this->db->lasterror();
1003 $error++;
1004 break;
1005 }
1006
1007 // Get depreciation period
1008 $depreciation_date_start = $this->date_start > $this->date_acquisition ? $this->date_start : $this->date_acquisition;
1009 $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');
1010 $depreciation_amount = $fields['amount_base_depreciation_ht'];
1011 if ($fields['duration_type'] == 2) { // Daily
1012 $fiscal_period_start = $depreciation_date_start;
1013 $fiscal_period_end = $depreciation_date_start;
1014 } elseif ($fields['duration_type'] == 1) { // Monthly
1015 $date_temp = dol_getdate((int) $depreciation_date_start);
1016 $fiscal_period_start = dol_get_first_day($date_temp['year'], $date_temp['mon'], false);
1017 $fiscal_period_end = dol_get_last_day($date_temp['year'], $date_temp['mon'], false);
1018 } else { // Annually
1019 $fiscal_period_start = $init_fiscal_period_start;
1020 $fiscal_period_end = $init_fiscal_period_end;
1021 }
1022 $cumulative_depreciation_ht = (float) $last_cumulative_depreciation_ht;
1023 $depreciation_period_amount = $depreciation_amount - (float) $this->reversal_amount_ht;
1024 $start_date = $depreciation_date_start;
1025 $disposal_date = isset($this->disposal_date) && $this->disposal_date !== "" ? $this->disposal_date : "";
1026 $finish_date = $disposal_date !== "" ? $disposal_date : $depreciation_date_end;
1027 $accountancy_code_depreciation_debit_key = $accountancy_codes->accountancy_codes_fields[$mode_key]['depreciation_debit'];
1028 $accountancy_code_depreciation_debit = $accountancy_codes->accountancy_codes[$mode_key][$accountancy_code_depreciation_debit_key];
1029 $accountancy_code_depreciation_credit_key = $accountancy_codes->accountancy_codes_fields[$mode_key]['depreciation_credit'];
1030 $accountancy_code_credit = $accountancy_codes->accountancy_codes[$mode_key][$accountancy_code_depreciation_credit_key];
1031
1032 // Reversal depreciation line
1033 //-----------------------------------------------------
1034 if ($last_depreciation_date === "" && ($depreciation_date_start < $fiscal_period_start || is_numeric($this->reversal_date))) {
1035 if (is_numeric($this->reversal_date)) {
1036 if ($this->reversal_date < $fiscal_period_start) {
1037 $this->errors[] = $langs->trans('AssetErrorReversalDateNotGreaterThanCurrentBeginFiscalDateForMode', $mode_key);
1038 $error++;
1039 break;
1040 }
1041
1042 if (empty($this->reversal_amount_ht)) {
1043 $this->errors[] = $langs->trans('AssetErrorReversalAmountNotProvidedForMode', $mode_key);
1044 $error++;
1045 break;
1046 }
1047
1048 $start_date = $this->reversal_date;
1049 $result = $this->addDepreciationLine($mode_key, '', $start_date, $this->reversal_amount_ht, $this->reversal_amount_ht, $accountancy_code_depreciation_debit, $accountancy_code_credit);
1050 if ($result < 0) {
1051 $error++;
1052 break;
1053 }
1054 } else {
1055 $this->errors[] = $langs->trans('AssetErrorReversalDateNotProvidedForMode', $mode_key);
1056 $error++;
1057 break;
1058 }
1059 }
1060
1061 // futures depreciation lines
1062 //-----------------------------------------------------
1063 $nb_days_in_year = getDolGlobalInt('ASSET_DEPRECIATION_DURATION_PER_YEAR', 360);
1064 $nb_days_in_month = getDolGlobalInt('ASSET_DEPRECIATION_DURATION_PER_MONTH', 30);
1065 $period_amount = (float) price2num($depreciation_period_amount / $fields['duration'], 'MT');
1066 $first_period_found = false;
1067 // TODO fix declaration of $begin_period
1068 $first_period_date = isset($begin_period) && $begin_period > $fiscal_period_start ? $begin_period : $fiscal_period_start;
1069
1070 $ref_date_format = "%Y" . ($fields['duration_type'] == 1 || $fields['duration_type'] == 2 ? '-%m' : '') . ($fields['duration_type'] == 2 ? '-%d' : '');
1071
1072 // Loop security
1073 $idx_loop = 0;
1074 $max_loop = $fields['duration'] + 2;
1075 do {
1076 // Loop security
1077 $idx_loop++;
1078 if ($idx_loop > $max_loop) {
1079 break;
1080 }
1081
1082 if ($last_depreciation_date < $fiscal_period_end && ($first_period_date <= $start_date || $first_period_found)) {
1083 // Disposal not depreciated
1084 if ($fiscal_period_start <= $disposal_date && $disposal_date <= $fiscal_period_end && empty($this->disposal_depreciated)) {
1085 break;
1086 }
1087
1088 $first_period_found = true;
1089
1090 $period_begin = dol_print_date($fiscal_period_start, $ref_date_format);
1091 $period_end = dol_print_date($fiscal_period_end, $ref_date_format);
1092 $ref = $period_begin . ($period_begin != $period_end ? ' - ' . $period_end : '');
1093 if ($fiscal_period_start <= $disposal_date && $disposal_date <= $fiscal_period_end) {
1094 $ref .= ' - ' . $langs->transnoentitiesnoconv('AssetDisposal');
1095 }
1096
1097 $begin_date = $fiscal_period_start < $start_date && $start_date <= $fiscal_period_end ? $start_date : $fiscal_period_start;
1098 $end_date = $fiscal_period_start < $finish_date && $finish_date <= $fiscal_period_end ? $finish_date : $fiscal_period_end;
1099 if ($fields['duration_type'] == 2) { // Daily
1100 $depreciation_ht = $period_amount;
1101 } elseif ($fields['duration_type'] == 1) { // Monthly
1102 $nb_days = min($nb_days_in_month, num_between_day($begin_date, $end_date, 1));
1103 if ($nb_days >= 28) {
1104 $date_temp = dol_getdate($begin_date);
1105 if ($date_temp['mon'] == 2) {
1106 $nb_days = 30;
1107 }
1108 }
1109 $depreciation_ht = (float) price2num($period_amount * $nb_days / $nb_days_in_month, 'MT');
1110 } else { // Annually, taking care for adjustments to shortened or extended periods (e.g., fiscal years of 9 or 15 months)
1111 $nb_days_real = num_between_day($begin_date, $end_date, 1);
1112 if (($nb_days_real > 366) || (num_between_day($fiscal_period_start, $fiscal_period_end, 1) < $nb_days_in_year)) { // FY Period changed
1113 $nb_days = $nb_days_real;
1114 } else {
1115 $nb_days = min($nb_days_in_year, $nb_days_real);
1116 }
1117 $depreciation_ht = (double) price2num($period_amount * $nb_days / $nb_days_in_year, 'MT');
1118 }
1119 if (getDolGlobalInt('ASSET_ROUND_INTEGER_NUMBER_UPWARDS') == 1) {
1120 if ($idx_loop < $max_loop) { // avoid last depreciation value
1121 $depreciation_ht = ceil($depreciation_ht);
1122 }
1123 }
1124
1125 if ($fiscal_period_start <= $depreciation_date_end && $depreciation_date_end <= $fiscal_period_end) { // last period
1126 $depreciation_ht = (float) price2num($depreciation_amount - (float) $cumulative_depreciation_ht, 'MT');
1127 $cumulative_depreciation_ht = $depreciation_amount;
1128 } else {
1129 $cumulative_depreciation_ht += $depreciation_ht;
1130 }
1131
1132 $result = $this->addDepreciationLine($mode_key, $ref, $fiscal_period_end, $depreciation_ht, $cumulative_depreciation_ht, $accountancy_code_depreciation_debit, $accountancy_code_credit);
1133 if ($result < 0) {
1134 $error++;
1135 break;
1136 }
1137 }
1138
1139 // Next fiscal period (+1 day/month/year)
1140 $fiscal_period_start = dol_time_plus_duree($fiscal_period_end, 1, 'd');
1141 $dates_fiscal_period = getCurrentPeriodOfFiscalYear($this->db, $conf, $fiscal_period_start, 'gmt');
1142 if ($fields['duration_type'] == 2) { // Daily
1143 $fiscal_period_end = $fiscal_period_start;
1144 } elseif ($fields['duration_type'] == 1) { // Monthly
1145 $fiscal_period_end = dol_time_plus_duree(dol_time_plus_duree($fiscal_period_start, 1, 'm'), -1, 'd');
1146 } else { // Annually
1147 $fiscal_period_end = $dates_fiscal_period['date_end'];
1148 }
1149 $last_period_date = $disposal_date !== "" && $disposal_date < $depreciation_date_end ? $disposal_date : $depreciation_date_end;
1150 } while ($fiscal_period_start < $last_period_date);
1151
1152 if ($error) {
1153 break;
1154 }
1155 }
1156 }
1157
1158 if ($error) {
1159 $this->db->rollback();
1160 return -1;
1161 } else {
1162 $this->db->commit();
1163 return 1;
1164 }
1165 }
1166
1173 public function setLastCumulativeDepreciation($asset_depreciation_id)
1174 {
1175 global $langs;
1176 $langs->load('assets');
1177
1178 // Clean parameters
1179 $asset_depreciation_id = $asset_depreciation_id > 0 ? $asset_depreciation_id : 0;
1180
1181 // Check parameters
1182 $error = 0;
1183 if (empty($asset_depreciation_id)) {
1184 $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("AssetDepreciation") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
1185 $error++;
1186 }
1187 if ($error) {
1188 return -1;
1189 }
1190
1191 $this->db->begin();
1192
1193 require_once DOL_DOCUMENT_ROOT . '/asset/class/assetdepreciationoptions.class.php';
1194 $options = new AssetDepreciationOptions($this->db);
1195
1196 // Get last depreciation lines save in bookkeeping
1197 //-----------------------------------------------------
1198 $sql = "SELECT fk_asset, depreciation_mode, cumulative_depreciation_ht";
1199 $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation";
1200 $sql .= " WHERE rowid = " . (int) $asset_depreciation_id;
1201 $resql = $this->db->query($sql);
1202 if (!$resql) {
1203 $this->errors[] = $langs->trans('AssetErrorFetchCumulativeDepreciation') . ': ' . $this->db->lasterror();
1204 $error++;
1205 } else {
1206 if ($obj = $this->db->fetch_object($resql)) {
1207 $mode_key = $obj->depreciation_mode;
1208 if (!empty($options->deprecation_options_fields[$mode_key])) {
1209 $sql = "UPDATE " . MAIN_DB_PREFIX . $options->deprecation_options_fields[$mode_key]['table'];
1210 $sql .= " SET total_amount_last_depreciation_ht = " . $obj->cumulative_depreciation_ht;
1211 $sql .= " WHERE fk_asset = " . (int) $obj->fk_asset;
1212 $resql = $this->db->query($sql);
1213 if (!$resql) {
1214 $this->errors[] = $langs->trans('AssetErrorSetLastCumulativeDepreciation') . ': ' . $this->db->lasterror();
1215 $error++;
1216 }
1217 }
1218 }
1219 }
1220
1221 if ($error) {
1222 $this->db->rollback();
1223 return -1;
1224 } else {
1225 $this->db->commit();
1226 return 1;
1227 }
1228 }
1229
1238 public function dispose($user, $disposal_invoice_id, $notrigger = 0)
1239 {
1240 global $conf, $langs;
1241
1242 // Protection
1243 if ($this->status != self::STATUS_DRAFT || $this->status == self::STATUS_DISPOSED) {
1244 return 0;
1245 }
1246
1247 $this->db->begin();
1248
1249 $required_fields = array('disposal_date', 'disposal_date', 'fk_disposal_type');
1250 foreach ($required_fields as $field) {
1251 $this->fields[$field]['notnull'] = 1;
1252 }
1253 $result = $this->update($user, 1);
1254 foreach ($required_fields as $field) {
1255 $this->fields[$field]['notnull'] = 0;
1256 }
1257 if ($result > 0) {
1258 if ($disposal_invoice_id > 0) {
1259 $this->add_object_linked('facture', $disposal_invoice_id);
1260 }
1261 $result = $this->setStatusCommon($user, self::STATUS_DISPOSED, $notrigger, 'ASSET_DISPOSED');
1262 }
1263 if ($result > 0) {
1264 $result = $this->calculationDepreciation();
1265 }
1266
1267 if ($result < 0) {
1268 $this->db->rollback();
1269 } else {
1270 $this->db->commit();
1271 }
1272
1273 // Define output language
1274 if ($result > 0 && !getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
1275 if (method_exists($this, 'generateDocument')) {
1276 global $hidedetails, $hidedesc, $hideref;
1277 $outputlangs = $langs;
1278 $newlang = '';
1279 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
1280 $newlang = GETPOST('lang_id', 'aZ09');
1281 }
1282 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
1283 $newlang = $this->thirdparty->default_lang;
1284 }
1285 if (!empty($newlang)) {
1286 $outputlangs = new Translate("", $conf);
1287 $outputlangs->setDefaultLang($newlang);
1288 }
1289 $model = $this->model_pdf;
1290 $ret = $this->fetch($this->id); // Reload to get new records
1291
1292 $this->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
1293 }
1294 }
1295
1296 return $result;
1297 }
1298
1306 public function reopen($user, $notrigger = 0)
1307 {
1308 global $conf, $langs;
1309
1310 // Protection
1311 if ($this->status != self::STATUS_DISPOSED || $this->status == self::STATUS_DRAFT) {
1312 return 0;
1313 }
1314
1315
1316 $this->db->begin();
1317
1318 $this->disposal_date = null;
1319 $this->disposal_amount_ht = null;
1320 $this->fk_disposal_type = null;
1321 $this->disposal_depreciated = 0;
1322 $this->disposal_subject_to_vat = 0;
1323 $result = $this->update($user, 1);
1324 if ($result > 0) {
1325 $this->deleteObjectLinked(null, 'facture');
1326 $result = $this->setStatusCommon($user, self::STATUS_DRAFT, $notrigger, 'ASSET_REOPEN');
1327 }
1328 if ($result > 0) {
1329 $result = $this->calculationDepreciation();
1330 }
1331
1332 if ($result < 0) {
1333 $this->db->rollback();
1334 } else {
1335 $this->db->commit();
1336 }
1337
1338 // Define output language
1339 if ($result > 0 && !getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
1340 if (method_exists($this, 'generateDocument')) {
1341 global $hidedetails, $hidedesc, $hideref;
1342 $outputlangs = $langs;
1343 $newlang = '';
1344 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
1345 $newlang = GETPOST('lang_id', 'aZ09');
1346 }
1347 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
1348 $newlang = $this->thirdparty->default_lang;
1349 }
1350 if (!empty($newlang)) {
1351 $outputlangs = new Translate("", $conf);
1352 $outputlangs->setDefaultLang($newlang);
1353 }
1354 $model = $this->model_pdf;
1355 $ret = $this->fetch($this->id); // Reload to get new records
1356
1357 $this->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
1358 }
1359 }
1360
1361 return $result;
1362 }
1363
1375 public function getNomUrl($withpicto = 0, $option = '', $maxlen = 0, $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
1376 {
1377 global $db, $conf, $langs, $hookmanager;
1378 global $dolibarr_main_authentication, $dolibarr_main_demo;
1379 global $menumanager;
1380
1381 if (!empty($conf->dol_no_mouse_hover)) {
1382 $notooltip = 1; // Force disable tooltips
1383 }
1384
1385 $result = '';
1386
1387 $label = img_picto('', $this->picto).' <u>'.$langs->trans("Asset").'</u>';
1388 if (isset($this->status)) {
1389 $label .= ' '.$this->getLibStatut(5);
1390 }
1391 $label .= '<br>';
1392 $label .= '<b>'.$langs->trans('Ref').':</b> '.$this->ref;
1393
1394 $url = dol_buildpath('/asset/card.php', 1).'?id='.$this->id;
1395
1396 if ($option != 'nolink') {
1397 // Add param to save lastsearch_values or not
1398 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1399 if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
1400 $add_save_lastsearch_values = 1;
1401 }
1402 if ($add_save_lastsearch_values) {
1403 $url .= '&save_lastsearch_values=1';
1404 }
1405 }
1406
1407 $linkclose = '';
1408 if (empty($notooltip)) {
1409 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
1410 $label = $langs->trans("ShowAsset");
1411 $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
1412 }
1413 $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
1414 $linkclose .= ' class="classfortooltip'.($morecss ? ' '.$morecss : '').'"';
1415 } else {
1416 $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
1417 }
1418
1419 if ($option == 'nolink') {
1420 $linkstart = '<span';
1421 } else {
1422 $linkstart = '<a href="'.$url.'"';
1423 }
1424 $linkstart .= $linkclose.'>';
1425 if ($option == 'nolink') {
1426 $linkend = '</span>';
1427 } else {
1428 $linkend = '</a>';
1429 }
1430
1431 $result .= $linkstart;
1432
1433 if (empty($this->showphoto_on_popup)) {
1434 if ($withpicto) {
1435 $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);
1436 }
1437 } else {
1438 if ($withpicto) {
1439 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1440
1441 list($class, $module) = explode('@', $this->picto);
1442 $upload_dir = $conf->$module->multidir_output[$conf->entity]."/$class/".dol_sanitizeFileName($this->ref);
1443 $filearray = dol_dir_list($upload_dir, "files");
1444 $filename = $filearray[0]['name'];
1445 if (!empty($filename)) {
1446 $pospoint = strpos($filearray[0]['name'], '.');
1447
1448 $pathtophoto = $class.'/'.$this->ref.'/thumbs/'.substr($filename, 0, $pospoint).'_mini'.substr($filename, $pospoint);
1449 if (!getDolGlobalString(strtoupper($module.'_'.$class).'_FORMATLISTPHOTOSASUSERS')) {
1450 $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>';
1451 } else {
1452 $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>';
1453 }
1454
1455 $result .= '</div>';
1456 } else {
1457 $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);
1458 }
1459 }
1460 }
1461
1462 if ($withpicto != 2) {
1463 $name = $this->ref;
1464 if ($option == 'label') {
1465 $name = $this->label;
1466 } elseif ($option == 'with_label') {
1467 $name .= ' - ' . $this->label;
1468 }
1469 $result .= dol_escape_htmltag($maxlen ? dol_trunc($name, $maxlen) : $name);
1470 }
1471
1472 $result .= $linkend;
1473 //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
1474
1475 global $action;
1476 $hookmanager->initHooks(array($this->element . 'dao'));
1477 $parameters = array('id' => $this->id, 'getnomurl' => &$result);
1478 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1479 if ($reshook > 0) {
1480 $result = $hookmanager->resPrint;
1481 } else {
1482 $result .= $hookmanager->resPrint;
1483 }
1484 return $result;
1485 }
1486
1493 public function getLabelStatus($mode = 0)
1494 {
1495 return $this->LibStatut($this->status, $mode);
1496 }
1497
1504 public function getLibStatut($mode = 0)
1505 {
1506 return $this->LibStatut($this->status, $mode);
1507 }
1508
1509 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1517 public function LibStatut($status, $mode = 0)
1518 {
1519 // phpcs:enable
1520 if (empty($this->labelStatus) || empty($this->labelStatusShort)) {
1521 global $langs;
1522 //$langs->load("assets");
1523 $this->labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('AssetInProgress');
1524 $this->labelStatus[self::STATUS_DISPOSED] = $langs->transnoentitiesnoconv('AssetDisposed');
1525 $this->labelStatusShort[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('AssetInProgress');
1526 $this->labelStatusShort[self::STATUS_DISPOSED] = $langs->transnoentitiesnoconv('AssetDisposed');
1527 }
1528
1529 $statusType = 'status4';
1530 if ($status == self::STATUS_DISPOSED) {
1531 $statusType = 'status6';
1532 }
1533
1534 return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode);
1535 }
1536
1543 public function info($id)
1544 {
1545 $sql = "SELECT rowid, date_creation as datec, tms as datem,";
1546 $sql .= " fk_user_creat, fk_user_modif";
1547 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as t";
1548 $sql .= " WHERE t.rowid = ".((int) $id);
1549
1550 $result = $this->db->query($sql);
1551 if ($result) {
1552 if ($this->db->num_rows($result)) {
1553 $obj = $this->db->fetch_object($result);
1554 $this->id = $obj->rowid;
1555
1556 $this->user_creation_id = $obj->fk_user_creat;
1557 $this->user_modification_id = $obj->fk_user_modif;
1558 $this->date_creation = $this->db->jdate($obj->datec);
1559 $this->date_modification = $this->db->jdate($obj->datem);
1560 }
1561
1562 $this->db->free($result);
1563 } else {
1564 dol_print_error($this->db);
1565 }
1566 }
1567
1574 public function initAsSpecimen()
1575 {
1576 // Set here init that are not commonf fields
1577 // $this->property1 = ...
1578 // $this->property2 = ...
1579
1580 return $this->initAsSpecimenCommon();
1581 }
1582
1588 public function getNextNumRef()
1589 {
1590 global $langs, $conf;
1591 $langs->load("assets");
1592
1593 if (!getDolGlobalString('ASSET_ASSET_ADDON')) {
1594 $conf->global->ASSET_ASSET_ADDON = 'mod_asset_standard';
1595 }
1596
1597 if (getDolGlobalString('ASSET_ASSET_ADDON')) {
1598 $mybool = false;
1599
1600 $file = getDolGlobalString('ASSET_ASSET_ADDON') . ".php";
1601 $classname = getDolGlobalString('ASSET_ASSET_ADDON');
1602
1603 // Include file with class
1604 $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
1605 foreach ($dirmodels as $reldir) {
1606 $dir = dol_buildpath($reldir."core/modules/asset/");
1607
1608 // Load file with numbering class (if found)
1609 $mybool = ((bool) @include_once $dir.$file) || $mybool;
1610 }
1611
1612 if (!$mybool) {
1613 dol_print_error(null, "Failed to include file ".$file);
1614 return '';
1615 }
1616
1617 if (class_exists($classname)) {
1618 $obj = new $classname();
1619
1620 '@phan-var-force ModeleNumRefAsset $obj';
1621
1622 $numref = $obj->getNextValue($this);
1623
1624 if ($numref != '' && $numref != '-1') {
1625 return $numref;
1626 } else {
1627 $this->error = $obj->error;
1628 //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error);
1629 return "";
1630 }
1631 } else {
1632 print $langs->trans("Error")." ".$langs->trans("ClassNotFound").' '.$classname;
1633 return "";
1634 }
1635 } else {
1636 print $langs->trans("ErrorNumberingModuleNotSetup", $this->element);
1637 return "";
1638 }
1639 }
1640}
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_object($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
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 '.
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_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
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.
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