dolibarr 20.0.0
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 // Get depreciation options
818 //---------------------------
819 require_once DOL_DOCUMENT_ROOT . '/asset/class/assetdepreciationoptions.class.php';
820 $options = new AssetDepreciationOptions($this->db);
821 $result = $options->fetchDeprecationOptions($this->id);
822 if ($result < 0) {
823 $this->error = $options->error;
824 $this->errors = $options->errors;
825 return -1;
826 }
827
828 // Get accountancy codes
829 //---------------------------
830 require_once DOL_DOCUMENT_ROOT . '/asset/class/assetaccountancycodes.class.php';
831 $accountancy_codes = new AssetAccountancyCodes($this->db);
832 $result = $accountancy_codes->fetchAccountancyCodes($this->id);
833 if ($result < 0) {
834 $this->error = $accountancy_codes->error;
835 $this->errors = $accountancy_codes->errors;
836 return -1;
837 }
838
839 $this->db->begin();
840
841 // Delete old lines
842 $modes = array();
843 foreach ($options->deprecation_options as $mode_key => $fields) {
844 $modes[$mode_key] = $this->db->escape($mode_key);
845 }
846 $sql = "DELETE FROM " . MAIN_DB_PREFIX . "asset_depreciation";
847 $sql .= " WHERE fk_asset = " . (int) $this->id;
848 $sql .= " AND depreciation_mode NOT IN ('" . $this->db->sanitize(implode("', '", $modes)) . "')";
849
850 $resql = $this->db->query($sql);
851 if (!$resql) {
852 $this->errors[] = $langs->trans('AssetErrorClearDepreciationLines') . ': ' . $this->db->lasterror();
853 $error++;
854 }
855
856 if (!$error) {
857 // Get fiscal period
858 require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
859 require_once DOL_DOCUMENT_ROOT . '/core/lib/accounting.lib.php';
860 $dates = getCurrentPeriodOfFiscalYear($this->db, $conf, $this->date_start > $this->date_acquisition ? $this->date_start : $this->date_acquisition);
861 $init_fiscal_period_start = $dates['date_start'];
862 $init_fiscal_period_end = $dates['date_end'];
863 if (empty($init_fiscal_period_start) || empty($init_fiscal_period_end)) {
864 $pastmonthyear = $dates['pastmonthyear'];
865 $pastmonth = $dates['pastmonth'];
866 $init_fiscal_period_start = dol_get_first_day($pastmonthyear, $pastmonth, false);
867 $init_fiscal_period_end = dol_get_last_day($pastmonthyear, $pastmonth, false);
868 }
869
870 foreach ($options->deprecation_options as $mode_key => $fields) {
871 // Get last depreciation lines save in bookkeeping
872 //-----------------------------------------------------
873
874 // Old request with 'WITH'
875 /*
876 $sql = "WITH in_accounting_bookkeeping(fk_docdet) AS (";
877 $sql .= " SELECT fk_docdet";
878 $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping";
879 $sql .= " WHERE doc_type = 'asset'";
880 $sql .= ")";
881 $sql .= "SELECT ad.depreciation_date, ad.cumulative_depreciation_ht";
882 $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
883 $sql .= " LEFT JOIN in_accounting_bookkeeping as iab ON iab.fk_docdet = ad.rowid";
884 $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
885 $sql .= " AND ad.depreciation_mode = '" . $this->db->escape($mode_key) . "'";
886 $sql .= " AND iab.fk_docdet IS NOT NULL";
887 $sql .= " ORDER BY ad.depreciation_date DESC";
888 $sql .= " LIMIT 1";
889 */
890
891 $sql = "SELECT ad.depreciation_date, ad.cumulative_depreciation_ht";
892 $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
893 $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";
894 $sql .= " WHERE ad.fk_asset = " . (int) $this->id;
895 $sql .= " AND ad.depreciation_mode = '" . $this->db->escape($mode_key) . "'";
896 $sql .= " AND iab.fk_docdet IS NOT NULL";
897 $sql .= " ORDER BY ad.depreciation_date DESC";
898 $sql .= " LIMIT 1";
899
900 $resql = $this->db->query($sql);
901 if (!$resql) {
902 $this->errors[] = $langs->trans('AssetErrorFetchMaxDepreciationDateForMode', $mode_key) . ': ' . $this->db->lasterror();
903 $error++;
904 break;
905 }
906 $last_depreciation_date = '';
907 $last_cumulative_depreciation_ht = $this->reversal_amount_ht;
908 if ($obj = $this->db->fetch_object($resql)) {
909 $last_depreciation_date = $this->db->jdate($obj->depreciation_date);
910 $last_cumulative_depreciation_ht = $obj->cumulative_depreciation_ht;
911 }
912
913 // Set last cumulative depreciation
914 $sql = "UPDATE " . MAIN_DB_PREFIX . $options->deprecation_options_fields[$mode_key]['table'];
915 $sql .= " SET total_amount_last_depreciation_ht = " . (empty($last_cumulative_depreciation_ht) ? 0 : $last_cumulative_depreciation_ht);
916 $sql .= " WHERE fk_asset = " . (int) $this->id;
917 $resql = $this->db->query($sql);
918 if (!$resql) {
919 $this->errors[] = $langs->trans('AssetErrorSetLastCumulativeDepreciation') . ': ' . $this->db->lasterror();
920 $error++;
921 break;
922 }
923
924 // Delete old lines
925 $sql = "DELETE " . MAIN_DB_PREFIX . "asset_depreciation FROM " . MAIN_DB_PREFIX . "asset_depreciation";
926 $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";
927 $sql .= " WHERE " . MAIN_DB_PREFIX . "asset_depreciation.fk_asset = " . (int) $this->id;
928 $sql .= " AND " . MAIN_DB_PREFIX . "asset_depreciation.depreciation_mode = '" . $this->db->escape($mode_key) . "'";
929 $sql .= " AND ab.fk_docdet IS NULL";
930 if ($last_depreciation_date !== "") {
931 $sql .= " AND " . MAIN_DB_PREFIX . "asset_depreciation.ref != ''";
932 }
933 $resql = $this->db->query($sql);
934 if (!$resql) {
935 $this->errors[] = $langs->trans('AssetErrorClearDepreciationLines') . ': ' . $this->db->lasterror();
936 $error++;
937 break;
938 }
939
940 // Get depreciation period
941 $depreciation_date_start = $this->date_start > $this->date_acquisition ? $this->date_start : $this->date_acquisition;
942 $depreciation_date_end = dol_time_plus_duree($depreciation_date_start, $fields['duration'], $fields['duration_type'] == 1 ? 'm' : ($fields['duration_type'] == 2 ? 'd' : 'y'));
943 $depreciation_amount = $fields['amount_base_depreciation_ht'];
944 if ($fields['duration_type'] == 2) { // Daily
945 $fiscal_period_start = $depreciation_date_start;
946 $fiscal_period_end = $depreciation_date_start;
947 } elseif ($fields['duration_type'] == 1) { // Monthly
948 $date_temp = dol_getdate($depreciation_date_start);
949 $fiscal_period_start = dol_get_first_day($date_temp['year'], $date_temp['mon'], false);
950 $fiscal_period_end = dol_get_last_day($date_temp['year'], $date_temp['mon'], false);
951 } else { // Annually
952 $fiscal_period_start = $init_fiscal_period_start;
953 $fiscal_period_end = $init_fiscal_period_end;
954 }
955 $cumulative_depreciation_ht = $last_cumulative_depreciation_ht;
956 $depreciation_period_amount = $depreciation_amount - $this->reversal_amount_ht;
957 $start_date = $depreciation_date_start;
958 $disposal_date = isset($this->disposal_date) && $this->disposal_date !== "" ? $this->disposal_date : "";
959 $finish_date = $disposal_date !== "" ? $disposal_date : $depreciation_date_end;
960 $accountancy_code_depreciation_debit_key = $accountancy_codes->accountancy_codes_fields[$mode_key]['depreciation_debit'];
961 $accountancy_code_depreciation_debit = $accountancy_codes->accountancy_codes[$mode_key][$accountancy_code_depreciation_debit_key];
962 $accountancy_code_depreciation_credit_key = $accountancy_codes->accountancy_codes_fields[$mode_key]['depreciation_credit'];
963 $accountancy_code_credit = $accountancy_codes->accountancy_codes[$mode_key][$accountancy_code_depreciation_credit_key];
964
965 // Reversal depreciation line
966 //-----------------------------------------------------
967 if ($last_depreciation_date === "" && ($depreciation_date_start < $fiscal_period_start || is_numeric($this->reversal_date))) {
968 if (is_numeric($this->reversal_date)) {
969 if ($this->reversal_date < $fiscal_period_start) {
970 $this->errors[] = $langs->trans('AssetErrorReversalDateNotGreaterThanCurrentBeginFiscalDateForMode', $mode_key);
971 $error++;
972 break;
973 }
974
975 if (empty($this->reversal_amount_ht)) {
976 $this->errors[] = $langs->trans('AssetErrorReversalAmountNotProvidedForMode', $mode_key);
977 $error++;
978 break;
979 }
980
981 $start_date = $this->reversal_date;
982 $result = $this->addDepreciationLine($mode_key, '', $start_date, $this->reversal_amount_ht, $this->reversal_amount_ht, $accountancy_code_depreciation_debit, $accountancy_code_credit);
983 if ($result < 0) {
984 $error++;
985 break;
986 }
987 } else {
988 $this->errors[] = $langs->trans('AssetErrorReversalDateNotProvidedForMode', $mode_key);
989 $error++;
990 break;
991 }
992 }
993
994 // futures depreciation lines
995 //-----------------------------------------------------
996 $nb_days_in_year = getDolGlobalInt('ASSET_DEPRECIATION_DURATION_PER_YEAR', 365);
997 $nb_days_in_month = getDolGlobalInt('ASSET_DEPRECIATION_DURATION_PER_MONTH', 30);
998 $period_amount = (float) price2num($depreciation_period_amount / $fields['duration'], 'MT');
999 $first_period_found = false;
1000 // TODO fix declaration of $begin_period
1001 $first_period_date = isset($begin_period) && $begin_period > $fiscal_period_start ? $begin_period : $fiscal_period_start;
1002
1003 $ref_date_format = "%Y" . ($fields['duration_type'] == 1 || $fields['duration_type'] == 2 ? '-%m' : '') . ($fields['duration_type'] == 2 ? '-%d' : '');
1004
1005 // Loop security
1006 $idx_loop = 0;
1007 $max_loop = $fields['duration'] + 2;
1008 do {
1009 // Loop security
1010 $idx_loop++;
1011 if ($idx_loop > $max_loop) {
1012 break;
1013 }
1014
1015 if ($last_depreciation_date < $fiscal_period_end && ($first_period_date <= $start_date || $first_period_found)) {
1016 // Disposal not depreciated
1017 if ($fiscal_period_start <= $disposal_date && $disposal_date <= $fiscal_period_end && empty($this->disposal_depreciated)) {
1018 break;
1019 }
1020
1021 $first_period_found = true;
1022
1023 $period_begin = dol_print_date($fiscal_period_start, $ref_date_format);
1024 $period_end = dol_print_date($fiscal_period_end, $ref_date_format);
1025 $ref = $period_begin . ($period_begin != $period_end ? ' - ' . $period_end : '');
1026 if ($fiscal_period_start <= $disposal_date && $disposal_date <= $fiscal_period_end) {
1027 $ref .= ' - ' . $langs->transnoentitiesnoconv('AssetDisposal');
1028 }
1029
1030 $begin_date = $fiscal_period_start < $start_date && $start_date <= $fiscal_period_end ? $start_date : $fiscal_period_start;
1031 $end_date = $fiscal_period_start < $finish_date && $finish_date <= $fiscal_period_end ? $finish_date : $fiscal_period_end;
1032 if ($fields['duration_type'] == 2) { // Daily
1033 $depreciation_ht = $period_amount;
1034 } elseif ($fields['duration_type'] == 1) { // Monthly
1035 $nb_days = min($nb_days_in_month, num_between_day($begin_date, $end_date, 1));
1036 if ($nb_days >= 28) {
1037 $date_temp = dol_getdate($begin_date);
1038 if ($date_temp['mon'] == 2) {
1039 $nb_days = 30;
1040 }
1041 }
1042 $depreciation_ht = (float) price2num($period_amount * $nb_days / $nb_days_in_month, 'MT');
1043 } else { // Annually
1044 $nb_days = min($nb_days_in_year, num_between_day($begin_date, $end_date, 1));
1045 $depreciation_ht = (float) price2num($period_amount * $nb_days / $nb_days_in_year, 'MT');
1046 }
1047
1048 if ($fiscal_period_start <= $depreciation_date_end && $depreciation_date_end <= $fiscal_period_end) { // last period
1049 $depreciation_ht = (float) price2num($depreciation_amount - $cumulative_depreciation_ht, 'MT');
1050 $cumulative_depreciation_ht = $depreciation_amount;
1051 } else {
1052 $cumulative_depreciation_ht += $depreciation_ht;
1053 }
1054
1055 $result = $this->addDepreciationLine($mode_key, $ref, $fiscal_period_end, $depreciation_ht, $cumulative_depreciation_ht, $accountancy_code_depreciation_debit, $accountancy_code_credit);
1056 if ($result < 0) {
1057 $error++;
1058 break;
1059 }
1060 }
1061
1062 // Next fiscal period (+1 day/month/year)
1063 $fiscal_period_start = dol_time_plus_duree($fiscal_period_end, 1, 'd');
1064 if ($fields['duration_type'] == 2) { // Daily
1065 $fiscal_period_end = $fiscal_period_start;
1066 } elseif ($fields['duration_type'] == 1) { // Monthly
1067 $fiscal_period_end = dol_time_plus_duree(dol_time_plus_duree($fiscal_period_start, 1, 'm'), -1, 'd');
1068 } else { // Annually
1069 $fiscal_period_end = dol_time_plus_duree(dol_time_plus_duree($fiscal_period_start, 1, 'y'), -1, 'd');
1070 }
1071 $last_period_date = $disposal_date !== "" && $disposal_date < $depreciation_date_end ? $disposal_date : $depreciation_date_end;
1072 } while ($fiscal_period_start < $last_period_date);
1073
1074 if ($error) {
1075 break;
1076 }
1077 }
1078 }
1079
1080 if ($error) {
1081 $this->db->rollback();
1082 return -1;
1083 } else {
1084 $this->db->commit();
1085 return 1;
1086 }
1087 }
1088
1095 public function setLastCumulativeDepreciation($asset_depreciation_id)
1096 {
1097 global $langs;
1098 $langs->load('assets');
1099
1100 // Clean parameters
1101 $asset_depreciation_id = $asset_depreciation_id > 0 ? $asset_depreciation_id : 0;
1102
1103 // Check parameters
1104 $error = 0;
1105 if (empty($asset_depreciation_id)) {
1106 $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("AssetDepreciation") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
1107 $error++;
1108 }
1109 if ($error) {
1110 return -1;
1111 }
1112
1113 $this->db->begin();
1114
1115 require_once DOL_DOCUMENT_ROOT . '/asset/class/assetdepreciationoptions.class.php';
1116 $options = new AssetDepreciationOptions($this->db);
1117
1118 // Get last depreciation lines save in bookkeeping
1119 //-----------------------------------------------------
1120 $sql = "SELECT fk_asset, depreciation_mode, cumulative_depreciation_ht";
1121 $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation";
1122 $sql .= " WHERE rowid = " . (int) $asset_depreciation_id;
1123 $resql = $this->db->query($sql);
1124 if (!$resql) {
1125 $this->errors[] = $langs->trans('AssetErrorFetchCumulativeDepreciation') . ': ' . $this->db->lasterror();
1126 $error++;
1127 } else {
1128 if ($obj = $this->db->fetch_object($resql)) {
1129 $mode_key = $obj->depreciation_mode;
1130 if (!empty($options->deprecation_options_fields[$mode_key])) {
1131 $sql = "UPDATE " . MAIN_DB_PREFIX . $options->deprecation_options_fields[$mode_key]['table'];
1132 $sql .= " SET total_amount_last_depreciation_ht = " . $obj->cumulative_depreciation_ht;
1133 $sql .= " WHERE fk_asset = " . (int) $obj->fk_asset;
1134 $resql = $this->db->query($sql);
1135 if (!$resql) {
1136 $this->errors[] = $langs->trans('AssetErrorSetLastCumulativeDepreciation') . ': ' . $this->db->lasterror();
1137 $error++;
1138 }
1139 }
1140 }
1141 }
1142
1143 if ($error) {
1144 $this->db->rollback();
1145 return -1;
1146 } else {
1147 $this->db->commit();
1148 return 1;
1149 }
1150 }
1151
1160 public function dispose($user, $disposal_invoice_id, $notrigger = 0)
1161 {
1162 global $conf, $langs;
1163
1164 // Protection
1165 if ($this->status != self::STATUS_DRAFT || $this->status == self::STATUS_DISPOSED) {
1166 return 0;
1167 }
1168
1169 $this->db->begin();
1170
1171 $required_fields = array('disposal_date', 'disposal_date', 'fk_disposal_type');
1172 foreach ($required_fields as $field) {
1173 $this->fields[$field]['notnull'] = 1;
1174 }
1175 $result = $this->update($user, 1);
1176 foreach ($required_fields as $field) {
1177 $this->fields[$field]['notnull'] = 0;
1178 }
1179 if ($result > 0) {
1180 if ($disposal_invoice_id > 0) {
1181 $this->add_object_linked('facture', $disposal_invoice_id);
1182 }
1183 $result = $this->setStatusCommon($user, self::STATUS_DISPOSED, $notrigger, 'ASSET_DISPOSED');
1184 }
1185 if ($result > 0) {
1186 $result = $this->calculationDepreciation();
1187 }
1188
1189 if ($result < 0) {
1190 $this->db->rollback();
1191 } else {
1192 $this->db->commit();
1193 }
1194
1195 // Define output language
1196 if ($result > 0 && !getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
1197 if (method_exists($this, 'generateDocument')) {
1198 global $hidedetails, $hidedesc, $hideref;
1199 $outputlangs = $langs;
1200 $newlang = '';
1201 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
1202 $newlang = GETPOST('lang_id', 'aZ09');
1203 }
1204 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
1205 $newlang = $this->thirdparty->default_lang;
1206 }
1207 if (!empty($newlang)) {
1208 $outputlangs = new Translate("", $conf);
1209 $outputlangs->setDefaultLang($newlang);
1210 }
1211 $model = $this->model_pdf;
1212 $ret = $this->fetch($this->id); // Reload to get new records
1213
1214 $this->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
1215 }
1216 }
1217
1218 return $result;
1219 }
1220
1228 public function reopen($user, $notrigger = 0)
1229 {
1230 global $conf, $langs;
1231
1232 // Protection
1233 if ($this->status != self::STATUS_DISPOSED || $this->status == self::STATUS_DRAFT) {
1234 return 0;
1235 }
1236
1237
1238 $this->db->begin();
1239
1240 $this->disposal_date = null;
1241 $this->disposal_amount_ht = null;
1242 $this->fk_disposal_type = null;
1243 $this->disposal_depreciated = null;
1244 $this->disposal_subject_to_vat = null;
1245 $result = $this->update($user, 1);
1246 if ($result > 0) {
1247 $this->deleteObjectLinked(null, 'facture');
1248 $result = $this->setStatusCommon($user, self::STATUS_DRAFT, $notrigger, 'ASSET_REOPEN');
1249 }
1250 if ($result > 0) {
1251 $result = $this->calculationDepreciation();
1252 }
1253
1254 if ($result < 0) {
1255 $this->db->rollback();
1256 } else {
1257 $this->db->commit();
1258 }
1259
1260 // Define output language
1261 if ($result > 0 && !getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
1262 if (method_exists($this, 'generateDocument')) {
1263 global $hidedetails, $hidedesc, $hideref;
1264 $outputlangs = $langs;
1265 $newlang = '';
1266 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
1267 $newlang = GETPOST('lang_id', 'aZ09');
1268 }
1269 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
1270 $newlang = $this->thirdparty->default_lang;
1271 }
1272 if (!empty($newlang)) {
1273 $outputlangs = new Translate("", $conf);
1274 $outputlangs->setDefaultLang($newlang);
1275 }
1276 $model = $this->model_pdf;
1277 $ret = $this->fetch($this->id); // Reload to get new records
1278
1279 $this->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
1280 }
1281 }
1282
1283 return $result;
1284 }
1285
1297 public function getNomUrl($withpicto = 0, $option = '', $maxlen = 0, $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
1298 {
1299 global $db, $conf, $langs, $hookmanager;
1300 global $dolibarr_main_authentication, $dolibarr_main_demo;
1301 global $menumanager;
1302
1303 if (!empty($conf->dol_no_mouse_hover)) {
1304 $notooltip = 1; // Force disable tooltips
1305 }
1306
1307 $result = '';
1308
1309 $label = img_picto('', $this->picto).' <u>'.$langs->trans("Asset").'</u>';
1310 if (isset($this->status)) {
1311 $label .= ' '.$this->getLibStatut(5);
1312 }
1313 $label .= '<br>';
1314 $label .= '<b>'.$langs->trans('Ref').':</b> '.$this->ref;
1315
1316 $url = dol_buildpath('/asset/card.php', 1).'?id='.$this->id;
1317
1318 if ($option != 'nolink') {
1319 // Add param to save lastsearch_values or not
1320 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1321 if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
1322 $add_save_lastsearch_values = 1;
1323 }
1324 if ($add_save_lastsearch_values) {
1325 $url .= '&save_lastsearch_values=1';
1326 }
1327 }
1328
1329 $linkclose = '';
1330 if (empty($notooltip)) {
1331 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
1332 $label = $langs->trans("ShowAsset");
1333 $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
1334 }
1335 $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
1336 $linkclose .= ' class="classfortooltip'.($morecss ? ' '.$morecss : '').'"';
1337 } else {
1338 $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
1339 }
1340
1341 if ($option == 'nolink') {
1342 $linkstart = '<span';
1343 } else {
1344 $linkstart = '<a href="'.$url.'"';
1345 }
1346 $linkstart .= $linkclose.'>';
1347 if ($option == 'nolink') {
1348 $linkend = '</span>';
1349 } else {
1350 $linkend = '</a>';
1351 }
1352
1353 $result .= $linkstart;
1354
1355 if (empty($this->showphoto_on_popup)) {
1356 if ($withpicto) {
1357 $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);
1358 }
1359 } else {
1360 if ($withpicto) {
1361 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1362
1363 list($class, $module) = explode('@', $this->picto);
1364 $upload_dir = $conf->$module->multidir_output[$conf->entity]."/$class/".dol_sanitizeFileName($this->ref);
1365 $filearray = dol_dir_list($upload_dir, "files");
1366 $filename = $filearray[0]['name'];
1367 if (!empty($filename)) {
1368 $pospoint = strpos($filearray[0]['name'], '.');
1369
1370 $pathtophoto = $class.'/'.$this->ref.'/thumbs/'.substr($filename, 0, $pospoint).'_mini'.substr($filename, $pospoint);
1371 if (!getDolGlobalString(strtoupper($module.'_'.$class).'_FORMATLISTPHOTOSASUSERS')) {
1372 $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>';
1373 } else {
1374 $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>';
1375 }
1376
1377 $result .= '</div>';
1378 } else {
1379 $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);
1380 }
1381 }
1382 }
1383
1384 if ($withpicto != 2) {
1385 $name = $this->ref;
1386 if ($option == 'label') {
1387 $name = $this->label;
1388 } elseif ($option == 'with_label') {
1389 $name .= ' - ' . $this->label;
1390 }
1391 $result .= dol_escape_htmltag($maxlen ? dol_trunc($name, $maxlen) : $name);
1392 }
1393
1394 $result .= $linkend;
1395 //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
1396
1397 global $action;
1398 $hookmanager->initHooks(array($this->element . 'dao'));
1399 $parameters = array('id' => $this->id, 'getnomurl' => &$result);
1400 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1401 if ($reshook > 0) {
1402 $result = $hookmanager->resPrint;
1403 } else {
1404 $result .= $hookmanager->resPrint;
1405 }
1406 return $result;
1407 }
1408
1415 public function getLabelStatus($mode = 0)
1416 {
1417 return $this->LibStatut($this->status, $mode);
1418 }
1419
1426 public function getLibStatut($mode = 0)
1427 {
1428 return $this->LibStatut($this->status, $mode);
1429 }
1430
1431 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1439 public function LibStatut($status, $mode = 0)
1440 {
1441 // phpcs:enable
1442 if (empty($this->labelStatus) || empty($this->labelStatusShort)) {
1443 global $langs;
1444 //$langs->load("assets");
1445 $this->labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('AssetInProgress');
1446 $this->labelStatus[self::STATUS_DISPOSED] = $langs->transnoentitiesnoconv('AssetDisposed');
1447 $this->labelStatusShort[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('AssetInProgress');
1448 $this->labelStatusShort[self::STATUS_DISPOSED] = $langs->transnoentitiesnoconv('AssetDisposed');
1449 }
1450
1451 $statusType = 'status4';
1452 if ($status == self::STATUS_DISPOSED) {
1453 $statusType = 'status6';
1454 }
1455
1456 return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode);
1457 }
1458
1465 public function info($id)
1466 {
1467 $sql = "SELECT rowid, date_creation as datec, tms as datem,";
1468 $sql .= " fk_user_creat, fk_user_modif";
1469 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as t";
1470 $sql .= " WHERE t.rowid = ".((int) $id);
1471
1472 $result = $this->db->query($sql);
1473 if ($result) {
1474 if ($this->db->num_rows($result)) {
1475 $obj = $this->db->fetch_object($result);
1476 $this->id = $obj->rowid;
1477
1478 $this->user_creation_id = $obj->fk_user_creat;
1479 $this->user_modification_id = $obj->fk_user_modif;
1480 $this->date_creation = $this->db->jdate($obj->datec);
1481 $this->date_modification = $this->db->jdate($obj->datem);
1482 }
1483
1484 $this->db->free($result);
1485 } else {
1486 dol_print_error($this->db);
1487 }
1488 }
1489
1496 public function initAsSpecimen()
1497 {
1498 // Set here init that are not commonf fields
1499 // $this->property1 = ...
1500 // $this->property2 = ...
1501
1502 return $this->initAsSpecimenCommon();
1503 }
1504
1510 public function getLinesArray()
1511 {
1512 $this->lines = array();
1513
1514 return $this->lines;
1515 }
1516
1522 public function getNextNumRef()
1523 {
1524 global $langs, $conf;
1525 $langs->load("assets");
1526
1527 if (!getDolGlobalString('ASSET_ASSET_ADDON')) {
1528 $conf->global->ASSET_ASSET_ADDON = 'mod_asset_standard';
1529 }
1530
1531 if (getDolGlobalString('ASSET_ASSET_ADDON')) {
1532 $mybool = false;
1533
1534 $file = getDolGlobalString('ASSET_ASSET_ADDON') . ".php";
1535 $classname = getDolGlobalString('ASSET_ASSET_ADDON');
1536
1537 // Include file with class
1538 $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
1539 foreach ($dirmodels as $reldir) {
1540 $dir = dol_buildpath($reldir."core/modules/asset/");
1541
1542 // Load file with numbering class (if found)
1543 $mybool = ((bool) @include_once $dir.$file) || $mybool;
1544 }
1545
1546 if ($mybool === false) {
1547 dol_print_error(null, "Failed to include file ".$file);
1548 return '';
1549 }
1550
1551 if (class_exists($classname)) {
1552 $obj = new $classname();
1553 $numref = $obj->getNextValue($this);
1554
1555 if ($numref != '' && $numref != '-1') {
1556 return $numref;
1557 } else {
1558 $this->error = $obj->error;
1559 //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error);
1560 return "";
1561 }
1562 } else {
1563 print $langs->trans("Error")." ".$langs->trans("ClassNotFound").' '.$classname;
1564 return "";
1565 }
1566 } else {
1567 print $langs->trans("ErrorNumberingModuleNotSetup", $this->element);
1568 return "";
1569 }
1570 }
1571}
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:636
$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: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:124
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($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...