diff --git a/htdocs/asset/agenda.php b/htdocs/asset/agenda.php index b45d739bba9..2d5a5ae6a75 100644 --- a/htdocs/asset/agenda.php +++ b/htdocs/asset/agenda.php @@ -1,7 +1,7 @@ - * Copyright (C) ---Put here your own copyright and developer email--- - * Copyright (C) 2024 Frédéric France +/* Copyright (C) 2017 Laurent Destailleur + * Copyright (C) 2024 Frédéric France + * Copyright (C) 2025 Alexandre Spangaro * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,14 +23,6 @@ * \brief Tab of events on Asset */ -/** - * @var Conf $conf - * @var DoliDB $db - * @var HookManager $hookmanager - * @var Translate $langs - * @var User $user - */ - // Load Dolibarr environment require '../main.inc.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/asset.lib.php'; @@ -39,6 +31,14 @@ require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; +/** + * @var Conf $conf + * @var DoliDB $db + * @var HookManager $hookmanager + * @var Translate $langs + * @var User $user + */ + // Load translation files required by the page $langs->loadLangs(array("assets", "other")); @@ -138,7 +138,7 @@ $form = new Form($db); if ($object->id > 0) { $title = $langs->trans("Agenda"); - $help_url = 'EN:Module_Agenda_En|DE:Modul_Terminplanung'; + $help_url = 'EN:Module_Agenda_En|FR:Module_Agenda|ES:Módulo_Agenda|DE:Modul_Agenda'; llxHeader('', $title, $help_url, '', 0, 0, '', '', '', 'mod-asset page-card_agenda'); if (isModEnabled('notification')) { diff --git a/htdocs/asset/card.php b/htdocs/asset/card.php index 35f131273ac..17bd8700f4d 100644 --- a/htdocs/asset/card.php +++ b/htdocs/asset/card.php @@ -1,7 +1,7 @@ - * Copyright (C) 2018 Alexandre Spangaro - * Copyright (C) 2024 Frédéric France +/* Copyright (C) 2017 Laurent Destailleur + * Copyright (C) 2018-2025 Alexandre Spangaro + * Copyright (C) 2024 Frédéric France * Copyright (C) 2025 MDW * * This program is free software; you can redistribute it and/or modify @@ -186,7 +186,7 @@ llxHeader('', $title, $help_url, '', 0, 0, '', '', '', 'mod-asset page-card'); // Part to create if ($action == 'create') { - print load_fiche_titre($langs->trans("NewObject", $langs->transnoentitiesnoconv("Asset")), '', 'object_'.$object->picto); + print load_fiche_titre($langs->trans("NewAsset"), '', 'object_'.$object->picto); print '
'; print ''; @@ -270,7 +270,33 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea // Confirmation to delete if ($action == 'delete') { $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('DeleteAsset'), $langs->trans('ConfirmDeleteObject'), 'confirm_delete', '', 0, 1); - } elseif ($action == 'disposal') { + } + + // Confirmation of validation + if ($action == 'validate') { + // We check that object has a temporary ref + $ref = substr($object->ref, 1, 4); + if ($ref == 'PROV') { + $numref = $object->getNextNumRef(); + } else { + $numref = $object->ref; + } + + $text = $langs->trans('ConfirmValidateAsset', $numref); + if (isModEnabled('notification')) { + require_once DOL_DOCUMENT_ROOT . '/core/class/notify.class.php'; + $notify = new Notify($db); + $text .= '
'; + $text .= $notify->confirmMessage('ASSET_VALIDATE', 0, $object); + } + + $formquestion = array(); + + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('Validate'), $text, 'confirm_validate', $formquestion, 0, 1, 220); + } + + // Confirmation of disposal + if ($action == 'disposal') { // Disposal $langs->load('bills'); @@ -301,12 +327,24 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea array('type' => 'checkbox', 'name' => 'disposal_subject_to_vat', 'label' => $langs->trans("AssetDisposalSubjectToVat"), 'value' => $disposal_subject_to_vat), ); $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id, $langs->trans('AssetDisposal'), $langs->trans('AssetConfirmDisposalAsk', $object->ref . ' - ' . $object->label), 'confirm_disposal', $formquestion, 'yes', 1); - } elseif ($action == 'reopen') { + } + + // Confirmation of reopen + if ($action == 'reopen') { // Re-open // Create an array for form $formquestion = array(); $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ReOpen'), $langs->trans('AssetConfirmReOpenAsk', $object->ref), 'confirm_reopen', $formquestion, 'yes', 1); } + + // Confirmation of setdraft + if ($action == 'setdraft') { + $text = $langs->trans('ConfirmSetToDraft', $object->ref); + + $formquestion = array(); + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('SetToDraft'), $text, 'confirm_setdraft', $formquestion, 0, 1, 220); + } + // Clone confirmation /* elseif ($action == 'clone') { // Create an array for form @@ -375,19 +413,35 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea print dolGetButtonAction('', $langs->trans('SendMail'), 'default', $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=presend&mode=init&token=' . newToken() . '#formmailbeforetitle'); } + // Back to draft + if ($object->status == $object::STATUS_VALIDATED) { + if ($permissiontoadd) { + print ''.$langs->trans("SetToDraft").''."\n"; + } + } + + // Modify if ($object->status == $object::STATUS_DRAFT) { print dolGetButtonAction($langs->trans('Modify'), '', 'default', $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=edit&token=' . newToken(), '', $permissiontoadd); } - // Clone - //print dolGetButtonAction($langs->trans('ToClone'), '', 'default', $_SERVER['PHP_SELF'] . '?id=' . $object->id . '&action=clone&token=' . newToken(), '', false && $permissiontoadd); - + // Validate if ($object->status == $object::STATUS_DRAFT) { + print dolGetButtonAction($langs->trans('Validate'), '', 'default', $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=validate&token=' . newToken(), '', $permissiontoadd); + } + + if ($object->status == $object::STATUS_VALIDATED) { print dolGetButtonAction($langs->trans('AssetDisposal'), '', 'default', $_SERVER['PHP_SELF'] . '?id=' . $object->id . '&action=disposal&token=' . newToken(), '', $permissiontoadd); - } else { + } + + // Re-open + if ($permissiontoadd && $object->status == $object::STATUS_DISPOSED) { print dolGetButtonAction($langs->trans('ReOpen'), '', 'default', $_SERVER['PHP_SELF'] . '?id=' . $object->id . '&action=reopen&token=' . newToken(), '', $permissiontoadd); } + // Clone + //print dolGetButtonAction($langs->trans('ToClone'), '', 'default', $_SERVER['PHP_SELF'] . '?id=' . $object->id . '&action=clone&token=' . newToken(), '', false && $permissiontoadd); + // Delete (need delete permission, or if draft, just need create/modify permission) print dolGetButtonAction($langs->trans('Delete'), '', 'delete', $_SERVER['PHP_SELF'] . '?id=' . $object->id . '&action=delete&token=' . newToken(), '', $permissiontodelete || ($object->status == $object::STATUS_DRAFT && $permissiontoadd)); } diff --git a/htdocs/asset/class/asset.class.php b/htdocs/asset/class/asset.class.php index a148ad25554..d659873db17 100644 --- a/htdocs/asset/class/asset.class.php +++ b/htdocs/asset/class/asset.class.php @@ -1,9 +1,9 @@ - * Copyright (C) 2018-2024 Alexandre Spangaro - * Copyright (C) 2024-2025 Frédéric France - * Copyright (C) 2024-2025 MDW - * Copyright (C) 2024 Jose MARTINEZ +/* Copyright (C) 2017 Laurent Destailleur + * Copyright (C) 2018-2025 Alexandre Spangaro + * Copyright (C) 2024-2025 Frédéric France + * Copyright (C) 2024-2025 MDW + * Copyright (C) 2024 Jose MARTINEZ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -52,7 +52,8 @@ class Asset extends CommonObject */ public $picto = 'asset'; - const STATUS_DRAFT = 0; // In progress + const STATUS_DRAFT = 0; // Draft + const STATUS_VALIDATED = 1; // In progress const STATUS_DISPOSED = 9; // Disposed /** @@ -88,7 +89,7 @@ class Asset extends CommonObject */ public $fields = array( 'rowid' => array('type' => 'integer', 'label' => 'TechnicalID', 'enabled' => 1, 'position' => 1, 'notnull' => 1, 'visible' => 0, 'noteditable' => 1, 'index' => 1, 'css' => 'left', 'comment' => "Id"), - '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", "css" => "maxwidth150"), + 'ref' => array('type' => 'varchar(128)', 'label' => 'Ref', 'enabled' => 1, 'position' => 20, 'notnull' => 1, 'visible' => 4, 'noteditable' => 0, 'default' => '(PROV)', 'index' => 1, 'searchall' => 1, 'showoncombobox' => 1, 'validate' => 1, 'comment' => "Reference of object", "css" => "maxwidth150"), 'label' => array('type' => 'varchar(255)', 'label' => 'Label', 'enabled' => 1, 'position' => 30, 'notnull' => 1, 'visible' => 1, 'searchall' => 1, 'csslist' => 'tdoverflowmax125', 'css' => 'minwidth300', 'cssview' => 'wordbreak', 'showoncombobox' => 2, 'validate' => 1,), '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, 'csslist' => 'tdoverflowmax75', 'css' => 'maxwidth300'), 'qty' => array('type' => 'real', 'label' => 'Qty', 'enabled' => 1, 'position' => 50, 'notnull' => 1, 'visible' => 0, 'default' => '1', 'isameasure' => 1, 'css' => 'maxwidth75imp', 'validate' => 1,), @@ -110,8 +111,10 @@ class Asset extends CommonObject 'note_private' => array('type' => 'html', 'label' => 'NotePrivate', 'enabled' => 1, 'position' => 301, 'notnull' => 0, 'visible' => 0, 'validate' => 1,), 'date_creation' => array('type' => 'datetime', 'label' => 'DateCreation', 'enabled' => 1, 'position' => 500, 'notnull' => 1, 'visible' => -2,), 'tms' => array('type' => 'timestamp', 'label' => 'DateModification', 'enabled' => 1, 'position' => 501, 'notnull' => 0, 'visible' => -2,), + 'date_valid' => array('type' => 'datetime', 'label' => 'DateValidation', 'enabled' => 1, 'visible' => -2, 'position' => 502, 'notnull' => 0,), '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',), 'fk_user_modif' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserModif', 'enabled' => 1, 'position' => 511, 'notnull' => -1, 'visible' => -2,), + 'fk_user_valid' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserValidation', 'picto' => 'user', 'enabled' => 1, 'visible' => -2, 'position' => 512, 'notnull' => 0, 'csslist' => 'tdoverflowmax100'), 'last_main_doc' => array('type' => 'varchar(255)', 'label' => 'LastMainDoc', 'enabled' => 1, 'position' => 600, 'notnull' => 0, 'visible' => 0,), 'import_key' => array('type' => 'varchar(14)', 'label' => 'ImportId', 'enabled' => 1, 'position' => 1000, 'notnull' => -1, 'visible' => -2,), 'model_pdf' => array('type' => 'varchar(255)', 'label' => 'Model pdf', 'enabled' => 1, 'position' => 1010, 'notnull' => -1, 'visible' => 0,), @@ -206,6 +209,10 @@ class Asset extends CommonObject * @var string */ public $note_private; + /** + * @var int|string date_valid + */ + public $date_valid; /** * @var int */ @@ -214,6 +221,10 @@ class Asset extends CommonObject * @var int */ public $fk_user_modif; + /** + * @var int Id User modifying + */ + public $fk_user_valid; /** * @var string */ @@ -1297,7 +1308,7 @@ class Asset extends CommonObject } /** - * Set back to validated status + * Set back to validated status if disposed status * * @param User $user Object user that modify * @param int $notrigger 1=Does not execute triggers, 0=Execute triggers @@ -1308,7 +1319,7 @@ class Asset extends CommonObject global $conf, $langs; // Protection - if ($this->status != self::STATUS_DISPOSED || $this->status == self::STATUS_DRAFT) { + if ($this->status != self::STATUS_DISPOSED) { return 0; } @@ -1323,7 +1334,7 @@ class Asset extends CommonObject $result = $this->update($user, 1); if ($result > 0) { $this->deleteObjectLinked(null, 'facture'); - $result = $this->setStatusCommon($user, self::STATUS_DRAFT, $notrigger, 'ASSET_REOPEN'); + $result = $this->setStatusCommon($user, self::STATUS_VALIDATED, $notrigger, 'ASSET_REOPEN'); } if ($result > 0) { $result = $this->calculationDepreciation(); @@ -1520,13 +1531,18 @@ class Asset extends CommonObject if (empty($this->labelStatus) || empty($this->labelStatusShort)) { global $langs; //$langs->load("assets"); - $this->labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('AssetInProgress'); + $this->labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('AssetInDraft'); + $this->labelStatus[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('AssetInProgress'); $this->labelStatus[self::STATUS_DISPOSED] = $langs->transnoentitiesnoconv('AssetDisposed'); - $this->labelStatusShort[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('AssetInProgress'); + $this->labelStatusShort[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('AssetInDraft'); + $this->labelStatusShort[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('AssetInProgress'); $this->labelStatusShort[self::STATUS_DISPOSED] = $langs->transnoentitiesnoconv('AssetDisposed'); } - $statusType = 'status4'; + $statusType = 'status'.$status; + if ($status == self::STATUS_VALIDATED) { + $statusType = 'status4'; + } if ($status == self::STATUS_DISPOSED) { $statusType = 'status6'; } @@ -1542,8 +1558,8 @@ class Asset extends CommonObject */ public function info($id) { - $sql = "SELECT rowid, date_creation as datec, tms as datem,"; - $sql .= " fk_user_creat, fk_user_modif"; + $sql = "SELECT rowid, date_creation as datec, tms as datem, date_valid as datev,"; + $sql .= " fk_user_creat, fk_user_modif, fk_user_valid"; $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as t"; $sql .= " WHERE t.rowid = ".((int) $id); @@ -1553,10 +1569,12 @@ class Asset extends CommonObject $obj = $this->db->fetch_object($result); $this->id = $obj->rowid; - $this->user_creation_id = $obj->fk_user_creat; - $this->user_modification_id = $obj->fk_user_modif; - $this->date_creation = $this->db->jdate($obj->datec); - $this->date_modification = $this->db->jdate($obj->datem); + $this->user_creation_id = $obj->fk_user_creat; + $this->user_modification_id = $obj->fk_user_modif; + $this->user_validation_id = $obj->fk_user_valid; + $this->date_creation = $this->db->jdate($obj->datec); + $this->date_modification = $this->db->jdate($obj->datem); + $this->date_validation = $this->db->jdate($obj->datev); } $this->db->free($result); @@ -1637,4 +1655,139 @@ class Asset extends CommonObject return ""; } } + + /** + * Validate asset + * + * @param User $user User making status change + * @param int<0,1> $notrigger 1=Does not execute triggers, 0= execute triggers + * @return int<-1,1> Return integer <=0 if OK, 0=Nothing done, >0 if KO + */ + public function validate($user, $notrigger = 0) + { + global $conf; + + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + + $error = 0; + + // Protection + if ($this->status == self::STATUS_VALIDATED) { + dol_syslog(get_class($this)."::validate action abandoned: already validated", LOG_WARNING); + return 0; + } + + $now = dol_now(); + + $this->db->begin(); + + // Define new ref + if (/* !$error && */ (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref))) { // empty should not happened, but when it occurs, the test save life + $num = $this->getNextNumRef(); + } else { + $num = $this->ref; + } + $this->newref = dol_sanitizeFileName($num); + + // Validate + $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element; + $sql .= " SET ref = '".$this->db->escape($num)."',"; + $sql .= " status = ".self::STATUS_VALIDATED.","; + $sql .= " date_valid='".$this->db->idate($now)."',"; + $sql .= " fk_user_valid = ".((int) $user->id); + $sql .= " WHERE rowid = ".((int) $this->id); + + dol_syslog(get_class($this)."::validate()", LOG_DEBUG); + $resql = $this->db->query($sql); + if (!$resql) { + dol_print_error($this->db); + $this->error = $this->db->lasterror(); + $error++; + } + + if (!$error && !$notrigger) { + // Call trigger + $result = $this->call_trigger('ASSET_VALIDATE', $user); + if ($result < 0) { + $error++; + } + // End call triggers + } + + if (!$error) { + $this->oldref = $this->ref; + + // Rename directory if dir was a temporary ref + if (preg_match('/^[\(]?PROV/i', $this->ref)) { + // Now we rename also files into index + $sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filename = CONCAT('".$this->db->escape($this->newref)."', SUBSTR(filename, ".(strlen($this->ref) + 1).")), filepath = 'asset/".$this->db->escape($this->newref)."'"; + $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'bom/".$this->db->escape($this->ref)."' and entity = ".$conf->entity; + $resql = $this->db->query($sql); + if (!$resql) { + $error++; + $this->error = $this->db->lasterror(); + } + $sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filepath = 'asset/".$this->db->escape($this->newref)."'"; + $sql .= " WHERE filepath = 'asset/".$this->db->escape($this->ref)."' and entity = ".$conf->entity; + $resql = $this->db->query($sql); + if (!$resql) { + $error++; + $this->error = $this->db->lasterror(); + } + + // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments + $oldref = dol_sanitizeFileName($this->ref); + $newref = dol_sanitizeFileName($num); + $dirsource = $conf->asset->dir_output.'/'.$oldref; + $dirdest = $conf->asset->dir_output.'/'.$newref; + if (!$error && file_exists($dirsource)) { + dol_syslog(get_class($this)."::validate() rename dir ".$dirsource." into ".$dirdest); + + if (@rename($dirsource, $dirdest)) { + dol_syslog("Rename ok"); + // Rename docs starting with $oldref with $newref + $listoffiles = dol_dir_list($conf->asset->dir_output.'/'.$newref, 'files', 1, '^'.preg_quote($oldref, '/')); + foreach ($listoffiles as $fileentry) { + $dirsource = $fileentry['name']; + $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource); + $dirsource = $fileentry['path'].'/'.$dirsource; + $dirdest = $fileentry['path'].'/'.$dirdest; + @rename($dirsource, $dirdest); + } + } + } + } + } + + // Set new ref and current status + if (!$error) { + $this->ref = $num; + $this->status = self::STATUS_VALIDATED; + } + + if (!$error) { + $this->db->commit(); + return 1; + } else { + $this->db->rollback(); + return -1; + } + } + + /** + * Set draft status + * + * @param User $user Object user that modify + * @param int<0,1> $notrigger 1=Does not execute triggers, 0=Execute triggers + * @return int<-1,1> Return integer <0 if KO, 0=Nothing done, >0 if OK + */ + public function setDraft($user, $notrigger = 0) + { + // Protection + if ($this->status <= self::STATUS_DRAFT) { + return 0; + } + + return $this->setStatusCommon($user, self::STATUS_DRAFT, $notrigger, 'ASSET_UNVALIDATE'); + } } diff --git a/htdocs/core/lib/asset.lib.php b/htdocs/core/lib/asset.lib.php index 6ced74e5966..ff763e2419b 100644 --- a/htdocs/core/lib/asset.lib.php +++ b/htdocs/core/lib/asset.lib.php @@ -1,7 +1,8 @@ - * Copyright (C) 2022-2024 Frédéric France +/* Copyright (C) 2018-2022 OpenDSI + * Copyright (C) 2022-2024 Frédéric France * Copyright (C) 2024 MDW + * Copyright (C) 2025 Alexandre Spangaro * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -95,7 +96,7 @@ function assetPrepareHead(Asset $object) $head = array(); $head[$h][0] = DOL_URL_ROOT . '/asset/card.php?id=' . $object->id; - $head[$h][1] = $langs->trans("Card"); + $head[$h][1] = $langs->trans("Asset"); $head[$h][2] = 'card'; $h++; diff --git a/htdocs/core/modules/modAsset.class.php b/htdocs/core/modules/modAsset.class.php index 62d50a2989b..f0c2b9c6be9 100644 --- a/htdocs/core/modules/modAsset.class.php +++ b/htdocs/core/modules/modAsset.class.php @@ -58,9 +58,9 @@ class modAsset extends DolibarrModules // Module label (no space allowed), used if translation string 'ModuleAssetsName' not found (MyModue is name of module). $this->name = preg_replace('/^mod/i', '', get_class($this)); // Module description, used if translation string 'ModuleAssetsDesc' not found (MyModue is name of module). - $this->description = "Asset module"; + $this->description = "Fixed asset management"; // Used only if file README.md and README-LL.md not found. - $this->descriptionlong = "Asset module to manage assets module and depreciation charge on Dolibarr"; + $this->descriptionlong = "Asset module to manage fixed asset module and depreciation charge"; // Possible values for version are: 'development', 'experimental', 'dolibarr', 'dolibarr_deprecated' or a version string like 'x.y.z' $this->version = 'experimental'; @@ -113,6 +113,16 @@ class modAsset extends DolibarrModules 1 ); + $this->const[2] = array( + "ASSET_ASSET_ADDON", + "chaine", + "mod_asset_standard", + "Name of numbering rules for fixed asset", + 0, + 'current', + 1 + ); + if (!isModEnabled('asset')) { $conf->asset = new stdClass(); diff --git a/htdocs/install/mysql/migration/21.0.0-22.0.0.sql b/htdocs/install/mysql/migration/21.0.0-22.0.0.sql index eacd4a7db95..ba5b2abb57f 100644 --- a/htdocs/install/mysql/migration/21.0.0-22.0.0.sql +++ b/htdocs/install/mysql/migration/21.0.0-22.0.0.sql @@ -246,3 +246,6 @@ ALTER TABLE llx_contratdet DROP COLUMN remise; ALTER TABLE llx_extrafields ADD COLUMN aiprompt text; ALTER TABLE llx_menu ADD COLUMN showtopmenuinframe integer DEFAULT 0; + +ALTER TABLE llx_asset ADD COLUMN fk_user_valid integer; +ALTER TABLE llx_asset ADD COLUMN date_valid datetime; diff --git a/htdocs/install/mysql/tables/llx_asset-asset.sql b/htdocs/install/mysql/tables/llx_asset-asset.sql index 65cb9d6b477..dbd89c55ba8 100644 --- a/htdocs/install/mysql/tables/llx_asset-asset.sql +++ b/htdocs/install/mysql/tables/llx_asset-asset.sql @@ -1,5 +1,6 @@ -- ======================================================================== --- Copyright (C) 2018-2022 OpenDSI +-- Copyright (C) 2018-2022 OpenDSI +-- Copyright (C) 2025 Alexandre Spangaro -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by @@ -56,8 +57,10 @@ CREATE TABLE llx_asset( date_creation datetime NOT NULL, tms timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + date_valid datetime, fk_user_creat integer NOT NULL, fk_user_modif integer, + fk_user_valid integer, last_main_doc varchar(255), import_key varchar(14), model_pdf varchar(255), diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang index 28e57c05a5a..0754f523805 100644 --- a/htdocs/langs/en_US/admin.lang +++ b/htdocs/langs/en_US/admin.lang @@ -725,6 +725,8 @@ Module50300Name=Stripe Module50300Desc=Offer customers a Stripe online payment page (credit/debit cards). This can be used to allow your customers to make ad-hoc payments or payments related to a specific Dolibarr object (invoice, order etc...) Module50400Name=Accounting (double entry) Module50400Desc=Accounting management (double entries, support General and Subsidiary Ledgers). Export the ledger in several other accounting software formats. +Module51000Name=Fixed asset +Module51000Desc=Fixed asset complete management. Linked to the accounting module (double entries). Module54000Name=PrintIPP Module54000Desc=Direct print (without opening the documents) using Cups IPP interface (Printer must be visible from server, and CUPS must be installed on server). Module55000Name=Poll, Survey or Vote diff --git a/htdocs/langs/en_US/assets.lang b/htdocs/langs/en_US/assets.lang index 7cd68618ec6..15c757b23f3 100644 --- a/htdocs/langs/en_US/assets.lang +++ b/htdocs/langs/en_US/assets.lang @@ -17,6 +17,7 @@ AccountancyCodeAsset=Accounting code (asset) AccountancyCodeDepreciationAsset=Accounting code (depreciation asset account) AccountancyCodeDepreciationExpense=Accounting code (depreciation expense account) AssetsLines=Assets +ConfirmValidateAsset=Are you sure you want to validate this asset with the reference %s? DeleteType=Delete DeleteAnAssetType=Delete an asset model ConfirmDeleteAssetType=Are you sure you want to delete this asset model? @@ -70,6 +71,7 @@ AssetDisposal=Disposal AssetConfirmDisposalAsk=Are you sure you want to dispose of the asset %s? AssetConfirmReOpenAsk=Are you sure you want to reopen the asset %s? # Asset status +AssetInDraft=Draft AssetInProgress=In progress AssetDisposed=Disposed AssetRecorded=Accounted diff --git a/htdocs/langs/fr_FR/assets.lang b/htdocs/langs/fr_FR/assets.lang index d3ec94e1cd2..92199635b34 100644 --- a/htdocs/langs/fr_FR/assets.lang +++ b/htdocs/langs/fr_FR/assets.lang @@ -49,7 +49,7 @@ AssetDepreciationOptions=Options d'amortissement AssetAccountancyCodes=Comptes comptables AssetDepreciation=Dépréciation # Asset -Asset=Immobilisations +Asset=Immobilisation Assets=Immobilisations AssetReversalAmountHT=Montant de l'annulation (hors taxes) AssetAcquisitionValueHT=Montant de l'acquisition (hors taxes)