dolibarr 20.0.5
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 * Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
5 * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
27require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
28
32class Asset extends CommonObject
33{
37 public $module = 'asset';
38
42 public $element = 'asset';
43
47 public $table_element = 'asset';
48
52 public $picto = 'asset';
53
54 const STATUS_DRAFT = 0; // In progress
55 const STATUS_DISPOSED = 9; // Disposed
56
88 public $fields = array(
89 'rowid' => array('type' => 'integer', 'label' => 'TechnicalID', 'enabled' => 1, 'position' => 1, 'notnull' => 1, 'visible' => 0, 'noteditable' => 1, 'index' => 1, 'css' => 'left', 'comment' => "Id"),
90 '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"),
91 '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,),
92 '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,),
93 'qty' => array('type' => 'real', 'label' => 'Qty', 'enabled' => 1, 'position' => 50, 'notnull' => 1, 'visible' => 0, 'default' => '1', 'isameasure' => 1, 'css' => 'maxwidth75imp', 'validate' => 1,),
94 'acquisition_type' => array('type' => 'smallint', 'label' => 'AssetAcquisitionType', 'enabled' => 1, 'position' => 60, 'notnull' => 1, 'visible' => 1, 'arrayofkeyval' => array('0' => 'AssetAcquisitionTypeNew', '1' => 'AssetAcquisitionTypeOccasion'), 'validate' => 1,),
95 '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,),
96 'not_depreciated' => array('type' => 'boolean', 'label' => 'AssetNotDepreciated', 'enabled' => 1, 'position' => 80, 'notnull' => 0, 'default' => '0', 'visible' => 1, 'validate' => 1,),
97 'date_acquisition' => array('type' => 'date', 'label' => 'AssetDateAcquisition', 'enabled' => 1, 'position' => 90, 'notnull' => 1, 'visible' => 1,),
98 'date_start' => array('type' => 'date', 'label' => 'AssetDateStart', 'enabled' => 1, 'position' => 100, 'notnull' => 0, 'visible' => -1,),
99 'acquisition_value_ht' => array('type' => 'price', 'label' => 'AssetAcquisitionValueHT', 'enabled' => 1, 'position' => 110, 'notnull' => 1, 'visible' => 1, 'isameasure' => 1, 'validate' => 1,),
100 'recovered_vat' => array('type' => 'price', 'label' => 'AssetRecoveredVAT', 'enabled' => 1, 'position' => 120, 'notnull' => 0, 'visible' => 1, 'isameasure' => 1, 'validate' => 1,),
101 'reversal_date' => array('type' => 'date', 'label' => 'AssetReversalDate', 'enabled' => 1, 'position' => 130, 'notnull' => 0, 'visible' => 1,),
102 'reversal_amount_ht' => array('type' => 'price', 'label' => 'AssetReversalAmountHT', 'enabled' => 1, 'position' => 140, 'notnull' => 0, 'visible' => 1, 'isameasure' => 1, 'validate' => 1,),
103 'disposal_date' => array('type' => 'date', 'label' => 'AssetDisposalDate', 'enabled' => 1, 'position' => 200, 'notnull' => 0, 'visible' => -2,),
104 'disposal_amount_ht' => array('type' => 'price', 'label' => 'AssetDisposalAmount', 'enabled' => 1, 'position' => 210, 'notnull' => 0, 'visible' => -2, 'default' => '0', 'isameasure' => 1, 'validate' => 1,),
105 '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,),
106 'disposal_depreciated' => array('type' => 'boolean', 'label' => 'AssetDisposalDepreciated', 'enabled' => 1, 'position' => 230, 'notnull' => 0, 'default' => '0', 'visible' => -2, 'validate' => 1,),
107 'disposal_subject_to_vat' => array('type' => 'boolean', 'label' => 'AssetDisposalSubjectToVat', 'enabled' => 1, 'position' => 240, 'notnull' => 0, 'default' => '0', 'visible' => -2, 'validate' => 1,),
108 'note_public' => array('type' => 'html', 'label' => 'NotePublic', 'enabled' => 1, 'position' => 300, 'notnull' => 0, 'visible' => 0, 'validate' => 1,),
109 'note_private' => array('type' => 'html', 'label' => 'NotePrivate', 'enabled' => 1, 'position' => 301, 'notnull' => 0, 'visible' => 0, 'validate' => 1,),
110 'date_creation' => array('type' => 'datetime', 'label' => 'DateCreation', 'enabled' => 1, 'position' => 500, 'notnull' => 1, 'visible' => -2,),
111 'tms' => array('type' => 'timestamp', 'label' => 'DateModification', 'enabled' => 1, 'position' => 501, 'notnull' => 0, 'visible' => -2,),
112 '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',),
113 'fk_user_modif' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserModif', 'enabled' => 1, 'position' => 511, 'notnull' => -1, 'visible' => -2,),
114 'last_main_doc' => array('type' => 'varchar(255)', 'label' => 'LastMainDoc', 'enabled' => 1, 'position' => 600, 'notnull' => 0, 'visible' => 0,),
115 'import_key' => array('type' => 'varchar(14)', 'label' => 'ImportId', 'enabled' => 1, 'position' => 1000, 'notnull' => -1, 'visible' => -2,),
116 'model_pdf' => array('type' => 'varchar(255)', 'label' => 'Model pdf', 'enabled' => 1, 'position' => 1010, 'notnull' => -1, 'visible' => 0,),
117 '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,),
118 );
119 public $rowid;
120 public $ref;
121 public $label;
122 public $fk_asset_model;
123 public $reversal_amount_ht;
124 public $acquisition_value_ht;
125 public $recovered_vat;
126 public $reversal_date;
127 public $date_acquisition;
128 public $date_start;
129 public $qty;
130 public $acquisition_type;
131 public $asset_type;
132 public $not_depreciated;
133 public $disposal_date;
134 public $disposal_amount_ht;
135 public $fk_disposal_type;
136 public $disposal_depreciated;
137 public $disposal_subject_to_vat;
138 public $supplier_invoice_id;
139 public $note_public;
140 public $note_private;
141 public $date_creation;
142 public $fk_user_creat;
143 public $fk_user_modif;
144 public $last_main_doc;
145 public $import_key;
146 public $model_pdf;
147 public $status;
148
152 public $oldcopy;
153
154
158 public $asset_depreciation_options;
159 public $asset_accountancy_codes;
163 public $depreciation_lines = array();
164
170 public function __construct(DoliDB $db)
171 {
172 global $conf, $langs;
173
174 $this->db = $db;
175
176 $this->ismultientitymanaged = 1;
177 $this->isextrafieldmanaged = 1;
178
179 if (!getDolGlobalString('MAIN_SHOW_TECHNICAL_ID') && isset($this->fields['rowid'])) {
180 $this->fields['rowid']['visible'] = 0;
181 }
182 if (!isModEnabled('multicompany') && isset($this->fields['entity'])) {
183 $this->fields['entity']['enabled'] = 0;
184 }
185
186 // Unset fields that are disabled
187 foreach ($this->fields as $key => $val) {
188 if (isset($val['enabled']) && empty($val['enabled'])) {
189 unset($this->fields[$key]);
190 }
191 }
192
193 // Translate some data of arrayofkeyval
194 if (is_object($langs)) {
195 foreach ($this->fields as $key => $val) {
196 if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
197 foreach ($val['arrayofkeyval'] as $key2 => $val2) {
198 $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2);
199 }
200 }
201 }
202 }
203 }
204
212 public function create(User $user, $notrigger = 0)
213 {
214 if (!isset($this->date_start) || $this->date_start === "") {
215 $this->date_start = $this->date_acquisition;
216 }
217
218 $this->db->begin();
219
220 $result = $result_create = $this->createCommon($user, $notrigger);
221 if ($result > 0 && $this->fk_asset_model > 0) {
222 $result = $this->setDataFromAssetModel($user, $notrigger);
223 }
224 if ($result > 0) {
225 if ($this->supplier_invoice_id > 0) {
226 $this->add_object_linked('invoice_supplier', $this->supplier_invoice_id);
227 }
228 }
229
230 if ($result < 0) {
231 $this->db->rollback();
232 } else {
233 $this->db->commit();
234 }
235
236 return $result > 0 ? $result_create : $result;
237 }
238
246 public function createFromClone(User $user, $fromid)
247 {
248 global $langs, $extrafields;
249 $error = 0;
250
251 dol_syslog(__METHOD__, LOG_DEBUG);
252
253 // $object = new self($this->db);
254 //
255 // $this->db->begin();
256 //
257 // // Load source object
258 // $result = $object->fetchCommon($fromid);
259 // if ($result > 0 && !empty($object->table_element_line)) {
260 // $object->fetchLines();
261 // }
262 //
263 // // get lines so they will be clone
264 // //foreach($this->lines as $line)
265 // // $line->fetch_optionals();
266 //
267 // // Reset some properties
268 // unset($object->id);
269 // unset($object->fk_user_creat);
270 // unset($object->import_key);
271 //
272 // // Clear fields
273 // if (property_exists($object, 'ref')) {
274 // $object->ref = empty($this->fields['ref']['default']) ? "Copy_Of_".$object->ref : $this->fields['ref']['default'];
275 // }
276 // if (property_exists($object, 'label')) {
277 // $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf")." ".$object->label : $this->fields['label']['default'];
278 // }
279 // if (property_exists($object, 'status')) {
280 // $object->status = self::STATUS_DRAFT;
281 // }
282 // if (property_exists($object, 'date_creation')) {
283 // $object->date_creation = dol_now();
284 // }
285 // if (property_exists($object, 'date_modification')) {
286 // $object->date_modification = null;
287 // }
288 // // ...
289 // // Clear extrafields that are unique
290 // if (is_array($object->array_options) && count($object->array_options) > 0) {
291 // $extrafields->fetch_name_optionals_label($this->table_element);
292 // foreach ($object->array_options as $key => $option) {
293 // $shortkey = preg_replace('/options_/', '', $key);
294 // if (!empty($extrafields->attributes[$this->table_element]['unique'][$shortkey])) {
295 // //var_dump($key); var_dump($clonedObj->array_options[$key]); exit;
296 // unset($object->array_options[$key]);
297 // }
298 // }
299 // }
300 //
301 // // Create clone
302 // $object->context['createfromclone'] = 'createfromclone';
303 // $result = $object->createCommon($user);
304 // if ($result < 0) {
305 // $error++;
306 // $this->error = $object->error;
307 // $this->errors = $object->errors;
308 // }
309 //
310 // if (!$error) {
311 // // copy internal contacts
312 // if ($this->copy_linked_contact($object, 'internal') < 0) {
313 // $error++;
314 // }
315 // }
316 //
317 // if (!$error) {
318 // // copy external contacts if same company
319 // if (property_exists($this, 'fk_soc') && $this->fk_soc == $object->socid) {
320 // if ($this->copy_linked_contact($object, 'external') < 0) {
321 // $error++;
322 // }
323 // }
324 // }
325 //
326 // unset($object->context['createfromclone']);
327 //
328 // // End
329 // if (!$error) {
330 // $this->db->commit();
331 // return $object;
332 // } else {
333 // $this->db->rollback();
334 // return -1;
335 // }
336 return -1;
337 }
338
346 public function fetch($id, $ref = null)
347 {
348 $result = $this->fetchCommon($id, $ref);
349 if ($result > 0) {
350 if (!empty($this->table_element_line)) {
351 $this->fetchLines();
352 }
353
354 $res = $this->hasDepreciationLinesInBookkeeping();
355 if ($res < 0) {
356 return -1;
357 } elseif ($res > 0) {
358 $this->fields['date_acquisition']['noteditable'] = 1;
359 $this->fields['date_start']['noteditable'] = 1;
360 $this->fields['acquisition_value_ht']['noteditable'] = 1;
361 $this->fields['recovered_vat']['noteditable'] = 1;
362 $this->fields['reversal_date']['noteditable'] = 1;
363 $this->fields['reversal_amount_ht']['noteditable'] = 1;
364 }
365 }
366 return $result;
367 }
368
374 public function fetchLines()
375 {
376 $this->lines = array();
377
378 return 1;
379 }
380
381
394 public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, $filter = '', $filtermode = 'AND')
395 {
396 dol_syslog(__METHOD__, LOG_DEBUG);
397
398 $records = array();
399
400 $sql = "SELECT ";
401 $sql .= $this->getFieldList('t');
402 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as t";
403 if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
404 $sql .= " WHERE t.entity IN (".getEntity($this->element).")";
405 } else {
406 $sql .= " WHERE 1 = 1";
407 }
408
409 // Manage filter
410 $errormessage = '';
411 $sql .= forgeSQLFromUniversalSearchCriteria($filter, $errormessage);
412 if ($errormessage) {
413 $this->errors[] = $errormessage;
414 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
415
416 return -1;
417 }
418
419 if (!empty($sortfield)) {
420 $sql .= $this->db->order($sortfield, $sortorder);
421 }
422 if (!empty($limit)) {
423 $sql .= $this->db->plimit($limit, $offset);
424 }
425
426 $resql = $this->db->query($sql);
427 if ($resql) {
428 $num = $this->db->num_rows($resql);
429 $i = 0;
430 while ($i < ($limit ? min($limit, $num) : $num)) {
431 $obj = $this->db->fetch_object($resql);
432
433 $record = new self($this->db);
434 $record->setVarsFromFetchObj($obj);
435
436 $records[$record->id] = $record;
437
438 $i++;
439 }
440 $this->db->free($resql);
441
442 return $records;
443 } else {
444 $this->errors[] = 'Error '.$this->db->lasterror();
445 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
446
447 return -1;
448 }
449 }
450
458 public function update(User $user, $notrigger = 0)
459 {
460 if (!isset($this->date_start) || $this->date_start === "") {
461 $this->date_start = $this->date_acquisition;
462 }
463
464 $this->db->begin();
465
466 $result = $this->updateCommon($user, $notrigger);
467 if ($result > 0 && $this->fk_asset_model > 0 && $this->fk_asset_model != $this->oldcopy->fk_asset_model) {
468 $result = $this->setDataFromAssetModel($user, $notrigger);
469 }
470 if ($result > 0 && (
471 $this->date_start != $this->oldcopy->date_start ||
472 $this->acquisition_value_ht != $this->oldcopy->acquisition_value_ht ||
473 $this->reversal_date != $this->oldcopy->reversal_date ||
474 $this->reversal_amount_ht != $this->oldcopy->reversal_amount_ht ||
475 ($this->fk_asset_model > 0 && $this->fk_asset_model != $this->oldcopy->fk_asset_model)
476 )
477 ) {
478 $result = $this->calculationDepreciation();
479 }
480
481 if ($result < 0) {
482 $this->db->rollback();
483 } else {
484 $this->db->commit();
485 }
486
487 return $result;
488 }
489
497 public function delete(User $user, $notrigger = 0)
498 {
499 return $this->deleteCommon($user, $notrigger);
500 //return $this->deleteCommon($user, $notrigger, 1);
501 }
502
510 public function setDataFromAssetModel(User $user, $notrigger = 0)
511 {
512 global $langs;
513 $langs->load('assets');
514
515 // Clean parameters
516 $this->id = $this->id > 0 ? $this->id : 0;
517 $this->fk_asset_model = $this->fk_asset_model > 0 ? $this->fk_asset_model : 0;
518
519 // Check parameters
520 $error = 0;
521 if (empty($this->id)) {
522 $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Asset") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
523 $error++;
524 }
525 if (empty($this->fk_asset_model)) {
526 $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("AssetModel") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
527 $error++;
528 }
529 if ($error) {
530 return -1;
531 }
532
533 $this->db->begin();
534
535 // Get depreciation options
536 //---------------------------
537 require_once DOL_DOCUMENT_ROOT . '/asset/class/assetdepreciationoptions.class.php';
538 $options_model = new AssetDepreciationOptions($this->db);
539 $result = $options_model->fetchDeprecationOptions(0, $this->fk_asset_model);
540 if ($result < 0) {
541 $this->error = $options_model->error;
542 $this->errors = $options_model->errors;
543 $error++;
544 } elseif ($result > 0) {
545 $options = new AssetDepreciationOptions($this->db);
546 $result = $options->fetchDeprecationOptions($this->id);
547 if ($result < 0) {
548 $this->error = $options->error;
549 $this->errors = $options->errors;
550 $error++;
551 }
552
553 if (!$error) {
554 foreach ($options_model->deprecation_options as $mode_key => $fields) {
555 foreach ($fields as $field_key => $value) {
556 $options->deprecation_options[$mode_key][$field_key] = $value;
557 }
558 }
559
560 $result = $options->updateDeprecationOptions($user, $this->id, 0, $notrigger);
561 if ($result < 0) {
562 $this->error = $options->error;
563 $this->errors = $options->errors;
564 $error++;
565 }
566 }
567 }
568
569 // Get accountancy codes
570 //---------------------------
571 if (!$error) {
572 require_once DOL_DOCUMENT_ROOT . '/asset/class/assetaccountancycodes.class.php';
573 $accountancy_codes_model = new AssetAccountancyCodes($this->db);
574 $result = $accountancy_codes_model->fetchAccountancyCodes(0, $this->fk_asset_model);
575 if ($result < 0) {
576 $this->error = $accountancy_codes_model->error;
577 $this->errors = $accountancy_codes_model->errors;
578 $error++;
579 } elseif ($result > 0) {
580 $accountancy_codes = new AssetAccountancyCodes($this->db);
581 $result = $accountancy_codes->fetchAccountancyCodes($this->id);
582 if ($result < 0) {
583 $this->error = $accountancy_codes->error;
584 $this->errors = $accountancy_codes->errors;
585 $error++;
586 }
587
588 if (!$error) {
589 foreach ($accountancy_codes_model->accountancy_codes as $mode_key => $fields) {
590 foreach ($fields as $field_key => $value) {
591 $accountancy_codes->accountancy_codes[$mode_key][$field_key] = $value;
592 }
593 }
594
595 $result = $accountancy_codes->updateAccountancyCodes($user, $this->id, 0, $notrigger);
596 if ($result < 0) {
597 $this->error = $accountancy_codes->error;
598 $this->errors = $accountancy_codes->errors;
599 $error++;
600 }
601 }
602 }
603 }
604
605 if ($error) {
606 $this->db->rollback();
607 return -1;
608 } else {
609 $this->db->commit();
610 return 1;
611 }
612 }
613
619 public function fetchDepreciationLines()
620 {
621 global $langs;
622 $langs->load('assets');
623 $this->depreciation_lines = array();
624
625 // Clean parameters
626 $this->id = $this->id > 0 ? $this->id : 0;
627
628 // Check parameters
629 $error = 0;
630 if (empty($this->id)) {
631 $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Asset") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
632 $error++;
633 }
634 if ($error) {
635 return -1;
636 }
637
638 // Old request with 'WITH'
639 /*
640 $sql = "WITH in_accounting_bookkeeping(fk_docdet) AS (";
641 $sql .= " SELECT DISTINCT fk_docdet";
642 $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping";
643 $sql .= " WHERE doc_type = 'asset'";
644 $sql .= ")";
645 $sql .= "SELECT ad.rowid, ad.depreciation_mode, ad.ref, ad.depreciation_date, ad.depreciation_ht, ad.cumulative_depreciation_ht";
646 $sql .= ", " . $this->db->ifsql('iab.fk_docdet IS NOT NULL', 1, 0) . " AS bookkeeping";
647 $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
648 $sql .= " LEFT JOIN in_accounting_bookkeeping as iab ON iab.fk_docdet = ad.rowid";
649 $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
650 $sql .= " ORDER BY ad.depreciation_date ASC";
651 */
652
653 $sql = "SELECT ad.rowid, ad.depreciation_mode, ad.ref, ad.depreciation_date, ad.depreciation_ht, ad.cumulative_depreciation_ht";
654 $sql .= ", " . $this->db->ifsql('iab.fk_docdet IS NOT NULL', 1, 0) . " AS bookkeeping";
655 $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
656 $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";
657 $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
658 $sql .= " ORDER BY ad.depreciation_date ASC";
659
660 $resql = $this->db->query($sql);
661 if (!$resql) {
662 $this->errors[] = $langs->trans('AssetErrorFetchDepreciationLines') . ': ' . $this->db->lasterror();
663 return -1;
664 }
665
666 while ($obj = $this->db->fetch_object($resql)) {
667 if (!isset($this->depreciation_lines[$obj->depreciation_mode])) {
668 $this->depreciation_lines[$obj->depreciation_mode] = array();
669 }
670 $this->depreciation_lines[$obj->depreciation_mode][] = array(
671 'id' => $obj->rowid,
672 'ref' => $obj->ref,
673 'depreciation_date' => $this->db->jdate($obj->depreciation_date),
674 'depreciation_ht' => $obj->depreciation_ht,
675 'cumulative_depreciation_ht' => $obj->cumulative_depreciation_ht,
676 'bookkeeping' => $obj->bookkeeping,
677 );
678 }
679
680 return 1;
681 }
682
689 {
690 global $langs;
691 $langs->load('assets');
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 COUNT(*) AS has_bookkeeping";
714 $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
715 $sql .= " LEFT JOIN in_accounting_bookkeeping as iab ON iab.fk_docdet = ad.rowid";
716 $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
717 $sql .= " AND iab.fk_docdet IS NOT NULL";
718 */
719
720 $sql = "SELECT COUNT(*) AS has_bookkeeping";
721 $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
722 $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";
723 $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
724 $sql .= " AND iab.fk_docdet IS NOT NULL";
725
726 $resql = $this->db->query($sql);
727 if (!$resql) {
728 $this->errors[] = $langs->trans('AssetErrorFetchDepreciationLines') . ': ' . $this->db->lasterror();
729 return -1;
730 }
731
732 if ($obj = $this->db->fetch_object($resql)) {
733 return $obj->has_bookkeeping > 0 ? 1 : 0;
734 }
735
736 return 0;
737 }
738
751 public function addDepreciationLine($mode, $ref, $depreciation_date, $depreciation_ht, $cumulative_depreciation_ht, $accountancy_code_debit, $accountancy_code_credit)
752 {
753 global $langs;
754 $langs->load('assets');
755
756 // Clean parameters
757 $this->id = $this->id > 0 ? $this->id : 0;
758 $mode = strtolower(trim($mode));
759 $ref = trim($ref);
760 $accountancy_code_debit = trim($accountancy_code_debit);
761 $accountancy_code_credit = trim($accountancy_code_credit);
762
763 // Check parameters
764 $error = 0;
765 if (empty($this->id)) {
766 $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Asset") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
767 $error++;
768 }
769 if ($error) {
770 return -1;
771 }
772
773 $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)";
774 $sql .= " VALUES ( ";
775 $sql .= " " . (int) $this->id;
776 $sql .= ", '" . $this->db->escape($mode) . "'";
777 $sql .= ", '" . $this->db->escape($ref) . "'";
778 $sql .= ", '" . $this->db->idate($depreciation_date) . "'";
779 $sql .= ", " . (float) $depreciation_ht;
780 $sql .= ", " . (float) $cumulative_depreciation_ht;
781 $sql .= ", '" . $this->db->escape($accountancy_code_debit) . "'";
782 $sql .= ", '" . $this->db->escape($accountancy_code_credit) . "'";
783 $sql .= ")";
784
785 $resql = $this->db->query($sql);
786 if (!$resql) {
787 $this->errors[] = $langs->trans('AssetErrorAddDepreciationLine') . ': ' . $this->db->lasterror();
788 return -1;
789 }
790
791 return 1;
792 }
793
799 public function calculationDepreciation()
800 {
801 global $conf, $langs;
802 $langs->load('assets');
803
804 // Clean parameters
805 $this->id = $this->id > 0 ? $this->id : 0;
806
807 // Check parameters
808 $error = 0;
809 if (empty($this->id)) {
810 $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Asset") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
811 $error++;
812 }
813 if ($error) {
814 return -1;
815 }
816
817 if (! empty($this->not_depreciated)) {
818 return 1;
819 }
820
821 // Get depreciation options
822 //---------------------------
823 require_once DOL_DOCUMENT_ROOT . '/asset/class/assetdepreciationoptions.class.php';
824 $options = new AssetDepreciationOptions($this->db);
825 $result = $options->fetchDeprecationOptions($this->id);
826 if ($result < 0) {
827 $this->error = $options->error;
828 $this->errors = $options->errors;
829 return -1;
830 }
831
832 // Get accountancy codes
833 //---------------------------
834 require_once DOL_DOCUMENT_ROOT . '/asset/class/assetaccountancycodes.class.php';
835 $accountancy_codes = new AssetAccountancyCodes($this->db);
836 $result = $accountancy_codes->fetchAccountancyCodes($this->id);
837 if ($result < 0) {
838 $this->error = $accountancy_codes->error;
839 $this->errors = $accountancy_codes->errors;
840 return -1;
841 }
842
843 $this->db->begin();
844
845 // Delete old lines
846 $modes = array();
847 foreach ($options->deprecation_options as $mode_key => $fields) {
848 $modes[$mode_key] = $this->db->escape($mode_key);
849 }
850 $sql = "DELETE FROM " . MAIN_DB_PREFIX . "asset_depreciation";
851 $sql .= " WHERE fk_asset = " . (int) $this->id;
852 $sql .= " AND depreciation_mode NOT IN ('" . $this->db->sanitize(implode("', '", $modes)) . "')";
853
854 $resql = $this->db->query($sql);
855 if (!$resql) {
856 $this->errors[] = $langs->trans('AssetErrorClearDepreciationLines') . ': ' . $this->db->lasterror();
857 $error++;
858 }
859
860 if (!$error) {
861 // Get fiscal period
862 require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
863 require_once DOL_DOCUMENT_ROOT . '/core/lib/accounting.lib.php';
864 $dates = getCurrentPeriodOfFiscalYear($this->db, $conf, $this->date_start > $this->date_acquisition ? $this->date_start : $this->date_acquisition);
865 $init_fiscal_period_start = $dates['date_start'];
866 $init_fiscal_period_end = $dates['date_end'];
867 if (empty($init_fiscal_period_start) || empty($init_fiscal_period_end)) {
868 $pastmonthyear = $dates['pastmonthyear'];
869 $pastmonth = $dates['pastmonth'];
870 $init_fiscal_period_start = dol_get_first_day($pastmonthyear, $pastmonth, false);
871 $init_fiscal_period_end = dol_get_last_day($pastmonthyear, $pastmonth, false);
872 }
873
874 foreach ($options->deprecation_options as $mode_key => $fields) {
875 // Get last depreciation lines save in bookkeeping
876 //-----------------------------------------------------
877
878 // Old request with 'WITH'
879 /*
880 $sql = "WITH in_accounting_bookkeeping(fk_docdet) AS (";
881 $sql .= " SELECT fk_docdet";
882 $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping";
883 $sql .= " WHERE doc_type = 'asset'";
884 $sql .= ")";
885 $sql .= "SELECT ad.depreciation_date, ad.cumulative_depreciation_ht";
886 $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
887 $sql .= " LEFT JOIN in_accounting_bookkeeping as iab ON iab.fk_docdet = ad.rowid";
888 $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
889 $sql .= " AND ad.depreciation_mode = '" . $this->db->escape($mode_key) . "'";
890 $sql .= " AND iab.fk_docdet IS NOT NULL";
891 $sql .= " ORDER BY ad.depreciation_date DESC";
892 $sql .= " LIMIT 1";
893 */
894
895 $sql = "SELECT ad.depreciation_date, ad.cumulative_depreciation_ht";
896 $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
897 $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";
898 $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
899 $sql .= " AND ad.depreciation_mode = '" . $this->db->escape($mode_key) . "'";
900 $sql .= " AND iab.fk_docdet IS NOT NULL";
901 $sql .= " ORDER BY ad.depreciation_date DESC";
902 $sql .= " LIMIT 1";
903
904 $resql = $this->db->query($sql);
905 if (!$resql) {
906 $this->errors[] = $langs->trans('AssetErrorFetchMaxDepreciationDateForMode', $mode_key) . ': ' . $this->db->lasterror();
907 $error++;
908 break;
909 }
910 $last_depreciation_date = '';
911 $last_cumulative_depreciation_ht = $this->reversal_amount_ht;
912 if ($obj = $this->db->fetch_object($resql)) {
913 $last_depreciation_date = $this->db->jdate($obj->depreciation_date);
914 $last_cumulative_depreciation_ht = $obj->cumulative_depreciation_ht;
915 }
916
917 // Set last cumulative depreciation
918 $sql = "UPDATE " . MAIN_DB_PREFIX . $options->deprecation_options_fields[$mode_key]['table'];
919 $sql .= " SET total_amount_last_depreciation_ht = " . (empty($last_cumulative_depreciation_ht) ? 0 : $last_cumulative_depreciation_ht);
920 $sql .= " WHERE fk_asset = " . (int) $this->id;
921 $resql = $this->db->query($sql);
922 if (!$resql) {
923 $this->errors[] = $langs->trans('AssetErrorSetLastCumulativeDepreciation') . ': ' . $this->db->lasterror();
924 $error++;
925 break;
926 }
927
928 // Delete old lines
929 $sql = "DELETE FROM " . MAIN_DB_PREFIX . "asset_depreciation";
930 $sql .= " WHERE fk_asset = " . (int) $this->id;
931 $sql .= " AND depreciation_mode = '" . $this->db->escape($mode_key) . "'";
932 $sql .= " AND NOT EXISTS (SELECT fk_docdet FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping WHERE doc_type = 'asset' AND fk_docdet = " . MAIN_DB_PREFIX . "asset_depreciation.rowid)";
933 if ($last_depreciation_date !== "") {
934 $sql .= " AND ref <> ''";
935 }
936 $resql = $this->db->query($sql);
937 if (!$resql) {
938 $this->errors[] = $langs->trans('AssetErrorClearDepreciationLines') . ': ' . $this->db->lasterror();
939 $error++;
940 break;
941 }
942
943 // Get depreciation period
944 $depreciation_date_start = $this->date_start > $this->date_acquisition ? $this->date_start : $this->date_acquisition;
945 $depreciation_date_end = dol_time_plus_duree($depreciation_date_start, $fields['duration'], $fields['duration_type'] == 1 ? 'm' : ($fields['duration_type'] == 2 ? 'd' : 'y'));
946 $depreciation_amount = $fields['amount_base_depreciation_ht'];
947 if ($fields['duration_type'] == 2) { // Daily
948 $fiscal_period_start = $depreciation_date_start;
949 $fiscal_period_end = $depreciation_date_start;
950 } elseif ($fields['duration_type'] == 1) { // Monthly
951 $date_temp = dol_getdate($depreciation_date_start);
952 $fiscal_period_start = dol_get_first_day($date_temp['year'], $date_temp['mon'], false);
953 $fiscal_period_end = dol_get_last_day($date_temp['year'], $date_temp['mon'], false);
954 } else { // Annually
955 $fiscal_period_start = $init_fiscal_period_start;
956 $fiscal_period_end = $init_fiscal_period_end;
957 }
958 $cumulative_depreciation_ht = $last_cumulative_depreciation_ht;
959 $depreciation_period_amount = $depreciation_amount - $this->reversal_amount_ht;
960 $start_date = $depreciation_date_start;
961 $disposal_date = isset($this->disposal_date) && $this->disposal_date !== "" ? $this->disposal_date : "";
962 $finish_date = $disposal_date !== "" ? $disposal_date : $depreciation_date_end;
963 $accountancy_code_depreciation_debit_key = $accountancy_codes->accountancy_codes_fields[$mode_key]['depreciation_debit'];
964 $accountancy_code_depreciation_debit = $accountancy_codes->accountancy_codes[$mode_key][$accountancy_code_depreciation_debit_key];
965 $accountancy_code_depreciation_credit_key = $accountancy_codes->accountancy_codes_fields[$mode_key]['depreciation_credit'];
966 $accountancy_code_credit = $accountancy_codes->accountancy_codes[$mode_key][$accountancy_code_depreciation_credit_key];
967
968 // Reversal depreciation line
969 //-----------------------------------------------------
970 if ($last_depreciation_date === "" && ($depreciation_date_start < $fiscal_period_start || is_numeric($this->reversal_date))) {
971 if (is_numeric($this->reversal_date)) {
972 if ($this->reversal_date < $fiscal_period_start) {
973 $this->errors[] = $langs->trans('AssetErrorReversalDateNotGreaterThanCurrentBeginFiscalDateForMode', $mode_key);
974 $error++;
975 break;
976 }
977
978 if (empty($this->reversal_amount_ht)) {
979 $this->errors[] = $langs->trans('AssetErrorReversalAmountNotProvidedForMode', $mode_key);
980 $error++;
981 break;
982 }
983
984 $start_date = $this->reversal_date;
985 $result = $this->addDepreciationLine($mode_key, '', $start_date, $this->reversal_amount_ht, $this->reversal_amount_ht, $accountancy_code_depreciation_debit, $accountancy_code_credit);
986 if ($result < 0) {
987 $error++;
988 break;
989 }
990 } else {
991 $this->errors[] = $langs->trans('AssetErrorReversalDateNotProvidedForMode', $mode_key);
992 $error++;
993 break;
994 }
995 }
996
997 // futures depreciation lines
998 //-----------------------------------------------------
999 $nb_days_in_year = getDolGlobalInt('ASSET_DEPRECIATION_DURATION_PER_YEAR', 365);
1000 $nb_days_in_month = getDolGlobalInt('ASSET_DEPRECIATION_DURATION_PER_MONTH', 30);
1001 $period_amount = (float) ($fields['duration'] > 0 ? price2num($depreciation_period_amount / $fields['duration'], 'MT') : 0);
1002 $first_period_found = false;
1003 // TODO fix declaration of $begin_period
1004 $first_period_date = isset($begin_period) && $begin_period > $fiscal_period_start ? $begin_period : $fiscal_period_start;
1005
1006 $ref_date_format = "%Y" . ($fields['duration_type'] == 1 || $fields['duration_type'] == 2 ? '-%m' : '') . ($fields['duration_type'] == 2 ? '-%d' : '');
1007
1008 // Loop security
1009 $idx_loop = 0;
1010 $max_loop = $fields['duration'] + 2;
1011 do {
1012 // Loop security
1013 $idx_loop++;
1014 if ($idx_loop > $max_loop) {
1015 break;
1016 }
1017
1018 if ($last_depreciation_date < $fiscal_period_end && ($first_period_date <= $start_date || $first_period_found)) {
1019 // Disposal not depreciated
1020 if ($fiscal_period_start <= $disposal_date && $disposal_date <= $fiscal_period_end && empty($this->disposal_depreciated)) {
1021 break;
1022 }
1023
1024 $first_period_found = true;
1025
1026 $period_begin = dol_print_date($fiscal_period_start, $ref_date_format);
1027 $period_end = dol_print_date($fiscal_period_end, $ref_date_format);
1028 $ref = $period_begin . ($period_begin != $period_end ? ' - ' . $period_end : '');
1029 if ($fiscal_period_start <= $disposal_date && $disposal_date <= $fiscal_period_end) {
1030 $ref .= ' - ' . $langs->transnoentitiesnoconv('AssetDisposal');
1031 }
1032
1033 $begin_date = $fiscal_period_start < $start_date && $start_date <= $fiscal_period_end ? $start_date : $fiscal_period_start;
1034 $end_date = $fiscal_period_start < $finish_date && $finish_date <= $fiscal_period_end ? $finish_date : $fiscal_period_end;
1035 if ($fields['duration_type'] == 2) { // Daily
1036 $depreciation_ht = $period_amount;
1037 } elseif ($fields['duration_type'] == 1) { // Monthly
1038 $nb_days = min($nb_days_in_month, num_between_day($begin_date, $end_date, 1));
1039 if ($nb_days >= 28) {
1040 $date_temp = dol_getdate($begin_date);
1041 if ($date_temp['mon'] == 2) {
1042 $nb_days = 30;
1043 }
1044 }
1045 $depreciation_ht = (float) price2num($period_amount * $nb_days / $nb_days_in_month, 'MT');
1046 } else { // Annually
1047 $nb_days = min($nb_days_in_year, num_between_day($begin_date, $end_date, 1));
1048 $depreciation_ht = (float) price2num($period_amount * $nb_days / $nb_days_in_year, 'MT');
1049 }
1050
1051 if ($fiscal_period_start <= $depreciation_date_end && $depreciation_date_end <= $fiscal_period_end) { // last period
1052 $depreciation_ht = (float) price2num($depreciation_amount - $cumulative_depreciation_ht, 'MT');
1053 $cumulative_depreciation_ht = $depreciation_amount;
1054 } else {
1055 $cumulative_depreciation_ht += $depreciation_ht;
1056 }
1057
1058 $result = $this->addDepreciationLine($mode_key, $ref, $fiscal_period_end, $depreciation_ht, $cumulative_depreciation_ht, $accountancy_code_depreciation_debit, $accountancy_code_credit);
1059 if ($result < 0) {
1060 $error++;
1061 break;
1062 }
1063 }
1064
1065 // Next fiscal period (+1 day/month/year)
1066 $fiscal_period_start = dol_time_plus_duree($fiscal_period_end, 1, 'd');
1067 if ($fields['duration_type'] == 2) { // Daily
1068 $fiscal_period_end = $fiscal_period_start;
1069 } elseif ($fields['duration_type'] == 1) { // Monthly
1070 $fiscal_period_end = dol_time_plus_duree(dol_time_plus_duree($fiscal_period_start, 1, 'm'), -1, 'd');
1071 } else { // Annually
1072 $fiscal_period_end = dol_time_plus_duree(dol_time_plus_duree($fiscal_period_start, 1, 'y'), -1, 'd');
1073 }
1074 $last_period_date = $disposal_date !== "" && $disposal_date < $depreciation_date_end ? $disposal_date : $depreciation_date_end;
1075 } while ($fiscal_period_start < $last_period_date);
1076
1077 if ($error) {
1078 break;
1079 }
1080 }
1081 }
1082
1083 if ($error) {
1084 $this->db->rollback();
1085 return -1;
1086 } else {
1087 $this->db->commit();
1088 return 1;
1089 }
1090 }
1091
1098 public function setLastCumulativeDepreciation($asset_depreciation_id)
1099 {
1100 global $langs;
1101 $langs->load('assets');
1102
1103 // Clean parameters
1104 $asset_depreciation_id = $asset_depreciation_id > 0 ? $asset_depreciation_id : 0;
1105
1106 // Check parameters
1107 $error = 0;
1108 if (empty($asset_depreciation_id)) {
1109 $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("AssetDepreciation") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
1110 $error++;
1111 }
1112 if ($error) {
1113 return -1;
1114 }
1115
1116 $this->db->begin();
1117
1118 require_once DOL_DOCUMENT_ROOT . '/asset/class/assetdepreciationoptions.class.php';
1119 $options = new AssetDepreciationOptions($this->db);
1120
1121 // Get last depreciation lines save in bookkeeping
1122 //-----------------------------------------------------
1123 $sql = "SELECT fk_asset, depreciation_mode, cumulative_depreciation_ht";
1124 $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation";
1125 $sql .= " WHERE rowid = " . (int) $asset_depreciation_id;
1126 $resql = $this->db->query($sql);
1127 if (!$resql) {
1128 $this->errors[] = $langs->trans('AssetErrorFetchCumulativeDepreciation') . ': ' . $this->db->lasterror();
1129 $error++;
1130 } else {
1131 if ($obj = $this->db->fetch_object($resql)) {
1132 $mode_key = $obj->depreciation_mode;
1133 if (!empty($options->deprecation_options_fields[$mode_key])) {
1134 $sql = "UPDATE " . MAIN_DB_PREFIX . $options->deprecation_options_fields[$mode_key]['table'];
1135 $sql .= " SET total_amount_last_depreciation_ht = " . $obj->cumulative_depreciation_ht;
1136 $sql .= " WHERE fk_asset = " . (int) $obj->fk_asset;
1137 $resql = $this->db->query($sql);
1138 if (!$resql) {
1139 $this->errors[] = $langs->trans('AssetErrorSetLastCumulativeDepreciation') . ': ' . $this->db->lasterror();
1140 $error++;
1141 }
1142 }
1143 }
1144 }
1145
1146 if ($error) {
1147 $this->db->rollback();
1148 return -1;
1149 } else {
1150 $this->db->commit();
1151 return 1;
1152 }
1153 }
1154
1163 public function dispose($user, $disposal_invoice_id, $notrigger = 0)
1164 {
1165 global $conf, $langs;
1166
1167 // Protection
1168 if ($this->status != self::STATUS_DRAFT || $this->status == self::STATUS_DISPOSED) {
1169 return 0;
1170 }
1171
1172 $this->db->begin();
1173
1174 $required_fields = array('disposal_date', 'disposal_date', 'fk_disposal_type');
1175 foreach ($required_fields as $field) {
1176 $this->fields[$field]['notnull'] = 1;
1177 }
1178 $result = $this->update($user, 1);
1179 foreach ($required_fields as $field) {
1180 $this->fields[$field]['notnull'] = 0;
1181 }
1182 if ($result > 0) {
1183 if ($disposal_invoice_id > 0) {
1184 $this->add_object_linked('facture', $disposal_invoice_id);
1185 }
1186 $result = $this->setStatusCommon($user, self::STATUS_DISPOSED, $notrigger, 'ASSET_DISPOSED');
1187 }
1188 if ($result > 0) {
1189 $result = $this->calculationDepreciation();
1190 }
1191
1192 if ($result < 0) {
1193 $this->db->rollback();
1194 } else {
1195 $this->db->commit();
1196 }
1197
1198 // Define output language
1199 if ($result > 0 && !getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
1200 if (method_exists($this, 'generateDocument')) {
1201 global $hidedetails, $hidedesc, $hideref;
1202 $outputlangs = $langs;
1203 $newlang = '';
1204 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
1205 $newlang = GETPOST('lang_id', 'aZ09');
1206 }
1207 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
1208 $newlang = $this->thirdparty->default_lang;
1209 }
1210 if (!empty($newlang)) {
1211 $outputlangs = new Translate("", $conf);
1212 $outputlangs->setDefaultLang($newlang);
1213 }
1214 $model = $this->model_pdf;
1215 $ret = $this->fetch($this->id); // Reload to get new records
1216
1217 $this->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
1218 }
1219 }
1220
1221 return $result;
1222 }
1223
1231 public function reopen($user, $notrigger = 0)
1232 {
1233 global $conf, $langs;
1234
1235 // Protection
1236 if ($this->status != self::STATUS_DISPOSED || $this->status == self::STATUS_DRAFT) {
1237 return 0;
1238 }
1239
1240
1241 $this->db->begin();
1242
1243 $this->disposal_date = null;
1244 $this->disposal_amount_ht = null;
1245 $this->fk_disposal_type = null;
1246 $this->disposal_depreciated = null;
1247 $this->disposal_subject_to_vat = null;
1248 $result = $this->update($user, 1);
1249 if ($result > 0) {
1250 $this->deleteObjectLinked(null, 'facture');
1251 $result = $this->setStatusCommon($user, self::STATUS_DRAFT, $notrigger, 'ASSET_REOPEN');
1252 }
1253 if ($result > 0) {
1254 $result = $this->calculationDepreciation();
1255 }
1256
1257 if ($result < 0) {
1258 $this->db->rollback();
1259 } else {
1260 $this->db->commit();
1261 }
1262
1263 // Define output language
1264 if ($result > 0 && !getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
1265 if (method_exists($this, 'generateDocument')) {
1266 global $hidedetails, $hidedesc, $hideref;
1267 $outputlangs = $langs;
1268 $newlang = '';
1269 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
1270 $newlang = GETPOST('lang_id', 'aZ09');
1271 }
1272 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
1273 $newlang = $this->thirdparty->default_lang;
1274 }
1275 if (!empty($newlang)) {
1276 $outputlangs = new Translate("", $conf);
1277 $outputlangs->setDefaultLang($newlang);
1278 }
1279 $model = $this->model_pdf;
1280 $ret = $this->fetch($this->id); // Reload to get new records
1281
1282 $this->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
1283 }
1284 }
1285
1286 return $result;
1287 }
1288
1300 public function getNomUrl($withpicto = 0, $option = '', $maxlen = 0, $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
1301 {
1302 global $db, $conf, $langs, $hookmanager;
1303 global $dolibarr_main_authentication, $dolibarr_main_demo;
1304 global $menumanager;
1305
1306 if (!empty($conf->dol_no_mouse_hover)) {
1307 $notooltip = 1; // Force disable tooltips
1308 }
1309
1310 $result = '';
1311
1312 $label = img_picto('', $this->picto).' <u>'.$langs->trans("Asset").'</u>';
1313 if (isset($this->status)) {
1314 $label .= ' '.$this->getLibStatut(5);
1315 }
1316 $label .= '<br>';
1317 $label .= '<b>'.$langs->trans('Ref').':</b> '.$this->ref;
1318
1319 $url = dol_buildpath('/asset/card.php', 1).'?id='.$this->id;
1320
1321 if ($option != 'nolink') {
1322 // Add param to save lastsearch_values or not
1323 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1324 if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
1325 $add_save_lastsearch_values = 1;
1326 }
1327 if ($add_save_lastsearch_values) {
1328 $url .= '&save_lastsearch_values=1';
1329 }
1330 }
1331
1332 $linkclose = '';
1333 if (empty($notooltip)) {
1334 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
1335 $label = $langs->trans("ShowAsset");
1336 $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
1337 }
1338 $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
1339 $linkclose .= ' class="classfortooltip'.($morecss ? ' '.$morecss : '').'"';
1340 } else {
1341 $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
1342 }
1343
1344 if ($option == 'nolink') {
1345 $linkstart = '<span';
1346 } else {
1347 $linkstart = '<a href="'.$url.'"';
1348 }
1349 $linkstart .= $linkclose.'>';
1350 if ($option == 'nolink') {
1351 $linkend = '</span>';
1352 } else {
1353 $linkend = '</a>';
1354 }
1355
1356 $result .= $linkstart;
1357
1358 if (empty($this->showphoto_on_popup)) {
1359 if ($withpicto) {
1360 $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);
1361 }
1362 } else {
1363 if ($withpicto) {
1364 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1365
1366 list($class, $module) = explode('@', $this->picto);
1367 $upload_dir = $conf->$module->multidir_output[$conf->entity]."/$class/".dol_sanitizeFileName($this->ref);
1368 $filearray = dol_dir_list($upload_dir, "files");
1369 $filename = $filearray[0]['name'];
1370 if (!empty($filename)) {
1371 $pospoint = strpos($filearray[0]['name'], '.');
1372
1373 $pathtophoto = $class.'/'.$this->ref.'/thumbs/'.substr($filename, 0, $pospoint).'_mini'.substr($filename, $pospoint);
1374 if (!getDolGlobalString(strtoupper($module.'_'.$class).'_FORMATLISTPHOTOSASUSERS')) {
1375 $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>';
1376 } else {
1377 $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>';
1378 }
1379
1380 $result .= '</div>';
1381 } else {
1382 $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);
1383 }
1384 }
1385 }
1386
1387 if ($withpicto != 2) {
1388 $name = $this->ref;
1389 if ($option == 'label') {
1390 $name = $this->label;
1391 } elseif ($option == 'with_label') {
1392 $name .= ' - ' . $this->label;
1393 }
1394 $result .= dol_escape_htmltag($maxlen ? dol_trunc($name, $maxlen) : $name);
1395 }
1396
1397 $result .= $linkend;
1398 //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
1399
1400 global $action;
1401 $hookmanager->initHooks(array($this->element . 'dao'));
1402 $parameters = array('id' => $this->id, 'getnomurl' => &$result);
1403 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1404 if ($reshook > 0) {
1405 $result = $hookmanager->resPrint;
1406 } else {
1407 $result .= $hookmanager->resPrint;
1408 }
1409 return $result;
1410 }
1411
1418 public function getLabelStatus($mode = 0)
1419 {
1420 return $this->LibStatut($this->status, $mode);
1421 }
1422
1429 public function getLibStatut($mode = 0)
1430 {
1431 return $this->LibStatut($this->status, $mode);
1432 }
1433
1434 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1442 public function LibStatut($status, $mode = 0)
1443 {
1444 // phpcs:enable
1445 if (empty($this->labelStatus) || empty($this->labelStatusShort)) {
1446 global $langs;
1447 //$langs->load("assets");
1448 $this->labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('AssetInProgress');
1449 $this->labelStatus[self::STATUS_DISPOSED] = $langs->transnoentitiesnoconv('AssetDisposed');
1450 $this->labelStatusShort[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('AssetInProgress');
1451 $this->labelStatusShort[self::STATUS_DISPOSED] = $langs->transnoentitiesnoconv('AssetDisposed');
1452 }
1453
1454 $statusType = 'status4';
1455 if ($status == self::STATUS_DISPOSED) {
1456 $statusType = 'status6';
1457 }
1458
1459 return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode);
1460 }
1461
1468 public function info($id)
1469 {
1470 $sql = "SELECT rowid, date_creation as datec, tms as datem,";
1471 $sql .= " fk_user_creat, fk_user_modif";
1472 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as t";
1473 $sql .= " WHERE t.rowid = ".((int) $id);
1474
1475 $result = $this->db->query($sql);
1476 if ($result) {
1477 if ($this->db->num_rows($result)) {
1478 $obj = $this->db->fetch_object($result);
1479 $this->id = $obj->rowid;
1480
1481 $this->user_creation_id = $obj->fk_user_creat;
1482 $this->user_modification_id = $obj->fk_user_modif;
1483 $this->date_creation = $this->db->jdate($obj->datec);
1484 $this->date_modification = $this->db->jdate($obj->datem);
1485 }
1486
1487 $this->db->free($result);
1488 } else {
1489 dol_print_error($this->db);
1490 }
1491 }
1492
1499 public function initAsSpecimen()
1500 {
1501 // Set here init that are not commonf fields
1502 // $this->property1 = ...
1503 // $this->property2 = ...
1504
1505 return $this->initAsSpecimenCommon();
1506 }
1507
1513 public function getLinesArray()
1514 {
1515 $this->lines = array();
1516
1517 return $this->lines;
1518 }
1519
1525 public function getNextNumRef()
1526 {
1527 global $langs, $conf;
1528 $langs->load("assets");
1529
1530 if (!getDolGlobalString('ASSET_ASSET_ADDON')) {
1531 $conf->global->ASSET_ASSET_ADDON = 'mod_asset_standard';
1532 }
1533
1534 if (getDolGlobalString('ASSET_ASSET_ADDON')) {
1535 $mybool = false;
1536
1537 $file = getDolGlobalString('ASSET_ASSET_ADDON') . ".php";
1538 $classname = getDolGlobalString('ASSET_ASSET_ADDON');
1539
1540 // Include file with class
1541 $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
1542 foreach ($dirmodels as $reldir) {
1543 $dir = dol_buildpath($reldir."core/modules/asset/");
1544
1545 // Load file with numbering class (if found)
1546 $mybool = ((bool) @include_once $dir.$file) || $mybool;
1547 }
1548
1549 if ($mybool === false) {
1550 dol_print_error(null, "Failed to include file ".$file);
1551 return '';
1552 }
1553
1554 if (class_exists($classname)) {
1555 $obj = new $classname();
1556 $numref = $obj->getNextValue($this);
1557
1558 if ($numref != '' && $numref != '-1') {
1559 return $numref;
1560 } else {
1561 $this->error = $obj->error;
1562 //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error);
1563 return "";
1564 }
1565 } else {
1566 print $langs->trans("Error")." ".$langs->trans("ClassNotFound").' '.$classname;
1567 return "";
1568 }
1569 } else {
1570 print $langs->trans("ErrorNumberingModuleNotSetup", $this->element);
1571 return "";
1572 }
1573 }
1574}
getCurrentPeriodOfFiscalYear($db, $conf, $from_time=null)
Get current period of fiscal year.
print $langs trans("AuditedSecurityEvents").'</strong >< span class="opacitymedium"></span >< br > status
Or an array listing all the potential status of the object: array: int of the status => translated la...
Definition security.php:637
$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.
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.
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.
dol_get_first_day($year, $month=1, $gm=false)
Return GMT time for first day of a month or year.
Definition date.lib.php:595
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:614
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 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...