dolibarr 21.0.0-alpha
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 $oldcopy;
238
239
243 public $asset_depreciation_options;
247 public $asset_accountancy_codes;
251 public $depreciation_lines = array();
252
258 public function __construct(DoliDB $db)
259 {
260 global $langs;
261
262 $this->db = $db;
263
264 $this->ismultientitymanaged = 1;
265 $this->isextrafieldmanaged = 1;
266
267 if (!getDolGlobalString('MAIN_SHOW_TECHNICAL_ID') && isset($this->fields['rowid'])) {
268 $this->fields['rowid']['visible'] = 0;
269 }
270 if (!isModEnabled('multicompany') && isset($this->fields['entity'])) {
271 $this->fields['entity']['enabled'] = 0;
272 }
273
274 // Unset fields that are disabled
275 foreach ($this->fields as $key => $val) {
276 if (isset($val['enabled']) && empty($val['enabled'])) {
277 unset($this->fields[$key]);
278 }
279 }
280
281 // Translate some data of arrayofkeyval
282 if (is_object($langs)) {
283 foreach ($this->fields as $key => $val) {
284 if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
285 foreach ($val['arrayofkeyval'] as $key2 => $val2) {
286 $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2);
287 }
288 }
289 }
290 }
291 }
292
300 public function create(User $user, $notrigger = 0)
301 {
302 if (!isset($this->date_start) || $this->date_start === "") {
303 $this->date_start = $this->date_acquisition;
304 }
305
306 $this->db->begin();
307
308 $result = $result_create = $this->createCommon($user, $notrigger);
309 if ($result > 0 && $this->fk_asset_model > 0) {
310 $result = $this->setDataFromAssetModel($user, $notrigger);
311 }
312 if ($result > 0) {
313 if ($this->supplier_invoice_id > 0) {
314 $this->add_object_linked('invoice_supplier', $this->supplier_invoice_id);
315 }
316 }
317
318 if ($result < 0) {
319 $this->db->rollback();
320 } else {
321 $this->db->commit();
322 }
323
324 return $result > 0 ? $result_create : $result;
325 }
326
334 public function createFromClone(User $user, $fromid)
335 {
336 global $langs, $extrafields;
337 $error = 0;
338
339 dol_syslog(__METHOD__, LOG_DEBUG);
340
341 // $object = new self($this->db);
342 //
343 // $this->db->begin();
344 //
345 // // Load source object
346 // $result = $object->fetchCommon($fromid);
347 //
348 //
349 // // Reset some properties
350 // unset($object->id);
351 // unset($object->fk_user_creat);
352 // unset($object->import_key);
353 //
354 // // Clear fields
355 // if (property_exists($object, 'ref')) {
356 // $object->ref = empty($this->fields['ref']['default']) ? "Copy_Of_".$object->ref : $this->fields['ref']['default'];
357 // }
358 // if (property_exists($object, 'label')) {
359 // $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf")." ".$object->label : $this->fields['label']['default'];
360 // }
361 // if (property_exists($object, 'status')) {
362 // $object->status = self::STATUS_DRAFT;
363 // }
364 // if (property_exists($object, 'date_creation')) {
365 // $object->date_creation = dol_now();
366 // }
367 // if (property_exists($object, 'date_modification')) {
368 // $object->date_modification = null;
369 // }
370 // // ...
371 // // Clear extrafields that are unique
372 // if (is_array($object->array_options) && count($object->array_options) > 0) {
373 // $extrafields->fetch_name_optionals_label($this->table_element);
374 // foreach ($object->array_options as $key => $option) {
375 // $shortkey = preg_replace('/options_/', '', $key);
376 // if (!empty($extrafields->attributes[$this->table_element]['unique'][$shortkey])) {
377 // //var_dump($key); var_dump($clonedObj->array_options[$key]); exit;
378 // unset($object->array_options[$key]);
379 // }
380 // }
381 // }
382 //
383 // // Create clone
384 // $object->context['createfromclone'] = 'createfromclone';
385 // $result = $object->createCommon($user);
386 // if ($result < 0) {
387 // $error++;
388 // $this->error = $object->error;
389 // $this->errors = $object->errors;
390 // }
391 //
392 // if (!$error) {
393 // // copy internal contacts
394 // if ($this->copy_linked_contact($object, 'internal') < 0) {
395 // $error++;
396 // }
397 // }
398 //
399 // if (!$error) {
400 // // copy external contacts if same company
401 // if (property_exists($this, 'fk_soc') && $this->fk_soc == $object->socid) {
402 // if ($this->copy_linked_contact($object, 'external') < 0) {
403 // $error++;
404 // }
405 // }
406 // }
407 //
408 // unset($object->context['createfromclone']);
409 //
410 // // End
411 // if (!$error) {
412 // $this->db->commit();
413 // return $object;
414 // } else {
415 // $this->db->rollback();
416 // return -1;
417 // }
418
419 return -1;
420 }
421
429 public function fetch($id, $ref = null)
430 {
431 $result = $this->fetchCommon($id, $ref);
432 if ($result > 0) {
433 $res = $this->hasDepreciationLinesInBookkeeping();
434 if ($res < 0) {
435 return -1;
436 } elseif ($res > 0) {
437 $this->fields['date_acquisition']['noteditable'] = '1';
438 $this->fields['date_start']['noteditable'] = '1';
439 $this->fields['acquisition_value_ht']['noteditable'] = '1';
440 $this->fields['recovered_vat']['noteditable'] = '1';
441 $this->fields['reversal_date']['noteditable'] = '1';
442 $this->fields['reversal_amount_ht']['noteditable'] = '1';
443 }
444 }
445
446 return $result;
447 }
448
449
462 public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, $filter = '', $filtermode = 'AND')
463 {
464 dol_syslog(__METHOD__, LOG_DEBUG);
465
466 $records = array();
467
468 $sql = "SELECT ";
469 $sql .= $this->getFieldList('t');
470 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as t";
471 if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
472 $sql .= " WHERE t.entity IN (".getEntity($this->element).")";
473 } else {
474 $sql .= " WHERE 1 = 1";
475 }
476
477 // Manage filter
478 $errormessage = '';
479 $sql .= forgeSQLFromUniversalSearchCriteria($filter, $errormessage);
480 if ($errormessage) {
481 $this->errors[] = $errormessage;
482 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
483
484 return -1;
485 }
486
487 if (!empty($sortfield)) {
488 $sql .= $this->db->order($sortfield, $sortorder);
489 }
490 if (!empty($limit)) {
491 $sql .= $this->db->plimit($limit, $offset);
492 }
493
494 $resql = $this->db->query($sql);
495 if ($resql) {
496 $num = $this->db->num_rows($resql);
497 $i = 0;
498 while ($i < ($limit ? min($limit, $num) : $num)) {
499 $obj = $this->db->fetch_object($resql);
500
501 $record = new self($this->db);
502 $record->setVarsFromFetchObj($obj);
503
504 $records[$record->id] = $record;
505
506 $i++;
507 }
508 $this->db->free($resql);
509
510 return $records;
511 } else {
512 $this->errors[] = 'Error '.$this->db->lasterror();
513 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
514
515 return -1;
516 }
517 }
518
526 public function update(User $user, $notrigger = 0)
527 {
528 if (!isset($this->date_start) || $this->date_start === "") {
529 $this->date_start = $this->date_acquisition;
530 }
531
532 $this->db->begin();
533
534 $result = $this->updateCommon($user, $notrigger);
535 if ($result > 0 && $this->fk_asset_model > 0 && $this->fk_asset_model != $this->oldcopy->fk_asset_model) {
536 $result = $this->setDataFromAssetModel($user, $notrigger);
537 }
538 if ($result > 0 && (
539 $this->date_start != $this->oldcopy->date_start ||
540 $this->acquisition_value_ht != $this->oldcopy->acquisition_value_ht ||
541 $this->reversal_date != $this->oldcopy->reversal_date ||
542 $this->reversal_amount_ht != $this->oldcopy->reversal_amount_ht ||
543 ($this->fk_asset_model > 0 && $this->fk_asset_model != $this->oldcopy->fk_asset_model)
544 )
545 ) {
546 $result = $this->calculationDepreciation();
547 }
548
549 if ($result < 0) {
550 $this->db->rollback();
551 } else {
552 $this->db->commit();
553 }
554
555 return $result;
556 }
557
565 public function delete(User $user, $notrigger = 0)
566 {
567 return $this->deleteCommon($user, $notrigger);
568 //return $this->deleteCommon($user, $notrigger, 1);
569 }
570
578 public function setDataFromAssetModel(User $user, $notrigger = 0)
579 {
580 global $langs;
581 $langs->load('assets');
582
583 // Clean parameters
584 $this->id = $this->id > 0 ? $this->id : 0;
585 $this->fk_asset_model = $this->fk_asset_model > 0 ? $this->fk_asset_model : 0;
586
587 // Check parameters
588 $error = 0;
589 if (empty($this->id)) {
590 $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Asset") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
591 $error++;
592 }
593 if (empty($this->fk_asset_model)) {
594 $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("AssetModel") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
595 $error++;
596 }
597 if ($error) {
598 return -1;
599 }
600
601 $this->db->begin();
602
603 // Get depreciation options
604 //---------------------------
605 require_once DOL_DOCUMENT_ROOT . '/asset/class/assetdepreciationoptions.class.php';
606 $options_model = new AssetDepreciationOptions($this->db);
607 $result = $options_model->fetchDeprecationOptions(0, $this->fk_asset_model);
608 if ($result < 0) {
609 $this->error = $options_model->error;
610 $this->errors = $options_model->errors;
611 $error++;
612 } elseif ($result > 0) {
613 $options = new AssetDepreciationOptions($this->db);
614 $result = $options->fetchDeprecationOptions($this->id);
615 if ($result < 0) {
616 $this->error = $options->error;
617 $this->errors = $options->errors;
618 $error++;
619 }
620
621 if (!$error) {
622 foreach ($options_model->deprecation_options as $mode_key => $fields) {
623 foreach ($fields as $field_key => $value) {
624 $options->deprecation_options[$mode_key][$field_key] = $value;
625 }
626 }
627
628 $result = $options->updateDeprecationOptions($user, $this->id, 0, $notrigger);
629 if ($result < 0) {
630 $this->error = $options->error;
631 $this->errors = $options->errors;
632 $error++;
633 }
634 }
635 }
636
637 // Get accountancy codes
638 //---------------------------
639 if (!$error) {
640 require_once DOL_DOCUMENT_ROOT . '/asset/class/assetaccountancycodes.class.php';
641 $accountancy_codes_model = new AssetAccountancyCodes($this->db);
642 $result = $accountancy_codes_model->fetchAccountancyCodes(0, $this->fk_asset_model);
643 if ($result < 0) {
644 $this->error = $accountancy_codes_model->error;
645 $this->errors = $accountancy_codes_model->errors;
646 $error++;
647 } elseif ($result > 0) {
648 $accountancy_codes = new AssetAccountancyCodes($this->db);
649 $result = $accountancy_codes->fetchAccountancyCodes($this->id);
650 if ($result < 0) {
651 $this->error = $accountancy_codes->error;
652 $this->errors = $accountancy_codes->errors;
653 $error++;
654 }
655
656 if (!$error) {
657 foreach ($accountancy_codes_model->accountancy_codes as $mode_key => $fields) {
658 foreach ($fields as $field_key => $value) {
659 $accountancy_codes->accountancy_codes[$mode_key][$field_key] = $value;
660 }
661 }
662
663 $result = $accountancy_codes->updateAccountancyCodes($user, $this->id, 0, $notrigger);
664 if ($result < 0) {
665 $this->error = $accountancy_codes->error;
666 $this->errors = $accountancy_codes->errors;
667 $error++;
668 }
669 }
670 }
671 }
672
673 if ($error) {
674 $this->db->rollback();
675 return -1;
676 } else {
677 $this->db->commit();
678 return 1;
679 }
680 }
681
687 public function fetchDepreciationLines()
688 {
689 global $langs;
690 $langs->load('assets');
691 $this->depreciation_lines = array();
692
693 // Clean parameters
694 $this->id = $this->id > 0 ? $this->id : 0;
695
696 // Check parameters
697 $error = 0;
698 if (empty($this->id)) {
699 $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Asset") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
700 $error++;
701 }
702 if ($error) {
703 return -1;
704 }
705
706 // Old request with 'WITH'
707 /*
708 $sql = "WITH in_accounting_bookkeeping(fk_docdet) AS (";
709 $sql .= " SELECT DISTINCT fk_docdet";
710 $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping";
711 $sql .= " WHERE doc_type = 'asset'";
712 $sql .= ")";
713 $sql .= "SELECT ad.rowid, ad.depreciation_mode, ad.ref, ad.depreciation_date, ad.depreciation_ht, ad.cumulative_depreciation_ht";
714 $sql .= ", " . $this->db->ifsql('iab.fk_docdet IS NOT NULL', 1, 0) . " AS bookkeeping";
715 $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
716 $sql .= " LEFT JOIN in_accounting_bookkeeping as iab ON iab.fk_docdet = ad.rowid";
717 $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
718 $sql .= " ORDER BY ad.depreciation_date ASC";
719 */
720
721 $sql = "SELECT ad.rowid, ad.depreciation_mode, ad.ref, ad.depreciation_date, ad.depreciation_ht, ad.cumulative_depreciation_ht";
722 $sql .= ", " . $this->db->ifsql('iab.fk_docdet IS NOT NULL', 1, 0) . " AS bookkeeping";
723 $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
724 $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";
725 $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
726 $sql .= " ORDER BY ad.depreciation_date ASC";
727
728 $resql = $this->db->query($sql);
729 if (!$resql) {
730 $this->errors[] = $langs->trans('AssetErrorFetchDepreciationLines') . ': ' . $this->db->lasterror();
731 return -1;
732 }
733
734 while ($obj = $this->db->fetch_object($resql)) {
735 if (!isset($this->depreciation_lines[$obj->depreciation_mode])) {
736 $this->depreciation_lines[$obj->depreciation_mode] = array();
737 }
738 $this->depreciation_lines[$obj->depreciation_mode][] = array(
739 'id' => $obj->rowid,
740 'ref' => $obj->ref,
741 'depreciation_date' => $this->db->jdate($obj->depreciation_date),
742 'depreciation_ht' => $obj->depreciation_ht,
743 'cumulative_depreciation_ht' => $obj->cumulative_depreciation_ht,
744 'bookkeeping' => $obj->bookkeeping,
745 );
746 }
747
748 return 1;
749 }
750
757 {
758 global $langs;
759 $langs->load('assets');
760
761 // Clean parameters
762 $this->id = $this->id > 0 ? $this->id : 0;
763
764 // Check parameters
765 $error = 0;
766 if (empty($this->id)) {
767 $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Asset") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
768 $error++;
769 }
770 if ($error) {
771 return -1;
772 }
773
774 // Old request with 'WITH'
775 /*
776 $sql = "WITH in_accounting_bookkeeping(fk_docdet) AS (";
777 $sql .= " SELECT DISTINCT fk_docdet";
778 $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping";
779 $sql .= " WHERE doc_type = 'asset'";
780 $sql .= ")";
781 $sql .= "SELECT COUNT(*) AS has_bookkeeping";
782 $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
783 $sql .= " LEFT JOIN in_accounting_bookkeeping as iab ON iab.fk_docdet = ad.rowid";
784 $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
785 $sql .= " AND iab.fk_docdet IS NOT NULL";
786 */
787
788 $sql = "SELECT COUNT(*) AS has_bookkeeping";
789 $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
790 $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";
791 $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
792 $sql .= " AND iab.fk_docdet IS NOT NULL";
793
794 $resql = $this->db->query($sql);
795 if (!$resql) {
796 $this->errors[] = $langs->trans('AssetErrorFetchDepreciationLines') . ': ' . $this->db->lasterror();
797 return -1;
798 }
799
800 if ($obj = $this->db->fetch_object($resql)) {
801 return $obj->has_bookkeeping > 0 ? 1 : 0;
802 }
803
804 return 0;
805 }
806
819 public function addDepreciationLine($mode, $ref, $depreciation_date, $depreciation_ht, $cumulative_depreciation_ht, $accountancy_code_debit, $accountancy_code_credit)
820 {
821 global $langs;
822 $langs->load('assets');
823
824 // Clean parameters
825 $this->id = $this->id > 0 ? $this->id : 0;
826 $mode = strtolower(trim($mode));
827 $ref = trim($ref);
828 $accountancy_code_debit = trim($accountancy_code_debit);
829 $accountancy_code_credit = trim($accountancy_code_credit);
830
831 // Check parameters
832 $error = 0;
833 if (empty($this->id)) {
834 $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Asset") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
835 $error++;
836 }
837 if ($error) {
838 return -1;
839 }
840
841 $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)";
842 $sql .= " VALUES ( ";
843 $sql .= " " . (int) $this->id;
844 $sql .= ", '" . $this->db->escape($mode) . "'";
845 $sql .= ", '" . $this->db->escape($ref) . "'";
846 $sql .= ", '" . $this->db->idate($depreciation_date) . "'";
847 $sql .= ", " . (float) $depreciation_ht;
848 $sql .= ", " . (float) $cumulative_depreciation_ht;
849 $sql .= ", '" . $this->db->escape($accountancy_code_debit) . "'";
850 $sql .= ", '" . $this->db->escape($accountancy_code_credit) . "'";
851 $sql .= ")";
852
853 $resql = $this->db->query($sql);
854 if (!$resql) {
855 $this->errors[] = $langs->trans('AssetErrorAddDepreciationLine') . ': ' . $this->db->lasterror();
856 return -1;
857 }
858
859 return 1;
860 }
861
867 public function calculationDepreciation()
868 {
869 global $conf, $langs;
870 $langs->load('assets');
871
872 // Clean parameters
873 $this->id = $this->id > 0 ? $this->id : 0;
874
875 // Check parameters
876 $error = 0;
877 if (empty($this->id)) {
878 $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Asset") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
879 $error++;
880 }
881 if ($error) {
882 return -1;
883 }
884
885 // Get depreciation options
886 //---------------------------
887 require_once DOL_DOCUMENT_ROOT . '/asset/class/assetdepreciationoptions.class.php';
888 $options = new AssetDepreciationOptions($this->db);
889 $result = $options->fetchDeprecationOptions($this->id);
890 if ($result < 0) {
891 $this->error = $options->error;
892 $this->errors = $options->errors;
893 return -1;
894 }
895
896 // Get accountancy codes
897 //---------------------------
898 require_once DOL_DOCUMENT_ROOT . '/asset/class/assetaccountancycodes.class.php';
899 $accountancy_codes = new AssetAccountancyCodes($this->db);
900 $result = $accountancy_codes->fetchAccountancyCodes($this->id);
901 if ($result < 0) {
902 $this->error = $accountancy_codes->error;
903 $this->errors = $accountancy_codes->errors;
904 return -1;
905 }
906
907 $this->db->begin();
908
909 // Delete old lines
910 $modes = array();
911 foreach ($options->deprecation_options as $mode_key => $fields) {
912 $modes[$mode_key] = $this->db->escape($mode_key);
913 }
914 $sql = "DELETE FROM " . MAIN_DB_PREFIX . "asset_depreciation";
915 $sql .= " WHERE fk_asset = " . (int) $this->id;
916 $sql .= " AND depreciation_mode NOT IN ('" . $this->db->sanitize(implode("', '", $modes)) . "')";
917
918 $resql = $this->db->query($sql);
919 if (!$resql) {
920 $this->errors[] = $langs->trans('AssetErrorClearDepreciationLines') . ': ' . $this->db->lasterror();
921 $error++;
922 }
923
924 if (!$error) {
925 // Get fiscal period
926 require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
927 require_once DOL_DOCUMENT_ROOT . '/core/lib/accounting.lib.php';
928 // @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.
929 $dates = getCurrentPeriodOfFiscalYear($this->db, $conf, $this->date_start > $this->date_acquisition ? $this->date_start : $this->date_acquisition);
930 $init_fiscal_period_start = $dates['date_start'];
931 $init_fiscal_period_end = $dates['date_end'];
932 if (empty($init_fiscal_period_start) || empty($init_fiscal_period_end)) {
933 $pastmonthyear = $dates['pastmonthyear'];
934 $pastmonth = $dates['pastmonth'];
935 $init_fiscal_period_start = dol_get_first_day($pastmonthyear, $pastmonth, false);
936 $init_fiscal_period_end = dol_get_last_day($pastmonthyear, $pastmonth, false);
937 }
938
939 foreach ($options->deprecation_options as $mode_key => $fields) {
940 // Get last depreciation lines save in bookkeeping
941 //-----------------------------------------------------
942
943 // Old request with 'WITH'
944 /*
945 $sql = "WITH in_accounting_bookkeeping(fk_docdet) AS (";
946 $sql .= " SELECT fk_docdet";
947 $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping";
948 $sql .= " WHERE doc_type = 'asset'";
949 $sql .= ")";
950 $sql .= "SELECT ad.depreciation_date, ad.cumulative_depreciation_ht";
951 $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
952 $sql .= " LEFT JOIN in_accounting_bookkeeping as iab ON iab.fk_docdet = ad.rowid";
953 $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
954 $sql .= " AND ad.depreciation_mode = '" . $this->db->escape($mode_key) . "'";
955 $sql .= " AND iab.fk_docdet IS NOT NULL";
956 $sql .= " ORDER BY ad.depreciation_date DESC";
957 $sql .= " LIMIT 1";
958 */
959
960 $sql = "SELECT ad.depreciation_date, ad.cumulative_depreciation_ht";
961 $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
962 $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";
963 $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
964 $sql .= " AND ad.depreciation_mode = '" . $this->db->escape($mode_key) . "'";
965 $sql .= " AND iab.fk_docdet IS NOT NULL";
966 $sql .= " ORDER BY ad.depreciation_date DESC";
967 $sql .= " LIMIT 1";
968
969 $resql = $this->db->query($sql);
970 if (!$resql) {
971 $this->errors[] = $langs->trans('AssetErrorFetchMaxDepreciationDateForMode', $mode_key) . ': ' . $this->db->lasterror();
972 $error++;
973 break;
974 }
975 $last_depreciation_date = '';
976 $last_cumulative_depreciation_ht = $this->reversal_amount_ht;
977 if ($obj = $this->db->fetch_object($resql)) {
978 $last_depreciation_date = $this->db->jdate($obj->depreciation_date);
979 $last_cumulative_depreciation_ht = $obj->cumulative_depreciation_ht;
980 }
981
982 // Set last cumulative depreciation
983 $sql = "UPDATE " . MAIN_DB_PREFIX . $options->deprecation_options_fields[$mode_key]['table'];
984 $sql .= " SET total_amount_last_depreciation_ht = " . (empty($last_cumulative_depreciation_ht) ? 0 : $last_cumulative_depreciation_ht);
985 $sql .= " WHERE fk_asset = " . (int) $this->id;
986 $resql = $this->db->query($sql);
987 if (!$resql) {
988 $this->errors[] = $langs->trans('AssetErrorSetLastCumulativeDepreciation') . ': ' . $this->db->lasterror();
989 $error++;
990 break;
991 }
992
993 // Delete old lines
994 $sql = "DELETE " . MAIN_DB_PREFIX . "asset_depreciation FROM " . MAIN_DB_PREFIX . "asset_depreciation";
995 $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";
996 $sql .= " WHERE " . MAIN_DB_PREFIX . "asset_depreciation.fk_asset = " . (int) $this->id;
997 $sql .= " AND " . MAIN_DB_PREFIX . "asset_depreciation.depreciation_mode = '" . $this->db->escape($mode_key) . "'";
998 $sql .= " AND ab.fk_docdet IS NULL";
999 if ($last_depreciation_date !== "") {
1000 $sql .= " AND " . MAIN_DB_PREFIX . "asset_depreciation.ref != ''";
1001 }
1002 $resql = $this->db->query($sql);
1003 if (!$resql) {
1004 $this->errors[] = $langs->trans('AssetErrorClearDepreciationLines') . ': ' . $this->db->lasterror();
1005 $error++;
1006 break;
1007 }
1008
1009 // Get depreciation period
1010 $depreciation_date_start = $this->date_start > $this->date_acquisition ? $this->date_start : $this->date_acquisition;
1011 $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');
1012 $depreciation_amount = $fields['amount_base_depreciation_ht'];
1013 if ($fields['duration_type'] == 2) { // Daily
1014 $fiscal_period_start = $depreciation_date_start;
1015 $fiscal_period_end = $depreciation_date_start;
1016 } elseif ($fields['duration_type'] == 1) { // Monthly
1017 $date_temp = dol_getdate((int) $depreciation_date_start);
1018 $fiscal_period_start = dol_get_first_day($date_temp['year'], $date_temp['mon'], false);
1019 $fiscal_period_end = dol_get_last_day($date_temp['year'], $date_temp['mon'], false);
1020 } else { // Annually
1021 $fiscal_period_start = $init_fiscal_period_start;
1022 $fiscal_period_end = $init_fiscal_period_end;
1023 }
1024 $cumulative_depreciation_ht = (float) $last_cumulative_depreciation_ht;
1025 $depreciation_period_amount = $depreciation_amount - (float) $this->reversal_amount_ht;
1026 $start_date = $depreciation_date_start;
1027 $disposal_date = isset($this->disposal_date) && $this->disposal_date !== "" ? $this->disposal_date : "";
1028 $finish_date = $disposal_date !== "" ? $disposal_date : $depreciation_date_end;
1029 $accountancy_code_depreciation_debit_key = $accountancy_codes->accountancy_codes_fields[$mode_key]['depreciation_debit'];
1030 $accountancy_code_depreciation_debit = $accountancy_codes->accountancy_codes[$mode_key][$accountancy_code_depreciation_debit_key];
1031 $accountancy_code_depreciation_credit_key = $accountancy_codes->accountancy_codes_fields[$mode_key]['depreciation_credit'];
1032 $accountancy_code_credit = $accountancy_codes->accountancy_codes[$mode_key][$accountancy_code_depreciation_credit_key];
1033
1034 // Reversal depreciation line
1035 //-----------------------------------------------------
1036 if ($last_depreciation_date === "" && ($depreciation_date_start < $fiscal_period_start || is_numeric($this->reversal_date))) {
1037 if (is_numeric($this->reversal_date)) {
1038 if ($this->reversal_date < $fiscal_period_start) {
1039 $this->errors[] = $langs->trans('AssetErrorReversalDateNotGreaterThanCurrentBeginFiscalDateForMode', $mode_key);
1040 $error++;
1041 break;
1042 }
1043
1044 if (empty($this->reversal_amount_ht)) {
1045 $this->errors[] = $langs->trans('AssetErrorReversalAmountNotProvidedForMode', $mode_key);
1046 $error++;
1047 break;
1048 }
1049
1050 $start_date = $this->reversal_date;
1051 $result = $this->addDepreciationLine($mode_key, '', $start_date, $this->reversal_amount_ht, $this->reversal_amount_ht, $accountancy_code_depreciation_debit, $accountancy_code_credit);
1052 if ($result < 0) {
1053 $error++;
1054 break;
1055 }
1056 } else {
1057 $this->errors[] = $langs->trans('AssetErrorReversalDateNotProvidedForMode', $mode_key);
1058 $error++;
1059 break;
1060 }
1061 }
1062
1063 // futures depreciation lines
1064 //-----------------------------------------------------
1065 $nb_days_in_year = getDolGlobalInt('ASSET_DEPRECIATION_DURATION_PER_YEAR', 360);
1066 $nb_days_in_month = getDolGlobalInt('ASSET_DEPRECIATION_DURATION_PER_MONTH', 30);
1067 $period_amount = (float) price2num($depreciation_period_amount / $fields['duration'], 'MT');
1068 $first_period_found = false;
1069 // TODO fix declaration of $begin_period
1070 $first_period_date = isset($begin_period) && $begin_period > $fiscal_period_start ? $begin_period : $fiscal_period_start;
1071
1072 $ref_date_format = "%Y" . ($fields['duration_type'] == 1 || $fields['duration_type'] == 2 ? '-%m' : '') . ($fields['duration_type'] == 2 ? '-%d' : '');
1073
1074 // Loop security
1075 $idx_loop = 0;
1076 $max_loop = $fields['duration'] + 2;
1077 do {
1078 // Loop security
1079 $idx_loop++;
1080 if ($idx_loop > $max_loop) {
1081 break;
1082 }
1083
1084 if ($last_depreciation_date < $fiscal_period_end && ($first_period_date <= $start_date || $first_period_found)) {
1085 // Disposal not depreciated
1086 if ($fiscal_period_start <= $disposal_date && $disposal_date <= $fiscal_period_end && empty($this->disposal_depreciated)) {
1087 break;
1088 }
1089
1090 $first_period_found = true;
1091
1092 $period_begin = dol_print_date($fiscal_period_start, $ref_date_format);
1093 $period_end = dol_print_date($fiscal_period_end, $ref_date_format);
1094 $ref = $period_begin . ($period_begin != $period_end ? ' - ' . $period_end : '');
1095 if ($fiscal_period_start <= $disposal_date && $disposal_date <= $fiscal_period_end) {
1096 $ref .= ' - ' . $langs->transnoentitiesnoconv('AssetDisposal');
1097 }
1098
1099 $begin_date = $fiscal_period_start < $start_date && $start_date <= $fiscal_period_end ? $start_date : $fiscal_period_start;
1100 $end_date = $fiscal_period_start < $finish_date && $finish_date <= $fiscal_period_end ? $finish_date : $fiscal_period_end;
1101 if ($fields['duration_type'] == 2) { // Daily
1102 $depreciation_ht = $period_amount;
1103 } elseif ($fields['duration_type'] == 1) { // Monthly
1104 $nb_days = min($nb_days_in_month, num_between_day($begin_date, $end_date, 1));
1105 if ($nb_days >= 28) {
1106 $date_temp = dol_getdate($begin_date);
1107 if ($date_temp['mon'] == 2) {
1108 $nb_days = 30;
1109 }
1110 }
1111 $depreciation_ht = (float) price2num($period_amount * $nb_days / $nb_days_in_month, 'MT');
1112 } else { // Annually, taking care for adjustments to shortened or extended periods (e.g., fiscal years of 9 or 15 months)
1113 $nb_days_real = num_between_day($begin_date, $end_date, 1);
1114 if (($nb_days_real > 366) || (num_between_day($fiscal_period_start, $fiscal_period_end, 1) < $nb_days_in_year)) { // FY Period changed
1115 $nb_days = $nb_days_real;
1116 } else {
1117 $nb_days = min($nb_days_in_year, $nb_days_real);
1118 }
1119 $depreciation_ht = (double) price2num($period_amount * $nb_days / $nb_days_in_year, 'MT');
1120 }
1121 if (getDolGlobalInt('ASSET_ROUND_INTEGER_NUMBER_UPWARDS') == 1) {
1122 if ($idx_loop < $max_loop) { // avoid last depreciation value
1123 $depreciation_ht = ceil($depreciation_ht);
1124 }
1125 }
1126
1127 if ($fiscal_period_start <= $depreciation_date_end && $depreciation_date_end <= $fiscal_period_end) { // last period
1128 $depreciation_ht = (float) price2num($depreciation_amount - (float) $cumulative_depreciation_ht, 'MT');
1129 $cumulative_depreciation_ht = $depreciation_amount;
1130 } else {
1131 $cumulative_depreciation_ht += $depreciation_ht;
1132 }
1133
1134 $result = $this->addDepreciationLine($mode_key, $ref, $fiscal_period_end, $depreciation_ht, $cumulative_depreciation_ht, $accountancy_code_depreciation_debit, $accountancy_code_credit);
1135 if ($result < 0) {
1136 $error++;
1137 break;
1138 }
1139 }
1140
1141 // Next fiscal period (+1 day/month/year)
1142 $fiscal_period_start = dol_time_plus_duree($fiscal_period_end, 1, 'd');
1143 $dates_fiscal_period = getCurrentPeriodOfFiscalYear($this->db, $conf, $fiscal_period_start, 'gmt');
1144 if ($fields['duration_type'] == 2) { // Daily
1145 $fiscal_period_end = $fiscal_period_start;
1146 } elseif ($fields['duration_type'] == 1) { // Monthly
1147 $fiscal_period_end = dol_time_plus_duree(dol_time_plus_duree($fiscal_period_start, 1, 'm'), -1, 'd');
1148 } else { // Annually
1149 $fiscal_period_end = $dates_fiscal_period['date_end'];
1150 }
1151 $last_period_date = $disposal_date !== "" && $disposal_date < $depreciation_date_end ? $disposal_date : $depreciation_date_end;
1152 } while ($fiscal_period_start < $last_period_date);
1153
1154 if ($error) {
1155 break;
1156 }
1157 }
1158 }
1159
1160 if ($error) {
1161 $this->db->rollback();
1162 return -1;
1163 } else {
1164 $this->db->commit();
1165 return 1;
1166 }
1167 }
1168
1175 public function setLastCumulativeDepreciation($asset_depreciation_id)
1176 {
1177 global $langs;
1178 $langs->load('assets');
1179
1180 // Clean parameters
1181 $asset_depreciation_id = $asset_depreciation_id > 0 ? $asset_depreciation_id : 0;
1182
1183 // Check parameters
1184 $error = 0;
1185 if (empty($asset_depreciation_id)) {
1186 $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("AssetDepreciation") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
1187 $error++;
1188 }
1189 if ($error) {
1190 return -1;
1191 }
1192
1193 $this->db->begin();
1194
1195 require_once DOL_DOCUMENT_ROOT . '/asset/class/assetdepreciationoptions.class.php';
1196 $options = new AssetDepreciationOptions($this->db);
1197
1198 // Get last depreciation lines save in bookkeeping
1199 //-----------------------------------------------------
1200 $sql = "SELECT fk_asset, depreciation_mode, cumulative_depreciation_ht";
1201 $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation";
1202 $sql .= " WHERE rowid = " . (int) $asset_depreciation_id;
1203 $resql = $this->db->query($sql);
1204 if (!$resql) {
1205 $this->errors[] = $langs->trans('AssetErrorFetchCumulativeDepreciation') . ': ' . $this->db->lasterror();
1206 $error++;
1207 } else {
1208 if ($obj = $this->db->fetch_object($resql)) {
1209 $mode_key = $obj->depreciation_mode;
1210 if (!empty($options->deprecation_options_fields[$mode_key])) {
1211 $sql = "UPDATE " . MAIN_DB_PREFIX . $options->deprecation_options_fields[$mode_key]['table'];
1212 $sql .= " SET total_amount_last_depreciation_ht = " . $obj->cumulative_depreciation_ht;
1213 $sql .= " WHERE fk_asset = " . (int) $obj->fk_asset;
1214 $resql = $this->db->query($sql);
1215 if (!$resql) {
1216 $this->errors[] = $langs->trans('AssetErrorSetLastCumulativeDepreciation') . ': ' . $this->db->lasterror();
1217 $error++;
1218 }
1219 }
1220 }
1221 }
1222
1223 if ($error) {
1224 $this->db->rollback();
1225 return -1;
1226 } else {
1227 $this->db->commit();
1228 return 1;
1229 }
1230 }
1231
1240 public function dispose($user, $disposal_invoice_id, $notrigger = 0)
1241 {
1242 global $conf, $langs;
1243
1244 // Protection
1245 if ($this->status != self::STATUS_DRAFT || $this->status == self::STATUS_DISPOSED) {
1246 return 0;
1247 }
1248
1249 $this->db->begin();
1250
1251 $required_fields = array('disposal_date', 'disposal_date', 'fk_disposal_type');
1252 foreach ($required_fields as $field) {
1253 $this->fields[$field]['notnull'] = 1;
1254 }
1255 $result = $this->update($user, 1);
1256 foreach ($required_fields as $field) {
1257 $this->fields[$field]['notnull'] = 0;
1258 }
1259 if ($result > 0) {
1260 if ($disposal_invoice_id > 0) {
1261 $this->add_object_linked('facture', $disposal_invoice_id);
1262 }
1263 $result = $this->setStatusCommon($user, self::STATUS_DISPOSED, $notrigger, 'ASSET_DISPOSED');
1264 }
1265 if ($result > 0) {
1266 $result = $this->calculationDepreciation();
1267 }
1268
1269 if ($result < 0) {
1270 $this->db->rollback();
1271 } else {
1272 $this->db->commit();
1273 }
1274
1275 // Define output language
1276 if ($result > 0 && !getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
1277 if (method_exists($this, 'generateDocument')) {
1278 global $hidedetails, $hidedesc, $hideref;
1279 $outputlangs = $langs;
1280 $newlang = '';
1281 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
1282 $newlang = GETPOST('lang_id', 'aZ09');
1283 }
1284 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
1285 $newlang = $this->thirdparty->default_lang;
1286 }
1287 if (!empty($newlang)) {
1288 $outputlangs = new Translate("", $conf);
1289 $outputlangs->setDefaultLang($newlang);
1290 }
1291 $model = $this->model_pdf;
1292 $ret = $this->fetch($this->id); // Reload to get new records
1293
1294 $this->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
1295 }
1296 }
1297
1298 return $result;
1299 }
1300
1308 public function reopen($user, $notrigger = 0)
1309 {
1310 global $conf, $langs;
1311
1312 // Protection
1313 if ($this->status != self::STATUS_DISPOSED || $this->status == self::STATUS_DRAFT) {
1314 return 0;
1315 }
1316
1317
1318 $this->db->begin();
1319
1320 $this->disposal_date = null;
1321 $this->disposal_amount_ht = null;
1322 $this->fk_disposal_type = null;
1323 $this->disposal_depreciated = 0;
1324 $this->disposal_subject_to_vat = 0;
1325 $result = $this->update($user, 1);
1326 if ($result > 0) {
1327 $this->deleteObjectLinked(null, 'facture');
1328 $result = $this->setStatusCommon($user, self::STATUS_DRAFT, $notrigger, 'ASSET_REOPEN');
1329 }
1330 if ($result > 0) {
1331 $result = $this->calculationDepreciation();
1332 }
1333
1334 if ($result < 0) {
1335 $this->db->rollback();
1336 } else {
1337 $this->db->commit();
1338 }
1339
1340 // Define output language
1341 if ($result > 0 && !getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
1342 if (method_exists($this, 'generateDocument')) {
1343 global $hidedetails, $hidedesc, $hideref;
1344 $outputlangs = $langs;
1345 $newlang = '';
1346 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
1347 $newlang = GETPOST('lang_id', 'aZ09');
1348 }
1349 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
1350 $newlang = $this->thirdparty->default_lang;
1351 }
1352 if (!empty($newlang)) {
1353 $outputlangs = new Translate("", $conf);
1354 $outputlangs->setDefaultLang($newlang);
1355 }
1356 $model = $this->model_pdf;
1357 $ret = $this->fetch($this->id); // Reload to get new records
1358
1359 $this->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
1360 }
1361 }
1362
1363 return $result;
1364 }
1365
1377 public function getNomUrl($withpicto = 0, $option = '', $maxlen = 0, $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
1378 {
1379 global $db, $conf, $langs, $hookmanager;
1380 global $dolibarr_main_authentication, $dolibarr_main_demo;
1381 global $menumanager;
1382
1383 if (!empty($conf->dol_no_mouse_hover)) {
1384 $notooltip = 1; // Force disable tooltips
1385 }
1386
1387 $result = '';
1388
1389 $label = img_picto('', $this->picto).' <u>'.$langs->trans("Asset").'</u>';
1390 if (isset($this->status)) {
1391 $label .= ' '.$this->getLibStatut(5);
1392 }
1393 $label .= '<br>';
1394 $label .= '<b>'.$langs->trans('Ref').':</b> '.$this->ref;
1395
1396 $url = dol_buildpath('/asset/card.php', 1).'?id='.$this->id;
1397
1398 if ($option != 'nolink') {
1399 // Add param to save lastsearch_values or not
1400 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1401 if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
1402 $add_save_lastsearch_values = 1;
1403 }
1404 if ($add_save_lastsearch_values) {
1405 $url .= '&save_lastsearch_values=1';
1406 }
1407 }
1408
1409 $linkclose = '';
1410 if (empty($notooltip)) {
1411 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
1412 $label = $langs->trans("ShowAsset");
1413 $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
1414 }
1415 $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
1416 $linkclose .= ' class="classfortooltip'.($morecss ? ' '.$morecss : '').'"';
1417 } else {
1418 $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
1419 }
1420
1421 if ($option == 'nolink') {
1422 $linkstart = '<span';
1423 } else {
1424 $linkstart = '<a href="'.$url.'"';
1425 }
1426 $linkstart .= $linkclose.'>';
1427 if ($option == 'nolink') {
1428 $linkend = '</span>';
1429 } else {
1430 $linkend = '</a>';
1431 }
1432
1433 $result .= $linkstart;
1434
1435 if (empty($this->showphoto_on_popup)) {
1436 if ($withpicto) {
1437 $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);
1438 }
1439 } else {
1440 if ($withpicto) {
1441 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1442
1443 list($class, $module) = explode('@', $this->picto);
1444 $upload_dir = $conf->$module->multidir_output[$conf->entity]."/$class/".dol_sanitizeFileName($this->ref);
1445 $filearray = dol_dir_list($upload_dir, "files");
1446 $filename = $filearray[0]['name'];
1447 if (!empty($filename)) {
1448 $pospoint = strpos($filearray[0]['name'], '.');
1449
1450 $pathtophoto = $class.'/'.$this->ref.'/thumbs/'.substr($filename, 0, $pospoint).'_mini'.substr($filename, $pospoint);
1451 if (!getDolGlobalString(strtoupper($module.'_'.$class).'_FORMATLISTPHOTOSASUSERS')) {
1452 $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>';
1453 } else {
1454 $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>';
1455 }
1456
1457 $result .= '</div>';
1458 } else {
1459 $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);
1460 }
1461 }
1462 }
1463
1464 if ($withpicto != 2) {
1465 $name = $this->ref;
1466 if ($option == 'label') {
1467 $name = $this->label;
1468 } elseif ($option == 'with_label') {
1469 $name .= ' - ' . $this->label;
1470 }
1471 $result .= dol_escape_htmltag($maxlen ? dol_trunc($name, $maxlen) : $name);
1472 }
1473
1474 $result .= $linkend;
1475 //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
1476
1477 global $action;
1478 $hookmanager->initHooks(array($this->element . 'dao'));
1479 $parameters = array('id' => $this->id, 'getnomurl' => &$result);
1480 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1481 if ($reshook > 0) {
1482 $result = $hookmanager->resPrint;
1483 } else {
1484 $result .= $hookmanager->resPrint;
1485 }
1486 return $result;
1487 }
1488
1495 public function getLabelStatus($mode = 0)
1496 {
1497 return $this->LibStatut($this->status, $mode);
1498 }
1499
1506 public function getLibStatut($mode = 0)
1507 {
1508 return $this->LibStatut($this->status, $mode);
1509 }
1510
1511 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1519 public function LibStatut($status, $mode = 0)
1520 {
1521 // phpcs:enable
1522 if (empty($this->labelStatus) || empty($this->labelStatusShort)) {
1523 global $langs;
1524 //$langs->load("assets");
1525 $this->labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('AssetInProgress');
1526 $this->labelStatus[self::STATUS_DISPOSED] = $langs->transnoentitiesnoconv('AssetDisposed');
1527 $this->labelStatusShort[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('AssetInProgress');
1528 $this->labelStatusShort[self::STATUS_DISPOSED] = $langs->transnoentitiesnoconv('AssetDisposed');
1529 }
1530
1531 $statusType = 'status4';
1532 if ($status == self::STATUS_DISPOSED) {
1533 $statusType = 'status6';
1534 }
1535
1536 return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode);
1537 }
1538
1545 public function info($id)
1546 {
1547 $sql = "SELECT rowid, date_creation as datec, tms as datem,";
1548 $sql .= " fk_user_creat, fk_user_modif";
1549 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as t";
1550 $sql .= " WHERE t.rowid = ".((int) $id);
1551
1552 $result = $this->db->query($sql);
1553 if ($result) {
1554 if ($this->db->num_rows($result)) {
1555 $obj = $this->db->fetch_object($result);
1556 $this->id = $obj->rowid;
1557
1558 $this->user_creation_id = $obj->fk_user_creat;
1559 $this->user_modification_id = $obj->fk_user_modif;
1560 $this->date_creation = $this->db->jdate($obj->datec);
1561 $this->date_modification = $this->db->jdate($obj->datem);
1562 }
1563
1564 $this->db->free($result);
1565 } else {
1566 dol_print_error($this->db);
1567 }
1568 }
1569
1576 public function initAsSpecimen()
1577 {
1578 // Set here init that are not commonf fields
1579 // $this->property1 = ...
1580 // $this->property2 = ...
1581
1582 return $this->initAsSpecimenCommon();
1583 }
1584
1590 public function getNextNumRef()
1591 {
1592 global $langs, $conf;
1593 $langs->load("assets");
1594
1595 if (!getDolGlobalString('ASSET_ASSET_ADDON')) {
1596 $conf->global->ASSET_ASSET_ADDON = 'mod_asset_standard';
1597 }
1598
1599 if (getDolGlobalString('ASSET_ASSET_ADDON')) {
1600 $mybool = false;
1601
1602 $file = getDolGlobalString('ASSET_ASSET_ADDON') . ".php";
1603 $classname = getDolGlobalString('ASSET_ASSET_ADDON');
1604
1605 // Include file with class
1606 $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
1607 foreach ($dirmodels as $reldir) {
1608 $dir = dol_buildpath($reldir."core/modules/asset/");
1609
1610 // Load file with numbering class (if found)
1611 $mybool = ((bool) @include_once $dir.$file) || $mybool;
1612 }
1613
1614 if (!$mybool) {
1615 dol_print_error(null, "Failed to include file ".$file);
1616 return '';
1617 }
1618
1619 if (class_exists($classname)) {
1620 $obj = new $classname();
1621
1622 '@phan-var-force ModeleNumRefAsset $obj';
1623
1624 $numref = $obj->getNextValue($this);
1625
1626 if ($numref != '' && $numref != '-1') {
1627 return $numref;
1628 } else {
1629 $this->error = $obj->error;
1630 //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error);
1631 return "";
1632 }
1633 } else {
1634 print $langs->trans("Error")." ".$langs->trans("ClassNotFound").' '.$classname;
1635 return "";
1636 }
1637 } else {
1638 print $langs->trans("ErrorNumberingModuleNotSetup", $this->element);
1639 return "";
1640 }
1641 }
1642}
getCurrentPeriodOfFiscalYear($db, $conf, $from_time=null, $gm='tzserver', $withenddateonly=1)
Get current period of fiscal year?
$object ref
Definition info.php:79
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:162
dol_get_first_day($year, $month=1, $gm=false)
Return GMT time for first day of a month or year.
Definition date.lib.php:596
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:615
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).
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...