dolibarr 19.0.4
asset.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2017 Laurent Destailleur <eldy@users.sourceforge.net>
3 * Copyright (C) 2018 Alexandre Spangaro <aspangaro@open-dsi.fr>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 */
18
25require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
26
30class Asset extends CommonObject
31{
35 public $module = 'asset';
36
40 public $element = 'asset';
41
45 public $table_element = 'asset';
46
51 public $ismultientitymanaged = 1;
52
56 public $isextrafieldmanaged = 1;
57
61 public $picto = 'asset';
62
63 const STATUS_DRAFT = 0; // In progress
64 const STATUS_DISPOSED = 9; // Disposed
65
97 public $fields=array(
98 'rowid' => array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>'1', 'position'=>1, 'notnull'=>1, 'visible'=>0, 'noteditable'=>'1', 'index'=>1, 'css'=>'left', 'comment'=>"Id"),
99 'ref' => array('type'=>'varchar(128)', 'label'=>'Ref', 'enabled'=>'1', 'position'=>20, 'notnull'=>1, 'visible'=>1, 'noteditable'=>'0', 'index'=>1, 'searchall'=>1, 'showoncombobox'=>'1', 'validate'=>'1', 'comment'=>"Reference of object"),
100 'label' => array('type'=>'varchar(255)', 'label'=>'Label', 'enabled'=>'1', 'position'=>30, 'notnull'=>1, 'visible'=>1, 'searchall'=>1, 'css'=>'minwidth300', 'cssview'=>'wordbreak', 'showoncombobox'=>'2', 'validate'=>'1',),
101 'fk_asset_model' => array('type'=>'integer:AssetModel:asset/class/assetmodel.class.php:1:((status:=:1) and (entity:IN:__SHARED_ENTITIES__))', 'label'=>'AssetModel', 'enabled'=>'1', 'position'=>40, 'notnull'=>0, 'visible'=>1, 'index'=>1, 'validate'=>'1',),
102 'qty' => array('type'=>'real', 'label'=>'Qty', 'enabled'=>'1', 'position'=>50, 'notnull'=>1, 'visible'=>0, 'default'=>'1', 'isameasure'=>'1', 'css'=>'maxwidth75imp', 'validate'=>'1',),
103 'acquisition_type' => array('type'=>'smallint', 'label'=>'AssetAcquisitionType', 'enabled'=>'1', 'position'=>60, 'notnull'=>1, 'visible'=>1, 'arrayofkeyval'=>array('0'=>'AssetAcquisitionTypeNew', '1'=>'AssetAcquisitionTypeOccasion'), 'validate'=>'1',),
104 'asset_type' => array('type'=>'smallint', 'label'=>'AssetType', 'enabled'=>'1', 'position'=>70, 'notnull'=>1, 'visible'=>1, 'arrayofkeyval'=>array('0'=>'AssetTypeIntangible', '1'=>'AssetTypeTangible', '2'=>'AssetTypeInProgress', '3'=>'AssetTypeFinancial'), 'validate'=>'1',),
105 'not_depreciated' => array('type'=>'boolean', 'label'=>'AssetNotDepreciated', 'enabled'=>'1', 'position'=>80, 'notnull'=>0, 'default'=>'0', 'visible'=>1, 'validate'=>'1',),
106 'date_acquisition' => array('type'=>'date', 'label'=>'AssetDateAcquisition', 'enabled'=>'1', 'position'=>90, 'notnull'=>1, 'visible'=>1,),
107 'date_start' => array('type'=>'date', 'label'=>'AssetDateStart', 'enabled'=>'1', 'position'=>100, 'notnull'=>0, 'visible'=>-1,),
108 'acquisition_value_ht' => array('type'=>'price', 'label'=>'AssetAcquisitionValueHT', 'enabled'=>'1', 'position'=>110, 'notnull'=>1, 'visible'=>1, 'isameasure'=>'1', 'validate'=>'1',),
109 'recovered_vat' => array('type'=>'price', 'label'=>'AssetRecoveredVAT', 'enabled'=>'1', 'position'=>120, 'notnull'=>0, 'visible'=>1, 'isameasure'=>'1', 'validate'=>'1',),
110 'reversal_date' => array('type'=>'date', 'label'=>'AssetReversalDate', 'enabled'=>'1', 'position'=>130, 'notnull'=>0, 'visible'=>1,),
111 'reversal_amount_ht' => array('type'=>'price', 'label'=>'AssetReversalAmountHT', 'enabled'=>'1', 'position'=>140, 'notnull'=>0, 'visible'=>1, 'isameasure'=>'1', 'validate'=>'1',),
112 'disposal_date' => array('type'=>'date', 'label'=>'AssetDisposalDate', 'enabled'=>'1', 'position'=>200, 'notnull'=>0, 'visible'=>-2,),
113 'disposal_amount_ht' => array('type'=>'price', 'label'=>'AssetDisposalAmount', 'enabled'=>'1', 'position'=>210, 'notnull'=>0, 'visible'=>-2, 'default'=>'0', 'isameasure'=>'1', 'validate'=>'1',),
114 'fk_disposal_type' => array('type'=>'sellist:c_asset_disposal_type:label:rowid::active=1', 'label'=>'AssetDisposalType', 'enabled'=>'1', 'position'=>220, 'notnull'=>0, 'visible'=>-2, 'index'=>1, 'validate'=>'1',),
115 'disposal_depreciated' => array('type'=>'boolean', 'label'=>'AssetDisposalDepreciated', 'enabled'=>'1', 'position'=>230, 'notnull'=>0, 'default'=>'0', 'visible'=>-2, 'validate'=>'1',),
116 'disposal_subject_to_vat' => array('type'=>'boolean', 'label'=>'AssetDisposalSubjectToVat', 'enabled'=>'1', 'position'=>240, 'notnull'=>0, 'default'=>'0', 'visible'=>-2, 'validate'=>'1',),
117 'note_public' => array('type'=>'html', 'label'=>'NotePublic', 'enabled'=>'1', 'position'=>300, 'notnull'=>0, 'visible'=>0, 'validate'=>'1',),
118 'note_private' => array('type'=>'html', 'label'=>'NotePrivate', 'enabled'=>'1', 'position'=>301, 'notnull'=>0, 'visible'=>0, 'validate'=>'1',),
119 'date_creation' => array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>'1', 'position'=>500, 'notnull'=>1, 'visible'=>-2,),
120 'tms' => array('type'=>'timestamp', 'label'=>'DateModification', 'enabled'=>'1', 'position'=>501, 'notnull'=>0, 'visible'=>-2,),
121 'fk_user_creat' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserAuthor', 'enabled'=>'1', 'position'=>510, 'notnull'=>1, 'visible'=>-2, 'foreignkey'=>'user.rowid',),
122 'fk_user_modif' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserModif', 'enabled'=>'1', 'position'=>511, 'notnull'=>-1, 'visible'=>-2,),
123 'last_main_doc' => array('type'=>'varchar(255)', 'label'=>'LastMainDoc', 'enabled'=>'1', 'position'=>600, 'notnull'=>0, 'visible'=>0,),
124 'import_key' => array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>'1', 'position'=>1000, 'notnull'=>-1, 'visible'=>-2,),
125 'model_pdf' => array('type'=>'varchar(255)', 'label'=>'Model pdf', 'enabled'=>'1', 'position'=>1010, 'notnull'=>-1, 'visible'=>0,),
126 'status' => array('type'=>'smallint', 'label'=>'Status', 'enabled'=>'1', 'position'=>1000, 'notnull'=>1, 'default'=>'0', 'visible'=>2, 'index'=>1, 'arrayofkeyval'=>array('0'=>'Draft', '1'=>'Validated', '9'=>'Canceled'), 'validate'=>'1',),
127 );
128 public $rowid;
129 public $ref;
130 public $label;
131 public $fk_asset_model;
132 public $reversal_amount_ht;
133 public $acquisition_value_ht;
134 public $recovered_vat;
135 public $reversal_date;
136 public $date_acquisition;
137 public $date_start;
138 public $qty;
139 public $acquisition_type;
140 public $asset_type;
141 public $not_depreciated;
142 public $disposal_date;
143 public $disposal_amount_ht;
144 public $fk_disposal_type;
145 public $disposal_depreciated;
146 public $disposal_subject_to_vat;
147 public $supplier_invoice_id;
148 public $note_public;
149 public $note_private;
150 public $date_creation;
151 public $tms;
152 public $fk_user_creat;
153 public $fk_user_modif;
154 public $last_main_doc;
155 public $import_key;
156 public $model_pdf;
157 public $status;
158
162 public $oldcopy;
163
164
168 public $asset_depreciation_options;
172 public $depreciation_lines = array();
173
179 public function __construct(DoliDB $db)
180 {
181 global $conf, $langs;
182
183 $this->db = $db;
184
185 if (!getDolGlobalString('MAIN_SHOW_TECHNICAL_ID') && isset($this->fields['rowid'])) {
186 $this->fields['rowid']['visible'] = 0;
187 }
188 if (!isModEnabled('multicompany') && isset($this->fields['entity'])) {
189 $this->fields['entity']['enabled'] = 0;
190 }
191
192 // Unset fields that are disabled
193 foreach ($this->fields as $key => $val) {
194 if (isset($val['enabled']) && empty($val['enabled'])) {
195 unset($this->fields[$key]);
196 }
197 }
198
199 // Translate some data of arrayofkeyval
200 if (is_object($langs)) {
201 foreach ($this->fields as $key => $val) {
202 if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
203 foreach ($val['arrayofkeyval'] as $key2 => $val2) {
204 $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2);
205 }
206 }
207 }
208 }
209 }
210
218 public function create(User $user, $notrigger = false)
219 {
220 if (!isset($this->date_start) || $this->date_start === "") {
221 $this->date_start = $this->date_acquisition;
222 }
223
224 $this->db->begin();
225
226 $result = $result_create = $this->createCommon($user, $notrigger);
227 if ($result > 0 && $this->fk_asset_model > 0) {
228 $result = $this->setDataFromAssetModel($user, $notrigger);
229 }
230 if ($result > 0) {
231 if ($this->supplier_invoice_id > 0) {
232 $this->add_object_linked('invoice_supplier', $this->supplier_invoice_id);
233 }
234 }
235
236 if ($result < 0) {
237 $this->db->rollback();
238 } else {
239 $this->db->commit();
240 }
241
242 return $result > 0 ? $result_create : $result;
243 }
244
252 public function createFromClone(User $user, $fromid)
253 {
254 global $langs, $extrafields;
255 $error = 0;
256
257 dol_syslog(__METHOD__, LOG_DEBUG);
258
259 // $object = new self($this->db);
260 //
261 // $this->db->begin();
262 //
263 // // Load source object
264 // $result = $object->fetchCommon($fromid);
265 // if ($result > 0 && !empty($object->table_element_line)) {
266 // $object->fetchLines();
267 // }
268 //
269 // // get lines so they will be clone
270 // //foreach($this->lines as $line)
271 // // $line->fetch_optionals();
272 //
273 // // Reset some properties
274 // unset($object->id);
275 // unset($object->fk_user_creat);
276 // unset($object->import_key);
277 //
278 // // Clear fields
279 // if (property_exists($object, 'ref')) {
280 // $object->ref = empty($this->fields['ref']['default']) ? "Copy_Of_".$object->ref : $this->fields['ref']['default'];
281 // }
282 // if (property_exists($object, 'label')) {
283 // $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf")." ".$object->label : $this->fields['label']['default'];
284 // }
285 // if (property_exists($object, 'status')) {
286 // $object->status = self::STATUS_DRAFT;
287 // }
288 // if (property_exists($object, 'date_creation')) {
289 // $object->date_creation = dol_now();
290 // }
291 // if (property_exists($object, 'date_modification')) {
292 // $object->date_modification = null;
293 // }
294 // // ...
295 // // Clear extrafields that are unique
296 // if (is_array($object->array_options) && count($object->array_options) > 0) {
297 // $extrafields->fetch_name_optionals_label($this->table_element);
298 // foreach ($object->array_options as $key => $option) {
299 // $shortkey = preg_replace('/options_/', '', $key);
300 // if (!empty($extrafields->attributes[$this->table_element]['unique'][$shortkey])) {
301 // //var_dump($key); var_dump($clonedObj->array_options[$key]); exit;
302 // unset($object->array_options[$key]);
303 // }
304 // }
305 // }
306 //
307 // // Create clone
308 // $object->context['createfromclone'] = 'createfromclone';
309 // $result = $object->createCommon($user);
310 // if ($result < 0) {
311 // $error++;
312 // $this->error = $object->error;
313 // $this->errors = $object->errors;
314 // }
315 //
316 // if (!$error) {
317 // // copy internal contacts
318 // if ($this->copy_linked_contact($object, 'internal') < 0) {
319 // $error++;
320 // }
321 // }
322 //
323 // if (!$error) {
324 // // copy external contacts if same company
325 // if (property_exists($this, 'fk_soc') && $this->fk_soc == $object->socid) {
326 // if ($this->copy_linked_contact($object, 'external') < 0) {
327 // $error++;
328 // }
329 // }
330 // }
331 //
332 // unset($object->context['createfromclone']);
333 //
334 // // End
335 // if (!$error) {
336 // $this->db->commit();
337 // return $object;
338 // } else {
339 // $this->db->rollback();
340 // return -1;
341 // }
342 return -1;
343 }
344
352 public function fetch($id, $ref = null)
353 {
354 $result = $this->fetchCommon($id, $ref);
355 if ($result > 0) {
356 if (!empty($this->table_element_line)) {
357 $this->fetchLines();
358 }
359
360 $res = $this->hasDepreciationLinesInBookkeeping();
361 if ($res < 0) {
362 return -1;
363 } elseif ($res > 0) {
364 $this->fields['date_acquisition']['noteditable'] = '1';
365 $this->fields['date_start']['noteditable'] = '1';
366 $this->fields['acquisition_value_ht']['noteditable'] = '1';
367 $this->fields['recovered_vat']['noteditable'] = '1';
368 $this->fields['reversal_date']['noteditable'] = '1';
369 $this->fields['reversal_amount_ht']['noteditable'] = '1';
370 }
371 }
372 return $result;
373 }
374
380 public function fetchLines()
381 {
382 $this->lines = array();
383
384 return 1;
385 }
386
387
399 public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND')
400 {
401 global $conf;
402
403 dol_syslog(__METHOD__, LOG_DEBUG);
404
405 $records = array();
406
407 $sql = "SELECT ";
408 $sql .= $this->getFieldList('t');
409 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as t";
410 if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
411 $sql .= " WHERE t.entity IN (".getEntity($this->element).")";
412 } else {
413 $sql .= " WHERE 1 = 1";
414 }
415 // Manage filter
416 $sqlwhere = array();
417 if (count($filter) > 0) {
418 foreach ($filter as $key => $value) {
419 if ($key == 't.rowid') {
420 $sqlwhere[] = $key." = ".((int) $value);
421 } elseif (array_key_exists($key, $this->fields) && in_array($this->fields[$key]['type'], array('date', 'datetime', 'timestamp'))) {
422 $sqlwhere[] = $key." = '".$this->db->idate($value)."'";
423 } elseif ($key == 'customsql') {
424 $sqlwhere[] = $value;
425 } elseif (strpos($value, '%') === false) {
426 $sqlwhere[] = $key." IN (".$this->db->sanitize($this->db->escape($value)).")";
427 } else {
428 $sqlwhere[] = $key." LIKE '%".$this->db->escape($value)."%'";
429 }
430 }
431 }
432 if (count($sqlwhere) > 0) {
433 $sql .= " AND (".implode(" ".$filtermode." ", $sqlwhere).")";
434 }
435
436 if (!empty($sortfield)) {
437 $sql .= $this->db->order($sortfield, $sortorder);
438 }
439 if (!empty($limit)) {
440 $sql .= $this->db->plimit($limit, $offset);
441 }
442
443 $resql = $this->db->query($sql);
444 if ($resql) {
445 $num = $this->db->num_rows($resql);
446 $i = 0;
447 while ($i < ($limit ? min($limit, $num) : $num)) {
448 $obj = $this->db->fetch_object($resql);
449
450 $record = new self($this->db);
451 $record->setVarsFromFetchObj($obj);
452
453 $records[$record->id] = $record;
454
455 $i++;
456 }
457 $this->db->free($resql);
458
459 return $records;
460 } else {
461 $this->errors[] = 'Error '.$this->db->lasterror();
462 dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
463
464 return -1;
465 }
466 }
467
475 public function update(User $user, $notrigger = false)
476 {
477 if (!isset($this->date_start) || $this->date_start === "") {
478 $this->date_start = $this->date_acquisition;
479 }
480
481 $this->db->begin();
482
483 $result = $this->updateCommon($user, $notrigger);
484 if ($result > 0 && $this->fk_asset_model > 0 && $this->fk_asset_model != $this->oldcopy->fk_asset_model) {
485 $result = $this->setDataFromAssetModel($user, $notrigger);
486 }
487 if ($result > 0 && (
488 $this->date_start != $this->oldcopy->date_start ||
489 $this->acquisition_value_ht != $this->oldcopy->acquisition_value_ht ||
490 $this->reversal_date != $this->oldcopy->reversal_date ||
491 $this->reversal_amount_ht != $this->oldcopy->reversal_amount_ht ||
492 ($this->fk_asset_model > 0 && $this->fk_asset_model != $this->oldcopy->fk_asset_model)
493 )
494 ) {
495 $result = $this->calculationDepreciation();
496 }
497
498 if ($result < 0) {
499 $this->db->rollback();
500 } else {
501 $this->db->commit();
502 }
503
504 return $result;
505 }
506
514 public function delete(User $user, $notrigger = false)
515 {
516 return $this->deleteCommon($user, $notrigger);
517 //return $this->deleteCommon($user, $notrigger, 1);
518 }
519
527 public function setDataFromAssetModel(User $user, $notrigger = false)
528 {
529 global $langs;
530 $langs->load('assets');
531
532 // Clean parameters
533 $this->id = $this->id > 0 ? $this->id : 0;
534 $this->fk_asset_model = $this->fk_asset_model > 0 ? $this->fk_asset_model : 0;
535
536 // Check parameters
537 $error = 0;
538 if (empty($this->id)) {
539 $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Asset") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
540 $error++;
541 }
542 if (empty($this->fk_asset_model)) {
543 $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("AssetModel") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
544 $error++;
545 }
546 if ($error) {
547 return -1;
548 }
549
550 $this->db->begin();
551
552 // Get depreciation options
553 //---------------------------
554 require_once DOL_DOCUMENT_ROOT . '/asset/class/assetdepreciationoptions.class.php';
555 $options_model = new AssetDepreciationOptions($this->db);
556 $result = $options_model->fetchDeprecationOptions(0, $this->fk_asset_model);
557 if ($result < 0) {
558 $this->error = $options_model->error;
559 $this->errors = $options_model->errors;
560 $error++;
561 } elseif ($result > 0) {
562 $options = new AssetDepreciationOptions($this->db);
563 $result = $options->fetchDeprecationOptions($this->id);
564 if ($result < 0) {
565 $this->error = $options->error;
566 $this->errors = $options->errors;
567 $error++;
568 }
569
570 if (!$error) {
571 foreach ($options_model->deprecation_options as $mode_key => $fields) {
572 foreach ($fields as $field_key => $value) {
573 $options->deprecation_options[$mode_key][$field_key] = $value;
574 }
575 }
576
577 $result = $options->updateDeprecationOptions($user, $this->id, 0, $notrigger);
578 if ($result < 0) {
579 $this->error = $options->error;
580 $this->errors = $options->errors;
581 $error++;
582 }
583 }
584 }
585
586 // Get accountancy codes
587 //---------------------------
588 if (!$error) {
589 require_once DOL_DOCUMENT_ROOT . '/asset/class/assetaccountancycodes.class.php';
590 $accountancy_codes_model = new AssetAccountancyCodes($this->db);
591 $result = $accountancy_codes_model->fetchAccountancyCodes(0, $this->fk_asset_model);
592 if ($result < 0) {
593 $this->error = $accountancy_codes_model->error;
594 $this->errors = $accountancy_codes_model->errors;
595 $error++;
596 } elseif ($result > 0) {
597 $accountancy_codes = new AssetAccountancyCodes($this->db);
598 $result = $accountancy_codes->fetchAccountancyCodes($this->id);
599 if ($result < 0) {
600 $this->error = $accountancy_codes->error;
601 $this->errors = $accountancy_codes->errors;
602 $error++;
603 }
604
605 if (!$error) {
606 foreach ($accountancy_codes_model->accountancy_codes as $mode_key => $fields) {
607 foreach ($fields as $field_key => $value) {
608 $accountancy_codes->accountancy_codes[$mode_key][$field_key] = $value;
609 }
610 }
611
612 $result = $accountancy_codes->updateAccountancyCodes($user, $this->id, 0, $notrigger);
613 if ($result < 0) {
614 $this->error = $accountancy_codes->error;
615 $this->errors = $accountancy_codes->errors;
616 $error++;
617 }
618 }
619 }
620 }
621
622 if ($error) {
623 $this->db->rollback();
624 return -1;
625 } else {
626 $this->db->commit();
627 return 1;
628 }
629 }
630
636 public function fetchDepreciationLines()
637 {
638 global $langs;
639 $langs->load('assets');
640 $this->depreciation_lines = array();
641
642 // Clean parameters
643 $this->id = $this->id > 0 ? $this->id : 0;
644
645 // Check parameters
646 $error = 0;
647 if (empty($this->id)) {
648 $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Asset") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
649 $error++;
650 }
651 if ($error) {
652 return -1;
653 }
654
655 // Old request with 'WITH'
656 /*
657 $sql = "WITH in_accounting_bookkeeping(fk_docdet) AS (";
658 $sql .= " SELECT DISTINCT fk_docdet";
659 $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping";
660 $sql .= " WHERE doc_type = 'asset'";
661 $sql .= ")";
662 $sql .= "SELECT ad.rowid, ad.depreciation_mode, ad.ref, ad.depreciation_date, ad.depreciation_ht, ad.cumulative_depreciation_ht";
663 $sql .= ", " . $this->db->ifsql('iab.fk_docdet IS NOT NULL', 1, 0) . " AS bookkeeping";
664 $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
665 $sql .= " LEFT JOIN in_accounting_bookkeeping as iab ON iab.fk_docdet = ad.rowid";
666 $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
667 $sql .= " ORDER BY ad.depreciation_date ASC";
668 */
669
670 $sql = "SELECT ad.rowid, ad.depreciation_mode, ad.ref, ad.depreciation_date, ad.depreciation_ht, ad.cumulative_depreciation_ht";
671 $sql .= ", " . $this->db->ifsql('iab.fk_docdet IS NOT NULL', 1, 0) . " AS bookkeeping";
672 $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
673 $sql .= " LEFT JOIN (SELECT DISTINCT fk_docdet FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping WHERE doc_type = 'asset') AS iab ON iab.fk_docdet = ad.rowid";
674 $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
675 $sql .= " ORDER BY ad.depreciation_date ASC";
676
677 $resql = $this->db->query($sql);
678 if (!$resql) {
679 $this->errors[] = $langs->trans('AssetErrorFetchDepreciationLines') . ': ' . $this->db->lasterror();
680 return -1;
681 }
682
683 while ($obj = $this->db->fetch_object($resql)) {
684 if (!isset($this->depreciation_lines[$obj->depreciation_mode])) {
685 $this->depreciation_lines[$obj->depreciation_mode] = array();
686 }
687 $this->depreciation_lines[$obj->depreciation_mode][] = array(
688 'id' => $obj->rowid,
689 'ref' => $obj->ref,
690 'depreciation_date' => $this->db->jdate($obj->depreciation_date),
691 'depreciation_ht' => $obj->depreciation_ht,
692 'cumulative_depreciation_ht' => $obj->cumulative_depreciation_ht,
693 'bookkeeping' => $obj->bookkeeping,
694 );
695 }
696
697 return 1;
698 }
699
706 {
707 global $langs;
708 $langs->load('assets');
709
710 // Clean parameters
711 $this->id = $this->id > 0 ? $this->id : 0;
712
713 // Check parameters
714 $error = 0;
715 if (empty($this->id)) {
716 $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Asset") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
717 $error++;
718 }
719 if ($error) {
720 return -1;
721 }
722
723 // Old request with 'WITH'
724 /*
725 $sql = "WITH in_accounting_bookkeeping(fk_docdet) AS (";
726 $sql .= " SELECT DISTINCT fk_docdet";
727 $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping";
728 $sql .= " WHERE doc_type = 'asset'";
729 $sql .= ")";
730 $sql .= "SELECT COUNT(*) AS has_bookkeeping";
731 $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
732 $sql .= " LEFT JOIN in_accounting_bookkeeping as iab ON iab.fk_docdet = ad.rowid";
733 $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
734 $sql .= " AND iab.fk_docdet IS NOT NULL";
735 */
736
737 $sql = "SELECT COUNT(*) AS has_bookkeeping";
738 $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
739 $sql .= " LEFT JOIN (SELECT DISTINCT fk_docdet FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping WHERE doc_type = 'asset') AS iab ON iab.fk_docdet = ad.rowid";
740 $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
741 $sql .= " AND iab.fk_docdet IS NOT NULL";
742
743 $resql = $this->db->query($sql);
744 if (!$resql) {
745 $this->errors[] = $langs->trans('AssetErrorFetchDepreciationLines') . ': ' . $this->db->lasterror();
746 return -1;
747 }
748
749 if ($obj = $this->db->fetch_object($resql)) {
750 return $obj->has_bookkeeping > 0 ? 1 : 0;
751 }
752
753 return 0;
754 }
755
768 public function addDepreciationLine($mode, $ref, $depreciation_date, $depreciation_ht, $cumulative_depreciation_ht, $accountancy_code_debit, $accountancy_code_credit)
769 {
770 global $langs;
771 $langs->load('assets');
772
773 // Clean parameters
774 $this->id = $this->id > 0 ? $this->id : 0;
775 $mode = strtolower(trim($mode));
776 $ref = trim($ref);
777 $accountancy_code_debit = trim($accountancy_code_debit);
778 $accountancy_code_credit = trim($accountancy_code_credit);
779
780 // Check parameters
781 $error = 0;
782 if (empty($this->id)) {
783 $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Asset") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
784 $error++;
785 }
786 if ($error) {
787 return -1;
788 }
789
790 $sql = "INSERT INTO " . MAIN_DB_PREFIX . "asset_depreciation(fk_asset, depreciation_mode, ref, depreciation_date, depreciation_ht, cumulative_depreciation_ht, accountancy_code_debit, accountancy_code_credit)";
791 $sql .= " VALUES ( ";
792 $sql .= " " . (int) $this->id;
793 $sql .= ", '" . $this->db->escape($mode) . "'";
794 $sql .= ", '" . $this->db->escape($ref) . "'";
795 $sql .= ", '" . $this->db->idate($depreciation_date) . "'";
796 $sql .= ", " . (float) $depreciation_ht;
797 $sql .= ", " . (float) $cumulative_depreciation_ht;
798 $sql .= ", '" . $this->db->escape($accountancy_code_debit) . "'";
799 $sql .= ", '" . $this->db->escape($accountancy_code_credit) . "'";
800 $sql .= ")";
801
802 $resql = $this->db->query($sql);
803 if (!$resql) {
804 $this->errors[] = $langs->trans('AssetErrorAddDepreciationLine') . ': ' . $this->db->lasterror();
805 return -1;
806 }
807
808 return 1;
809 }
810
816 public function calculationDepreciation()
817 {
818 global $conf, $langs;
819 $langs->load('assets');
820
821 // Clean parameters
822 $this->id = $this->id > 0 ? $this->id : 0;
823
824 // Check parameters
825 $error = 0;
826 if (empty($this->id)) {
827 $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Asset") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
828 $error++;
829 }
830 if ($error) {
831 return -1;
832 }
833
834 // Get depreciation options
835 //---------------------------
836 require_once DOL_DOCUMENT_ROOT . '/asset/class/assetdepreciationoptions.class.php';
837 $options = new AssetDepreciationOptions($this->db);
838 $result = $options->fetchDeprecationOptions($this->id);
839 if ($result < 0) {
840 $this->error = $options->error;
841 $this->errors = $options->errors;
842 return -1;
843 }
844
845 // Get accountancy codes
846 //---------------------------
847 require_once DOL_DOCUMENT_ROOT . '/asset/class/assetaccountancycodes.class.php';
848 $accountancy_codes = new AssetAccountancyCodes($this->db);
849 $result = $accountancy_codes->fetchAccountancyCodes($this->id);
850 if ($result < 0) {
851 $this->error = $accountancy_codes->error;
852 $this->errors = $accountancy_codes->errors;
853 return -1;
854 }
855
856 $this->db->begin();
857
858 // Delete old lines
859 $modes = array();
860 foreach ($options->deprecation_options as $mode_key => $fields) {
861 $modes[$mode_key] = $this->db->escape($mode_key);
862 }
863 $sql = "DELETE FROM " . MAIN_DB_PREFIX . "asset_depreciation";
864 $sql .= " WHERE fk_asset = " . (int) $this->id;
865 $sql .= " AND depreciation_mode NOT IN ('" . $this->db->sanitize(implode("', '", $modes)) . "')";
866
867 $resql = $this->db->query($sql);
868 if (!$resql) {
869 $this->errors[] = $langs->trans('AssetErrorClearDepreciationLines') . ': ' . $this->db->lasterror();
870 $error++;
871 }
872
873 if (!$error) {
874 // Get fiscal period
875 require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
876 require_once DOL_DOCUMENT_ROOT . '/core/lib/accounting.lib.php';
877 $dates = getCurrentPeriodOfFiscalYear($this->db, $conf, $this->date_start > $this->date_acquisition ? $this->date_start : $this->date_acquisition);
878 $init_fiscal_period_start = $dates['date_start'];
879 $init_fiscal_period_end = $dates['date_end'];
880 if (empty($init_fiscal_period_start) || empty($init_fiscal_period_end)) {
881 $pastmonthyear = $dates['pastmonthyear'];
882 $pastmonth = $dates['pastmonth'];
883 $init_fiscal_period_start = dol_get_first_day($pastmonthyear, $pastmonth, false);
884 $init_fiscal_period_end = dol_get_last_day($pastmonthyear, $pastmonth, false);
885 }
886
887 foreach ($options->deprecation_options as $mode_key => $fields) {
888 // Get last depreciation lines save in bookkeeping
889 //-----------------------------------------------------
890
891 // Old request with 'WITH'
892 /*
893 $sql = "WITH in_accounting_bookkeeping(fk_docdet) AS (";
894 $sql .= " SELECT fk_docdet";
895 $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping";
896 $sql .= " WHERE doc_type = 'asset'";
897 $sql .= ")";
898 $sql .= "SELECT ad.depreciation_date, ad.cumulative_depreciation_ht";
899 $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
900 $sql .= " LEFT JOIN in_accounting_bookkeeping as iab ON iab.fk_docdet = ad.rowid";
901 $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
902 $sql .= " AND ad.depreciation_mode = '" . $this->db->escape($mode_key) . "'";
903 $sql .= " AND iab.fk_docdet IS NOT NULL";
904 $sql .= " ORDER BY ad.depreciation_date DESC";
905 $sql .= " LIMIT 1";
906 */
907
908 $sql = "SELECT ad.depreciation_date, ad.cumulative_depreciation_ht";
909 $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
910 $sql .= " LEFT JOIN (SELECT DISTINCT fk_docdet FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping WHERE doc_type = 'asset') AS iab ON iab.fk_docdet = ad.rowid";
911 $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
912 $sql .= " AND ad.depreciation_mode = '" . $this->db->escape($mode_key) . "'";
913 $sql .= " AND iab.fk_docdet IS NOT NULL";
914 $sql .= " ORDER BY ad.depreciation_date DESC";
915 $sql .= " LIMIT 1";
916
917 $resql = $this->db->query($sql);
918 if (!$resql) {
919 $this->errors[] = $langs->trans('AssetErrorFetchMaxDepreciationDateForMode', $mode_key) . ': ' . $this->db->lasterror();
920 $error++;
921 break;
922 }
923 $last_depreciation_date = '';
924 $last_cumulative_depreciation_ht = $this->reversal_amount_ht;
925 if ($obj = $this->db->fetch_object($resql)) {
926 $last_depreciation_date = $this->db->jdate($obj->depreciation_date);
927 $last_cumulative_depreciation_ht = $obj->cumulative_depreciation_ht;
928 }
929
930 // Set last cumulative depreciation
931 $sql = "UPDATE " . MAIN_DB_PREFIX . $options->deprecation_options_fields[$mode_key]['table'];
932 $sql .= " SET total_amount_last_depreciation_ht = " . (empty($last_cumulative_depreciation_ht) ? 0 : $last_cumulative_depreciation_ht);
933 $sql .= " WHERE fk_asset = " . (int) $this->id;
934 $resql = $this->db->query($sql);
935 if (!$resql) {
936 $this->errors[] = $langs->trans('AssetErrorSetLastCumulativeDepreciation') . ': ' . $this->db->lasterror();
937 $error++;
938 break;
939 }
940
941 // Delete old lines
942 $sql = "DELETE " . MAIN_DB_PREFIX . "asset_depreciation FROM " . MAIN_DB_PREFIX . "asset_depreciation";
943 $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";
944 $sql .= " WHERE " . MAIN_DB_PREFIX . "asset_depreciation.fk_asset = " . (int) $this->id;
945 $sql .= " AND " . MAIN_DB_PREFIX . "asset_depreciation.depreciation_mode = '" . $this->db->escape($mode_key) . "'";
946 $sql .= " AND ab.fk_docdet IS NULL";
947 if ($last_depreciation_date !== "") {
948 $sql .= " AND " . MAIN_DB_PREFIX . "asset_depreciation.ref != ''";
949 }
950 $resql = $this->db->query($sql);
951 if (!$resql) {
952 $this->errors[] = $langs->trans('AssetErrorClearDepreciationLines') . ': ' . $this->db->lasterror();
953 $error++;
954 break;
955 }
956
957 // Get depreciation period
958 $depreciation_date_start = $this->date_start > $this->date_acquisition ? $this->date_start : $this->date_acquisition;
959 $depreciation_date_end = dol_time_plus_duree($depreciation_date_start, $fields['duration'], $fields['duration_type'] == 1 ? 'm' : ($fields['duration_type'] == 2 ? 'd' : 'y'));
960 $depreciation_amount = $fields['amount_base_depreciation_ht'];
961 if ($fields['duration_type'] == 2) { // Daily
962 $fiscal_period_start = $depreciation_date_start;
963 $fiscal_period_end = $depreciation_date_start;
964 } elseif ($fields['duration_type'] == 1) { // Monthly
965 $date_temp = dol_getdate($depreciation_date_start);
966 $fiscal_period_start = dol_get_first_day($date_temp['year'], $date_temp['mon'], false);
967 $fiscal_period_end = dol_get_last_day($date_temp['year'], $date_temp['mon'], false);
968 } else { // Annually
969 $fiscal_period_start = $init_fiscal_period_start;
970 $fiscal_period_end = $init_fiscal_period_end;
971 }
972 $cumulative_depreciation_ht = $last_cumulative_depreciation_ht;
973 $depreciation_period_amount = $depreciation_amount - $this->reversal_amount_ht;
974 $start_date = $depreciation_date_start;
975 $disposal_date = isset($this->disposal_date) && $this->disposal_date !== "" ? $this->disposal_date : "";
976 $finish_date = $disposal_date !== "" ? $disposal_date : $depreciation_date_end;
977 $accountancy_code_depreciation_debit_key = $accountancy_codes->accountancy_codes_fields[$mode_key]['depreciation_debit'];
978 $accountancy_code_depreciation_debit = $accountancy_codes->accountancy_codes[$mode_key][$accountancy_code_depreciation_debit_key];
979 $accountancy_code_depreciation_credit_key = $accountancy_codes->accountancy_codes_fields[$mode_key]['depreciation_credit'];
980 $accountancy_code_credit = $accountancy_codes->accountancy_codes[$mode_key][$accountancy_code_depreciation_credit_key];
981
982 // Reversal depreciation line
983 //-----------------------------------------------------
984 if ($last_depreciation_date === "" && ($depreciation_date_start < $fiscal_period_start || is_numeric($this->reversal_date))) {
985 if (is_numeric($this->reversal_date)) {
986 if ($this->reversal_date < $fiscal_period_start) {
987 $this->errors[] = $langs->trans('AssetErrorReversalDateNotGreaterThanCurrentBeginFiscalDateForMode', $mode_key);
988 $error++;
989 break;
990 }
991
992 if (empty($this->reversal_amount_ht)) {
993 $this->errors[] = $langs->trans('AssetErrorReversalAmountNotProvidedForMode', $mode_key);
994 $error++;
995 break;
996 }
997
998 $start_date = $this->reversal_date;
999 $result = $this->addDepreciationLine($mode_key, '', $start_date, $this->reversal_amount_ht, $this->reversal_amount_ht, $accountancy_code_depreciation_debit, $accountancy_code_credit);
1000 if ($result < 0) {
1001 $error++;
1002 break;
1003 }
1004 } else {
1005 $this->errors[] = $langs->trans('AssetErrorReversalDateNotProvidedForMode', $mode_key);
1006 $error++;
1007 break;
1008 }
1009 }
1010
1011 // futures depreciation lines
1012 //-----------------------------------------------------
1013 $nb_days_in_year = getDolGlobalString('ASSET_DEPRECIATION_DURATION_PER_YEAR') ? $conf->global->ASSET_DEPRECIATION_DURATION_PER_YEAR : 365;
1014 $nb_days_in_month = getDolGlobalString('ASSET_DEPRECIATION_DURATION_PER_MONTH') ? $conf->global->ASSET_DEPRECIATION_DURATION_PER_MONTH : 30;
1015 $period_amount = (float) price2num($depreciation_period_amount / $fields['duration'], 'MT');
1016 $first_period_found = false;
1017 // TODO fix declaration of $begin_period
1018 // @phpstan-ignore-next-line
1019 $first_period_date = isset($begin_period) && $begin_period > $fiscal_period_start ? $begin_period : $fiscal_period_start;
1020
1021 $ref_date_format = "%Y" . ($fields['duration_type'] == 1 || $fields['duration_type'] == 2 ? '-%m' : '') . ($fields['duration_type'] == 2 ? '-%d' : '');
1022
1023 // Loop security
1024 $idx_loop = 0;
1025 $max_loop = $fields['duration'] + 2;
1026 do {
1027 // Loop security
1028 $idx_loop++;
1029 if ($idx_loop > $max_loop) {
1030 break;
1031 }
1032
1033 if ($last_depreciation_date < $fiscal_period_end && ($first_period_date <= $start_date || $first_period_found)) {
1034 // Disposal not depreciated
1035 if ($fiscal_period_start <= $disposal_date && $disposal_date <= $fiscal_period_end && empty($this->disposal_depreciated)) {
1036 break;
1037 }
1038
1039 $first_period_found = true;
1040
1041 $period_begin = dol_print_date($fiscal_period_start, $ref_date_format);
1042 $period_end = dol_print_date($fiscal_period_end, $ref_date_format);
1043 $ref = $period_begin . ($period_begin != $period_end ? ' - ' . $period_end : '');
1044 if ($fiscal_period_start <= $disposal_date && $disposal_date <= $fiscal_period_end) {
1045 $ref .= ' - ' . $langs->transnoentitiesnoconv('AssetDisposal');
1046 }
1047
1048 $begin_date = $fiscal_period_start < $start_date && $start_date <= $fiscal_period_end ? $start_date : $fiscal_period_start;
1049 $end_date = $fiscal_period_start < $finish_date && $finish_date <= $fiscal_period_end ? $finish_date : $fiscal_period_end;
1050 if ($fields['duration_type'] == 2) { // Daily
1051 $depreciation_ht = $period_amount;
1052 } elseif ($fields['duration_type'] == 1) { // Monthly
1053 $nb_days = min($nb_days_in_month, num_between_day($begin_date, $end_date, 1));
1054 if ($nb_days >= 28) {
1055 $date_temp = dol_getdate($begin_date);
1056 if ($date_temp['mon'] == 2) {
1057 $nb_days = 30;
1058 }
1059 }
1060 $depreciation_ht = (float) price2num($period_amount * $nb_days / $nb_days_in_month, 'MT');
1061 } else { // Annually
1062 $nb_days = min($nb_days_in_year, num_between_day($begin_date, $end_date, 1));
1063 $depreciation_ht = (float) price2num($period_amount * $nb_days / $nb_days_in_year, 'MT');
1064 }
1065
1066 if ($fiscal_period_start <= $depreciation_date_end && $depreciation_date_end <= $fiscal_period_end) { // last period
1067 $depreciation_ht = (float) price2num($depreciation_amount - $cumulative_depreciation_ht, 'MT');
1068 $cumulative_depreciation_ht = $depreciation_amount;
1069 } else {
1070 $cumulative_depreciation_ht += $depreciation_ht;
1071 }
1072
1073 $result = $this->addDepreciationLine($mode_key, $ref, $fiscal_period_end, $depreciation_ht, $cumulative_depreciation_ht, $accountancy_code_depreciation_debit, $accountancy_code_credit);
1074 if ($result < 0) {
1075 $error++;
1076 break;
1077 }
1078 }
1079
1080 // Next fiscal period (+1 day/month/year)
1081 $fiscal_period_start = dol_time_plus_duree($fiscal_period_end, 1, 'd');
1082 if ($fields['duration_type'] == 2) { // Daily
1083 $fiscal_period_end = $fiscal_period_start;
1084 } elseif ($fields['duration_type'] == 1) { // Monthly
1085 $fiscal_period_end = dol_time_plus_duree(dol_time_plus_duree($fiscal_period_start, 1, 'm'), -1, 'd');
1086 } else { // Annually
1087 $fiscal_period_end = dol_time_plus_duree(dol_time_plus_duree($fiscal_period_start, 1, 'y'), -1, 'd');
1088 }
1089 $last_period_date = $disposal_date !== "" && $disposal_date < $depreciation_date_end ? $disposal_date : $depreciation_date_end;
1090 } while ($fiscal_period_start < $last_period_date);
1091
1092 if ($error) {
1093 break;
1094 }
1095 }
1096 }
1097
1098 if ($error) {
1099 $this->db->rollback();
1100 return -1;
1101 } else {
1102 $this->db->commit();
1103 return 1;
1104 }
1105 }
1106
1113 public function setLastCumulativeDepreciation($asset_depreciation_id)
1114 {
1115 global $langs;
1116 $langs->load('assets');
1117
1118 // Clean parameters
1119 $asset_depreciation_id = $asset_depreciation_id > 0 ? $asset_depreciation_id : 0;
1120
1121 // Check parameters
1122 $error = 0;
1123 if (empty($asset_depreciation_id)) {
1124 $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("AssetDepreciation") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
1125 $error++;
1126 }
1127 if ($error) {
1128 return -1;
1129 }
1130
1131 $this->db->begin();
1132
1133 require_once DOL_DOCUMENT_ROOT . '/asset/class/assetdepreciationoptions.class.php';
1134 $options = new AssetDepreciationOptions($this->db);
1135
1136 // Get last depreciation lines save in bookkeeping
1137 //-----------------------------------------------------
1138 $sql = "SELECT fk_asset, depreciation_mode, cumulative_depreciation_ht";
1139 $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation";
1140 $sql .= " WHERE rowid = " . (int) $asset_depreciation_id;
1141 $resql = $this->db->query($sql);
1142 if (!$resql) {
1143 $this->errors[] = $langs->trans('AssetErrorFetchCumulativeDepreciation') . ': ' . $this->db->lasterror();
1144 $error++;
1145 } else {
1146 if ($obj = $this->db->fetch_object($resql)) {
1147 $mode_key = $obj->depreciation_mode;
1148 if (!empty($options->deprecation_options_fields[$mode_key])) {
1149 $sql = "UPDATE " . MAIN_DB_PREFIX . $options->deprecation_options_fields[$mode_key]['table'];
1150 $sql .= " SET total_amount_last_depreciation_ht = " . $obj->cumulative_depreciation_ht;
1151 $sql .= " WHERE fk_asset = " . (int) $obj->fk_asset;
1152 $resql = $this->db->query($sql);
1153 if (!$resql) {
1154 $this->errors[] = $langs->trans('AssetErrorSetLastCumulativeDepreciation') . ': ' . $this->db->lasterror();
1155 $error++;
1156 }
1157 }
1158 }
1159 }
1160
1161 if ($error) {
1162 $this->db->rollback();
1163 return -1;
1164 } else {
1165 $this->db->commit();
1166 return 1;
1167 }
1168 }
1169
1178 public function dispose($user, $disposal_invoice_id, $notrigger = 0)
1179 {
1180 global $conf, $langs;
1181
1182 // Protection
1183 if ($this->status != self::STATUS_DRAFT || $this->status == self::STATUS_DISPOSED) {
1184 return 0;
1185 }
1186
1187 $this->db->begin();
1188
1189 $required_fields = array('disposal_date', 'disposal_date', 'fk_disposal_type');
1190 foreach ($required_fields as $field) {
1191 $this->fields[$field]['notnull'] = 1;
1192 }
1193 $result = $this->update($user, 1);
1194 foreach ($required_fields as $field) {
1195 $this->fields[$field]['notnull'] = 0;
1196 }
1197 if ($result > 0) {
1198 if ($disposal_invoice_id > 0) {
1199 $this->add_object_linked('facture', $disposal_invoice_id);
1200 }
1201 $result = $this->setStatusCommon($user, self::STATUS_DISPOSED, $notrigger, 'ASSET_DISPOSED');
1202 }
1203 if ($result > 0) {
1204 $result = $this->calculationDepreciation();
1205 }
1206
1207 if ($result < 0) {
1208 $this->db->rollback();
1209 } else {
1210 $this->db->commit();
1211 }
1212
1213 // Define output language
1214 if ($result > 0 && !getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
1215 if (method_exists($this, 'generateDocument')) {
1216 global $hidedetails, $hidedesc, $hideref;
1217 $outputlangs = $langs;
1218 $newlang = '';
1219 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
1220 $newlang = GETPOST('lang_id', 'aZ09');
1221 }
1222 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
1223 $newlang = $this->thirdparty->default_lang;
1224 }
1225 if (!empty($newlang)) {
1226 $outputlangs = new Translate("", $conf);
1227 $outputlangs->setDefaultLang($newlang);
1228 }
1229 $model = $this->model_pdf;
1230 $ret = $this->fetch($this->id); // Reload to get new records
1231
1232 $this->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
1233 }
1234 }
1235
1236 return $result;
1237 }
1238
1246 public function reopen($user, $notrigger = 0)
1247 {
1248 global $conf, $langs;
1249
1250 // Protection
1251 if ($this->status != self::STATUS_DISPOSED || $this->status == self::STATUS_DRAFT) {
1252 return 0;
1253 }
1254
1255
1256 $this->db->begin();
1257
1258 $this->disposal_date = null;
1259 $this->disposal_amount_ht = null;
1260 $this->fk_disposal_type = null;
1261 $this->disposal_depreciated = null;
1262 $this->disposal_subject_to_vat = null;
1263 $result = $this->update($user, 1);
1264 if ($result > 0) {
1265 $this->deleteObjectLinked(null, 'facture');
1266 $result = $this->setStatusCommon($user, self::STATUS_DRAFT, $notrigger, 'ASSET_REOPEN');
1267 }
1268 if ($result > 0) {
1269 $result = $this->calculationDepreciation();
1270 }
1271
1272 if ($result < 0) {
1273 $this->db->rollback();
1274 } else {
1275 $this->db->commit();
1276 }
1277
1278 // Define output language
1279 if ($result > 0 && !getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
1280 if (method_exists($this, 'generateDocument')) {
1281 global $hidedetails, $hidedesc, $hideref;
1282 $outputlangs = $langs;
1283 $newlang = '';
1284 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
1285 $newlang = GETPOST('lang_id', 'aZ09');
1286 }
1287 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
1288 $newlang = $this->thirdparty->default_lang;
1289 }
1290 if (!empty($newlang)) {
1291 $outputlangs = new Translate("", $conf);
1292 $outputlangs->setDefaultLang($newlang);
1293 }
1294 $model = $this->model_pdf;
1295 $ret = $this->fetch($this->id); // Reload to get new records
1296
1297 $this->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
1298 }
1299 }
1300
1301 return $result;
1302 }
1303
1315 public function getNomUrl($withpicto = 0, $option = '', $maxlen = 0, $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
1316 {
1317 global $db, $conf, $langs, $hookmanager;
1318 global $dolibarr_main_authentication, $dolibarr_main_demo;
1319 global $menumanager;
1320
1321 if (!empty($conf->dol_no_mouse_hover)) {
1322 $notooltip = 1; // Force disable tooltips
1323 }
1324
1325 $result = '';
1326
1327 $label = img_picto('', $this->picto).' <u>'.$langs->trans("Asset").'</u>';
1328 if (isset($this->status)) {
1329 $label .= ' '.$this->getLibStatut(5);
1330 }
1331 $label .= '<br>';
1332 $label .= '<b>'.$langs->trans('Ref').':</b> '.$this->ref;
1333
1334 $url = dol_buildpath('/asset/card.php', 1).'?id='.$this->id;
1335
1336 if ($option != 'nolink') {
1337 // Add param to save lastsearch_values or not
1338 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1339 if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
1340 $add_save_lastsearch_values = 1;
1341 }
1342 if ($add_save_lastsearch_values) {
1343 $url .= '&save_lastsearch_values=1';
1344 }
1345 }
1346
1347 $linkclose = '';
1348 if (empty($notooltip)) {
1349 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
1350 $label = $langs->trans("ShowAsset");
1351 $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
1352 }
1353 $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
1354 $linkclose .= ' class="classfortooltip'.($morecss ? ' '.$morecss : '').'"';
1355 } else {
1356 $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
1357 }
1358
1359 if ($option == 'nolink') {
1360 $linkstart = '<span';
1361 } else {
1362 $linkstart = '<a href="'.$url.'"';
1363 }
1364 $linkstart .= $linkclose.'>';
1365 if ($option == 'nolink') {
1366 $linkend = '</span>';
1367 } else {
1368 $linkend = '</a>';
1369 }
1370
1371 $result .= $linkstart;
1372
1373 if (empty($this->showphoto_on_popup)) {
1374 if ($withpicto) {
1375 $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);
1376 }
1377 } else {
1378 if ($withpicto) {
1379 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1380
1381 list($class, $module) = explode('@', $this->picto);
1382 $upload_dir = $conf->$module->multidir_output[$conf->entity]."/$class/".dol_sanitizeFileName($this->ref);
1383 $filearray = dol_dir_list($upload_dir, "files");
1384 $filename = $filearray[0]['name'];
1385 if (!empty($filename)) {
1386 $pospoint = strpos($filearray[0]['name'], '.');
1387
1388 $pathtophoto = $class.'/'.$this->ref.'/thumbs/'.substr($filename, 0, $pospoint).'_mini'.substr($filename, $pospoint);
1389 if (!getDolGlobalString(strtoupper($module.'_'.$class).'_FORMATLISTPHOTOSASUSERS')) {
1390 $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>';
1391 } else {
1392 $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>';
1393 }
1394
1395 $result .= '</div>';
1396 } else {
1397 $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);
1398 }
1399 }
1400 }
1401
1402 if ($withpicto != 2) {
1403 $name = $this->ref;
1404 if ($option == 'label') {
1405 $name = $this->label;
1406 } elseif ($option == 'with_label') {
1407 $name .= ' - ' . $this->label;
1408 }
1409 $result .= dol_escape_htmltag($maxlen ? dol_trunc($name, $maxlen) : $name);
1410 }
1411
1412 $result .= $linkend;
1413 //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
1414
1415 global $action;
1416 $hookmanager->initHooks(array($this->element . 'dao'));
1417 $parameters = array('id'=>$this->id, 'getnomurl' => &$result);
1418 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1419 if ($reshook > 0) {
1420 $result = $hookmanager->resPrint;
1421 } else {
1422 $result .= $hookmanager->resPrint;
1423 }
1424 return $result;
1425 }
1426
1433 public function getLabelStatus($mode = 0)
1434 {
1435 return $this->LibStatut($this->status, $mode);
1436 }
1437
1444 public function getLibStatut($mode = 0)
1445 {
1446 return $this->LibStatut($this->status, $mode);
1447 }
1448
1449 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1457 public function LibStatut($status, $mode = 0)
1458 {
1459 // phpcs:enable
1460 if (empty($this->labelStatus) || empty($this->labelStatusShort)) {
1461 global $langs;
1462 //$langs->load("assets");
1463 $this->labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('AssetInProgress');
1464 $this->labelStatus[self::STATUS_DISPOSED] = $langs->transnoentitiesnoconv('AssetDisposed');
1465 $this->labelStatusShort[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('AssetInProgress');
1466 $this->labelStatusShort[self::STATUS_DISPOSED] = $langs->transnoentitiesnoconv('AssetDisposed');
1467 }
1468
1469 $statusType = 'status4';
1470 if ($status == self::STATUS_DISPOSED) {
1471 $statusType = 'status6';
1472 }
1473
1474 return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode);
1475 }
1476
1483 public function info($id)
1484 {
1485 $sql = "SELECT rowid, date_creation as datec, tms as datem,";
1486 $sql .= " fk_user_creat, fk_user_modif";
1487 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as t";
1488 $sql .= " WHERE t.rowid = ".((int) $id);
1489
1490 $result = $this->db->query($sql);
1491 if ($result) {
1492 if ($this->db->num_rows($result)) {
1493 $obj = $this->db->fetch_object($result);
1494 $this->id = $obj->rowid;
1495
1496 $this->user_creation_id = $obj->fk_user_creat;
1497 $this->user_modification_id = $obj->fk_user_modif;
1498 $this->date_creation = $this->db->jdate($obj->datec);
1499 $this->date_modification = $this->db->jdate($obj->datem);
1500 }
1501
1502 $this->db->free($result);
1503 } else {
1504 dol_print_error($this->db);
1505 }
1506 }
1507
1514 public function initAsSpecimen()
1515 {
1516 // Set here init that are not commonf fields
1517 // $this->property1 = ...
1518 // $this->property2 = ...
1519
1520 $this->initAsSpecimenCommon();
1521 }
1522
1528 public function getLinesArray()
1529 {
1530 $this->lines = array();
1531
1532 return $this->lines;
1533 }
1534
1540 public function getNextNumRef()
1541 {
1542 global $langs, $conf;
1543 $langs->load("assets");
1544
1545 if (!getDolGlobalString('ASSET_ASSET_ADDON')) {
1546 $conf->global->ASSET_ASSET_ADDON = 'mod_asset_standard';
1547 }
1548
1549 if (getDolGlobalString('ASSET_ASSET_ADDON')) {
1550 $mybool = false;
1551
1552 $file = getDolGlobalString('ASSET_ASSET_ADDON') . ".php";
1553 $classname = $conf->global->ASSET_ASSET_ADDON;
1554
1555 // Include file with class
1556 $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
1557 foreach ($dirmodels as $reldir) {
1558 $dir = dol_buildpath($reldir."core/modules/asset/");
1559
1560 // Load file with numbering class (if found)
1561 $mybool |= @include_once $dir.$file;
1562 }
1563
1564 if ($mybool === false) {
1565 dol_print_error('', "Failed to include file ".$file);
1566 return '';
1567 }
1568
1569 if (class_exists($classname)) {
1570 $obj = new $classname();
1571 $numref = $obj->getNextValue($this);
1572
1573 if ($numref != '' && $numref != '-1') {
1574 return $numref;
1575 } else {
1576 $this->error = $obj->error;
1577 //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error);
1578 return "";
1579 }
1580 } else {
1581 print $langs->trans("Error")." ".$langs->trans("ClassNotFound").' '.$classname;
1582 return "";
1583 }
1584 } else {
1585 print $langs->trans("ErrorNumberingModuleNotSetup", $this->element);
1586 return "";
1587 }
1588 }
1589
1601 // public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
1602 // {
1603 // global $conf, $langs;
1604 //
1605 // $result = 0;
1606 // $includedocgeneration = 1;
1607 //
1608 // $langs->load("assets");
1609 //
1610 // if (!dol_strlen($modele)) {
1611 // $modele = 'standard_asset';
1612 //
1613 // if (!empty($this->model_pdf)) {
1614 // $modele = $this->model_pdf;
1615 // } elseif (!empty($conf->global->ASSET_ADDON_PDF)) {
1616 // $modele = $conf->global->ASSET_ADDON_PDF;
1617 // }
1618 // }
1619 //
1620 // $modelpath = "core/modules/asset/doc/";
1621 //
1622 // if ($includedocgeneration && !empty($modele)) {
1623 // $result = $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
1624 // }
1625 //
1626 // return $result;
1627 // }
1628}
getCurrentPeriodOfFiscalYear($db, $conf, $from_time=null)
Get current period of fiscal year.
print $langs trans("AuditedSecurityEvents").'</strong >< span class="opacitymedium"></span >< br > status
Definition security.php:604
$object ref
Definition info.php:79
Class for AssetAccountancyCodes.
Class for AssetDepreciationOptions.
Class for Asset.
create(User $user, $notrigger=false)
Create object into database.
getNomUrl($withpicto=0, $option='', $maxlen=0, $notooltip=0, $morecss='', $save_lastsearch_value=-1)
Return a link to the object card (with optionaly the picto)
fetchAll($sortorder='', $sortfield='', $limit=0, $offset=0, array $filter=array(), $filtermode='AND')
Load list of objects in memory from the database.
hasDepreciationLinesInBookkeeping()
If has depreciation lines in bookkeeping.
getLinesArray()
Create an array of lines.
dispose($user, $disposal_invoice_id, $notrigger=0)
Set dispose status.
createFromClone(User $user, $fromid)
Clone an object into another one.
calculationDepreciation()
Calculation depreciation lines (reversal and future) for each mode.
fetchLines()
Load object lines in memory from the database.
__construct(DoliDB $db)
Constructor.
info($id)
Load the info information in the object.
getLabelStatus($mode=0)
Return the label of the status.
update(User $user, $notrigger=false)
Update object into database.
fetch($id, $ref=null)
Load object in memory from the database.
LibStatut($status, $mode=0)
Return the status.
reopen($user, $notrigger=0)
Set back to validated status.
getLibStatut($mode=0)
Return the label of the status.
initAsSpecimen()
Initialise object with example values Id must be 0 if object instance is a specimen.
addDepreciationLine($mode, $ref, $depreciation_date, $depreciation_ht, $cumulative_depreciation_ht, $accountancy_code_debit, $accountancy_code_credit)
Add depreciation line for a mode.
fetchDepreciationLines()
Fetch depreciation lines for each mode in $this->depreciation_lines (sort by depreciation date)
setLastCumulativeDepreciation($asset_depreciation_id)
Set last cumulative depreciation for each mode.
setDataFromAssetModel(User $user, $notrigger=false)
Set asset model.
getNextNumRef()
Returns the reference to the following non used object depending on the active numbering module.
Parent class of all other business classes (invoices, contracts, proposals, orders,...
add_object_linked($origin=null, $origin_id=null, $f_user=null, $notrigger=0)
Add an object link into llx_element_element.
deleteObjectLinked($sourceid=null, $sourcetype='', $targetid=null, $targettype='', $rowid=0, $f_user=null, $notrigger=0)
Delete all links between an object $this.
createCommon(User $user, $notrigger=false)
Create object into database.
deleteCommon(User $user, $notrigger=false, $forcechilddeletion=0)
Delete object in database.
getFieldList($alias='', $excludefields=array())
Function to concat keys of fields.
setStatusCommon($user, $status, $notrigger=0, $triggercode='')
Set to a status.
initAsSpecimenCommon()
Initialise object with example values Id must be 0 if object instance is a specimen.
updateCommon(User $user, $notrigger=false)
Update object into database.
fetchCommon($id, $ref=null, $morewhere='', $noextrafields=0)
Load object in memory from the database.
Class to manage Dolibarr database access.
Class to manage translations.
Class to manage Dolibarr users.
dol_get_first_day($year, $month=1, $gm=false)
Return GMT time for first day of a month or year.
Definition date.lib.php:594
num_between_day($timestampStart, $timestampEnd, $lastday=0)
Function to return number of days between two dates (date must be UTC date !) Example: 2012-01-01 201...
dol_time_plus_duree($time, $duration_value, $duration_unit, $ruleforendofmonth=0)
Add a delay to a date.
Definition date.lib.php:125
dol_get_last_day($year, $month=12, $gm=false)
Return GMT time for last day of a month or year.
Definition date.lib.php:613
dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0, $nbsecondsold=0)
Scan a directory and return a list of files/directories.
Definition files.lib.php:62
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_getdate($timestamp, $fast=false, $forcetimezone='')
Return an array with locale date info.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...