dolibarr 20.0.2
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 " . MAIN_DB_PREFIX . "asset_depreciation FROM " . MAIN_DB_PREFIX . "asset_depreciation";
930 $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";
931 $sql .= " WHERE " . MAIN_DB_PREFIX . "asset_depreciation.fk_asset = " . (int) $this->id;
932 $sql .= " AND " . MAIN_DB_PREFIX . "asset_depreciation.depreciation_mode = '" . $this->db->escape($mode_key) . "'";
933 $sql .= " AND ab.fk_docdet IS NULL";
934 if ($last_depreciation_date !== "") {
935 $sql .= " AND " . MAIN_DB_PREFIX . "asset_depreciation.ref != ''";
936 }
937 $resql = $this->db->query($sql);
938 if (!$resql) {
939 $this->errors[] = $langs->trans('AssetErrorClearDepreciationLines') . ': ' . $this->db->lasterror();
940 $error++;
941 break;
942 }
943
944 // Get depreciation period
945 $depreciation_date_start = $this->date_start > $this->date_acquisition ? $this->date_start : $this->date_acquisition;
946 $depreciation_date_end = dol_time_plus_duree($depreciation_date_start, $fields['duration'], $fields['duration_type'] == 1 ? 'm' : ($fields['duration_type'] == 2 ? 'd' : 'y'));
947 $depreciation_amount = $fields['amount_base_depreciation_ht'];
948 if ($fields['duration_type'] == 2) { // Daily
949 $fiscal_period_start = $depreciation_date_start;
950 $fiscal_period_end = $depreciation_date_start;
951 } elseif ($fields['duration_type'] == 1) { // Monthly
952 $date_temp = dol_getdate($depreciation_date_start);
953 $fiscal_period_start = dol_get_first_day($date_temp['year'], $date_temp['mon'], false);
954 $fiscal_period_end = dol_get_last_day($date_temp['year'], $date_temp['mon'], false);
955 } else { // Annually
956 $fiscal_period_start = $init_fiscal_period_start;
957 $fiscal_period_end = $init_fiscal_period_end;
958 }
959 $cumulative_depreciation_ht = $last_cumulative_depreciation_ht;
960 $depreciation_period_amount = $depreciation_amount - $this->reversal_amount_ht;
961 $start_date = $depreciation_date_start;
962 $disposal_date = isset($this->disposal_date) && $this->disposal_date !== "" ? $this->disposal_date : "";
963 $finish_date = $disposal_date !== "" ? $disposal_date : $depreciation_date_end;
964 $accountancy_code_depreciation_debit_key = $accountancy_codes->accountancy_codes_fields[$mode_key]['depreciation_debit'];
965 $accountancy_code_depreciation_debit = $accountancy_codes->accountancy_codes[$mode_key][$accountancy_code_depreciation_debit_key];
966 $accountancy_code_depreciation_credit_key = $accountancy_codes->accountancy_codes_fields[$mode_key]['depreciation_credit'];
967 $accountancy_code_credit = $accountancy_codes->accountancy_codes[$mode_key][$accountancy_code_depreciation_credit_key];
968
969 // Reversal depreciation line
970 //-----------------------------------------------------
971 if ($last_depreciation_date === "" && ($depreciation_date_start < $fiscal_period_start || is_numeric($this->reversal_date))) {
972 if (is_numeric($this->reversal_date)) {
973 if ($this->reversal_date < $fiscal_period_start) {
974 $this->errors[] = $langs->trans('AssetErrorReversalDateNotGreaterThanCurrentBeginFiscalDateForMode', $mode_key);
975 $error++;
976 break;
977 }
978
979 if (empty($this->reversal_amount_ht)) {
980 $this->errors[] = $langs->trans('AssetErrorReversalAmountNotProvidedForMode', $mode_key);
981 $error++;
982 break;
983 }
984
985 $start_date = $this->reversal_date;
986 $result = $this->addDepreciationLine($mode_key, '', $start_date, $this->reversal_amount_ht, $this->reversal_amount_ht, $accountancy_code_depreciation_debit, $accountancy_code_credit);
987 if ($result < 0) {
988 $error++;
989 break;
990 }
991 } else {
992 $this->errors[] = $langs->trans('AssetErrorReversalDateNotProvidedForMode', $mode_key);
993 $error++;
994 break;
995 }
996 }
997
998 // futures depreciation lines
999 //-----------------------------------------------------
1000 $nb_days_in_year = getDolGlobalInt('ASSET_DEPRECIATION_DURATION_PER_YEAR', 365);
1001 $nb_days_in_month = getDolGlobalInt('ASSET_DEPRECIATION_DURATION_PER_MONTH', 30);
1002 $period_amount = (float) price2num($depreciation_period_amount / $fields['duration'], 'MT');
1003 $first_period_found = false;
1004 // TODO fix declaration of $begin_period
1005 $first_period_date = isset($begin_period) && $begin_period > $fiscal_period_start ? $begin_period : $fiscal_period_start;
1006
1007 $ref_date_format = "%Y" . ($fields['duration_type'] == 1 || $fields['duration_type'] == 2 ? '-%m' : '') . ($fields['duration_type'] == 2 ? '-%d' : '');
1008
1009 // Loop security
1010 $idx_loop = 0;
1011 $max_loop = $fields['duration'] + 2;
1012 do {
1013 // Loop security
1014 $idx_loop++;
1015 if ($idx_loop > $max_loop) {
1016 break;
1017 }
1018
1019 if ($last_depreciation_date < $fiscal_period_end && ($first_period_date <= $start_date || $first_period_found)) {
1020 // Disposal not depreciated
1021 if ($fiscal_period_start <= $disposal_date && $disposal_date <= $fiscal_period_end && empty($this->disposal_depreciated)) {
1022 break;
1023 }
1024
1025 $first_period_found = true;
1026
1027 $period_begin = dol_print_date($fiscal_period_start, $ref_date_format);
1028 $period_end = dol_print_date($fiscal_period_end, $ref_date_format);
1029 $ref = $period_begin . ($period_begin != $period_end ? ' - ' . $period_end : '');
1030 if ($fiscal_period_start <= $disposal_date && $disposal_date <= $fiscal_period_end) {
1031 $ref .= ' - ' . $langs->transnoentitiesnoconv('AssetDisposal');
1032 }
1033
1034 $begin_date = $fiscal_period_start < $start_date && $start_date <= $fiscal_period_end ? $start_date : $fiscal_period_start;
1035 $end_date = $fiscal_period_start < $finish_date && $finish_date <= $fiscal_period_end ? $finish_date : $fiscal_period_end;
1036 if ($fields['duration_type'] == 2) { // Daily
1037 $depreciation_ht = $period_amount;
1038 } elseif ($fields['duration_type'] == 1) { // Monthly
1039 $nb_days = min($nb_days_in_month, num_between_day($begin_date, $end_date, 1));
1040 if ($nb_days >= 28) {
1041 $date_temp = dol_getdate($begin_date);
1042 if ($date_temp['mon'] == 2) {
1043 $nb_days = 30;
1044 }
1045 }
1046 $depreciation_ht = (float) price2num($period_amount * $nb_days / $nb_days_in_month, 'MT');
1047 } else { // Annually
1048 $nb_days = min($nb_days_in_year, num_between_day($begin_date, $end_date, 1));
1049 $depreciation_ht = (float) price2num($period_amount * $nb_days / $nb_days_in_year, 'MT');
1050 }
1051
1052 if ($fiscal_period_start <= $depreciation_date_end && $depreciation_date_end <= $fiscal_period_end) { // last period
1053 $depreciation_ht = (float) price2num($depreciation_amount - $cumulative_depreciation_ht, 'MT');
1054 $cumulative_depreciation_ht = $depreciation_amount;
1055 } else {
1056 $cumulative_depreciation_ht += $depreciation_ht;
1057 }
1058
1059 $result = $this->addDepreciationLine($mode_key, $ref, $fiscal_period_end, $depreciation_ht, $cumulative_depreciation_ht, $accountancy_code_depreciation_debit, $accountancy_code_credit);
1060 if ($result < 0) {
1061 $error++;
1062 break;
1063 }
1064 }
1065
1066 // Next fiscal period (+1 day/month/year)
1067 $fiscal_period_start = dol_time_plus_duree($fiscal_period_end, 1, 'd');
1068 if ($fields['duration_type'] == 2) { // Daily
1069 $fiscal_period_end = $fiscal_period_start;
1070 } elseif ($fields['duration_type'] == 1) { // Monthly
1071 $fiscal_period_end = dol_time_plus_duree(dol_time_plus_duree($fiscal_period_start, 1, 'm'), -1, 'd');
1072 } else { // Annually
1073 $fiscal_period_end = dol_time_plus_duree(dol_time_plus_duree($fiscal_period_start, 1, 'y'), -1, 'd');
1074 }
1075 $last_period_date = $disposal_date !== "" && $disposal_date < $depreciation_date_end ? $disposal_date : $depreciation_date_end;
1076 } while ($fiscal_period_start < $last_period_date);
1077
1078 if ($error) {
1079 break;
1080 }
1081 }
1082 }
1083
1084 if ($error) {
1085 $this->db->rollback();
1086 return -1;
1087 } else {
1088 $this->db->commit();
1089 return 1;
1090 }
1091 }
1092
1099 public function setLastCumulativeDepreciation($asset_depreciation_id)
1100 {
1101 global $langs;
1102 $langs->load('assets');
1103
1104 // Clean parameters
1105 $asset_depreciation_id = $asset_depreciation_id > 0 ? $asset_depreciation_id : 0;
1106
1107 // Check parameters
1108 $error = 0;
1109 if (empty($asset_depreciation_id)) {
1110 $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("AssetDepreciation") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')');
1111 $error++;
1112 }
1113 if ($error) {
1114 return -1;
1115 }
1116
1117 $this->db->begin();
1118
1119 require_once DOL_DOCUMENT_ROOT . '/asset/class/assetdepreciationoptions.class.php';
1120 $options = new AssetDepreciationOptions($this->db);
1121
1122 // Get last depreciation lines save in bookkeeping
1123 //-----------------------------------------------------
1124 $sql = "SELECT fk_asset, depreciation_mode, cumulative_depreciation_ht";
1125 $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation";
1126 $sql .= " WHERE rowid = " . (int) $asset_depreciation_id;
1127 $resql = $this->db->query($sql);
1128 if (!$resql) {
1129 $this->errors[] = $langs->trans('AssetErrorFetchCumulativeDepreciation') . ': ' . $this->db->lasterror();
1130 $error++;
1131 } else {
1132 if ($obj = $this->db->fetch_object($resql)) {
1133 $mode_key = $obj->depreciation_mode;
1134 if (!empty($options->deprecation_options_fields[$mode_key])) {
1135 $sql = "UPDATE " . MAIN_DB_PREFIX . $options->deprecation_options_fields[$mode_key]['table'];
1136 $sql .= " SET total_amount_last_depreciation_ht = " . $obj->cumulative_depreciation_ht;
1137 $sql .= " WHERE fk_asset = " . (int) $obj->fk_asset;
1138 $resql = $this->db->query($sql);
1139 if (!$resql) {
1140 $this->errors[] = $langs->trans('AssetErrorSetLastCumulativeDepreciation') . ': ' . $this->db->lasterror();
1141 $error++;
1142 }
1143 }
1144 }
1145 }
1146
1147 if ($error) {
1148 $this->db->rollback();
1149 return -1;
1150 } else {
1151 $this->db->commit();
1152 return 1;
1153 }
1154 }
1155
1164 public function dispose($user, $disposal_invoice_id, $notrigger = 0)
1165 {
1166 global $conf, $langs;
1167
1168 // Protection
1169 if ($this->status != self::STATUS_DRAFT || $this->status == self::STATUS_DISPOSED) {
1170 return 0;
1171 }
1172
1173 $this->db->begin();
1174
1175 $required_fields = array('disposal_date', 'disposal_date', 'fk_disposal_type');
1176 foreach ($required_fields as $field) {
1177 $this->fields[$field]['notnull'] = 1;
1178 }
1179 $result = $this->update($user, 1);
1180 foreach ($required_fields as $field) {
1181 $this->fields[$field]['notnull'] = 0;
1182 }
1183 if ($result > 0) {
1184 if ($disposal_invoice_id > 0) {
1185 $this->add_object_linked('facture', $disposal_invoice_id);
1186 }
1187 $result = $this->setStatusCommon($user, self::STATUS_DISPOSED, $notrigger, 'ASSET_DISPOSED');
1188 }
1189 if ($result > 0) {
1190 $result = $this->calculationDepreciation();
1191 }
1192
1193 if ($result < 0) {
1194 $this->db->rollback();
1195 } else {
1196 $this->db->commit();
1197 }
1198
1199 // Define output language
1200 if ($result > 0 && !getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
1201 if (method_exists($this, 'generateDocument')) {
1202 global $hidedetails, $hidedesc, $hideref;
1203 $outputlangs = $langs;
1204 $newlang = '';
1205 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
1206 $newlang = GETPOST('lang_id', 'aZ09');
1207 }
1208 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
1209 $newlang = $this->thirdparty->default_lang;
1210 }
1211 if (!empty($newlang)) {
1212 $outputlangs = new Translate("", $conf);
1213 $outputlangs->setDefaultLang($newlang);
1214 }
1215 $model = $this->model_pdf;
1216 $ret = $this->fetch($this->id); // Reload to get new records
1217
1218 $this->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
1219 }
1220 }
1221
1222 return $result;
1223 }
1224
1232 public function reopen($user, $notrigger = 0)
1233 {
1234 global $conf, $langs;
1235
1236 // Protection
1237 if ($this->status != self::STATUS_DISPOSED || $this->status == self::STATUS_DRAFT) {
1238 return 0;
1239 }
1240
1241
1242 $this->db->begin();
1243
1244 $this->disposal_date = null;
1245 $this->disposal_amount_ht = null;
1246 $this->fk_disposal_type = null;
1247 $this->disposal_depreciated = null;
1248 $this->disposal_subject_to_vat = null;
1249 $result = $this->update($user, 1);
1250 if ($result > 0) {
1251 $this->deleteObjectLinked(null, 'facture');
1252 $result = $this->setStatusCommon($user, self::STATUS_DRAFT, $notrigger, 'ASSET_REOPEN');
1253 }
1254 if ($result > 0) {
1255 $result = $this->calculationDepreciation();
1256 }
1257
1258 if ($result < 0) {
1259 $this->db->rollback();
1260 } else {
1261 $this->db->commit();
1262 }
1263
1264 // Define output language
1265 if ($result > 0 && !getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
1266 if (method_exists($this, 'generateDocument')) {
1267 global $hidedetails, $hidedesc, $hideref;
1268 $outputlangs = $langs;
1269 $newlang = '';
1270 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
1271 $newlang = GETPOST('lang_id', 'aZ09');
1272 }
1273 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
1274 $newlang = $this->thirdparty->default_lang;
1275 }
1276 if (!empty($newlang)) {
1277 $outputlangs = new Translate("", $conf);
1278 $outputlangs->setDefaultLang($newlang);
1279 }
1280 $model = $this->model_pdf;
1281 $ret = $this->fetch($this->id); // Reload to get new records
1282
1283 $this->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
1284 }
1285 }
1286
1287 return $result;
1288 }
1289
1301 public function getNomUrl($withpicto = 0, $option = '', $maxlen = 0, $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
1302 {
1303 global $db, $conf, $langs, $hookmanager;
1304 global $dolibarr_main_authentication, $dolibarr_main_demo;
1305 global $menumanager;
1306
1307 if (!empty($conf->dol_no_mouse_hover)) {
1308 $notooltip = 1; // Force disable tooltips
1309 }
1310
1311 $result = '';
1312
1313 $label = img_picto('', $this->picto).' <u>'.$langs->trans("Asset").'</u>';
1314 if (isset($this->status)) {
1315 $label .= ' '.$this->getLibStatut(5);
1316 }
1317 $label .= '<br>';
1318 $label .= '<b>'.$langs->trans('Ref').':</b> '.$this->ref;
1319
1320 $url = dol_buildpath('/asset/card.php', 1).'?id='.$this->id;
1321
1322 if ($option != 'nolink') {
1323 // Add param to save lastsearch_values or not
1324 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1325 if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
1326 $add_save_lastsearch_values = 1;
1327 }
1328 if ($add_save_lastsearch_values) {
1329 $url .= '&save_lastsearch_values=1';
1330 }
1331 }
1332
1333 $linkclose = '';
1334 if (empty($notooltip)) {
1335 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
1336 $label = $langs->trans("ShowAsset");
1337 $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
1338 }
1339 $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
1340 $linkclose .= ' class="classfortooltip'.($morecss ? ' '.$morecss : '').'"';
1341 } else {
1342 $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
1343 }
1344
1345 if ($option == 'nolink') {
1346 $linkstart = '<span';
1347 } else {
1348 $linkstart = '<a href="'.$url.'"';
1349 }
1350 $linkstart .= $linkclose.'>';
1351 if ($option == 'nolink') {
1352 $linkend = '</span>';
1353 } else {
1354 $linkend = '</a>';
1355 }
1356
1357 $result .= $linkstart;
1358
1359 if (empty($this->showphoto_on_popup)) {
1360 if ($withpicto) {
1361 $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);
1362 }
1363 } else {
1364 if ($withpicto) {
1365 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1366
1367 list($class, $module) = explode('@', $this->picto);
1368 $upload_dir = $conf->$module->multidir_output[$conf->entity]."/$class/".dol_sanitizeFileName($this->ref);
1369 $filearray = dol_dir_list($upload_dir, "files");
1370 $filename = $filearray[0]['name'];
1371 if (!empty($filename)) {
1372 $pospoint = strpos($filearray[0]['name'], '.');
1373
1374 $pathtophoto = $class.'/'.$this->ref.'/thumbs/'.substr($filename, 0, $pospoint).'_mini'.substr($filename, $pospoint);
1375 if (!getDolGlobalString(strtoupper($module.'_'.$class).'_FORMATLISTPHOTOSASUSERS')) {
1376 $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>';
1377 } else {
1378 $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>';
1379 }
1380
1381 $result .= '</div>';
1382 } else {
1383 $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);
1384 }
1385 }
1386 }
1387
1388 if ($withpicto != 2) {
1389 $name = $this->ref;
1390 if ($option == 'label') {
1391 $name = $this->label;
1392 } elseif ($option == 'with_label') {
1393 $name .= ' - ' . $this->label;
1394 }
1395 $result .= dol_escape_htmltag($maxlen ? dol_trunc($name, $maxlen) : $name);
1396 }
1397
1398 $result .= $linkend;
1399 //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
1400
1401 global $action;
1402 $hookmanager->initHooks(array($this->element . 'dao'));
1403 $parameters = array('id' => $this->id, 'getnomurl' => &$result);
1404 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1405 if ($reshook > 0) {
1406 $result = $hookmanager->resPrint;
1407 } else {
1408 $result .= $hookmanager->resPrint;
1409 }
1410 return $result;
1411 }
1412
1419 public function getLabelStatus($mode = 0)
1420 {
1421 return $this->LibStatut($this->status, $mode);
1422 }
1423
1430 public function getLibStatut($mode = 0)
1431 {
1432 return $this->LibStatut($this->status, $mode);
1433 }
1434
1435 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1443 public function LibStatut($status, $mode = 0)
1444 {
1445 // phpcs:enable
1446 if (empty($this->labelStatus) || empty($this->labelStatusShort)) {
1447 global $langs;
1448 //$langs->load("assets");
1449 $this->labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('AssetInProgress');
1450 $this->labelStatus[self::STATUS_DISPOSED] = $langs->transnoentitiesnoconv('AssetDisposed');
1451 $this->labelStatusShort[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('AssetInProgress');
1452 $this->labelStatusShort[self::STATUS_DISPOSED] = $langs->transnoentitiesnoconv('AssetDisposed');
1453 }
1454
1455 $statusType = 'status4';
1456 if ($status == self::STATUS_DISPOSED) {
1457 $statusType = 'status6';
1458 }
1459
1460 return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode);
1461 }
1462
1469 public function info($id)
1470 {
1471 $sql = "SELECT rowid, date_creation as datec, tms as datem,";
1472 $sql .= " fk_user_creat, fk_user_modif";
1473 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as t";
1474 $sql .= " WHERE t.rowid = ".((int) $id);
1475
1476 $result = $this->db->query($sql);
1477 if ($result) {
1478 if ($this->db->num_rows($result)) {
1479 $obj = $this->db->fetch_object($result);
1480 $this->id = $obj->rowid;
1481
1482 $this->user_creation_id = $obj->fk_user_creat;
1483 $this->user_modification_id = $obj->fk_user_modif;
1484 $this->date_creation = $this->db->jdate($obj->datec);
1485 $this->date_modification = $this->db->jdate($obj->datem);
1486 }
1487
1488 $this->db->free($result);
1489 } else {
1490 dol_print_error($this->db);
1491 }
1492 }
1493
1500 public function initAsSpecimen()
1501 {
1502 // Set here init that are not commonf fields
1503 // $this->property1 = ...
1504 // $this->property2 = ...
1505
1506 return $this->initAsSpecimenCommon();
1507 }
1508
1514 public function getLinesArray()
1515 {
1516 $this->lines = array();
1517
1518 return $this->lines;
1519 }
1520
1526 public function getNextNumRef()
1527 {
1528 global $langs, $conf;
1529 $langs->load("assets");
1530
1531 if (!getDolGlobalString('ASSET_ASSET_ADDON')) {
1532 $conf->global->ASSET_ASSET_ADDON = 'mod_asset_standard';
1533 }
1534
1535 if (getDolGlobalString('ASSET_ASSET_ADDON')) {
1536 $mybool = false;
1537
1538 $file = getDolGlobalString('ASSET_ASSET_ADDON') . ".php";
1539 $classname = getDolGlobalString('ASSET_ASSET_ADDON');
1540
1541 // Include file with class
1542 $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
1543 foreach ($dirmodels as $reldir) {
1544 $dir = dol_buildpath($reldir."core/modules/asset/");
1545
1546 // Load file with numbering class (if found)
1547 $mybool = ((bool) @include_once $dir.$file) || $mybool;
1548 }
1549
1550 if ($mybool === false) {
1551 dol_print_error(null, "Failed to include file ".$file);
1552 return '';
1553 }
1554
1555 if (class_exists($classname)) {
1556 $obj = new $classname();
1557 $numref = $obj->getNextValue($this);
1558
1559 if ($numref != '' && $numref != '-1') {
1560 return $numref;
1561 } else {
1562 $this->error = $obj->error;
1563 //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error);
1564 return "";
1565 }
1566 } else {
1567 print $langs->trans("Error")." ".$langs->trans("ClassNotFound").' '.$classname;
1568 return "";
1569 }
1570 } else {
1571 print $langs->trans("ErrorNumberingModuleNotSetup", $this->element);
1572 return "";
1573 }
1574 }
1575}
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...