From 65934498061cbd6aecc44855814a2cd90c948fa7 Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Mon, 14 Feb 2022 04:20:42 +0100 Subject: [PATCH 01/20] Dictionary --- htdocs/admin/dict.php | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/htdocs/admin/dict.php b/htdocs/admin/dict.php index fb28aa3d045..058bd78824c 100644 --- a/htdocs/admin/dict.php +++ b/htdocs/admin/dict.php @@ -12,7 +12,7 @@ * Copyright (C) 2015 Ferran Marcet * Copyright (C) 2016 Raphaël Doursenaud * Copyright (C) 2019-2020 Frédéric France - * Copyright (C) 2020 Open-Dsi + * Copyright (C) 2020-2022 Open-Dsi * * 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 @@ -100,7 +100,7 @@ $hookmanager->initHooks(array('admin')); // Put here declaration of dictionaries properties // Sort order to show dictionary (0 is space). All other dictionaries (added by modules) will be at end of this. -$taborder = array(9, 15, 30, 0, 4, 3, 2, 0, 1, 8, 19, 16, 39, 27, 40, 38, 0, 5, 11, 0, 6, 24, 0, 29, 0, 33, 34, 32, 28, 17, 35, 36, 0, 10, 23, 12, 13, 7, 0, 14, 0, 22, 20, 18, 21, 41, 0, 37, 42, 0, 43, 0, 25, 0); +$taborder = array(9, 15, 30, 0, 4, 3, 2, 0, 1, 8, 19, 16, 39, 27, 40, 38, 0, 5, 11, 0, 6, 24, 0, 29, 0, 33, 34, 32, 28, 17, 35, 36, 0, 10, 23, 12, 13, 7, 0, 14, 0, 22, 20, 18, 21, 41, 0, 37, 42, 0, 43, 0, 25, 0, 44, 0); // Name of SQL tables of dictionaries $tabname = array(); @@ -147,6 +147,7 @@ $tabname[40] = MAIN_DB_PREFIX."c_stcommcontact"; $tabname[41] = MAIN_DB_PREFIX."c_transport_mode"; $tabname[42] = MAIN_DB_PREFIX."c_product_nature"; $tabname[43] = MAIN_DB_PREFIX."c_productbatch_qcstatus"; +$tabname[44] = MAIN_DB_PREFIX."c_asset_disposal_type"; // Dictionary labels $tablib = array(); @@ -193,6 +194,7 @@ $tablib[40] = "DictionaryProspectContactStatus"; $tablib[41] = "DictionaryTransportMode"; $tablib[42] = "DictionaryProductNature"; $tablib[43] = "DictionaryBatchStatus"; +$tablib[44] = "DictionaryAssetDisposalType"; // Requests to extract data $tabsql = array(); @@ -239,6 +241,7 @@ $tabsql[40] = "SELECT id as rowid, code, libelle, picto, active FROM ".MAIN $tabsql[41] = "SELECT rowid as rowid, code, label, active FROM ".MAIN_DB_PREFIX."c_transport_mode"; $tabsql[42] = "SELECT rowid as rowid, code, label, active FROM ".MAIN_DB_PREFIX."c_product_nature"; $tabsql[43] = "SELECT rowid, code, label, active FROM ".MAIN_DB_PREFIX."c_productbatch_qcstatus"; +$tabsql[44] = "SELECT rowid, code, label, active FROM ".MAIN_DB_PREFIX."c_asset_disposal_type"; // Criteria to sort dictionaries $tabsqlsort = array(); @@ -285,6 +288,7 @@ $tabsqlsort[40] = "code ASC"; $tabsqlsort[41] = "code ASC"; $tabsqlsort[42] = "code ASC"; $tabsqlsort[43] = "code ASC"; +$tabsqlsort[44] = "code ASC"; // Field names in select result for dictionary display $tabfield = array(); @@ -331,6 +335,7 @@ $tabfield[40] = "code,libelle,picto"; $tabfield[41] = "code,label"; $tabfield[42] = "code,label"; $tabfield[43] = "code,label"; +$tabfield[44] = "code,label"; // Edit field names for editing a record $tabfieldvalue = array(); @@ -377,6 +382,7 @@ $tabfieldvalue[40] = "code,libelle,picto"; $tabfieldvalue[41] = "code,label"; $tabfieldvalue[42] = "code,label"; $tabfieldvalue[43] = "code,label"; +$tabfieldvalue[44] = "code,label"; // Field names in the table for inserting a record $tabfieldinsert = array(); @@ -424,6 +430,7 @@ $tabfieldinsert[40] = "code,libelle,picto"; $tabfieldinsert[41] = "code,label"; $tabfieldinsert[42] = "code,label"; $tabfieldinsert[43] = "code,label"; +$tabfieldinsert[44] = "code,label"; // Rowid name of field depending if field is autoincrement on or off.. // Use "" if id field is "rowid" and has autoincrement on @@ -472,6 +479,7 @@ $tabrowid[40] = "id"; $tabrowid[41] = ""; $tabrowid[42] = "rowid"; $tabrowid[43] = "rowid"; +$tabrowid[44] = "rowid"; // Condition to show dictionary in setup page $tabcond = array(); @@ -518,6 +526,7 @@ $tabcond[40] = (!empty($conf->societe->enabled) && !empty($conf->global->THIRDPA $tabcond[41] = !empty($conf->intracommreport->enabled); $tabcond[42] = !empty($conf->product->enabled); $tabcond[43] = !empty($conf->product->enabled) && !empty($conf->productbatch->enabled) && $conf->global->MAIN_FEATURES_LEVEL >= 2; +$tabcond[44] = !empty($conf->asset->enabled); // List of help for fields $tabhelp = array(); @@ -564,6 +573,7 @@ $tabhelp[40] = array('code'=>$langs->trans("EnterAnyCode"), 'picto'=>$langs->tra $tabhelp[41] = array('code'=>$langs->trans("EnterAnyCode")); $tabhelp[42] = array('code'=>$langs->trans("EnterAnyCode")); $tabhelp[43] = array('code'=>$langs->trans("EnterAnyCode")); +$tabhelp[44] = array('code'=>$langs->trans("EnterAnyCode")); // Table to store complete informations (will replace all other table). Key is table name. $tabcomplete = array( @@ -609,6 +619,7 @@ $tabcomplete = array( 'c_stcommcontact'=>array('picto'=>'company'), 'c_product_nature'=>array('picto'=>'product'), 'c_productbatch_qcstatus'=>array('picto'=>'lot'), + 'c_asset_disposal_type'=>array('picto'=>'asset'), ); From d5e521c87b09863d7a9f6cdf381a592d0591ba01 Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Mon, 14 Feb 2022 04:27:52 +0100 Subject: [PATCH 02/20] Accountancy --- .../class/accountingjournal.class.php | 695 +++++++++++++++++- htdocs/accountancy/journal/variousjournal.php | 311 ++++++++ 2 files changed, 1005 insertions(+), 1 deletion(-) create mode 100644 htdocs/accountancy/journal/variousjournal.php diff --git a/htdocs/accountancy/class/accountingjournal.class.php b/htdocs/accountancy/class/accountingjournal.class.php index 376178b45ba..d233dcc0c2e 100644 --- a/htdocs/accountancy/class/accountingjournal.class.php +++ b/htdocs/accountancy/class/accountingjournal.class.php @@ -1,5 +1,5 @@ +/* Copyright (C) 2017-2022 OpenDSI * * 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 @@ -81,6 +81,24 @@ class AccountingJournal extends CommonObject */ public $lines; + /** + * @var array Accounting account cached + */ + static public $accounting_account_cached = array(); + + /** + * @var array Nature mapping + */ + static public $nature_maps = array( + 1 => 'variousoperations', + 2 => 'sells', + 3 => 'purchases', + 4 => 'bank', + 5 => 'expensereports', + 8 => 'inventories', + 9 => 'hasnew', + ); + /** * Constructor * @@ -336,4 +354,679 @@ class AccountingJournal extends CommonObject } } } + + + /** + * Get journal data + * + * @param User $user User who get infos + * @param string $type Type data returned ('view', 'bookkeeping', 'csv') + * @param int $date_start Filter 'start date' + * @param int $date_end Filter 'end date' + * @param string $in_bookkeeping Filter 'in bookkeeping' ('already', 'notyet') + * @return array|int <0 if KO, >0 if OK + */ + public function getData(User $user, $type = 'view', $date_start = null, $date_end = null, $in_bookkeeping = 'notyet') + { + global $hookmanager; + + // Clean parameters + if (empty($type)) $type = 'view'; + if (empty($in_bookkeeping)) $in_bookkeeping = 'notyet'; + + // Hook + if (!is_object($hookmanager)) { + include_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php'; + $hookmanager = new HookManager($this->db); + } + + $data = array(); + + $hookmanager->initHooks(array('accountingjournaldao')); + $parameters = array('data' => &$data, 'user' => $user, 'type' => $type, 'date_start' => $date_start, 'date_end' => $date_end, 'in_bookkeeping' => $in_bookkeeping); + $reshook = $hookmanager->executeHooks('getData', $parameters, $this); // Note that $action and $object may have been + if ($reshook < 0) { + $this->error = $hookmanager->error; + $this->errors = $hookmanager->errors; + return -1; + } elseif (empty($reshook)) { + switch ($this->nature) { + case 1: // Various Journal + $data = $this->getAssetData($user, $type, $date_start, $date_end, $in_bookkeeping); + break; +// case 2: // Sells Journal +// case 3: // Purchases Journal +// case 4: // Bank Journal +// case 5: // Expense reports Journal +// case 8: // Inventory Journal +// case 9: // hasnew Journal + } + } + + return $data; + } + + /** + * Get asset data for various journal + * + * @param User $user User who get infos + * @param string $type Type data returned ('view', 'bookkeeping', 'csv') + * @param int $date_start Filter 'start date' + * @param int $date_end Filter 'end date' + * @param string $in_bookkeeping Filter 'in bookkeeping' ('already', 'notyet') + * @return array|int <0 if KO, >0 if OK + */ + public function getAssetData(User $user, $type = 'view', $date_start = null, $date_end = null, $in_bookkeeping = 'notyet') + { + global $conf, $langs; + + if (empty($conf->asset->enabled)) { + return array(); + } + + require_once DOL_DOCUMENT_ROOT . '/core/lib/accounting.lib.php'; + require_once DOL_DOCUMENT_ROOT . '/asset/class/asset.class.php'; + require_once DOL_DOCUMENT_ROOT . '/asset/class/assetaccountancycodes.class.php'; + require_once DOL_DOCUMENT_ROOT . '/asset/class/assetdepreciationoptions.class.php'; + + $langs->loadLangs(array("assets")); + + // Clean parameters + if (empty($type)) $type = 'view'; + if (empty($in_bookkeeping)) $in_bookkeeping = 'notyet'; + + $sql = ""; + if ($in_bookkeeping == 'already' || $in_bookkeeping == 'notyet') { + $sql .= "WITH in_accounting_bookkeeping(fk_docdet) AS ("; + $sql .= " SELECT DISTINCT fk_docdet"; + $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping"; + $sql .= " WHERE doc_type = 'asset'"; + $sql .= ")"; + } + $sql .= "SELECT ad.fk_asset AS rowid, a.ref AS asset_ref, a.label AS asset_label, a.acquisition_value_ht AS asset_acquisition_value_ht"; + $sql .= ", a.disposal_date AS asset_disposal_date, a.disposal_amount_ht AS asset_disposal_amount_ht, a.disposal_subject_to_vat AS asset_disposal_subject_to_vat"; + $sql .= ", ad.rowid AS depreciation_id, ad.depreciation_mode, ad.ref AS depreciation_ref, ad.depreciation_date, ad.depreciation_ht, ad.accountancy_code_debit, ad.accountancy_code_credit"; + $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation as ad"; + $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "asset as a ON a.rowid = ad.fk_asset"; + if ($in_bookkeeping == 'already' || $in_bookkeeping == 'notyet') { + $sql .= " LEFT JOIN in_accounting_bookkeeping as iab ON iab.fk_docdet = ad.rowid"; + } + $sql .= " WHERE a.entity IN (" . getEntity('asset', 0) . ')'; // We don't share object for accountancy, we use source object sharing + $sql .= " AND ad.ref != ''"; // not reversal lines + if ($date_start && $date_end) { + $sql .= " AND ad.depreciation_date >= '" . $this->db->idate($date_start) . "' AND ad.depreciation_date <= '" . $this->db->idate($date_end) . "'"; + } + // Define begin binding date + if (!empty($conf->global->ACCOUNTING_DATE_START_BINDING)) { + $sql .= " AND ad.depreciation_date >= '" . $this->db->idate($conf->global->ACCOUNTING_DATE_START_BINDING) . "'"; + } + // Already in bookkeeping or not + if ($in_bookkeeping == 'already' || $in_bookkeeping == 'notyet') { + $sql .= " AND iab.fk_docdet IS" . ($in_bookkeeping == 'already' ? " NOT" : "") . " NULL"; + } + $sql .= " ORDER BY ad.depreciation_date"; + + dol_syslog(__METHOD__, LOG_DEBUG); + $resql = $this->db->query($sql); + if (!$resql) { + $this->errors[] = $this->db->lasterror(); + return -1; + } + + $pre_data = array( + 'elements' => array(), + ); + while ($obj = $this->db->fetch_object($resql)) { + if (!isset($pre_data['elements'][$obj->rowid])) { + $pre_data['elements'][$obj->rowid] = array( + 'ref' => $obj->asset_ref, + 'label' => $obj->asset_label, + 'acquisition_value_ht' => $obj->asset_acquisition_value_ht, + 'depreciation' => array(), + ); + + // Disposal infos + if (isset($obj->asset_disposal_date)) { + $pre_data['elements'][$obj->rowid]['disposal'] = array( + 'date' => $this->db->jdate($obj->asset_disposal_date), + 'amount' => $obj->asset_disposal_amount_ht, + 'subject_to_vat' => !empty($obj->asset_disposal_subject_to_vat), + ); + } + } + + $compta_debit = empty($obj->accountancy_code_debit) ? 'NotDefined' : $obj->accountancy_code_debit; + $compta_credit = empty($obj->accountancy_code_credit) ? 'NotDefined' : $obj->accountancy_code_credit; + + $pre_data['elements'][$obj->rowid]['depreciation'][$obj->depreciation_id] = array( + 'date' => $this->db->jdate($obj->depreciation_date), + 'ref' => $obj->depreciation_ref, + 'lines' => array( + $compta_debit => -$obj->depreciation_ht, + $compta_credit => $obj->depreciation_ht, + ), + ); + } + + $disposal_ref = $langs->transnoentitiesnoconv('AssetDisposal'); + $journal = $this->code; + $journal_label = $this->label; + $journal_label_formatted = $langs->transnoentities($journal_label); + $now = dol_now(); + + $element_static = new Asset($this->db); + + $journal_data = array(); + foreach ($pre_data['elements'] as $pre_data_id => $pre_data_info) { + $element_static->id = $pre_data_id; + $element_static->ref = (string)$pre_data_info["ref"]; + $element_static->label = (string)$pre_data_info["label"]; + $element_static->acquisition_value_ht = $pre_data_info["acquisition_value_ht"]; + $element_link = $element_static->getNomUrl(1, 'with_label'); + + $element_name_formatted_0 = dol_trunc($element_static->label, 16); + $element_name_formatted_1 = utf8_decode(dol_trunc($element_static->label, 32)); + $element_name_formatted_2 = utf8_decode(dol_trunc($element_static->label, 16)); + $label_operation = $element_static->getNomUrl(0, 'label', 16); + + $element = array( + 'ref' => dol_trunc($element_static->ref, 16, 'right', 'UTF-8', 1), + 'error' => $pre_data_info['error'], + 'blocks' => array(), + ); + + // Depreciation lines + //-------------------- + foreach ($pre_data_info['depreciation'] as $depreciation_id => $line) { + $depreciation_ref = $line["ref"]; + $depreciation_date = $line["date"]; + $depreciation_date_formatted = dol_print_date($depreciation_date, 'day'); + + // lines + $blocks = array(); + foreach ($line['lines'] as $account => $mt) { + $account_infos = $this->getAccountingAccountInfos($account); + + if ($type == 'view') { + $account_to_show = length_accounta($account); + if (($account_to_show == "") || $account_to_show == 'NotDefined') { + $account_to_show = '' . $langs->trans("AssetInAccountNotDefined") . ''; + } + + $blocks[] = array( + 'date' => $depreciation_date_formatted, + 'piece' => $element_link, + 'account_accounting' => $account_to_show, + 'subledger_account' => '', + 'label_operation' => $label_operation . ' - ' . $depreciation_ref, + 'debit' => $mt < 0 ? price(-$mt) : '', + 'credit' => $mt >= 0 ? price($mt) : '', + ); + } elseif ($type == 'bookkeeping') { + if ($account_infos['found']) { + $blocks[] = array( + 'doc_date' => $depreciation_date, + 'date_lim_reglement' => '', + 'doc_ref' => $element_static->ref, + 'date_creation' => $now, + 'doc_type' => 'asset', + 'fk_doc' => $element_static->id, + 'fk_docdet' => $depreciation_id, // Useless, can be several lines that are source of this record to add + 'thirdparty_code' => '', + 'subledger_account' => '', + 'subledger_label' => '', + 'numero_compte' => $account, + 'label_compte' => $account_infos['label'], + 'label_operation' => $element_name_formatted_0 . ' - ' . $depreciation_ref, + 'montant' => $mt, + 'sens' => $mt < 0 ? 'D' : 'C', + 'debit' => $mt < 0 ? -$mt : 0, + 'credit' => $mt >= 0 ? $mt : 0, + 'code_journal' => $journal, + 'journal_label' => $journal_label_formatted, + 'piece_num' => '', + 'import_key' => '', + 'fk_user_author' => $user->id, + 'entity' => $conf->entity, + ); + } + } else { // $type == 'csv' + $blocks[] = array( + $depreciation_date, // Date + $element_static->ref, // Piece + $account_infos['code_formatted_1'], // AccountAccounting + $element_name_formatted_0 . ' - ' . $depreciation_ref, // LabelOperation + $mt < 0 ? price(-$mt) : '', // Debit + $mt >= 0 ? price($mt) : '', // Credit + ); + } + } + $element['blocks'][] = $blocks; + } + + // Disposal line + //-------------------- + if (!empty($pre_data_info['disposal'])) { + $disposal_date = $pre_data_info['disposal']['date']; + + if ((!($date_start && $date_end) || ($date_start <= $disposal_date && $disposal_date <= $date_end)) && + (empty($conf->global->ACCOUNTING_DATE_START_BINDING) || $conf->global->ACCOUNTING_DATE_START_BINDING <= $disposal_date) + ) { + $disposal_amount = $pre_data_info['disposal']['amount']; + $disposal_subject_to_vat = $pre_data_info['disposal']['subject_to_vat']; + $disposal_date_formatted = dol_print_date($disposal_date, 'day'); + $disposal_vat = $conf->global->ASSET_DISPOSAL_VAT > 0 ? $conf->global->ASSET_DISPOSAL_VAT : 20; + + // Get accountancy codes + //--------------------------- + require_once DOL_DOCUMENT_ROOT . '/asset/class/assetaccountancycodes.class.php'; + $accountancy_codes = new AssetAccountancyCodes($this->db); + $result = $accountancy_codes->fetchAccountancyCodes($element_static->id); + if ($result < 0) { + $element['error'] = $accountancy_codes->errorsToString(); + } else { + // Get last depreciation cumulative amount + $element_static->fetchDepreciationLines(); + foreach ($element_static->depreciation_lines as $mode_key => $depreciation_lines) { + $accountancy_codes_list = $accountancy_codes->accountancy_codes[$mode_key]; + + if (!isset($accountancy_codes_list['value_asset_sold'])) { + continue; + } + + $accountancy_code_value_asset_sold = empty($accountancy_codes_list['value_asset_sold']) ? 'NotDefined' : $accountancy_codes_list['value_asset_sold']; + $accountancy_code_depreciation_asset = empty($accountancy_codes_list['depreciation_asset']) ? 'NotDefined' : $accountancy_codes_list['depreciation_asset']; + $accountancy_code_asset = empty($accountancy_codes_list['asset']) ? 'NotDefined' : $accountancy_codes_list['asset']; + $accountancy_code_receivable_on_assignment = empty($accountancy_codes_list['receivable_on_assignment']) ? 'NotDefined' : $accountancy_codes_list['receivable_on_assignment']; + $accountancy_code_vat_collected = empty($accountancy_codes_list['vat_collected']) ? 'NotDefined' : $accountancy_codes_list['vat_collected']; + $accountancy_code_proceeds_from_sales = empty($accountancy_codes_list['proceeds_from_sales']) ? 'NotDefined' : $accountancy_codes_list['proceeds_from_sales']; + + $last_cumulative_amount_ht = 0; + $depreciated_ids = array_keys($pre_data_info['depreciation']); + foreach ($depreciation_lines as $line) { + $last_cumulative_amount_ht = $line['cumulative_depreciation_ht']; + if (!in_array($line['id'], $depreciated_ids) && empty($line['bookkeeping']) && !empty($line['ref'])) { + break; + } + } + + $lines = array(); + $lines[0][$accountancy_code_value_asset_sold] = -($element_static->acquisition_value_ht - $last_cumulative_amount_ht); + $lines[0][$accountancy_code_depreciation_asset] = -$last_cumulative_amount_ht; + $lines[0][$accountancy_code_asset] = $element_static->acquisition_value_ht; + + $disposal_amount_vat = $disposal_subject_to_vat ? (double)price2num($disposal_amount * $disposal_vat / 100, 'MT') : 0; + $lines[1][$accountancy_code_receivable_on_assignment] = -($disposal_amount + $disposal_amount_vat); + if ($disposal_subject_to_vat) $lines[1][$accountancy_code_vat_collected] = $disposal_amount_vat; + $lines[1][$accountancy_code_proceeds_from_sales] = $disposal_amount; + + foreach ($lines as $lines_block) { + $blocks = array(); + foreach ($lines_block as $account => $mt) { + $account_infos = $this->getAccountingAccountInfos($account); + + if ($type == 'view') { + $account_to_show = length_accounta($account); + if (($account_to_show == "") || $account_to_show == 'NotDefined') { + $account_to_show = '' . $langs->trans("AssetInAccountNotDefined") . ''; + } + + $blocks[] = array( + 'date' => $disposal_date_formatted, + 'piece' => $element_link, + 'account_accounting' => $account_to_show, + 'subledger_account' => '', + 'label_operation' => $label_operation . ' - ' . $disposal_ref, + 'debit' => $mt < 0 ? price(-$mt) : '', + 'credit' => $mt >= 0 ? price($mt) : '', + ); + } elseif ($type == 'bookkeeping') { + if ($account_infos['found']) { + $blocks[] = array( + 'doc_date' => $disposal_date, + 'date_lim_reglement' => '', + 'doc_ref' => $element_static->ref, + 'date_creation' => $now, + 'doc_type' => 'asset', + 'fk_doc' => $element_static->id, + 'fk_docdet' => 0, // Useless, can be several lines that are source of this record to add + 'thirdparty_code' => '', + 'subledger_account' => '', + 'subledger_label' => '', + 'numero_compte' => $account, + 'label_compte' => $account_infos['label'], + 'label_operation' => $element_name_formatted_0 . ' - ' . $disposal_ref, + 'montant' => $mt, + 'sens' => $mt < 0 ? 'D' : 'C', + 'debit' => $mt < 0 ? -$mt : 0, + 'credit' => $mt >= 0 ? $mt : 0, + 'code_journal' => $journal, + 'journal_label' => $journal_label_formatted, + 'piece_num' => '', + 'import_key' => '', + 'fk_user_author' => $user->id, + 'entity' => $conf->entity, + ); + } + } else { // $type == 'csv' + $blocks[] = array( + $disposal_date, // Date + $element_static->ref, // Piece + $account_infos['code_formatted_1'], // AccountAccounting + $element_name_formatted_0 . ' - ' . $disposal_ref, // LabelOperation + $mt < 0 ? price(-$mt) : '', // Debit + $mt >= 0 ? price($mt) : '', // Credit + ); + } + } + $element['blocks'][] = $blocks; + } + } + } + } + } + + $journal_data[$pre_data_id] = $element; + } + unset($pre_data); + + return $journal_data; + } + + /** + * Write bookkeeping + * + * @param User $user User who write in the bookkeeping + * @param array $journal_data Journal data to write in the bookkeeping + * $journal_data = array( + * id_element => array( + * 'ref' => 'ref', + * 'error' => '', + * 'blocks' => array( + * pos_block => array( + * num_line => array( + * 'doc_date' => '', + * 'date_lim_reglement' => '', + * 'doc_ref' => '', + * 'date_creation' => '', + * 'doc_type' => '', + * 'fk_doc' => '', + * 'fk_docdet' => '', + * 'thirdparty_code' => '', + * 'subledger_account' => '', + * 'subledger_label' => '', + * 'numero_compte' => '', + * 'label_compte' => '', + * 'label_operation' => '', + * 'montant' => '', + * 'sens' => '', + * 'debit' => '', + * 'credit' => '', + * 'code_journal' => '', + * 'journal_label' => '', + * 'piece_num' => '', + * 'import_key' => '', + * 'fk_user_author' => '', + * 'entity' => '', + * ), + * ), + * ), + * ), + * ); + * @param int $max_nb_errors Nb error authorized before stop the process + * @return int <0 if KO, >0 if OK + */ + public function writeIntoBookkeeping(User $user, &$journal_data = array(), $max_nb_errors = 10) + { + global $conf, $langs, $hookmanager; + require_once DOL_DOCUMENT_ROOT . '/accountancy/class/bookkeeping.class.php'; + + // Hook + if (!is_object($hookmanager)) { + include_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php'; + $hookmanager = new HookManager($this->db); + } + + $error = 0; + + $hookmanager->initHooks(array('accountingjournaldao')); + $parameters = array('journal_data' => &$journal_data); + $reshook = $hookmanager->executeHooks('writeBookkeeping', $parameters, $this); // Note that $action and $object may have been + if ($reshook < 0) { + $this->error = $hookmanager->error; + $this->errors = $hookmanager->errors; + return -1; + } elseif (empty($reshook)) { + // Clean parameters + $journal_data = is_array($journal_data) ? $journal_data : array(); + + foreach ($journal_data as $element_id => $element) { + $error_for_line = 0; + $total_credit = 0; + $total_debit = 0; + + $this->db->begin(); + + if ($element['error'] == 'somelinesarenotbound') { + $error++; + $error_for_line++; + $this->errors[] = $langs->trans('ErrorInvoiceContainsLinesNotYetBounded', $element['ref']); + } + + if (!$error_for_line) { + foreach ($element['blocks'] as $lines) { + foreach ($lines as $line) { + $bookkeeping = new BookKeeping($this->db); + $bookkeeping->doc_date = $line['doc_date']; + $bookkeeping->date_lim_reglement = $line['date_lim_reglement']; + $bookkeeping->doc_ref = $line['doc_ref']; + $bookkeeping->date_creation = $line['date_creation']; // not used + $bookkeeping->doc_type = $line['doc_type']; + $bookkeeping->fk_doc = $line['fk_doc']; + $bookkeeping->fk_docdet = $line['fk_docdet']; + $bookkeeping->thirdparty_code = $line['thirdparty_code']; + $bookkeeping->subledger_account = $line['subledger_account']; + $bookkeeping->subledger_label = $line['subledger_label']; + $bookkeeping->numero_compte = $line['numero_compte']; + $bookkeeping->label_compte = $line['label_compte']; + $bookkeeping->label_operation = $line['label_operation']; + $bookkeeping->montant = $line['montant']; + $bookkeeping->sens = $line['sens']; + $bookkeeping->debit = $line['debit']; + $bookkeeping->credit = $line['credit']; + $bookkeeping->code_journal = $line['code_journal']; + $bookkeeping->journal_label = $line['journal_label']; + $bookkeeping->piece_num = $line['piece_num']; + $bookkeeping->import_key = $line['import_key']; + $bookkeeping->fk_user_author = $user->id; + $bookkeeping->entity = $conf->entity; + + $total_debit += $bookkeeping->debit; + $total_credit += $bookkeeping->credit; + + $result = $bookkeeping->create($user); + if ($result < 0) { + if ($bookkeeping->error == 'BookkeepingRecordAlreadyExists') { // Already exists + $error++; + $error_for_line++; + $journal_data[$element_id]['error'] = 'alreadyjournalized'; + } else { + $error++; + $error_for_line++; + $journal_data[$element_id]['error'] = 'other'; + $this->errors[] = $bookkeeping->errorsToString(); + } + } +// +// if (!$error_for_line && !empty($conf->asset->enabled) && $this->nature == 1 && $bookkeeping->fk_doc > 0) { +// // Set last cumulative depreciation +// require_once DOL_DOCUMENT_ROOT . '/asset/class/asset.class.php'; +// $asset = new Asset($this->db); +// $result = $asset->setLastCumulativeDepreciation($bookkeeping->fk_doc); +// if ($result < 0) { +// $error++; +// $error_for_line++; +// $journal_data[$element_id]['error'] = 'other'; +// $this->errors[] = $asset->errorsToString(); +// } +// } + } + + if ($error_for_line) { + break; + } + } + } + + // Protection against a bug on lines before + if (!$error_for_line && (price2num($total_debit, 'MT') != price2num($total_credit, 'MT'))) { + $error++; + $error_for_line++; + $journal_data[$element_id]['error'] = 'amountsnotbalanced'; + $this->errors[] = 'Try to insert a non balanced transaction in book for ' . $element['blocks'] . '. Canceled. Surely a bug.'; + } + + if (!$error_for_line) { + $this->db->commit(); + } else { + $this->db->rollback(); + + if ($error >= $max_nb_errors) { + $this->errors[] = $langs->trans("ErrorTooManyErrorsProcessStopped"); + break; // Break in the foreach + } + } + } + } + + return $error ? -$error : 1; + } + + /** + * Export journal CSV + * ISO and not UTF8 ! + * + * @param array $journal_data Journal data to write in the bookkeeping + * $journal_data = array( + * id_element => array( + * 'continue' => false, + * 'blocks' => array( + * pos_block => array( + * num_line => array( + * data to write in the CSV line + * ), + * ), + * ), + * ), + * ); + * @param int $search_date_end Search date end + * @param string $sep CSV separator + * @return int|string <0 if KO, >0 if OK + */ + public function exportCsv(&$journal_data = array(), $search_date_end = 0, $sep = '') + { + global $conf, $langs, $hookmanager; + + if (empty($sep)) $sep = $conf->global->ACCOUNTING_EXPORT_SEPARATORCSV; + $out = ''; + + // Hook + if (!is_object($hookmanager)) { + include_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php'; + $hookmanager = new HookManager($this->db); + } + + $hookmanager->initHooks(array('accountingjournaldao')); + $parameters = array('journal_data' => &$journal_data, 'search_date_end' => &$search_date_end, 'sep' => &$sep, 'out' => &$out); + $reshook = $hookmanager->executeHooks('exportCsv', $parameters, $this); // Note that $action and $object may have been + if ($reshook < 0) { + $this->error = $hookmanager->error; + $this->errors = $hookmanager->errors; + return -1; + } elseif (empty($reshook)) { + // Clean parameters + $journal_data = is_array($journal_data) ? $journal_data : array(); + + // CSV header line + $header = array(); + if ($this->nature == 4) { + $header = array( + $langs->transnoentitiesnoconv("BankId"), + $langs->transnoentitiesnoconv("Date"), + $langs->transnoentitiesnoconv("PaymentMode"), + $langs->transnoentitiesnoconv("AccountAccounting"), + $langs->transnoentitiesnoconv("LedgerAccount"), + $langs->transnoentitiesnoconv("SubledgerAccount"), + $langs->transnoentitiesnoconv("Label"), + $langs->transnoentitiesnoconv("Debit"), + $langs->transnoentitiesnoconv("Credit"), + $langs->transnoentitiesnoconv("Journal"), + $langs->transnoentitiesnoconv("Note"), + ); + } elseif ($this->nature == 5) { + $header = array( + $langs->transnoentitiesnoconv("Date"), + $langs->transnoentitiesnoconv("Piece"), + $langs->transnoentitiesnoconv("AccountAccounting"), + $langs->transnoentitiesnoconv("LabelOperation"), + $langs->transnoentitiesnoconv("Debit"), + $langs->transnoentitiesnoconv("Credit"), + ); + } elseif ($this->nature == 1) { + $header = array( + $langs->transnoentitiesnoconv("Date"), + $langs->transnoentitiesnoconv("Piece"), + $langs->transnoentitiesnoconv("AccountAccounting"), + $langs->transnoentitiesnoconv("LabelOperation"), + $langs->transnoentitiesnoconv("Debit"), + $langs->transnoentitiesnoconv("Credit"), + ); + } + + if (!empty($header)) $out .= '"' . implode('"' . $sep . '"', $header) . '"' . "\n"; + foreach ($journal_data as $element_id => $element) { + foreach ($element['blocks'] as $lines) { + foreach ($lines as $line) { + $out .= '"' . implode('"' . $sep . '"', $line) . '"' . "\n"; + } + } + } + } + + return $out; + } + + /** + * Get accounting account infos + * + * @param string $account Accounting account number + * @return array Accounting account infos + */ + function getAccountingAccountInfos($account) { + if (!isset(self::$accounting_account_cached[$account])) { + require_once DOL_DOCUMENT_ROOT . '/core/lib/accounting.lib.php'; + require_once DOL_DOCUMENT_ROOT . '/accountancy/class/accountingaccount.class.php'; + $accountingaccount = new AccountingAccount($this->db); + $result = $accountingaccount->fetch(null, $account, true); + if ($result > 0) { + self::$accounting_account_cached[$account] = array( + 'found' => true, + 'label' => $accountingaccount->label, + 'code_formatted_1' => length_accounta(html_entity_decode($account)), + 'label_formatted_1' => utf8_decode(dol_trunc($accountingaccount->label, 32)), + 'label_formatted_2' => dol_trunc($accountingaccount->label, 32), + ); + } else { + self::$accounting_account_cached[$account] = array( + 'found' => false, + 'label' => '', + 'code_formatted_1' => length_accounta(html_entity_decode($account)), + 'label_formatted_1' => '', + 'label_formatted_2' => '', + ); + } + } + + return self::$accounting_account_cached[$account]; + } } diff --git a/htdocs/accountancy/journal/variousjournal.php b/htdocs/accountancy/journal/variousjournal.php new file mode 100644 index 00000000000..378c0dbb915 --- /dev/null +++ b/htdocs/accountancy/journal/variousjournal.php @@ -0,0 +1,311 @@ + + * + * 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 + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/accountancy/journal/journal.php + * \ingroup Accountancy (Double entries) + * \brief Page of a journal + */ + +require '../../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingjournal.class.php'; + +// Load translation files required by the page +$langs->loadLangs(array("banks", "accountancy", "compta", "other", "errors")); + +$id_journal = GETPOST('id_journal', 'int'); +$action = GETPOST('action', 'aZ09'); + +$date_startmonth = GETPOST('date_startmonth'); +$date_startday = GETPOST('date_startday'); +$date_startyear = GETPOST('date_startyear'); +$date_endmonth = GETPOST('date_endmonth'); +$date_endday = GETPOST('date_endday'); +$date_endyear = GETPOST('date_endyear'); +$in_bookkeeping = GETPOST('in_bookkeeping'); +if ($in_bookkeeping == '') { + $in_bookkeeping = 'notyet'; +} + +// Security check +if (empty($conf->accounting->enabled)) { + accessforbidden(); +} +if ($user->socid > 0) { + accessforbidden(); +} +if (empty($user->rights->accounting->mouvements->lire)) { + accessforbidden(); +} + +// Get information of journal +$object = new AccountingJournal($db); +$result = $object->fetch($id_journal); +if ($result > 0) { + $id_journal = $object->id; +} elseif ($result < 0) { + dol_print_error('', $object->error, $object->errors); +} elseif ($result == 0) { + accessforbidden($langs->trans('ErrorRecordNotFound')); +} + +$hookmanager->initHooks(array('globaljournal', $object->nature_text . 'journal')); +$parameters = array(); + +$date_start = dol_mktime(0, 0, 0, $date_startmonth, $date_startday, $date_startyear); +$date_end = dol_mktime(23, 59, 59, $date_endmonth, $date_endday, $date_endyear); + +if (empty($date_startmonth) || empty($date_endmonth)) { + // Period by default on transfer + $dates = getDefaultDatesForTransfer(); + $date_start = $dates['date_start']; + $date_end = $dates['date_end']; + $pastmonthyear = $dates['pastmonthyear']; + $pastmonth = $dates['pastmonth']; +} + +if (!GETPOSTISSET('date_startmonth') && (empty($date_start) || empty($date_end))) { // We define date_start and date_end, only if we did not submit the form + $date_start = dol_get_first_day($pastmonthyear, $pastmonth, false); + $date_end = dol_get_last_day($pastmonthyear, $pastmonth, false); +} + +$data_type = 'view'; +if ($action == 'writebookkeeping') $data_type = 'bookkeeping'; +if ($action == 'exportcsv') $data_type = 'csv'; +$journal_data = $object->getData($user, $data_type, $date_start, $date_end, $in_bookkeeping); +if (!is_array($journal_data)) { + setEventMessages($object->error, $object->errors, 'errors'); +} + +/* + * Actions + */ + +$reshook = $hookmanager->executeHooks('doActions', $parameters, $user, $action); // Note that $action and $object may have been modified by some hooks + +$reload = false; + +// Bookkeeping Write +if ($action == 'writebookkeeping') { + $error = 0; + + $result = $object->writeIntoBookkeeping($user, $journal_data); + if ($result < 0) { + setEventMessages($object->error, $object->errors, 'errors'); + $error = abs($result); + } + + $nb_elements = count($journal_data); + if (empty($error) && $nb_elements > 0) { + setEventMessages($langs->trans("GeneralLedgerIsWritten"), null, 'mesgs'); + } elseif ($nb_elements == $error) { + setEventMessages($langs->trans("NoNewRecordSaved"), null, 'warnings'); + } else { + setEventMessages($langs->trans("GeneralLedgerSomeRecordWasNotRecorded"), null, 'warnings'); + } + + $reload = true; +} + +// Export +elseif ($action == 'exportcsv') { + $result = $object->exportCsv($journal_data, $date_end); + if ($result < 0) { + setEventMessages($object->error, $object->errors, 'errors'); + $reload = true; + } else { + $filename = 'journal'; + $type_export = 'journal'; + + require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php'; + include DOL_DOCUMENT_ROOT.'/accountancy/tpl/export_journal.tpl.php'; + + print $result; + + $db->close(); + exit(); + } +} + +// Must reload data, so we make a redirect +if ($reload) { + $param = 'id_journal=' . $id_journal; + $param .= '&date_startday=' . $date_startday; + $param .= '&date_startmonth=' . $date_startmonth; + $param .= '&date_startyear=' . $date_startyear; + $param .= '&date_endday=' . $date_endday; + $param .= '&date_endmonth=' . $date_endmonth; + $param .= '&date_endyear=' . $date_endyear; + $param .= '&in_bookkeeping=' . $in_bookkeeping; + header("Location: " . $_SERVER['PHP_SELF'] . ($param ? '?' . $param : '')); + exit; +} + + +/* + * View + */ + +$form = new Form($db); + +if ($object->nature == 2) { + $title = $langs->trans("SellsJournal"); + $some_mandatory_steps_of_setup_were_not_done = $conf->global->ACCOUNTING_ACCOUNT_CUSTOMER == "" || $conf->global->ACCOUNTING_ACCOUNT_CUSTOMER == '-1'; + $account_accounting_not_defined = $conf->global->ACCOUNTING_ACCOUNT_CUSTOMER == "" || $conf->global->ACCOUNTING_ACCOUNT_CUSTOMER == '-1'; +} elseif ($object->nature == 3) { + $title = $langs->trans("PurchasesJournal"); + $some_mandatory_steps_of_setup_were_not_done = $conf->global->ACCOUNTING_ACCOUNT_SUPPLIER == "" || $conf->global->ACCOUNTING_ACCOUNT_SUPPLIER == '-1'; + $account_accounting_not_defined = $conf->global->ACCOUNTING_ACCOUNT_SUPPLIER == "" || $conf->global->ACCOUNTING_ACCOUNT_SUPPLIER == '-1'; +} elseif ($object->nature == 4) { + $title = $langs->trans("FinanceJournal"); + $some_mandatory_steps_of_setup_were_not_done = $conf->global->ACCOUNTING_ACCOUNT_CUSTOMER == "" || $conf->global->ACCOUNTING_ACCOUNT_CUSTOMER == '-1' + || $conf->global->ACCOUNTING_ACCOUNT_SUPPLIER == "" || $conf->global->ACCOUNTING_ACCOUNT_SUPPLIER == '-1' + || empty($conf->global->SALARIES_ACCOUNTING_ACCOUNT_PAYMENT) || $conf->global->SALARIES_ACCOUNTING_ACCOUNT_PAYMENT == '-1'; + $account_accounting_not_defined = $conf->global->ACCOUNTING_ACCOUNT_CUSTOMER == "" || $conf->global->ACCOUNTING_ACCOUNT_CUSTOMER == '-1' + || $conf->global->ACCOUNTING_ACCOUNT_SUPPLIER == "" || $conf->global->ACCOUNTING_ACCOUNT_SUPPLIER == '-1'; +} elseif ($object->nature == 5) { + $title = $langs->trans("ExpenseReportsJournal"); + $some_mandatory_steps_of_setup_were_not_done = empty($conf->global->SALARIES_ACCOUNTING_ACCOUNT_PAYMENT) || $conf->global->SALARIES_ACCOUNTING_ACCOUNT_PAYMENT == '-1'; + $account_accounting_not_defined = empty($conf->global->SALARIES_ACCOUNTING_ACCOUNT_PAYMENT) || $conf->global->SALARIES_ACCOUNTING_ACCOUNT_PAYMENT == '-1'; +} else { + $title = $object->getLibType(); + $some_mandatory_steps_of_setup_were_not_done = false; + $account_accounting_not_defined = false; +} + + +$nom = $title . ' | ' . $object->getNomUrl(0, 1, 1, '', 1); +$nomlink = ''; +$periodlink = ''; +$exportlink = ''; +$builddate = dol_now(); +$description = $langs->trans("DescJournalOnlyBindedVisible") . '
'; +if ($object->nature == 2 || $object->nature == 3) { + if (!empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) { + $description .= $langs->trans("DepositsAreNotIncluded"); + } else { + $description .= $langs->trans("DepositsAreIncluded"); + } +} + +$listofchoices = array('notyet' => $langs->trans("NotYetInGeneralLedger"), 'already' => $langs->trans("AlreadyInGeneralLedger")); +$period = $form->selectDate($date_start ? $date_start : -1, 'date_start', 0, 0, 0, '', 1, 0) . ' - ' . $form->selectDate($date_end ? $date_end : -1, 'date_end', 0, 0, 0, '', 1, 0); +$period .= ' - ' . $langs->trans("JournalizationInLedgerStatus") . ' ' . $form->selectarray('in_bookkeeping', $listofchoices, $in_bookkeeping, 1); + +$varlink = 'id_journal=' . $id_journal; + +llxHeader('', $title); + +journalHead($nom, $nomlink, $period, $periodlink, $description, $builddate, $exportlink, array('action' => ''), '', $varlink); + +if ($object->nature == 4) { // Bank journal + // Test that setup is complete (we are in accounting, so test on entity is always on $conf->entity only, no sharing allowed) + $sql = 'SELECT COUNT(rowid) as nb FROM ' . MAIN_DB_PREFIX . 'bank_account WHERE entity = ' . $conf->entity . ' AND fk_accountancy_journal IS NULL AND clos=0'; + $resql = $db->query($sql); + if ($resql) { + $obj = $db->fetch_object($resql); + if ($obj->nb > 0) { + print '
' . img_warning() . ' ' . $langs->trans("TheJournalCodeIsNotDefinedOnSomeBankAccount"); + print ' : ' . $langs->trans("AccountancyAreaDescBank", 9, '' . $langs->transnoentitiesnoconv("MenuAccountancy") . '-' . $langs->transnoentitiesnoconv("Setup") . "-" . $langs->transnoentitiesnoconv("BankAccounts") . ''); + } + } else dol_print_error($db); +} + +// Button to write into Ledger +if ($some_mandatory_steps_of_setup_were_not_done) { + print '
' . img_warning() . ' ' . $langs->trans("SomeMandatoryStepsOfSetupWereNotDone"); + print ' : ' . $langs->trans("AccountancyAreaDescMisc", 4, '' . $langs->transnoentitiesnoconv("MenuAccountancy") . '-' . $langs->transnoentitiesnoconv("Setup") . "-" . $langs->transnoentitiesnoconv("MenuDefaultAccounts") . ''); + print '
'; +} +print '
'; +if (!empty($conf->global->ACCOUNTING_ENABLE_EXPORT_DRAFT_JOURNAL) && $in_bookkeeping == 'notyet') { + print ''; +} +if ($account_accounting_not_defined) { + print ''; +} else { + if ($in_bookkeeping == 'notyet') { + print ''; + } else { + print '' . $langs->trans("WriteBookKeeping") . ''; + } +} +print '
'; + +// TODO Avoid using js. We can use a direct link with $param +print ' + '; + +$object_label = $langs->trans("ObjectsRef"); +if ($object->nature == 2 || $object->nature == 3) $object_label = $langs->trans("InvoiceRef"); +if ($object->nature == 5) $object_label = $langs->trans("ExpenseReportRef"); + +/* + * Show result array + */ +print '
'; + +print '
'; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +if ($object->nature == 4) print ''; // bank +print ''; +print ''; +print "\n"; + +foreach ($journal_data as $element_id => $element) { + foreach ($element['blocks'] as $lines) { + foreach ($lines as $line) { + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + if ($object->nature == 4) print ''; + print ''; + print ''; + print ''; + } + } +} + +print '
' . $langs->trans("Date") . '' . $langs->trans("Piece") . ' (' . $object_label . ')' . $langs->trans("AccountAccounting") . '' . $langs->trans("SubledgerAccount") . '' . $langs->trans("LabelOperation") . '' . $langs->trans("PaymentMode") . '' . $langs->trans("Debit") . '' . $langs->trans("Credit") . '
' . $line['date'] . '' . $line['piece'] . '' . $line['account_accounting'] . '' . $line['subledger_account'] . '' . $line['label_operation'] . '' . $line['payment_mode'] . '' . $line['debit'] . '' . $line['credit'] . '
'; +print '
'; + +llxFooter(); + +$db->close(); From dd5be840aa75c448121502c77e72582ae80df3d1 Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Mon, 14 Feb 2022 03:31:30 +0000 Subject: [PATCH 03/20] Fixing style errors. --- .../class/accountingjournal.class.php | 133 +++++++++--------- 1 file changed, 67 insertions(+), 66 deletions(-) diff --git a/htdocs/accountancy/class/accountingjournal.class.php b/htdocs/accountancy/class/accountingjournal.class.php index d233dcc0c2e..5ccaa971e5c 100644 --- a/htdocs/accountancy/class/accountingjournal.class.php +++ b/htdocs/accountancy/class/accountingjournal.class.php @@ -394,12 +394,12 @@ class AccountingJournal extends CommonObject case 1: // Various Journal $data = $this->getAssetData($user, $type, $date_start, $date_end, $in_bookkeeping); break; -// case 2: // Sells Journal -// case 3: // Purchases Journal -// case 4: // Bank Journal -// case 5: // Expense reports Journal -// case 8: // Inventory Journal -// case 9: // hasnew Journal + // case 2: // Sells Journal + // case 3: // Purchases Journal + // case 4: // Bank Journal + // case 5: // Expense reports Journal + // case 8: // Inventory Journal + // case 9: // hasnew Journal } } @@ -519,8 +519,8 @@ class AccountingJournal extends CommonObject $journal_data = array(); foreach ($pre_data['elements'] as $pre_data_id => $pre_data_info) { $element_static->id = $pre_data_id; - $element_static->ref = (string)$pre_data_info["ref"]; - $element_static->label = (string)$pre_data_info["label"]; + $element_static->ref = (string) $pre_data_info["ref"]; + $element_static->label = (string) $pre_data_info["label"]; $element_static->acquisition_value_ht = $pre_data_info["acquisition_value_ht"]; $element_link = $element_static->getNomUrl(1, 'with_label'); @@ -655,7 +655,7 @@ class AccountingJournal extends CommonObject $lines[0][$accountancy_code_depreciation_asset] = -$last_cumulative_amount_ht; $lines[0][$accountancy_code_asset] = $element_static->acquisition_value_ht; - $disposal_amount_vat = $disposal_subject_to_vat ? (double)price2num($disposal_amount * $disposal_vat / 100, 'MT') : 0; + $disposal_amount_vat = $disposal_subject_to_vat ? (double) price2num($disposal_amount * $disposal_vat / 100, 'MT') : 0; $lines[1][$accountancy_code_receivable_on_assignment] = -($disposal_amount + $disposal_amount_vat); if ($disposal_subject_to_vat) $lines[1][$accountancy_code_vat_collected] = $disposal_amount_vat; $lines[1][$accountancy_code_proceeds_from_sales] = $disposal_amount; @@ -739,39 +739,39 @@ class AccountingJournal extends CommonObject * @param User $user User who write in the bookkeeping * @param array $journal_data Journal data to write in the bookkeeping * $journal_data = array( - * id_element => array( - * 'ref' => 'ref', - * 'error' => '', - * 'blocks' => array( - * pos_block => array( - * num_line => array( - * 'doc_date' => '', - * 'date_lim_reglement' => '', - * 'doc_ref' => '', - * 'date_creation' => '', - * 'doc_type' => '', - * 'fk_doc' => '', - * 'fk_docdet' => '', - * 'thirdparty_code' => '', - * 'subledger_account' => '', - * 'subledger_label' => '', - * 'numero_compte' => '', - * 'label_compte' => '', - * 'label_operation' => '', - * 'montant' => '', - * 'sens' => '', - * 'debit' => '', - * 'credit' => '', - * 'code_journal' => '', - * 'journal_label' => '', - * 'piece_num' => '', - * 'import_key' => '', - * 'fk_user_author' => '', - * 'entity' => '', - * ), - * ), - * ), - * ), + * id_element => array( + * 'ref' => 'ref', + * 'error' => '', + * 'blocks' => array( + * pos_block => array( + * num_line => array( + * 'doc_date' => '', + * 'date_lim_reglement' => '', + * 'doc_ref' => '', + * 'date_creation' => '', + * 'doc_type' => '', + * 'fk_doc' => '', + * 'fk_docdet' => '', + * 'thirdparty_code' => '', + * 'subledger_account' => '', + * 'subledger_label' => '', + * 'numero_compte' => '', + * 'label_compte' => '', + * 'label_operation' => '', + * 'montant' => '', + * 'sens' => '', + * 'debit' => '', + * 'credit' => '', + * 'code_journal' => '', + * 'journal_label' => '', + * 'piece_num' => '', + * 'import_key' => '', + * 'fk_user_author' => '', + * 'entity' => '', + * ), + * ), + * ), + * ), * ); * @param int $max_nb_errors Nb error authorized before stop the process * @return int <0 if KO, >0 if OK @@ -857,19 +857,19 @@ class AccountingJournal extends CommonObject $this->errors[] = $bookkeeping->errorsToString(); } } -// -// if (!$error_for_line && !empty($conf->asset->enabled) && $this->nature == 1 && $bookkeeping->fk_doc > 0) { -// // Set last cumulative depreciation -// require_once DOL_DOCUMENT_ROOT . '/asset/class/asset.class.php'; -// $asset = new Asset($this->db); -// $result = $asset->setLastCumulativeDepreciation($bookkeeping->fk_doc); -// if ($result < 0) { -// $error++; -// $error_for_line++; -// $journal_data[$element_id]['error'] = 'other'; -// $this->errors[] = $asset->errorsToString(); -// } -// } + // + // if (!$error_for_line && !empty($conf->asset->enabled) && $this->nature == 1 && $bookkeeping->fk_doc > 0) { + // // Set last cumulative depreciation + // require_once DOL_DOCUMENT_ROOT . '/asset/class/asset.class.php'; + // $asset = new Asset($this->db); + // $result = $asset->setLastCumulativeDepreciation($bookkeeping->fk_doc); + // if ($result < 0) { + // $error++; + // $error_for_line++; + // $journal_data[$element_id]['error'] = 'other'; + // $this->errors[] = $asset->errorsToString(); + // } + // } } if ($error_for_line) { @@ -908,16 +908,16 @@ class AccountingJournal extends CommonObject * * @param array $journal_data Journal data to write in the bookkeeping * $journal_data = array( - * id_element => array( - * 'continue' => false, - * 'blocks' => array( - * pos_block => array( - * num_line => array( - * data to write in the CSV line - * ), - * ), - * ), - * ), + * id_element => array( + * 'continue' => false, + * 'blocks' => array( + * pos_block => array( + * num_line => array( + * data to write in the CSV line + * ), + * ), + * ), + * ), * ); * @param int $search_date_end Search date end * @param string $sep CSV separator @@ -1002,7 +1002,8 @@ class AccountingJournal extends CommonObject * @param string $account Accounting account number * @return array Accounting account infos */ - function getAccountingAccountInfos($account) { + function getAccountingAccountInfos($account) + { if (!isset(self::$accounting_account_cached[$account])) { require_once DOL_DOCUMENT_ROOT . '/core/lib/accounting.lib.php'; require_once DOL_DOCUMENT_ROOT . '/accountancy/class/accountingaccount.class.php'; From 6734a3575e80f351cf52c49c4e2b671e512fd0ff Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Mon, 14 Feb 2022 04:52:39 +0100 Subject: [PATCH 04/20] Core --- htdocs/core/class/commonobject.class.php | 4 +- htdocs/core/lib/asset.lib.php | 193 ++- htdocs/core/menus/standard/auguria.lib.php | 2 +- htdocs/core/menus/standard/eldy.lib.php | 10 +- .../doc/doc_generic_asset_odt.modules.php | 499 ++++++ .../asset/doc/pdf_standard_asset.modules.php | 1375 +++++++++++++++++ .../core/modules/asset/mod_asset_advanced.php | 147 ++ .../core/modules/asset/mod_asset_standard.php | 161 ++ htdocs/core/modules/asset/modules_asset.php | 158 ++ htdocs/core/modules/modAsset.class.php | 26 +- htdocs/core/tpl/objectline_create.tpl.php | 6 +- htdocs/core/tpl/objectline_edit.tpl.php | 6 + htdocs/core/tpl/objectline_title.tpl.php | 5 + htdocs/core/tpl/objectline_view.tpl.php | 30 + 14 files changed, 2545 insertions(+), 77 deletions(-) create mode 100644 htdocs/core/modules/asset/doc/doc_generic_asset_odt.modules.php create mode 100644 htdocs/core/modules/asset/doc/pdf_standard_asset.modules.php create mode 100644 htdocs/core/modules/asset/mod_asset_advanced.php create mode 100644 htdocs/core/modules/asset/mod_asset_standard.php create mode 100644 htdocs/core/modules/asset/modules_asset.php diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index 87f6ba693fc..00a263f358d 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -7,7 +7,7 @@ * Copyright (C) 2012-2015 Marcos García * Copyright (C) 2012-2015 Raphaël Doursenaud * Copyright (C) 2012 Cedric Salvador - * Copyright (C) 2015-2021 Alexandre Spangaro + * Copyright (C) 2015-2022 Alexandre Spangaro * Copyright (C) 2016 Bahfir abbes * Copyright (C) 2017 ATM Consulting * Copyright (C) 2017-2019 Nicolas ZABOURI @@ -3670,7 +3670,7 @@ abstract class CommonObject // Elements of the core modules which have `$module` property but may to which we don't want to prefix module part to the element name for finding the linked object in llx_element_element. // It's because an entry for this element may be exist in llx_element_element before this modification (version <=14.2) and ave named only with their element name in fk_source or fk_target. - $coremodule = array('knowledgemanagement', 'partnership', 'workstation', 'ticket', 'recruitment', 'eventorganization'); + $coremodule = array('knowledgemanagement', 'partnership', 'workstation', 'ticket', 'recruitment', 'eventorganization', 'asset'); // Add module part to target type if object has $module property and isn't in core modules. $targettype = ((!empty($this->module) && ! in_array($this->module, $coremodule)) ? $this->module.'_' : '').$this->element; diff --git a/htdocs/core/lib/asset.lib.php b/htdocs/core/lib/asset.lib.php index 840aca1339a..9d71e2b38f1 100644 --- a/htdocs/core/lib/asset.lib.php +++ b/htdocs/core/lib/asset.lib.php @@ -1,5 +1,5 @@ +/* Copyright (C) 2018-2022 OpenDSI * * 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 @@ -26,7 +26,7 @@ * * @return array head array with tabs */ -function asset_admin_prepare_head() +function assetAdminPrepareHead() { global $langs, $conf; @@ -43,90 +43,118 @@ function asset_admin_prepare_head() // Show more tabs from modules // Entries must be declared in modules descriptor with line //$this->tabs = array( - // 'entity:+tabname:Title:@assets:/asset/mypage.php?id=__ID__' + // 'entity:+tabname:Title:@asset:/asset/mypage.php?id=__ID__' //); // to add new tab //$this->tabs = array( - // 'entity:-tabname:Title:@assets:/asset/mypage.php?id=__ID__' + // 'entity:-tabname:Title:@asset:/asset/mypage.php?id=__ID__' //); // to remove a tab - complete_head_from_modules($conf, $langs, null, $head, $h, 'assets_admin'); + complete_head_from_modules($conf, $langs, null, $head, $h, 'asset_admin'); - $head[$h][0] = DOL_URL_ROOT.'/asset/admin/assets_extrafields.php'; + $head[$h][0] = DOL_URL_ROOT.'/asset/admin/asset_extrafields.php'; $head[$h][1] = $langs->trans("ExtraFields"); - $head[$h][2] = 'attributes'; + $head[$h][2] = 'asset_extrafields'; $h++; - $head[$h][0] = DOL_URL_ROOT.'/asset/admin/assets_type_extrafields.php'; - $head[$h][1] = $langs->trans("ExtraFieldsAssetsType"); - $head[$h][2] = 'attributes_type'; + $head[$h][0] = DOL_URL_ROOT.'/asset/admin/assetmodel_extrafields.php'; + $head[$h][1] = $langs->trans("ExtraFieldsAssetModel"); + $head[$h][2] = 'assetmodel_extrafields'; $h++; - complete_head_from_modules($conf, $langs, null, $head, $h, 'assets_admin', 'remove'); + complete_head_from_modules($conf, $langs, null, $head, $h, 'asset_admin', 'remove'); return $head; } /** - * Prepare admin pages header + * Prepare array of tabs for Asset * - * @param Contrat $object Object related to tabs - * @return array head array with tabs + * @param Asset $object Asset + * @return array Array of tabs */ -function asset_prepare_head(Asset $object) +function assetPrepareHead(Asset $object) { global $db, $langs, $conf; - $langs->load("assets"); + $langs->load("assets", "admin"); $h = 0; $head = array(); - $head[$h][0] = DOL_URL_ROOT.'/asset/card.php?id='.$object->id; + $head[$h][0] = DOL_URL_ROOT . '/asset/card.php?id=' . $object->id; $head[$h][1] = $langs->trans("Card"); $head[$h][2] = 'card'; $h++; + if (empty($object->not_depreciated)) { + $head[$h][0] = DOL_URL_ROOT . '/asset/depreciation_options.php?id=' . $object->id; + $head[$h][1] = $langs->trans("AssetDepreciationOptions"); + $head[$h][2] = 'depreciation_options'; + $h++; + } + + $head[$h][0] = DOL_URL_ROOT . '/asset/accountancy_codes.php?id=' . $object->id; + $head[$h][1] = $langs->trans("AssetAccountancyCodes"); + $head[$h][2] = 'accountancy_codes'; + $h++; + + if (empty($object->not_depreciated)) { + $head[$h][0] = DOL_URL_ROOT . '/asset/depreciation.php?id=' . $object->id; + $head[$h][1] = $langs->trans("AssetDepreciation"); + $head[$h][2] = 'depreciation'; + $h++; + } + + if (isset($object->disposal_date) && $object->disposal_date !== "") { + $head[$h][0] = DOL_URL_ROOT . '/asset/disposal.php?id=' . $object->id; + $head[$h][1] = $langs->trans("AssetDisposal"); + $head[$h][2] = 'disposal'; + $h++; + } + + if (isset($object->fields['note_public']) || isset($object->fields['note_private'])) { + $nbNote = 0; + if (!empty($object->note_private)) { + $nbNote++; + } + if (!empty($object->note_public)) { + $nbNote++; + } + $head[$h][0] = DOL_URL_ROOT . '/asset/note.php?id=' . $object->id; + $head[$h][1] = $langs->trans('Notes'); + if ($nbNote > 0) { + $head[$h][1] .= (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER) ? '' . $nbNote . '' : ''); + } + $head[$h][2] = 'note'; + $h++; + } + + require_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php'; + require_once DOL_DOCUMENT_ROOT . '/core/class/link.class.php'; + $upload_dir = $conf->asset->dir_output . "/asset/" . dol_sanitizeFileName($object->ref); + $nbFiles = count(dol_dir_list($upload_dir, 'files', 0, '', '(\.meta|_preview.*\.png)$')); + $nbLinks = Link::count($db, $object->element, $object->id); + $head[$h][0] = DOL_URL_ROOT . '/asset/document.php?id=' . $object->id; + $head[$h][1] = $langs->trans('Documents'); + if (($nbFiles + $nbLinks) > 0) { + $head[$h][1] .= '' . ($nbFiles + $nbLinks) . ''; + } + $head[$h][2] = 'document'; + $h++; + + $head[$h][0] = DOL_URL_ROOT . '/asset/agenda.php?id=' . $object->id; + $head[$h][1] = $langs->trans("Events"); + $head[$h][2] = 'agenda'; + $h++; + // Show more tabs from modules // Entries must be declared in modules descriptor with line //$this->tabs = array( - // 'entity:+tabname:Title:@assets:/asset/mypage.php?id=__ID__' + // 'entity:+tabname:Title:@asset:/asset/mypage.php?id=__ID__' //); // to add new tab //$this->tabs = array( - // 'entity:-tabname:Title:@assets:/asset/mypage.php?id=__ID__' + // 'entity:-tabname:Title:@asset:/asset/mypage.php?id=__ID__' //); // to remove a tab - complete_head_from_modules($conf, $langs, $object, $head, $h, 'assets'); - - require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; - require_once DOL_DOCUMENT_ROOT.'/core/class/link.class.php'; - $upload_dir = $conf->assets->dir_output.'/'.dol_sanitizeFileName($object->ref); - $nbFiles = count(dol_dir_list($upload_dir, 'files', 0, '', '(\.meta|_preview.*\.png)$')); - $nbLinks = Link::count($db, $object->element, $object->id); - $head[$h][0] = DOL_URL_ROOT.'/asset/document.php?id='.$object->id; - $head[$h][1] = $langs->trans('Documents'); - if (($nbFiles + $nbLinks) > 0) { - $head[$h][1] .= ''.($nbFiles + $nbLinks).''; - } - $head[$h][2] = 'documents'; - $h++; - - $nbNote = 0; - if (!empty($object->note_private)) { - $nbNote++; - } - if (!empty($object->note_public)) { - $nbNote++; - } - $head[$h][0] = DOL_URL_ROOT.'/asset/note.php?id='.$object->id; - $head[$h][1] = $langs->trans("Notes"); - if ($nbNote > 0) { - $head[$h][1] .= ''.$nbNote.''; - } - $head[$h][2] = 'note'; - $h++; - - $head[$h][0] = DOL_URL_ROOT.'/asset/info.php?id='.$object->id; - $head[$h][1] = $langs->trans("Info"); - $head[$h][2] = 'info'; - $h++; + complete_head_from_modules($conf, $langs, $object, $head, $h, 'asset'); complete_head_from_modules($conf, $langs, $object, $head, $h, 'asset', 'remove'); @@ -134,30 +162,69 @@ function asset_prepare_head(Asset $object) } /** - * Return array head with list of tabs to view object informations + * Prepare array of tabs for AssetModel * - * @param AssetType $object Asset - * @return array head + * @param AssetModel $object AssetModel + * @return array Array of tabs */ -function asset_type_prepare_head(AssetType $object) +function assetModelPrepareHead($object) { - global $langs, $conf, $user; + global $langs, $conf; + + $langs->load("assets", "admin"); $h = 0; $head = array(); - $head[$h][0] = DOL_URL_ROOT.'/asset/type.php?rowid='.$object->id; + $head[$h][0] = DOL_URL_ROOT . '/asset/model/card.php?id=' . $object->id; $head[$h][1] = $langs->trans("Card"); $head[$h][2] = 'card'; $h++; + $head[$h][0] = DOL_URL_ROOT . '/asset/model/depreciation_options.php?id=' . $object->id; + $head[$h][1] = $langs->trans("AssetDepreciationOptions"); + $head[$h][2] = 'depreciation_options'; + $h++; + + $head[$h][0] = DOL_URL_ROOT . '/asset/model/accountancy_codes.php?id=' . $object->id; + $head[$h][1] = $langs->trans("AssetAccountancyCodes"); + $head[$h][2] = 'accountancy_codes'; + $h++; + + if (isset($object->fields['note_public']) || isset($object->fields['note_private'])) { + $nbNote = 0; + if (!empty($object->note_private)) { + $nbNote++; + } + if (!empty($object->note_public)) { + $nbNote++; + } + $head[$h][0] = DOL_URL_ROOT . '/asset/model/note.php?id=' . $object->id; + $head[$h][1] = $langs->trans('Notes'); + if ($nbNote > 0) { + $head[$h][1] .= (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER) ? '' . $nbNote . '' : ''); + } + $head[$h][2] = 'note'; + $h++; + } + + $head[$h][0] = DOL_URL_ROOT . '/asset/model/agenda.php?id=' . $object->id; + $head[$h][1] = $langs->trans("Events"); + $head[$h][2] = 'agenda'; + $h++; + + // Show more tabs from modules // Entries must be declared in modules descriptor with line - // $this->tabs = array('entity:+tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__'); to add new tab - // $this->tabs = array('entity:-tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__'); to remove a tab - complete_head_from_modules($conf, $langs, $object, $head, $h, 'assettype'); + //$this->tabs = array( + // 'entity:+tabname:Title:@asset:/asset/mypage.php?id=__ID__' + //); // to add new tab + //$this->tabs = array( + // 'entity:-tabname:Title:@asset:/asset/mypage.php?id=__ID__' + //); // to remove a tab + complete_head_from_modules($conf, $langs, $object, $head, $h, 'assetmodel'); - complete_head_from_modules($conf, $langs, $object, $head, $h, 'assettype', 'remove'); + complete_head_from_modules($conf, $langs, $object, $head, $h, 'assetmodel', 'remove'); return $head; } diff --git a/htdocs/core/menus/standard/auguria.lib.php b/htdocs/core/menus/standard/auguria.lib.php index 6504cfa27a6..6b415aec7a2 100644 --- a/htdocs/core/menus/standard/auguria.lib.php +++ b/htdocs/core/menus/standard/auguria.lib.php @@ -410,7 +410,7 @@ function print_left_auguria_menu($db, $menu_array_before, $menu_array_after, &$t // To enable when page exists if (empty($conf->global->ACCOUNTANCY_SHOW_DEVELOP_JOURNAL)) { - if ($nature == 'various' || $nature == 'hasnew' || $nature == 'inventory') { + if ($nature == 'hasnew' || $nature == 'inventory') { $nature = ''; } } diff --git a/htdocs/core/menus/standard/eldy.lib.php b/htdocs/core/menus/standard/eldy.lib.php index e69644bd123..9361b01b086 100644 --- a/htdocs/core/menus/standard/eldy.lib.php +++ b/htdocs/core/menus/standard/eldy.lib.php @@ -1332,7 +1332,7 @@ function print_left_eldy_menu($db, $menu_array_before, $menu_array_after, &$tabM // To enable when page exists if (empty($conf->global->ACCOUNTANCY_SHOW_DEVELOP_JOURNAL)) { - if ($nature == 'various' || $nature == 'hasnew' || $nature == 'inventory') { + if ($nature == 'hasnew' || $nature == 'inventory') { $nature = ''; } } @@ -1507,10 +1507,10 @@ function print_left_eldy_menu($db, $menu_array_before, $menu_array_after, &$tabM $newmenu->add("/asset/list.php?leftmenu=asset&mainmenu=accountancy", $langs->trans("MenuAssets"), 0, $user->rights->asset->read, '', $mainmenu, 'asset', 100, '', '', '', img_picto('', 'payment', 'class="paddingright pictofixedwidth"')); $newmenu->add("/asset/card.php?leftmenu=asset&action=create", $langs->trans("MenuNewAsset"), 1, $user->rights->asset->write); $newmenu->add("/asset/list.php?leftmenu=asset&mainmenu=accountancy", $langs->trans("MenuListAssets"), 1, $user->rights->asset->read); - $newmenu->add("/asset/type.php?leftmenu=asset_type", $langs->trans("MenuTypeAssets"), 1, $user->rights->asset->read, '', $mainmenu, 'asset_type'); - if ($usemenuhider || empty($leftmenu) || preg_match('/asset_type/', $leftmenu)) { - $newmenu->add("/asset/type.php?leftmenu=asset_type&action=create", $langs->trans("MenuNewTypeAssets"), 2, $user->rights->asset->setup_advance); - $newmenu->add("/asset/type.php?leftmenu=asset_type", $langs->trans("MenuListTypeAssets"), 2, $user->rights->asset->read); + $newmenu->add("/asset/model/list.php?leftmenu=asset_model", $langs->trans("MenuAssetModels"), 1, (empty($conf->global->MAIN_USE_ADVANCED_PERMS) && $user->rights->asset->read) || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->asset->setup_advance->read)), '', $mainmenu, 'asset_model'); + if ($usemenuhider || empty($leftmenu) || preg_match('/asset_model/', $leftmenu)) { + $newmenu->add("/asset/model/card.php?leftmenu=asset_model&action=create", $langs->trans("MenuNewAssetModel"), 2, (empty($conf->global->MAIN_USE_ADVANCED_PERMS) && $user->rights->asset->write) || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->asset->setup_advance->write))); + $newmenu->add("/asset/model/list.php?leftmenu=asset_model", $langs->trans("MenuListAssetModels"), 2, (empty($conf->global->MAIN_USE_ADVANCED_PERMS) && $user->rights->asset->read) || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->asset->setup_advance->read))); } } } diff --git a/htdocs/core/modules/asset/doc/doc_generic_asset_odt.modules.php b/htdocs/core/modules/asset/doc/doc_generic_asset_odt.modules.php new file mode 100644 index 00000000000..7fe684c9da1 --- /dev/null +++ b/htdocs/core/modules/asset/doc/doc_generic_asset_odt.modules.php @@ -0,0 +1,499 @@ + + * Copyright (C) 2012 Juanjo Menent + * Copyright (C) 2014 Marcos García + * Copyright (C) 2016 Charlie Benke + * Copyright (C) 2018-2021 Philippe Grand + * Copyright (C) 2018 Frédéric France + * + * 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 + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * or see https://www.gnu.org/ + */ + +/** + * \file htdocs/core/modules/asset/doc/doc_generic_asset_odt.modules.php + * \ingroup asset + * \brief File of class to build ODT documents for assets + */ + +dol_include_once('/asset/core/modules/asset/modules_asset.php'); +require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/doc.lib.php'; + + +/** + * Class to build documents using ODF templates generator + */ +class doc_generic_asset_odt extends ModelePDFAsset +{ + /** + * Issuer + * @var Societe + */ + public $emetteur; + + /** + * @var array Minimum version of PHP required by module. + * e.g.: PHP ≥ 5.6 = array(5, 6) + */ + public $phpmin = array(5, 6); + + /** + * @var string Dolibarr version of the loaded document + */ + public $version = 'dolibarr'; + + + /** + * Constructor + * + * @param DoliDB $db Database handler + */ + public function __construct($db) + { + global $conf, $langs, $mysoc; + + // Load translation files required by the page + $langs->loadLangs(array("main", "companies")); + + $this->db = $db; + $this->name = "ODT templates"; + $this->description = $langs->trans("DocumentModelOdt"); + $this->scandir = 'ASSET_ASSET_ADDON_PDF_ODT_PATH'; // Name of constant that is used to save list of directories to scan + + // Page size for A4 format + $this->type = 'odt'; + $this->page_largeur = 0; + $this->page_hauteur = 0; + $this->format = array($this->page_largeur, $this->page_hauteur); + $this->marge_gauche = 0; + $this->marge_droite = 0; + $this->marge_haute = 0; + $this->marge_basse = 0; + + $this->option_logo = 1; // Display logo + $this->option_tva = 0; // Manage the vat option FACTURE_TVAOPTION + $this->option_modereg = 0; // Display payment mode + $this->option_condreg = 0; // Display payment terms + $this->option_codeproduitservice = 0; // Display product-service code + $this->option_multilang = 1; // Available in several languages + $this->option_escompte = 0; // Displays if there has been a discount + $this->option_credit_note = 0; // Support credit notes + $this->option_freetext = 1; // Support add of a personalised text + $this->option_draft_watermark = 0; // Support add of a watermark on drafts + + // Get source company + $this->emetteur = $mysoc; + if (!$this->emetteur->country_code) { + $this->emetteur->country_code = substr($langs->defaultlang, -2); // By default if not defined + } + } + + + /** + * Return description of a module + * + * @param Translate $langs Lang object to use for output + * @return string Description + */ + public function info($langs) + { + global $conf, $langs; + + // Load translation files required by the page + $langs->loadLangs(array("errors", "companies")); + + $form = new Form($this->db); + + $texte = $this->description.".
\n"; + $texte .= '
'; + $texte .= ''; + $texte .= ''; + $texte .= ''; + $texte .= ''; + + // List of directories area + $texte .= ''; + + $texte .= ''; + $texte .= ''; + + $texte .= '
'; + $texttitle = $langs->trans("ListOfDirectories"); + $listofdir = explode(',', preg_replace('/[\r\n]+/', ',', trim($conf->global->ASSET_ASSET_ADDON_PDF_ODT_PATH))); + $listoffiles = array(); + foreach ($listofdir as $key => $tmpdir) { + $tmpdir = trim($tmpdir); + $tmpdir = preg_replace('/DOL_DATA_ROOT/', DOL_DATA_ROOT, $tmpdir); + if (!$tmpdir) { + unset($listofdir[$key]); + continue; + } + if (!is_dir($tmpdir)) { + $texttitle .= img_warning($langs->trans("ErrorDirNotFound", $tmpdir), 0); + } else { + $tmpfiles = dol_dir_list($tmpdir, 'files', 0, '\.(ods|odt)'); + if (count($tmpfiles)) { + $listoffiles = array_merge($listoffiles, $tmpfiles); + } + } + } + $texthelp = $langs->trans("ListOfDirectoriesForModelGenODT"); + // Add list of substitution keys + $texthelp .= '
'.$langs->trans("FollowingSubstitutionKeysCanBeUsed").'
'; + $texthelp .= $langs->transnoentitiesnoconv("FullListOnOnlineDocumentation"); // This contains an url, we don't modify it + + $texte .= $form->textwithpicto($texttitle, $texthelp, 1, 'help', '', 1); + $texte .= '
'; + $texte .= ''; + $texte .= '
'; + $texte .= ''; + $texte .= '
'; + + // Scan directories + $nbofiles = count($listoffiles); + if (!empty($conf->global->ASSET_ASSET_ADDON_PDF_ODT_PATH)) { + $texte .= $langs->trans("NumberOfModelFilesFound").': '; + //$texte.=$nbofiles?'':''; + $texte .= count($listoffiles); + //$texte.=$nbofiles?'':''; + $texte .= ''; + } + + if ($nbofiles) { + $texte .= ''; + } + + $texte .= '
'; + $texte .= $langs->trans("ExampleOfDirectoriesForModelGen"); + $texte .= '
'; + $texte .= '
'; + + return $texte; + } + + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Function to build a document on disk using the generic odt module. + * + * @param Asset $object Object source to build document + * @param Translate $outputlangs Lang output object + * @param string $srctemplatepath Full path of source filename for generator using a template file + * @param int $hidedetails Do not show line details + * @param int $hidedesc Do not show desc + * @param int $hideref Do not show ref + * @return int 1 if OK, <=0 if KO + */ + public function write_file($object, $outputlangs, $srctemplatepath, $hidedetails = 0, $hidedesc = 0, $hideref = 0) + { + // phpcs:enable + global $user, $langs, $conf, $mysoc, $hookmanager; + + if (empty($srctemplatepath)) { + dol_syslog("doc_generic_odt::write_file parameter srctemplatepath empty", LOG_WARNING); + return -1; + } + + // Add odtgeneration hook + if (!is_object($hookmanager)) { + include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; + $hookmanager = new HookManager($this->db); + } + $hookmanager->initHooks(array('odtgeneration')); + global $action; + + if (!is_object($outputlangs)) { + $outputlangs = $langs; + } + $sav_charset_output = $outputlangs->charset_output; + $outputlangs->charset_output = 'UTF-8'; + + $outputlangs->loadLangs(array("main", "dict", "companies", "bills")); + + if ($conf->asset->dir_output) { + // If $object is id instead of object + if (!is_object($object)) { + $id = $object; + $object = new Asset($this->db); + $result = $object->fetch($id); + if ($result < 0) { + dol_print_error($this->db, $object->error); + return -1; + } + } + + $object->fetch_thirdparty(); + + $dir = $conf->asset->multidir_output[isset($object->entity) ? $object->entity : 1]; + $objectref = dol_sanitizeFileName($object->ref); + if (!preg_match('/specimen/i', $objectref)) { + $dir .= "/".$objectref; + } + $file = $dir."/".$objectref.".odt"; + + if (!file_exists($dir)) { + if (dol_mkdir($dir) < 0) { + $this->error = $langs->transnoentities("ErrorCanNotCreateDir", $dir); + return -1; + } + } + + if (file_exists($dir)) { + //print "srctemplatepath=".$srctemplatepath; // Src filename + $newfile = basename($srctemplatepath); + $newfiletmp = preg_replace('/\.od(t|s)/i', '', $newfile); + $newfiletmp = preg_replace('/template_/i', '', $newfiletmp); + $newfiletmp = preg_replace('/modele_/i', '', $newfiletmp); + $newfiletmp = $objectref.'_'.$newfiletmp; + //$file=$dir.'/'.$newfiletmp.'.'.dol_print_date(dol_now(),'%Y%m%d%H%M%S').'.odt'; + // Get extension (ods or odt) + $newfileformat = substr($newfile, strrpos($newfile, '.') + 1); + if (!empty($conf->global->MAIN_DOC_USE_TIMING)) { + $format = $conf->global->MAIN_DOC_USE_TIMING; + if ($format == '1') { + $format = '%Y%m%d%H%M%S'; + } + $filename = $newfiletmp.'-'.dol_print_date(dol_now(), $format).'.'.$newfileformat; + } else { + $filename = $newfiletmp.'.'.$newfileformat; + } + $file = $dir.'/'.$filename; + //print "newdir=".$dir; + //print "newfile=".$newfile; + //print "file=".$file; + //print "conf->societe->dir_temp=".$conf->societe->dir_temp; + + dol_mkdir($conf->asset->dir_temp); + if (!is_writable($conf->asset->dir_temp)) { + $this->error = "Failed to write in temp directory ".$conf->asset->dir_temp; + dol_syslog('Error in write_file: '.$this->error, LOG_ERR); + return -1; + } + + // If CUSTOMER contact defined on order, we use it + $usecontact = false; + $arrayidcontact = $object->getIdContact('external', 'CUSTOMER'); + if (count($arrayidcontact) > 0) { + $usecontact = true; + $result = $object->fetch_contact($arrayidcontact[0]); + } + + // Recipient name + $contactobject = null; + if (!empty($usecontact)) { + // We can use the company of contact instead of thirdparty company + if ($object->contact->socid != $object->thirdparty->id && (!isset($conf->global->MAIN_USE_COMPANY_NAME_OF_CONTACT) || !empty($conf->global->MAIN_USE_COMPANY_NAME_OF_CONTACT))) { + $object->contact->fetch_thirdparty(); + $socobject = $object->contact->thirdparty; + $contactobject = $object->contact; + } else { + $socobject = $object->thirdparty; + // if we have a CUSTOMER contact and we dont use it as thirdparty recipient we store the contact object for later use + $contactobject = $object->contact; + } + } else { + $socobject = $object->thirdparty; + } + + // Make substitution + $substitutionarray = array( + '__FROM_NAME__' => $this->emetteur->name, + '__FROM_EMAIL__' => $this->emetteur->email, + '__TOTAL_TTC__' => $object->total_ttc, + '__TOTAL_HT__' => $object->total_ht, + '__TOTAL_VAT__' => $object->total_tva + ); + complete_substitutions_array($substitutionarray, $langs, $object); + // Call the ODTSubstitution hook + $parameters = array('file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs, 'substitutionarray'=>&$substitutionarray); + $reshook = $hookmanager->executeHooks('ODTSubstitution', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks + + // Line of free text + $newfreetext = ''; + $paramfreetext = 'ORDER_FREE_TEXT'; + if (!empty($conf->global->$paramfreetext)) { + $newfreetext = make_substitutions($conf->global->$paramfreetext, $substitutionarray); + } + + // Open and load template + require_once ODTPHP_PATH.'odf.php'; + try { + $odfHandler = new odf( + $srctemplatepath, + array( + 'PATH_TO_TMP' => $conf->asset->dir_temp, + 'ZIP_PROXY' => 'PclZipProxy', // PhpZipProxy or PclZipProxy. Got "bad compression method" error when using PhpZipProxy. + 'DELIMITER_LEFT' => '{', + 'DELIMITER_RIGHT' => '}' + ) + ); + } catch (Exception $e) { + $this->error = $e->getMessage(); + dol_syslog($e->getMessage(), LOG_INFO); + return -1; + } + // After construction $odfHandler->contentXml contains content and + // [!-- BEGIN row.lines --]*[!-- END row.lines --] has been replaced by + // [!-- BEGIN lines --]*[!-- END lines --] + //print html_entity_decode($odfHandler->__toString()); + //print exit; + + + // Make substitutions into odt of freetext + try { + $odfHandler->setVars('free_text', $newfreetext, true, 'UTF-8'); + } catch (OdfException $e) { + dol_syslog($e->getMessage(), LOG_INFO); + } + + // Define substitution array + $substitutionarray = getCommonSubstitutionArray($outputlangs, 0, null, $object); + $array_object_from_properties = $this->get_substitutionarray_each_var_object($object, $outputlangs); + $array_objet = $this->get_substitutionarray_object($object, $outputlangs); + $array_user = $this->get_substitutionarray_user($user, $outputlangs); + $array_soc = $this->get_substitutionarray_mysoc($mysoc, $outputlangs); + $array_thirdparty = $this->get_substitutionarray_thirdparty($socobject, $outputlangs); + $array_other = $this->get_substitutionarray_other($outputlangs); + // retrieve contact information for use in object as contact_xxx tags + $array_thirdparty_contact = array(); + if ($usecontact && is_object($contactobject)) { + $array_thirdparty_contact = $this->get_substitutionarray_contact($contactobject, $outputlangs, 'contact'); + } + + $tmparray = array_merge($substitutionarray, $array_object_from_properties, $array_user, $array_soc, $array_thirdparty, $array_objet, $array_other, $array_thirdparty_contact); + complete_substitutions_array($tmparray, $outputlangs, $object); + + // Call the ODTSubstitution hook + $parameters = array('odfHandler'=>&$odfHandler, 'file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs, 'substitutionarray'=>&$tmparray); + $reshook = $hookmanager->executeHooks('ODTSubstitution', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks + + foreach ($tmparray as $key => $value) { + try { + if (preg_match('/logo$/', $key)) { + // Image + if (file_exists($value)) { + $odfHandler->setImage($key, $value); + } else { + $odfHandler->setVars($key, 'ErrorFileNotFound', true, 'UTF-8'); + } + } else { + // Text + $odfHandler->setVars($key, $value, true, 'UTF-8'); + } + } catch (OdfException $e) { + dol_syslog($e->getMessage(), LOG_INFO); + } + } + // Replace tags of lines + try { + $foundtagforlines = 1; + try { + $listlines = $odfHandler->setSegment('lines'); + } catch (OdfException $e) { + // We may arrive here if tags for lines not present into template + $foundtagforlines = 0; + dol_syslog($e->getMessage(), LOG_INFO); + } + if ($foundtagforlines) { + $linenumber = 0; + foreach ($object->lines as $line) { + $linenumber++; + $tmparray = $this->get_substitutionarray_lines($line, $outputlangs, $linenumber); + complete_substitutions_array($tmparray, $outputlangs, $object, $line, "completesubstitutionarray_lines"); + // Call the ODTSubstitutionLine hook + $parameters = array('odfHandler'=>&$odfHandler, 'file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs, 'substitutionarray'=>&$tmparray, 'line'=>$line); + $reshook = $hookmanager->executeHooks('ODTSubstitutionLine', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks + foreach ($tmparray as $key => $val) { + try { + $listlines->setVars($key, $val, true, 'UTF-8'); + } catch (OdfException $e) { + dol_syslog($e->getMessage(), LOG_INFO); + } catch (SegmentException $e) { + dol_syslog($e->getMessage(), LOG_INFO); + } + } + $listlines->merge(); + } + $odfHandler->mergeSegment($listlines); + } + } catch (OdfException $e) { + $this->error = $e->getMessage(); + dol_syslog($this->error, LOG_WARNING); + return -1; + } + + // Replace labels translated + $tmparray = $outputlangs->get_translations_for_substitutions(); + foreach ($tmparray as $key => $value) { + try { + $odfHandler->setVars($key, $value, true, 'UTF-8'); + } catch (OdfException $e) { + dol_syslog($e->getMessage(), LOG_INFO); + } + } + + // Call the beforeODTSave hook + + $parameters = array('odfHandler'=>&$odfHandler, 'file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs, 'substitutionarray'=>&$tmparray); + $reshook = $hookmanager->executeHooks('beforeODTSave', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks + + // Write new file + if (!empty($conf->global->MAIN_ODT_AS_PDF)) { + try { + $odfHandler->exportAsAttachedPDF($file); + } catch (Exception $e) { + $this->error = $e->getMessage(); + dol_syslog($e->getMessage(), LOG_INFO); + return -1; + } + } else { + try { + $odfHandler->saveToDisk($file); + } catch (Exception $e) { + $this->error = $e->getMessage(); + dol_syslog($e->getMessage(), LOG_INFO); + return -1; + } + } + + $parameters = array('odfHandler'=>&$odfHandler, 'file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs, 'substitutionarray'=>&$tmparray); + $reshook = $hookmanager->executeHooks('afterODTCreation', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks + + if (!empty($conf->global->MAIN_UMASK)) { + @chmod($file, octdec($conf->global->MAIN_UMASK)); + } + + $odfHandler = null; // Destroy object + + $this->result = array('fullpath'=>$file); + + return 1; // Success + } else { + $this->error = $langs->transnoentities("ErrorCanNotCreateDir", $dir); + return -1; + } + } + + return -1; + } +} diff --git a/htdocs/core/modules/asset/doc/pdf_standard_asset.modules.php b/htdocs/core/modules/asset/doc/pdf_standard_asset.modules.php new file mode 100644 index 00000000000..de378ee79a8 --- /dev/null +++ b/htdocs/core/modules/asset/doc/pdf_standard_asset.modules.php @@ -0,0 +1,1375 @@ + + * Copyright (C) 2005-2012 Regis Houssin + * Copyright (C) 2008 Raphael Bertrand + * Copyright (C) 2010-2014 Juanjo Menent + * Copyright (C) 2012 Christophe Battarel + * Copyright (C) 2012 Cédric Salvador + * Copyright (C) 2012-2014 Raphaël Doursenaud + * Copyright (C) 2015 Marcos García + * Copyright (C) 2017 Ferran Marcet + * Copyright (C) 2018 Frédéric France + * + * 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 + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * or see https://www.gnu.org/ + */ + +/** + * \file core/modules/asset/doc/pdf_standard.modules.php + * \ingroup asset + * \brief File of class to generate document from standard template + */ + +dol_include_once('/asset/core/modules/asset/modules_asset.php'); +require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php'; + + +/** + * Class to manage PDF template standard_asset + */ +class pdf_standard_asset extends ModelePDFAsset +{ + /** + * @var DoliDb Database handler + */ + public $db; + + /** + * @var string model name + */ + public $name; + + /** + * @var string model description (short text) + */ + public $description; + + /** + * @var int Save the name of generated file as the main doc when generating a doc with this template + */ + public $update_main_doc_field; + + /** + * @var string document type + */ + public $type; + + /** + * @var array Minimum version of PHP required by module. + * e.g.: PHP ≥ 5.6 = array(5, 6) + */ + public $phpmin = array(5, 6); + + /** + * Dolibarr version of the loaded document + * @var string + */ + public $version = 'dolibarr'; + + /** + * @var int page_largeur + */ + public $page_largeur; + + /** + * @var int page_hauteur + */ + public $page_hauteur; + + /** + * @var array format + */ + public $format; + + /** + * @var int marge_gauche + */ + public $marge_gauche; + + /** + * @var int marge_droite + */ + public $marge_droite; + + /** + * @var int marge_haute + */ + public $marge_haute; + + /** + * @var int marge_basse + */ + public $marge_basse; + + /** + * Issuer + * @var Societe Object that emits + */ + public $emetteur; + + /** + * @var bool Situation invoice type + */ + public $situationinvoice; + + + /** + * @var array of document table columns + */ + public $cols; + + + /** + * Constructor + * + * @param DoliDB $db Database handler + */ + public function __construct($db) + { + global $conf, $langs, $mysoc; + + // Translations + $langs->loadLangs(array("main", "bills")); + + $this->db = $db; + $this->name = "standard"; + $this->description = $langs->trans('DocumentModelStandardPDF'); + $this->update_main_doc_field = 1; // Save the name of generated file as the main doc when generating a doc with this template + + // Dimension page + $this->type = 'pdf'; + $formatarray = pdf_getFormat(); + $this->page_largeur = $formatarray['width']; + $this->page_hauteur = $formatarray['height']; + $this->format = array($this->page_largeur, $this->page_hauteur); + $this->marge_gauche = isset($conf->global->MAIN_PDF_MARGIN_LEFT) ? $conf->global->MAIN_PDF_MARGIN_LEFT : 10; + $this->marge_droite = isset($conf->global->MAIN_PDF_MARGIN_RIGHT) ? $conf->global->MAIN_PDF_MARGIN_RIGHT : 10; + $this->marge_haute = isset($conf->global->MAIN_PDF_MARGIN_TOP) ? $conf->global->MAIN_PDF_MARGIN_TOP : 10; + $this->marge_basse = isset($conf->global->MAIN_PDF_MARGIN_BOTTOM) ? $conf->global->MAIN_PDF_MARGIN_BOTTOM : 10; + + // Get source company + $this->emetteur = $mysoc; + if (empty($this->emetteur->country_code)) { + $this->emetteur->country_code = substr($langs->defaultlang, -2); // By default, if was not defined + } + + // Define position of columns + $this->posxdesc = $this->marge_gauche + 1; // used for notes ans other stuff + + + $this->tabTitleHeight = 5; // default height + + // Use new system for position of columns, view $this->defineColumnField() + + $this->tva = array(); + $this->localtax1 = array(); + $this->localtax2 = array(); + $this->atleastoneratenotnull = 0; + $this->atleastonediscount = 0; + $this->situationinvoice = false; + } + + + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Function to build pdf onto disk + * + * @param Object $object Object to generate + * @param Translate $outputlangs Lang output object + * @param string $srctemplatepath Full path of source filename for generator using a template file + * @param int $hidedetails Do not show line details + * @param int $hidedesc Do not show desc + * @param int $hideref Do not show ref + * @return int 1=OK, 0=KO + */ + public function write_file($object, $outputlangs, $srctemplatepath = '', $hidedetails = 0, $hidedesc = 0, $hideref = 0) + { + // phpcs:enable + global $user, $langs, $conf, $mysoc, $db, $hookmanager, $nblines; + + dol_syslog("write_file outputlangs->defaultlang=".(is_object($outputlangs) ? $outputlangs->defaultlang : 'null')); + + if (!is_object($outputlangs)) { + $outputlangs = $langs; + } + // For backward compatibility with FPDF, force output charset to ISO, because FPDF expect text to be encoded in ISO + if (!empty($conf->global->MAIN_USE_FPDF)) { + $outputlangs->charset_output = 'ISO-8859-1'; + } + + // Load translation files required by the page + $outputlangs->loadLangs(array("main", "bills", "products", "dict", "companies")); + + if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE) && $outputlangs->defaultlang != $conf->global->PDF_USE_ALSO_LANGUAGE_CODE) { + global $outputlangsbis; + $outputlangsbis = new Translate('', $conf); + $outputlangsbis->setDefaultLang($conf->global->PDF_USE_ALSO_LANGUAGE_CODE); + $outputlangsbis->loadLangs(array("main", "bills", "products", "dict", "companies")); + } + + $nblines = (is_array($object->lines) ? count($object->lines) : 0); + + $hidetop = 0; + if (!empty($conf->global->MAIN_PDF_DISABLE_COL_HEAD_TITLE)) { + $hidetop = $conf->global->MAIN_PDF_DISABLE_COL_HEAD_TITLE; + } + + // Loop on each lines to detect if there is at least one image to show + $realpatharray = array(); + $this->atleastonephoto = false; + /* + if (!empty($conf->global->MAIN_GENERATE_ASSET_WITH_PICTURE)) + { + $objphoto = new Product($this->db); + + for ($i = 0; $i < $nblines; $i++) + { + if (empty($object->lines[$i]->fk_product)) continue; + + //var_dump($objphoto->ref);exit; + if (!empty($conf->global->PRODUCT_USE_OLD_PATH_FOR_PHOTO)) { + $pdir[0] = get_exdir($objphoto->id, 2, 0, 0, $objphoto, 'product').$objphoto->id."/photos/"; + $pdir[1] = get_exdir(0, 0, 0, 0, $objphoto, 'product').dol_sanitizeFileName($objphoto->ref).'/'; + } else { + $pdir[0] = get_exdir(0, 0, 0, 0, $objphoto, 'product'); // default + $pdir[1] = get_exdir($objphoto->id, 2, 0, 0, $objphoto, 'product').$objphoto->id."/photos/"; // alternative + } + + $arephoto = false; + foreach ($pdir as $midir) + { + if (!$arephoto) + { + $dir = $conf->product->dir_output.'/'.$midir; + + foreach ($objphoto->liste_photos($dir, 1) as $key => $obj) + { + if (empty($conf->global->CAT_HIGH_QUALITY_IMAGES)) // If CAT_HIGH_QUALITY_IMAGES not defined, we use thumb if defined and then original photo + { + if ($obj['photo_vignette']) + { + $filename = $obj['photo_vignette']; + } else { + $filename = $obj['photo']; + } + } else { + $filename = $obj['photo']; + } + + $realpath = $dir.$filename; + $arephoto = true; + $this->atleastonephoto = true; + } + } + } + + if ($realpath && $arephoto) $realpatharray[$i] = $realpath; + } + } + */ + + //if (count($realpatharray) == 0) $this->posxpicture=$this->posxtva; + + if ($conf->asset->dir_output.'/asset') { + $object->fetch_thirdparty(); + + // Definition of $dir and $file + if ($object->specimen) { + $dir = $conf->asset->dir_output.'/asset'; + $file = $dir."/SPECIMEN.pdf"; + } else { + $objectref = dol_sanitizeFileName($object->ref); + $dir = $conf->asset->dir_output.'/asset/'.$objectref; + $file = $dir."/".$objectref.".pdf"; + } + if (!file_exists($dir)) { + if (dol_mkdir($dir) < 0) { + $this->error = $langs->transnoentities("ErrorCanNotCreateDir", $dir); + return 0; + } + } + + if (file_exists($dir)) { + // Add pdfgeneration hook + if (!is_object($hookmanager)) { + include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; + $hookmanager = new HookManager($this->db); + } + $hookmanager->initHooks(array('pdfgeneration')); + $parameters = array('file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs); + global $action; + $reshook = $hookmanager->executeHooks('beforePDFCreation', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks + + // Set nblines with the new facture lines content after hook + $nblines = (is_array($object->lines) ? count($object->lines) : 0); + + // Create pdf instance + $pdf = pdf_getInstance($this->format); + $default_font_size = pdf_getPDFFontSize($outputlangs); // Must be after pdf_getInstance + $pdf->SetAutoPageBreak(1, 0); + + $heightforinfotot = 50; // Height reserved to output the info and total part and payment part + $heightforfreetext = (isset($conf->global->MAIN_PDF_FREETEXT_HEIGHT) ? $conf->global->MAIN_PDF_FREETEXT_HEIGHT : 5); // Height reserved to output the free text on last page + $heightforfooter = $this->marge_basse + (empty($conf->global->MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS) ? 12 : 22); // Height reserved to output the footer (value include bottom margin) + + if (class_exists('TCPDF')) { + $pdf->setPrintHeader(false); + $pdf->setPrintFooter(false); + } + $pdf->SetFont(pdf_getPDFFont($outputlangs)); + + // Set path to the background PDF File + if (!empty($conf->global->MAIN_ADD_PDF_BACKGROUND)) { + $pagecount = $pdf->setSourceFile($conf->mycompany->multidir_output[$object->entity].'/'.$conf->global->MAIN_ADD_PDF_BACKGROUND); + $tplidx = $pdf->importPage(1); + } + + $pdf->Open(); + $pagenb = 0; + $pdf->SetDrawColor(128, 128, 128); + + $pdf->SetTitle($outputlangs->convToOutputCharset($object->ref)); + $pdf->SetSubject($outputlangs->transnoentities("PdfTitle")); + $pdf->SetCreator("Dolibarr ".DOL_VERSION); + $pdf->SetAuthor($outputlangs->convToOutputCharset($user->getFullName($outputlangs))); + $pdf->SetKeyWords($outputlangs->convToOutputCharset($object->ref)." ".$outputlangs->transnoentities("PdfTitle")." ".$outputlangs->convToOutputCharset($object->thirdparty->name)); + if (!empty($conf->global->MAIN_DISABLE_PDF_COMPRESSION)) { + $pdf->SetCompression(false); + } + + // Set certificate + $cert = empty($user->conf->CERTIFICATE_CRT) ? '' : $user->conf->CERTIFICATE_CRT; + // If user has no certificate, we try to take the company one + if (!$cert) { + $cert = empty($conf->global->CERTIFICATE_CRT) ? '' : $conf->global->CERTIFICATE_CRT; + } + // If a certificate is found + if ($cert) { + $info = array( + 'Name' => $this->emetteur->name, + 'Location' => getCountry($this->emetteur->country_code, 0), + 'Reason' => 'ASSET', + 'ContactInfo' => $this->emetteur->email + ); + $pdf->setSignature($cert, $cert, $this->emetteur->name, '', 2, $info); + } + + $pdf->SetMargins($this->marge_gauche, $this->marge_haute, $this->marge_droite); // Left, Top, Right + + // New page + $pdf->AddPage(); + if (!empty($tplidx)) { + $pdf->useTemplate($tplidx); + } + $pagenb++; + + $top_shift = $this->_pagehead($pdf, $object, 1, $outputlangs, $outputlangsbis); + $pdf->SetFont('', '', $default_font_size - 1); + $pdf->MultiCell(0, 3, ''); // Set interline to 3 + $pdf->SetTextColor(0, 0, 0); + + $tab_top = 90 + $top_shift; + $tab_top_newpage = (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD) ? 42 + $top_shift : 10); + $tab_height = 130 - $top_shift; + $tab_height_newpage = 150; + if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) { + $tab_height_newpage -= $top_shift; + } + + $nexY = $tab_top - 1; + + // Display notes + $notetoshow = empty($object->note_public) ? '' : $object->note_public; + // Extrafields in note + $extranote = $this->getExtrafieldsInHtml($object, $outputlangs); + if (!empty($extranote)) { + $notetoshow = dol_concatdesc($notetoshow, $extranote); + } + + $pagenb = $pdf->getPage(); + if ($notetoshow) { + $tab_top -= 2; + + $tab_width = $this->page_largeur - $this->marge_gauche - $this->marge_droite; + $pageposbeforenote = $pagenb; + + $substitutionarray = pdf_getSubstitutionArray($outputlangs, null, $object); + complete_substitutions_array($substitutionarray, $outputlangs, $object); + $notetoshow = make_substitutions($notetoshow, $substitutionarray, $outputlangs); + $notetoshow = convertBackOfficeMediasLinksToPublicLinks($notetoshow); + + $pdf->startTransaction(); + + $pdf->SetFont('', '', $default_font_size - 1); + $pdf->writeHTMLCell(190, 3, $this->posxdesc - 1, $tab_top, dol_htmlentitiesbr($notetoshow), 0, 1); + // Description + $pageposafternote = $pdf->getPage(); + $posyafter = $pdf->GetY(); + + if ($pageposafternote > $pageposbeforenote) { + $pdf->rollbackTransaction(true); + + // prepare pages to receive notes + while ($pagenb < $pageposafternote) { + $pdf->AddPage(); + $pagenb++; + if (!empty($tplidx)) { + $pdf->useTemplate($tplidx); + } + if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) { + $this->_pagehead($pdf, $object, 0, $outputlangs); + } + // $this->_pagefoot($pdf,$object,$outputlangs,1); + $pdf->setTopMargin($tab_top_newpage); + // The only function to edit the bottom margin of current page to set it. + $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext); + } + + // back to start + $pdf->setPage($pageposbeforenote); + $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext); + $pdf->SetFont('', '', $default_font_size - 1); + $pdf->writeHTMLCell(190, 3, $this->posxdesc - 1, $tab_top, dol_htmlentitiesbr($notetoshow), 0, 1); + $pageposafternote = $pdf->getPage(); + + $posyafter = $pdf->GetY(); + + if ($posyafter > ($this->page_hauteur - ($heightforfooter + $heightforfreetext + 20))) { // There is no space left for total+free text + $pdf->AddPage('', '', true); + $pagenb++; + $pageposafternote++; + $pdf->setPage($pageposafternote); + $pdf->setTopMargin($tab_top_newpage); + // The only function to edit the bottom margin of current page to set it. + $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext); + //$posyafter = $tab_top_newpage; + } + + + // apply note frame to previous pages + $i = $pageposbeforenote; + while ($i < $pageposafternote) { + $pdf->setPage($i); + + + $pdf->SetDrawColor(128, 128, 128); + // Draw note frame + if ($i > $pageposbeforenote) { + $height_note = $this->page_hauteur - ($tab_top_newpage + $heightforfooter); + $pdf->Rect($this->marge_gauche, $tab_top_newpage - 1, $tab_width, $height_note + 1); + } else { + $height_note = $this->page_hauteur - ($tab_top + $heightforfooter); + $pdf->Rect($this->marge_gauche, $tab_top - 1, $tab_width, $height_note + 1); + } + + // Add footer + $pdf->setPageOrientation('', 1, 0); // The only function to edit the bottom margin of current page to set it. + $this->_pagefoot($pdf, $object, $outputlangs, 1); + + $i++; + } + + // apply note frame to last page + $pdf->setPage($pageposafternote); + if (!empty($tplidx)) { + $pdf->useTemplate($tplidx); + } + if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) { + $this->_pagehead($pdf, $object, 0, $outputlangs); + } + $height_note = $posyafter - $tab_top_newpage; + $pdf->Rect($this->marge_gauche, $tab_top_newpage - 1, $tab_width, $height_note + 1); + } else // No pagebreak + { + $pdf->commitTransaction(); + $posyafter = $pdf->GetY(); + $height_note = $posyafter - $tab_top; + $pdf->Rect($this->marge_gauche, $tab_top - 1, $tab_width, $height_note + 1); + + + if ($posyafter > ($this->page_hauteur - ($heightforfooter + $heightforfreetext + 20))) { + // not enough space, need to add page + $pdf->AddPage('', '', true); + $pagenb++; + $pageposafternote++; + $pdf->setPage($pageposafternote); + if (!empty($tplidx)) { + $pdf->useTemplate($tplidx); + } + if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) { + $this->_pagehead($pdf, $object, 0, $outputlangs); + } + + $posyafter = $tab_top_newpage; + } + } + + $tab_height = $tab_height - $height_note; + $tab_top = $posyafter + 6; + } else { + $height_note = 0; + } + + // Use new auto column system + $this->prepareArrayColumnField($object, $outputlangs, $hidedetails, $hidedesc, $hideref); + + // Table simulation to know the height of the title line + $pdf->startTransaction(); + $this->pdfTabTitles($pdf, $tab_top, $tab_height, $outputlangs, $hidetop); + $pdf->rollbackTransaction(true); + + $nexY = $tab_top + $this->tabTitleHeight; + + // Loop on each lines + $pageposbeforeprintlines = $pdf->getPage(); + $pagenb = $pageposbeforeprintlines; + for ($i = 0; $i < $nblines; $i++) { + $curY = $nexY; + $pdf->SetFont('', '', $default_font_size - 1); // Into loop to work with multipage + $pdf->SetTextColor(0, 0, 0); + + // Define size of image if we need it + $imglinesize = array(); + if (!empty($realpatharray[$i])) { + $imglinesize = pdf_getSizeForImage($realpatharray[$i]); + } + + $pdf->setTopMargin($tab_top_newpage); + $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext + $heightforinfotot); // The only function to edit the bottom margin of current page to set it. + $pageposbefore = $pdf->getPage(); + + $showpricebeforepagebreak = 1; + $posYAfterImage = 0; + + if ($this->getColumnStatus('photo')) { + // We start with Photo of product line + if (isset($imglinesize['width']) && isset($imglinesize['height']) && ($curY + $imglinesize['height']) > ($this->page_hauteur - ($heightforfooter + $heightforfreetext + $heightforinfotot))) { // If photo too high, we moved completely on new page + $pdf->AddPage('', '', true); + if (!empty($tplidx)) { + $pdf->useTemplate($tplidx); + } + $pdf->setPage($pageposbefore + 1); + + $curY = $tab_top_newpage; + + // Allows data in the first page if description is long enough to break in multiples pages + if (!empty($conf->global->MAIN_PDF_DATA_ON_FIRST_PAGE)) { + $showpricebeforepagebreak = 1; + } else { + $showpricebeforepagebreak = 0; + } + } + + if (!empty($this->cols['photo']) && isset($imglinesize['width']) && isset($imglinesize['height'])) { + $pdf->Image($realpatharray[$i], $this->getColumnContentXStart('photo'), $curY, $imglinesize['width'], $imglinesize['height'], '', '', '', 2, 300); // Use 300 dpi + // $pdf->Image does not increase value return by getY, so we save it manually + $posYAfterImage = $curY + $imglinesize['height']; + } + } + + // Description of product line + if ($this->getColumnStatus('desc')) { + $pdf->startTransaction(); + + $this->printColDescContent($pdf, $curY, 'desc', $object, $i, $outputlangs, $hideref, $hidedesc); + $pageposafter = $pdf->getPage(); + + if ($pageposafter > $pageposbefore) { // There is a pagebreak + $pdf->rollbackTransaction(true); + $pdf->setPageOrientation('', 1, $heightforfooter); // The only function to edit the bottom margin of current page to set it. + + $this->printColDescContent($pdf, $curY, 'desc', $object, $i, $outputlangs, $hideref, $hidedesc); + + $pageposafter = $pdf->getPage(); + $posyafter = $pdf->GetY(); + //var_dump($posyafter); var_dump(($this->page_hauteur - ($heightforfooter+$heightforfreetext+$heightforinfotot))); exit; + if ($posyafter > ($this->page_hauteur - ($heightforfooter + $heightforfreetext + $heightforinfotot))) { // There is no space left for total+free text + if ($i == ($nblines - 1)) { // No more lines, and no space left to show total, so we create a new page + $pdf->AddPage('', '', true); + if (!empty($tplidx)) { + $pdf->useTemplate($tplidx); + } + $pdf->setPage($pageposafter + 1); + } + } else { + // We found a page break + // Allows data in the first page if description is long enough to break in multiples pages + if (!empty($conf->global->MAIN_PDF_DATA_ON_FIRST_PAGE)) { + $showpricebeforepagebreak = 1; + } else { + $showpricebeforepagebreak = 0; + } + } + } else // No pagebreak + { + $pdf->commitTransaction(); + } + } + + $nexY = $pdf->GetY(); + $pageposafter = $pdf->getPage(); + $pdf->setPage($pageposbefore); + $pdf->setTopMargin($this->marge_haute); + $pdf->setPageOrientation('', 1, 0); // The only function to edit the bottom margin of current page to set it. + + // We suppose that a too long description or photo were moved completely on next page + if ($pageposafter > $pageposbefore && empty($showpricebeforepagebreak)) { + $pdf->setPage($pageposafter); $curY = $tab_top_newpage; + } + + $pdf->SetFont('', '', $default_font_size - 1); // On repositionne la police par defaut + + // Quantity + // Enough for 6 chars + if ($this->getColumnStatus('qty')) { + $qty = pdf_getlineqty($object, $i, $outputlangs, $hidedetails); + $this->printStdColumnContent($pdf, $curY, 'qty', $qty); + $nexY = max($pdf->GetY(), $nexY); + } + + // Extrafields + if (!empty($object->lines[$i]->array_options)) { + foreach ($object->lines[$i]->array_options as $extrafieldColKey => $extrafieldValue) { + if ($this->getColumnStatus($extrafieldColKey)) { + $extrafieldValue = $this->getExtrafieldContent($object->lines[$i], $extrafieldColKey, $outputlangs); + $this->printStdColumnContent($pdf, $curY, $extrafieldColKey, $extrafieldValue); + $nexY = max($pdf->GetY(), $nexY); + } + } + } + + + $parameters = array( + 'object' => $object, + 'i' => $i, + 'pdf' =>& $pdf, + 'curY' =>& $curY, + 'nexY' =>& $nexY, + 'outputlangs' => $outputlangs, + 'hidedetails' => $hidedetails + ); + $reshook = $hookmanager->executeHooks('printPDFline', $parameters, $this); // Note that $object may have been modified by hook + + + $sign = 1; + // Collecte des totaux par valeur de tva dans $this->tva["taux"]=total_tva + $prev_progress = $object->lines[$i]->get_prev_progress($object->id); + if ($prev_progress > 0 && !empty($object->lines[$i]->situation_percent)) { // Compute progress from previous situation + if (!empty($conf->multicurrency->enabled) && $object->multicurrency_tx != 1) { + $tvaligne = $sign * $object->lines[$i]->multicurrency_total_tva * ($object->lines[$i]->situation_percent - $prev_progress) / $object->lines[$i]->situation_percent; + } else { + $tvaligne = $sign * $object->lines[$i]->total_tva * ($object->lines[$i]->situation_percent - $prev_progress) / $object->lines[$i]->situation_percent; + } + } else { + if (!empty($conf->multicurrency->enabled) && $object->multicurrency_tx != 1) { + $tvaligne = $sign * $object->lines[$i]->multicurrency_total_tva; + } else { + $tvaligne = $sign * $object->lines[$i]->total_tva; + } + } + + $localtax1ligne = $object->lines[$i]->total_localtax1; + $localtax2ligne = $object->lines[$i]->total_localtax2; + $localtax1_rate = $object->lines[$i]->localtax1_tx; + $localtax2_rate = $object->lines[$i]->localtax2_tx; + $localtax1_type = $object->lines[$i]->localtax1_type; + $localtax2_type = $object->lines[$i]->localtax2_type; + + if ($object->remise_percent) { + $tvaligne -= ($tvaligne * $object->remise_percent) / 100; + } + if ($object->remise_percent) { + $localtax1ligne -= ($localtax1ligne * $object->remise_percent) / 100; + } + if ($object->remise_percent) { + $localtax2ligne -= ($localtax2ligne * $object->remise_percent) / 100; + } + + $vatrate = (string) $object->lines[$i]->tva_tx; + + // Retrieve type from database for backward compatibility with old records + if ((!isset($localtax1_type) || $localtax1_type == '' || !isset($localtax2_type) || $localtax2_type == '') // if tax type not defined + && (!empty($localtax1_rate) || !empty($localtax2_rate))) { // and there is local tax + $localtaxtmp_array = getLocalTaxesFromRate($vatrate, 0, $object->thirdparty, $mysoc); + $localtax1_type = isset($localtaxtmp_array[0]) ? $localtaxtmp_array[0] : ''; + $localtax2_type = isset($localtaxtmp_array[2]) ? $localtaxtmp_array[2] : ''; + } + + // retrieve global local tax + if ($localtax1_type && $localtax1ligne != 0) { + $this->localtax1[$localtax1_type][$localtax1_rate] += $localtax1ligne; + } + if ($localtax2_type && $localtax2ligne != 0) { + $this->localtax2[$localtax2_type][$localtax2_rate] += $localtax2ligne; + } + + if (($object->lines[$i]->info_bits & 0x01) == 0x01) { + $vatrate .= '*'; + } + if (!isset($this->tva[$vatrate])) { + $this->tva[$vatrate] = 0; + } + $this->tva[$vatrate] += $tvaligne; + + $nexY = max($nexY, $posYAfterImage); + + // Add line + if (!empty($conf->global->MAIN_PDF_DASH_BETWEEN_LINES) && $i < ($nblines - 1)) { + $pdf->setPage($pageposafter); + $pdf->SetLineStyle(array('dash'=>'1,1', 'color'=>array(80, 80, 80))); + //$pdf->SetDrawColor(190,190,200); + $pdf->line($this->marge_gauche, $nexY, $this->page_largeur - $this->marge_droite, $nexY); + $pdf->SetLineStyle(array('dash'=>0)); + } + + // Detect if some page were added automatically and output _tableau for past pages + while ($pagenb < $pageposafter) { + $pdf->setPage($pagenb); + if ($pagenb == $pageposbeforeprintlines) { + $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, $hidetop, 1, $object->multicurrency_code, $outputlangsbis); + } else { + $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1, $object->multicurrency_code, $outputlangsbis); + } + $this->_pagefoot($pdf, $object, $outputlangs, 1); + $pagenb++; + $pdf->setPage($pagenb); + $pdf->setPageOrientation('', 1, 0); // The only function to edit the bottom margin of current page to set it. + if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) { + $this->_pagehead($pdf, $object, 0, $outputlangs); + } + } + + if (isset($object->lines[$i + 1]->pagebreak) && $object->lines[$i + 1]->pagebreak) { + if ($pagenb == $pageposafter) { + $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, $hidetop, 1, $object->multicurrency_code, $outputlangsbis); + } else { + $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1, $object->multicurrency_code, $outputlangsbis); + } + $this->_pagefoot($pdf, $object, $outputlangs, 1); + // New page + $pdf->AddPage(); + if (!empty($tplidx)) { + $pdf->useTemplate($tplidx); + } + $pagenb++; + if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) { + $this->_pagehead($pdf, $object, 0, $outputlangs); + } + } + } + + // Show square + if ($pagenb == $pageposbeforeprintlines) { + $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, $hidetop, 0, $object->multicurrency_code, $outputlangsbis); + $bottomlasttab = $this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforfooter + 1; + } else { + $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, 1, 0, $object->multicurrency_code, $outputlangsbis); + $bottomlasttab = $this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforfooter + 1; + } + + // Display infos area + //$posy = $this->drawInfoTable($pdf, $object, $bottomlasttab, $outputlangs); + + // Display total zone + //$posy = $this->drawTotalTable($pdf, $object, $deja_regle, $bottomlasttab, $outputlangs); + + // Display payment area + /* + if (($deja_regle || $amount_credit_notes_included || $amount_deposits_included) && empty($conf->global->INVOICE_NO_PAYMENT_DETAILS)) + { + $posy = $this->drawPaymentsTable($pdf, $object, $posy, $outputlangs); + } + */ + + // Pagefoot + $this->_pagefoot($pdf, $object, $outputlangs); + if (method_exists($pdf, 'AliasNbPages')) { + $pdf->AliasNbPages(); + } + + $pdf->Close(); + + $pdf->Output($file, 'F'); + + // Add pdfgeneration hook + $hookmanager->initHooks(array('pdfgeneration')); + $parameters = array('file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs); + global $action; + $reshook = $hookmanager->executeHooks('afterPDFCreation', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks + if ($reshook < 0) { + $this->error = $hookmanager->error; + $this->errors = $hookmanager->errors; + } + + if (!empty($conf->global->MAIN_UMASK)) { + @chmod($file, octdec($conf->global->MAIN_UMASK)); + } + + $this->result = array('fullpath'=>$file); + + return 1; // No error + } else { + $this->error = $langs->transnoentities("ErrorCanNotCreateDir", $dir); + return 0; + } + } else { + $this->error = $langs->transnoentities("ErrorConstantNotDefined", "FAC_OUTPUTDIR"); + return 0; + } + } + + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Return list of active generation modules + * + * @param DoliDB $db Database handler + * @param integer $maxfilenamelength Max length of value to show + * @return array List of templates + */ + public static function liste_modeles($db, $maxfilenamelength = 0) + { + // phpcs:enable + return parent::liste_modeles($db, $maxfilenamelength); // TODO: Change the autogenerated stub + } + + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore + /** + * Show table for lines + * + * @param tcpdf $pdf Object PDF + * @param string $tab_top Top position of table + * @param string $tab_height Height of table (rectangle) + * @param int $nexY Y (not used) + * @param Translate $outputlangs Langs object + * @param int $hidetop 1=Hide top bar of array and title, 0=Hide nothing, -1=Hide only title + * @param int $hidebottom Hide bottom bar of array + * @param string $currency Currency code + * @param Translate $outputlangsbis Langs object bis + * @return void + */ + protected function _tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop = 0, $hidebottom = 0, $currency = '', $outputlangsbis = null) + { + global $conf; + + // Force to disable hidetop and hidebottom + $hidebottom = 0; + if ($hidetop) { + $hidetop = -1; + } + + $currency = !empty($currency) ? $currency : $conf->currency; + $default_font_size = pdf_getPDFFontSize($outputlangs); + + // Amount in (at tab_top - 1) + $pdf->SetTextColor(0, 0, 0); + $pdf->SetFont('', '', $default_font_size - 2); + + if (empty($hidetop)) { + $titre = $outputlangs->transnoentities("AmountInCurrency", $outputlangs->transnoentitiesnoconv("Currency".$currency)); + if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE) && is_object($outputlangsbis)) { + $titre .= ' - '.$outputlangsbis->transnoentities("AmountInCurrency", $outputlangsbis->transnoentitiesnoconv("Currency".$currency)); + } + + $pdf->SetXY($this->page_largeur - $this->marge_droite - ($pdf->GetStringWidth($titre) + 3), $tab_top - 4); + $pdf->MultiCell(($pdf->GetStringWidth($titre) + 3), 2, $titre); + + //$conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR='230,230,230'; + if (!empty($conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR)) { + $pdf->Rect($this->marge_gauche, $tab_top, $this->page_largeur - $this->marge_droite - $this->marge_gauche, $this->tabTitleHeight, 'F', null, explode(',', $conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR)); + } + } + + $pdf->SetDrawColor(128, 128, 128); + $pdf->SetFont('', '', $default_font_size - 1); + + // Output Rect + $this->printRect($pdf, $this->marge_gauche, $tab_top, $this->page_largeur - $this->marge_gauche - $this->marge_droite, $tab_height, $hidetop, $hidebottom); // Rect takes a length in 3rd parameter and 4th parameter + + + $this->pdfTabTitles($pdf, $tab_top, $tab_height, $outputlangs, $hidetop); + + if (empty($hidetop)) { + $pdf->line($this->marge_gauche, $tab_top + $this->tabTitleHeight, $this->page_largeur - $this->marge_droite, $tab_top + $this->tabTitleHeight); // line takes a position y in 2nd parameter and 4th parameter + } + } + + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore + /** + * Show top header of page. + * + * @param Tcpdf $pdf Object PDF + * @param Object $object Object to show + * @param int $showaddress 0=no, 1=yes + * @param Translate $outputlangs Object lang for output + * @param Translate $outputlangsbis Object lang for output bis + * @return void + */ + protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $outputlangsbis = null) + { + global $conf, $langs; + + // Load traductions files required by page + $outputlangs->loadLangs(array("main", "bills", "propal", "companies")); + + $default_font_size = pdf_getPDFFontSize($outputlangs); + + pdf_pagehead($pdf, $outputlangs, $this->page_hauteur); + + // Show Draft Watermark + if ($object->statut == $object::STATUS_DRAFT && (!empty($conf->global->FACTURE_DRAFT_WATERMARK))) { + pdf_watermark($pdf, $outputlangs, $this->page_hauteur, $this->page_largeur, 'mm', $conf->global->FACTURE_DRAFT_WATERMARK); + } + + $pdf->SetTextColor(0, 0, 60); + $pdf->SetFont('', 'B', $default_font_size + 3); + + $w = 110; + + $posy = $this->marge_haute; + $posx = $this->page_largeur - $this->marge_droite - $w; + + $pdf->SetXY($this->marge_gauche, $posy); + + // Logo + if (empty($conf->global->PDF_DISABLE_MYCOMPANY_LOGO)) { + if ($this->emetteur->logo) { + $logodir = $conf->mycompany->dir_output; + if (!empty($conf->mycompany->multidir_output[$object->entity])) { + $logodir = $conf->mycompany->multidir_output[$object->entity]; + } + if (empty($conf->global->MAIN_PDF_USE_LARGE_LOGO)) { + $logo = $logodir.'/logos/thumbs/'.$this->emetteur->logo_small; + } else { + $logo = $logodir.'/logos/'.$this->emetteur->logo; + } + if (is_readable($logo)) { + $height = pdf_getHeightForLogo($logo); + $pdf->Image($logo, $this->marge_gauche, $posy, 0, $height); // width=0 (auto) + } else { + $pdf->SetTextColor(200, 0, 0); + $pdf->SetFont('', 'B', $default_font_size - 2); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound", $logo), 0, 'L'); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities("ErrorGoToGlobalSetup"), 0, 'L'); + } + } else { + $text = $this->emetteur->name; + $pdf->MultiCell($w, 4, $outputlangs->convToOutputCharset($text), 0, 'L'); + } + } + + $pdf->SetFont('', 'B', $default_font_size + 3); + $pdf->SetXY($posx, $posy); + $pdf->SetTextColor(0, 0, 60); + $title = $outputlangs->transnoentities("PdfTitle"); + if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE) && is_object($outputlangsbis)) { + $title .= ' - '; + $title .= $outputlangsbis->transnoentities("PdfTitle"); + } + $pdf->MultiCell($w, 3, $title, '', 'R'); + + $pdf->SetFont('', 'B', $default_font_size); + + $posy += 5; + $pdf->SetXY($posx, $posy); + $pdf->SetTextColor(0, 0, 60); + $textref = $outputlangs->transnoentities("Ref")." : ".$outputlangs->convToOutputCharset($object->ref); + if ($object->statut == $object::STATUS_DRAFT) { + $pdf->SetTextColor(128, 0, 0); + $textref .= ' - '.$outputlangs->transnoentities("NotValidated"); + } + $pdf->MultiCell($w, 4, $textref, '', 'R'); + + $posy += 1; + $pdf->SetFont('', '', $default_font_size - 2); + + if ($object->ref_client) { + $posy += 4; + $pdf->SetXY($posx, $posy); + $pdf->SetTextColor(0, 0, 60); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities("RefCustomer")." : ".$outputlangs->convToOutputCharset($object->ref_client), '', 'R'); + } + + if (!empty($conf->global->PDF_SHOW_PROJECT_TITLE)) { + $object->fetch_projet(); + if (!empty($object->project->ref)) { + $posy += 3; + $pdf->SetXY($posx, $posy); + $pdf->SetTextColor(0, 0, 60); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities("Project")." : ".(empty($object->project->title) ? '' : $object->projet->title), '', 'R'); + } + } + + if (!empty($conf->global->PDF_SHOW_PROJECT)) { + $object->fetch_projet(); + if (!empty($object->project->ref)) { + $outputlangs->load("projects"); + $posy += 3; + $pdf->SetXY($posx, $posy); + $pdf->SetTextColor(0, 0, 60); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities("RefProject")." : ".(empty($object->project->ref) ? '' : $object->project->ref), '', 'R'); + } + } + + $posy += 4; + $pdf->SetXY($posx, $posy); + $pdf->SetTextColor(0, 0, 60); + + $title = $outputlangs->transnoentities("Date"); + if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE) && is_object($outputlangsbis)) { + $title .= ' - '.$outputlangsbis->transnoentities("Date"); + } + $pdf->MultiCell($w, 3, $title." : ".dol_print_date($object->date, "day", false, $outputlangs), '', 'R'); + + if ($object->thirdparty->code_client) { + $posy += 3; + $pdf->SetXY($posx, $posy); + $pdf->SetTextColor(0, 0, 60); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities("CustomerCode")." : ".$outputlangs->transnoentities($object->thirdparty->code_client), '', 'R'); + } + + // Get contact + if (!empty($conf->global->DOC_SHOW_FIRST_SALES_REP)) { + $arrayidcontact = $object->getIdContact('internal', 'SALESREPFOLL'); + if (count($arrayidcontact) > 0) { + $usertmp = new User($this->db); + $usertmp->fetch($arrayidcontact[0]); + $posy += 4; + $pdf->SetXY($posx, $posy); + $pdf->SetTextColor(0, 0, 60); + $pdf->MultiCell($w, 3, $langs->transnoentities("SalesRepresentative")." : ".$usertmp->getFullName($langs), '', 'R'); + } + } + + $posy += 1; + + $top_shift = 0; + // Show list of linked objects + $current_y = $pdf->getY(); + $posy = pdf_writeLinkedObjects($pdf, $object, $outputlangs, $posx, $posy, $w, 3, 'R', $default_font_size); + if ($current_y < $pdf->getY()) { + $top_shift = $pdf->getY() - $current_y; + } + + if ($showaddress) { + // Sender properties + $carac_emetteur = pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, '', 0, 'source', $object); + + // Show sender + $posy = !empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 40 : 42; + $posy += $top_shift; + $posx = $this->marge_gauche; + if (!empty($conf->global->MAIN_INVERT_SENDER_RECIPIENT)) { + $posx = $this->page_largeur - $this->marge_droite - 80; + } + + $hautcadre = !empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 38 : 40; + $widthrecbox = !empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 92 : 82; + + + // Show sender frame + $pdf->SetTextColor(0, 0, 0); + $pdf->SetFont('', '', $default_font_size - 2); + $pdf->SetXY($posx, $posy - 5); + $pdf->MultiCell(66, 5, $outputlangs->transnoentities("BillFrom").":", 0, 'L'); + $pdf->SetXY($posx, $posy); + $pdf->SetFillColor(230, 230, 230); + $pdf->MultiCell($widthrecbox, $hautcadre, "", 0, 'R', 1); + $pdf->SetTextColor(0, 0, 60); + + // Show sender name + $pdf->SetXY($posx + 2, $posy + 3); + $pdf->SetFont('', 'B', $default_font_size); + $pdf->MultiCell($widthrecbox - 2, 4, $outputlangs->convToOutputCharset($this->emetteur->name), 0, 'L'); + $posy = $pdf->getY(); + + // Show sender information + $pdf->SetXY($posx + 2, $posy); + $pdf->SetFont('', '', $default_font_size - 1); + $pdf->MultiCell($widthrecbox - 2, 4, $carac_emetteur, 0, 'L'); + + // If BILLING contact defined on invoice, we use it + $usecontact = false; + $arrayidcontact = $object->getIdContact('external', 'BILLING'); + if (count($arrayidcontact) > 0) { + $usecontact = true; + $result = $object->fetch_contact($arrayidcontact[0]); + } + + // Recipient name + if ($object->contact->socid != $object->thirdparty->id && (!isset($conf->global->MAIN_USE_COMPANY_NAME_OF_CONTACT) || !empty($conf->global->MAIN_USE_COMPANY_NAME_OF_CONTACT))) { + $thirdparty = $object->contact; + } else { + $thirdparty = $object->thirdparty; + } + + if (is_object($thirdparty)) { + $carac_client_name = pdfBuildThirdpartyName($thirdparty, $outputlangs); + } + + $carac_client = pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, ($usecontact ? $object->contact : ''), $usecontact, 'target', $object); + + // Show recipient + $widthrecbox = !empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 92 : 100; + if ($this->page_largeur < 210) { + $widthrecbox = 84; // To work with US executive format + } + $posy = !empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 40 : 42; + $posy += $top_shift; + $posx = $this->page_largeur - $this->marge_droite - $widthrecbox; + if (!empty($conf->global->MAIN_INVERT_SENDER_RECIPIENT)) { + $posx = $this->marge_gauche; + } + + // Show recipient frame + $pdf->SetTextColor(0, 0, 0); + $pdf->SetFont('', '', $default_font_size - 2); + $pdf->SetXY($posx + 2, $posy - 5); + $pdf->MultiCell($widthrecbox, 5, $outputlangs->transnoentities("BillTo").":", 0, 'L'); + $pdf->Rect($posx, $posy, $widthrecbox, $hautcadre); + + // Show recipient name + $pdf->SetXY($posx + 2, $posy + 3); + $pdf->SetFont('', 'B', $default_font_size); + $pdf->MultiCell($widthrecbox, 2, $carac_client_name, 0, 'L'); + + $posy = $pdf->getY(); + + // Show recipient information + $pdf->SetFont('', '', $default_font_size - 1); + $pdf->SetXY($posx + 2, $posy); + $pdf->MultiCell($widthrecbox, 4, $carac_client, 0, 'L'); + } + + $pdf->SetTextColor(0, 0, 0); + return $top_shift; + } + + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore + /** + * Show footer of page. Need this->emetteur object + * + * @param TCPDF $pdf PDF + * @param Object $object Object to show + * @param Translate $outputlangs Object lang for output + * @param int $hidefreetext 1=Hide free text + * @return int Return height of bottom margin including footer text + */ + protected function _pagefoot(&$pdf, $object, $outputlangs, $hidefreetext = 0) + { + global $conf; + $showdetails = empty($conf->global->MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS) ? 0 : $conf->global->MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS; + return pdf_pagefoot($pdf, $outputlangs, 'INVOICE_FREE_TEXT', $this->emetteur, $this->marge_basse, $this->marge_gauche, $this->page_hauteur, $object, $showdetails, $hidefreetext); + } + + /** + * Define Array Column Field + * + * @param object $object common object + * @param Translate $outputlangs langs + * @param int $hidedetails Do not show line details + * @param int $hidedesc Do not show desc + * @param int $hideref Do not show ref + * @return null + */ + public function defineColumnField($object, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0) + { + global $conf, $hookmanager; + + // Default field style for content + $this->defaultContentsFieldsStyle = array( + 'align' => 'R', // R,C,L + 'padding' => array(1, 0.5, 1, 0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left + ); + + // Default field style for content + $this->defaultTitlesFieldsStyle = array( + 'align' => 'C', // R,C,L + 'padding' => array(0.5, 0, 0.5, 0), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left + ); + + /* + * For exemple + $this->cols['theColKey'] = array( + 'rank' => $rank, // int : use for ordering columns + 'width' => 20, // the column width in mm + 'title' => array( + 'textkey' => 'yourLangKey', // if there is no label, yourLangKey will be translated to replace label + 'label' => ' ', // the final label : used fore final generated text + 'align' => 'L', // text alignement : R,C,L + 'padding' => array(0.5,0.5,0.5,0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left + ), + 'content' => array( + 'align' => 'L', // text alignement : R,C,L + 'padding' => array(0.5,0.5,0.5,0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left + ), + ); + */ + + $rank = 0; // do not use negative rank + $this->cols['desc'] = array( + 'rank' => $rank, + 'width' => false, // only for desc + 'status' => true, + 'title' => array( + 'textkey' => 'Designation', // use lang key is usefull in somme case with module + 'align' => 'L', + // 'textkey' => 'yourLangKey', // if there is no label, yourLangKey will be translated to replace label + // 'label' => ' ', // the final label + 'padding' => array(0.5, 0.5, 0.5, 0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left + ), + 'content' => array( + 'align' => 'L', + 'padding' => array(1, 0.5, 1, 1.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left + ), + ); + + // PHOTO + $rank = $rank + 10; + $this->cols['photo'] = array( + 'rank' => $rank, + 'width' => (empty($conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH) ? 20 : $conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH), // in mm + 'status' => false, + 'title' => array( + 'textkey' => 'Photo', + 'label' => ' ' + ), + 'content' => array( + 'padding' => array(0, 0, 0, 0), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left + ), + 'border-left' => false, // remove left line separator + ); + + if (!empty($conf->global->MAIN_GENERATE_INVOICES_WITH_PICTURE) && !empty($this->atleastonephoto)) { + $this->cols['photo']['status'] = true; + } + + + $rank = $rank + 10; + $this->cols['vat'] = array( + 'rank' => $rank, + 'status' => false, + 'width' => 16, // in mm + 'title' => array( + 'textkey' => 'VAT' + ), + 'border-left' => true, // add left line separator + ); + + if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT) && empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_COLUMN)) { + $this->cols['vat']['status'] = true; + } + + $rank = $rank + 10; + $this->cols['subprice'] = array( + 'rank' => $rank, + 'width' => 19, // in mm + 'status' => true, + 'title' => array( + 'textkey' => 'PriceUHT' + ), + 'border-left' => true, // add left line separator + ); + + $rank = $rank + 10; + $this->cols['qty'] = array( + 'rank' => $rank, + 'width' => 16, // in mm + 'status' => true, + 'title' => array( + 'textkey' => 'Qty' + ), + 'border-left' => true, // add left line separator + ); + + $rank = $rank + 10; + $this->cols['progress'] = array( + 'rank' => $rank, + 'width' => 19, // in mm + 'status' => false, + 'title' => array( + 'textkey' => 'Progress' + ), + 'border-left' => true, // add left line separator + ); + + if ($this->situationinvoice) { + $this->cols['progress']['status'] = true; + } + + $rank = $rank + 10; + $this->cols['unit'] = array( + 'rank' => $rank, + 'width' => 11, // in mm + 'status' => false, + 'title' => array( + 'textkey' => 'Unit' + ), + 'border-left' => true, // add left line separator + ); + if (!empty($conf->global->PRODUCT_USE_UNITS)) { + $this->cols['unit']['status'] = true; + } + + $rank = $rank + 10; + $this->cols['discount'] = array( + 'rank' => $rank, + 'width' => 13, // in mm + 'status' => false, + 'title' => array( + 'textkey' => 'ReductionShort' + ), + 'border-left' => true, // add left line separator + ); + if ($this->atleastonediscount) { + $this->cols['discount']['status'] = true; + } + + $rank = $rank + 1000; // add a big offset to be sure is the last col because default extrafield rank is 100 + $this->cols['totalexcltax'] = array( + 'rank' => $rank, + 'width' => 26, // in mm + 'status' => true, + 'title' => array( + 'textkey' => 'TotalHT' + ), + 'border-left' => true, // add left line separator + ); + + // Add extrafields cols + if (!empty($object->lines)) { + $line = reset($object->lines); + $this->defineColumnExtrafield($line, $outputlangs, $hidedetails); + } + + $parameters = array( + 'object' => $object, + 'outputlangs' => $outputlangs, + 'hidedetails' => $hidedetails, + 'hidedesc' => $hidedesc, + 'hideref' => $hideref + ); + + $reshook = $hookmanager->executeHooks('defineColumnField', $parameters, $this); // Note that $object may have been modified by hook + if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + } elseif (empty($reshook)) { + $this->cols = array_replace($this->cols, $hookmanager->resArray); // array_replace is used to preserve keys + } else { + $this->cols = $hookmanager->resArray; + } + } +} diff --git a/htdocs/core/modules/asset/mod_asset_advanced.php b/htdocs/core/modules/asset/mod_asset_advanced.php new file mode 100644 index 00000000000..0942604466c --- /dev/null +++ b/htdocs/core/modules/asset/mod_asset_advanced.php @@ -0,0 +1,147 @@ + + * Copyright (C) 2004-2007 Laurent Destailleur + * Copyright (C) 2005-2009 Regis Houssin + * Copyright (C) 2008 Raphael Bertrand (Resultic) + * Copyright (C) 2019 Frédéric France + * + * 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 + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * or see https://www.gnu.org/ + */ + +/** + * \file htdocs/core/modules/asset/mod_asset_advanced.php + * \ingroup asset + * \brief File containing class for advanced numbering model of Asset + */ + +require_once DOL_DOCUMENT_ROOT.'/core/modules/asset/modules_asset.php'; + +/** + * Class to manage customer Bom numbering rules advanced + */ +class mod_asset_advanced extends ModeleNumRefAsset +{ + /** + * Dolibarr version of the loaded document + * @var string + */ + public $version = 'dolibarr'; // 'development', 'experimental', 'dolibarr' + + /** + * @var string Error message + */ + public $error = ''; + + /** + * @var string name + */ + public $name = 'advanced'; + + + /** + * Returns the description of the numbering model + * + * @return string Texte descripif + */ + public function info() + { + global $conf, $langs, $db; + + $langs->load("bills"); + + $form = new Form($db); + + $texte = $langs->trans('GenericNumRefModelDesc')."
\n"; + $texte .= '
'; + $texte .= ''; + $texte .= ''; + $texte .= ''; + $texte .= ''; + + $tooltip = $langs->trans("GenericMaskCodes", $langs->transnoentities("Asset"), $langs->transnoentities("Asset")); + $tooltip .= $langs->trans("GenericMaskCodes2"); + $tooltip .= $langs->trans("GenericMaskCodes3"); + $tooltip .= $langs->trans("GenericMaskCodes4a", $langs->transnoentities("Asset"), $langs->transnoentities("Asset")); + $tooltip .= $langs->trans("GenericMaskCodes5"); + + // Parametrage du prefix + $texte .= ''; + $texte .= ''; + + $texte .= ''; + + $texte .= ''; + + $texte .= '
'.$langs->trans("Mask").':'.$form->textwithpicto('', $tooltip, 1, 1).' 
'; + $texte .= '
'; + + return $texte; + } + + /** + * Return an example of numbering + * + * @return string Example + */ + public function getExample() + { + global $conf, $db, $langs, $mysoc; + + $object = new Asset($db); + $object->initAsSpecimen(); + + /*$old_code_client = $mysoc->code_client; + $old_code_type = $mysoc->typent_code; + $mysoc->code_client = 'CCCCCCCCCC'; + $mysoc->typent_code = 'TTTTTTTTTT';*/ + + $numExample = $this->getNextValue($object); + + /*$mysoc->code_client = $old_code_client; + $mysoc->typent_code = $old_code_type;*/ + + if (!$numExample) { + $numExample = $langs->trans('NotConfigured'); + } + return $numExample; + } + + /** + * Return next free value + * + * @param Object $object Object we need next value for + * @return string Value if KO, <0 if KO + */ + public function getNextValue($object) + { + global $db, $conf; + + require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; + + // We get cursor rule + $mask = $conf->global->ASSET_ASSET_ADVANCED_MASK; + + if (!$mask) { + $this->error = 'NotConfigured'; + return 0; + } + + $date = $object->date; + + $numFinal = get_next_value($db, $mask, 'asset_asset', 'ref', '', null, $date); + + return $numFinal; + } +} diff --git a/htdocs/core/modules/asset/mod_asset_standard.php b/htdocs/core/modules/asset/mod_asset_standard.php new file mode 100644 index 00000000000..af28c0f9c5b --- /dev/null +++ b/htdocs/core/modules/asset/mod_asset_standard.php @@ -0,0 +1,161 @@ + + * Copyright (C) 2005-2009 Regis Houssin + * + * 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 + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * or see https://www.gnu.org/ + */ + +/** + * \file htdocs/core/modules/asset/mod_asset_standard.php + * \ingroup asset + * \brief File of class to manage Asset numbering rules standard + */ + +require_once DOL_DOCUMENT_ROOT.'/core/modules/asset/modules_asset.php'; + +/** + * Class to manage customer order numbering rules standard + */ +class mod_asset_standard extends ModeleNumRefAsset +{ + /** + * Dolibarr version of the loaded document + * @var string + */ + public $version = 'dolibarr'; // 'development', 'experimental', 'dolibarr' + + public $prefix = 'ASSET'; + + /** + * @var string Error code (or message) + */ + public $error = ''; + + /** + * @var string name + */ + public $name = 'standard'; + + + /** + * Return description of numbering module + * + * @return string Text with description + */ + public function info() + { + global $langs; + return $langs->trans("SimpleNumRefModelDesc", $this->prefix); + } + + + /** + * Return an example of numbering + * + * @return string Example + */ + public function getExample() + { + return $this->prefix."0501-0001"; + } + + + /** + * Checks if the numbers already in the database do not + * cause conflicts that would prevent this numbering working. + * + * @param Object $object Object we need next value for + * @return boolean false if conflict, true if ok + */ + public function canBeActivated($object) + { + global $conf, $langs, $db; + + $coyymm = ''; $max = ''; + + $posindice = strlen($this->prefix) + 6; + $sql = "SELECT MAX(CAST(SUBSTRING(ref FROM ".$posindice.") AS SIGNED)) as max"; + $sql .= " FROM ".MAIN_DB_PREFIX."asset_asset"; + $sql .= " WHERE ref LIKE '".$db->escape($this->prefix)."____-%'"; + if ($object->ismultientitymanaged == 1) { + $sql .= " AND entity = ".$conf->entity; + } elseif ($object->ismultientitymanaged == 2) { + // TODO + } + + $resql = $db->query($sql); + if ($resql) { + $row = $db->fetch_row($resql); + if ($row) { + $coyymm = substr($row[0], 0, 6); $max = $row[0]; + } + } + if ($coyymm && !preg_match('/'.$this->prefix.'[0-9][0-9][0-9][0-9]/i', $coyymm)) { + $langs->load("errors"); + $this->error = $langs->trans('ErrorNumRefModel', $max); + return false; + } + + return true; + } + + /** + * Return next free value + * + * @param Object $object Object we need next value for + * @return string Value if KO, <0 if KO + */ + public function getNextValue($object) + { + global $db, $conf; + + // first we get the max value + $posindice = strlen($this->prefix) + 6; + $sql = "SELECT MAX(CAST(SUBSTRING(ref FROM ".$posindice.") AS SIGNED)) as max"; + $sql .= " FROM ".MAIN_DB_PREFIX."asset_asset"; + $sql .= " WHERE ref LIKE '".$db->escape($this->prefix)."____-%'"; + if ($object->ismultientitymanaged == 1) { + $sql .= " AND entity = ".$conf->entity; + } elseif ($object->ismultientitymanaged == 2) { + // TODO + } + + $resql = $db->query($sql); + if ($resql) { + $obj = $db->fetch_object($resql); + if ($obj) { + $max = intval($obj->max); + } else { + $max = 0; + } + } else { + dol_syslog("mod_asset_standard::getNextValue", LOG_DEBUG); + return -1; + } + + //$date=time(); + $date = $object->date_creation; + $yymm = strftime("%y%m", $date); + + if ($max >= (pow(10, 4) - 1)) { + $num = $max + 1; // If counter > 9999, we do not format on 4 chars, we take number as it is + } else { + $num = sprintf("%04s", $max + 1); + } + + dol_syslog("mod_asset_standard::getNextValue return ".$this->prefix.$yymm."-".$num); + return $this->prefix.$yymm."-".$num; + } +} diff --git a/htdocs/core/modules/asset/modules_asset.php b/htdocs/core/modules/asset/modules_asset.php new file mode 100644 index 00000000000..e158b5bdfe9 --- /dev/null +++ b/htdocs/core/modules/asset/modules_asset.php @@ -0,0 +1,158 @@ + + * Copyright (C) 2004-2011 Laurent Destailleur + * Copyright (C) 2004 Eric Seigne + * Copyright (C) 2005-2012 Regis Houssin + * Copyright (C) 2006 Andre Cianfarani + * Copyright (C) 2012 Juanjo Menent + * Copyright (C) 2014 Marcos García + * + * 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 + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * or see https://www.gnu.org/ + */ + +/** + * \file htdocs/core/modules/asset/modules_asset.php + * \ingroup asset + * \brief File that contains parent class for assets document models and parent class for assets numbering models + */ + +require_once DOL_DOCUMENT_ROOT.'/core/class/commondocgenerator.class.php'; +require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php'; // required for use by classes that inherit + + +/** + * Parent class for documents models + */ +abstract class ModelePDFAsset extends CommonDocGenerator +{ + + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Return list of active generation modules + * + * @param DoliDB $db Database handler + * @param integer $maxfilenamelength Max length of value to show + * @return array List of templates + */ + public static function liste_modeles($db, $maxfilenamelength = 0) + { + // phpcs:enable + global $conf; + + $type = 'asset'; + $list = array(); + + include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; + $list = getListOfModels($db, $type, $maxfilenamelength); + + return $list; + } +} + + + +/** + * Parent class to manage numbering of Asset + */ +abstract class ModeleNumRefAsset +{ + /** + * @var string Error code (or message) + */ + public $error = ''; + + /** + * Return if a module can be used or not + * + * @return boolean true if module can be used + */ + public function isEnabled() + { + return true; + } + + /** + * Returns the default description of the numbering template + * + * @return string Texte descripif + */ + public function info() + { + global $langs; + $langs->load("asset@asset"); + return $langs->trans("NoDescription"); + } + + /** + * Returns an example of numbering + * + * @return string Example + */ + public function getExample() + { + global $langs; + $langs->load("asset@asset"); + return $langs->trans("NoExample"); + } + + /** + * Checks if the numbers already in the database do not + * cause conflicts that would prevent this numbering working. + * + * @param Object $object Object we need next value for + * @return boolean false if conflict, true if ok + */ + public function canBeActivated($object) + { + return true; + } + + /** + * Returns next assigned value + * + * @param Object $object Object we need next value for + * @return string Valeur + */ + public function getNextValue($object) + { + global $langs; + return $langs->trans("NotAvailable"); + } + + /** + * Returns version of numbering module + * + * @return string Valeur + */ + public function getVersion() + { + global $langs; + $langs->load("admin"); + + if ($this->version == 'development') { + return $langs->trans("VersionDevelopment"); + } + if ($this->version == 'experimental') { + return $langs->trans("VersionExperimental"); + } + if ($this->version == 'dolibarr') { + return DOL_VERSION; + } + if ($this->version) { + return $this->version; + } + return $langs->trans("NotAvailable"); + } +} diff --git a/htdocs/core/modules/modAsset.class.php b/htdocs/core/modules/modAsset.class.php index b275f38debe..0fe334bc846 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 = "Assets module"; + $this->description = "Asset module"; // Used only if file README.md and README-LL.md not found. - $this->descriptionlong = "Assets module to manage assets module and depreciation charge on Dolibarr"; + $this->descriptionlong = "Asset module to manage assets module and depreciation charge on Dolibarr"; // Possible values for version are: 'development', 'experimental', 'dolibarr', 'dolibarr_deprecated' or a version string like 'x.y.z' $this->version = 'development'; @@ -192,13 +192,29 @@ class modAsset extends DolibarrModules $this->rights[$r][4] = 'delete'; // In php code, permission will be checked by test if ($user->rights->asset->level1->level2) $this->rights[$r][5] = ''; // In php code, permission will be checked by test if ($user->rights->asset->level1->level2) + $r++; + $this->rights[$r][0] = 51004; // Permission id (must not be already used) + $this->rights[$r][1] = 'Read asset models'; // Permission label + $this->rights[$r][2] = 'r'; + $this->rights[$r][3] = 0; // Permission by default for new user (0/1) + $this->rights[$r][4] = 'model_advance'; // In php code, permission will be checked by test if ($user->rights->asset->level1->level2) + $this->rights[$r][5] = 'read'; // In php code, permission will be checked by test if ($user->rights->asset->level1->level2) + $r++; $this->rights[$r][0] = 51005; // Permission id (must not be already used) - $this->rights[$r][1] = 'Setup types of asset'; // Permission label + $this->rights[$r][1] = 'Create/Update asset models'; // Permission label $this->rights[$r][2] = 'w'; $this->rights[$r][3] = 0; // Permission by default for new user (0/1) - $this->rights[$r][4] = 'setup_advance'; // In php code, permission will be checked by test if ($user->rights->asset->level1->level2) - $this->rights[$r][5] = ''; // In php code, permission will be checked by test if ($user->rights->asset->level1->level2) + $this->rights[$r][4] = 'model_advance'; // In php code, permission will be checked by test if ($user->rights->asset->level1->level2) + $this->rights[$r][5] = 'write'; // In php code, permission will be checked by test if ($user->rights->asset->level1->level2) + + $r++; + $this->rights[$r][0] = 51006; // Permission id (must not be already used) + $this->rights[$r][1] = 'Delete asset models'; // Permission label + $this->rights[$r][2] = 'd'; + $this->rights[$r][3] = 0; // Permission by default for new user (0/1) + $this->rights[$r][4] = 'model_advance'; // In php code, permission will be checked by test if ($user->rights->asset->level1->level2) + $this->rights[$r][5] = 'delete'; // In php code, permission will be checked by test if ($user->rights->asset->level1->level2) // Menus //------- diff --git a/htdocs/core/tpl/objectline_create.tpl.php b/htdocs/core/tpl/objectline_create.tpl.php index 335754a8168..5014b47e9d3 100644 --- a/htdocs/core/tpl/objectline_create.tpl.php +++ b/htdocs/core/tpl/objectline_create.tpl.php @@ -6,9 +6,10 @@ * Copyright (C) 2014 Florian Henry * Copyright (C) 2014 Raphaël Doursenaud * Copyright (C) 2015-2016 Marcos García - * Copyright (C) 2018 Frédéric France + * Copyright (C) 2018 Frédéric France * Copyright (C) 2018 Ferran Marcet * Copyright (C) 2019 Nicolas ZABOURI + * Copyright (C) 2022 OpenDSI * * 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 @@ -68,6 +69,9 @@ if (!empty($conf->multicurrency->enabled) && $this->multicurrency_code != $conf- if (in_array($object->element, array('propal', 'commande', 'order', 'facture', 'facturerec', 'invoice', 'supplier_proposal', 'order_supplier', 'invoice_supplier', 'invoice_supplier_rec'))) { $colspan++; // With this, there is a column move button } +if (!empty($conf->asset->enabled) && $object->element == 'invoice_supplier') { + $colspan++; +} //print $object->element; // Lines for extrafield diff --git a/htdocs/core/tpl/objectline_edit.tpl.php b/htdocs/core/tpl/objectline_edit.tpl.php index 0f0043eadd6..b07ea5042f0 100644 --- a/htdocs/core/tpl/objectline_edit.tpl.php +++ b/htdocs/core/tpl/objectline_edit.tpl.php @@ -6,6 +6,7 @@ * Copyright (C) 2012-2014 Raphaël Doursenaud * Copyright (C) 2013 Florian Henry * Copyright (C) 2018 Frédéric France + * Copyright (C) 2022 OpenDSI * * 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 @@ -72,6 +73,11 @@ if (in_array($object->element, array('propal', 'supplier_proposal', 'facture', ' if (!empty($conf->multicurrency->enabled) && $this->multicurrency_code != $conf->currency) { $colspan += 2; } +if (!empty($conf->asset->enabled) && $object->element == 'invoice_supplier') { + $colspan++; +} + + print "\n"; diff --git a/htdocs/core/tpl/objectline_title.tpl.php b/htdocs/core/tpl/objectline_title.tpl.php index 0f86289dfe1..c40f07716f2 100644 --- a/htdocs/core/tpl/objectline_title.tpl.php +++ b/htdocs/core/tpl/objectline_title.tpl.php @@ -6,6 +6,7 @@ * Copyright (C) 2012-2014 Raphaël Doursenaud * Copyright (C) 2013 Florian Henry * Copyright (C) 2017 Juanjo Menent + * Copyright (C) 2022 OpenDSI * * 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 @@ -140,6 +141,10 @@ if ($outputalsopricetotalwithtax) { print ''.$langs->trans('TotalTTCShort').''; } +if (!empty($conf->asset->enabled) && $object->element == 'invoice_supplier') { + print ''; +} + print ''; // No width to allow autodim print ''; diff --git a/htdocs/core/tpl/objectline_view.tpl.php b/htdocs/core/tpl/objectline_view.tpl.php index 36eceb87341..b44996148f1 100644 --- a/htdocs/core/tpl/objectline_view.tpl.php +++ b/htdocs/core/tpl/objectline_view.tpl.php @@ -6,6 +6,7 @@ * Copyright (C) 2012-2014 Raphaël Doursenaud * Copyright (C) 2013 Florian Henry * Copyright (C) 2017 Juanjo Menent + * Copyright (C) 2022 OpenDSI * * 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 @@ -387,6 +388,35 @@ if ($this->statut == 0 && !empty($object_rights->creer) && $action != 'selectlin } } + if (!empty($conf->asset->enabled) && $object->element == 'invoice_supplier') { + print ''; + $coldisplay++; + if (!empty($product_static->accountancy_code_buy) || + !empty($product_static->accountancy_code_buy_intra) || + !empty($product_static->accountancy_code_buy_export) + ) { + $accountancy_category_asset = $conf->global->ASSET_ACCOUNTANCY_CATEGORY; + $filters = array(); + if (!empty($product_static->accountancy_code_buy)) $filters[] = "account_number = '" . $this->db->escape($product_static->accountancy_code_buy) . "'"; + if (!empty($product_static->accountancy_code_buy_intra)) $filters[] = "account_number = '" . $this->db->escape($product_static->accountancy_code_buy_intra) . "'"; + if (!empty($product_static->accountancy_code_buy_export)) $filters[] = "account_number = '" . $this->db->escape($product_static->accountancy_code_buy_export) . "'"; + $sql = "SELECT COUNT(*) AS found"; + $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_account"; + $sql .= " WHERE pcg_type = '" . $this->db->escape($conf->global->ASSET_ACCOUNTANCY_CATEGORY) . "'"; + $sql .= " AND (" . implode(' OR ', $filters). ")"; + $resql_asset = $this->db->query($sql); + if (!$resql_asset) { + print 'Error SQL: ' . $this->db->lasterror(); + } elseif ($obj = $this->db->fetch_object($resql_asset)) { + if (!empty($obj->found)) { + print ''; + print img_edit_add() . ''; + } + } + } + print ''; + } + print ''; $coldisplay++; if (($line->info_bits & 2) == 2 || !empty($disableedit)) { From 526157dfcb7a0514d6089fdf2f76d85389e121f8 Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Mon, 14 Feb 2022 03:56:45 +0000 Subject: [PATCH 05/20] Fixing style errors. --- htdocs/core/tpl/objectline_view.tpl.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/tpl/objectline_view.tpl.php b/htdocs/core/tpl/objectline_view.tpl.php index b44996148f1..e8316392043 100644 --- a/htdocs/core/tpl/objectline_view.tpl.php +++ b/htdocs/core/tpl/objectline_view.tpl.php @@ -414,7 +414,7 @@ if ($this->statut == 0 && !empty($object_rights->creer) && $action != 'selectlin } } } - print ''; + print ''; } print ''; From d869adb370f1ce725c2d4c08b850e637e52471af Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Mon, 14 Feb 2022 05:15:28 +0100 Subject: [PATCH 06/20] Asser --- htdocs/asset/accountancy_codes.php | 189 +++ ..._extrafields.php => asset_extrafields.php} | 51 +- ...afields.php => assetmodel_extrafields.php} | 53 +- htdocs/asset/admin/setup.php | 631 ++++++- htdocs/asset/agenda.php | 215 +++ htdocs/asset/card.php | 209 ++- htdocs/asset/class/asset.class.php | 1485 ++++++++++++++--- htdocs/asset/class/asset_type.class.php | 445 ----- .../class/assetaccountancycodes.class.php | 277 +++ .../class/assetdepreciationoptions.class.php | 546 ++++++ htdocs/asset/class/assetmodel.class.php | 822 +++++++++ htdocs/asset/depreciation.php | 199 +++ htdocs/asset/depreciation_options.php | 190 +++ htdocs/asset/disposal.php | 120 ++ htdocs/asset/document.php | 140 +- htdocs/asset/info.php | 93 -- htdocs/asset/list.php | 284 ++-- htdocs/asset/model/accountancy_codes.php | 191 +++ htdocs/asset/model/agenda.php | 217 +++ htdocs/asset/model/card.php | 330 ++++ htdocs/asset/model/depreciation_options.php | 191 +++ htdocs/asset/model/list.php | 681 ++++++++ htdocs/asset/model/note.php | 120 ++ htdocs/asset/note.php | 75 +- .../asset/tpl/accountancy_codes_edit.tpl.php | 81 + .../asset/tpl/accountancy_codes_view.tpl.php | 82 + .../tpl/depreciation_options_edit.tpl.php | 228 +++ .../tpl/depreciation_options_view.tpl.php | 154 ++ htdocs/asset/tpl/depreciation_view.tpl.php | 154 ++ htdocs/asset/tpl/linkedobjectblock.tpl.php | 81 + htdocs/asset/type.php | 608 ------- 31 files changed, 7448 insertions(+), 1694 deletions(-) create mode 100644 htdocs/asset/accountancy_codes.php rename htdocs/asset/admin/{assets_type_extrafields.php => asset_extrafields.php} (56%) rename htdocs/asset/admin/{assets_extrafields.php => assetmodel_extrafields.php} (54%) create mode 100644 htdocs/asset/agenda.php delete mode 100644 htdocs/asset/class/asset_type.class.php create mode 100644 htdocs/asset/class/assetaccountancycodes.class.php create mode 100644 htdocs/asset/class/assetdepreciationoptions.class.php create mode 100644 htdocs/asset/class/assetmodel.class.php create mode 100644 htdocs/asset/depreciation.php create mode 100644 htdocs/asset/depreciation_options.php create mode 100644 htdocs/asset/disposal.php delete mode 100644 htdocs/asset/info.php create mode 100644 htdocs/asset/model/accountancy_codes.php create mode 100644 htdocs/asset/model/agenda.php create mode 100644 htdocs/asset/model/card.php create mode 100644 htdocs/asset/model/depreciation_options.php create mode 100644 htdocs/asset/model/list.php create mode 100644 htdocs/asset/model/note.php create mode 100644 htdocs/asset/tpl/accountancy_codes_edit.tpl.php create mode 100644 htdocs/asset/tpl/accountancy_codes_view.tpl.php create mode 100644 htdocs/asset/tpl/depreciation_options_edit.tpl.php create mode 100644 htdocs/asset/tpl/depreciation_options_view.tpl.php create mode 100644 htdocs/asset/tpl/depreciation_view.tpl.php create mode 100644 htdocs/asset/tpl/linkedobjectblock.tpl.php delete mode 100644 htdocs/asset/type.php diff --git a/htdocs/asset/accountancy_codes.php b/htdocs/asset/accountancy_codes.php new file mode 100644 index 00000000000..431b4ba7c68 --- /dev/null +++ b/htdocs/asset/accountancy_codes.php @@ -0,0 +1,189 @@ + + * Copyright (C) 2018 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 + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/asset/accountancy_code.php + * \ingroup asset + * \brief Card with accountancy code on Asset + */ + +require '../main.inc.php'; +require_once DOL_DOCUMENT_ROOT . '/core/lib/asset.lib.php'; +require_once DOL_DOCUMENT_ROOT . '/asset/class/asset.class.php'; +require_once DOL_DOCUMENT_ROOT . '/asset/class/assetaccountancycodes.class.php'; + +// Load translation files required by the page +$langs->loadLangs(array("assets", "companies")); + +// Get parameters +$id = GETPOST('id', 'int'); +$ref = GETPOST('ref', 'alpha'); +$action = GETPOST('action', 'aZ09'); +$cancel = GETPOST('cancel', 'aZ09'); +$backtopage = GETPOST('backtopage', 'alpha'); + +// Initialize technical objects +$object = new Asset($db); +$assetaccountancycodes = new AssetAccountancyCodes($db); +$extrafields = new ExtraFields($db); +$diroutputmassaction = $conf->asset->dir_output . '/temp/massgeneration/' . $user->id; +$hookmanager->initHooks(array('assetaccountancycodes', 'globalcard')); // Note that conf->hooks_modules contains array +// Fetch optionals attributes and labels +$extrafields->fetch_name_optionals_label($object->table_element); + +// Load object +include DOL_DOCUMENT_ROOT . '/core/actions_fetchobject.inc.php'; // Must be include, not include_once // Must be include, not include_once. Include fetch and fetch_thirdparty but not fetch_optionals +if ($id > 0 || !empty($ref)) { + $upload_dir = $conf->asset->multidir_output[$object->entity] . "/" . $object->id; +} + +$permissiontoadd = $user->rights->asset->write; // Used by the include of actions_addupdatedelete.inc.php + +// Security check (enable the most restrictive one) +if ($user->socid > 0) accessforbidden(); +$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +if (empty($conf->asset->enabled)) accessforbidden(); + +$result = $assetaccountancycodes->fetchAccountancyCodes($object->id); +if ($result < 0) { + setEventMessages($assetaccountancycodes->error, $assetaccountancycodes->errors, 'errors'); +} + + +/* + * Actions + */ + +$reshook = $hookmanager->executeHooks('doActions', array(), $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); +} +if (empty($reshook)) { + $backurlforlist = DOL_URL_ROOT.'/asset/list.php'; + + if (empty($backtopage) || ($cancel && empty($id))) { + if (empty($backtopage) || ($cancel && strpos($backtopage, '__ID__'))) { + if (empty($id) && (($action != 'add' && $action != 'create') || $cancel)) { + $backtopage = $backurlforlist; + } else { + $backtopage = DOL_URL_ROOT.'/asset/accountancy_codes.php?id='.((!empty($id) && $id > 0) ? $id : '__ID__'); + } + } + } + + if ($cancel) { + /*var_dump($cancel);var_dump($backtopage);var_dump($backtopageforcancel);exit;*/ + if (!empty($backtopageforcancel)) { + header("Location: ".$backtopageforcancel); + exit; + } elseif (!empty($backtopage)) { + header("Location: ".$backtopage); + exit; + } + $action = ''; + } + + if ($action == "update") { + $assetaccountancycodes->setAccountancyCodesFromPost(); + + $result = $assetaccountancycodes->updateAccountancyCodes($user, $object->id); + if ($result < 0) { + setEventMessages($assetaccountancycodes->error, $assetaccountancycodes->errors, 'errors'); + $action = 'edit'; + } else { + setEventMessage($langs->trans('RecordSaved')); + header("Location: " . $_SERVER["PHP_SELF"] . '?id=' . $object->id); + exit; + } + } +} + + +/* + * View + */ + +$form = new Form($db); + +$help_url = ''; +llxHeader('', $langs->trans('Asset'), $help_url); + +if ($id > 0 || !empty($ref)) { + $head = assetPrepareHead($object); + print dol_get_fiche_head($head, 'accountancy_codes', $langs->trans("Asset"), -1, $object->picto); + + // Object card + // ------------------------------------------------------------ + $linkback = '' . $langs->trans("BackToList") . ''; + + $morehtmlref = '
'; + $morehtmlref .= '
'; + + dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref); + + print '
'; + print '
'; + print '
'; + + if ($action == 'edit') { + print '
'; + print ''; + print ''; + if ($backtopage) { + print ''; + } + if ($backtopageforcancel) { + print ''; + } + + print dol_get_fiche_head(array(), ''); + + include DOL_DOCUMENT_ROOT . '/asset/tpl/accountancy_codes_edit.tpl.php'; + + print dol_get_fiche_end(); + + print $form->buttonsSaveCancel(); + + print '
'; + } else { + include DOL_DOCUMENT_ROOT . '/asset/tpl/accountancy_codes_view.tpl.php'; + } + + print dol_get_fiche_end(); + + if ($action != 'edit') { + print '
' . "\n"; + $parameters = array(); + $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook + if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + } + + if (empty($reshook)) { + if ($object->status == $object::STATUS_DRAFT/* && !empty($object->enabled_modes)*/) { + print dolGetButtonAction($langs->trans('Modify'), '', 'default', $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=edit&token=' . newToken(), '', $permissiontoadd); + } + } + print '
' . "\n"; + } +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/asset/admin/assets_type_extrafields.php b/htdocs/asset/admin/asset_extrafields.php similarity index 56% rename from htdocs/asset/admin/assets_type_extrafields.php rename to htdocs/asset/admin/asset_extrafields.php index 165361f7f57..a84d3bc2016 100644 --- a/htdocs/asset/admin/assets_type_extrafields.php +++ b/htdocs/asset/admin/asset_extrafields.php @@ -1,5 +1,11 @@ +/* Copyright (C) 2001-2002 Rodolphe Quiedeville + * Copyright (C) 2003 Jean-Louis Bergamo + * Copyright (C) 2004-2011 Laurent Destailleur + * Copyright (C) 2012 Regis Houssin + * Copyright (C) 2014 Florian Henry + * Copyright (C) 2015 Jean-François Ferry + * Copyright (C) 2018 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 @@ -13,20 +19,20 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - * or see https://www.gnu.org/ */ /** - * \file htdocs/asset/admin/assets_type_extrafields.php - * \ingroup asset - * \brief Page to setup extra fields type of assets + * \file htdocs/asset/admin/asset_extrafields.php + * \ingroup asset + * \brief Page to setup extra fields of asset */ + require '../../main.inc.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/asset.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; // Load translation files required by the page -$langs->loadLangs(array('assets', 'admin')); +$langs->loadLangs(array("assets", "admin", "companies")); $extrafields = new ExtraFields($db); $form = new Form($db); @@ -40,7 +46,7 @@ foreach ($tmptype2label as $key => $val) { $action = GETPOST('action', 'aZ09'); $attrname = GETPOST('attrname', 'alpha'); -$elementtype = 'adherent_type'; //Must be the $table_element of the class that manage extrafield +$elementtype = 'asset'; //Must be the $table_element of the class that manage extrafield if (!$user->admin) { accessforbidden(); @@ -59,38 +65,47 @@ require DOL_DOCUMENT_ROOT.'/core/actions_extrafields.inc.php'; * View */ -$textobject = $langs->transnoentitiesnoconv("AssetsTypes"); +$help_url = ''; +$page_name = "AssetSetup"; +$textobject = $langs->transnoentitiesnoconv("Assets"); -llxHeader('', $langs->trans("AssetsSetup")); - -$linkback = ''.$langs->trans("BackToModuleList").''; -print load_fiche_titre($langs->trans("AssetsSetup"), $linkback, 'title_setup'); +llxHeader('', $langs->trans("AssetSetup"), $help_url); -$head = asset_admin_prepare_head(); +$linkback = ''.$langs->trans("BackToModuleList").''; +print load_fiche_titre($langs->trans($page_name), $linkback, 'title_setup'); -print dol_get_fiche_head($head, 'attributes_type', $langs->trans("Assets"), -1, 'generic'); + +$head = assetAdminPrepareHead(); + +print dol_get_fiche_head($head, 'asset_extrafields', $langs->trans($page_name), -1, 'asset'); require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_view.tpl.php'; print dol_get_fiche_end(); + // Buttons if ($action != 'create' && $action != 'edit') { print '"; } -// Creation of an optional field + +/* + * Creation of an optional field + */ if ($action == 'create') { - print "
"; + print '
'; print load_fiche_titre($langs->trans('NewAttribute')); require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_add.tpl.php'; } -// Edition of an optional field +/* + * Edition of an optional field + */ if ($action == 'edit' && !empty($attrname)) { print "
"; print load_fiche_titre($langs->trans("FieldEdition", $attrname)); diff --git a/htdocs/asset/admin/assets_extrafields.php b/htdocs/asset/admin/assetmodel_extrafields.php similarity index 54% rename from htdocs/asset/admin/assets_extrafields.php rename to htdocs/asset/admin/assetmodel_extrafields.php index 9a68f99fe06..387c43df635 100644 --- a/htdocs/asset/admin/assets_extrafields.php +++ b/htdocs/asset/admin/assetmodel_extrafields.php @@ -1,6 +1,11 @@ - * Copyright (C) 2018 Alexandre Spangaro +/* Copyright (C) 2001-2002 Rodolphe Quiedeville + * Copyright (C) 2003 Jean-Louis Bergamo + * Copyright (C) 2004-2011 Laurent Destailleur + * Copyright (C) 2012 Regis Houssin + * Copyright (C) 2014 Florian Henry + * Copyright (C) 2015 Jean-François Ferry + * Copyright (C) 2018 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 @@ -17,9 +22,9 @@ */ /** - * \file htdocs/asset/admin/assets_extrafields.php + * \file htdocs/asset/admin/assetmodel_extrafields.php * \ingroup asset - * \brief Page to setup extra fields of assets + * \brief Page to setup extra fields of asset model */ require '../../main.inc.php'; @@ -41,7 +46,7 @@ foreach ($tmptype2label as $key => $val) { $action = GETPOST('action', 'aZ09'); $attrname = GETPOST('attrname', 'alpha'); -$elementtype = 'don'; //Must be the $table_element of the class that manage extrafield +$elementtype = 'asset_model'; //Must be the $table_element of the class that manage extrafield if (!$user->admin) { accessforbidden(); @@ -60,17 +65,20 @@ require DOL_DOCUMENT_ROOT.'/core/actions_extrafields.inc.php'; * View */ -$textobject = $langs->transnoentitiesnoconv("Assets"); +$help_url = ''; +$page_name = "AssetSetup"; +$textobject = $langs->transnoentitiesnoconv("AssetModels"); -llxHeader('', $langs->trans("AssetsSetup")); - -$linkback = ''.$langs->trans("BackToModuleList").''; -print load_fiche_titre($langs->trans("AssetsSetup"), $linkback, 'title_setup'); +llxHeader('', $langs->trans("AssetSetup"), $help_url); -$head = asset_admin_prepare_head(); +$linkback = ''.$langs->trans("BackToModuleList").''; +print load_fiche_titre($langs->trans($page_name), $linkback, 'title_setup'); -print dol_get_fiche_head($head, 'attributes', $langs->trans("Assets"), -1, 'generic'); + +$head = assetAdminPrepareHead(); + +print dol_get_fiche_head($head, 'assetmodel_extrafields', $langs->trans($page_name), -1, 'asset'); require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_view.tpl.php'; @@ -80,29 +88,24 @@ print dol_get_fiche_end(); // Buttons if ($action != 'create' && $action != 'edit') { print '"; } -/* ************************************************************************** */ -/* */ -/* Create optional field */ -/* */ -/* ************************************************************************** */ - +/* + * Creation of an optional field + */ if ($action == 'create') { - print "
"; + print '
'; print load_fiche_titre($langs->trans('NewAttribute')); require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_add.tpl.php'; } -/* ************************************************************************** */ -/* */ -/* Edit optional field */ -/* */ -/* ************************************************************************** */ +/* + * Edition of an optional field + */ if ($action == 'edit' && !empty($attrname)) { print "
"; print load_fiche_titre($langs->trans("FieldEdition", $attrname)); diff --git a/htdocs/asset/admin/setup.php b/htdocs/asset/admin/setup.php index a90c2b479c4..b671f309138 100644 --- a/htdocs/asset/admin/setup.php +++ b/htdocs/asset/admin/setup.php @@ -18,8 +18,8 @@ /** * \file htdocs/asset/admin/setup.php - * \ingroup assets - * \brief Assets setup page. + * \ingroup asset + * \brief Asset setup page. */ require '../../main.inc.php'; @@ -40,30 +40,421 @@ if (!$user->admin) { $action = GETPOST('action', 'aZ09'); $backtopage = GETPOST('backtopage', 'alpha'); -$arrayofparameters = array('FIXEDASSETS_MYPARAM1'=>array('css'=>'minwidth200'), 'FIXEDASSETS_MYPARAM2'=>array('css'=>'minwidth500')); +$value = GETPOST('value', 'alpha'); +$label = GETPOST('label', 'alpha'); +$scandir = GETPOST('scan_dir', 'alpha'); +$type = 'asset'; + +$arrayofparameters = array( + 'ASSET_ACCOUNTANCY_CATEGORY'=>array('type'=>'accountancy_category', 'enabled'=>1), + //'ASSET_MYPARAM1'=>array('type'=>'string', 'css'=>'minwidth500' ,'enabled'=>1), + //'ASSET_MYPARAM2'=>array('type'=>'textarea','enabled'=>1), + //'ASSET_MYPARAM3'=>array('type'=>'category:'.Categorie::TYPE_CUSTOMER, 'enabled'=>1), + //'ASSET_MYPARAM4'=>array('type'=>'emailtemplate:thirdparty', 'enabled'=>1), + //'ASSET_MYPARAM5'=>array('type'=>'yesno', 'enabled'=>1), + //'ASSET_MYPARAM5'=>array('type'=>'thirdparty_type', 'enabled'=>1), + //'ASSET_MYPARAM6'=>array('type'=>'securekey', 'enabled'=>1), + //'ASSET_MYPARAM7'=>array('type'=>'product', 'enabled'=>1), +); + +$error = 0; +$setupnotempty = 0; + +$dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']); /* * Actions */ -include DOL_DOCUMENT_ROOT.'/core/actions_setmoduleoptions.inc.php'; +if ((float) DOL_VERSION >= 6) { + include DOL_DOCUMENT_ROOT.'/core/actions_setmoduleoptions.inc.php'; +} + +if ($action == 'updateMask') { + $maskconstorder = GETPOST('maskconstorder', 'alpha'); + $maskorder = GETPOST('maskorder', 'alpha'); + + if ($maskconstorder) { + $res = dolibarr_set_const($db, $maskconstorder, $maskorder, 'chaine', 0, '', $conf->entity); + if (!($res > 0)) { + $error++; + } + } + + if (!$error) { + setEventMessages($langs->trans("SetupSaved"), null, 'mesgs'); + } else { + setEventMessages($langs->trans("Error"), null, 'errors'); + } +} elseif ($action == 'specimen') { + $modele = GETPOST('module', 'alpha'); + $tmpobjectkey = GETPOST('object'); + + $tmpobject = new $tmpobjectkey($db); + $tmpobject->initAsSpecimen(); + + // Search template files + $file = ''; $classname = ''; $filefound = 0; + $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']); + foreach ($dirmodels as $reldir) { + $file = dol_buildpath($reldir."core/modules/asset/doc/pdf_".$modele."_".strtolower($tmpobjectkey).".modules.php", 0); + if (file_exists($file)) { + $filefound = 1; + $classname = "pdf_".$modele; + break; + } + } + + if ($filefound) { + require_once $file; + + $module = new $classname($db); + + if ($module->write_file($tmpobject, $langs) > 0) { + header("Location: ".DOL_URL_ROOT."/document.php?modulepart=".strtolower($tmpobjectkey)."&file=SPECIMEN.pdf"); + return; + } else { + setEventMessages($module->error, null, 'errors'); + dol_syslog($module->error, LOG_ERR); + } + } else { + setEventMessages($langs->trans("ErrorModuleNotFound"), null, 'errors'); + dol_syslog($langs->trans("ErrorModuleNotFound"), LOG_ERR); + } +} elseif ($action == 'setmod') { + // TODO Check if numbering module chosen can be activated by calling method canBeActivated + $tmpobjectkey = GETPOST('object'); + if (!empty($tmpobjectkey)) { + $constforval = 'ASSET_'.strtoupper($tmpobjectkey)."_ADDON"; + dolibarr_set_const($db, $constforval, $value, 'chaine', 0, '', $conf->entity); + } +} elseif ($action == 'set') { + // Activate a model + $ret = addDocumentModel($value, $type, $label, $scandir); +} elseif ($action == 'del') { + $ret = delDocumentModel($value, $type); + if ($ret > 0) { + $tmpobjectkey = GETPOST('object'); + if (!empty($tmpobjectkey)) { + $constforval = 'ASSET_'.strtoupper($tmpobjectkey).'_ADDON_PDF'; + if ($conf->global->$constforval == "$value") { + dolibarr_del_const($db, $constforval, $conf->entity); + } + } + } +} elseif ($action == 'setdoc') { + // Set or unset default model + $tmpobjectkey = GETPOST('object'); + if (!empty($tmpobjectkey)) { + $constforval = 'ASSET_'.strtoupper($tmpobjectkey).'_ADDON_PDF'; + if (dolibarr_set_const($db, $constforval, $value, 'chaine', 0, '', $conf->entity)) { + // The constant that was read before the new set + // We therefore requires a variable to have a coherent view + $conf->global->$constforval = $value; + } + + // We disable/enable the document template (into llx_document_model table) + $ret = delDocumentModel($value, $type); + if ($ret > 0) { + $ret = addDocumentModel($value, $type, $label, $scandir); + } + } +} elseif ($action == 'unsetdoc') { + $tmpobjectkey = GETPOST('object'); + if (!empty($tmpobjectkey)) { + $constforval = 'ASSET_'.strtoupper($tmpobjectkey).'_ADDON_PDF'; + dolibarr_del_const($db, $constforval, $conf->entity); + } +} + /* * View */ -llxHeader('', $langs->trans("AssetsSetup")); +$form = new Form($db); -$linkback = ''.$langs->trans("BackToModuleList").''; -print load_fiche_titre($langs->trans("AssetsSetup"), $linkback, 'title_setup'); +$help_url = ''; +$page_name = "AssetSetup"; + +llxHeader('', $langs->trans($page_name), $help_url); + +// Subheader +$linkback = ''.$langs->trans("BackToModuleList").''; + +print load_fiche_titre($langs->trans($page_name), $linkback, 'title_setup'); + +// Configuration header +$head = assetAdminPrepareHead(); +print dol_get_fiche_head($head, 'settings', $langs->trans($page_name), -1, "asset"); + +// Setup page goes here +echo ''.$langs->trans("AssetSetupPage").''; -$head = asset_admin_prepare_head(); +$moduledir = 'asset'; +$myTmpObjects = array(); +$myTmpObjects['Asset'] = array('includerefgeneration'=>1, 'includedocgeneration'=>0); -print dol_get_fiche_head($head, 'settings', $langs->trans("Assets"), -1, 'generic'); +foreach ($myTmpObjects as $myTmpObjectKey => $myTmpObjectArray) { + if ($myTmpObjectKey == 'MyObject') { + continue; + } + if ($myTmpObjectArray['includerefgeneration']) { + /* + * Orders Numbering model + */ + $setupnotempty++; + + print load_fiche_titre($langs->trans("NumberingModules", $myTmpObjectKey), '', ''); + + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''."\n"; + + clearstatcache(); + + foreach ($dirmodels as $reldir) { + $dir = dol_buildpath($reldir."core/modules/".$moduledir); + + if (is_dir($dir)) { + $handle = opendir($dir); + if (is_resource($handle)) { + while (($file = readdir($handle)) !== false) { + if (strpos($file, 'mod_'.strtolower($myTmpObjectKey).'_') === 0 && substr($file, dol_strlen($file) - 3, 3) == 'php') { + $file = substr($file, 0, dol_strlen($file) - 4); + + require_once $dir.'/'.$file.'.php'; + + $module = new $file($db); + + // Show modules according to features level + if ($module->version == 'development' && $conf->global->MAIN_FEATURES_LEVEL < 2) { + continue; + } + if ($module->version == 'experimental' && $conf->global->MAIN_FEATURES_LEVEL < 1) { + continue; + } + + if ($module->isEnabled()) { + dol_include_once('/'.$moduledir.'/class/'.strtolower($myTmpObjectKey).'.class.php'); + + print ''; + + // Show example of numbering model + print ''."\n"; + + print ''; + + $mytmpinstance = new $myTmpObjectKey($db); + $mytmpinstance->initAsSpecimen(); + + // Info + $htmltooltip = ''; + $htmltooltip .= ''.$langs->trans("Version").': '.$module->getVersion().'
'; + + $nextval = $module->getNextValue($mytmpinstance); + if ("$nextval" != $langs->trans("NotAvailable")) { // Keep " on nextval + $htmltooltip .= ''.$langs->trans("NextValue").': '; + if ($nextval) { + if (preg_match('/^Error/', $nextval) || $nextval == 'NotConfigured') { + $nextval = $langs->trans($nextval); + } + $htmltooltip .= $nextval.'
'; + } else { + $htmltooltip .= $langs->trans($module->error).'
'; + } + } + + print ''; + + print "\n"; + } + } + } + closedir($handle); + } + } + } + print "
'.$langs->trans("Name").''.$langs->trans("Description").''.$langs->trans("Example").''.$langs->trans("Status").''.$langs->trans("ShortInfo").'
'.$module->name."\n"; + print $module->info(); + print ''; + $tmp = $module->getExample(); + if (preg_match('/^Error/', $tmp)) { + $langs->load("errors"); + print '
'.$langs->trans($tmp).'
'; + } elseif ($tmp == 'NotConfigured') { + print $langs->trans($tmp); + } else { + print $tmp; + } + print '
'; + $constforvar = 'ASSET_'.strtoupper($myTmpObjectKey).'_ADDON'; + if ($conf->global->$constforvar == $file) { + print img_picto($langs->trans("Activated"), 'switch_on'); + } else { + print ''; + print img_picto($langs->trans("Disabled"), 'switch_off'); + print ''; + } + print ''; + print $form->textwithpicto('', $htmltooltip, 1, 0); + print '

\n"; + } + + if ($myTmpObjectArray['includedocgeneration']) { + /* + * Document templates generators + */ + $setupnotempty++; + $type = strtolower($myTmpObjectKey); + + print load_fiche_titre($langs->trans("DocumentModules", $myTmpObjectKey), '', ''); + + // Load array def with activated templates + $def = array(); + $sql = "SELECT nom"; + $sql .= " FROM ".MAIN_DB_PREFIX."document_model"; + $sql .= " WHERE type = '".$db->escape($type)."'"; + $sql .= " AND entity = ".$conf->entity; + $resql = $db->query($sql); + if ($resql) { + $i = 0; + $num_rows = $db->num_rows($resql); + while ($i < $num_rows) { + $array = $db->fetch_array($resql); + array_push($def, $array[0]); + $i++; + } + } else { + dol_print_error($db); + } + + print "\n"; + print "\n"; + print ''; + print ''; + print '\n"; + print '\n"; + print ''; + print ''; + print "\n"; + + clearstatcache(); + + foreach ($dirmodels as $reldir) { + foreach (array('', '/doc') as $valdir) { + $realpath = $reldir."core/modules/".$moduledir.$valdir; + $dir = dol_buildpath($realpath); + + if (is_dir($dir)) { + $handle = opendir($dir); + if (is_resource($handle)) { + while (($file = readdir($handle)) !== false) { + $filelist[] = $file; + } + closedir($handle); + arsort($filelist); + + foreach ($filelist as $file) { + if (preg_match('/\.modules\.php$/i', $file) && preg_match('/^(pdf_|doc_)/', $file)) { + if (file_exists($dir.'/'.$file)) { + $name = substr($file, 4, dol_strlen($file) - 16); + $classname = substr($file, 0, dol_strlen($file) - 12); + + require_once $dir.'/'.$file; + $module = new $classname($db); + + $modulequalified = 1; + if ($module->version == 'development' && $conf->global->MAIN_FEATURES_LEVEL < 2) { + $modulequalified = 0; + } + if ($module->version == 'experimental' && $conf->global->MAIN_FEATURES_LEVEL < 1) { + $modulequalified = 0; + } + + if ($modulequalified) { + print ''; + + // Active + if (in_array($name, $def)) { + print ''; + } else { + print '"; + } + + // Default + print ''; + + // Info + $htmltooltip = ''.$langs->trans("Name").': '.$module->name; + $htmltooltip .= '
'.$langs->trans("Type").': '.($module->type ? $module->type : $langs->trans("Unknown")); + if ($module->type == 'pdf') { + $htmltooltip .= '
'.$langs->trans("Width").'/'.$langs->trans("Height").': '.$module->page_largeur.'/'.$module->page_hauteur; + } + $htmltooltip .= '
'.$langs->trans("Path").': '.preg_replace('/^\//', '', $realpath).'/'.$file; + + $htmltooltip .= '

'.$langs->trans("FeaturesSupported").':'; + $htmltooltip .= '
'.$langs->trans("Logo").': '.yn($module->option_logo, 1, 1); + $htmltooltip .= '
'.$langs->trans("MultiLanguage").': '.yn($module->option_multilang, 1, 1); + + print ''; + + // Preview + print ''; + + print "\n"; + } + } + } + } + } + } + } + } + + print '
'.$langs->trans("Name").''.$langs->trans("Description").''.$langs->trans("Status")."'.$langs->trans("Default")."'.$langs->trans("ShortInfo").''.$langs->trans("Preview").'
'; + print (empty($module->name) ? $name : $module->name); + print "\n"; + if (method_exists($module, 'info')) { + print $module->info($langs); + } else { + print $module->description; + } + print ''."\n"; + print ''; + print img_picto($langs->trans("Enabled"), 'switch_on'); + print ''; + print ''."\n"; + print 'scandir).'&label='.urlencode($module->name).'">'.img_picto($langs->trans("Disabled"), 'switch_off').''; + print "'; + $constforvar = 'ASSET_'.strtoupper($myTmpObjectKey).'_ADDON'; + if ($conf->global->$constforvar == $name) { + //print img_picto($langs->trans("Default"), 'on'); + // Even if choice is the default value, we allow to disable it. Replace this with previous line if you need to disable unset + print 'scandir).'&label='.urlencode($module->name).'&type='.urlencode($type).'" alt="'.$langs->trans("Disable").'">'.img_picto($langs->trans("Enabled"), 'on').''; + } else { + print 'scandir).'&label='.urlencode($module->name).'" alt="'.$langs->trans("Default").'">'.img_picto($langs->trans("Disabled"), 'off').''; + } + print ''; + print $form->textwithpicto('', $htmltooltip, 1, 0); + print ''; + if ($module->type == 'pdf') { + print ''.img_object($langs->trans("Preview"), 'pdf').''; + } else { + print img_object($langs->trans("PreviewNotAvailable"), 'generic'); + } + print '
'; + } +} if ($action == 'edit') { print '
'; @@ -73,37 +464,221 @@ if ($action == 'edit') { print ''; print ''; - foreach ($arrayofparameters as $key => $val) { - print ''; - } + foreach ($arrayofparameters as $constname => $val) { + if ($val['enabled']==1) { + $setupnotempty++; + print ''; + } + } print '
'.$langs->trans("Parameter").''.$langs->trans("Value").'
'; - print $form->textwithpicto($langs->trans($key), $langs->trans($key.'Tooltip')); - print '
'; + $tooltiphelp = (($langs->trans($constname . 'Tooltip') != $constname . 'Tooltip') ? $langs->trans($constname . 'Tooltip') : ''); + print ''.$form->textwithpicto($langs->trans($constname), $tooltiphelp, 1, 'info', '', 0, 3, 'tootips'.$constname).''; + print ''; + if ($val['type'] == 'textarea') { + print '\n"; + } elseif ($val['type']== 'html') { + require_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php'; + $doleditor = new DolEditor($constname, $conf->global->{$constname}, '', 160, 'dolibarr_notes', '', false, false, $conf->fckeditor->enabled, ROWS_5, '90%'); + $doleditor->Create(); + } elseif ($val['type'] == 'yesno') { + print $form->selectyesno($constname, $conf->global->{$constname}, 1); + } elseif (preg_match('/emailtemplate:/', $val['type'])) { + include_once DOL_DOCUMENT_ROOT . '/core/class/html.formmail.class.php'; + $formmail = new FormMail($db); + + $tmp = explode(':', $val['type']); + $nboftemplates = $formmail->fetchAllEMailTemplate($tmp[1], $user, null, 1); // We set lang=null to get in priority record with no lang + //$arraydefaultmessage = $formmail->getEMailTemplate($db, $tmp[1], $user, null, 0, 1, ''); + $arrayofmessagename = array(); + if (is_array($formmail->lines_model)) { + foreach ($formmail->lines_model as $modelmail) { + //var_dump($modelmail); + $moreonlabel = ''; + if (!empty($arrayofmessagename[$modelmail->label])) { + $moreonlabel = ' (' . $langs->trans("SeveralLangugeVariatFound") . ')'; + } + // The 'label' is the key that is unique if we exclude the language + $arrayofmessagename[$modelmail->id] = $langs->trans(preg_replace('/\(|\)/', '', $modelmail->label)) . $moreonlabel; + } + } + print $form->selectarray($constname, $arrayofmessagename, $conf->global->{$constname}, 'None', 0, 0, '', 0, 0, 0, '', '', 1); + } elseif (preg_match('/category:/', $val['type'])) { + require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; + require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; + $formother = new FormOther($db); + + $tmp = explode(':', $val['type']); + print img_picto('', 'category', 'class="pictofixedwidth"'); + print $formother->select_categories($tmp[1], $conf->global->{$constname}, $constname, 0, $langs->trans('CustomersProspectsCategoriesShort')); + } elseif (preg_match('/thirdparty_type/', $val['type'])) { + require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; + $formcompany = new FormCompany($db); + print $formcompany->selectProspectCustomerType($conf->global->{$constname}, $constname); + } elseif ($val['type'] == 'securekey') { + print ''; + if (!empty($conf->use_javascript_ajax)) { + print ' '.img_picto($langs->trans('Generate'), 'refresh', 'id="generate_token'.$constname.'" class="linkobject"'); + } + if (!empty($conf->use_javascript_ajax)) { + print "\n".''; + } + } elseif ($val['type'] == 'product') { + if (!empty($conf->product->enabled) || !empty($conf->service->enabled)) { + $selected = (empty($conf->global->$constname) ? '' : $conf->global->$constname); + $form->select_produits($selected, $constname, '', 0); + } + } elseif ($val['type'] == 'accountancy_code') { + $selected = (empty($conf->global->$constname) ? '' : $conf->global->$constname); + if (!empty($conf->accounting->enabled)) { + require_once DOL_DOCUMENT_ROOT . '/core/class/html.formaccounting.class.php'; + $formaccounting = new FormAccounting($db); + print $formaccounting->select_account($selected, $constname, 1, null, 1, 1, 'minwidth150 maxwidth300', 1); + } else { + print ''; + } + } elseif ($val['type'] == 'accountancy_category') { + $selected = (empty($conf->global->$constname) ? '' : $conf->global->$constname); + if (!empty($conf->accounting->enabled)) { + print ''; + // autosuggest from existing account types if found + print ''; + require_once DOL_DOCUMENT_ROOT . '/accountancy/class/accountancysystem.class.php'; + $accountsystem = new AccountancySystem($db); + $accountsystem->fetch($conf->global->CHARTOFACCOUNTS); + $sql = 'SELECT DISTINCT pcg_type FROM ' . MAIN_DB_PREFIX . 'accounting_account'; + $sql .= " WHERE fk_pcg_version = '" . $db->escape($accountsystem->ref) . "'"; + $sql .= ' AND entity in ('.getEntity('accounting_account', 0).')'; // Always limit to current entity. No sharing in accountancy. + $sql .= ' LIMIT 50000'; // just as a sanity check + $resql = $db->query($sql); + if ($resql) { + while ($obj = $db->fetch_object($resql)) { + print ''; + } else { + print ''; + } + } else { + print ''; + } + print '
'; - print $form->buttonsSaveCancel("Save", ''); + print '
'; + print ''; + print '
'; print '
'; print '
'; } else { - print ''; - print ''; + if (!empty($arrayofparameters)) { + print '
'.$langs->trans("Parameter").''.$langs->trans("Value").'
'; + print ''; - foreach ($arrayofparameters as $key => $val) { - print ''; + foreach ($arrayofparameters as $constname => $val) { + if ($val['enabled']==1) { + $setupnotempty++; + print ''; + } + } + + print '
'.$langs->trans("Parameter").''.$langs->trans("Value").'
'; - print $form->textwithpicto($langs->trans($key), $langs->trans($key.'Tooltip')); - print ''.$conf->global->$key.'
'; + $tooltiphelp = (($langs->trans($constname . 'Tooltip') != $constname . 'Tooltip') ? $langs->trans($constname . 'Tooltip') : ''); + print $form->textwithpicto($langs->trans($constname), $tooltiphelp); + print ''; + + if ($val['type'] == 'textarea') { + print dol_nl2br($conf->global->{$constname}); + } elseif ($val['type']== 'html') { + print $conf->global->{$constname}; + } elseif ($val['type'] == 'yesno') { + print ajax_constantonoff($constname); + } elseif (preg_match('/emailtemplate:/', $val['type'])) { + include_once DOL_DOCUMENT_ROOT . '/core/class/html.formmail.class.php'; + $formmail = new FormMail($db); + + $tmp = explode(':', $val['type']); + + $template = $formmail->getEMailTemplate($db, $tmp[1], $user, $langs, $conf->global->{$constname}); + if ($template<0) { + setEventMessages(null, $formmail->errors, 'errors'); + } + print $langs->trans($template->label); + } elseif (preg_match('/category:/', $val['type'])) { + $c = new Categorie($db); + $result = $c->fetch($conf->global->{$constname}); + if ($result < 0) { + setEventMessages(null, $c->errors, 'errors'); + } elseif ($result > 0 ) { + $ways = $c->print_all_ways(' >> ', 'none', 0, 1); // $ways[0] = "ccc2 >> ccc2a >> ccc2a1" with html formated text + $toprint = array(); + foreach ($ways as $way) { + $toprint[] = '
  • color ? ' style="background: #' . $c->color . ';"' : ' style="background: #bbb"') . '>' . $way . '
  • '; + } + print '
      ' . implode(' ', $toprint) . '
    '; + } + } elseif (preg_match('/thirdparty_type/', $val['type'])) { + if ($conf->global->{$constname}==2) { + print $langs->trans("Prospect"); + } elseif ($conf->global->{$constname}==3) { + print $langs->trans("ProspectCustomer"); + } elseif ($conf->global->{$constname}==1) { + print $langs->trans("Customer"); + } elseif ($conf->global->{$constname}==0) { + print $langs->trans("NorProspectNorCustomer"); + } + } elseif ($val['type'] == 'product') { + $product = new Product($db); + $resprod = $product->fetch($conf->global->{$constname}); + if ($resprod > 0) { + print $product->ref; + } elseif ($resprod < 0) { + setEventMessages(null, $object->errors, "errors"); + } + } elseif ($val['type'] == 'accountancy_code') { + if (!empty($conf->accounting->enabled)) { + require_once DOL_DOCUMENT_ROOT . '/accountancy/class/accountingaccount.class.php'; + $accountingaccount = new AccountingAccount($db); + $accountingaccount->fetch('', $conf->global->{$constname}, 1); + + print $accountingaccount->getNomUrl(0, 1, 1, '', 1); + } else { + print $conf->global->{$constname}; + } + } else { + print $conf->global->{$constname}; + } + print '
    '; + + print '
    '; + print ''.$langs->trans("Modify").''; + print '
    '; + } else { + print '
    '.$langs->trans("NothingToSetup"); } - - print ''; - - print '
    '; - print ''.$langs->trans("Modify").''; - print '
    '; } +if (empty($setupnotempty)) { + print '
    '.$langs->trans("NothingToSetup"); +} + +// Page end print dol_get_fiche_end(); -// End of page llxFooter(); $db->close(); diff --git a/htdocs/asset/agenda.php b/htdocs/asset/agenda.php new file mode 100644 index 00000000000..49a0c215701 --- /dev/null +++ b/htdocs/asset/agenda.php @@ -0,0 +1,215 @@ + + * Copyright (C) ---Put here your own copyright and developer email--- + * + * 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 + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/asset/agenda.php + * \ingroup asset + * \brief Tab of events on Asset + */ + +require '../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/asset.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/asset/class/asset.class.php'; +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'; + +// Load translation files required by the page +$langs->loadLangs(array("assets", "other")); + +// Get parameters +$id = GETPOST('id', 'int'); +$ref = GETPOST('ref', 'alpha'); +$action = GETPOST('action', 'aZ09'); +$cancel = GETPOST('cancel', 'aZ09'); +$backtopage = GETPOST('backtopage', 'alpha'); + +if (GETPOST('actioncode', 'array')) { + $actioncode = GETPOST('actioncode', 'array', 3); + if (!count($actioncode)) { + $actioncode = '0'; + } +} else { + $actioncode = GETPOST("actioncode", "alpha", 3) ? GETPOST("actioncode", "alpha", 3) : (GETPOST("actioncode") == '0' ? '0' : (empty($conf->global->AGENDA_DEFAULT_FILTER_TYPE_FOR_OBJECT) ? '' : $conf->global->AGENDA_DEFAULT_FILTER_TYPE_FOR_OBJECT)); +} +$search_agenda_label = GETPOST('search_agenda_label'); + +$limit = GETPOST('limit', 'int') ? GETPOST('limit', 'int') : $conf->liste_limit; +$sortfield = GETPOST("sortfield", 'alpha'); +$sortorder = GETPOST("sortorder", 'alpha'); +$page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int'); +if (empty($page) || $page == -1) { + $page = 0; +} // If $page is not defined, or '' or -1 +$offset = $limit * $page; +$pageprev = $page - 1; +$pagenext = $page + 1; +if (!$sortfield) { + $sortfield = 'a.datep,a.id'; +} +if (!$sortorder) { + $sortorder = 'DESC,DESC'; +} + +// Initialize technical objects +$object = new Asset($db); +$extrafields = new ExtraFields($db); +$diroutputmassaction = $conf->asset->dir_output.'/temp/massgeneration/'.$user->id; +$hookmanager->initHooks(array('assetagenda', 'globalcard')); // Note that conf->hooks_modules contains array +// Fetch optionals attributes and labels +$extrafields->fetch_name_optionals_label($object->table_element); + +// Load object +include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be include, not include_once // Must be include, not include_once. Include fetch and fetch_thirdparty but not fetch_optionals +if ($id > 0 || !empty($ref)) { + $upload_dir = $conf->asset->multidir_output[$object->entity]."/".$object->id; +} + +$permissiontoadd = $user->rights->asset->write; // Used by the include of actions_addupdatedelete.inc.php + +// Security check (enable the most restrictive one) +if ($user->socid > 0) accessforbidden(); +$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +if (empty($conf->asset->enabled)) accessforbidden(); + + +/* + * Actions + */ + +$parameters = array('id'=>$id); +$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); +} + +if (empty($reshook)) { + // Cancel + if (GETPOST('cancel', 'alpha') && !empty($backtopage)) { + header("Location: ".$backtopage); + exit; + } + + // Purge search criteria + if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // All tests are required to be compatible with all browsers + $actioncode = ''; + $search_agenda_label = ''; + } +} + + + +/* + * View + */ + +$form = new Form($db); + +if ($object->id > 0) { + $title = $langs->trans("Agenda"); + //if (! empty($conf->global->MAIN_HTML_TITLE) && preg_match('/thirdpartynameonly/',$conf->global->MAIN_HTML_TITLE) && $object->name) $title=$object->name." - ".$title; + $help_url = 'EN:Module_Agenda_En'; + llxHeader('', $title, $help_url); + + if (!empty($conf->notification->enabled)) { + $langs->load("mails"); + } + $head = assetPrepareHead($object); + + + print dol_get_fiche_head($head, 'agenda', $langs->trans("Asset"), -1, $object->picto); + + // Object card + // ------------------------------------------------------------ + $linkback = '' . $langs->trans("BackToList") . ''; + + $morehtmlref = '
    '; + $morehtmlref .= '
    '; + + + dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref); + + print '
    '; + print '
    '; + + $object->info($object->id); + dol_print_object_info($object, 1); + + print '
    '; + + print dol_get_fiche_end(); + + + // Actions buttons + + $objthirdparty = $object; + $objcon = new stdClass(); + + $out = '&origin=' . urlencode($object->element . '@' . $object->module) . '&originid=' . urlencode($object->id); + $urlbacktopage = $_SERVER['PHP_SELF'] . '?id=' . $object->id; + $out .= '&backtopage=' . urlencode($urlbacktopage); + $permok = $user->rights->agenda->myactions->create; + if ((!empty($objthirdparty->id) || !empty($objcon->id)) && $permok) { + //$out.='trans("AddAnAction"),'filenew'); + //$out.=""; + } + + + print '
    '; + + if (!empty($conf->agenda->enabled)) { + if (!empty($user->rights->agenda->myactions->create) || !empty($user->rights->agenda->allactions->create)) { + print '' . $langs->trans("AddAction") . ''; + } else { + print '' . $langs->trans("AddAction") . ''; + } + } + + print '
    '; + + if (!empty($conf->agenda->enabled) && (!empty($user->rights->agenda->myactions->read) || !empty($user->rights->agenda->allactions->read))) { + $param = '&id=' . $object->id . '&socid=' . $socid; + if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) { + $param .= '&contextpage=' . urlencode($contextpage); + } + if ($limit > 0 && $limit != $conf->liste_limit) { + $param .= '&limit=' . urlencode($limit); + } + + + print load_fiche_titre($langs->trans("ActionsOnAsset"), '', ''); + + // List of all actions + $filters = array(); + $filters['search_agenda_label'] = $search_agenda_label; + + // TODO Replace this with same code than into list.php + show_actions_done($conf, $langs, $db, $object, null, 0, $actioncode, '', $filters, $sortfield, $sortorder, $object->module); + } +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/asset/card.php b/htdocs/asset/card.php index 35c0ffcff88..83271e299f0 100644 --- a/htdocs/asset/card.php +++ b/htdocs/asset/card.php @@ -1,6 +1,6 @@ - * Copyright (C) 2018 Alexandre Spangaro +/* Copyright (C) 2017 Laurent Destailleur + * Copyright (C) 2018 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 @@ -29,7 +29,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; // Load translation files required by the page -$langs->loadLangs(array("asset")); +$langs->loadLangs(array("assets", "other")); // Get parameters $id = GETPOST('id', 'int'); @@ -68,12 +68,6 @@ if (empty($action) && empty($id) && empty($ref)) { // Load object include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be include, not include_once. -// Security check -if (!empty($user->socid)) { - $socid = $user->socid; -} -$result = restrictedArea($user, 'asset', $id); - $permissiontoread = $user->rights->asset->read; $permissiontoadd = $user->rights->asset->write; // Used by the include of actions_addupdatedelete.inc.php and actions_lineupdown.inc.php $permissiontodelete = $user->rights->asset->delete || ($permissiontoadd && isset($object->status) && $object->status == $object::STATUS_DRAFT); @@ -81,7 +75,13 @@ $permissionnote = $user->rights->asset->write; // Used by the include of actions $permissiondellink = $user->rights->asset->write; // Used by the include of actions_dellink.inc.php $upload_dir = $conf->asset->multidir_output[isset($object->entity) ? $object->entity : 1]; -$error = 0; +// Security check (enable the most restrictive one) +if ($user->socid > 0) accessforbidden(); +if ($user->socid > 0) $socid = $user->socid; +$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +if (empty($conf->asset->enabled)) accessforbidden(); +if (!$permissiontoread) accessforbidden(); /* @@ -95,6 +95,8 @@ if ($reshook < 0) { } if (empty($reshook)) { + $error = 0; + $backurlforlist = DOL_URL_ROOT.'/asset/list.php'; if (empty($backtopage) || ($cancel && empty($id))) { @@ -107,6 +109,27 @@ if (empty($reshook)) { } } + $object->oldcopy = dol_clone($object); + $triggermodname = 'ASSET_MODIFY'; // Name of trigger action code to execute when we modify record + + // Action dispose object + if ($action == 'confirm_disposal' && $confirm == 'yes' && $permissiontoadd) { + $object->disposal_date = dol_mktime(12, 0, 0, GETPOST('disposal_datemonth', 'int'), GETPOST('disposal_dateday', 'int'), GETPOST('disposal_dateyear', 'int')); // for date without hour, we use gmt + $object->disposal_amount_ht = GETPOST('disposal_amount', 'int'); + $object->fk_disposal_type = GETPOST('fk_disposal_type', 'int'); + $disposal_invoice_id = GETPOST('disposal_invoice_id', 'int'); + $object->disposal_depreciated = ((GETPOST('disposal_depreciated') == '1' || GETPOST('disposal_depreciated') == 'on') ? 1 : 0); + $object->disposal_subject_to_vat = ((GETPOST('disposal_subject_to_vat') == '1' || GETPOST('disposal_subject_to_vat') == 'on') ? 1 : 0); + + $result = $object->dispose($user, $disposal_invoice_id); + if ($result < 0) { + setEventMessages($object->error, $object->errors, 'errors'); + } + $action = ''; + } elseif ($action == "add") { + $object->supplier_invoice_id = GETPOST('supplier_invoice_id', 'int'); + } + // Actions cancel, add, update, update_extras, confirm_validate, confirm_delete, confirm_deleteline, confirm_clone, confirm_close, confirm_setdraft, confirm_reopen include DOL_DOCUMENT_ROOT.'/core/actions_addupdatedelete.inc.php'; @@ -122,13 +145,6 @@ if (empty($reshook)) { // Action to build doc include DOL_DOCUMENT_ROOT.'/core/actions_builddoc.inc.php'; - if ($action == 'set_thirdparty' && $permissiontoadd) { - $object->setValueFrom('fk_soc', GETPOST('fk_soc', 'int'), '', '', 'date', '', $user, 'MYOBJECT_MODIFY'); - } - if ($action == 'classin' && $permissiontoadd) { - $object->setProject(GETPOST('projectid', 'int')); - } - // Actions to send emails $triggersendname = 'ASSET_SENTBYMAIL'; $autocopy = 'MAIN_MAIL_AUTOCOPY_ASSET_TO'; @@ -136,6 +152,7 @@ if (empty($reshook)) { include DOL_DOCUMENT_ROOT.'/core/actions_sendmails.inc.php'; } + /* * View * @@ -150,7 +167,7 @@ llxHeader('', $title, $help_url); // Part to create if ($action == 'create') { - print load_fiche_titre($langs->trans("NewAsset"), '', $object->picto); + print load_fiche_titre($langs->trans("NewObject", $langs->transnoentitiesnoconv("Asset")), '', 'object_'.$object->picto); print '
    '; print ''; @@ -161,9 +178,16 @@ if ($action == 'create') { if ($backtopageforcancel) { print ''; } + if (GETPOSTISSET('supplier_invoice_id')) { + $object->fields['supplier_invoice_id'] = array('type' => 'integer:FactureFournisseur:fourn/class/fournisseur.facture.class.php:1:entity IN (__SHARED_ENTITIES__)', 'label' => 'SupplierInvoice', 'enabled' => '1', 'noteditable' => '1', 'position' => 280, 'notnull' => 0, 'visible' => 1, 'index' => 1, 'validate' => '1',); + print ''; + } print dol_get_fiche_head(array(), ''); + // Set some default values + //if (! GETPOSTISSET('fieldname')) $_POST['fieldname'] = 'myvalue'; + print ''."\n"; // Common attributes @@ -185,12 +209,11 @@ if ($action == 'create') { // Part to edit record if (($id || $ref) && $action == 'edit') { - print load_fiche_titre($langs->trans("Assets")); + print load_fiche_titre($langs->trans("Asset"), '', 'object_'.$object->picto); print ''; print ''; print ''; - print ''; print ''; if ($backtopage) { print ''; @@ -222,18 +245,62 @@ if (($id || $ref) && $action == 'edit') { if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'create'))) { $res = $object->fetch_optionals(); - $head = asset_prepare_head($object); + $head = assetPrepareHead($object); print dol_get_fiche_head($head, 'card', $langs->trans("Asset"), -1, $object->picto); $formconfirm = ''; // Confirmation to delete if ($action == 'delete') { - $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('DeleteAssets'), $langs->trans('ConfirmDeleteAsset'), 'confirm_delete', '', 0, 1); + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('DeleteAsset'), $langs->trans('ConfirmDeleteObject'), 'confirm_delete', '', 0, 1); } + // Disposal + elseif ($action == 'disposal') { + $langs->load('bills'); + + $disposal_date = dol_mktime(12, 0, 0, GETPOST('disposal_datemonth', 'int'), GETPOST('disposal_dateday', 'int'), GETPOST('disposal_dateyear', 'int')); // for date without hour, we use gmt + $disposal_amount = GETPOST('disposal_amount', 'int'); + $fk_disposal_type = GETPOST('fk_disposal_type', 'int'); + $disposal_invoice_id = GETPOST('disposal_invoice_id', 'int'); + $disposal_depreciated = GETPOSTISSET('disposal_depreciated') ? GETPOST('disposal_depreciated') : 1; + $disposal_depreciated = !empty($disposal_depreciated) ? 1 : 0; + $disposal_subject_to_vat = GETPOSTISSET('disposal_subject_to_vat') ? GETPOST('disposal_subject_to_vat') : 1; + $disposal_subject_to_vat = !empty($disposal_subject_to_vat) ? 1 : 0; + + $object->fields['fk_disposal_type']['visible'] = 1; + $disposal_type_form = $object->showInputField(null, 'fk_disposal_type', $fk_disposal_type, '', '', '', 0); + $object->fields['fk_disposal_type']['visible'] = -2; + + $object->fields['disposal_invoice_id'] = array('type' => 'integer:Facture:compta/facture/class/facture.class.php::entity IN (__SHARED_ENTITIES__)', 'enabled' => '1', 'notnull' => 1, 'visible' => 1, 'index' => 1, 'validate' => '1',); + $disposal_invoice_form = $object->showInputField(null, 'disposal_invoice_id', $disposal_invoice_id, '', '', '', 0); + unset($object->fields['disposal_invoice_id']); + + // Create an array for form + $formquestion = array( + array('type' => 'date', 'name' => 'disposal_date', 'tdclass' => 'fieldrequired', 'label' => $langs->trans("AssetDisposalDate"), 'value' => $disposal_date), + array('type' => 'text', 'name' => 'disposal_amount', 'tdclass' => 'fieldrequired', 'label' => $langs->trans("AssetDisposalAmount"), 'value' => $disposal_amount), + array('type' => 'other', 'name' => 'fk_disposal_type', 'tdclass' => 'fieldrequired', 'label' => $langs->trans("AssetDisposalType"), 'value' => $disposal_type_form), + array('type' => 'other', 'name' => 'disposal_invoice_id', 'label' => $langs->trans("InvoiceCustomer"), 'value' => $disposal_invoice_form), + array('type' => 'checkbox', 'name' => 'disposal_depreciated', 'label' => $langs->trans("AssetDisposalDepreciated"), 'value' => $disposal_depreciated), + 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); + } + // Re-open + elseif ($action == 'reopen') { + // 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); + } + // Clone confirmation +/* elseif ($action == 'clone') { + // Create an array for form + $formquestion = array(); + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ToClone'), $langs->trans('ConfirmCloneAsk', $object->ref), 'confirm_clone', $formquestion, 'yes', 1); + }*/ // Call Hook formConfirm - $parameters = array('formConfirm' => $formconfirm, 'lineid' => $lineid); + $parameters = array('formConfirm' => $formconfirm); $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook if (empty($reshook)) { $formconfirm .= $hookmanager->resPrint; @@ -250,24 +317,19 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea $linkback = ''.$langs->trans("BackToList").''; $morehtmlref = '
    '; - /* - // Ref bis - $morehtmlref.=$form->editfieldkey("RefBis", 'ref_client', $object->ref_client, $object, $user->rights->asset->creer, 'string', '', 0, 1); - $morehtmlref.=$form->editfieldval("RefBis", 'ref_client', $object->ref_client, $object, $user->rights->asset->creer, 'string', '', null, null, '', 1); - // Thirdparty - $morehtmlref.='
    '.$langs->trans('ThirdParty') . ' : ' . $soc->getNomUrl(1); - */ $morehtmlref .= '
    '; + dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref); + print '
    '; print '
    '; print '
    '; - print '
    '."\n"; + print '
    '."\n"; // Common attributes - //$keyforbreak='fieldkeytoswitchonsecondcolumn'; // We change column just after this field + $keyforbreak='date_acquisition'; // We change column just before this field //unset($object->fields['fk_project']); // Hide field already shown in banner //unset($object->fields['fk_soc']); // Hide field already shown in banner include DOL_DOCUMENT_ROOT.'/core/tpl/commonfields_view.tpl.php'; @@ -277,69 +339,100 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea print '
    '; print ''; + print ''; print '
    '; print dol_get_fiche_end(); - - /* - * Buttons - */ - if ($user->socid == 0) { - print '
    '; - + // Buttons for actions + if ($action != 'presend' && $action != 'editline') { + print '
    ' . "\n"; $parameters = array(); $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook + if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + } if (empty($reshook)) { - if ($user->rights->asset->write) { - print ''.$langs->trans("Modify").''."\n"; - } else { - print ''.$langs->trans('Modify').''."\n"; + // Send + if (empty($user->socid)) { + print dolGetButtonAction($langs->trans('SendMail'), '', 'default', $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=presend&mode=init&token=' . newToken() . '#formmailbeforetitle'); } - if ($user->rights->asset->delete) { - print ''.$langs->trans('Delete').''."\n"; - } else { - print ''.$langs->trans('Delete').''."\n"; + 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); + + if ($object->status == $object::STATUS_DRAFT) { + print dolGetButtonAction($langs->trans('AssetDisposal'), '', 'default', $_SERVER['PHP_SELF'] . '?id=' . $object->id . '&action=disposal&token=' . newToken(), '', $permissiontoadd); + } else { + print dolGetButtonAction($langs->trans('ReOpen'), '', 'default', $_SERVER['PHP_SELF'] . '?id=' . $object->id . '&action=reopen&token=' . newToken(), '', $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)); } - print "
    "; + print '
    ' . "\n"; + } + + // Select mail models is same action as presend + if (GETPOST('modelselected')) { + $action = 'presend'; } if ($action != 'presend') { print '
    '; print ''; // ancre - // Documents - $filename = dol_sanitizeFileName($object->ref); - $filedir = $conf->contrat->dir_output."/".dol_sanitizeFileName($object->ref); - $urlsource = $_SERVER["PHP_SELF"]."?id=".$object->id; - $genallowed = $user->rights->asset->read; // If you can read, you can build the PDF to read content - $delallowed = $user->rights->asset->write; // If you can create/edit, you can remove a file on card + $includedocgeneration = 0; - print $formfile->showdocuments('asset', $filename, $filedir, $urlsource, 0, $delallowed, $object->model_pdf, 1, 0, 0, 28, 0, '', '', '', $soc->default_lang); + // Documents + if ($includedocgeneration) { + $objref = dol_sanitizeFileName($object->ref); + $relativepath = $objref.'/'.$objref.'.pdf'; + $filedir = $conf->asset->dir_output.'/'.$objref; + $urlsource = $_SERVER["PHP_SELF"]."?id=".$object->id; + $genallowed = $user->rights->asset->read; // If you can read, you can build the PDF to read content + $delallowed = $user->rights->asset->write; // If you can create/edit, you can remove a file on card + print $formfile->showdocuments('asset:Asset', $objref, $filedir, $urlsource, $genallowed, $delallowed, $object->model_pdf, 1, 0, 0, 28, 0, '', '', '', $langs->defaultlang); + } // Show links to link elements $linktoelem = $form->showLinkToObjectBlock($object, null, array('asset')); $somethingshown = $form->showLinkedObjectBlock($object, $linktoelem); + print '
    '; $MAXEVENT = 10; - $morehtmlcenter = dolGetButtonTitle($langs->trans('SeeAll'), '', 'fa fa-list-alt imgforviewmode', DOL_URL_ROOT.'/asset/info.php?id='.$object->id); + $morehtmlcenter = dolGetButtonTitle($langs->trans('SeeAll'), '', 'fa fa-list-alt imgforviewmode', DOL_URL_ROOT.'/asset/agenda.php?id='.$object->id); // List of actions on element include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php'; $formactions = new FormActions($db); - $somethingshown = $formactions->showactions($object, $object->element, $socid, 1, '', $MAXEVENT, '', $morehtmlright); + $somethingshown = $formactions->showactions($object, $object->element, 0, 1, '', $MAXEVENT, '', $morehtmlright); print '
    '; } -} + //Select mail models is same action as presend + if (GETPOST('modelselected')) { + $action = 'presend'; + } + + // Presend form + $modelmail = 'asset'; + $defaulttopic = 'InformationMessage'; + $diroutput = $conf->asset->dir_output; + $trackid = 'asset'.$object->id; + + include DOL_DOCUMENT_ROOT.'/core/tpl/card_presend.tpl.php'; +} // End of page llxFooter(); diff --git a/htdocs/asset/class/asset.class.php b/htdocs/asset/class/asset.class.php index e5ec21bfa6d..76f50c136fd 100644 --- a/htdocs/asset/class/asset.class.php +++ b/htdocs/asset/class/asset.class.php @@ -1,6 +1,6 @@ - * Copyright (C) 2018 Alexandre Spangaro +/* Copyright (C) 2017 Laurent Destailleur + * Copyright (C) 2018 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 @@ -19,7 +19,7 @@ /** * \file asset/class/asset.class.php * \ingroup asset - * \brief This file is a CRUD class file for asset (Create/Read/Update/Delete) + * \brief This file is a CRUD class file for Asset (Create/Read/Update/Delete) */ require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php'; @@ -30,22 +30,28 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php'; class Asset extends CommonObject { /** - * @var string ID to identify managed object + * @var string ID of module. + */ + public $module = 'asset'; + + /** + * @var string ID to identify managed object. */ public $element = 'asset'; /** - * @var string Name of table without prefix where object is stored + * @var string Name of table without prefix where object is stored. This is also the key used for extrafields management. */ public $table_element = 'asset'; /** - * @var int Does module support multicompany module ? 0=No test on entity, 1=Test with field entity, 2=Test with link by societe + * @var int Does this object support multicompany module ? + * 0=No test on entity, 1=Test with field entity, 'field@table'=Test with link by field@table */ - public $ismultientitymanaged = 0; + public $ismultientitymanaged = 1; /** - * @var int Does asset support extrafields ? 0=No, 1=Yes + * @var int Does object support extrafields ? 0=No, 1=Yes */ public $isextrafieldmanaged = 1; @@ -54,111 +60,124 @@ class Asset extends CommonObject */ public $picto = 'asset'; - - const STATUS_DRAFT = 0; - const STATUS_VALIDATED = 1; - const STATUS_CANCELED = 9; - + const STATUS_DRAFT = 0; // In progress + const STATUS_DISPOSED = 9; // Disposed /** - * 'type' if the field format. + * 'type' field format ('integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter[:Sortfield]]]', 'sellist:TableName:LabelFieldName[:KeyFieldName[:KeyFieldParent[:Filter[:Sortfield]]]]', 'varchar(x)', 'double(24,8)', 'real', 'price', 'text', 'text:none', 'html', 'date', 'datetime', 'timestamp', 'duration', 'mail', 'phone', 'url', 'password') + * Note: Filter can be a string like "(t.ref:like:'SO-%') or (t.date_creation:<:'20160101') or (t.nature:is:NULL)" * 'label' the translation key. - * 'enabled' is a condition when the field must be managed. - * 'visible' says if field is visible in list (Examples: 0=Not visible, 1=Visible on list and create/update/view forms, 2=Visible on list only. Using a negative value means field is not shown by default on list but can be selected for viewing) + * 'picto' is code of a picto to show before value in forms + * 'enabled' is a condition when the field must be managed (Example: 1 or '$conf->global->MY_SETUP_PARAM) + * 'position' is the sort order of field. * 'notnull' is set to 1 if not null in database. Set to -1 if we must set data to null if empty ('' or 0). + * 'visible' says if field is visible in list (Examples: 0=Not visible, 1=Visible on list and create/update/view forms, 2=Visible on list only, 3=Visible on create/update/view form only (not list), 4=Visible on list and update/view form only (not create). 5=Visible on list and view only (not create/not update). Using a negative value means field is not shown by default on list but can be selected for viewing) + * 'noteditable' says if field is not editable (1 or 0) + * 'default' is a default value for creation (can still be overwrote by the Setup of Default Values if field is editable in creation form). Note: If default is set to '(PROV)' and field is 'ref', the default value will be set to '(PROVid)' where id is rowid when a new record is created. * 'index' if we want an index in database. * 'foreignkey'=>'tablename.field' if the field is a foreign key (it is recommanded to name the field fk_...). - * 'position' is the sort order of field. * 'searchall' is 1 if we want to search in this field when making a search from the quick search button. - * 'isameasure' must be set to 1 if you want to have a total on list for this field. Field type must be summable like integer or double(24,8). - * 'help' is a string visible as a tooltip on field + * 'isameasure' must be set to 1 or 2 if field can be used for measure. Field type must be summable like integer or double(24,8). Use 1 in most cases, or 2 if you don't want to see the column total into list (for example for percentage) + * 'css' and 'cssview' and 'csslist' is the CSS style to use on field. 'css' is used in creation and update. 'cssview' is used in view mode. 'csslist' is used for columns in lists. For example: 'css'=>'minwidth300 maxwidth500 widthcentpercentminusx', 'cssview'=>'wordbreak', 'csslist'=>'tdoverflowmax200' + * 'help' is a 'TranslationString' to use to show a tooltip on field. You can also use 'TranslationString:keyfortooltiponlick' for a tooltip on click. + * 'showoncombobox' if value of the field must be visible into the label of the combobox that list record + * 'disabled' is 1 if we want to have the field locked by a 'disabled' attribute. In most cases, this is never set into the definition of $fields into class, but is set dynamically by some part of code. + * 'arrayofkeyval' to set a list of values if type is a list of predefined values. For example: array("0"=>"Draft","1"=>"Active","-1"=>"Cancel"). Note that type can be 'integer' or 'varchar' + * 'autofocusoncreate' to have field having the focus on a create form. Only 1 field should have this property set to 1. * 'comment' is not used. You can store here any text of your choice. It is not used by application. - * 'default' is a default value for creation (can still be replaced by the global setup of default values) - * 'showoncombobox' if field must be shown into the label of combobox + * 'validate' is 1 if need to validate with $this->validateField() + * 'copytoclipboard' is 1 or 2 to allow to add a picto to copy value into clipboard (1=picto after label, 2=picto after value) + * + * Note: To have value dynamic, you can set value to 0 in definition and edit the value on the fly into the constructor. */ /** * @var array Array with all fields and their property. Do not use it as a static var. It may be modified by constructor. */ - public $fields = array( - 'rowid' => array('type'=>'integer', 'label'=>'TechnicalID', 'visible'=>-1, 'enabled'=>1, 'position'=>1, 'notnull'=>1, 'index'=>1, 'comment'=>"Id",), - 'ref' => array('type'=>'varchar(10)', 'label'=>'Ref', 'visible'=>1, 'enabled'=>1, 'position'=>10, 'notnull'=>1, 'index'=>1, 'searchall'=>1, 'comment'=>"Reference of object", 'showoncombobox'=>1), - 'entity' => array('type'=>'integer', 'label'=>'Entity', 'visible'=>0, 'enabled'=>1, 'position'=>20, 'notnull'=>1, 'index'=>1,), - 'label' => array('type'=>'varchar(255)', 'label'=>'Label', 'visible'=>1, 'enabled'=>1, 'position'=>30, 'notnull'=>-1, 'searchall'=>1), - 'fk_asset_type' => array('type'=>'integer:AssetType:asset/class/asset_type.class.php', 'label'=>'AssetsType', 'visible'=>1, 'enabled'=>1, 'position'=>35, 'notnull'=>1, 'index'=>1, 'searchall'=>1), - 'amount_ht' => array('type'=>'double(24,8)', 'label'=>'AmountHTShort', 'visible'=>1, 'enabled'=>1, 'position'=>40, 'notnull'=>-1, 'isameasure'=>'1', 'help'=>"Help text",), - 'amount_vat' => array('type'=>'double(24,8)', 'label'=>'AmountVAT', 'visible'=>1, 'enabled'=>1, 'position'=>41, 'notnull'=>-1, 'isameasure'=>'1', 'help'=>"Help text",), - 'description' => array('type'=>'text', 'label'=>'Description', 'visible'=>-1, 'enabled'=>1, 'position'=>90, 'notnull'=>-1,), - 'note_public' => array('type'=>'html', 'label'=>'NotePublic', 'visible'=>-1, 'enabled'=>1, 'position'=>91, 'notnull'=>-1,), - 'note_private' => array('type'=>'html', 'label'=>'NotePrivate', 'visible'=>-1, 'enabled'=>1, 'position'=>92, 'notnull'=>-1,), - 'date_creation' => array('type'=>'datetime', 'label'=>'DateCreation', 'visible'=>-2, 'enabled'=>1, 'position'=>500, 'notnull'=>1,), - 'tms' => array('type'=>'timestamp', 'label'=>'DateModification', 'visible'=>-2, 'enabled'=>1, 'position'=>501, 'notnull'=>1,), - 'fk_user_creat' => array('type'=>'integer', 'label'=>'UserAuthor', 'visible'=>-2, 'enabled'=>1, 'position'=>510, 'notnull'=>1,), - 'fk_user_modif' => array('type'=>'integer', 'label'=>'UserModif', 'visible'=>-2, 'enabled'=>1, 'position'=>511, 'notnull'=>-1,), - 'import_key' => array('type'=>'varchar(14)', 'label'=>'ImportId', 'visible'=>-2, 'enabled'=>1, 'position'=>1000, 'notnull'=>-1,), - 'status' => array('type'=>'integer', 'label'=>'Status', 'visible'=>1, 'enabled'=>1, 'position'=>1000, 'notnull'=>1, 'index'=>1, 'arrayofkeyval'=>array('0'=>'Draft', '1'=>'Active', '9'=>'Cancel')), + 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"), + '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',), + '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',), + 'qty' => array('type'=>'real', 'label'=>'Qty', 'enabled'=>'1', 'position'=>50, 'notnull'=>1, 'visible'=>0, 'default'=>'1', 'isameasure'=>'1', 'css'=>'maxwidth75imp', 'validate'=>'1',), + 'acquisition_type' => array('type'=>'smallint', 'label'=>'AssetAcquisitionType', 'enabled'=>'1', 'position'=>60, 'notnull'=>1, 'visible'=>1, 'arrayofkeyval'=>array('0'=>'AssetAcquisitionTypeNew', '1'=>'AssetAcquisitionTypeOccasion'), 'validate'=>'1',), + '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',), + 'not_depreciated' => array('type'=>'boolean', 'label'=>'AssetNotDepreciated', 'enabled'=>'1', 'position'=>80, 'notnull'=>0, 'default'=>'0', 'visible'=>1, 'validate'=>'1',), + 'date_acquisition' => array('type'=>'date', 'label'=>'AssetDateAcquisition', 'enabled'=>'1', 'position'=>90, 'notnull'=>1, 'visible'=>1,), + 'date_start' => array('type'=>'date', 'label'=>'AssetDateStart', 'enabled'=>'1', 'position'=>100, 'notnull'=>0, 'visible'=>-1,), + 'acquisition_value_ht' => array('type'=>'price', 'label'=>'AssetAcquisitionValueHT', 'enabled'=>'1', 'position'=>110, 'notnull'=>1, 'visible'=>1, 'isameasure'=>'1', 'validate'=>'1',), + 'recovered_vat' => array('type'=>'price', 'label'=>'AssetRecoveredVAT', 'enabled'=>'1', 'position'=>120, 'notnull'=>0, 'visible'=>1, 'isameasure'=>'1', 'validate'=>'1',), + 'reversal_date' => array('type'=>'date', 'label'=>'AssetReversalDate', 'enabled'=>'1', 'position'=>130, 'notnull'=>0, 'visible'=>1,), + 'reversal_amount_ht' => array('type'=>'price', 'label'=>'AssetReversalAmountHT', 'enabled'=>'1', 'position'=>140, 'notnull'=>0, 'visible'=>1, 'isameasure'=>'1', 'validate'=>'1',), + 'disposal_date' => array('type'=>'date', 'label'=>'AssetDisposalDate', 'enabled'=>'1', 'position'=>200, 'notnull'=>0, 'visible'=>-2,), + 'disposal_amount_ht' => array('type'=>'price', 'label'=>'AssetDisposalAmount', 'enabled'=>'1', 'position'=>210, 'notnull'=>0, 'visible'=>-2, 'default'=>'0', 'isameasure'=>'1', 'validate'=>'1',), + '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',), + 'disposal_depreciated' => array('type'=>'boolean', 'label'=>'AssetDisposalDepreciated', 'enabled'=>'1', 'position'=>230, 'notnull'=>0, 'default'=>'0', 'visible'=>-2, 'validate'=>'1',), + 'disposal_subject_to_vat' => array('type'=>'boolean', 'label'=>'AssetDisposalSubjectToVat', 'enabled'=>'1', 'position'=>240, 'notnull'=>0, 'default'=>'0', 'visible'=>-2, 'validate'=>'1',), + 'note_public' => array('type'=>'html', 'label'=>'NotePublic', 'enabled'=>'1', 'position'=>300, 'notnull'=>0, 'visible'=>0, 'validate'=>'1',), + '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,), + '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,), + '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,), + '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',), ); - - /** - * @var int ID - */ public $rowid; - - /** - * @var string Ref - */ public $ref; - - /** - * @var int Entity - */ - public $entity; - - /** - * @var string Asset label - */ public $label; - - public $amount; - - /** - * @var int Thirdparty ID - */ - public $fk_soc; - - /** - * @var string description - */ - public $description; - - /** - * @var integer|string date_creation - */ + public $fk_asset_model; + public $reversal_amount_ht; + public $acquisition_value_ht; + public $recovered_vat; + public $reversal_date; + public $date_acquisition; + public $date_start; + public $qty; + public $acquisition_type; + public $asset_type; + public $not_depreciated; + public $disposal_date; + public $disposal_amount_ht; + public $fk_disposal_type; + public $disposal_depreciated; + public $disposal_subject_to_vat; + public $note_public; + public $note_private; public $date_creation; - - public $tms; - - /** - * @var int ID - */ public $fk_user_creat; - - /** - * @var int ID - */ public $fk_user_modif; - - /** - * @var string import key - */ + public $last_main_doc; public $import_key; - - /** - * @var int Status - */ + public $model_pdf; public $status; + // /** + // * @var string Field with ID of parent key if this object has a parent + // */ + // public $fk_element = 'fk_asset'; + // /** + // * @var array List of child tables. To test if we can delete object. + // */ + // protected $childtables = array(); + // /** + // * @var array List of child tables. To know object to delete on cascade. + // * If name matches '@ClassNAme:FilePathClass;ParentFkFieldName' it will + // * call method deleteByParentField(parentId, ParentFkFieldName) to fetch and delete child object + // */ + // protected $childtablesoncascade = array('asset_assetdet'); + + /** + * @var AssetDepreciationOptions Used for computed fields of depreciation options class. + */ + public $asset_depreciation_options; + /** + * @var array List of depreciation lines for each mode (sort by depreciation date). + */ + public $depreciation_lines = array(); /** * Constructor @@ -167,16 +186,34 @@ class Asset extends CommonObject */ public function __construct(DoliDB $db) { - global $conf; + global $conf, $langs; $this->db = $db; - if (empty($conf->global->MAIN_SHOW_TECHNICAL_ID)) { + if (empty($conf->global->MAIN_SHOW_TECHNICAL_ID) && isset($this->fields['rowid'])) { $this->fields['rowid']['visible'] = 0; } - if (empty($conf->multicompany->enabled)) { + if (empty($conf->multicompany->enabled) && isset($this->fields['entity'])) { $this->fields['entity']['enabled'] = 0; } + + // Unset fields that are disabled + foreach ($this->fields as $key => $val) { + if (isset($val['enabled']) && empty($val['enabled'])) { + unset($this->fields[$key]); + } + } + + // Translate some data of arrayofkeyval + if (is_object($langs)) { + foreach ($this->fields as $key => $val) { + if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) { + foreach ($val['arrayofkeyval'] as $key2 => $val2) { + $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2); + } + } + } + } } /** @@ -188,11 +225,27 @@ class Asset extends CommonObject */ public function create(User $user, $notrigger = false) { - return $this->createCommon($user, $notrigger); + if (!isset($this->date_start) || $this->date_start === "") $this->date_start = $this->date_acquisition; + + $this->db->begin(); + + $result = $result_create = $this->createCommon($user, $notrigger); + if ($result > 0 && $this->fk_asset_model > 0) $result = $this->setDataFromAssetModel($user, $notrigger); + if ($result > 0) { + if ($this->supplier_invoice_id > 0) $this->add_object_linked('invoice_supplier', $this->supplier_invoice_id); + } + + if ($result < 0) { + $this->db->rollback(); + } else { + $this->db->commit(); + } + + return $result > 0 ? $result_create : $result; } /** - * Clone and object into another one + * Clone an object into another one * * @param User $user User that creates * @param int $fromid Id of object to clone @@ -200,45 +253,95 @@ class Asset extends CommonObject */ public function createFromClone(User $user, $fromid) { - global $hookmanager, $langs; + global $langs, $extrafields; $error = 0; dol_syslog(__METHOD__, LOG_DEBUG); - $object = new self($this->db); - - $this->db->begin(); - - // Load source object - $object->fetchCommon($fromid); - // Reset some properties - unset($object->id); - unset($object->fk_user_creat); - unset($object->import_key); - - // Clear fields - $object->ref = "copy_of_".$object->ref; - $object->title = $langs->trans("CopyOf")." ".$object->title; - - // Create clone - $object->context['createfromclone'] = 'createfromclone'; - $result = $object->createCommon($user); - if ($result < 0) { - $error++; - $this->error = $object->error; - $this->errors = $object->errors; - } - - unset($object->context['createfromclone']); - - // End - if (!$error) { - $this->db->commit(); - return $object; - } else { - $this->db->rollback(); - return -1; - } +// $object = new self($this->db); +// +// $this->db->begin(); +// +// // Load source object +// $result = $object->fetchCommon($fromid); +// if ($result > 0 && !empty($object->table_element_line)) { +// $object->fetchLines(); +// } +// +// // get lines so they will be clone +// //foreach($this->lines as $line) +// // $line->fetch_optionals(); +// +// // Reset some properties +// unset($object->id); +// unset($object->fk_user_creat); +// unset($object->import_key); +// +// // Clear fields +// if (property_exists($object, 'ref')) { +// $object->ref = empty($this->fields['ref']['default']) ? "Copy_Of_".$object->ref : $this->fields['ref']['default']; +// } +// if (property_exists($object, 'label')) { +// $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf")." ".$object->label : $this->fields['label']['default']; +// } +// if (property_exists($object, 'status')) { +// $object->status = self::STATUS_DRAFT; +// } +// if (property_exists($object, 'date_creation')) { +// $object->date_creation = dol_now(); +// } +// if (property_exists($object, 'date_modification')) { +// $object->date_modification = null; +// } +// // ... +// // Clear extrafields that are unique +// if (is_array($object->array_options) && count($object->array_options) > 0) { +// $extrafields->fetch_name_optionals_label($this->table_element); +// foreach ($object->array_options as $key => $option) { +// $shortkey = preg_replace('/options_/', '', $key); +// if (!empty($extrafields->attributes[$this->table_element]['unique'][$shortkey])) { +// //var_dump($key); var_dump($clonedObj->array_options[$key]); exit; +// unset($object->array_options[$key]); +// } +// } +// } +// +// // Create clone +// $object->context['createfromclone'] = 'createfromclone'; +// $result = $object->createCommon($user); +// if ($result < 0) { +// $error++; +// $this->error = $object->error; +// $this->errors = $object->errors; +// } +// +// if (!$error) { +// // copy internal contacts +// if ($this->copy_linked_contact($object, 'internal') < 0) { +// $error++; +// } +// } +// +// if (!$error) { +// // copy external contacts if same company +// if (property_exists($this, 'fk_soc') && $this->fk_soc == $object->socid) { +// if ($this->copy_linked_contact($object, 'external') < 0) { +// $error++; +// } +// } +// } +// +// unset($object->context['createfromclone']); +// +// // End +// if (!$error) { +// $this->db->commit(); +// return $object; +// } else { +// $this->db->rollback(); +// return -1; +// } + return -1; } /** @@ -251,7 +354,21 @@ class Asset extends CommonObject public function fetch($id, $ref = null) { $result = $this->fetchCommon($id, $ref); - //if ($result > 0 && ! empty($this->table_element_line)) $this->fetchLines(); + if ($result > 0) { + if (!empty($this->table_element_line)) $this->fetchLines(); + + $res = $this->hasDepreciationLinesInBookkeeping(); + if ($res < 0) { + return -1; + } elseif ($res > 0) { + $this->fields['date_acquisition']['noteditable'] = '1'; + $this->fields['date_start']['noteditable'] = '1'; + $this->fields['acquisition_value_ht']['noteditable'] = '1'; + $this->fields['recovered_vat']['noteditable'] = '1'; + $this->fields['reversal_date']['noteditable'] = '1'; + $this->fields['reversal_amount_ht']['noteditable'] = '1'; + } + } return $result; } @@ -260,14 +377,93 @@ class Asset extends CommonObject * * @return int <0 if KO, 0 if not found, >0 if OK */ - /*public function fetchLines() + public function fetchLines() { - $this->lines=array(); + $this->lines = array(); - // Load lines with object AssetsLine + return 1; + } - return count($this->lines)?1:0; - }*/ + + /** + * Load list of objects in memory from the database. + * + * @param string $sortorder Sort Order + * @param string $sortfield Sort field + * @param int $limit limit + * @param int $offset Offset + * @param array $filter Filter array. Example array('field'=>'valueforlike', 'customurl'=>...) + * @param string $filtermode Filter mode (AND or OR) + * @return array|int int <0 if KO, array of pages if OK + */ + public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND') + { + global $conf; + + dol_syslog(__METHOD__, LOG_DEBUG); + + $records = array(); + + $sql = "SELECT "; + $sql .= $this->getFieldList('t'); + $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as t"; + if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) { + $sql .= " WHERE t.entity IN (".getEntity($this->table_element).")"; + } else { + $sql .= " WHERE 1 = 1"; + } + // Manage filter + $sqlwhere = array(); + if (count($filter) > 0) { + foreach ($filter as $key => $value) { + if ($key == 't.rowid') { + $sqlwhere[] = $key." = ".((int) $value); + } elseif (in_array($this->fields[$key]['type'], array('date', 'datetime', 'timestamp'))) { + $sqlwhere[] = $key." = '".$this->db->idate($value)."'"; + } elseif ($key == 'customsql') { + $sqlwhere[] = $value; + } elseif (strpos($value, '%') === false) { + $sqlwhere[] = $key." IN (".$this->db->sanitize($this->db->escape($value)).")"; + } else { + $sqlwhere[] = $key." LIKE '%".$this->db->escape($value)."%'"; + } + } + } + if (count($sqlwhere) > 0) { + $sql .= " AND (".implode(" ".$filtermode." ", $sqlwhere).")"; + } + + if (!empty($sortfield)) { + $sql .= $this->db->order($sortfield, $sortorder); + } + if (!empty($limit)) { + $sql .= $this->db->plimit($limit, $offset); + } + + $resql = $this->db->query($sql); + if ($resql) { + $num = $this->db->num_rows($resql); + $i = 0; + while ($i < ($limit ? min($limit, $num) : $num)) { + $obj = $this->db->fetch_object($resql); + + $record = new self($this->db); + $record->setVarsFromFetchObj($obj); + + $records[$record->id] = $record; + + $i++; + } + $this->db->free($resql); + + return $records; + } else { + $this->errors[] = 'Error '.$this->db->lasterror(); + dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR); + + return -1; + } + } /** * Update object into database @@ -278,7 +474,32 @@ class Asset extends CommonObject */ public function update(User $user, $notrigger = false) { - return $this->updateCommon($user, $notrigger); + if (!isset($this->date_start) || $this->date_start === "") $this->date_start = $this->date_acquisition; + + $this->db->begin(); + + $result = $this->updateCommon($user, $notrigger); + if ($result > 0 && $this->fk_asset_model > 0 && $this->fk_asset_model != $this->oldcopy->fk_asset_model) { + $result = $this->setDataFromAssetModel($user, $notrigger); + } + if ($result > 0 && ( + $this->date_start != $this->oldcopy->date_start || + $this->acquisition_value_ht != $this->oldcopy->acquisition_value_ht || + $this->reversal_date != $this->oldcopy->reversal_date || + $this->reversal_amount_ht != $this->oldcopy->reversal_amount_ht || + ($this->fk_asset_model > 0 && $this->fk_asset_model != $this->oldcopy->fk_asset_model) + ) + ) { + $result = $this->calculationDepreciation(); + } + + if ($result < 0) { + $this->db->rollback(); + } else { + $this->db->commit(); + } + + return $result; } /** @@ -291,23 +512,760 @@ class Asset extends CommonObject public function delete(User $user, $notrigger = false) { return $this->deleteCommon($user, $notrigger); + //return $this->deleteCommon($user, $notrigger, 1); + } + + /** + * Set asset model + * + * @param User $user User that creates + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @return int <0 if KO, Id of created object if OK + */ + public function setDataFromAssetModel(User $user, $notrigger = false) + { + global $langs; + $langs->load('assets'); + + // Clean parameters + $this->id = $this->id > 0 ? $this->id : 0; + $this->fk_asset_model = $this->fk_asset_model > 0 ? $this->fk_asset_model : 0; + + // Check parameters + $error = 0; + if (empty($this->id)) { + $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Asset") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')'); + $error++; + } + if (empty($this->fk_asset_model)) { + $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("AssetModel") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')'); + $error++; + } + if ($error) { + return -1; + } + + $this->db->begin(); + + // Get depreciation options + //--------------------------- + require_once DOL_DOCUMENT_ROOT . '/asset/class/assetdepreciationoptions.class.php'; + $options_model = new AssetDepreciationOptions($this->db); + $result = $options_model->fetchDeprecationOptions(0, $this->fk_asset_model); + if ($result < 0) { + $this->error = $options_model->error; + $this->errors = $options_model->errors; + $error++; + } elseif ($result > 0) { + $options = new AssetDepreciationOptions($this->db); + $result = $options->fetchDeprecationOptions($this->id); + if ($result < 0) { + $this->error = $options->error; + $this->errors = $options->errors; + $error++; + } + + if (!$error) { + foreach ($options_model->deprecation_options as $mode_key => $fields) { + foreach ($fields as $field_key => $value) { + $options->deprecation_options[$mode_key][$field_key] = $value; + } + } + + $result = $options->updateDeprecationOptions($user, $this->id, 0, $notrigger); + if ($result < 0) { + $this->error = $options->error; + $this->errors = $options->errors; + $error++; + } + } + } + + // Get accountancy codes + //--------------------------- + if (!$error) { + require_once DOL_DOCUMENT_ROOT . '/asset/class/assetaccountancycodes.class.php'; + $accountancy_codes_model = new AssetAccountancyCodes($this->db); + $result = $accountancy_codes_model->fetchAccountancyCodes(0, $this->fk_asset_model); + if ($result < 0) { + $this->error = $accountancy_codes_model->error; + $this->errors = $accountancy_codes_model->errors; + $error++; + } elseif ($result > 0) { + $accountancy_codes = new AssetAccountancyCodes($this->db); + $result = $accountancy_codes->fetchAccountancyCodes($this->id); + if ($result < 0) { + $this->error = $accountancy_codes->error; + $this->errors = $accountancy_codes->errors; + $error++; + } + + if (!$error) { + foreach ($accountancy_codes_model->accountancy_codes as $mode_key => $fields) { + foreach ($fields as $field_key => $value) { + $accountancy_codes->accountancy_codes[$mode_key][$field_key] = $value; + } + } + + $result = $accountancy_codes->updateAccountancyCodes($user, $this->id, 0, $notrigger); + if ($result < 0) { + $this->error = $accountancy_codes->error; + $this->errors = $accountancy_codes->errors; + $error++; + } + } + } + } + + if ($error) { + $this->db->rollback(); + return -1; + } else { + $this->db->commit(); + return 1; + } + } + + /** + * Fetch depreciation lines for each mode in $this->depreciation_lines (sort by depreciation date) + * + * @return int <0 if KO, Id of created object if OK + */ + public function fetchDepreciationLines() + { + global $langs; + $langs->load('assets'); + $this->depreciation_lines = array(); + + // Clean parameters + $this->id = $this->id > 0 ? $this->id : 0; + + // Check parameters + $error = 0; + if (empty($this->id)) { + $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Asset") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')'); + $error++; + } + if ($error) { + return -1; + } + + $sql = "WITH in_accounting_bookkeeping(fk_docdet) AS ("; + $sql .= " SELECT DISTINCT fk_docdet"; + $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping"; + $sql .= " WHERE doc_type = 'asset'"; + $sql .= ")"; + $sql .= "SELECT ad.rowid, ad.depreciation_mode, ad.ref, ad.depreciation_date, ad.depreciation_ht, ad.cumulative_depreciation_ht"; + $sql .= ", " . $this->db->ifsql('iab.fk_docdet IS NOT NULL', 1 , 0) . " AS bookkeeping"; + $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad"; + $sql .= " LEFT JOIN in_accounting_bookkeeping as iab ON iab.fk_docdet = ad.rowid"; + $sql .= " WHERE ad.fk_asset = " . $this->id; + $sql .= " ORDER BY ad.depreciation_date ASC"; + + $resql = $this->db->query($sql); + if (!$resql) { + $this->errors[] = $langs->trans('AssetErrorFetchDepreciationLines') . ': ' . $this->db->lasterror(); + return -1; + } + + while ($obj = $this->db->fetch_object($resql)) { + if (!isset($this->depreciation_lines[$obj->depreciation_mode])) $this->depreciation_lines[$obj->depreciation_mode] = array(); + $this->depreciation_lines[$obj->depreciation_mode][] = array( + 'id' => $obj->rowid, + 'ref' => $obj->ref, + 'depreciation_date' => $this->db->jdate($obj->depreciation_date), + 'depreciation_ht' => $obj->depreciation_ht, + 'cumulative_depreciation_ht' => $obj->cumulative_depreciation_ht, + 'bookkeeping' => $obj->bookkeeping, + ); + } + + return 1; + } + + /** + * If has depreciation lines in bookkeeping + * + * @return int <0 if KO, 0 if NO, 1 if Yes + */ + public function hasDepreciationLinesInBookkeeping() + { + global $langs; + $langs->load('assets'); + + // Clean parameters + $this->id = $this->id > 0 ? $this->id : 0; + + // Check parameters + $error = 0; + if (empty($this->id)) { + $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Asset") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')'); + $error++; + } + if ($error) { + return -1; + } + + $sql = "WITH in_accounting_bookkeeping(fk_docdet) AS ("; + $sql .= " SELECT DISTINCT fk_docdet"; + $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping"; + $sql .= " WHERE doc_type = 'asset'"; + $sql .= ")"; + $sql .= "SELECT COUNT(*) AS has_bookkeeping"; + $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad"; + $sql .= " LEFT JOIN in_accounting_bookkeeping as iab ON iab.fk_docdet = ad.rowid"; + $sql .= " WHERE ad.fk_asset = " . $this->id; + $sql .= " AND iab.fk_docdet IS NOT NULL"; + + $resql = $this->db->query($sql); + if (!$resql) { + $this->errors[] = $langs->trans('AssetErrorFetchDepreciationLines') . ': ' . $this->db->lasterror(); + return -1; + } + + if ($obj = $this->db->fetch_object($resql)) { + return $obj->has_bookkeeping > 0 ? 1 : 0; + } + + return 0; + } + + /** + * Add depreciation line for a mode + * + * @param string $mode Depreciation mode (economic, accelerated_depreciation, ...) + * @param string $ref Ref line + * @param int $depreciation_date Depreciation date + * @param double $depreciation_ht Depreciation amount HT + * @param double $cumulative_depreciation_ht Depreciation cumulative amount HT + * @param string $accountancy_code_debit Accountancy code Debit + * @param string $accountancy_code_credit Accountancy code Credit + * @return int <0 if KO, Id of created line if OK + */ + public function addDepreciationLine($mode, $ref, $depreciation_date, $depreciation_ht, $cumulative_depreciation_ht, $accountancy_code_debit, $accountancy_code_credit) + { + global $langs; + $langs->load('assets'); + + // Clean parameters + $this->id = $this->id > 0 ? $this->id : 0; + $mode = strtolower(trim($mode)); + $ref = trim($ref); + $accountancy_code_debit = trim($accountancy_code_debit); + $accountancy_code_credit = trim($accountancy_code_credit); + + // Check parameters + $error = 0; + if (empty($this->id)) { + $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Asset") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')'); + $error++; + } + if ($error) { + return -1; + } + + $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)"; + $sql .= " VALUES ( "; + $sql .= " " . (int)$this->id; + $sql .= ", '" . $this->db->escape($mode) . "'"; + $sql .= ", '" . $this->db->escape($ref) . "'"; + $sql .= ", '" . $this->db->idate($depreciation_date) . "'"; + $sql .= ", " . (double)$depreciation_ht; + $sql .= ", " . (double)$cumulative_depreciation_ht; + $sql .= ", '" . $this->db->escape($accountancy_code_debit) . "'"; + $sql .= ", '" . $this->db->escape($accountancy_code_credit) . "'"; + $sql .= ")"; + + $resql = $this->db->query($sql); + if (!$resql) { + $this->errors[] = $langs->trans('AssetErrorAddDepreciationLine') . ': ' . $this->db->lasterror(); + return -1; + } + + return 1; + } + + /** + * Calculation depreciation lines (reversal and future) for each mode + * + * @return int <0 if KO, Id of created object if OK + */ + public function calculationDepreciation() + { + global $conf, $langs; + $langs->load('assets'); + + // Clean parameters + $this->id = $this->id > 0 ? $this->id : 0; + + // Check parameters + $error = 0; + if (empty($this->id)) { + $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Asset") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')'); + $error++; + } + if ($error) { + return -1; + } + + // Get depreciation options + //--------------------------- + require_once DOL_DOCUMENT_ROOT . '/asset/class/assetdepreciationoptions.class.php'; + $options = new AssetDepreciationOptions($this->db); + $result = $options->fetchDeprecationOptions($this->id); + if ($result < 0) { + $this->error = $options->error; + $this->errors = $options->errors; + return -1; + } + + // Get accountancy codes + //--------------------------- + require_once DOL_DOCUMENT_ROOT . '/asset/class/assetaccountancycodes.class.php'; + $accountancy_codes = new AssetAccountancyCodes($this->db); + $result = $accountancy_codes->fetchAccountancyCodes($this->id); + if ($result < 0) { + $this->error = $accountancy_codes->error; + $this->errors = $accountancy_codes->errors; + return -1; + } + + $this->db->begin(); + + // Delete old lines + $modes = array(); + foreach ($options->deprecation_options as $mode_key => $fields) { + $modes[$mode_key] = $this->db->escape($mode_key); + } + $sql = "DELETE FROM " . MAIN_DB_PREFIX . "asset_depreciation"; + $sql .= " WHERE fk_asset = " . $this->id; + $sql .= " AND depreciation_mode NOT IN ('" . implode("', '", $modes) . "')"; + + $resql = $this->db->query($sql); + if (!$resql) { + $this->errors[] = $langs->trans('AssetErrorClearDepreciationLines') . ': ' . $this->db->lasterror(); + $error++; + } + + if (!$error) { + // Get fiscal period + require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php'; + require_once DOL_DOCUMENT_ROOT . '/core/lib/accounting.lib.php'; + $dates = getDefaultDatesForTransfer(); + $init_fiscal_period_start = $dates['date_start']; + $init_fiscal_period_end = $dates['date_end']; + if (empty($init_fiscal_period_start) || empty($init_fiscal_period_end)) { + $pastmonthyear = $dates['pastmonthyear']; + $pastmonth = $dates['pastmonth']; + $init_fiscal_period_start = dol_get_first_day($pastmonthyear, $pastmonth, false); + $init_fiscal_period_end = dol_get_last_day($pastmonthyear, $pastmonth, false); + } + + foreach ($options->deprecation_options as $mode_key => $fields) { + // Get last depreciation lines save in bookkeeping + //----------------------------------------------------- + $sql = "WITH in_accounting_bookkeeping(fk_docdet) AS ("; + $sql .= " SELECT fk_docdet"; + $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping"; + $sql .= " WHERE doc_type = 'asset'"; + $sql .= ")"; + $sql .= "SELECT ad.depreciation_date, ad.cumulative_depreciation_ht"; + $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad"; + $sql .= " LEFT JOIN in_accounting_bookkeeping as iab ON iab.fk_docdet = ad.rowid"; + $sql .= " WHERE ad.fk_asset = " . $this->id; + $sql .= " AND ad.depreciation_mode = '" . $this->db->escape($mode_key) . "'"; + $sql .= " AND iab.fk_docdet IS NOT NULL"; + $sql .= " ORDER BY ad.depreciation_date DESC"; + $sql .= " LIMIT 1"; + $resql = $this->db->query($sql); + if (!$resql) { + $this->errors[] = $langs->trans('AssetErrorFetchMaxDepreciationDateForMode', $mode_key) . ': ' . $this->db->lasterror(); + $error++; + break; + } + $last_depreciation_date = ''; + $last_cumulative_depreciation_ht = $this->reversal_amount_ht; + if ($obj = $this->db->fetch_object($resql)) { + $last_depreciation_date = $this->db->jdate($obj->depreciation_date); + $last_cumulative_depreciation_ht = $obj->cumulative_depreciation_ht; + } + + // Set last cumulative depreciation + $sql = "UPDATE " . MAIN_DB_PREFIX . $options->deprecation_options_fields[$mode_key]['table']; + $sql .= " SET total_amount_last_depreciation_ht = " . (empty($last_cumulative_depreciation_ht) ? 0 : $last_cumulative_depreciation_ht); + $sql .= " WHERE fk_asset = " . $this->id; + $resql = $this->db->query($sql); + if (!$resql) { + $this->errors[] = $langs->trans('AssetErrorSetLastCumulativeDepreciation') . ': ' . $this->db->lasterror(); + $error++; + break; + } + + // Delete old lines + $sql = "DELETE " . MAIN_DB_PREFIX . "asset_depreciation FROM " . MAIN_DB_PREFIX . "asset_depreciation"; + $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"; + $sql .= " WHERE " . MAIN_DB_PREFIX . "asset_depreciation.fk_asset = " . $this->id; + $sql .= " AND " . MAIN_DB_PREFIX . "asset_depreciation.depreciation_mode = '" . $this->db->escape($mode_key) . "'"; + $sql .= " AND ab.fk_docdet IS NULL"; + if ($last_depreciation_date !== "") $sql .= " AND " . MAIN_DB_PREFIX . "asset_depreciation.ref != ''"; + $resql = $this->db->query($sql); + if (!$resql) { + $this->errors[] = $langs->trans('AssetErrorClearDepreciationLines') . ': ' . $this->db->lasterror(); + $error++; + break; + } + + // Get depreciation period + $depreciation_date_start = $this->date_start > $this->date_acquisition ? $this->date_start : $this->date_acquisition; + $depreciation_date_end = dol_time_plus_duree($depreciation_date_start, $fields['duration'], $fields['duration_type'] == 1 ? 'm' : ($fields['duration_type'] == 2 ? 'd' : 'y')); + $depreciation_amount = $fields['amount_base_depreciation_ht']; + if ($fields['duration_type'] == 2) { // Daily + $fiscal_period_start = $depreciation_date_start; + $fiscal_period_end = $depreciation_date_start; + } elseif ($fields['duration_type'] == 1) { // Monthly + $date_temp = dol_getdate($depreciation_date_start); + $fiscal_period_start = dol_get_first_day($date_temp['year'], $date_temp['mon'], false); + $fiscal_period_end = dol_get_last_day($date_temp['year'], $date_temp['mon'], false); + } else { // Annually + $fiscal_period_start = $init_fiscal_period_start; + $fiscal_period_end = $init_fiscal_period_end; + } + $cumulative_depreciation_ht = $last_cumulative_depreciation_ht; + $depreciation_period_amount = $depreciation_amount - $this->reversal_amount_ht; + $start_date = $depreciation_date_start; + $disposal_date = isset($this->disposal_date) && $this->disposal_date !== "" ? $this->disposal_date : ""; + $finish_date = $disposal_date !== "" ? $disposal_date : $depreciation_date_end; + $accountancy_code_depreciation_debit_key = $accountancy_codes->accountancy_codes_fields[$mode_key]['depreciation_debit']; + $accountancy_code_depreciation_debit = $accountancy_codes->accountancy_codes[$mode_key][$accountancy_code_depreciation_debit_key]; + $accountancy_code_depreciation_credit_key = $accountancy_codes->accountancy_codes_fields[$mode_key]['depreciation_credit']; + $accountancy_code_credit = $accountancy_codes->accountancy_codes[$mode_key][$accountancy_code_depreciation_credit_key]; + + // Reversal depreciation line + //----------------------------------------------------- + if ($last_depreciation_date === "" && ($depreciation_date_start < $fiscal_period_start || is_numeric($this->reversal_date))) { + if (is_numeric($this->reversal_date)) { + if ($this->reversal_date < $fiscal_period_start) { + $this->errors[] = $langs->trans('AssetErrorReversalDateNotGreaterThanCurrentBeginFiscalDateForMode', $mode_key); + $error++; + break; + } + + if (empty($this->reversal_amount_ht)) { + $this->errors[] = $langs->trans('AssetErrorReversalAmountNotProvidedForMode', $mode_key); + $error++; + break; + } + + $start_date = $this->reversal_date; + $result = $this->addDepreciationLine($mode_key, '', $start_date, $this->reversal_amount_ht, $this->reversal_amount_ht, $accountancy_code_depreciation_debit, $accountancy_code_credit); + if ($result < 0) { + $error++; + break; + } + } else { + $this->errors[] = $langs->trans('AssetErrorReversalDateNotProvidedForMode', $mode_key); + $error++; + break; + } + } + + // futures depreciation lines + //----------------------------------------------------- + $nb_days_in_year = !empty($conf->global->ASSET_DEPRECIATION_DURATION_PER_YEAR) ? $conf->global->ASSET_DEPRECIATION_DURATION_PER_YEAR : 360; + $nb_days_in_month = !empty($conf->global->ASSET_DEPRECIATION_DURATION_PER_MONTH) ? $conf->global->ASSET_DEPRECIATION_DURATION_PER_MONTH : 30; + $period_amount = (double) price2num($depreciation_period_amount / $fields['duration'], 'MT'); + $first_period_found = false; + $first_period_date = isset($begin_period) && $begin_period > $fiscal_period_start ? $begin_period : $fiscal_period_start; + + $ref_date_format = "%Y" . ($fields['duration_type'] == 1 || $fields['duration_type'] == 2 ? '-%m' : '') . ($fields['duration_type'] == 2 ? '-%d' : ''); + + // Loop security + $idx_loop = 0; + $max_loop = $fields['duration'] + 2; + do { + // Loop security + $idx_loop++; + if ($idx_loop > $max_loop) break; + + if ($last_depreciation_date < $fiscal_period_end && ($first_period_date <= $start_date || $first_period_found)) { + // Disposal not depreciated + if ($fiscal_period_start <= $disposal_date && $disposal_date <= $fiscal_period_end && empty($this->disposal_depreciated)) { + break; + } + + $first_period_found = true; + + $period_begin = dol_print_date($fiscal_period_start, $ref_date_format); + $period_end = dol_print_date($fiscal_period_end, $ref_date_format); + $ref = $period_begin . ($period_begin != $period_end ? ' - ' . $period_end : ''); + if ($fiscal_period_start <= $disposal_date && $disposal_date <= $fiscal_period_end) { + $ref .= ' - ' . $langs->transnoentitiesnoconv('AssetDisposal'); + } + + $begin_date = $fiscal_period_start < $start_date && $start_date <= $fiscal_period_end ? $start_date : $fiscal_period_start; + $end_date = $fiscal_period_start < $finish_date && $finish_date <= $fiscal_period_end ? $finish_date : $fiscal_period_end; + if ($fields['duration_type'] == 2) { // Daily + $depreciation_ht = $period_amount; + } elseif ($fields['duration_type'] == 1) { // Monthly + $nb_days = min($nb_days_in_month, num_between_day($begin_date, $end_date, 1)); + if ($nb_days >= 28) { + $date_temp = dol_getdate($begin_date); + if ($date_temp['mon'] == 2) { + $nb_days = 30; + } + } + $depreciation_ht = (double) price2num($period_amount * $nb_days / $nb_days_in_month, 'MT'); + } else { // Annually + $nb_days = min($nb_days_in_year, num_between_day($begin_date, $end_date, 1)); + $depreciation_ht = (double) price2num($period_amount * $nb_days / $nb_days_in_year, 'MT'); + } + + if ($fiscal_period_start <= $depreciation_date_end && $depreciation_date_end <= $fiscal_period_end) { // last period + $depreciation_ht = (double)price2num($depreciation_amount - $cumulative_depreciation_ht, 'MT'); + $cumulative_depreciation_ht = $depreciation_amount; + } else { + $cumulative_depreciation_ht += $depreciation_ht; + } + + $result = $this->addDepreciationLine($mode_key, $ref, $fiscal_period_end, $depreciation_ht, $cumulative_depreciation_ht, $accountancy_code_depreciation_debit, $accountancy_code_credit); + if ($result < 0) { + $error++; + break; + } + } + + // Next fiscal period (+1 day/month/year) + $fiscal_period_start = dol_time_plus_duree($fiscal_period_end, 1, 'd'); + if ($fields['duration_type'] == 2) { // Daily + $fiscal_period_end = $fiscal_period_start; + } elseif ($fields['duration_type'] == 1) { // Monthly + $fiscal_period_end = dol_time_plus_duree(dol_time_plus_duree($fiscal_period_start, 1, 'm'), -1, 'd'); + } else { // Annually + $fiscal_period_end = dol_time_plus_duree(dol_time_plus_duree($fiscal_period_start, 1, 'y'), -1, 'd'); + } + $last_period_date = $disposal_date !== "" && $disposal_date < $depreciation_date_end ? $disposal_date : $depreciation_date_end; + } while ($fiscal_period_start < $last_period_date); + + if ($error) { + break; + } + } + } + + if ($error) { + $this->db->rollback(); + return -1; + } else { + $this->db->commit(); + return 1; + } + } + + /** + * Set last cumulative depreciation for each mode + * + * @param int $asset_depreciation_id Asset depreciation line ID + * @return int <0 if KO, >0 if OK + */ + public function setLastCumulativeDepreciation($asset_depreciation_id) + { + global $langs; + $langs->load('assets'); + + // Clean parameters + $asset_depreciation_id = $asset_depreciation_id > 0 ? $asset_depreciation_id : 0; + + // Check parameters + $error = 0; + if (empty($asset_depreciation_id)) { + $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("AssetDepreciation") . ' (' . $langs->transnoentitiesnoconv("TechnicalID") . ')'); + $error++; + } + if ($error) { + return -1; + } + + $this->db->begin(); + + require_once DOL_DOCUMENT_ROOT . '/asset/class/assetdepreciationoptions.class.php'; + $options = new AssetDepreciationOptions($this->db); + + // Get last depreciation lines save in bookkeeping + //----------------------------------------------------- + $sql = "SELECT fk_asset, depreciation_mode, cumulative_depreciation_ht"; + $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation"; + $sql .= " WHERE rowid = " . $asset_depreciation_id; + $resql = $this->db->query($sql); + if (!$resql) { + $this->errors[] = $langs->trans('AssetErrorFetchCumulativeDepreciation') . ': ' . $this->db->lasterror(); + $error++; + } else { + if ($obj = $this->db->fetch_object($resql)) { + $mode_key = $obj->depreciation_mode; + if (!empty($options->deprecation_options_fields[$mode_key])) { + $sql = "UPDATE " . MAIN_DB_PREFIX . $options->deprecation_options_fields[$mode_key]['table']; + $sql .= " SET total_amount_last_depreciation_ht = " . $obj->cumulative_depreciation_ht; + $sql .= " WHERE fk_asset = " . $obj->fk_asset; + $resql = $this->db->query($sql); + if (!$resql) { + $this->errors[] = $langs->trans('AssetErrorSetLastCumulativeDepreciation') . ': ' . $this->db->lasterror(); + $error++; + } + } + } + } + + if ($error) { + $this->db->rollback(); + return -1; + } else { + $this->db->commit(); + return 1; + } + } + + /** + * Set dispose status + * + * @param User $user Object user that dispose + * @param int $disposal_invoice_id Disposal invoice ID + * @param int $notrigger 1=Does not execute triggers, 0=Execute triggers + * @return int <0 if KO, 0=Nothing done, >0 if OK + */ + public function dispose($user, $disposal_invoice_id, $notrigger = 0) + { + global $conf, $langs; + + // Protection + if ($this->status != self::STATUS_DRAFT || $this->status == self::STATUS_DISPOSED) { + return 0; + } + + $this->db->begin(); + + $required_fields = array('disposal_date', 'disposal_date', 'fk_disposal_type'); + foreach ($required_fields as $field) { + $this->fields[$field]['notnull'] = 1; + } + $result = $this->update($user, 1); + foreach ($required_fields as $field) { + $this->fields[$field]['notnull'] = 0; + } + if ($result > 0) { + if ($disposal_invoice_id > 0) $this->add_object_linked('facture', $disposal_invoice_id); + $result = $this->setStatusCommon($user, self::STATUS_DISPOSED, $notrigger, 'ASSET_DISPOSED'); + } + if ($result > 0) $result = $this->calculationDepreciation(); + + if ($result < 0) { + $this->db->rollback(); + } else { + $this->db->commit(); + } + + // Define output language + if ($result > 0 && empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) { + if (method_exists($this, 'generateDocument')) { + global $hidedetails, $hidedesc, $hideref; + $outputlangs = $langs; + $newlang = ''; + if ($conf->global->MAIN_MULTILANGS && empty($newlang) && GETPOST('lang_id', 'aZ09')) { + $newlang = GETPOST('lang_id', 'aZ09'); + } + if ($conf->global->MAIN_MULTILANGS && empty($newlang)) { + $newlang = $this->thirdparty->default_lang; + } + if (!empty($newlang)) { + $outputlangs = new Translate("", $conf); + $outputlangs->setDefaultLang($newlang); + } + $model = $this->model_pdf; + $ret = $this->fetch($this->id); // Reload to get new records + + $this->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref); + } + } + + return $result; + } + + /** + * Set back to validated status + * + * @param User $user Object user that modify + * @param int $notrigger 1=Does not execute triggers, 0=Execute triggers + * @return int <0 if KO, 0=Nothing done, >0 if OK + */ + public function reopen($user, $notrigger = 0) + { + global $conf, $langs; + + // Protection + if ($this->status != self::STATUS_DISPOSED || $this->status == self::STATUS_DRAFT) { + return 0; + } + + + $this->db->begin(); + + $this->disposal_date = null; + $this->disposal_amount_ht = null; + $this->fk_disposal_type = null; + $this->disposal_depreciated = null; + $this->disposal_subject_to_vat = null; + $result = $this->update($user, 1); + if ($result > 0) { + $this->deleteObjectLinked(null, 'facture'); + $result = $this->setStatusCommon($user, self::STATUS_DRAFT, $notrigger, 'ASSET_REOPEN'); + } + if ($result > 0) $result = $this->calculationDepreciation(); + + if ($result < 0) { + $this->db->rollback(); + } else { + $this->db->commit(); + } + + // Define output language + if ($result > 0 && empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) { + if (method_exists($this, 'generateDocument')) { + global $hidedetails, $hidedesc, $hideref; + $outputlangs = $langs; + $newlang = ''; + if ($conf->global->MAIN_MULTILANGS && empty($newlang) && GETPOST('lang_id', 'aZ09')) { + $newlang = GETPOST('lang_id', 'aZ09'); + } + if ($conf->global->MAIN_MULTILANGS && empty($newlang)) { + $newlang = $this->thirdparty->default_lang; + } + if (!empty($newlang)) { + $outputlangs = new Translate("", $conf); + $outputlangs->setDefaultLang($newlang); + } + $model = $this->model_pdf; + $ret = $this->fetch($this->id); // Reload to get new records + + $this->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref); + } + } + + return $result; } /** * Return a link to the object card (with optionaly the picto) * - * @param int $withpicto Include picto in link (0=No picto, 1=Include picto into link, 2=Only picto) - * @param string $option On what the link point to ('nolink', ...) - * @param int $notooltip 1=Disable tooltip - * @param string $morecss Add more css on link - * @param int $save_lastsearch_value -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking - * @return string String with URL + * @param int $withpicto Include picto in link (0=No picto, 1=Include picto into link, 2=Only picto) + * @param string $option On what the link point to ('nolink', ...) + * @param int $maxlen Max length of name + * @param int $notooltip 1=Disable tooltip + * @param string $morecss Add more css on link + * @param int $save_lastsearch_value -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking + * @return string String with URL */ - public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1) + public function getNomUrl($withpicto = 0, $option = '', $maxlen = 0, $notooltip = 0, $morecss = '', $save_lastsearch_value = -1) { - global $db, $conf, $langs; - global $dolibarr_main_authentication, $dolibarr_main_demo; - global $menumanager; + global $conf, $langs, $hookmanager; if (!empty($conf->dol_no_mouse_hover)) { $notooltip = 1; // Force disable tooltips @@ -338,7 +1296,7 @@ class Asset extends CommonObject $linkclose = ''; if (empty($notooltip)) { if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) { - $label = $langs->trans("ShowAssets"); + $label = $langs->trans("ShowAsset"); $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"'; } $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"'; @@ -347,28 +1305,88 @@ class Asset extends CommonObject $linkclose = ($morecss ? ' class="'.$morecss.'"' : ''); } - $linkstart = ''; - $linkend = ''; + if ($option == 'nolink') { + $linkend = ''; + } else { + $linkend = ''; + } $result .= $linkstart; - if ($withpicto) { - $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); + + if (empty($this->showphoto_on_popup)) { + if ($withpicto) { + $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); + } + } else { + if ($withpicto) { + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + + list($class, $module) = explode('@', $this->picto); + $upload_dir = $conf->$module->multidir_output[$conf->entity]."/$class/".dol_sanitizeFileName($this->ref); + $filearray = dol_dir_list($upload_dir, "files"); + $filename = $filearray[0]['name']; + if (!empty($filename)) { + $pospoint = strpos($filearray[0]['name'], '.'); + + $pathtophoto = $class.'/'.$this->ref.'/thumbs/'.substr($filename, 0, $pospoint).'_mini'.substr($filename, $pospoint); + if (empty($conf->global->{strtoupper($module.'_'.$class).'_FORMATLISTPHOTOSASUSERS'})) { + $result .= '
    No photo
    '; + } else { + $result .= '
    No photo
    '; + } + + $result .= ''; + } else { + $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); + } + } } + if ($withpicto != 2) { - $result .= $this->ref; + $name = $this->ref; + if ($option == 'label') $name = $this->label; + elseif ($option == 'with_label') $name .= ' - ' . $this->label; + $result .= dol_escape_htmltag($maxlen ? dol_trunc($name, $maxlen) : $name); } + $result .= $linkend; //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : ''); + global $action, $hookmanager; + $hookmanager->initHooks(array('assetdao')); + $parameters = array('id'=>$this->id, 'getnomurl'=>$result); + $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks + if ($reshook > 0) { + $result = $hookmanager->resPrint; + } else { + $result .= $hookmanager->resPrint; + } + return $result; } /** - * Retourne le libelle du status d'un user (actif, inactif) + * Return the label of the status * - * @param int $mode 0=libelle long, 1=libelle court, 2=Picto + Libelle court, 3=Picto, 4=Picto + Libelle long, 5=Libelle court + Picto - * @return string Label of status + * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto + * @return string Label of status + */ + public function getLabelStatus($mode = 0) + { + return $this->LibStatut($this->status, $mode); + } + + /** + * Return the label of the status + * + * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto + * @return string Label of status */ public function getLibStatut($mode = 0) { @@ -379,43 +1397,43 @@ class Asset extends CommonObject /** * Return the status * - * @param int $status Id status - * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto - * @return string Label of status + * @param int $status Id status + * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto + * @return string Label of status */ - public static function LibStatut($status, $mode = 0) + public function LibStatut($status, $mode = 0) { // phpcs:enable - global $langs; - - $langs->load("contracts"); - $labelStatus = array(); - $labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Disabled'); - $labelStatus[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('Enabled'); - $labelStatusShort = array(); - $labelStatusShort[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Disabled'); - $labelStatusShort[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('Enabled'); - - $statusType = 'status0'; - if ($status == self::STATUS_VALIDATED) { - $statusType = 'status4'; + if (empty($this->labelStatus) || empty($this->labelStatusShort)) { + global $langs; + //$langs->load("asset@asset"); + $this->labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('AssetInProgress'); + $this->labelStatus[self::STATUS_DISPOSED] = $langs->transnoentitiesnoconv('AssetDisposed'); + $this->labelStatusShort[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('AssetInProgress'); + $this->labelStatusShort[self::STATUS_DISPOSED] = $langs->transnoentitiesnoconv('AssetDisposed'); } - return dolGetStatus($labelStatus[$status], $labelStatusShort[$status], '', $statusType, $mode); + $statusType = 'status4'; + if ($status == self::STATUS_DISPOSED) { + $statusType = 'status6'; + } + + return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode); } /** - * Load info into asset object + * Load the info information in the object * - * @param int $id Id of order + * @param int $id Id of object * @return void */ public function info($id) { - $sql = 'SELECT rowid, date_creation as datec, tms as datem,'; - $sql .= ' fk_user_creat, fk_user_modif'; - $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t'; - $sql .= ' WHERE t.rowid = '.((int) $id); + $sql = "SELECT rowid, date_creation as datec, tms as datem,"; + $sql .= " fk_user_creat, fk_user_modif"; + $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as t"; + $sql .= " WHERE t.rowid = ".((int) $id); + $result = $this->db->query($sql); if ($result) { if ($this->db->num_rows($result)) { @@ -458,25 +1476,116 @@ class Asset extends CommonObject */ public function initAsSpecimen() { + // Set here init that are not commonf fields + // $this->property1 = ... + // $this->property2 = ... + $this->initAsSpecimenCommon(); } + /** + * Create an array of lines + * + * @return array|int array of lines if OK, <0 if KO + */ + public function getLinesArray() + { + $this->lines = array(); + + return $this->lines; + } /** - * Action executed by scheduler - * CAN BE A CRON TASK + * Returns the reference to the following non used object depending on the active numbering module. * - * @return int 0 if OK, <>0 if KO (this function is used also by cron so only 0 is OK) + * @return string Object free reference */ - public function doScheduledJob() + public function getNextNumRef() { - global $conf, $langs; + global $langs, $conf; + $langs->load("asset@asset"); - $this->output = ''; - $this->error = ''; + if (empty($conf->global->ASSET_ASSET_ADDON)) { + $conf->global->ASSET_ASSET_ADDON = 'mod_asset_standard'; + } - dol_syslog(__METHOD__, LOG_DEBUG); + if (!empty($conf->global->ASSET_ASSET_ADDON)) { + $mybool = false; - return 0; + $file = $conf->global->ASSET_ASSET_ADDON.".php"; + $classname = $conf->global->ASSET_ASSET_ADDON; + + // Include file with class + $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']); + foreach ($dirmodels as $reldir) { + $dir = dol_buildpath($reldir."core/modules/asset/"); + + // Load file with numbering class (if found) + $mybool |= @include_once $dir.$file; + } + + if ($mybool === false) { + dol_print_error('', "Failed to include file ".$file); + return ''; + } + + if (class_exists($classname)) { + $obj = new $classname(); + $numref = $obj->getNextValue($this); + + if ($numref != '' && $numref != '-1') { + return $numref; + } else { + $this->error = $obj->error; + //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error); + return ""; + } + } else { + print $langs->trans("Error")." ".$langs->trans("ClassNotFound").' '.$classname; + return ""; + } + } else { + print $langs->trans("ErrorNumberingModuleNotSetup", $this->element); + return ""; + } } + + /** + * Create a document onto disk according to template module. + * + * @param string $modele Force template to use ('' to not force) + * @param Translate $outputlangs objet lang a utiliser pour traduction + * @param int $hidedetails Hide details of lines + * @param int $hidedesc Hide description + * @param int $hideref Hide ref + * @param null|array $moreparams Array to provide more information + * @return int 0 if KO, 1 if OK + */ +// public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null) +// { +// global $conf, $langs; +// +// $result = 0; +// $includedocgeneration = 1; +// +// $langs->load("asset@asset"); +// +// if (!dol_strlen($modele)) { +// $modele = 'standard_asset'; +// +// if (!empty($this->model_pdf)) { +// $modele = $this->model_pdf; +// } elseif (!empty($conf->global->ASSET_ADDON_PDF)) { +// $modele = $conf->global->ASSET_ADDON_PDF; +// } +// } +// +// $modelpath = "core/modules/asset/doc/"; +// +// if ($includedocgeneration && !empty($modele)) { +// $result = $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams); +// } +// +// return $result; +// } } diff --git a/htdocs/asset/class/asset_type.class.php b/htdocs/asset/class/asset_type.class.php deleted file mode 100644 index be8643e3f20..00000000000 --- a/htdocs/asset/class/asset_type.class.php +++ /dev/null @@ -1,445 +0,0 @@ - - * - * 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 - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** - * \file htdocs/asset/class/asset_type.class.php - * \ingroup asset - * \brief File of class to manage asset types - */ - -require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php'; - - -/** - * Class to manage asset type - */ -class AssetType extends CommonObject -{ - /** - * @var string Name of table without prefix where object is stored - */ - public $table_element = 'asset_type'; - - /** - * @var string ID to identify managed object - */ - public $element = 'asset_type'; - - /** - * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png - */ - public $picto = 'asset'; - - /** - * 0=No test on entity, 1=Test with field entity, 2=Test with link by societe - * @var int - */ - public $ismultientitymanaged = 1; - - /** - * @var string Asset type label - */ - public $label; - - /** @var string Accountancy code asset */ - public $accountancy_code_asset; - - /** @var string Accountancy code depreciation asset */ - public $accountancy_code_depreciation_asset; - - /** @var string Accountancy code depreciation expense */ - public $accountancy_code_depreciation_expense; - - /** @var string Public note */ - public $note; - - /** @var array Array of asset */ - public $asset = array(); - - public $fields = array( - 'rowid' =>array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>10), - 'entity' =>array('type'=>'integer', 'label'=>'Entity', 'default'=>1, 'enabled'=>1, 'visible'=>-2, 'notnull'=>1, 'position'=>15, 'index'=>1), - 'tms' =>array('type'=>'timestamp', 'label'=>'DateModification', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>20), - 'label' =>array('type'=>'varchar(50)', 'label'=>'Label', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>25, 'showoncombobox'=>1), - 'accountancy_code_asset' =>array('type'=>'varchar(32)', 'label'=>'Accountancy code asset', 'enabled'=>1, 'visible'=>-1, 'position'=>30), - 'accountancy_code_depreciation_asset' =>array('type'=>'varchar(32)', 'label'=>'Accountancy code depreciation asset', 'enabled'=>1, 'visible'=>-1, 'position'=>35), - 'accountancy_code_depreciation_expense' =>array('type'=>'varchar(32)', 'label'=>'Accountancy code depreciation expense', 'enabled'=>1, 'visible'=>-1, 'position'=>40), - 'note' =>array('type'=>'mediumtext', 'label'=>'Note', 'enabled'=>1, 'visible'=>-1, 'position'=>45), - ); - - - /** - * Constructor - * - * @param DoliDB $db Database handler - */ - public function __construct($db) - { - $this->db = $db; - } - - - /** - * Fonction qui permet de creer le type d'immobilisation - * - * @param User $user User making creation - * @param int $notrigger 1=do not execute triggers, 0 otherwise - * @return int >0 if OK, < 0 if KO - */ - public function create($user, $notrigger = 0) - { - global $conf; - - $error = 0; - - $this->label = trim($this->label); - $this->accountancy_code_asset = trim($this->accountancy_code_asset); - $this->accountancy_code_depreciation_asset = trim($this->accountancy_code_depreciation_asset); - $this->accountancy_code_depreciation_expense = trim($this->accountancy_code_depreciation_expense); - - $this->db->begin(); - - $sql = "INSERT INTO ".MAIN_DB_PREFIX."asset_type ("; - $sql .= "label"; - $sql .= ", accountancy_code_asset"; - $sql .= ", accountancy_code_depreciation_asset"; - $sql .= ", accountancy_code_depreciation_expense"; - $sql .= ", note"; - $sql .= ", entity"; - $sql .= ") VALUES ("; - $sql .= "'".$this->db->escape($this->label)."'"; - $sql .= ", '".$this->db->escape($this->accountancy_code_asset)."'"; - $sql .= ", '".$this->db->escape($this->accountancy_code_depreciation_asset)."'"; - $sql .= ", '".$this->db->escape($this->accountancy_code_depreciation_expense)."'"; - $sql .= ", '".$this->db->escape($this->note)."'"; - $sql .= ", ".((int) $conf->entity); - $sql .= ")"; - - dol_syslog("Asset_type::create", LOG_DEBUG); - $result = $this->db->query($sql); - if ($result) { - $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."asset_type"); - - $result = $this->update($user, 1); - if ($result < 0) { - $this->db->rollback(); - return -3; - } - - if (!$notrigger) { - // Call trigger - $result = $this->call_trigger('ASSET_TYPE_CREATE', $user); - if ($result < 0) { - $error++; - } - // End call triggers - } - - if (!$error) { - $this->db->commit(); - return $this->id; - } else { - dol_syslog(get_class($this)."::create ".$this->error, LOG_ERR); - $this->db->rollback(); - return -2; - } - } else { - $this->error = $this->db->lasterror(); - $this->db->rollback(); - return -1; - } - } - - /** - * Met a jour en base donnees du type - * - * @param User $user Object user making change - * @param int $notrigger 1=do not execute triggers, 0 otherwise - * @return int >0 if OK, < 0 if KO - */ - public function update($user, $notrigger = 0) - { - global $conf, $hookmanager; - - $error = 0; - - $this->label = trim($this->label); - - $this->db->begin(); - - $sql = "UPDATE ".MAIN_DB_PREFIX."asset_type "; - $sql .= "SET "; - $sql .= "label = '".$this->db->escape($this->label)."',"; - $sql .= "accountancy_code_asset = '".$this->db->escape($this->accountancy_code_asset)."',"; - $sql .= "accountancy_code_depreciation_asset = '".$this->db->escape($this->accountancy_code_depreciation_asset)."',"; - $sql .= "accountancy_code_depreciation_expense = '".$this->db->escape($this->accountancy_code_depreciation_expense)."',"; - $sql .= "note = '".$this->db->escape($this->note)."'"; - $sql .= " WHERE rowid = ".((int) $this->id); - - $result = $this->db->query($sql); - if ($result) { - $action = 'update'; - - // Actions on extra fields - if (!$error) { - $result = $this->insertExtraFields(); - if ($result < 0) { - $error++; - } - } - - if (!$error && !$notrigger) { - // Call trigger - $result = $this->call_trigger('ASSET_TYPE_MODIFY', $user); - if ($result < 0) { - $error++; - } - // End call triggers - } - - if (!$error) { - $this->db->commit(); - return 1; - } else { - $this->db->rollback(); - dol_syslog(get_class($this)."::update ".$this->error, LOG_ERR); - return -$error; - } - } else { - $this->error = $this->db->lasterror(); - $this->db->rollback(); - return -1; - } - } - - /** - * Fonction qui permet de supprimer le status de l'adherent - * - * @return int >0 if OK, 0 if not found, < 0 if KO - */ - public function delete() - { - global $user; - - $error = 0; - - $sql = "DELETE FROM ".MAIN_DB_PREFIX."asset_type"; - $sql .= " WHERE rowid = ".((int) $this->id); - - $resql = $this->db->query($sql); - if ($resql) { - // Call trigger - $result = $this->call_trigger('ASSET_TYPE_DELETE', $user); - if ($result < 0) { - $error++; $this->db->rollback(); return -2; - } - // End call triggers - - $this->db->commit(); - return 1; - } else { - $this->db->rollback(); - $this->error = $this->db->lasterror(); - return -1; - } - } - - /** - * Fonction qui permet de recuperer le status de l'immobilisation - * - * @param int $rowid Id of member type to load - * @return int <0 if KO, >0 if OK - */ - public function fetch($rowid) - { - $sql = "SELECT d.rowid, d.label as label, d.accountancy_code_asset, d.accountancy_code_depreciation_asset, d.accountancy_code_depreciation_expense, d.note"; - $sql .= " FROM ".MAIN_DB_PREFIX."asset_type as d"; - $sql .= " WHERE d.rowid = ".(int) $rowid; - - dol_syslog("Asset_type::fetch", LOG_DEBUG); - - $resql = $this->db->query($sql); - if ($resql) { - if ($this->db->num_rows($resql)) { - $obj = $this->db->fetch_object($resql); - - $this->id = $obj->rowid; - $this->ref = $obj->rowid; - $this->label = $obj->label; - $this->accountancy_code_asset = $obj->accountancy_code_asset; - $this->accountancy_code_depreciation_asset = $obj->accountancy_code_depreciation_asset; - $this->accountancy_code_depreciation_expense = $obj->accountancy_code_depreciation_expense; - $this->note = $obj->note; - } - - return 1; - } else { - $this->error = $this->db->lasterror(); - return -1; - } - } - - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps - /** - * Return list of asset's type - * - * @return array List of types of members - */ - public function liste_array() - { - // phpcs:enable - global $conf, $langs; - - $assettypes = array(); - - $sql = "SELECT rowid, label as label"; - $sql .= " FROM ".MAIN_DB_PREFIX."asset_type"; - $sql .= " WHERE entity IN (".getEntity('asset_type').")"; - - $resql = $this->db->query($sql); - if ($resql) { - $nump = $this->db->num_rows($resql); - - if ($nump) { - $i = 0; - while ($i < $nump) { - $obj = $this->db->fetch_object($resql); - - $assettypes[$obj->rowid] = $langs->trans($obj->label); - $i++; - } - } - } else { - print $this->db->error(); - } - return $assettypes; - } - - /** - * Return array of Asset objects for asset type this->id (or all if this->id not defined) - * - * @param string $excludefilter Filter string to exclude. This parameter must not be provided by input of users - * @param int $mode 0=Return array of asset instance - * 1=Return array of asset instance without extra data - * 2=Return array of asset id only - * @return mixed Array of asset or -1 on error - */ - public function listAssetForAssetType($excludefilter = '', $mode = 0) - { - global $conf, $user; - - $ret = array(); - - $sql = "SELECT a.rowid"; - $sql .= " FROM ".MAIN_DB_PREFIX."asset as a"; - $sql .= " WHERE a.entity IN (".getEntity('asset').")"; - $sql .= " AND a.fk_asset_type = ".((int) $this->id); - if (!empty($excludefilter)) { - $sql .= ' AND ('.$excludefilter.')'; - } - - dol_syslog(get_class($this)."::listAssetsForGroup", LOG_DEBUG); - $resql = $this->db->query($sql); - if ($resql) { - while ($obj = $this->db->fetch_object($resql)) { - if (!array_key_exists($obj->rowid, $ret)) { - if ($mode < 2) { - $assetstatic = new Asset($this->db); - $assetstatic->fetch($obj->rowid); - $ret[$obj->rowid] = $assetstatic; - } else { - $ret[$obj->rowid] = $obj->rowid; - } - } - } - - $this->db->free($resql); - - $this->asset = $ret; - - return $ret; - } else { - $this->error = $this->db->lasterror(); - return -1; - } - } - - /** - * Return clicable name (with picto eventually) - * - * @param int $withpicto 0=No picto, 1=Include picto into link, 2=Only picto - * @param int $maxlen length max label - * @param int $notooltip 1=Disable tooltip - * @return string String with URL - */ - public function getNomUrl($withpicto = 0, $maxlen = 0, $notooltip = 0) - { - global $langs; - - $result = ''; - $label = $langs->trans("ShowTypeCard", $this->label); - - $linkstart = ''; - $linkend = ''; - - $result .= $linkstart; - if ($withpicto) { - $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); - } - if ($withpicto != 2) { - $result .= ($maxlen ?dol_trunc($this->label, $maxlen) : $this->label); - } - $result .= $linkend; - - return $result; - } - - /** - * Initialise an instance with random values. - * Used to build previews or test instances. - * id must be 0 if object instance is a specimen. - * - * @return void - */ - public function initAsSpecimen() - { - global $conf, $user, $langs; - - // Initialize parameters - $this->id = 0; - $this->ref = 'ATSPEC'; - $this->specimen = 1; - - $this->label = 'ASSET TYPE SPECIMEN'; - $this->note = 'This is a note'; - - // Assets of this asset type is just me - $this->asset = array( - $user->id => $user - ); - } - - /** - * getLibStatut - * - * @return string Return status of a type of asset - */ - public function getLibStatut() - { - return ''; - } -} diff --git a/htdocs/asset/class/assetaccountancycodes.class.php b/htdocs/asset/class/assetaccountancycodes.class.php new file mode 100644 index 00000000000..112aa1e3f35 --- /dev/null +++ b/htdocs/asset/class/assetaccountancycodes.class.php @@ -0,0 +1,277 @@ + + * + * 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 + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file asset/class/assetaccountancycodes.class.php + * \ingroup asset + * \brief This file is a class file for AssetAccountancyCodes + */ + +require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php'; + +/** + * Class for AssetAccountancyCodes + */ +class AssetAccountancyCodes extends CommonObject +{ + /** + * @var array Array with all accountancy codes info by mode. + * Note : 'economic' mode is mandatory and is the primary accountancy codes + * 'depreciation_asset' and 'depreciation_expense' is mandatory and is used for write depreciation in bookkeeping + */ + public $accountancy_codes_fields = array( + 'economic' => array( + 'label' => 'AssetAccountancyCodeDepreciationEconomic', + 'table' => 'asset_accountancy_codes_economic', + 'depreciation_debit' => 'depreciation_asset', + 'depreciation_credit' => 'depreciation_expense', + 'fields' => array( + 'asset' => array('label' => 'AssetAccountancyCodeAsset'), + 'depreciation_asset' => array('label' => 'AssetAccountancyCodeDepreciationAsset'), + 'depreciation_expense' => array('label' => 'AssetAccountancyCodeDepreciationExpense'), + 'value_asset_sold' => array('label' => 'AssetAccountancyCodeValueAssetSold'), + 'receivable_on_assignment' => array('label' => 'AssetAccountancyCodeReceivableOnAssignment'), + 'proceeds_from_sales' => array('label' => 'AssetAccountancyCodeProceedsFromSales'), + 'vat_collected' => array('label' => 'AssetAccountancyCodeVatCollected'), + 'vat_deductible' => array('label' => 'AssetAccountancyCodeVatDeductible'), + ), + ), + 'accelerated_depreciation' => array( + 'label' => 'AssetAccountancyCodeDepreciationAcceleratedDepreciation', + 'table' => 'asset_accountancy_codes_fiscal', + 'depreciation_debit' => 'accelerated_depreciation', + 'depreciation_credit' => 'endowment_accelerated_depreciation', + 'fields' => array( + 'accelerated_depreciation' => array('label' => 'AssetAccountancyCodeAcceleratedDepreciation'), + 'endowment_accelerated_depreciation' => array('label' => 'AssetAccountancyCodeEndowmentAcceleratedDepreciation'), + 'provision_accelerated_depreciation' => array('label' => 'AssetAccountancyCodeProvisionAcceleratedDepreciation'), + ), + ), + ); + + /** + * @var array Array with all accountancy codes by mode. + */ + public $accountancy_codes = array(); + + /** + * Constructor + * + * @param DoliDb $db Database handler + */ + public function __construct(DoliDB $db) + { + $this->db = $db; + } + + /** + * Fill accountancy_codes property of object (using for data sent by forms) + */ + public function setAccountancyCodesFromPost() + { + $this->accountancy_codes = array(); + foreach ($this->accountancy_codes_fields as $mode_key => $mode_info) { + $this->accountancy_codes[$mode_key] = array(); + foreach ($mode_info['fields'] as $field_key => $field_info) { + $accountancy_code = GETPOST($mode_key . '_' . $field_key, 'aZ09'); + if (empty($accountancy_code) || $accountancy_code == '-1') $accountancy_code = ''; + $this->accountancy_codes[$mode_key][$field_key] = $accountancy_code; + } + } + } + + /** + * Load accountancy codes of a asset or a asset model + * + * @param int $asset_id Asset ID to set + * @param int $asset_model_id Asset model ID to set + * @return int <0 if KO, >0 if OK + */ + public function fetchAccountancyCodes($asset_id = 0, $asset_model_id = 0) + { + global $langs, $hookmanager; + dol_syslog(__METHOD__ . " sset_id=$asset_id, asset_model_id=$asset_model_id"); + + $error = 0; + $this->errors = array(); + $this->accountancy_codes = array(); + + // Clean parameters + $asset_id = $asset_id > 0 ? $asset_id : 0; + $asset_model_id = $asset_model_id > 0 ? $asset_model_id : 0; + + if (!is_object($hookmanager)) { + require_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php'; + $hookmanager = new HookManager($this->db); + } + + $hookmanager->initHooks(array('assetaccountancycodesdao')); + $parameters = array('asset_id' => $asset_id, 'asset_model_id' => $asset_model_id); + $reshook = $hookmanager->executeHooks('fetchAccountancyCodes', $parameters, $this); // Note that $action and $object may have been modified by some hooks + if (!empty($reshook)) { + return $reshook; + } + + // Check parameters + if (empty($asset_id) && empty($asset_model_id)) { + $this->errors[] = $langs->trans('AssetErrorAssetOrAssetModelIDNotProvide'); + $error++; + } + if ($error) { + dol_syslog(__METHOD__ . " Error check parameters: " . $this->errorsToString(), LOG_ERR); + return -1; + } + + $accountancy_codes = array(); + foreach ($this->accountancy_codes_fields as $mode_key => $mode_info) { + $sql = "SELECT " . implode(',', array_keys($mode_info['fields'])); + $sql .= " FROM " . MAIN_DB_PREFIX . $mode_info['table']; + $sql .= " WHERE " . ($asset_id > 0 ? " fk_asset = " . $asset_id : " fk_asset_model = " . $asset_model_id); + + $resql = $this->db->query($sql); + if ($resql) { + if ($obj = $this->db->fetch_object($resql)) { + $accountancy_codes[$mode_key] = array(); + foreach ($mode_info['fields'] as $field_key => $field_info) { + $accountancy_codes[$mode_key][$field_key] = $obj->$field_key; + } + } + } else { + $this->errors[] = $langs->trans('AssetErrorFetchAccountancyCodesForMode', $mode_key) . ': ' . $this->db->lasterror(); + $error++; + } + } + + if ($error) { + dol_syslog(__METHOD__ . " Error fetch accountancy codes: " . $this->errorsToString(), LOG_ERR); + return -1; + } else { + $this->accountancy_codes = $accountancy_codes; + return 1; + } + } + + /** + * Update accountancy codes of a asset or a asset model + * + * @param User $user User making update + * @param int $asset_id Asset ID to set + * @param int $asset_model_id Asset model ID to set + * @param int $notrigger 1=disable trigger UPDATE (when called by create) + * @return int <0 if KO, >0 if OK + */ + public function updateAccountancyCodes($user, $asset_id = 0, $asset_model_id = 0, $notrigger = 0) + { + global $langs, $hookmanager; + dol_syslog(__METHOD__ . " user_id={$user->id}, asset_id=$asset_id, asset_model_id=$asset_model_id, notrigger=$notrigger"); + + $error = 0; + $this->errors = array(); + + // Clean parameters + $asset_id = $asset_id > 0 ? $asset_id : 0; + $asset_model_id = $asset_model_id > 0 ? $asset_model_id : 0; + + if (!is_object($hookmanager)) { + require_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php'; + $hookmanager = new HookManager($this->db); + } + + $hookmanager->initHooks(array('assetaccountancycodesdao')); + $parameters = array('user' => $user, 'asset_id' => $asset_id, 'asset_model_id' => $asset_model_id); + $reshook = $hookmanager->executeHooks('updateAccountancyCodes', $parameters, $this); // Note that $action and $object may have been modified by some hooks + if (!empty($reshook)) { + return $reshook; + } + + // Check parameters + if (empty($asset_id) && empty($asset_model_id)) { + $this->errors[] = $langs->trans('AssetErrorAssetOrAssetModelIDNotProvide'); + $error++; + } + if ($error) { + dol_syslog(__METHOD__ . " Error check parameters: " . $this->errorsToString(), LOG_ERR); + return -1; + } + + $this->db->begin(); + $now = dol_now(); + + foreach ($this->accountancy_codes_fields as $mode_key => $mode_info) { + // Delete old accountancy codes + $sql = "DELETE FROM " . MAIN_DB_PREFIX . $mode_info['table']; + $sql .= " WHERE " . ($asset_id > 0 ? " fk_asset = " . $asset_id : " fk_asset_model = " . $asset_model_id); + $resql = $this->db->query($sql); + if (!$resql) { + $this->errors[] = $langs->trans('AssetErrorDeleteAccountancyCodesForMode', $mode_key) . ': ' . $this->db->lasterror(); + $error++; + } + + if (!$error && !empty($this->accountancy_codes[$mode_key])) { + // Insert accountancy codes + $sql = "INSERT INTO " . MAIN_DB_PREFIX . $mode_info['table'] . "("; + $sql .= $asset_id > 0 ? "fk_asset," : "fk_asset_model,"; + $sql .= implode(',', array_keys($mode_info['fields'])); + $sql .= ", tms, fk_user_modif"; + $sql .= ") VALUES("; + $sql .= $asset_id > 0 ? $asset_id : $asset_model_id; + foreach ($mode_info['fields'] as $field_key => $field_info) { + $sql .= ', ' . (empty($this->accountancy_codes[$mode_key][$field_key]) ? 'NULL' : "'" . $this->db->escape($this->accountancy_codes[$mode_key][$field_key]) . "'"); + } + $sql .= ", '" . $this->db->idate($now) . "'"; + $sql .= ", " . $user->id; + $sql .= ")"; + + $resql = $this->db->query($sql); + if (!$resql) { + $this->errors[] = $langs->trans('AssetErrorInsertAccountancyCodesForMode', $mode_key) . ': ' . $this->db->lasterror(); + $error++; + } + } + } + + if (!$error && $asset_id > 0) { + // Calculation of depreciation lines (reversal and future) + require_once DOL_DOCUMENT_ROOT . '/asset/class/asset.class.php'; + $asset = new Asset($this->db); + $result = $asset->fetch($asset_id); + if ($result > 0) $result = $asset->calculationDepreciation(); + if ($result < 0) { + $this->errors[] = $langs->trans('AssetErrorCalculationDepreciationLines'); + $this->errors[] = $asset->errorsToString(); + $error++; + } + } + + if (!$error && !$notrigger) { + // Call trigger + $result = $this->call_trigger('ASSET_ACCOUNTANCY_CODES_MODIFY', $user); + if ($result < 0) { + $error++; + } + // End call triggers + } + + if (!$error) { + $this->db->commit(); + return 1; + } else { + $this->db->rollback(); + return -1; + } + } +} diff --git a/htdocs/asset/class/assetdepreciationoptions.class.php b/htdocs/asset/class/assetdepreciationoptions.class.php new file mode 100644 index 00000000000..3f447621be5 --- /dev/null +++ b/htdocs/asset/class/assetdepreciationoptions.class.php @@ -0,0 +1,546 @@ + + * + * 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 + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file asset/class/assetdepreciationoptions.class.php + * \ingroup asset + * \brief This file is a class file for AssetDepreciationOptions + */ + +require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php'; + +/** + * Class for AssetDepreciationOptions + */ +class AssetDepreciationOptions extends CommonObject +{ + /** + * @var string Name of table without prefix where object is stored. This is also the key used for extrafields management. + */ + public $table_element = ''; + + /** + * 'type' field format ('integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter[:Sortfield]]]', 'sellist:TableName:LabelFieldName[:KeyFieldName[:KeyFieldParent[:Filter[:Sortfield]]]]', 'varchar(x)', 'double(24,8)', 'real', 'price', 'text', 'text:none', 'html', 'date', 'datetime', 'timestamp', 'duration', 'mail', 'phone', 'url', 'password') + * Note: Filter can be a string like "(t.ref:like:'SO-%') or (t.date_creation:<:'20160101') or (t.nature:is:NULL)" + * 'label' the translation key. + * 'picto' is code of a picto to show before value in forms + * 'enabled' is a condition when the field must be managed (Example: 1 or '$conf->global->MY_SETUP_PARAM) + * 'position' is the sort order of field. + * 'notnull' is set to 1 if not null in database. Set to -1 if we must set data to null if empty ('' or 0). + * 'visible' says if field is visible in list (Examples: 0=Not visible, 1=Visible on list and create/update/view forms, 2=Visible on list only, 3=Visible on create/update/view form only (not list), 4=Visible on list and update/view form only (not create). 5=Visible on list and view only (not create/not update). Using a negative value means field is not shown by default on list but can be selected for viewing) + * 'noteditable' says if field is not editable (1 or 0) + * 'default' is a default value for creation (can still be overwrote by the Setup of Default Values if field is editable in creation form). Note: If default is set to '(PROV)' and field is 'ref', the default value will be set to '(PROVid)' where id is rowid when a new record is created. + * 'index' if we want an index in database. + * 'foreignkey'=>'tablename.field' if the field is a foreign key (it is recommanded to name the field fk_...). + * 'searchall' is 1 if we want to search in this field when making a search from the quick search button. + * 'isameasure' must be set to 1 or 2 if field can be used for measure. Field type must be summable like integer or double(24,8). Use 1 in most cases, or 2 if you don't want to see the column total into list (for example for percentage) + * 'css' and 'cssview' and 'csslist' is the CSS style to use on field. 'css' is used in creation and update. 'cssview' is used in view mode. 'csslist' is used for columns in lists. For example: 'css'=>'minwidth300 maxwidth500 widthcentpercentminusx', 'cssview'=>'wordbreak', 'csslist'=>'tdoverflowmax200' + * 'help' is a 'TranslationString' to use to show a tooltip on field. You can also use 'TranslationString:keyfortooltiponlick' for a tooltip on click. + * 'showoncombobox' if value of the field must be visible into the label of the combobox that list record + * 'disabled' is 1 if we want to have the field locked by a 'disabled' attribute. In most cases, this is never set into the definition of $fields into class, but is set dynamically by some part of code. + * 'arrayofkeyval' to set a list of values if type is a list of predefined values. For example: array("0"=>"Draft","1"=>"Active","-1"=>"Cancel"). Note that type can be 'integer' or 'varchar' + * 'autofocusoncreate' to have field having the focus on a create form. Only 1 field should have this property set to 1. + * 'comment' is not used. You can store here any text of your choice. It is not used by application. + * 'validate' is 1 if need to validate with $this->validateField() + * 'copytoclipboard' is 1 or 2 to allow to add a picto to copy value into clipboard (1=picto after label, 2=picto after value) + * 'enabled_field' if the mode block or a field is enabled if another field equal a value (="mode_key:field_key:value") + * 'only_on_asset' is 1 if only a field on a asset + * + * Note: To have value dynamic, you can set value to 0 in definition and edit the value on the fly into the constructor. + */ + + /** + * @var array Array with all fields and their property. Do not use it as a static var. It may be modified by constructor. + */ + public $fields = array(); + + /** + * @var array Array with all deprecation options info by mode. + * Note : economic mode is mandatory and is the primary options + */ + public $deprecation_options_fields = array( + 'economic' => array( + 'label' => 'AssetDepreciationOptionEconomic', + 'table' => 'asset_depreciation_options_economic', + 'fields' => array( + 'depreciation_type' => array('type'=>'smallint', 'label'=>'AssetDepreciationOptionDepreciationType', 'enabled'=>'1', 'position'=>10, 'notnull'=>1, 'visible'=>1, 'default'=>'0', 'arrayofkeyval'=>array('0'=>'AssetDepreciationOptionDepreciationTypeLinear', '1'=>'AssetDepreciationOptionDepreciationTypeDegressive', '2'=>'AssetDepreciationOptionDepreciationTypeExceptional'), 'validate'=>'1',), + 'degressive_coefficient' => array('type'=>'double(24,8)', 'label'=>'AssetDepreciationOptionDegressiveRate', 'enabled'=>'1', 'position'=>20, 'notnull'=>1, 'visible'=>1, 'default'=>'0', 'isameasure'=>'1', 'validate'=>'1','enabled_field' => 'economic:depreciation_type:1'), + 'duration' => array('type'=>'integer', 'label'=>'AssetDepreciationOptionDuration', 'enabled'=>'1', 'position'=>30, 'notnull'=>1, 'visible'=>1, 'default'=>'0', 'isameasure'=>'1', 'validate'=>'1',), + 'duration_type' => array('type'=>'smallint', 'label'=>'AssetDepreciationOptionDurationType', 'enabled'=>'1', 'position'=>40, 'notnull'=>1, 'visible'=>1, 'default'=>'0', 'arrayofkeyval'=>array('0'=>'AssetDepreciationOptionDurationTypeAnnual', '1'=>'AssetDepreciationOptionDurationTypeMonthly'/*, '2'=>'AssetDepreciationOptionDurationTypeDaily'*/), 'validate'=>'1',), + 'rate' => array('type'=>'double(24,8)', 'label'=>'AssetDepreciationOptionRate', 'enabled'=>'1', 'position'=>50, 'visible'=>3, 'default'=>'0', 'isameasure'=>'1', 'validate'=>'1', 'computed' => '$object->asset_depreciation_options->getRate("economic")',), + 'accelerated_depreciation_option' => array('type'=>'boolean', 'label'=>'AssetDepreciationOptionAcceleratedDepreciation', 'enabled'=>'1', 'position'=>60, 'column_break' => true, 'notnull'=>0, 'default'=>'0', 'visible'=>1, 'validate'=>'1',), + 'amount_base_depreciation_ht' => array('type'=>'price', 'label'=>'AssetDepreciationOptionAmountBaseDepreciationHT', 'enabled'=>'isset($object)&&get_class($object)=="Asset"', 'only_on_asset'=>1, 'position'=>90, 'notnull'=>0, 'required'=>1, 'visible'=>1, 'default'=>'$object->reversal_amount_ht > 0 ? $object->reversal_amount_ht : $object->acquisition_value_ht', 'isameasure'=>'1', 'validate'=>'1',), + 'amount_base_deductible_ht' => array('type'=>'price', 'label'=>'AssetDepreciationOptionAmountBaseDeductibleHT', 'enabled'=>'isset($object)&&get_class($object)=="Asset"', 'only_on_asset'=>1, 'position'=>100, 'notnull'=>0, 'visible'=>1, 'default'=>'0', 'isameasure'=>'1', 'validate'=>'1',), + 'total_amount_last_depreciation_ht' => array('type'=>'price', 'label'=>'AssetDepreciationOptionTotalAmountLastDepreciationHT', 'enabled'=>'isset($object)&&get_class($object)=="Asset"', 'only_on_asset'=>1, 'position'=>110, 'noteditable'=> 1, 'notnull'=>0, 'visible'=>1, 'default'=>'0', 'isameasure'=>'1', 'validate'=>'1',), + ), + ), + 'accelerated_depreciation' => array( + 'label' => 'AssetDepreciationOptionAcceleratedDepreciation', + 'table' => 'asset_depreciation_options_fiscal', + 'enabled_field' => 'economic:accelerated_depreciation_option:1', + 'fields' => array( + 'depreciation_type' => array('type'=>'smallint', 'label'=>'AssetDepreciationOptionDepreciationType', 'enabled'=>'1', 'position'=>10, 'notnull'=>1, 'visible'=>1, 'default'=>'0', 'arrayofkeyval'=>array('0'=>'AssetDepreciationOptionDepreciationTypeLinear', '1'=>'AssetDepreciationOptionDepreciationTypeDegressive', '2'=>'AssetDepreciationOptionDepreciationTypeExceptional'), 'validate'=>'1',), + 'degressive_coefficient' => array('type'=>'double(24,8)', 'label'=>'AssetDepreciationOptionDegressiveRate', 'enabled'=>'1', 'position'=>20, 'notnull'=>1, 'visible'=>1, 'default'=>'0', 'isameasure'=>'1', 'validate'=>'1','enabled_field' => 'accelerated_depreciation:depreciation_type:1'), + 'duration' => array('type'=>'integer', 'label'=>'AssetDepreciationOptionDuration', 'enabled'=>'1', 'position'=>30, 'notnull'=>1, 'visible'=>1, 'default'=>'0', 'isameasure'=>'1', 'validate'=>'1',), + 'duration_type' => array('type'=>'smallint', 'label'=>'AssetDepreciationOptionDurationType', 'enabled'=>'1', 'position'=>40, 'notnull'=>1, 'visible'=>1, 'default'=>'0', 'arrayofkeyval'=>array('0'=>'AssetDepreciationOptionDurationTypeAnnual', '1'=>'AssetDepreciationOptionDurationTypeMonthly'/*, '2'=>'AssetDepreciationOptionDurationTypeDaily'*/), 'validate'=>'1',), + 'rate' => array('type'=>'double(24,8)', 'label'=>'AssetDepreciationOptionRate', 'enabled'=>'1', 'position'=>50, 'visible'=>3, 'default'=>'0', 'isameasure'=>'1', 'validate'=>'1', 'computed' => '$object->asset_depreciation_options->getRate("accelerated_depreciation")',), + 'amount_base_depreciation_ht' => array('type'=>'price', 'label'=>'AssetDepreciationOptionAmountBaseDepreciationHT', 'enabled'=>'isset($object)&&get_class($object)=="Asset"', 'only_on_asset'=>1, 'position'=>80, 'column_break' => true, 'notnull'=>0, 'required'=>1, 'visible'=>1, 'default'=>'$object->reversal_amount_ht > 0 ? $object->reversal_amount_ht : $object->acquisition_value_ht', 'isameasure'=>'1', 'validate'=>'1',), + 'amount_base_deductible_ht' => array('type'=>'price', 'label'=>'AssetDepreciationOptionAmountBaseDeductibleHT', 'enabled'=>'isset($object)&&get_class($object)=="Asset"', 'only_on_asset'=>1, 'position'=>90, 'notnull'=>0, 'visible'=>1, 'default'=>'0', 'isameasure'=>'1', 'validate'=>'1',), + 'total_amount_last_depreciation_ht' => array('type'=>'price', 'label'=>'AssetDepreciationOptionTotalAmountLastDepreciationHT', 'enabled'=>'isset($object)&&get_class($object)=="Asset"', 'only_on_asset'=>1, 'position'=>100, 'noteditable'=> 1, 'notnull'=>0, 'visible'=>1, 'default'=>'0', 'isameasure'=>'1', 'validate'=>'1',), + ), + ), + ); + public $fk_asset; + public $fk_asset_model; + public $tms; + public $fk_user_modif; + + /** + * @var array Array with all deprecation options by mode. + */ + public $deprecation_options = array(); + + /** + * Constructor + * + * @param DoliDb $db Database handler + */ + public function __construct(DoliDB $db) + { + global $langs; + $this->db = $db; + + // Translate some data of arrayofkeyval + if (is_object($langs)) { + foreach ($this->deprecation_options_fields as $mode_key => $mode_info) { + if (!empty($mode_info['fields']) && is_array($mode_info['fields'])) { + foreach ($mode_info['fields'] as $field_key => $field_info) { + if (!empty($field_info['arrayofkeyval']) && is_array($field_info['arrayofkeyval'])) { + foreach ($field_info['arrayofkeyval'] as $key => $val) { + $this->deprecation_options_fields[$mode_key]['fields'][$field_key]['arrayofkeyval'][$key] = $langs->trans($val); + } + } + } + } + } + } + } + + /** + * Set object infos for a mode + * + * @param string $mode Depreciation mode (economic, accelerated_depreciation, ...) + * @param int $class_type Type (0:asset, 1:asset model) + * @param bool $all_field Get all fields + * @return int <0 if KO, >0 if OK + */ + public function setInfosForMode($mode, $class_type = 0, $all_field = false) + { + // Clean parameters + $mode = strtolower(trim($mode)); + + if (!empty($this->deprecation_options_fields[$mode])) { + $this->table_element = $this->deprecation_options_fields[$mode]['table']; + $this->fields = $this->deprecation_options_fields[$mode]['fields']; + foreach ($this->fields as $field_key => $field_info) { + if ((!empty($field_info['computed']) && !$all_field) || (!empty($field_info['only_on_asset']) && !empty($class_type))) { + unset($this->fields[$field_key]); + continue; + } + + // Unset required option (notnull) if field disabled + if (!empty($mode_info['enabled_field'])) { + $info = explode(':', $mode_info['enabled_field']); + if ($this->deprecation_options[$info[0]][$info[1]] != $info[2] && isset($this->fields[$field_key]['notnull'])) { + unset($this->fields[$field_key]['notnull']); + } + } + // Set value of the field in the object (for createCommon and setDeprecationOptionsFromPost functions) + $this->{$field_key} = $this->deprecation_options[$mode][$field_key]; + } + + $this->fields['rowid'] = array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>'1', 'position'=>1, 'notnull'=>1, 'visible'=>0, 'noteditable'=>'1', 'index'=>1, 'css'=>'left', 'comment'=>"Id"); + if (empty($class_type)) { + $this->fields['fk_asset'] = array('type' => 'integer:Asset:asset/class/asset.class.php:1:status=1 AND entity IN (__SHARED_ENTITIES__)', 'label' => 'Asset', 'enabled' => '1', 'position' => 0, 'notnull' => 0, 'visible' => 0, 'index' => 1, 'validate' => '1',); + } else { + $this->fields['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' => 0, 'notnull' => 0, 'visible' => 0, 'index' => 1, 'validate' => '1',); + } + $this->fields['tms'] = array('type' => 'timestamp', 'label' => 'DateModification', 'enabled' => '1', 'position' => 501, 'notnull' => 0, 'visible' => 0,); + $this->fields['fk_user_modif'] = array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserModif', 'enabled' => '1', 'position' => 511, 'notnull' => -1, 'visible' => 0,); + } + + return 1; + } + + /** + * Fill deprecation_options property of object (using for data sent by forms) + * + * @param int $class_type Type (0:asset, 1:asset model) + * @return int <0 if KO, >0 if OK + */ + public function setDeprecationOptionsFromPost($class_type = 0) + { + global $conf, $langs; + + $error = 0; + + $deprecation_options = array(); + foreach ($this->deprecation_options_fields as $mode_key => $mode_info) { + $this->setInfosForMode($mode_key, $class_type); + + foreach ($mode_info['fields'] as $field_key => $field_info) { + if (!empty($field_info['computed'])) { + continue; + } + + $html_name = $mode_key . '_' . $field_key; + if ($field_info['type'] == 'duration') { + if (GETPOST($html_name . 'hour') == '' && GETPOST($html_name . 'min') == '') { + continue; // The field was not submited to be saved + } + } else { + if (!GETPOSTISSET($html_name)) { + continue; // The field was not submited to be saved + } + } + // Ignore special fields + if (in_array($field_key, array('rowid', 'entity', 'import_key'))) { + continue; + } + if (in_array($field_key, array('date_creation', 'tms', 'fk_user_creat', 'fk_user_modif'))) { + if (!in_array(abs($field_info['visible']), array(1, 3))) { + continue; // Only 1 and 3 that are case to create + } + } + + // Set value to insert + if (in_array($field_info['type'], array('text', 'html'))) { + $value = GETPOST($html_name, 'restricthtml'); + } elseif ($field_info['type'] == 'date') { + $value = dol_mktime(12, 0, 0, GETPOST($html_name . 'month', 'int'), GETPOST($html_name . 'day', 'int'), GETPOST($html_name . 'year', 'int')); // for date without hour, we use gmt + } elseif ($field_info['type'] == 'datetime') { + $value = dol_mktime(GETPOST($html_name . 'hour', 'int'), GETPOST($html_name . 'min', 'int'), GETPOST($html_name . 'sec', 'int'), GETPOST($html_name . 'month', 'int'), GETPOST($html_name . 'day', 'int'), GETPOST($html_name . 'year', 'int'), 'tzuserrel'); + } elseif ($field_info['type'] == 'duration') { + $value = 60 * 60 * GETPOST($html_name . 'hour', 'int') + 60 * GETPOST($html_name . 'min', 'int'); + } elseif (preg_match('/^(integer|price|real|double)/', $field_info['type'])) { + $value = price2num(GETPOST($html_name, 'alphanohtml')); // To fix decimal separator according to lang setup + } elseif ($field_info['type'] == 'boolean') { + $value = ((GETPOST($html_name) == '1' || GETPOST($html_name) == 'on') ? 1 : 0); + } elseif ($field_info['type'] == 'reference') { + // todo to check + $tmparraykey = array(); //array_keys($object->param_list); + $value = $tmparraykey[GETPOST($html_name)] . ',' . GETPOST($html_name . '2'); + } else { + if ($field_key == 'lang') { + $value = GETPOST($html_name, 'aZ09') ? GETPOST($html_name, 'aZ09') : ""; + } else { + $value = GETPOST($html_name, 'alphanohtml'); + } + } + if (preg_match('/^integer:/i', $field_info['type']) && $value == '-1') { + $value = ''; // This is an implicit foreign key field + } + if (!empty($field_info['foreignkey']) && $value == '-1') { + $value = ''; // This is an explicit foreign key field + } + + //var_dump($field_key.' '.$value.' '.$field_info['type']); + $field_value = $value; + if ($field_info['notnull'] > 0 && $field_value == '' && !is_null($field_info['default']) && $field_info['default'] == '(PROV)') { + $field_value = '(PROV)'; + } elseif ((!empty($field_info['required']) || $field_info['notnull'] > 0) && $field_value == '' && !empty($field_info['default'])) { + $field_value = dol_eval($field_info['default'], 1); + } + if ($field_info['notnull'] > 0 && $field_value == '' && is_null($field_info['default'])) { + $error++; + setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv($field_info['label'])), null, 'errors'); + } + $deprecation_options[$mode_key][$field_key] = $field_value; + + // Validation of fields values + if ($conf->global->MAIN_FEATURE_LEVEL >= 2 || !empty($conf->global->MAIN_ACTIVATE_VALIDATION_RESULT)) { + if (!$error && !empty($field_info['validate']) && is_callable(array($this, 'validateField'))) { + if (!$this->validateField($mode_info['fields'], $field_key, $value)) { + $error++; + } + } + } + } + } + // Unset not enabled modes + foreach ($this->deprecation_options_fields as $mode_key => $mode_info) { + if (!empty($mode_info['enabled_field'])) { + $info = explode(':', $mode_info['enabled_field']); + if ($deprecation_options[$info[0]][$info[1]] != $info[2]) { + unset($deprecation_options[$info[0]][$info[1]]); + } + } + } + $this->deprecation_options = $deprecation_options; + + if ($error) { + return -1; + } else { + return 1; + } + } + + /** + * Load deprecation options of a asset or a asset model + * + * @param int $asset_id Asset ID to set + * @param int $asset_model_id Asset model ID to set + * @return int <0 if KO, >0 if OK + */ + public function fetchDeprecationOptions($asset_id = 0, $asset_model_id = 0) + { + global $langs, $hookmanager; + dol_syslog(__METHOD__ . " sset_id=$asset_id, asset_model_id=$asset_model_id"); + + $error = 0; + $this->errors = array(); + $this->deprecation_options = array(); + + // Clean parameters + $asset_id = $asset_id > 0 ? $asset_id : 0; + $asset_model_id = $asset_model_id > 0 ? $asset_model_id : 0; + + if (!is_object($hookmanager)) { + require_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php'; + $hookmanager = new HookManager($this->db); + } + + $hookmanager->initHooks(array('assetdepreciationoptionsdao')); + $parameters = array('asset_id' => $asset_id, 'asset_model_id' => $asset_model_id); + $reshook = $hookmanager->executeHooks('fetchDepreciationOptions', $parameters, $this); // Note that $action and $object may have been modified by some hooks + if (!empty($reshook)) { + return $reshook; + } + + // Check parameters + if (empty($asset_id) && empty($asset_model_id)) { + $this->errors[] = $langs->trans('AssetErrorAssetOrAssetModelIDNotProvide'); + $error++; + } + if ($error) { + dol_syslog(__METHOD__ . " Error check parameters: " . $this->errorsToString(), LOG_ERR); + return -1; + } + + $class_type = $asset_id > 0 ? 0 : 1; + $deprecation_options = array(); + foreach ($this->deprecation_options_fields as $mode_key => $mode_info) { + $this->setInfosForMode($mode_key, $class_type); + + $result = $this->fetchCommon(0, '', " AND " . ($asset_id > 0 ? " fk_asset = " . $asset_id : " fk_asset_model = " . $asset_model_id)); + if ($result < 0) { + $this->errors = array_merge(array($langs->trans('AssetErrorFetchDepreciationOptionsForMode', $mode_key) . ':'), $this->errors); + $error++; + } elseif ($result > 0) { + foreach ($this->fields as $field_key => $field_info) { + if (in_array($field_key, array('rowid', 'fk_asset', 'fk_asset_model', 'tms', 'fk_user_modif'))) continue; + $deprecation_options[$mode_key][$field_key] = $this->{$field_key}; + } + } + } + // Unset not enabled modes + foreach ($this->deprecation_options_fields as $mode_key => $mode_info) { + if (!empty($mode_info['enabled_field'])) { + $info = explode(':', $mode_info['enabled_field']); + if ($deprecation_options[$info[0]][$info[1]] != $info[2]) { + unset($deprecation_options[$info[0]][$info[1]]); + } + } + } + + if ($error) { + dol_syslog(__METHOD__ . " Error fetch accountancy codes: " . $this->errorsToString(), LOG_ERR); + return -1; + } else { + $this->deprecation_options = $deprecation_options; + return 1; + } + } + + /** + * get general depreciation info for a mode (used in depreciation card) + * + * @param string $mode Depreciation mode (economic, accelerated_depreciation, ...) + * @return array|int <0 if KO otherwise array with general depreciation info + */ + public function getGeneralDepreciationInfoForMode($mode) + { + global $hookmanager; + dol_syslog(__METHOD__ . " mode=$mode"); + + $this->errors = array(); + + // Clean parameters + $mode = strtolower(trim($mode)); + + if (!is_object($hookmanager)) { + require_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php'; + $hookmanager = new HookManager($this->db); + } + + $hookmanager->initHooks(array('assetdepreciationoptionsdao')); + $parameters = array('mode' => $mode); + $reshook = $hookmanager->executeHooks('getGeneralDepreciationInfoForMode', $parameters, $this); // Note that $action and $object may have been modified by some hooks + if ($reshook < 0) { + return $reshook; + } elseif ($reshook > 0) { + return $hookmanager->resArray; + } + + $duration_type_list = $this->deprecation_options_fields[$mode]['fields']['duration_type']['arrayofkeyval']; + + return array( + 'base_depreciation_ht' => $this->deprecation_options[$mode]['amount_base_depreciation_ht'], + 'duration' => $this->deprecation_options[$mode]['duration'], + 'duration_type' => $duration_type_list[$this->deprecation_options[$mode]['duration_type']], + 'rate' => $this->getRate($mode), + ); + } + + /** + * Update deprecation options of a asset or a asset model + * + * @param User $user User making update + * @param int $asset_id Asset ID to set + * @param int $asset_model_id Asset model ID to set + * @param int $notrigger 1=disable trigger UPDATE (when called by create) + * @return int <0 if KO, >0 if OK + */ + public function updateDeprecationOptions($user, $asset_id = 0, $asset_model_id = 0, $notrigger = 0) + { + global $langs, $hookmanager; + dol_syslog(__METHOD__ . " user_id={$user->id}, asset_id=$asset_id, asset_model_id=$asset_model_id, notrigger=$notrigger"); + + $error = 0; + $this->errors = array(); + + // Clean parameters + $asset_id = $asset_id > 0 ? $asset_id : 0; + $asset_model_id = $asset_model_id > 0 ? $asset_model_id : 0; + + if (!is_object($hookmanager)) { + require_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php'; + $hookmanager = new HookManager($this->db); + } + + $hookmanager->initHooks(array('assetdepreciationoptionsdao')); + $parameters = array('user' => $user, 'asset_id' => $asset_id, 'asset_model_id' => $asset_model_id); + $reshook = $hookmanager->executeHooks('updateDepreciationOptions', $parameters, $this); // Note that $action and $object may have been modified by some hooks + if (!empty($reshook)) { + return $reshook; + } + + // Check parameters + if (empty($asset_id) && empty($asset_model_id)) { + $this->errors[] = $langs->trans('AssetErrorAssetOrAssetModelIDNotProvide'); + $error++; + } + if ($error) { + dol_syslog(__METHOD__ . " Error check parameters: " . $this->errorsToString(), LOG_ERR); + return -1; + } + + $this->db->begin(); + + if ($asset_id > 0) { + $this->fk_asset = $asset_id; + $class_type = 0; + } else { + $this->fk_asset_model = $asset_model_id; + $class_type = 1; + } + $this->tms = dol_now(); + $this->fk_user_modif = $user->id; + + foreach ($this->deprecation_options_fields as $mode_key => $mode_info) { + // Delete old accountancy codes + $sql = "DELETE FROM " . MAIN_DB_PREFIX . $mode_info['table']; + $sql .= " WHERE " . ($asset_id > 0 ? " fk_asset = " . $asset_id : " fk_asset_model = " . $asset_model_id); + $resql = $this->db->query($sql); + if (!$resql) { + $this->errors[] = $langs->trans('AssetErrorDeleteDepreciationOptionsForMode', $mode_key) . ': ' . $this->db->lasterror(); + $error++; + } + + if (!$error && !empty($this->deprecation_options[$mode_key])) { + if (!empty($mode_info['enabled_field'])) { + $info = explode(':', $mode_info['enabled_field']); + if ($this->deprecation_options[$info[0]][$info[1]] != $info[2]) { + continue; + } + } + + $this->setInfosForMode($mode_key, $class_type); + + $result = $this->createCommon($user, 1); + if ($result < 0) { + $this->errors = array_merge(array($langs->trans('AssetErrorInsertDepreciationOptionsForMode', $mode_key) . ':'), $this->errors); + $error++; + } + } + } + + if (!$error && $this->fk_asset > 0) { + // Calculation of depreciation lines (reversal and future) + require_once DOL_DOCUMENT_ROOT . '/asset/class/asset.class.php'; + $asset = new Asset($this->db); + $result = $asset->fetch($this->fk_asset); + if ($result > 0) $result = $asset->calculationDepreciation(); + if ($result < 0) { + $this->errors[] = $langs->trans('AssetErrorCalculationDepreciationLines'); + $this->errors[] = $asset->errorsToString(); + $error++; + } + } + + if (!$error && !$notrigger) { + // Call trigger + $result = $this->call_trigger('ASSET_DEPRECIATION_OPTIONS_MODIFY', $user); + if ($result < 0) { + $error++; + } + // End call triggers + } + + if ($error) { + $this->db->rollback(); + return -1; + } else { + $this->db->commit(); + return 1; + } + } + + /** + * Get rate + * + * @param string $mode Depreciation mode (economic, accelerated_depreciation, ...) + * @return string Rate of the provided mode option + */ + public function getRate($mode) + { + $duration = $this->deprecation_options[$mode]["duration"] > 0 ? $this->deprecation_options[$mode]["duration"] : 0; + $duration_type = $this->deprecation_options[$mode]["duration_type"] > 0 ? $this->deprecation_options[$mode]["duration_type"] : 0; + + return price(price2num($duration > 0 ? (100 * ($duration_type == 1 ? 12 : 1) / $duration) : 0, 2)); + } +} diff --git a/htdocs/asset/class/assetmodel.class.php b/htdocs/asset/class/assetmodel.class.php new file mode 100644 index 00000000000..ec04bf75851 --- /dev/null +++ b/htdocs/asset/class/assetmodel.class.php @@ -0,0 +1,822 @@ + + * Copyright (C) 2021 Open-Dsi + * + * 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 + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file class/assetmodel.class.php + * \ingroup asset + * \brief This file is a CRUD class file for AssetModel (Create/Read/Update/Delete) + */ + +// Put here all includes required by your class file +require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php'; +//require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php'; +//require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php'; + +/** + * Class for AssetModel + */ +class AssetModel extends CommonObject +{ + /** + * @var string ID of module. + */ + public $module = 'asset'; + + /** + * @var string ID to identify managed object. + */ + public $element = 'assetmodel'; + + /** + * @var string Name of table without prefix where object is stored. This is also the key used for extrafields management. + */ + public $table_element = 'asset_model'; + + /** + * @var int Does this object support multicompany module ? + * 0=No test on entity, 1=Test with field entity, 'field@table'=Test with link by field@table + */ + public $ismultientitymanaged = 1; + + /** + * @var int Does object support extrafields ? 0=No, 1=Yes + */ + public $isextrafieldmanaged = 1; + + /** + * @var string String with name of icon for assetmodel. Must be the part after the 'object_' into object_assetmodel.png + */ + public $picto = 'asset'; + + + const STATUS_DRAFT = 0; + const STATUS_VALIDATED = 1; + const STATUS_CANCELED = 9; + + + /** + * 'type' field format ('integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter[:Sortfield]]]', 'sellist:TableName:LabelFieldName[:KeyFieldName[:KeyFieldParent[:Filter[:Sortfield]]]]', 'varchar(x)', 'double(24,8)', 'real', 'price', 'text', 'text:none', 'html', 'date', 'datetime', 'timestamp', 'duration', 'mail', 'phone', 'url', 'password') + * Note: Filter can be a string like "(t.ref:like:'SO-%') or (t.date_creation:<:'20160101') or (t.nature:is:NULL)" + * 'label' the translation key. + * 'picto' is code of a picto to show before value in forms + * 'enabled' is a condition when the field must be managed (Example: 1 or '$conf->global->MY_SETUP_PARAM) + * 'position' is the sort order of field. + * 'notnull' is set to 1 if not null in database. Set to -1 if we must set data to null if empty ('' or 0). + * 'visible' says if field is visible in list (Examples: 0=Not visible, 1=Visible on list and create/update/view forms, 2=Visible on list only, 3=Visible on create/update/view form only (not list), 4=Visible on list and update/view form only (not create). 5=Visible on list and view only (not create/not update). Using a negative value means field is not shown by default on list but can be selected for viewing) + * 'noteditable' says if field is not editable (1 or 0) + * 'default' is a default value for creation (can still be overwrote by the Setup of Default Values if field is editable in creation form). Note: If default is set to '(PROV)' and field is 'ref', the default value will be set to '(PROVid)' where id is rowid when a new record is created. + * 'index' if we want an index in database. + * 'foreignkey'=>'tablename.field' if the field is a foreign key (it is recommanded to name the field fk_...). + * 'searchall' is 1 if we want to search in this field when making a search from the quick search button. + * 'isameasure' must be set to 1 or 2 if field can be used for measure. Field type must be summable like integer or double(24,8). Use 1 in most cases, or 2 if you don't want to see the column total into list (for example for percentage) + * 'css' and 'cssview' and 'csslist' is the CSS style to use on field. 'css' is used in creation and update. 'cssview' is used in view mode. 'csslist' is used for columns in lists. For example: 'css'=>'minwidth300 maxwidth500 widthcentpercentminusx', 'cssview'=>'wordbreak', 'csslist'=>'tdoverflowmax200' + * 'help' is a 'TranslationString' to use to show a tooltip on field. You can also use 'TranslationString:keyfortooltiponlick' for a tooltip on click. + * 'showoncombobox' if value of the field must be visible into the label of the combobox that list record + * 'disabled' is 1 if we want to have the field locked by a 'disabled' attribute. In most cases, this is never set into the definition of $fields into class, but is set dynamically by some part of code. + * 'arrayofkeyval' to set a list of values if type is a list of predefined values. For example: array("0"=>"Draft","1"=>"Active","-1"=>"Cancel"). Note that type can be 'integer' or 'varchar' + * 'autofocusoncreate' to have field having the focus on a create form. Only 1 field should have this property set to 1. + * 'comment' is not used. You can store here any text of your choice. It is not used by application. + * 'validate' is 1 if need to validate with $this->validateField() + * 'copytoclipboard' is 1 or 2 to allow to add a picto to copy value into clipboard (1=picto after label, 2=picto after value) + * + * Note: To have value dynamic, you can set value to 0 in definition and edit the value on the fly into the constructor. + */ + + /** + * @var array Array with all fields and their property. Do not use it as a static var. It may be modified by constructor. + */ + 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, 'index'=>1, 'searchall'=>1, 'showoncombobox'=>'1', 'validate'=>'1'), + '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',), + 'asset_type' => array('type'=>'smallint', 'label'=>'AssetType', 'enabled'=>'1', 'position'=>40, 'notnull'=>1, 'visible'=>1, 'arrayofkeyval'=>array('0'=>'AssetTypeIntangible', '1'=>'AssetTypeTangible', '2'=>'AssetTypeInProgress', '3'=>'AssetTypeFinancial'), 'validate'=>'1',), + 'fk_pays' =>array('type'=>'integer:Ccountry:core/class/ccountry.class.php', 'label'=>'Country', 'enabled'=>1, 'visible'=>1, 'position'=>50), + 'note_public' => array('type'=>'html', 'label'=>'NotePublic', 'enabled'=>'1', 'position'=>300, 'notnull'=>0, 'visible'=>0, 'validate'=>'1',), + '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,), + '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,), + 'import_key' => array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>'1', 'position'=>1000, 'notnull'=>-1, 'visible'=>-2,), + 'status' => array('type'=>'smallint', 'label'=>'Status', 'enabled'=>'1', 'position'=>1000, 'notnull'=>1, 'default'=>'0', 'visible'=>2, 'index'=>1, 'arrayofkeyval'=>array('0'=>'Draft', '1'=>'Enabled', '9'=>'Disabled'), 'validate'=>'1',), + ); + public $rowid; + public $ref; + public $label; + public $asset_type; + public $note_public; + public $note_private; + public $date_creation; + public $tms; + public $fk_user_creat; + public $fk_user_modif; + public $last_main_doc; + public $import_key; + public $model_pdf; + public $status; + + // /** + // * @var string Field with ID of parent key if this object has a parent + // */ + // public $fk_element = 'fk_assetmodel'; + // /** + // * @var array List of child tables. To test if we can delete object. + // */ + // protected $childtables = array(); + // /** + // * @var array List of child tables. To know object to delete on cascade. + // * If name matches '@ClassNAme:FilePathClass;ParentFkFieldName' it will + // * call method deleteByParentField(parentId, ParentFkFieldName) to fetch and delete child object + // */ + // protected $childtablesoncascade = array('asset_assetmodeldet'); + + + /** + * Constructor + * + * @param DoliDb $db Database handler + */ + public function __construct(DoliDB $db) + { + global $conf, $langs; + + $this->db = $db; + + if (empty($conf->global->MAIN_SHOW_TECHNICAL_ID) && isset($this->fields['rowid'])) { + $this->fields['rowid']['visible'] = 0; + } + if (empty($conf->multicompany->enabled) && isset($this->fields['entity'])) { + $this->fields['entity']['enabled'] = 0; + } + + // Unset fields that are disabled + foreach ($this->fields as $key => $val) { + if (isset($val['enabled']) && empty($val['enabled'])) { + unset($this->fields[$key]); + } + } + + // Translate some data of arrayofkeyval + if (is_object($langs)) { + foreach ($this->fields as $key => $val) { + if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) { + foreach ($val['arrayofkeyval'] as $key2 => $val2) { + $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2); + } + } + } + } + } + + /** + * Create object into database + * + * @param User $user User that creates + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @return int <0 if KO, Id of created object if OK + */ + public function create(User $user, $notrigger = false) + { + $resultcreate = $this->createCommon($user, $notrigger); + + return $resultcreate; + } + + /** + * Clone an object into another one + * + * @param User $user User that creates + * @param int $fromid Id of object to clone + * @return mixed New object created, <0 if KO + */ + public function createFromClone(User $user, $fromid) + { + global $langs, $extrafields; + $error = 0; + + dol_syslog(__METHOD__, LOG_DEBUG); + + $object = new self($this->db); + + $this->db->begin(); + + // Load source object + $result = $object->fetchCommon($fromid); + if ($result > 0 && !empty($object->table_element_line)) { + $object->fetchLines(); + } + + // get lines so they will be clone + //foreach($this->lines as $line) + // $line->fetch_optionals(); + + // Reset some properties + unset($object->id); + unset($object->fk_user_creat); + unset($object->import_key); + + // Clear fields + if (property_exists($object, 'ref')) { + $object->ref = empty($this->fields['ref']['default']) ? "Copy_Of_".$object->ref : $this->fields['ref']['default']; + } + if (property_exists($object, 'label')) { + $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf")." ".$object->label : $this->fields['label']['default']; + } + if (property_exists($object, 'status')) { + $object->status = self::STATUS_DRAFT; + } + if (property_exists($object, 'date_creation')) { + $object->date_creation = dol_now(); + } + if (property_exists($object, 'date_modification')) { + $object->date_modification = null; + } + // ... + // Clear extrafields that are unique + if (is_array($object->array_options) && count($object->array_options) > 0) { + $extrafields->fetch_name_optionals_label($this->table_element); + foreach ($object->array_options as $key => $option) { + $shortkey = preg_replace('/options_/', '', $key); + if (!empty($extrafields->attributes[$this->table_element]['unique'][$shortkey])) { + //var_dump($key); var_dump($clonedObj->array_options[$key]); exit; + unset($object->array_options[$key]); + } + } + } + + // Create clone + $object->context['createfromclone'] = 'createfromclone'; + $result = $object->createCommon($user); + if ($result < 0) { + $error++; + $this->error = $object->error; + $this->errors = $object->errors; + } + + if (!$error) { + // copy internal contacts + if ($this->copy_linked_contact($object, 'internal') < 0) { + $error++; + } + } + + if (!$error) { + // copy external contacts if same company + if (property_exists($this, 'fk_soc') && $this->fk_soc == $object->socid) { + if ($this->copy_linked_contact($object, 'external') < 0) { + $error++; + } + } + } + + unset($object->context['createfromclone']); + + // End + if (!$error) { + $this->db->commit(); + return $object; + } else { + $this->db->rollback(); + return -1; + } + } + + /** + * Load object in memory from the database + * + * @param int $id Id object + * @param string $ref Ref + * @return int <0 if KO, 0 if not found, >0 if OK + */ + public function fetch($id, $ref = null) + { + $result = $this->fetchCommon($id, $ref); + if ($result > 0 && !empty($this->table_element_line)) { + $this->fetchLines(); + } + return $result; + } + + /** + * Load object lines in memory from the database + * + * @return int <0 if KO, 0 if not found, >0 if OK + */ + public function fetchLines() + { + $this->lines = array(); + + return 1; + } + + + /** + * Load list of objects in memory from the database. + * + * @param string $sortorder Sort Order + * @param string $sortfield Sort field + * @param int $limit limit + * @param int $offset Offset + * @param array $filter Filter array. Example array('field'=>'valueforlike', 'customurl'=>...) + * @param string $filtermode Filter mode (AND or OR) + * @return array|int int <0 if KO, array of pages if OK + */ + public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND') + { + global $conf; + + dol_syslog(__METHOD__, LOG_DEBUG); + + $records = array(); + + $sql = "SELECT "; + $sql .= $this->getFieldList('t'); + $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as t"; + if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) { + $sql .= " WHERE t.entity IN (".getEntity($this->table_element).")"; + } else { + $sql .= " WHERE 1 = 1"; + } + // Manage filter + $sqlwhere = array(); + if (count($filter) > 0) { + foreach ($filter as $key => $value) { + if ($key == 't.rowid') { + $sqlwhere[] = $key." = ".((int) $value); + } elseif (in_array($this->fields[$key]['type'], array('date', 'datetime', 'timestamp'))) { + $sqlwhere[] = $key." = '".$this->db->idate($value)."'"; + } elseif ($key == 'customsql') { + $sqlwhere[] = $value; + } elseif (strpos($value, '%') === false) { + $sqlwhere[] = $key." IN (".$this->db->sanitize($this->db->escape($value)).")"; + } else { + $sqlwhere[] = $key." LIKE '%".$this->db->escape($value)."%'"; + } + } + } + if (count($sqlwhere) > 0) { + $sql .= " AND (".implode(" ".$filtermode." ", $sqlwhere).")"; + } + + if (!empty($sortfield)) { + $sql .= $this->db->order($sortfield, $sortorder); + } + if (!empty($limit)) { + $sql .= $this->db->plimit($limit, $offset); + } + + $resql = $this->db->query($sql); + if ($resql) { + $num = $this->db->num_rows($resql); + $i = 0; + while ($i < ($limit ? min($limit, $num) : $num)) { + $obj = $this->db->fetch_object($resql); + + $record = new self($this->db); + $record->setVarsFromFetchObj($obj); + + $records[$record->id] = $record; + + $i++; + } + $this->db->free($resql); + + return $records; + } else { + $this->errors[] = 'Error '.$this->db->lasterror(); + dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR); + + return -1; + } + } + + /** + * Update object into database + * + * @param User $user User that modifies + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @return int <0 if KO, >0 if OK + */ + public function update(User $user, $notrigger = false) + { + return $this->updateCommon($user, $notrigger); + } + + /** + * Delete object in database + * + * @param User $user User that deletes + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @return int <0 if KO, >0 if OK + */ + public function delete(User $user, $notrigger = false) + { + return $this->deleteCommon($user, $notrigger); + //return $this->deleteCommon($user, $notrigger, 1); + } + + + /** + * Validate object + * + * @param User $user User making status change + * @param int $notrigger 1=Does not execute triggers, 0= execute triggers + * @return int <=0 if OK, 0=Nothing done, >0 if KO + */ + public function validate($user, $notrigger = 0) + { + global $conf, $langs; + + $error = 0; + + // Protection + if ($this->status == self::STATUS_VALIDATED) { + dol_syslog(get_class($this) . "::validate action abandonned: already validated", LOG_WARNING); + return 0; + } + + $now = dol_now(); + + $this->db->begin(); + + // Validate + $sql = "UPDATE " . MAIN_DB_PREFIX . $this->table_element; + $sql .= " SET status = " . self::STATUS_VALIDATED; + if (!empty($this->fields['date_validation'])) { + $sql .= ", date_validation = '" . $this->db->idate($now) . "'"; + } + if (!empty($this->fields['fk_user_valid'])) { + $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('ASSETMODEL_VALIDATE', $user); + if ($result < 0) { + $error++; + } + // End call triggers + } + + // Set new ref and current status + if (!$error) { + $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 $notrigger 1=Does not execute triggers, 0=Execute triggers + * @return int <0 if KO, >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, 'ASSETMODEL_UNVALIDATE'); + } + + /** + * Set cancel status + * + * @param User $user Object user that modify + * @param int $notrigger 1=Does not execute triggers, 0=Execute triggers + * @return int <0 if KO, 0=Nothing done, >0 if OK + */ + public function cancel($user, $notrigger = 0) + { + // Protection + if ($this->status != self::STATUS_VALIDATED) { + return 0; + } + + return $this->setStatusCommon($user, self::STATUS_CANCELED, $notrigger, 'ASSETMODEL_CANCEL'); + } + + /** + * Set back to validated status + * + * @param User $user Object user that modify + * @param int $notrigger 1=Does not execute triggers, 0=Execute triggers + * @return int <0 if KO, 0=Nothing done, >0 if OK + */ + public function reopen($user, $notrigger = 0) + { + // Protection + if ($this->status != self::STATUS_CANCELED) { + return 0; + } + + return $this->setStatusCommon($user, self::STATUS_VALIDATED, $notrigger, 'ASSETMODEL_REOPEN'); + } + + /** + * Return a link to the object card (with optionaly the picto) + * + * @param int $withpicto Include picto in link (0=No picto, 1=Include picto into link, 2=Only picto) + * @param string $option On what the link point to ('nolink', ...) + * @param int $notooltip 1=Disable tooltip + * @param string $morecss Add more css on link + * @param int $save_lastsearch_value -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking + * @return string String with URL + */ + public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1) + { + global $conf, $langs, $hookmanager; + + if (!empty($conf->dol_no_mouse_hover)) { + $notooltip = 1; // Force disable tooltips + } + + $result = ''; + + $label = img_picto('', $this->picto).' '.$langs->trans("AssetModel").''; + if (isset($this->status)) { + $label .= ' '.$this->getLibStatut(5); + } + $label .= '
    '; + $label .= ''.$langs->trans('Ref').': '.$this->ref; + + $url = dol_buildpath('/asset/model/card.php', 1).'?id='.$this->id; + + if ($option != 'nolink') { + // Add param to save lastsearch_values or not + $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0); + if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) { + $add_save_lastsearch_values = 1; + } + if ($add_save_lastsearch_values) { + $url .= '&save_lastsearch_values=1'; + } + } + + $linkclose = ''; + if (empty($notooltip)) { + if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) { + $label = $langs->trans("ShowAssetModel"); + $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"'; + } + $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"'; + $linkclose .= ' class="classfortooltip'.($morecss ? ' '.$morecss : '').'"'; + } else { + $linkclose = ($morecss ? ' class="'.$morecss.'"' : ''); + } + + if ($option == 'nolink') { + $linkstart = ''; + if ($option == 'nolink') { + $linkend = ''; + } else { + $linkend = ''; + } + + $result .= $linkstart; + + if (empty($this->showphoto_on_popup)) { + if ($withpicto) { + $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); + } + } else { + if ($withpicto) { + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + + list($class, $module) = explode('@', $this->picto); + $upload_dir = $conf->$module->multidir_output[$conf->entity]."/$class/".dol_sanitizeFileName($this->ref); + $filearray = dol_dir_list($upload_dir, "files"); + $filename = $filearray[0]['name']; + if (!empty($filename)) { + $pospoint = strpos($filearray[0]['name'], '.'); + + $pathtophoto = $class.'/'.$this->ref.'/thumbs/'.substr($filename, 0, $pospoint).'_mini'.substr($filename, $pospoint); + if (empty($conf->global->{strtoupper($module.'_'.$class).'_FORMATLISTPHOTOSASUSERS'})) { + $result .= '
    No photo
    '; + } else { + $result .= '
    No photo
    '; + } + + $result .= ''; + } else { + $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); + } + } + } + + if ($withpicto != 2) { + $result .= $this->ref; + } + + $result .= $linkend; + //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : ''); + + global $action, $hookmanager; + $hookmanager->initHooks(array('assetmodeldao')); + $parameters = array('id'=>$this->id, 'getnomurl'=>$result); + $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks + if ($reshook > 0) { + $result = $hookmanager->resPrint; + } else { + $result .= $hookmanager->resPrint; + } + + return $result; + } + + /** + * Return the label of the status + * + * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto + * @return string Label of status + */ + public function getLabelStatus($mode = 0) + { + return $this->LibStatut($this->status, $mode); + } + + /** + * Return the label of the status + * + * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto + * @return string Label of status + */ + public function getLibStatut($mode = 0) + { + return $this->LibStatut($this->status, $mode); + } + + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Return the status + * + * @param int $status Id status + * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto + * @return string Label of status + */ + public function LibStatut($status, $mode = 0) + { + // phpcs:enable + if (empty($this->labelStatus) || empty($this->labelStatusShort)) { + global $langs; + //$langs->load("asset@asset"); + $this->labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Draft'); + $this->labelStatus[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('Enabled'); + $this->labelStatus[self::STATUS_CANCELED] = $langs->transnoentitiesnoconv('Disabled'); + $this->labelStatusShort[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Draft'); + $this->labelStatusShort[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('Enabled'); + $this->labelStatusShort[self::STATUS_CANCELED] = $langs->transnoentitiesnoconv('Disabled'); + } + + $statusType = 'status'.$status; + //if ($status == self::STATUS_VALIDATED) $statusType = 'status1'; + if ($status == self::STATUS_CANCELED) { + $statusType = 'status6'; + } + + return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode); + } + + /** + * Load the info information in the object + * + * @param int $id Id of object + * @return void + */ + public function info($id) + { + $sql = "SELECT rowid, date_creation as datec, tms as datem,"; + $sql .= " fk_user_creat, fk_user_modif"; + $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as t"; + $sql .= " WHERE t.rowid = ".((int) $id); + + $result = $this->db->query($sql); + if ($result) { + if ($this->db->num_rows($result)) { + $obj = $this->db->fetch_object($result); + $this->id = $obj->rowid; + if ($obj->fk_user_author) { + $cuser = new User($this->db); + $cuser->fetch($obj->fk_user_author); + $this->user_creation = $cuser; + } + + if ($obj->fk_user_valid) { + $vuser = new User($this->db); + $vuser->fetch($obj->fk_user_valid); + $this->user_validation = $vuser; + } + + if ($obj->fk_user_cloture) { + $cluser = new User($this->db); + $cluser->fetch($obj->fk_user_cloture); + $this->user_cloture = $cluser; + } + + $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); + } else { + dol_print_error($this->db); + } + } + + /** + * Initialise object with example values + * Id must be 0 if object instance is a specimen + * + * @return void + */ + public function initAsSpecimen() + { + // Set here init that are not commonf fields + // $this->property1 = ... + // $this->property2 = ... + + $this->initAsSpecimenCommon(); + } + + /** + * Create an array of lines + * + * @return array|int array of lines if OK, <0 if KO + */ + public function getLinesArray() + { + $this->lines = array(); + + return $this->lines; + } + + /** + * Action executed by scheduler + * CAN BE A CRON TASK. In such a case, parameters come from the schedule job setup field 'Parameters' + * Use public function doScheduledJob($param1, $param2, ...) to get parameters + * + * @return int 0 if OK, <>0 if KO (this function is used also by cron so only 0 is OK) + */ + public function doScheduledJob() + { + global $conf, $langs; + + //$conf->global->SYSLOG_FILE = 'DOL_DATA_ROOT/dolibarr_mydedicatedlofile.log'; + + $error = 0; + $this->output = ''; + $this->error = ''; + + dol_syslog(__METHOD__, LOG_DEBUG); + + $now = dol_now(); + + $this->db->begin(); + + // ... + + $this->db->commit(); + + return $error; + } +} diff --git a/htdocs/asset/depreciation.php b/htdocs/asset/depreciation.php new file mode 100644 index 00000000000..8f3547d81fb --- /dev/null +++ b/htdocs/asset/depreciation.php @@ -0,0 +1,199 @@ + + * Copyright (C) 2018 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 + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/asset/depreciation.php + * \ingroup asset + * \brief Card with depreciation on Asset + */ + +require '../main.inc.php'; +require_once DOL_DOCUMENT_ROOT . '/core/lib/asset.lib.php'; +require_once DOL_DOCUMENT_ROOT . '/asset/class/asset.class.php'; +require_once DOL_DOCUMENT_ROOT . '/asset/class/assetdepreciationoptions.class.php'; + +// Load translation files required by the page +$langs->loadLangs(array("assets", "companies")); + +// Get parameters +$id = GETPOST('id', 'int'); +$ref = GETPOST('ref', 'alpha'); +$action = GETPOST('action', 'aZ09'); +$cancel = GETPOST('cancel', 'aZ09'); +$backtopage = GETPOST('backtopage', 'alpha'); + +// Initialize technical objects +$object = new Asset($db); +$assetdepreciationoptions = new AssetDepreciationOptions($db); +$extrafields = new ExtraFields($db); +$diroutputmassaction = $conf->asset->dir_output.'/temp/massgeneration/'.$user->id; +$hookmanager->initHooks(array('assetdepreciation', 'globalcard')); // Note that conf->hooks_modules contains array +// Fetch optionals attributes and labels +$extrafields->fetch_name_optionals_label($object->table_element); + +// Load object +include DOL_DOCUMENT_ROOT . '/core/actions_fetchobject.inc.php'; // Must be include, not include_once // Must be include, not include_once. Include fetch and fetch_thirdparty but not fetch_optionals +if ($id > 0 || !empty($ref)) { + $upload_dir = $conf->asset->multidir_output[$object->entity] . "/" . $object->id; +} + +// Security check (enable the most restrictive one) +if ($user->socid > 0) accessforbidden(); +$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +if (empty($conf->asset->enabled)) accessforbidden(); +if (!empty($object->not_depreciated)) accessforbidden(); + +$object->asset_depreciation_options = &$assetdepreciationoptions; +$result = $assetdepreciationoptions->fetchDeprecationOptions($object->id); +if ($result < 0) { + setEventMessages($assetdepreciationoptions->error, $assetdepreciationoptions->errors, 'errors'); +} +$result = $object->fetchDepreciationLines(); +if ($result < 0) { + setEventMessages($object->error, $object->errors, 'errors'); +} + + +/* + * Actions + */ + +$reshook = $hookmanager->executeHooks('doActions', array(), $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); +} +if (empty($reshook)) { +} + + +/* + * View + */ + +$form = new Form($db); + +$help_url = ''; +llxHeader('', $langs->trans('Asset'), $help_url); + +if ($id > 0 || !empty($ref)) { + $head = assetPrepareHead($object); + print dol_get_fiche_head($head, 'depreciation', $langs->trans("Asset"), -1, $object->picto); + + // Object card + // ------------------------------------------------------------ + $linkback = '' . $langs->trans("BackToList") . ''; + + $morehtmlref = '
    '; + $morehtmlref .= '
    '; + + dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref); + + print '
    '; + print '
    '; + print '
    '; + + print dol_get_fiche_end(); + + $parameters = array(); + $reshook = $hookmanager->executeHooks('listAssetDeprecation', $parameters, $object, $action); + print $hookmanager->resPrint; + if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + } elseif (empty($reshook)) { + $bookkeeping_icon = ''; + $future_icon = ''; + $now = dol_now(); + + foreach ($assetdepreciationoptions->deprecation_options_fields as $mode_key => $fields) { + $lines = $object->depreciation_lines[$mode_key]; + if (!empty($lines)) { + $mode_info = $assetdepreciationoptions->deprecation_options_fields[$mode_key]; + $depreciation_info = $assetdepreciationoptions->getGeneralDepreciationInfoForMode($mode_key); + + print load_fiche_titre($langs->trans($mode_info['label']), '', ''); + + // Depreciation general info + //--------------------------------- + print '
    '; + print '
    '; + print '
    '; + print '' . "\n"; + print ''; + print ''; + print '
    ' . $langs->trans('AssetBaseDepreciationHT') . '' . price($depreciation_info['base_depreciation_ht']) . '
    ' . $langs->trans('AssetDepreciationBeginDate') . '' . dol_print_date($object->date_start > $object->date_acquisition ? $object->date_start : $object->date_acquisition, 'day') . '
    '; + + // We close div and reopen for second column + print '
    '; + print '
    '; + + print '
    '; + print ''; + print ''; + print ''; + print '
    ' . $langs->trans('AssetDepreciationDuration') . '' . $depreciation_info['duration'] . ' ( ' . $depreciation_info['duration_type'] . ' )
    ' . $langs->trans('AssetDepreciationRate') . '' . $depreciation_info['rate'] . '
    '; + print '
    '; + print '
    '; + print '
    '; + + // Depreciation lines + //--------------------------------- + print '
    '; + print '
    '; + print ''; + + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + + if (empty($lines)) { + print ''; + } else { + foreach ($lines as $line) { + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print "\n"; + } + } + + print '
    ' . $langs->trans("Ref") . '' . $langs->trans("AssetDepreciationDate") . '' . $langs->trans("AssetDepreciationHT") . '' . $langs->trans("AssetCumulativeDepreciationHT") . '' . $langs->trans("AssetResidualHT") . '
    ' . $langs->trans("None") . '
    ' . ($line['bookkeeping'] ? $bookkeeping_icon : ($line['depreciation_date'] > $now ? $future_icon : '')) . '' . (empty($line['ref']) ? $langs->trans('AssetDepreciationReversal') : $line['ref']) . '' . dol_print_date($line['depreciation_date'], 'day') . ''; + print price($line['depreciation_ht']); + print ''; + print price($line['cumulative_depreciation_ht']); + print ''; + print price(price2num($depreciation_info['base_depreciation_ht'] - $line['cumulative_depreciation_ht'], 'MT')); + print '
    '; + print '
    '; + } + } + } +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/asset/depreciation_options.php b/htdocs/asset/depreciation_options.php new file mode 100644 index 00000000000..ba5719705dc --- /dev/null +++ b/htdocs/asset/depreciation_options.php @@ -0,0 +1,190 @@ + + * Copyright (C) 2018 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 + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/asset/depreciation_options.php + * \ingroup asset + * \brief Card with depreciation options on Asset + */ + +require '../main.inc.php'; +require_once DOL_DOCUMENT_ROOT . '/core/lib/asset.lib.php'; +require_once DOL_DOCUMENT_ROOT . '/asset/class/asset.class.php'; +require_once DOL_DOCUMENT_ROOT . '/asset/class/assetdepreciationoptions.class.php'; + +// Load translation files required by the page +$langs->loadLangs(array("assets", "companies")); + +// Get parameters +$id = GETPOST('id', 'int'); +$ref = GETPOST('ref', 'alpha'); +$action = GETPOST('action', 'aZ09'); +$cancel = GETPOST('cancel', 'aZ09'); +$backtopage = GETPOST('backtopage', 'alpha'); + +// Initialize technical objects +$object = new Asset($db); +$assetdepreciationoptions = new AssetDepreciationOptions($db); +$extrafields = new ExtraFields($db); +$diroutputmassaction = $conf->asset->dir_output.'/temp/massgeneration/'.$user->id; +$hookmanager->initHooks(array('assetdepreciationoptions', 'globalcard')); // Note that conf->hooks_modules contains array +// Fetch optionals attributes and labels +$extrafields->fetch_name_optionals_label($object->table_element); + +// Load object +include DOL_DOCUMENT_ROOT . '/core/actions_fetchobject.inc.php'; // Must be include, not include_once // Must be include, not include_once. Include fetch and fetch_thirdparty but not fetch_optionals +if ($id > 0 || !empty($ref)) { + $upload_dir = $conf->asset->multidir_output[$object->entity] . "/" . $object->id; +} + +$permissiontoadd = $user->rights->asset->write; // Used by the include of actions_addupdatedelete.inc.php + +// Security check (enable the most restrictive one) +if ($user->socid > 0) accessforbidden(); +$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +if (empty($conf->asset->enabled)) accessforbidden(); +if (!empty($object->not_depreciated)) accessforbidden(); + +$object->asset_depreciation_options = &$assetdepreciationoptions; +$result = $assetdepreciationoptions->fetchDeprecationOptions($object->id); +if ($result < 0) { + setEventMessages($assetdepreciationoptions->error, $assetdepreciationoptions->errors, 'errors'); +} + + +/* + * Actions + */ + +$reshook = $hookmanager->executeHooks('doActions', array(), $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); +} +if (empty($reshook)) { + $backurlforlist = DOL_URL_ROOT.'/asset/list.php'; + + if (empty($backtopage) || ($cancel && empty($id))) { + if (empty($backtopage) || ($cancel && strpos($backtopage, '__ID__'))) { + if (empty($id) && (($action != 'add' && $action != 'create') || $cancel)) { + $backtopage = $backurlforlist; + } else { + $backtopage = DOL_URL_ROOT.'/asset/depreciation_options.php?id='.((!empty($id) && $id > 0) ? $id : '__ID__'); + } + } + } + + if ($cancel) { + /*var_dump($cancel);var_dump($backtopage);var_dump($backtopageforcancel);exit;*/ + if (!empty($backtopageforcancel)) { + header("Location: ".$backtopageforcancel); + exit; + } elseif (!empty($backtopage)) { + header("Location: ".$backtopage); + exit; + } + $action = ''; + } + + if ($action == "update") { + $result = $assetdepreciationoptions->setDeprecationOptionsFromPost(); + if ($result > 0) $result = $assetdepreciationoptions->updateDeprecationOptions($user, $object->id); + if ($result < 0) { + setEventMessages($assetdepreciationoptions->error, $assetdepreciationoptions->errors, 'errors'); + $action = 'edit'; + } else { + setEventMessage($langs->trans('RecordSaved')); + header("Location: " . $_SERVER["PHP_SELF"] . '?id=' . $object->id); + exit; + } + } +} + + +/* + * View + */ + +$form = new Form($db); + +$help_url = ''; +llxHeader('', $langs->trans('Asset'), $help_url); + +if ($id > 0 || !empty($ref)) { + $head = assetPrepareHead($object); + print dol_get_fiche_head($head, 'depreciation_options', $langs->trans("Asset"), -1, $object->picto); + + // Object card + // ------------------------------------------------------------ + $linkback = ''.$langs->trans("BackToList").''; + + $morehtmlref = '
    '; + $morehtmlref .= '
    '; + + dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref); + + print '
    '; + print '
    '; + print '
    '; + + if ($action == 'edit') { + print ''; + print ''; + print ''; + if ($backtopage) { + print ''; + } + if ($backtopageforcancel) { + print ''; + } + + print dol_get_fiche_head(array(), ''); + + include DOL_DOCUMENT_ROOT . '/asset/tpl/depreciation_options_edit.tpl.php'; + + print dol_get_fiche_end(); + + print $form->buttonsSaveCancel(); + + print ''; + } else { + include DOL_DOCUMENT_ROOT . '/asset/tpl/depreciation_options_view.tpl.php'; + } + + print dol_get_fiche_end(); + + if ($action != 'edit') { + print '
    ' . "\n"; + $parameters = array(); + $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook + if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + } + + if (empty($reshook)) { + if ($object->status == $object::STATUS_DRAFT/* && !empty($object->enabled_modes)*/) { + print dolGetButtonAction($langs->trans('Modify'), '', 'default', $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=edit&token=' . newToken(), '', $permissiontoadd); + } + } + print '
    ' . "\n"; + } +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/asset/disposal.php b/htdocs/asset/disposal.php new file mode 100644 index 00000000000..7fddb92b05f --- /dev/null +++ b/htdocs/asset/disposal.php @@ -0,0 +1,120 @@ + + * Copyright (C) 2018 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 + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/asset/disposal.php + * \ingroup asset + * \brief Card with disposal info on Asset + */ + +require '../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/asset.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/asset/class/asset.class.php'; + +// Load translation files required by the page +$langs->loadLangs(array("assets", "companies")); + +// Get parameters +$id = GETPOST('id', 'int'); +$ref = GETPOST('ref', 'alpha'); +$action = GETPOST('action', 'aZ09'); +$cancel = GETPOST('cancel', 'aZ09'); +$backtopage = GETPOST('backtopage', 'alpha'); + +// Initialize technical objects +$object = new Asset($db); +$extrafields = new ExtraFields($db); +$diroutputmassaction = $conf->asset->dir_output.'/temp/massgeneration/'.$user->id; +$hookmanager->initHooks(array('assetdisposal', 'globalcard')); // Note that conf->hooks_modules contains array +// Fetch optionals attributes and labels +$extrafields->fetch_name_optionals_label($object->table_element); + +// Load object +include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be include, not include_once // Must be include, not include_once. Include fetch and fetch_thirdparty but not fetch_optionals +if ($id > 0 || !empty($ref)) { + $upload_dir = $conf->asset->multidir_output[$object->entity]."/".$object->id; +} + +$permissionnote = $user->rights->asset->write; // Used by the include of actions_setnotes.inc.php +$permissiontoadd = $user->rights->asset->write; // Used by the include of actions_addupdatedelete.inc.php + +// Security check (enable the most restrictive one) +if ($user->socid > 0) accessforbidden(); +$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +if (empty($conf->asset->enabled)) accessforbidden(); +if (!isset($object->disposal_date) || $object->disposal_date === "") accessforbidden(); + + +/* + * Actions + */ + +$reshook = $hookmanager->executeHooks('doActions', array(), $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); +} +if (empty($reshook)) { +} + + +/* + * View + */ + +$form = new Form($db); + +$help_url = ''; +llxHeader('', $langs->trans('Asset'), $help_url); + +if ($id > 0 || !empty($ref)) { + $object->fetch_thirdparty(); + + $head = assetPrepareHead($object); + + print dol_get_fiche_head($head, 'disposal', $langs->trans("Asset"), -1, $object->picto); + + // Object card + // ------------------------------------------------------------ + $linkback = '' . $langs->trans("BackToList") . ''; + + $morehtmlref = '
    '; + $morehtmlref .= '
    '; + + dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref); + + print '
    '; + print '
    '; + print ''."\n"; + + // Common attributes + $show_fields = array('disposal_date', 'disposal_amount_ht', 'fk_disposal_type', 'disposal_depreciated', 'disposal_subject_to_vat'); + foreach ($object->fields as $field_key => $field_info) { + $object->fields[$field_key]['visible'] = in_array($field_key, $show_fields) ? 1 : 0; + } + include DOL_DOCUMENT_ROOT.'/core/tpl/commonfields_view.tpl.php'; + + print '
    '; + print '
    '; + + print dol_get_fiche_end(); +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/asset/document.php b/htdocs/asset/document.php index 9d46e9ae0b6..c3f04feab91 100644 --- a/htdocs/asset/document.php +++ b/htdocs/asset/document.php @@ -31,19 +31,18 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; // Load translation files required by the page -$langs->loadLangs(array('assets', 'companies', 'other')); +$langs->loadLangs(array('assets', 'companies', 'other', 'mails')); -$id = (GETPOST('id', 'int') ?GETPOST('id', 'int') : GETPOST('facid', 'int')); // For backward compatibility -$ref = GETPOST('ref', 'alpha'); -$socid = GETPOST('socid', 'int'); $action = GETPOST('action', 'aZ09'); $confirm = GETPOST('confirm', 'alpha'); +$id = GETPOST('id', 'int'); +$ref = GETPOST('ref', 'alpha'); // Get parameters $limit = GETPOST('limit', 'int') ? GETPOST('limit', 'int') : $conf->liste_limit; -$sortfield = GETPOST('sortfield', 'aZ09comma'); -$sortorder = GETPOST('sortorder', 'aZ09comma'); +$sortfield = GETPOST("sortfield", 'alpha'); +$sortorder = GETPOST("sortorder", 'alpha'); $page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int'); if (empty($page) || $page == -1) { $page = 0; @@ -58,18 +57,28 @@ if (!$sortfield) { $sortfield = "name"; } +// Initialize technical objects $object = new Asset($db); -if ($object->fetch($id)) { - $upload_dir = $conf->asset->dir_output."/".dol_sanitizeFileName($object->ref); +$extrafields = new ExtraFields($db); +$diroutputmassaction = $conf->asset->dir_output.'/temp/massgeneration/'.$user->id; +$hookmanager->initHooks(array('assetdocument', 'globalcard')); // Note that conf->hooks_modules contains array +// Fetch optionals attributes and labels +$extrafields->fetch_name_optionals_label($object->table_element); + +// Load object +include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be include, not include_once // Must be include, not include_once. Include fetch and fetch_thirdparty but not fetch_optionals + +if ($id > 0 || !empty($ref)) { + $upload_dir = $conf->asset->multidir_output[$object->entity ? $object->entity : $conf->entity]."/".get_exdir(0, 0, 0, 1, $object); } -$permissiontoadd = $user->rights->asset->write; // Used by the include of actions_addupdatedelete.inc.php and actions_linkedfiles.inc.php +$permissiontoadd = $user->rights->asset->asset->write; // Used by the include of actions_addupdatedelete.inc.php and actions_linkedfiles.inc.php -// Security check -if ($user->socid) { - $socid = $user->socid; -} -$result=restrictedArea($user, 'asset', $id, ''); +// Security check (enable the most restrictive one) +if ($user->socid > 0) accessforbidden(); +$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +if (empty($conf->asset->enabled)) accessforbidden(); /* @@ -83,60 +92,67 @@ include DOL_DOCUMENT_ROOT.'/core/actions_linkedfiles.inc.php'; * View */ -$title = $langs->trans('Assets')." - ".$langs->trans('Documents'); - -$help_url = ''; - -llxHeader('', $title, $help_url); - $form = new Form($db); +$title = $langs->trans("Asset").' - '.$langs->trans("Files"); +$help_url = ''; +llxHeader('', $title, $help_url); + +if ($object->id) { + /* + * Show tabs + */ + $head = assetPrepareHead($object); + + print dol_get_fiche_head($head, 'document', $langs->trans("Asset"), -1, $object->picto); -if ($id > 0 || !empty($ref)) { - if ($object->fetch($id, $ref) > 0) { - $upload_dir = $conf->asset->multidir_output[$object->entity].'/'.dol_sanitizeFileName($object->ref); - - $head = asset_prepare_head($object); - print dol_get_fiche_head($head, 'documents', $langs->trans('Asset'), -1, 'accounting'); - - // Build file list - $filearray = dol_dir_list($upload_dir, "files", 0, '', '(\.meta|_preview.*\.png)$', $sortfield, (strtolower($sortorder) == 'desc' ?SORT_DESC:SORT_ASC), 1); - $totalsize = 0; - foreach ($filearray as $key => $file) { - $totalsize += $file['size']; - } - - // Asset content - - $linkback = ''.$langs->trans("BackToList").''; - - $morehtmlref = ''; - dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref, '', 0); - - print '
    '; - print '
    '; - - print ''; - - print ''; - print ''; - print "
    '.$langs->trans("NbOfAttachedFiles").''.count($filearray).'
    '.$langs->trans("TotalSizeOfAttachedFiles").''.dol_print_size($totalsize, 1, 1).'
    \n"; - - print "
    \n"; - - print dol_get_fiche_end(); - - $modulepart = 'asset'; - $permissiontoadd = $user->rights->asset->write; - $permtoedit = $user->rights->asset->write; - $param = '&id='.$object->id; - include DOL_DOCUMENT_ROOT.'/core/tpl/document_actions_post_headers.tpl.php'; - } else { - dol_print_error($db); + // Build file list + $filearray = dol_dir_list($upload_dir, "files", 0, '', '(\.meta|_preview.*\.png)$', $sortfield, (strtolower($sortorder) == 'desc' ? SORT_DESC : SORT_ASC), 1); + $totalsize = 0; + foreach ($filearray as $key => $file) { + $totalsize += $file['size']; } + + // Object card + // ------------------------------------------------------------ + $linkback = '' . $langs->trans("BackToList") . ''; + + $morehtmlref = '
    '; + $morehtmlref .= '
    '; + + dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref); + + print '
    '; + + print '
    '; + print ''; + + // Number of files + print ''; + + // Total size + print ''; + + print '
    ' . $langs->trans("NbOfAttachedFiles") . '' . count($filearray) . '
    ' . $langs->trans("TotalSizeOfAttachedFiles") . '' . $totalsize . ' ' . $langs->trans("bytes") . '
    '; + + print '
    '; + + print dol_get_fiche_end(); + + $modulepart = 'asset'; + $permissiontoadd = $user->rights->asset->write; +// $permissiontoadd = 1; + $permtoedit = $user->rights->asset->write; +// $permtoedit = 1; + $param = '&id=' . $object->id; + + //$relativepathwithnofile='asset/' . dol_sanitizeFileName($object->id).'/'; + $relativepathwithnofile = dol_sanitizeFileName($object->ref) . '/'; + + include DOL_DOCUMENT_ROOT . '/core/tpl/document_actions_post_headers.tpl.php'; } else { - print $langs->trans("ErrorUnknown"); + accessforbidden('', 0, 1); } // End of page diff --git a/htdocs/asset/info.php b/htdocs/asset/info.php deleted file mode 100644 index 7a8f4c20ce2..00000000000 --- a/htdocs/asset/info.php +++ /dev/null @@ -1,93 +0,0 @@ - - * - * 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 - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** - * \file htdocs/asset/info.php - * \ingroup asset - * \brief Page to show an asset information - */ - -require '../main.inc.php'; -require_once DOL_DOCUMENT_ROOT.'/core/lib/asset.lib.php'; -require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; -require_once DOL_DOCUMENT_ROOT.'/asset/class/asset.class.php'; - -// Load translation files required by the page -$langs->loadLangs(array("asset")); - -$id = GETPOSTINT('id'); -$ref = GETPOST('ref', 'alpha'); -$action = GETPOST('action', 'aZ09'); - -// Security check -if ($user->socid) { - $socid = $user->socid; -} -$result = restrictedArea($user, 'asset', $id); - -$object = new Asset($db); -$object->fetch($id); - - -/* - * Actions - */ - -// None - - -/* - * View - */ - -$form = new Form($db); - -$title = $langs->trans('Asset')." - ".$langs->trans('Info'); - -$help_url = ""; - -llxHeader('', $title, $help_url); - -$object->info($id); - -$head = asset_prepare_head($object); - -print dol_get_fiche_head($head, 'info', $langs->trans("Asset"), -1, 'generic'); - -$linkback = ''.$langs->trans("BackToList").''; - -$morehtmlref = '
    '; -$morehtmlref .= '
    '; - -dol_banner_tab($object, 'rowid', $linkback, 1, 'rowid', 'ref', $morehtmlref); - -print '
    '; -print '
    '; - -print '
    '; - -print '
    '; -dol_print_object_info($object); -print '
    '; - -print '
    '; - -print dol_get_fiche_end(); - -// End of page -llxFooter(); -$db->close(); diff --git a/htdocs/asset/list.php b/htdocs/asset/list.php index 1abdabd333e..c475e22fc83 100644 --- a/htdocs/asset/list.php +++ b/htdocs/asset/list.php @@ -31,26 +31,26 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; require_once DOL_DOCUMENT_ROOT.'/asset/class/asset.class.php'; // Load translation files required by the page -$langs->loadLangs(array("assets")); +$langs->loadLangs(array("assets", "other")); -$action = GETPOST('action', 'aZ09') ?GETPOST('action', 'aZ09') : 'view'; // The action 'add', 'create', 'edit', 'update', 'view', ... -$massaction = GETPOST('massaction', 'alpha'); // The bulk action (combo box choice into lists) -$show_files = GETPOST('show_files', 'int'); // Show files area generated by bulk actions ? -$confirm = GETPOST('confirm', 'alpha'); // Result of a confirmation -$cancel = GETPOST('cancel', 'alpha'); // We click on a Cancel button -$toselect = GETPOST('toselect', 'array'); // Array of ids of elements selected into a list -$contextpage = GETPOST('contextpage', 'aZ') ?GETPOST('contextpage', 'aZ') : 'assetlist'; // To manage different context of search -$backtopage = GETPOST('backtopage', 'alpha'); // Go back to a dedicated page -$optioncss = GETPOST('optioncss', 'aZ'); // Option for the css output (always '' except when 'print') +$action = GETPOST('action', 'aZ09') ?GETPOST('action', 'aZ09') : 'view'; // The action 'add', 'create', 'edit', 'update', 'view', ... +$massaction = GETPOST('massaction', 'alpha'); // The bulk action (combo box choice into lists) +$show_files = GETPOST('show_files', 'int'); // Show files area generated by bulk actions ? +$confirm = GETPOST('confirm', 'alpha'); // Result of a confirmation +$cancel = GETPOST('cancel', 'alpha'); // We click on a Cancel button +$toselect = GETPOST('toselect', 'array'); // Array of ids of elements selected into a list +$contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : 'assetlist'; // To manage different context of search +$backtopage = GETPOST('backtopage', 'alpha'); // Go back to a dedicated page +$optioncss = GETPOST('optioncss', 'aZ'); // Option for the css output (always '' except when 'print') $id = GETPOST('id', 'int'); // Load variable for pagination -$limit = GETPOST('limit', 'int') ?GETPOST('limit', 'int') : $conf->liste_limit; +$limit = GETPOST('limit', 'int') ? GETPOST('limit', 'int') : $conf->liste_limit; $sortfield = GETPOST('sortfield', 'aZ09comma'); $sortorder = GETPOST('sortorder', 'aZ09comma'); $page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int'); -if (empty($page) || $page == -1 || GETPOST('button_search', 'alpha') || GETPOST('button_removefilter', 'alpha') || (empty($toselect) && $massaction === '0')) { +if (empty($page) || $page < 0 || GETPOST('button_search', 'alpha') || GETPOST('button_removefilter', 'alpha') || (empty($toselect) && $massaction === '0')) { $page = 0; } // If $page is not defined, or '' or -1 or if we click on clear filters or if we select empty mass action $offset = $limit * $page; @@ -71,33 +71,24 @@ $search_array_options = $extrafields->getOptionalsFromPost($object->table_elemen // Default sort order (if not yet defined by previous GETPOST) if (!$sortfield) { + reset($object->fields); // Reset is required to avoid key() to return null. $sortfield = "t.".key($object->fields); // Set here default search field. By default 1st field in definition. } if (!$sortorder) { $sortorder = "ASC"; } -// Security check -$socid = 0; -if ($user->socid) { - $socid = $user->socid; -} -if ($user->socid > 0) { - // Protection if external user - //$socid = $user->socid; - accessforbidden(); -} -// Security check -$result = restrictedArea($user, 'asset', $id); - - // Initialize array of search criterias -$search_all = GETPOST("search_all", 'alpha'); +$search_all = GETPOST('search_all', 'alphanohtml'); $search = array(); foreach ($object->fields as $key => $val) { if (GETPOST('search_'.$key, 'alpha') !== '') { $search[$key] = GETPOST('search_'.$key, 'alpha'); } + if (preg_match('/^(date|timestamp|datetime)/', $val['type'])) { + $search[$key.'_dtstart'] = dol_mktime(0, 0, 0, GETPOST('search_'.$key.'_dtstartmonth', 'int'), GETPOST('search_'.$key.'_dtstartday', 'int'), GETPOST('search_'.$key.'_dtstartyear', 'int')); + $search[$key.'_dtend'] = dol_mktime(23, 59, 59, GETPOST('search_'.$key.'_dtendmonth', 'int'), GETPOST('search_'.$key.'_dtendday', 'int'), GETPOST('search_'.$key.'_dtendyear', 'int')); + } } // List of fields to search into when doing a "search in all" @@ -108,27 +99,24 @@ foreach ($object->fields as $key => $val) { } } -// Definition of fields for list +// Definition of array of fields for columns $arrayfields = array(); foreach ($object->fields as $key => $val) { // If $val['visible']==0, then we never show the field if (!empty($val['visible'])) { - $arrayfields['t.'.$key] = array('label'=>$val['label'], 'checked'=>(($val['visible'] < 0) ? 0 : 1), 'enabled'=>($val['enabled'] && ($val['visible'] != 3)), 'position'=>$val['position']); + $visible = (int) dol_eval($val['visible'], 1); + $arrayfields['t.'.$key] = array( + 'label'=>$val['label'], + 'checked'=>(($visible < 0) ? 0 : 1), + 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)), + 'position'=>$val['position'], + 'help'=> isset($val['help']) ? $val['help'] : '' + ); } } // Extra fields -if (is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label']) > 0) { - foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) { - if (!empty($extrafields->attributes[$object->table_element]['list'][$key])) { - $arrayfields["ef.".$key] = array( - 'label'=>$extrafields->attributes[$object->table_element]['label'][$key], - 'checked'=>(($extrafields->attributes[$object->table_element]['list'][$key] < 0) ? 0 : 1), - 'position'=>$extrafields->attributes[$object->table_element]['pos'][$key], - 'enabled'=>(abs($extrafields->attributes[$object->table_element]['list'][$key]) != 3 && $extrafields->attributes[$object->table_element]['perms'][$key]) - ); - } - } -} +include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_array_fields.tpl.php'; + $object->fields = dol_sort_array($object->fields, 'position'); $arrayfields = dol_sort_array($arrayfields, 'position'); @@ -136,13 +124,28 @@ $permissiontoread = $user->rights->asset->read; $permissiontoadd = $user->rights->asset->write; $permissiontodelete = $user->rights->asset->delete; +// Security check +if (empty($conf->asset->enabled)) { + accessforbidden('Module not enabled'); +} + +// Security check (enable the most restrictive one) +if ($user->socid > 0) accessforbidden(); +$socid = 0; if ($user->socid > 0) $socid = $user->socid; +$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +if (empty($conf->asset->enabled)) accessforbidden(); +if (!$permissiontoread) accessforbidden(); + + /* * Actions */ if (GETPOST('cancel', 'alpha')) { - $action = 'list'; $massaction = ''; + $action = 'list'; + $massaction = ''; } if (!GETPOST('confirmmassaction', 'alpha') && $massaction != 'presend' && $massaction != 'confirm_presend') { $massaction = ''; @@ -162,8 +165,12 @@ if (empty($reshook)) { if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // All tests are required to be compatible with all browsers foreach ($object->fields as $key => $val) { $search[$key] = ''; + if (preg_match('/^(date|timestamp|datetime)/', $val['type'])) { + $search[$key.'_dtstart'] = ''; + $search[$key.'_dtend'] = ''; + } } - $toselect = ''; + $toselect = array(); $search_array_options = array(); } if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha') @@ -188,21 +195,20 @@ $form = new Form($db); $now = dol_now(); -//$help_url="EN:Module_Asset|FR:Module_Asset_FR|ES:Módulo_Asset"; $help_url = ''; $title = $langs->trans('ListOf', $langs->transnoentitiesnoconv("Assets")); +$morejs = array(); +$morecss = array(); // Build and execute select // -------------------------------------------------------------------- $sql = 'SELECT '; -foreach ($object->fields as $key => $val) { - $sql .= "t.".$key.", "; -} +$sql .= $object->getFieldList('t'); // Add fields from extrafields if (!empty($extrafields->attributes[$object->table_element]['label'])) { foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) { - $sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? "ef.".$key." as options_".$key.', ' : ''); + $sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? ", ef.".$key." as options_".$key : ''); } } // Add fields from hooks @@ -211,27 +217,45 @@ $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters, $obje $sql .= preg_replace('/^,/', '', $hookmanager->resPrint); $sql = preg_replace('/,\s*$/', '', $sql); $sql .= " FROM ".MAIN_DB_PREFIX.$object->table_element." as t"; -if (is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label'])) { +if (isset($extrafields->attributes[$object->table_element]['label']) && is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label'])) { $sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$object->table_element."_extrafields as ef on (t.rowid = ef.fk_object)"; } +// Add table from hooks +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldListFrom', $parameters, $object); // Note that $action and $object may have been modified by hook +$sql .= $hookmanager->resPrint; if ($object->ismultientitymanaged == 1) { $sql .= " WHERE t.entity IN (".getEntity($object->element).")"; } else { $sql .= " WHERE 1 = 1"; } foreach ($search as $key => $val) { - if ($key == 'status' && $search[$key] == -1) { - continue; - } - $mode_search = (($object->isInt($object->fields[$key]) || $object->isFloat($object->fields[$key])) ? 1 : 0); - if (strpos($object->fields[$key]['type'], 'integer:') === 0) { - if ($search[$key] == '-1') { - $search[$key] = ''; + if (array_key_exists($key, $object->fields)) { + if ($key == 'status' && $search[$key] == -1) { + continue; + } + $mode_search = (($object->isInt($object->fields[$key]) || $object->isFloat($object->fields[$key])) ? 1 : 0); + if ((strpos($object->fields[$key]['type'], 'integer:') === 0) || (strpos($object->fields[$key]['type'], 'sellist:') === 0) || !empty($object->fields[$key]['arrayofkeyval'])) { + if ($search[$key] == '-1' || ($search[$key] === '0' && (empty($object->fields[$key]['arrayofkeyval']) || !array_key_exists('0', $object->fields[$key]['arrayofkeyval'])))) { + $search[$key] = ''; + } + $mode_search = 2; + } + if ($search[$key] != '') { + $sql .= natural_search($key, $search[$key], (($key == 'status') ? 2 : $mode_search)); + } + } else { + if (preg_match('/(_dtstart|_dtend)$/', $key) && $search[$key] != '') { + $columnName = preg_replace('/(_dtstart|_dtend)$/', '', $key); + if (preg_match('/^(date|timestamp|datetime)/', $object->fields[$columnName]['type'])) { + if (preg_match('/_dtstart$/', $key)) { + $sql .= " AND t.".$columnName." >= '".$db->idate($search[$key])."'"; + } + if (preg_match('/_dtend$/', $key)) { + $sql .= " AND t." . $columnName . " <= '" . $db->idate($search[$key]) . "'"; + } + } } - $mode_search = 2; - } - if ($search[$key] != '') { - $sql .= natural_search($key, $search[$key], (($key == 'status') ? 2 : $mode_search)); } } if ($search_all) { @@ -246,51 +270,69 @@ $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $objec $sql .= $hookmanager->resPrint; /* If a group by is required -$sql.= " GROUP BY " -foreach($object->fields as $key => $val) -{ +$sql .= " GROUP BY "; +foreach($object->fields as $key => $val) { $sql .= "t.".$key.", "; } // Add fields from extrafields -if (! empty($extrafields->attributes[$object->table_element]['label'])) { - foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) $sql.=($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? "ef.".$key.', ' : ''); +if (!empty($extrafields->attributes[$object->table_element]['label'])) { + foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) { + $sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? "ef.".$key.', ' : ''); + } } // Add where from hooks -$parameters=array(); -$reshook=$hookmanager->executeHooks('printFieldListGroupBy',$parameters); // Note that $action and $object may have been modified by hook -$sql.=$hookmanager->resPrint; -$sql=preg_replace('/,\s*$/','', $sql); +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldListGroupBy', $parameters, $object); // Note that $action and $object may have been modified by hook +$sql .= $hookmanager->resPrint; +$sql = preg_replace('/,\s*$/', '', $sql); */ -$sql .= $db->order($sortfield, $sortorder); +// Add HAVING from hooks +/* +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldListHaving', $parameters, $object); // Note that $action and $object may have been modified by hook +$sql .= !empty($hookmanager->resPrint) ? (" HAVING 1=1 " . $hookmanager->resPrint) : ""; +*/ // Count total nb of records $nbtotalofrecords = ''; if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { + /* This old and fast method to get and count full list returns all record so use a high amount of memory. $resql = $db->query($sql); $nbtotalofrecords = $db->num_rows($resql); + */ + /* The slow method does not consume memory on mysql (not tested on pgsql) */ + /*$resql = $db->query($sql, 0, 'auto', 1); + while ($db->fetch_object($resql)) { + $nbtotalofrecords++; + }*/ + /* The fast and low memory method to get and count full list converts the sql into a sql count */ + $sqlforcount = preg_replace('/^SELECT[a-z0-9\._\s\(\),]+FROM/i', 'SELECT COUNT(*) as nbtotalofrecords FROM', $sql); + $resql = $db->query($sqlforcount); + $objforcount = $db->fetch_object($resql); + $nbtotalofrecords = $objforcount->nbtotalofrecords; if (($page * $limit) > $nbtotalofrecords) { // if total of record found is smaller than page * limit, goto and load page 0 $page = 0; $offset = 0; } + $db->free($resql); } -// if total of record found is smaller than limit, no need to do paging and to restart another select with limits set. -if (is_numeric($nbtotalofrecords) && ($limit > $nbtotalofrecords || empty($limit))) { - $num = $nbtotalofrecords; -} else { - if ($limit) { - $sql .= $db->plimit($limit + 1, $offset); - } - $resql = $db->query($sql); - if (!$resql) { - dol_print_error($db); - exit; - } - - $num = $db->num_rows($resql); +// Complete request and execute it with limit +$sql .= $db->order($sortfield, $sortorder); +if ($limit) { + $sql .= $db->plimit($limit + 1, $offset); } +$resql = $db->query($sql); +if (!$resql) { + dol_print_error($db); + exit; +} + +$num = $db->num_rows($resql); + + // Direct jump if only one record found if ($num == 1 && !empty($conf->global->MAIN_SEARCH_DIRECT_OPEN_IF_ONLY_ONE) && $search_all && !$page) { $obj = $db->fetch_object($resql); @@ -303,7 +345,7 @@ if ($num == 1 && !empty($conf->global->MAIN_SEARCH_DIRECT_OPEN_IF_ONLY_ONE) && $ // Output page // -------------------------------------------------------------------- -llxHeader('', $title, $help_url); +llxHeader('', $title, $help_url, '', 0, 0, $morejs, $morecss, '', ''); $arrayofselected = is_array($toselect) ? $toselect : array(); @@ -317,9 +359,11 @@ if ($limit > 0 && $limit != $conf->liste_limit) { foreach ($search as $key => $val) { if (is_array($search[$key]) && count($search[$key])) { foreach ($search[$key] as $skey) { - $param .= '&search_'.$key.'[]='.urlencode($skey); + if ($skey != '') { + $param .= '&search_'.$key.'[]='.urlencode($skey); + } } - } else { + } elseif ($search[$key] != '') { $param .= '&search_'.$key.'='.urlencode($search[$key]); } } @@ -328,11 +372,17 @@ if ($optioncss != '') { } // Add $param from extra fields include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php'; +// Add $param from hooks +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldListSearchParam', $parameters, $object); // Note that $action and $object may have been modified by hook +$param .= $hookmanager->resPrint; // List of mass actions available $arrayofmassactions = array( - //'presend'=>img_picto('', 'email', 'class="pictofixedwidth"').$langs->trans("SendByMail"), + //'validate'=>img_picto('', 'check', 'class="pictofixedwidth"').$langs->trans("Validate"), + //'generate_doc'=>img_picto('', 'pdf', 'class="pictofixedwidth"').$langs->trans("ReGeneratePDF"), //'builddoc'=>img_picto('', 'pdf', 'class="pictofixedwidth"').$langs->trans("PDFMerge"), + //'presend'=>img_picto('', 'email', 'class="pictofixedwidth"').$langs->trans("SendByMail"), ); if ($permissiontodelete) { $arrayofmassactions['predelete'] = img_picto('', 'delete', 'class="pictofixedwidth"').$langs->trans("Delete"); @@ -351,24 +401,25 @@ print ''; print ''; print ''; +print ''; print ''; -$newcardbutton = dolGetButtonTitle($langs->trans('NewAsset'), '', 'fa fa-plus-circle', dol_buildpath('/asset/card.php', 1).'?action=create&backtopage='.urlencode($_SERVER['PHP_SELF']), '', $permissiontoadd); +$newcardbutton = dolGetButtonTitle($langs->trans('New'), '', 'fa fa-plus-circle', DOL_URL_ROOT.'/asset/card.php?action=create&backtopage='.urlencode($_SERVER['PHP_SELF']), '', $permissiontoadd); -print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, $object->picto, 0, $newcardbutton, '', $limit, 0, 0, 1); +print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'object_'.$object->picto, 0, $newcardbutton, '', $limit, 0, 0, 1); // Add code for pre mass action (confirmation or email presend form) -$topicmail = "SendAssetsRef"; +$topicmail = "SendAssetRef"; $modelmail = "asset"; $objecttmp = new Asset($db); $trackid = 'asset'.$object->id; include DOL_DOCUMENT_ROOT.'/core/tpl/massactions_pre.tpl.php'; -if ($sall) { +if ($search_all) { foreach ($fieldstosearchall as $key => $val) { $fieldstosearchall[$key] = $langs->trans($val); } - print '
    '.$langs->trans("FilterOnInto", $sall).join(', ', $fieldstosearchall).'
    '; + print '
    '.$langs->trans("FilterOnInto", $search_all).join(', ', $fieldstosearchall).'
    '; } $moreforfilter = ''; @@ -395,31 +446,42 @@ $selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfi $selectedfields .= (count($arrayofmassactions) ? $form->showCheckAddButtons('checkforselect', 1) : ''); print '
    '; // You can use div-table-responsive-no-min if you dont need reserved height for your table -print ''."\n"; +print '
    '."\n"; // Fields title search // -------------------------------------------------------------------- print ''; foreach ($object->fields as $key => $val) { - $cssforfield = (empty($val['css']) ? '' : $val['css']); + $cssforfield = (empty($val['csslist']) ? (empty($val['css']) ? '' : $val['css']) : $val['csslist']); if ($key == 'status') { $cssforfield .= ($cssforfield ? ' ' : '').'center'; } elseif (in_array($val['type'], array('date', 'datetime', 'timestamp'))) { $cssforfield .= ($cssforfield ? ' ' : '').'center'; } elseif (in_array($val['type'], array('timestamp'))) { $cssforfield .= ($cssforfield ? ' ' : '').'nowrap'; - } elseif (in_array($val['type'], array('double(24,8)', 'double(6,3)', 'integer', 'real', 'price')) && $val['label'] != 'TechnicalID') { + } elseif (in_array($val['type'], array('double(24,8)', 'double(6,3)', 'integer', 'real', 'price')) && $val['label'] != 'TechnicalID' && empty($val['arrayofkeyval'])) { $cssforfield .= ($cssforfield ? ' ' : '').'right'; } if (!empty($arrayfields['t.'.$key]['checked'])) { print ''; } @@ -443,14 +505,14 @@ print ''."\n"; // -------------------------------------------------------------------- print ''; foreach ($object->fields as $key => $val) { - $cssforfield = (empty($val['css']) ? '' : $val['css']); + $cssforfield = (empty($val['csslist']) ? (empty($val['css']) ? '' : $val['css']) : $val['csslist']); if ($key == 'status') { $cssforfield .= ($cssforfield ? ' ' : '').'center'; } elseif (in_array($val['type'], array('date', 'datetime', 'timestamp'))) { $cssforfield .= ($cssforfield ? ' ' : '').'center'; } elseif (in_array($val['type'], array('timestamp'))) { $cssforfield .= ($cssforfield ? ' ' : '').'nowrap'; - } elseif (in_array($val['type'], array('double(24,8)', 'double(6,3)', 'integer', 'real', 'price')) && $val['label'] != 'TechnicalID') { + } elseif (in_array($val['type'], array('double(24,8)', 'double(6,3)', 'integer', 'real', 'price')) && $val['label'] != 'TechnicalID' && empty($val['arrayofkeyval'])) { $cssforfield .= ($cssforfield ? ' ' : '').'right'; } if (!empty($arrayfields['t.'.$key]['checked'])) { @@ -464,13 +526,13 @@ $parameters = array('arrayfields'=>$arrayfields, 'param'=>$param, 'sortfield'=>$ $reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters, $object); // Note that $action and $object may have been modified by hook print $hookmanager->resPrint; // Action column -print getTitleFieldOfList($selectedfields, 0, $_SERVER["PHP_SELF"], '', '', '', 'align="center"', $sortfield, $sortorder, 'maxwidthsearch ')."\n"; +print getTitleFieldOfList($selectedfields, 0, $_SERVER["PHP_SELF"], '', '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ')."\n"; print ''."\n"; // Detect if we need a fetch on each output line $needToFetchEachLine = 0; -if (is_array($extrafields->attributes[$object->table_element]['computed']) && count($extrafields->attributes[$object->table_element]['computed']) > 0) { +if (isset($extrafields->attributes[$object->table_element]['computed']) && is_array($extrafields->attributes[$object->table_element]['computed']) && count($extrafields->attributes[$object->table_element]['computed']) > 0) { foreach ($extrafields->attributes[$object->table_element]['computed'] as $key => $val) { if (preg_match('/\$object/', $val)) { $needToFetchEachLine++; // There is at least one compute field that use $object @@ -483,6 +545,7 @@ if (is_array($extrafields->attributes[$object->table_element]['computed']) && co // -------------------------------------------------------------------- $i = 0; $totalarray = array(); +$totalarray['nbfield'] = 0; while ($i < ($limit ? min($num, $limit) : $num)) { $obj = $db->fetch_object($resql); if (empty($obj)) { @@ -495,7 +558,7 @@ while ($i < ($limit ? min($num, $limit) : $num)) { // Show here line of result print ''; foreach ($object->fields as $key => $val) { - $cssforfield = (empty($val['css']) ? '' : $val['css']); + $cssforfield = (empty($val['csslist']) ? (empty($val['css']) ? '' : $val['css']) : $val['csslist']); if (in_array($val['type'], array('date', 'datetime', 'timestamp'))) { $cssforfield .= ($cssforfield ? ' ' : '').'center'; } elseif ($key == 'status') { @@ -508,14 +571,17 @@ while ($i < ($limit ? min($num, $limit) : $num)) { $cssforfield .= ($cssforfield ? ' ' : '').'nowrap'; } - if (in_array($val['type'], array('double(24,8)', 'double(6,3)', 'integer', 'real', 'price')) && $key != 'status') { + if (in_array($val['type'], array('double(24,8)', 'double(6,3)', 'integer', 'real', 'price')) && !in_array($key, array('rowid', 'status')) && empty($val['arrayofkeyval'])) { $cssforfield .= ($cssforfield ? ' ' : '').'right'; } + //if (in_array($key, array('fk_soc', 'fk_user', 'fk_warehouse'))) $cssforfield = 'tdoverflowmax100'; if (!empty($arrayfields['t.'.$key]['checked'])) { print ''; if ($key == 'status') { print $object->getLibStatut(5); + } elseif ($key == 'rowid') { + print $object->showOutputField($val, $key, $object->id, ''); } else { print $object->showOutputField($val, $key, $object->$key, ''); } @@ -545,7 +611,7 @@ while ($i < ($limit ? min($num, $limit) : $num)) { print $hookmanager->resPrint; // Action column print ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo "\n"; +} +if (count($linkedObjectBlock) > 1) { + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo "\n"; +} + +echo "\n"; diff --git a/htdocs/asset/type.php b/htdocs/asset/type.php deleted file mode 100644 index cd802c1c4fd..00000000000 --- a/htdocs/asset/type.php +++ /dev/null @@ -1,608 +0,0 @@ - - * - * 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 - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** - * \file htdocs/asset/type.php - * \ingroup asset - * \brief Asset's type setup - */ - -require '../main.inc.php'; -require_once DOL_DOCUMENT_ROOT.'/core/lib/asset.lib.php'; -require_once DOL_DOCUMENT_ROOT.'/asset/class/asset.class.php'; -require_once DOL_DOCUMENT_ROOT.'/asset/class/asset_type.class.php'; -require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; -if (!empty($conf->accounting->enabled)) { - require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php'; -} -if (!empty($conf->accounting->enabled)) { - require_once DOL_DOCUMENT_ROOT.'/core/class/html.formaccounting.class.php'; -} -if (!empty($conf->accounting->enabled)) { - require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingaccount.class.php'; -} - -// Load translation files required by the page -$langs->load("assets"); - -$rowid = GETPOST('rowid', 'int'); -$action = GETPOST('action', 'aZ09'); -$cancel = GETPOST('cancel', 'alpha'); -$backtopage = GETPOST('backtopage', 'alpha'); - -$type = GETPOST('type', 'alpha'); - -$limit = GETPOST('limit', 'int') ?GETPOST('limit', 'int') : $conf->liste_limit; -$sortfield = GETPOST('sortfield', 'aZ09comma'); -$sortorder = GETPOST('sortorder', 'aZ09comma'); -$page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int'); -if (empty($page) || $page == -1) { - $page = 0; -} // If $page is not defined, or '' or -1 -$offset = $limit * $page; -$pageprev = $page - 1; -$pagenext = $page + 1; -if (!$sortorder) { - $sortorder = "DESC"; -} -if (!$sortfield) { - $sortfield = "a.label"; -} - -$label = GETPOST("label", "alpha"); -$accountancy_code_asset = GETPOST('accountancy_code_asset', 'string'); -$accountancy_code_depreciation_asset = GETPOST('accountancy_code_depreciation_asset', 'string'); -$accountancy_code_depreciation_expense = GETPOST('accountancy_code_depreciation_expense', 'string'); -$comment = GETPOST('comment', 'string'); - -// Security check -$result = restrictedArea($user, 'asset', $rowid, 'asset_type'); - -$object = new AssetType($db); - -$extrafields = new ExtraFields($db); - -// fetch optionals attributes and labels -$extrafields->fetch_name_optionals_label($object->table_element); - -if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // All tests are required to be compatible with all browsers - $type = ""; - $sall = ""; -} - - -// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context -$hookmanager->initHooks(array('assettypecard', 'globalcard')); - -$permissiontoadd = $user->rights->asset->setup_advance; - - -/* - * Actions - */ - -if ($cancel) { - $action = ''; - - if (!empty($backtopage)) { - header("Location: ".$backtopage); - exit; - } -} - -if ($action == 'add' && $user->rights->asset->write) { - $object->label = trim($label); - $object->accountancy_code_asset = trim($accountancy_code_asset); - $object->accountancy_code_depreciation_asset = trim($accountancy_code_depreciation_asset); - $object->accountancy_code_depreciation_expense = trim($accountancy_code_depreciation_expense); - $object->note = trim($comment); - - // Fill array 'array_options' with data from add form - $ret = $extrafields->setOptionalsFromPost(null, $object); - if ($ret < 0) { - $error++; - } - - if (empty($object->label)) { - $error++; - setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Label")), null, 'errors'); - } else { - $sql = "SELECT label FROM ".MAIN_DB_PREFIX."asset_type WHERE label='".$db->escape($object->label)."'"; - $result = $db->query($sql); - if ($result) { - $num = $db->num_rows($result); - } - if ($num) { - $error++; - $langs->load("errors"); - setEventMessages($langs->trans("ErrorLabelAlreadyExists", $login), null, 'errors'); - } - } - - if (!$error) { - $id = $object->create($user); - if ($id > 0) { - header("Location: ".$_SERVER["PHP_SELF"]); - exit; - } else { - setEventMessages($object->error, $object->errors, 'errors'); - $action = 'create'; - } - } else { - $action = 'create'; - } -} - -if ($action == 'update' && $user->rights->asset->write) { - $object->fetch($rowid); - - $object->oldcopy = clone $object; - - $object->label = trim($label); - $object->accountancy_code_asset = trim($accountancy_code_asset); - $object->accountancy_code_depreciation_asset = trim($accountancy_code_depreciation_asset); - $object->accountancy_code_depreciation_expense = trim($accountancy_code_depreciation_expense); - $object->note = trim($comment); - - // Fill array 'array_options' with data from add form - $ret = $extrafields->setOptionalsFromPost(null, $object, '@GETPOSTISSET'); - if ($ret < 0) { - $error++; - } - - $ret = $object->update($user); - - if ($ret >= 0 && !count($object->errors)) { - setEventMessages($langs->trans("AssetTypeModified"), null, 'mesgs'); - } else { - setEventMessages($object->error, $object->errors, 'errors'); - } - - header("Location: ".$_SERVER["PHP_SELF"]."?rowid=".$object->id); - exit; -} - -if ($action == 'confirm_delete' && $user->rights->asset->write) { - $object->fetch($rowid); - $res = $object->delete(); - - if ($res > 0) { - setEventMessages($langs->trans("AssetsTypeDeleted"), null, 'mesgs'); - header("Location: ".$_SERVER["PHP_SELF"]); - exit; - } else { - setEventMessages($langs->trans("AssetsTypeCanNotBeDeleted"), null, 'errors'); - $action = ''; - } -} - - -/* - * View - */ - -$form = new Form($db); - -$help_url = ''; - -llxHeader('', $langs->trans("AssetsTypeSetup"), $help_url); - - -// List of asset type -if (!$rowid && $action != 'create' && $action != 'edit') { - //print dol_get_fiche_head(''); - - $sql = "SELECT d.rowid, d.label as label, d.accountancy_code_asset, d.accountancy_code_depreciation_asset, d.accountancy_code_depreciation_expense, d.note"; - $sql .= " FROM ".MAIN_DB_PREFIX."asset_type as d"; - $sql .= " WHERE d.entity IN (".getEntity('asset_type').")"; - - $result = $db->query($sql); - if ($result) { - $num = $db->num_rows($result); - $nbtotalofrecords = $num; - - $i = 0; - - $param = ''; - - print '
    '; - if ($optioncss != '') { - print ''; - } - print ''; - print ''; - print ''; - print ''; - print ''; - print ''; - - $newcardbutton = dolGetButtonTitle($langs->trans('NewAssetType'), '', 'fa fa-plus-circle', dol_buildpath('/asset/type.php', 1).'?action=create&backtopage='.urlencode($_SERVER['PHP_SELF']), '', $permissiontoadd); - - print_barre_liste($langs->trans("AssetsTypes"), $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num, $nbtotalofrecords, $object->picto, 0, $newcardbutton, '', $limit); - - $moreforfilter = ''; - - print '
    '; - print '
    '; if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) { - print $form->selectarray('search_'.$key, $val['arrayofkeyval'], $search[$key], $val['notnull'], 0, 0, '', 1, 0, 0, '', 'maxwidth100', 1); - } elseif (strpos($val['type'], 'integer:') === 0) { - print $object->showInputField($val, $key, $search[$key], '', '', 'search_', 'maxwidth150', 1); - } elseif (!preg_match('/^(date|timestamp)/', $val['type'])) { - print ''; + print $form->selectarray('search_'.$key, $val['arrayofkeyval'], (isset($search[$key]) ? $search[$key] : ''), $val['notnull'], 0, 0, '', 1, 0, 0, '', 'maxwidth100', 1); + } elseif ((strpos($val['type'], 'integer:') === 0) || (strpos($val['type'], 'sellist:') === 0)) { + print $object->showInputField($val, $key, (isset($search[$key]) ? $search[$key] : ''), '', '', 'search_', 'maxwidth125', 1); + } elseif (preg_match('/^(date|timestamp|datetime)/', $val['type'])) { + print '
    '; + print $form->selectDate($search[$key.'_dtstart'] ? $search[$key.'_dtstart'] : '', "search_".$key."_dtstart", 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('From')); + print '
    '; + print '
    '; + print $form->selectDate($search[$key.'_dtend'] ? $search[$key.'_dtend'] : '', "search_".$key."_dtend", 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('to')); + print '
    '; + } elseif ($key == 'lang') { + require_once DOL_DOCUMENT_ROOT.'/core/class/html.formadmin.class.php'; + $formadmin = new FormAdmin($db); + print $formadmin->select_language($search[$key], 'search_lang', 0, null, 1, 0, 0, 'minwidth150 maxwidth200', 2); + } else { + print ''; } print '
    '; - if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined + if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined $selected = 0; if (in_array($object->id, $arrayofselected)) { $selected = 1; @@ -605,7 +671,7 @@ if (in_array('builddoc', $arrayofmassactions) && ($nbtotalofrecords === '' || $n $genallowed = $permissiontoread; $delallowed = $permissiontoadd; - print $formfile->showdocuments('massfilesarea_asset', '', $filedir, $urlsource, 0, $delallowed, '', 1, 1, 0, 48, 1, $param, $title, ''); + print $formfile->showdocuments('massfilesarea_asset', '', $filedir, $urlsource, 0, $delallowed, '', 1, 1, 0, 48, 1, $param, $title, '', '', '', null, $hidegeneratedfilelistifempty); } // End of page diff --git a/htdocs/asset/model/accountancy_codes.php b/htdocs/asset/model/accountancy_codes.php new file mode 100644 index 00000000000..fd5999b20b0 --- /dev/null +++ b/htdocs/asset/model/accountancy_codes.php @@ -0,0 +1,191 @@ + + * Copyright (C) 2018 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 + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/asset/model/accountancy_code.php + * \ingroup asset + * \brief Card with accountancy code on Asset Model + */ + +require '../../main.inc.php'; +require_once DOL_DOCUMENT_ROOT . '/core/lib/asset.lib.php'; +require_once DOL_DOCUMENT_ROOT . '/asset/class/assetmodel.class.php'; +require_once DOL_DOCUMENT_ROOT . '/asset/class/assetaccountancycodes.class.php'; + +// Load translation files required by the page +$langs->loadLangs(array("assets", "companies")); + +// Get parameters +$id = GETPOST('id', 'int'); +$ref = GETPOST('ref', 'alpha'); +$action = GETPOST('action', 'aZ09'); +$cancel = GETPOST('cancel', 'aZ09'); +$backtopage = GETPOST('backtopage', 'alpha'); + +// Initialize technical objects +$object = new AssetModel($db); +$assetaccountancycodes = new AssetAccountancyCodes($db); +$extrafields = new ExtraFields($db); +$diroutputmassaction = $conf->asset->dir_output . '/temp/massgeneration/' . $user->id; +$hookmanager->initHooks(array('assetmodelaccountancycodes', 'globalcard')); // Note that conf->hooks_modules contains array +// Fetch optionals attributes and labels +$extrafields->fetch_name_optionals_label($object->table_element); + +// Load object +include DOL_DOCUMENT_ROOT . '/core/actions_fetchobject.inc.php'; // Must be include, not include_once // Must be include, not include_once. Include fetch and fetch_thirdparty but not fetch_optionals +if ($id > 0 || !empty($ref)) { + $upload_dir = $conf->asset->multidir_output[$object->entity] . "/" . $object->id; +} + +$permissiontoread = ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && $user->rights->asset->read) || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->asset->setup_advance->read))); +$permissiontoadd = ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && $user->rights->asset->write) || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->asset->setup_advance->write))); // Used by the include of actions_addupdatedelete.inc.php + +// Security check (enable the most restrictive one) +if ($user->socid > 0) accessforbidden(); +$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +restrictedArea($user, 'asset', $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +if (empty($conf->asset->enabled)) accessforbidden(); +if (!$permissiontoread) accessforbidden(); + +$result = $assetaccountancycodes->fetchAccountancyCodes(0, $object->id); +if ($result < 0) { + setEventMessages($assetaccountancycodes->error, $assetaccountancycodes->errors, 'errors'); +} + + +/* + * Actions + */ + +$reshook = $hookmanager->executeHooks('doActions', array(), $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); +} +if (empty($reshook)) { + $backurlforlist = DOL_URL_ROOT.'/asset/list.php'; + + if (empty($backtopage) || ($cancel && empty($id))) { + if (empty($backtopage) || ($cancel && strpos($backtopage, '__ID__'))) { + if (empty($id) && (($action != 'add' && $action != 'create') || $cancel)) { + $backtopage = $backurlforlist; + } else { + $backtopage = DOL_URL_ROOT.'/asset/model/accountancy_codes.php?id='.((!empty($id) && $id > 0) ? $id : '__ID__'); + } + } + } + + if ($cancel) { + /*var_dump($cancel);var_dump($backtopage);var_dump($backtopageforcancel);exit;*/ + if (!empty($backtopageforcancel)) { + header("Location: ".$backtopageforcancel); + exit; + } elseif (!empty($backtopage)) { + header("Location: ".$backtopage); + exit; + } + $action = ''; + } + + if ($action == "update") { + $assetaccountancycodes->setAccountancyCodesFromPost(); + + $result = $assetaccountancycodes->updateAccountancyCodes($user, 0, $object->id); + if ($result < 0) { + setEventMessages($assetaccountancycodes->error, $assetaccountancycodes->errors, 'errors'); + $action = 'edit'; + } else { + setEventMessage($langs->trans('RecordSaved')); + header("Location: " . $_SERVER["PHP_SELF"] . '?id=' . $object->id); + exit; + } + } +} + + +/* + * View + */ + +$form = new Form($db); + +$help_url = ''; +llxHeader('', $langs->trans('AssetModel'), $help_url); + +if ($id > 0 || !empty($ref)) { + $head = assetModelPrepareHead($object); + print dol_get_fiche_head($head, 'accountancy_codes', $langs->trans("AssetModel"), -1, $object->picto); + + // Object card + // ------------------------------------------------------------ + $linkback = '' . $langs->trans("BackToList") . ''; + + $morehtmlref = '
    '; + $morehtmlref .= '
    '; + + dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref); + + print '
    '; + print '
    '; + print '
    '; + + if ($action == 'edit') { + print '
    '; + print ''; + print ''; + if ($backtopage) { + print ''; + } + if ($backtopageforcancel) { + print ''; + } + + print dol_get_fiche_head(array(), ''); + + include DOL_DOCUMENT_ROOT . '/asset/tpl/accountancy_codes_edit.tpl.php'; + + print dol_get_fiche_end(); + + print $form->buttonsSaveCancel(); + + print '
    '; + } else { + include DOL_DOCUMENT_ROOT . '/asset/tpl/accountancy_codes_view.tpl.php'; + } + + print dol_get_fiche_end(); + + if ($action != 'edit') { + print '
    ' . "\n"; + $parameters = array(); + $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook + if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + } + + if (empty($reshook)) { + if ($object->status == $object::STATUS_DRAFT/* && !empty($object->enabled_modes)*/) { + print dolGetButtonAction($langs->trans('Modify'), '', 'default', $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=edit&token=' . newToken(), '', $permissiontoadd); + } + } + print '
    ' . "\n"; + } +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/asset/model/agenda.php b/htdocs/asset/model/agenda.php new file mode 100644 index 00000000000..494c271668a --- /dev/null +++ b/htdocs/asset/model/agenda.php @@ -0,0 +1,217 @@ + + * Copyright (C) ---Put here your own copyright and developer email--- + * + * 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 + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/asset/model/agenda.php + * \ingroup asset + * \brief Tab of events on Asset Model + */ + +require '../../main.inc.php'; +require_once DOL_DOCUMENT_ROOT . '/core/lib/asset.lib.php'; +require_once DOL_DOCUMENT_ROOT . '/asset/class/assetmodel.class.php'; +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'; + +// Load translation files required by the page +$langs->loadLangs(array("assets", "other")); + +// Get parameters +$id = GETPOST('id', 'int'); +$ref = GETPOST('ref', 'alpha'); +$action = GETPOST('action', 'aZ09'); +$cancel = GETPOST('cancel', 'aZ09'); +$backtopage = GETPOST('backtopage', 'alpha'); + +if (GETPOST('actioncode', 'array')) { + $actioncode = GETPOST('actioncode', 'array', 3); + if (!count($actioncode)) { + $actioncode = '0'; + } +} else { + $actioncode = GETPOST("actioncode", "alpha", 3) ? GETPOST("actioncode", "alpha", 3) : (GETPOST("actioncode") == '0' ? '0' : (empty($conf->global->AGENDA_DEFAULT_FILTER_TYPE_FOR_OBJECT) ? '' : $conf->global->AGENDA_DEFAULT_FILTER_TYPE_FOR_OBJECT)); +} +$search_agenda_label = GETPOST('search_agenda_label'); + +$limit = GETPOST('limit', 'int') ? GETPOST('limit', 'int') : $conf->liste_limit; +$sortfield = GETPOST("sortfield", 'alpha'); +$sortorder = GETPOST("sortorder", 'alpha'); +$page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int'); +if (empty($page) || $page == -1) { + $page = 0; +} // If $page is not defined, or '' or -1 +$offset = $limit * $page; +$pageprev = $page - 1; +$pagenext = $page + 1; +if (!$sortfield) { + $sortfield = 'a.datep,a.id'; +} +if (!$sortorder) { + $sortorder = 'DESC,DESC'; +} + +// Initialize technical objects +$object = new AssetModel($db); +$extrafields = new ExtraFields($db); +$diroutputmassaction = $conf->asset->dir_output . '/temp/massgeneration/' . $user->id; +$hookmanager->initHooks(array('assetmodelagenda', 'globalcard')); // Note that conf->hooks_modules contains array +// Fetch optionals attributes and labels +$extrafields->fetch_name_optionals_label($object->table_element); + +// Load object +include DOL_DOCUMENT_ROOT . '/core/actions_fetchobject.inc.php'; // Must be include, not include_once // Must be include, not include_once. Include fetch and fetch_thirdparty but not fetch_optionals +if ($id > 0 || !empty($ref)) { + $upload_dir = $conf->asset->multidir_output[$object->entity] . "/model/" . $object->id; +} + +$permissiontoread = ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && $user->rights->asset->read) || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->asset->setup_advance->read))); +$permissiontoadd = ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && $user->rights->asset->write) || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->asset->setup_advance->write))); // Used by the include of actions_addupdatedelete.inc.php + +// Security check (enable the most restrictive one) +if ($user->socid > 0) accessforbidden(); +if ($user->socid > 0) $socid = $user->socid; +$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +restrictedArea($user, 'asset', $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +if (empty($conf->asset->enabled)) accessforbidden(); +if (!$permissiontoread) accessforbidden(); + + +/* + * Actions + */ + +$parameters = array('id' => $id); +$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); +} + +if (empty($reshook)) { + // Cancel + if (GETPOST('cancel', 'alpha') && !empty($backtopage)) { + header("Location: " . $backtopage); + exit; + } + + // Purge search criteria + if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // All tests are required to be compatible with all browsers + $actioncode = ''; + $search_agenda_label = ''; + } +} + + +/* + * View + */ + +$form = new Form($db); + +if ($object->id > 0) { + $title = $langs->trans("Agenda"); + //if (! empty($conf->global->MAIN_HTML_TITLE) && preg_match('/thirdpartynameonly/',$conf->global->MAIN_HTML_TITLE) && $object->name) $title=$object->name." - ".$title; + $help_url = 'EN:Module_Agenda_En'; + llxHeader('', $title, $help_url); + + if (!empty($conf->notification->enabled)) { + $langs->load("mails"); + } + $head = assetModelPrepareHead($object); + + + print dol_get_fiche_head($head, 'agenda', $langs->trans("AssetModel"), -1, $object->picto); + + // Object card + // ------------------------------------------------------------ + $linkback = '' . $langs->trans("BackToList") . ''; + + $morehtmlref = '
    '; + $morehtmlref .= '
    '; + + + dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref); + + print '
    '; + print '
    '; + + $object->info($object->id); + dol_print_object_info($object, 1); + + print '
    '; + + print dol_get_fiche_end(); + + + // Actions buttons + + $objthirdparty = $object; + $objcon = new stdClass(); + + $out = '&origin=' . urlencode($object->element . '@' . $object->module) . '&originid=' . urlencode($object->id); + $urlbacktopage = $_SERVER['PHP_SELF'] . '?id=' . $object->id; + $out .= '&backtopage=' . urlencode($urlbacktopage); + $permok = $user->rights->agenda->myactions->create; + if ((!empty($objthirdparty->id) || !empty($objcon->id)) && $permok) { + //$out.='trans("AddAnAction"),'filenew'); + //$out.=""; + } + + + print '
    '; + +// if (!empty($conf->agenda->enabled)) { +// if (!empty($user->rights->agenda->myactions->create) || !empty($user->rights->agenda->allactions->create)) { +// print '' . $langs->trans("AddAction") . ''; +// } else { +// print '' . $langs->trans("AddAction") . ''; +// } +// } + + print '
    '; + +// if (!empty($conf->agenda->enabled) && (!empty($user->rights->agenda->myactions->read) || !empty($user->rights->agenda->allactions->read))) { +// $param = '&id=' . $object->id . '&socid=' . $socid; +// if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) { +// $param .= '&contextpage=' . urlencode($contextpage); +// } +// if ($limit > 0 && $limit != $conf->liste_limit) { +// $param .= '&limit=' . urlencode($limit); +// } +// +// +// print load_fiche_titre($langs->trans("ActionsOnAssetModel"), '', ''); +// +// // List of all actions +// $filters = array(); +// $filters['search_agenda_label'] = $search_agenda_label; +// +// // TODO Replace this with same code than into list.php +// show_actions_done($conf, $langs, $db, $object, null, 0, $actioncode, '', $filters, $sortfield, $sortorder, $object->module); +// } +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/asset/model/card.php b/htdocs/asset/model/card.php new file mode 100644 index 00000000000..85e3ea207af --- /dev/null +++ b/htdocs/asset/model/card.php @@ -0,0 +1,330 @@ + + * Copyright (C) 2018 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 + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/asset/model/card.php + * \ingroup asset + * \brief Page to create/edit/view asset Model + */ + +require '../../main.inc.php'; +require_once DOL_DOCUMENT_ROOT . '/core/lib/asset.lib.php'; +require_once DOL_DOCUMENT_ROOT . '/asset/class/assetmodel.class.php'; +require_once DOL_DOCUMENT_ROOT . '/core/class/html.formcompany.class.php'; +require_once DOL_DOCUMENT_ROOT . '/core/class/html.formfile.class.php'; + +// Load translation files required by the page +$langs->loadLangs(array("assets", "other")); + +// Get parameters +$id = GETPOST('id', 'int'); +$ref = GETPOST('ref', 'alpha'); +$action = GETPOST('action', 'aZ09'); +$confirm = GETPOST('confirm', 'alpha'); +$cancel = GETPOST('cancel', 'aZ09'); +$contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : 'assetmodelcard'; // To manage different context of search +$backtopage = GETPOST('backtopage', 'alpha'); +$backtopageforcancel = GETPOST('backtopageforcancel', 'alpha'); + +// Initialize technical objects +$object = new AssetModel($db); +$extrafields = new ExtraFields($db); +$diroutputmassaction = $conf->asset->dir_output . '/temp/massgeneration/' . $user->id; +$hookmanager->initHooks(array('assetmodelcard', 'globalcard')); // Note that conf->hooks_modules contains array + +// Fetch optionals attributes and labels +$extrafields->fetch_name_optionals_label($object->table_element); + +$search_array_options = $extrafields->getOptionalsFromPost($object->table_element, '', 'search_'); + +// Initialize array of search criterias +$search_all = GETPOST("search_all", 'alpha'); +$search = array(); +foreach ($object->fields as $key => $val) { + if (GETPOST('search_' . $key, 'alpha')) { + $search[$key] = GETPOST('search_' . $key, 'alpha'); + } +} + +if (empty($action) && empty($id) && empty($ref)) { + $action = 'view'; +} + +// Load object +include DOL_DOCUMENT_ROOT . '/core/actions_fetchobject.inc.php'; // Must be include, not include_once. + +$permissiontoread = ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && $user->rights->asset->read) || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->asset->setup_advance->read))); +$permissiontoadd = ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && $user->rights->asset->write) || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->asset->setup_advance->write))); // Used by the include of actions_addupdatedelete.inc.php and actions_lineupdown.inc.php +$permissiontodelete = ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && $user->rights->asset->delete) || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->asset->setup_advance->delete))) || ($permissiontoadd && isset($object->status) && $object->status == $object::STATUS_DRAFT); +$permissionnote = $permissiontoadd; // Used by the include of actions_setnotes.inc.php +$permissiondellink = $permissiontoadd; // Used by the include of actions_dellink.inc.php +$upload_dir = $conf->asset->multidir_output[isset($object->entity) ? $object->entity : 1]; + +// Security check (enable the most restrictive one) +if ($user->socid > 0) accessforbidden(); +if ($user->socid > 0) $socid = $user->socid; +$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +restrictedArea($user, 'asset', $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +if (empty($conf->asset->enabled)) accessforbidden(); +if (!$permissiontoread) accessforbidden(); + + +/* + * Actions + */ + +$parameters = array(); +$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); +} + +if (empty($reshook)) { + $error = 0; + + $backurlforlist = DOL_URL_ROOT . '/asset/model/list.php'; + + if (empty($backtopage) || ($cancel && empty($id))) { + if (empty($backtopage) || ($cancel && strpos($backtopage, '__ID__'))) { + if (empty($id) && (($action != 'add' && $action != 'create') || $cancel)) { + $backtopage = $backurlforlist; + } else { + $backtopage = DOL_URL_ROOT . '/asset/model/card.php?id=' . ((!empty($id) && $id > 0) ? $id : '__ID__'); + } + } + } + + $triggermodname = 'ASSETMODEL_MODIFY'; // Name of trigger action code to execute when we modify record + + if (($action == 'edit' && !($permissiontoadd && $object->status == $object::STATUS_DRAFT)) || + ($action == 'confirm_setdraft' && !($permissiontoadd && $object->status != $object::STATUS_DRAFT)) || + ($action == 'confirm_validate' && !($permissiontoadd && $object->status != $object::STATUS_VALIDATED)) || + ($action == 'confirm_close' && !($permissiontoadd && $object->status != $object::STATUS_CANCELED)) + ) { + $action = ""; + } + + // Actions cancel, add, update, update_extras, confirm_validate, confirm_delete, confirm_deleteline, confirm_clone, confirm_close, confirm_setdraft, confirm_reopen + include DOL_DOCUMENT_ROOT . '/core/actions_addupdatedelete.inc.php'; +} + + +/* + * View + * + * Put here all code to build page + */ + +$form = new Form($db); +$formfile = new FormFile($db); + +$title = $langs->trans("AssetModel") . ' - ' . $langs->trans("Card"); +$help_url = ''; +llxHeader('', $title, $help_url); + +// Part to create +if ($action == 'create') { + print load_fiche_titre($langs->trans("NewObject", $langs->transnoentitiesnoconv("AssetModel")), '', 'object_' . $object->picto); + + print '
    '; + print ''; + print ''; + if ($backtopage) { + print ''; + } + if ($backtopageforcancel) { + print ''; + } + + print dol_get_fiche_head(array(), ''); + + // Set some default values + //if (! GETPOSTISSET('fieldname')) $_POST['fieldname'] = 'myvalue'; + + print '' . "\n"; + + // Common attributes + include DOL_DOCUMENT_ROOT . '/core/tpl/commonfields_add.tpl.php'; + + // Other attributes + include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_add.tpl.php'; + + print '
    ' . "\n"; + + print dol_get_fiche_end(); + + print $form->buttonsSaveCancel("Create"); + + print '
    '; + + //dol_set_focus('input[name="ref"]'); +} + +// Part to edit record +if (($id || $ref) && $action == 'edit') { + print load_fiche_titre($langs->trans("AssetModel"), '', 'object_' . $object->picto); + + print '
    '; + print ''; + print ''; + print ''; + if ($backtopage) { + print ''; + } + if ($backtopageforcancel) { + print ''; + } + + print dol_get_fiche_head(); + + print '' . "\n"; + + // Common attributes + include DOL_DOCUMENT_ROOT . '/core/tpl/commonfields_edit.tpl.php'; + + // Other attributes + include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_edit.tpl.php'; + + print '
    '; + + print dol_get_fiche_end(); + + print $form->buttonsSaveCancel(); + + print '
    '; +} + +// Part to show record +if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'create'))) { + $res = $object->fetch_optionals(); + + $head = assetModelPrepareHead($object); + print dol_get_fiche_head($head, 'card', $langs->trans("AssetModel"), -1, $object->picto); + + $formconfirm = ''; + + // Confirmation to delete + if ($action == 'delete') { + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id, $langs->trans('DeleteAssetModel'), $langs->trans('ConfirmDeleteObject'), 'confirm_delete', '', 0, 1); + } // Clone confirmation + elseif ($action == 'clone') { + // Create an array for form + $formquestion = array(); + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id, $langs->trans('ToClone'), $langs->trans('ConfirmCloneAsk', $object->ref), 'confirm_clone', $formquestion, 'yes', 1); + } + + // Call Hook formConfirm + $parameters = array('formConfirm' => $formconfirm); + $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook + if (empty($reshook)) { + $formconfirm .= $hookmanager->resPrint; + } elseif ($reshook > 0) { + $formconfirm = $hookmanager->resPrint; + } + + // Print form confirm + print $formconfirm; + + + // Object card + // ------------------------------------------------------------ + $linkback = '' . $langs->trans("BackToList") . ''; + + $morehtmlref = '
    '; + $morehtmlref .= '
    '; + + + dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref); + + + print '
    '; + print '
    '; + print '
    '; + print '' . "\n"; + + // Common attributes + include DOL_DOCUMENT_ROOT . '/core/tpl/commonfields_view.tpl.php'; + + // Other attributes. Fields from hook formObjectOptions and Extrafields. + include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_view.tpl.php'; + + print '
    '; + print '
    '; + print '
    '; + + print '
    '; + + print dol_get_fiche_end(); + + + // Buttons for actions + if ($action != 'editline') { + print '
    ' . "\n"; + $parameters = array(); + $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook + if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + } + + if (empty($reshook)) { + if ($object->status == $object::STATUS_DRAFT) { + print dolGetButtonAction($langs->trans('Modify'), '', 'default', $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=edit&token=' . newToken(), '', $permissiontoadd); + } + + // Back to draft + if ($object->status != $object::STATUS_DRAFT) { + print dolGetButtonAction($langs->trans('SetToDraft'), '', 'default', $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=confirm_setdraft&confirm=yes&token=' . newToken(), '', $permissiontoadd); + } + + if ($object->status != $object::STATUS_VALIDATED) { + print dolGetButtonAction($langs->trans('Enable'), '', 'default', $_SERVER['PHP_SELF'] . '?id=' . $object->id . '&action=confirm_validate&confirm=yes&token=' . newToken(), '', $permissiontoadd); + } + + if ($object->status != $object::STATUS_CANCELED) { + print dolGetButtonAction($langs->trans('Disable'), '', 'default', $_SERVER['PHP_SELF'].'?id='.$object->id.'&action=confirm_close&confirm=yes&token='.newToken(), '', $permissiontoadd); + } + + // Clone + print dolGetButtonAction($langs->trans('ToClone'), '', 'default', $_SERVER['PHP_SELF'] . '?id=' . $object->id . '&socid=' . $object->socid . '&action=clone&token=' . newToken(), '', $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)); + } + print '
    ' . "\n"; + } + + print '
    '; + print ''; // ancre + + print '
    '; + +// $MAXEVENT = 10; +// +// $morehtmlcenter = dolGetButtonTitle($langs->trans('SeeAll'), '', 'fa fa-list-alt imgforviewmode', DOL_URL_ROOT . '/asset/model/agenda.php?id=' . $object->id); +// +// // List of actions on element +// include_once DOL_DOCUMENT_ROOT . '/core/class/html.formactions.class.php'; +// $formactions = new FormActions($db); +// $somethingshown = $formactions->showactions($object, $object->element.'@'.$object->module, 0, 1, '', $MAXEVENT, '', $morehtmlright); + + print '
    '; +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/asset/model/depreciation_options.php b/htdocs/asset/model/depreciation_options.php new file mode 100644 index 00000000000..f5bc751663b --- /dev/null +++ b/htdocs/asset/model/depreciation_options.php @@ -0,0 +1,191 @@ + + * Copyright (C) 2018 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 + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/asset/model/depreciation_options.php + * \ingroup asset + * \brief Card with depreciation options on Asset Model + */ + +require '../../main.inc.php'; +require_once DOL_DOCUMENT_ROOT . '/core/lib/asset.lib.php'; +require_once DOL_DOCUMENT_ROOT . '/asset/class/assetmodel.class.php'; +require_once DOL_DOCUMENT_ROOT . '/asset/class/assetdepreciationoptions.class.php'; + +// Load translation files required by the page +$langs->loadLangs(array("assets", "companies")); + +// Get parameters +$id = GETPOST('id', 'int'); +$ref = GETPOST('ref', 'alpha'); +$action = GETPOST('action', 'aZ09'); +$cancel = GETPOST('cancel', 'aZ09'); +$backtopage = GETPOST('backtopage', 'alpha'); + +// Initialize technical objects +$object = new AssetModel($db); +$assetdepreciationoptions = new AssetDepreciationOptions($db); +$extrafields = new ExtraFields($db); +$diroutputmassaction = $conf->asset->dir_output . '/temp/massgeneration/' . $user->id; +$hookmanager->initHooks(array('assetmodeldeprectationoptions', 'globalcard')); // Note that conf->hooks_modules contains array +// Fetch optionals attributes and labels +$extrafields->fetch_name_optionals_label($object->table_element); + +// Load object +include DOL_DOCUMENT_ROOT . '/core/actions_fetchobject.inc.php'; // Must be include, not include_once // Must be include, not include_once. Include fetch and fetch_thirdparty but not fetch_optionals +if ($id > 0 || !empty($ref)) { + $upload_dir = $conf->asset->multidir_output[$object->entity] . "/" . $object->id; +} + +$permissiontoread = ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && $user->rights->asset->read) || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->asset->setup_advance->read))); +$permissiontoadd = ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && $user->rights->asset->write) || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->asset->setup_advance->write))); // Used by the include of actions_addupdatedelete.inc.php + +// Security check (enable the most restrictive one) +if ($user->socid > 0) accessforbidden(); +$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +restrictedArea($user, 'asset', $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +if (empty($conf->asset->enabled)) accessforbidden(); +if (!$permissiontoread) accessforbidden(); + +$object->asset_depreciation_options = &$assetdepreciationoptions; +$result = $assetdepreciationoptions->fetchDeprecationOptions(0, $object->id); +if ($result < 0) { + setEventMessages($assetdepreciationoptions->error, $assetdepreciationoptions->errors, 'errors'); +} + + +/* + * Actions + */ + +$reshook = $hookmanager->executeHooks('doActions', array(), $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); +} +if (empty($reshook)) { + $backurlforlist = DOL_URL_ROOT.'/asset/list.php'; + + if (empty($backtopage) || ($cancel && empty($id))) { + if (empty($backtopage) || ($cancel && strpos($backtopage, '__ID__'))) { + if (empty($id) && (($action != 'add' && $action != 'create') || $cancel)) { + $backtopage = $backurlforlist; + } else { + $backtopage = DOL_URL_ROOT.'/asset/model/depreciation_options.php?id='.((!empty($id) && $id > 0) ? $id : '__ID__'); + } + } + } + + if ($cancel) { + /*var_dump($cancel);var_dump($backtopage);var_dump($backtopageforcancel);exit;*/ + if (!empty($backtopageforcancel)) { + header("Location: ".$backtopageforcancel); + exit; + } elseif (!empty($backtopage)) { + header("Location: ".$backtopage); + exit; + } + $action = ''; + } + + if ($action == "update") { + $result = $assetdepreciationoptions->setDeprecationOptionsFromPost(1); + if ($result > 0) $result = $assetdepreciationoptions->updateDeprecationOptions($user, 0, $object->id); + if ($result < 0) { + setEventMessages($assetdepreciationoptions->error, $assetdepreciationoptions->errors, 'errors'); + $action = 'edit'; + } else { + setEventMessage($langs->trans('RecordSaved')); + header("Location: " . $_SERVER["PHP_SELF"] . '?id=' . $object->id); + exit; + } + } +} + + +/* + * View + */ + +$form = new Form($db); + +$help_url = ''; +llxHeader('', $langs->trans('AssetModel'), $help_url); + +if ($id > 0 || !empty($ref)) { + $head = assetModelPrepareHead($object); + print dol_get_fiche_head($head, 'depreciation_options', $langs->trans("AssetModel"), -1, $object->picto); + + // Object card + // ------------------------------------------------------------ + $linkback = '' . $langs->trans("BackToList") . ''; + + $morehtmlref = '
    '; + $morehtmlref .= '
    '; + + dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref); + + print '
    '; + print '
    '; + print '
    '; + + if ($action == 'edit') { + print '
    '; + print ''; + print ''; + if ($backtopage) { + print ''; + } + if ($backtopageforcancel) { + print ''; + } + + print dol_get_fiche_head(array(), ''); + + include DOL_DOCUMENT_ROOT . '/asset/tpl/depreciation_options_edit.tpl.php'; + + print dol_get_fiche_end(); + + print $form->buttonsSaveCancel(); + + print '
    '; + } else { + include DOL_DOCUMENT_ROOT . '/asset/tpl/depreciation_options_view.tpl.php'; + } + + print dol_get_fiche_end(); + + if ($action != 'edit') { + print '
    ' . "\n"; + $parameters = array(); + $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook + if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + } + + if (empty($reshook)) { + if ($object->status == $object::STATUS_DRAFT/* && !empty($object->enabled_modes)*/) { + print dolGetButtonAction($langs->trans('Modify'), '', 'default', $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=edit&token=' . newToken(), '', $permissiontoadd); + } + } + print '
    ' . "\n"; + } +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/asset/model/list.php b/htdocs/asset/model/list.php new file mode 100644 index 00000000000..57602b36e6d --- /dev/null +++ b/htdocs/asset/model/list.php @@ -0,0 +1,681 @@ + + * Copyright (C) 2018 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 + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/asset/model/list.php + * \ingroup asset + * \brief List page for asset model + */ + +// Load Dolibarr environment +require '../../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/asset/class/assetmodel.class.php'; + +// Load translation files required by the page +$langs->loadLangs(array("assets", "other")); + +$action = GETPOST('action', 'aZ09') ?GETPOST('action', 'aZ09') : 'view'; // The action 'add', 'create', 'edit', 'update', 'view', ... +$massaction = GETPOST('massaction', 'alpha'); // The bulk action (combo box choice into lists) +$show_files = GETPOST('show_files', 'int'); // Show files area generated by bulk actions ? +$confirm = GETPOST('confirm', 'alpha'); // Result of a confirmation +$cancel = GETPOST('cancel', 'alpha'); // We click on a Cancel button +$toselect = GETPOST('toselect', 'array'); // Array of ids of elements selected into a list +$contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : 'assetmodellist'; // To manage different context of search +$backtopage = GETPOST('backtopage', 'alpha'); // Go back to a dedicated page +$optioncss = GETPOST('optioncss', 'aZ'); // Option for the css output (always '' except when 'print') + +$id = GETPOST('id', 'int'); + +// Load variable for pagination +$limit = GETPOST('limit', 'int') ? GETPOST('limit', 'int') : $conf->liste_limit; +$sortfield = GETPOST('sortfield', 'aZ09comma'); +$sortorder = GETPOST('sortorder', 'aZ09comma'); +$page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int'); +if (empty($page) || $page < 0 || GETPOST('button_search', 'alpha') || GETPOST('button_removefilter', 'alpha') || (empty($toselect) && $massaction === '0')) { + $page = 0; +} // If $page is not defined, or '' or -1 or if we click on clear filters or if we select empty mass action +$offset = $limit * $page; +$pageprev = $page - 1; +$pagenext = $page + 1; + +// Initialize technical objects +$object = new AssetModel($db); +$extrafields = new ExtraFields($db); +$diroutputmassaction = $conf->asset->dir_output.'/temp/massgeneration/'.$user->id; +$hookmanager->initHooks(array('assetmodellist')); // Note that conf->hooks_modules contains array + +// Fetch optionals attributes and labels +$extrafields->fetch_name_optionals_label($object->table_element); +//$extrafields->fetch_name_optionals_label($object->table_element_line); + +$search_array_options = $extrafields->getOptionalsFromPost($object->table_element, '', 'search_'); + +// Default sort order (if not yet defined by previous GETPOST) +if (!$sortfield) { + reset($object->fields); // Reset is required to avoid key() to return null. + $sortfield = "t.".key($object->fields); // Set here default search field. By default 1st field in definition. +} +if (!$sortorder) { + $sortorder = "ASC"; +} + +// Initialize array of search criterias +$search_all = GETPOST('search_all', 'alphanohtml'); +$search = array(); +foreach ($object->fields as $key => $val) { + if ($key == 'fk_pays' && !GETPOSTISSET('search_'.$key)) { + $search[$key] = $mysoc->country_id; + } elseif (GETPOST('search_'.$key, 'alpha') !== '') { + $search[$key] = GETPOST('search_'.$key, 'alpha'); + } + if (preg_match('/^(date|timestamp|datetime)/', $val['type'])) { + $search[$key.'_dtstart'] = dol_mktime(0, 0, 0, GETPOST('search_'.$key.'_dtstartmonth', 'int'), GETPOST('search_'.$key.'_dtstartday', 'int'), GETPOST('search_'.$key.'_dtstartyear', 'int')); + $search[$key.'_dtend'] = dol_mktime(23, 59, 59, GETPOST('search_'.$key.'_dtendmonth', 'int'), GETPOST('search_'.$key.'_dtendday', 'int'), GETPOST('search_'.$key.'_dtendyear', 'int')); + } +} + +// List of fields to search into when doing a "search in all" +$fieldstosearchall = array(); +foreach ($object->fields as $key => $val) { + if (!empty($val['searchall'])) { + $fieldstosearchall['t.'.$key] = $val['label']; + } +} + +// Definition of array of fields for columns +$arrayfields = array(); +foreach ($object->fields as $key => $val) { + // If $val['visible']==0, then we never show the field + if (!empty($val['visible'])) { + $visible = (int) dol_eval($val['visible'], 1); + $arrayfields['t.'.$key] = array( + 'label'=>$val['label'], + 'checked'=>(($visible < 0) ? 0 : 1), + 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)), + 'position'=>$val['position'], + 'help'=> isset($val['help']) ? $val['help'] : '' + ); + } +} +// Extra fields +include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_array_fields.tpl.php'; + +$object->fields = dol_sort_array($object->fields, 'position'); +$arrayfields = dol_sort_array($arrayfields, 'position'); + +$permissiontoread = ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && $user->rights->asset->read) || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->asset->setup_advance->read))); +$permissiontoadd = ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && $user->rights->asset->write) || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->asset->setup_advance->write))); +$permissiontodelete = ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && $user->rights->asset->delete) || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->asset->setup_advance->delete))); + +// Security check +if (empty($conf->asset->enabled)) { + accessforbidden('Module not enabled'); +} + +// Security check (enable the most restrictive one) +if ($user->socid > 0) accessforbidden(); +$socid = 0; if ($user->socid > 0) $socid = $user->socid; +$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +restrictedArea($user, 'asset', $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +if (empty($conf->asset->enabled)) accessforbidden(); +if (!$permissiontoread) accessforbidden(); + + + +/* + * Actions + */ + +if (GETPOST('cancel', 'alpha')) { + $action = 'list'; + $massaction = ''; +} +if (!GETPOST('confirmmassaction', 'alpha') && $massaction != 'presend' && $massaction != 'confirm_presend') { + $massaction = ''; +} + +$parameters = array(); +$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); +} + +if (empty($reshook)) { + // Selection of new fields + include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php'; + + // Purge search criteria + if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // All tests are required to be compatible with all browsers + foreach ($object->fields as $key => $val) { + $search[$key] = ''; + if ($key == 'fk_pays') $search[$key] = $mysoc->country_id; + if (preg_match('/^(date|timestamp|datetime)/', $val['type'])) { + $search[$key.'_dtstart'] = ''; + $search[$key.'_dtend'] = ''; + } + } + $toselect = array(); + $search_array_options = array(); + } + if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha') + || GETPOST('button_search_x', 'alpha') || GETPOST('button_search.x', 'alpha') || GETPOST('button_search', 'alpha')) { + $massaction = ''; // Protection to avoid mass action if we force a new search during a mass action confirmation + } + + // Mass actions + $objectclass = 'AssetModel'; + $objectlabel = 'AssetModel'; + $uploaddir = $conf->asset->dir_output; + include DOL_DOCUMENT_ROOT.'/core/actions_massactions.inc.php'; +} + + + +/* + * View + */ + +$form = new Form($db); + +$now = dol_now(); + +$help_url = ''; +$title = $langs->trans('ListOf', $langs->transnoentitiesnoconv("AssetModels")); +$morejs = array(); +$morecss = array(); + + +// Build and execute select +// -------------------------------------------------------------------- +$sql = 'SELECT '; +$sql .= $object->getFieldList('t'); +// Add fields from extrafields +if (!empty($extrafields->attributes[$object->table_element]['label'])) { + foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) { + $sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? ", ef.".$key." as options_".$key : ''); + } +} +// Add fields from hooks +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters, $object); // Note that $action and $object may have been modified by hook +$sql .= preg_replace('/^,/', '', $hookmanager->resPrint); +$sql = preg_replace('/,\s*$/', '', $sql); +$sql .= " FROM ".MAIN_DB_PREFIX.$object->table_element." as t"; +if (isset($extrafields->attributes[$object->table_element]['label']) && is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label'])) { + $sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$object->table_element."_extrafields as ef on (t.rowid = ef.fk_object)"; +} +// Add table from hooks +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldListFrom', $parameters, $object); // Note that $action and $object may have been modified by hook +$sql .= $hookmanager->resPrint; +if ($object->ismultientitymanaged == 1) { + $sql .= " WHERE t.entity IN (".getEntity($object->element).")"; +} else { + $sql .= " WHERE 1 = 1"; +} +foreach ($search as $key => $val) { + if (array_key_exists($key, $object->fields)) { + if ($key == 'status' && $search[$key] == -1) { + continue; + } + $mode_search = (($object->isInt($object->fields[$key]) || $object->isFloat($object->fields[$key])) ? 1 : 0); + if ((strpos($object->fields[$key]['type'], 'integer:') === 0) || (strpos($object->fields[$key]['type'], 'sellist:') === 0) || !empty($object->fields[$key]['arrayofkeyval'])) { + if ($search[$key] == '-1' || ($search[$key] === '0' && (empty($object->fields[$key]['arrayofkeyval']) || !array_key_exists('0', $object->fields[$key]['arrayofkeyval'])))) { + $search[$key] = ''; + } + $mode_search = 2; + } + if ($search[$key] != '') { + $sql .= natural_search($key, $search[$key], (($key == 'status') ? 2 : $mode_search)); + } + } else { + if (preg_match('/(_dtstart|_dtend)$/', $key) && $search[$key] != '') { + $columnName = preg_replace('/(_dtstart|_dtend)$/', '', $key); + if (preg_match('/^(date|timestamp|datetime)/', $object->fields[$columnName]['type'])) { + if (preg_match('/_dtstart$/', $key)) { + $sql .= " AND t.".$columnName." >= '".$db->idate($search[$key])."'"; + } + if (preg_match('/_dtend$/', $key)) { + $sql .= " AND t." . $columnName . " <= '" . $db->idate($search[$key]) . "'"; + } + } + } + } +} +if ($search_all) { + $sql .= natural_search(array_keys($fieldstosearchall), $search_all); +} +//$sql.= dolSqlDateFilter("t.field", $search_xxxday, $search_xxxmonth, $search_xxxyear); +// Add where from extra fields +include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php'; +// Add where from hooks +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object); // Note that $action and $object may have been modified by hook +$sql .= $hookmanager->resPrint; + +/* If a group by is required +$sql .= " GROUP BY "; +foreach($object->fields as $key => $val) { + $sql .= "t.".$key.", "; +} +// Add fields from extrafields +if (!empty($extrafields->attributes[$object->table_element]['label'])) { + foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) { + $sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? "ef.".$key.', ' : ''); + } +} +// Add where from hooks +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldListGroupBy', $parameters, $object); // Note that $action and $object may have been modified by hook +$sql .= $hookmanager->resPrint; +$sql = preg_replace('/,\s*$/', '', $sql); +*/ + +// Add HAVING from hooks +/* +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldListHaving', $parameters, $object); // Note that $action and $object may have been modified by hook +$sql .= !empty($hookmanager->resPrint) ? (" HAVING 1=1 " . $hookmanager->resPrint) : ""; +*/ + +// Count total nb of records +$nbtotalofrecords = ''; +if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { + /* This old and fast method to get and count full list returns all record so use a high amount of memory. + $resql = $db->query($sql); + $nbtotalofrecords = $db->num_rows($resql); + */ + /* The slow method does not consume memory on mysql (not tested on pgsql) */ + /*$resql = $db->query($sql, 0, 'auto', 1); + while ($db->fetch_object($resql)) { + $nbtotalofrecords++; + }*/ + /* The fast and low memory method to get and count full list converts the sql into a sql count */ + $sqlforcount = preg_replace('/^SELECT[a-z0-9\._\s\(\),]+FROM/i', 'SELECT COUNT(*) as nbtotalofrecords FROM', $sql); + $resql = $db->query($sqlforcount); + $objforcount = $db->fetch_object($resql); + $nbtotalofrecords = $objforcount->nbtotalofrecords; + if (($page * $limit) > $nbtotalofrecords) { // if total of record found is smaller than page * limit, goto and load page 0 + $page = 0; + $offset = 0; + } + $db->free($resql); +} + +// Complete request and execute it with limit +$sql .= $db->order($sortfield, $sortorder); +if ($limit) { + $sql .= $db->plimit($limit + 1, $offset); +} + +$resql = $db->query($sql); +if (!$resql) { + dol_print_error($db); + exit; +} + +$num = $db->num_rows($resql); + + +// Direct jump if only one record found +if ($num == 1 && !empty($conf->global->MAIN_SEARCH_DIRECT_OPEN_IF_ONLY_ONE) && $search_all && !$page) { + $obj = $db->fetch_object($resql); + $id = $obj->rowid; + header("Location: ".DOL_URL_ROOT.'/asset/model/card.php?id='.$id); + exit; +} + + +// Output page +// -------------------------------------------------------------------- + +llxHeader('', $title, $help_url, '', 0, 0, $morejs, $morecss, '', ''); + +$arrayofselected = is_array($toselect) ? $toselect : array(); + +$param = ''; +if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) { + $param .= '&contextpage='.urlencode($contextpage); +} +if ($limit > 0 && $limit != $conf->liste_limit) { + $param .= '&limit='.urlencode($limit); +} +foreach ($search as $key => $val) { + if (is_array($search[$key]) && count($search[$key])) { + foreach ($search[$key] as $skey) { + if ($skey != '') { + $param .= '&search_'.$key.'[]='.urlencode($skey); + } + } + } elseif ($search[$key] != '') { + $param .= '&search_'.$key.'='.urlencode($search[$key]); + } +} +if ($optioncss != '') { + $param .= '&optioncss='.urlencode($optioncss); +} +// Add $param from extra fields +include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php'; +// Add $param from hooks +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldListSearchParam', $parameters, $object); // Note that $action and $object may have been modified by hook +$param .= $hookmanager->resPrint; + +// List of mass actions available +$arrayofmassactions = array( + //'validate'=>img_picto('', 'check', 'class="pictofixedwidth"').$langs->trans("Validate"), + //'generate_doc'=>img_picto('', 'pdf', 'class="pictofixedwidth"').$langs->trans("ReGeneratePDF"), + //'builddoc'=>img_picto('', 'pdf', 'class="pictofixedwidth"').$langs->trans("PDFMerge"), + //'presend'=>img_picto('', 'email', 'class="pictofixedwidth"').$langs->trans("SendByMail"), +); +if ($permissiontodelete) { + $arrayofmassactions['predelete'] = img_picto('', 'delete', 'class="pictofixedwidth"').$langs->trans("Delete"); +} +if (GETPOST('nomassaction', 'int') || in_array($massaction, array('presend', 'predelete'))) { + $arrayofmassactions = array(); +} +$massactionbutton = $form->selectMassAction('', $arrayofmassactions); + +print '
    '."\n"; +if ($optioncss != '') { + print ''; +} +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; + +$newcardbutton = dolGetButtonTitle($langs->trans('New'), '', 'fa fa-plus-circle', DOL_URL_ROOT.'/asset/model/card.php?action=create&backtopage='.urlencode($_SERVER['PHP_SELF']), '', $permissiontoadd); + +print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'object_'.$object->picto, 0, $newcardbutton, '', $limit, 0, 0, 1); + +// Add code for pre mass action (confirmation or email presend form) +$topicmail = "SendAssetModelRef"; +$modelmail = "assetmodel"; +$objecttmp = new AssetModel($db); +$trackid = 'assetmodel'.$object->id; +include DOL_DOCUMENT_ROOT.'/core/tpl/massactions_pre.tpl.php'; + +if ($search_all) { + foreach ($fieldstosearchall as $key => $val) { + $fieldstosearchall[$key] = $langs->trans($val); + } + print '
    '.$langs->trans("FilterOnInto", $search_all).join(', ', $fieldstosearchall).'
    '; +} + +$moreforfilter = ''; +/*$moreforfilter.='
    '; +$moreforfilter.= $langs->trans('MyFilter') . ': '; +$moreforfilter.= '
    ';*/ + +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters, $object); // Note that $action and $object may have been modified by hook +if (empty($reshook)) { + $moreforfilter .= $hookmanager->resPrint; +} else { + $moreforfilter = $hookmanager->resPrint; +} + +if (!empty($moreforfilter)) { + print '
    '; + print $moreforfilter; + print '
    '; +} + +$varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage; +$selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields +$selectedfields .= (count($arrayofmassactions) ? $form->showCheckAddButtons('checkforselect', 1) : ''); + +print '
    '; // You can use div-table-responsive-no-min if you dont need reserved height for your table +print ''."\n"; + + +// Fields title search +// -------------------------------------------------------------------- +print ''; +foreach ($object->fields as $key => $val) { + $cssforfield = (empty($val['csslist']) ? (empty($val['css']) ? '' : $val['css']) : $val['csslist']); + if ($key == 'status') { + $cssforfield .= ($cssforfield ? ' ' : '').'center'; + } elseif (in_array($val['type'], array('date', 'datetime', 'timestamp'))) { + $cssforfield .= ($cssforfield ? ' ' : '').'center'; + } elseif (in_array($val['type'], array('timestamp'))) { + $cssforfield .= ($cssforfield ? ' ' : '').'nowrap'; + } elseif (in_array($val['type'], array('double(24,8)', 'double(6,3)', 'integer', 'real', 'price')) && $val['label'] != 'TechnicalID' && empty($val['arrayofkeyval'])) { + $cssforfield .= ($cssforfield ? ' ' : '').'right'; + } + if (!empty($arrayfields['t.'.$key]['checked'])) { + print ''; + } +} +// Extra fields +include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_input.tpl.php'; + +// Fields from hook +$parameters = array('arrayfields'=>$arrayfields); +$reshook = $hookmanager->executeHooks('printFieldListOption', $parameters, $object); // Note that $action and $object may have been modified by hook +print $hookmanager->resPrint; +// Action column +print ''; +print ''."\n"; + + +// Fields title label +// -------------------------------------------------------------------- +print ''; +foreach ($object->fields as $key => $val) { + $cssforfield = (empty($val['csslist']) ? (empty($val['css']) ? '' : $val['css']) : $val['csslist']); + if ($key == 'status') { + $cssforfield .= ($cssforfield ? ' ' : '').'center'; + } elseif (in_array($val['type'], array('date', 'datetime', 'timestamp'))) { + $cssforfield .= ($cssforfield ? ' ' : '').'center'; + } elseif (in_array($val['type'], array('timestamp'))) { + $cssforfield .= ($cssforfield ? ' ' : '').'nowrap'; + } elseif (in_array($val['type'], array('double(24,8)', 'double(6,3)', 'integer', 'real', 'price')) && $val['label'] != 'TechnicalID' && empty($val['arrayofkeyval'])) { + $cssforfield .= ($cssforfield ? ' ' : '').'right'; + } + if (!empty($arrayfields['t.'.$key]['checked'])) { + print getTitleFieldOfList($arrayfields['t.'.$key]['label'], 0, $_SERVER['PHP_SELF'], 't.'.$key, '', $param, ($cssforfield ? 'class="'.$cssforfield.'"' : ''), $sortfield, $sortorder, ($cssforfield ? $cssforfield.' ' : ''))."\n"; + } +} +// Extra fields +include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php'; +// Hook fields +$parameters = array('arrayfields'=>$arrayfields, 'param'=>$param, 'sortfield'=>$sortfield, 'sortorder'=>$sortorder); +$reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters, $object); // Note that $action and $object may have been modified by hook +print $hookmanager->resPrint; +// Action column +print getTitleFieldOfList($selectedfields, 0, $_SERVER["PHP_SELF"], '', '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ')."\n"; +print ''."\n"; + + +// Detect if we need a fetch on each output line +$needToFetchEachLine = 0; +if (isset($extrafields->attributes[$object->table_element]['computed']) && is_array($extrafields->attributes[$object->table_element]['computed']) && count($extrafields->attributes[$object->table_element]['computed']) > 0) { + foreach ($extrafields->attributes[$object->table_element]['computed'] as $key => $val) { + if (preg_match('/\$object/', $val)) { + $needToFetchEachLine++; // There is at least one compute field that use $object + } + } +} + + +// Loop on record +// -------------------------------------------------------------------- +$i = 0; +$totalarray = array(); +$totalarray['nbfield'] = 0; +while ($i < ($limit ? min($num, $limit) : $num)) { + $obj = $db->fetch_object($resql); + if (empty($obj)) { + break; // Should not happen + } + + // Store properties in $object + $object->setVarsFromFetchObj($obj); + + // Show here line of result + print ''; + foreach ($object->fields as $key => $val) { + $cssforfield = (empty($val['csslist']) ? (empty($val['css']) ? '' : $val['css']) : $val['csslist']); + if (in_array($val['type'], array('date', 'datetime', 'timestamp'))) { + $cssforfield .= ($cssforfield ? ' ' : '').'center'; + } elseif ($key == 'status') { + $cssforfield .= ($cssforfield ? ' ' : '').'center'; + } + + if (in_array($val['type'], array('timestamp'))) { + $cssforfield .= ($cssforfield ? ' ' : '').'nowrap'; + } elseif ($key == 'ref') { + $cssforfield .= ($cssforfield ? ' ' : '').'nowrap'; + } + + if (in_array($val['type'], array('double(24,8)', 'double(6,3)', 'integer', 'real', 'price')) && !in_array($key, array('rowid', 'status')) && empty($val['arrayofkeyval'])) { + $cssforfield .= ($cssforfield ? ' ' : '').'right'; + } + //if (in_array($key, array('fk_soc', 'fk_user', 'fk_warehouse'))) $cssforfield = 'tdoverflowmax100'; + + if (!empty($arrayfields['t.'.$key]['checked'])) { + print ''; + if ($key == 'status') { + print $object->getLibStatut(5); + } elseif ($key == 'rowid') { + print $object->showOutputField($val, $key, $object->id, ''); + } else { + print $object->showOutputField($val, $key, $object->$key, ''); + } + print ''; + if (!$i) { + $totalarray['nbfield']++; + } + if (!empty($val['isameasure']) && $val['isameasure'] == 1) { + if (!$i) { + $totalarray['pos'][$totalarray['nbfield']] = 't.'.$key; + } + if (!isset($totalarray['val'])) { + $totalarray['val'] = array(); + } + if (!isset($totalarray['val']['t.'.$key])) { + $totalarray['val']['t.'.$key] = 0; + } + $totalarray['val']['t.'.$key] += $object->$key; + } + } + } + // Extra fields + include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php'; + // Fields from hook + $parameters = array('arrayfields'=>$arrayfields, 'object'=>$object, 'obj'=>$obj, 'i'=>$i, 'totalarray'=>&$totalarray); + $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters, $object); // Note that $action and $object may have been modified by hook + print $hookmanager->resPrint; + // Action column + print ''; + if (!$i) { + $totalarray['nbfield']++; + } + + print ''."\n"; + + $i++; +} + +// Show total line +include DOL_DOCUMENT_ROOT.'/core/tpl/list_print_total.tpl.php'; + +// If no record found +if ($num == 0) { + $colspan = 1; + foreach ($arrayfields as $key => $val) { + if (!empty($val['checked'])) { + $colspan++; + } + } + print ''; +} + + +$db->free($resql); + +$parameters = array('arrayfields'=>$arrayfields, 'sql'=>$sql); +$reshook = $hookmanager->executeHooks('printFieldListFooter', $parameters, $object); // Note that $action and $object may have been modified by hook +print $hookmanager->resPrint; + +print '
    '; + if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) { + print $form->selectarray('search_'.$key, $val['arrayofkeyval'], (isset($search[$key]) ? $search[$key] : ''), $val['notnull'], 0, 0, '', 1, 0, 0, '', 'maxwidth100', 1); + } elseif ((strpos($val['type'], 'integer:') === 0) || (strpos($val['type'], 'sellist:') === 0)) { + print $object->showInputField($val, $key, (isset($search[$key]) ? $search[$key] : ''), '', '', 'search_', 'maxwidth125', 1); + } elseif (preg_match('/^(date|timestamp|datetime)/', $val['type'])) { + print '
    '; + print $form->selectDate($search[$key.'_dtstart'] ? $search[$key.'_dtstart'] : '', "search_".$key."_dtstart", 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('From')); + print '
    '; + print '
    '; + print $form->selectDate($search[$key.'_dtend'] ? $search[$key.'_dtend'] : '', "search_".$key."_dtend", 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('to')); + print '
    '; + } elseif ($key == 'lang') { + require_once DOL_DOCUMENT_ROOT.'/core/class/html.formadmin.class.php'; + $formadmin = new FormAdmin($db); + print $formadmin->select_language($search[$key], 'search_lang', 0, null, 1, 0, 0, 'minwidth150 maxwidth200', 2); + } else { + print ''; + } + print '
    '; +$searchpicto = $form->showFilterButtons(); +print $searchpicto; +print '
    '; + if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined + $selected = 0; + if (in_array($object->id, $arrayofselected)) { + $selected = 1; + } + print ''; + } + print '
    '.$langs->trans("NoRecordFound").'
    '."\n"; +print '
    '."\n"; + +print '
    '."\n"; + +if (in_array('builddoc', $arrayofmassactions) && ($nbtotalofrecords === '' || $nbtotalofrecords)) { + $hidegeneratedfilelistifempty = 1; + if ($massaction == 'builddoc' || $action == 'remove_file' || $show_files) { + $hidegeneratedfilelistifempty = 0; + } + + require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; + $formfile = new FormFile($db); + + // Show list of available documents + $urlsource = $_SERVER['PHP_SELF'].'?sortfield='.$sortfield.'&sortorder='.$sortorder; + $urlsource .= str_replace('&', '&', $param); + + $filedir = $diroutputmassaction; + $genallowed = $permissiontoread; + $delallowed = $permissiontoadd; + + print $formfile->showdocuments('massfilesarea_asset', '', $filedir, $urlsource, 0, $delallowed, '', 1, 1, 0, 48, 1, $param, $title, '', '', '', null, $hidegeneratedfilelistifempty); +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/asset/model/note.php b/htdocs/asset/model/note.php new file mode 100644 index 00000000000..4af8407976f --- /dev/null +++ b/htdocs/asset/model/note.php @@ -0,0 +1,120 @@ + + * Copyright (C) 2018 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 + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/asset/model/note.php + * \ingroup asset + * \brief Card with notes on Asset Model + */ + +require '../../main.inc.php'; +require_once DOL_DOCUMENT_ROOT . '/core/lib/asset.lib.php'; +require_once DOL_DOCUMENT_ROOT . '/asset/class/assetmodel.class.php'; + +// Load translation files required by the page +$langs->loadLangs(array("assets", "companies")); + +// Get parameters +$id = GETPOST('id', 'int'); +$ref = GETPOST('ref', 'alpha'); +$action = GETPOST('action', 'aZ09'); +$cancel = GETPOST('cancel', 'aZ09'); +$backtopage = GETPOST('backtopage', 'alpha'); + +// Initialize technical objects +$object = new AssetModel($db); +$extrafields = new ExtraFields($db); +$diroutputmassaction = $conf->asset->dir_output . '/temp/massgeneration/' . $user->id; +$hookmanager->initHooks(array('assetmodelnote', 'globalcard')); // Note that conf->hooks_modules contains array +// Fetch optionals attributes and labels +$extrafields->fetch_name_optionals_label($object->table_element); + +// Load object +include DOL_DOCUMENT_ROOT . '/core/actions_fetchobject.inc.php'; // Must be include, not include_once // Must be include, not include_once. Include fetch and fetch_thirdparty but not fetch_optionals +if ($id > 0 || !empty($ref)) { + $upload_dir = $conf->asset->multidir_output[$object->entity] . "/" . $object->id; +} + +$permissiontoread = ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && $user->rights->asset->read) || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->asset->setup_advance->read))); +$permissiontoadd = ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && $user->rights->asset->write) || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->asset->setup_advance->write))); // Used by the include of actions_addupdatedelete.inc.php +$permissionnote = $permissiontoadd; // Used by the include of actions_setnotes.inc.php + +// Security check (enable the most restrictive one) +if ($user->socid > 0) accessforbidden(); +if ($user->socid > 0) $socid = $user->socid; +$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +restrictedArea($user, 'asset', $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +if (empty($conf->asset->enabled)) accessforbidden(); +if (!$permissiontoread) accessforbidden(); + + +/* + * Actions + */ + +$reshook = $hookmanager->executeHooks('doActions', array(), $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); +} +if (empty($reshook)) { + include DOL_DOCUMENT_ROOT . '/core/actions_setnotes.inc.php'; // Must be include, not include_once +} + + +/* + * View + */ + +$form = new Form($db); + +$help_url = ''; +llxHeader('', $langs->trans('AssetModel'), $help_url); + +if ($id > 0 || !empty($ref)) { + $object->fetch_thirdparty(); + + $head = assetModelPrepareHead($object); + + print dol_get_fiche_head($head, 'note', $langs->trans("AssetModel"), -1, $object->picto); + + // Object card + // ------------------------------------------------------------ + $linkback = '' . $langs->trans("BackToList") . ''; + + $morehtmlref = '
    '; + $morehtmlref .= '
    '; + + + dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref); + + + print '
    '; + print '
    '; + + + $cssclass = "titlefield"; + include DOL_DOCUMENT_ROOT . '/core/tpl/notes.tpl.php'; + + print '
    '; + + print dol_get_fiche_end(); +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/asset/note.php b/htdocs/asset/note.php index ebd340e393d..8de86d49bb7 100644 --- a/htdocs/asset/note.php +++ b/htdocs/asset/note.php @@ -27,7 +27,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/asset.lib.php'; require_once DOL_DOCUMENT_ROOT.'/asset/class/asset.class.php'; // Load translation files required by the page -$langs->loadLangs(array("asset", "companies")); +$langs->loadLangs(array("assets", "companies")); // Get parameters $id = GETPOST('id', 'int'); @@ -40,30 +40,24 @@ $backtopage = GETPOST('backtopage', 'alpha'); $object = new Asset($db); $extrafields = new ExtraFields($db); $diroutputmassaction = $conf->asset->dir_output.'/temp/massgeneration/'.$user->id; -$hookmanager->initHooks(array('assetnote')); // Note that conf->hooks_modules contains array - +$hookmanager->initHooks(array('assetnote', 'globalcard')); // Note that conf->hooks_modules contains array // Fetch optionals attributes and labels $extrafields->fetch_name_optionals_label($object->table_element); -// Security check - Protection if external user -//if ($user->socid > 0) accessforbidden(); -//if ($user->socid > 0) $socid = $user->socid; -//$result = restrictedArea($user, 'asset', $id); - // Load object include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be include, not include_once // Must be include, not include_once. Include fetch and fetch_thirdparty but not fetch_optionals if ($id > 0 || !empty($ref)) { $upload_dir = $conf->asset->multidir_output[$object->entity]."/".$object->id; } -// Security check -if (!empty($user->socid)) { - $socid = $user->socid; -} -$result = restrictedArea($user, 'asset', $id); +$permissionnote = $user->rights->asset->write; // Used by the include of actions_setnotes.inc.php +$permissiontoadd = $user->rights->asset->write; // Used by the include of actions_addupdatedelete.inc.php -$permissionnote = 1; -//$permissionnote=$user->rights->asset->creer; // Used by the include of actions_setnotes.inc.php +// Security check (enable the most restrictive one) +if ($user->socid > 0) accessforbidden(); +$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +if (empty($conf->asset->enabled)) accessforbidden(); /* @@ -78,67 +72,28 @@ if (empty($reshook)) { include DOL_DOCUMENT_ROOT.'/core/actions_setnotes.inc.php'; // Must be include, not include_once } + /* * View */ $form = new Form($db); -//$help_url='EN:Customers_Orders|FR:Commandes_Clients|ES:Pedidos de clientes'; $help_url = ''; -llxHeader('', $langs->trans('Assets'), $help_url); +llxHeader('', $langs->trans('Asset'), $help_url); if ($id > 0 || !empty($ref)) { $object->fetch_thirdparty(); - $head = asset_prepare_head($object); + $head = assetPrepareHead($object); - print dol_get_fiche_head($head, 'note', $langs->trans("Asset"), -1, 'generic'); + print dol_get_fiche_head($head, 'note', $langs->trans("Asset"), -1, $object->picto); // Object card // ------------------------------------------------------------ - $linkback = ''.$langs->trans("BackToList").''; + $linkback = '' . $langs->trans("BackToList") . ''; $morehtmlref = '
    '; - /* - // Ref customer - $morehtmlref.=$form->editfieldkey("RefCustomer", 'ref_client', $object->ref_client, $object, 0, 'string', '', 0, 1); - $morehtmlref.=$form->editfieldval("RefCustomer", 'ref_client', $object->ref_client, $object, 0, 'string', '', null, null, '', 1); - // Thirdparty - $morehtmlref.='
    '.$langs->trans('ThirdParty') . ' : ' . $object->thirdparty->getNomUrl(1); - // Project - if (! empty($conf->projet->enabled)) - { - $langs->load("projects"); - $morehtmlref.='
    '.$langs->trans('Project') . ' '; - if ($user->rights->asset->creer) - { - if ($action != 'classify') - //$morehtmlref.='' . img_edit($langs->transnoentitiesnoconv('SetProject')) . ' : '; - $morehtmlref.=' : '; - if ($action == 'classify') { - //$morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'projectid', 0, 0, 1, 1); - $morehtmlref.='
    '; - $morehtmlref.=''; - $morehtmlref.=''; - $morehtmlref.=$formproject->select_projects($object->socid, $object->fk_project, 'projectid', $maxlength, 0, 1, 0, 1, 0, 0, '', 1); - $morehtmlref.=''; - $morehtmlref.='
    '; - } else { - $morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'none', 0, 0, 0, 1); - } - } else { - if (! empty($object->fk_project)) { - $proj = new Project($db); - $proj->fetch($object->fk_project); - $morehtmlref.=''; - $morehtmlref.=$proj->ref; - $morehtmlref.=''; - } else { - $morehtmlref.=''; - } - } - }*/ $morehtmlref .= '
    '; @@ -150,7 +105,7 @@ if ($id > 0 || !empty($ref)) { $cssclass = "titlefield"; - include DOL_DOCUMENT_ROOT.'/core/tpl/notes.tpl.php'; + include DOL_DOCUMENT_ROOT . '/core/tpl/notes.tpl.php'; print ''; diff --git a/htdocs/asset/tpl/accountancy_codes_edit.tpl.php b/htdocs/asset/tpl/accountancy_codes_edit.tpl.php new file mode 100644 index 00000000000..bbd2b3d797c --- /dev/null +++ b/htdocs/asset/tpl/accountancy_codes_edit.tpl.php @@ -0,0 +1,81 @@ + + * + * 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 + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Show extrafields. It also show fields from hook formAssetAccountancyCode. Need to have following variables defined: + * $object (asset, assetmodel, ...) + * $assetaccountancycodes + * $action + * $conf + * $langs + * + * $parameters + */ + +// Protection to avoid direct call of template +if (empty($object) || !is_object($object)) { + print "Error, template page can't be called as URL"; + exit; +} + +if (!is_object($form)) { + $form = new Form($db); +} + +if (!empty($conf->accounting->enabled) && !is_object($formaccounting)) { + require_once DOL_DOCUMENT_ROOT . '/core/class/html.formaccounting.class.php'; + $formaccounting = new FormAccounting($db); +} + + +?> + +executeHooks('formAssetAccountancyCodes', $parameters, $object, $action); +print $hookmanager->resPrint; +if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); +} + +if (empty($reshook)) { + foreach ($assetaccountancycodes->accountancy_codes_fields as $mode_key => $mode_info) { + //if (empty($object->enabled_modes[$mode_key])) continue; + + print load_fiche_titre($langs->trans($mode_info['label']), '', ''); + print '
    '; + print '
    '; + print ''; + foreach ($mode_info['fields'] as $field_key => $field_info) { + $html_name = $mode_key . '_' . $field_key; + print ''; + } + print '
    ' . $langs->trans($field_info['label']) . ''; + $accountancy_code = GETPOSTISSET($html_name) ? GETPOST($html_name, 'aZ09') : (!empty($assetaccountancycodes->accountancy_codes[$mode_key][$field_key]) ? $assetaccountancycodes->accountancy_codes[$mode_key][$field_key] : ''); + if (!empty($conf->accounting->enabled)) { + print $formaccounting->select_account($accountancy_code, $html_name, 1, null, 1, 1, 'minwidth150 maxwidth300', 1); + } else { + print ''; + } + print '
    '; + print '
    '; + } +} +?> + diff --git a/htdocs/asset/tpl/accountancy_codes_view.tpl.php b/htdocs/asset/tpl/accountancy_codes_view.tpl.php new file mode 100644 index 00000000000..0d92ad8eb37 --- /dev/null +++ b/htdocs/asset/tpl/accountancy_codes_view.tpl.php @@ -0,0 +1,82 @@ + + * + * 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 + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Show extrafields. It also show fields from hook formAssetAccountancyCode. Need to have following variables defined: + * $object (asset, assetmodel, ...) + * $assetaccountancycodes + * $action + * $conf + * $langs + * + * $parameters + */ + +// Protection to avoid direct call of template +if (empty($object) || !is_object($object)) { + print "Error, template page can't be called as URL"; + exit; +} + +if (!is_object($form)) { + $form = new Form($db); +} + + +?> + +executeHooks('formAssetAccountancyCodes', $parameters, $object, $action); +print $hookmanager->resPrint; +if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); +} + +if (empty($reshook)) { + if (!empty($conf->accounting->enabled)) require_once DOL_DOCUMENT_ROOT . '/accountancy/class/accountingaccount.class.php'; + + foreach ($assetaccountancycodes->accountancy_codes_fields as $mode_key => $mode_info) { + //if (empty($object->enabled_modes[$mode_key])) continue; + + print load_fiche_titre($langs->trans($mode_info['label']), '', ''); + print '
    '; + print '
    '; + print ''; + foreach ($mode_info['fields'] as $field_key => $field_info) { + print ''; + } + print '
    ' . $langs->trans($field_info['label']) . ''; + if (!empty($assetaccountancycodes->accountancy_codes[$mode_key][$field_key])) { + $accountancy_code = $assetaccountancycodes->accountancy_codes[$mode_key][$field_key]; + if (!empty($conf->accounting->enabled)) { + $accountingaccount = new AccountingAccount($db); + $accountingaccount->fetch('', $accountancy_code, 1); + + print $accountingaccount->getNomUrl(0, 1, 1, '', 1); + } else { + print $accountancy_code; + } + } + print '
    '; + print '
    '; + } +} +?> + diff --git a/htdocs/asset/tpl/depreciation_options_edit.tpl.php b/htdocs/asset/tpl/depreciation_options_edit.tpl.php new file mode 100644 index 00000000000..140a19d5f2a --- /dev/null +++ b/htdocs/asset/tpl/depreciation_options_edit.tpl.php @@ -0,0 +1,228 @@ + + * + * 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 + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Show extrafields. It also show fields from hook formAssetAccountancyCode. Need to have following variables defined: + * $object (asset, assetmodel, ...) + * $assetaccountancycodes + * $action + * $conf + * $langs + * + * $parameters + */ + +// Protection to avoid direct call of template +if (empty($object) || !is_object($object)) { + print "Error, template page can't be called as URL"; + exit; +} + +if (!is_object($form)) { + $form = new Form($db); +} + +if (!is_object($formadmin)) { + require_once DOL_DOCUMENT_ROOT . '/core/class/html.formadmin.class.php'; + $formadmin = new FormAdmin($db); +} + + +?> + +executeHooks('formAssetDeprecationOptions', $parameters, $object, $action); +print $hookmanager->resPrint; +if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); +} + +if (empty($reshook)) { + $class_type = get_class($object) == 'Asset' ? 0 : 1; + foreach ($assetdepreciationoptions->deprecation_options_fields as $mode_key => $mode_info) { + if (!empty($mode_info['enabled_field'])) { + $info = explode(':', $mode_info['enabled_field']); + $enabled_field_info[] = array( + 'mode_key' => $info[0], + 'field_key' => $info[1], + 'value' => $info[2], + 'target' => 'block_' . $mode_key, + ); + } + + $assetdepreciationoptions->setInfosForMode($mode_key, $class_type, true); + $prefix_html_name = $mode_key . '_'; + + print '
    '; + print load_fiche_titre($langs->trans($mode_info['label']), '', ''); + print '
    '; + print '
    '; + print '
    '; + print '' . "\n"; + $mode_info['fields'] = dol_sort_array($mode_info['fields'], 'position'); + foreach ($mode_info['fields'] as $field_key => $field_info) { + // Discard if extrafield is a hidden field on form + if (abs($field_info['visible']) != 1 && abs($field_info['visible']) != 3 && abs($field_info['visible']) != 4) { + continue; + } + if (array_key_exists('enabled', $field_info) && isset($field_info['enabled']) && !verifCond($field_info['enabled'])) { + continue; // We don't want this field + } + if (!empty($field_info['column_break'])) { + print '
    '; + + // We close div and reopen for second column + print '
    '; + print '
    '; + + print '
    '; + print ''; + } + + $html_name = $prefix_html_name . $field_key; + if (!empty($field_info['enabled_field'])) { + $info = explode(':', $field_info['enabled_field']); + $enabled_field_info[] = array( + 'mode_key' => $info[0], + 'field_key' => $info[1], + 'value' => $info[2], + 'target' => 'field_' . $html_name, + ); + } + + $more_class = ''; + if (!empty($field_info['required']) || (isset($field_info['notnull']) && $field_info['notnull'] > 0)) { + $more_class .= ' fieldrequired'; + } + if (preg_match('/^(text|html)/', $val['type'])) { + $more_class .= ' tdtop'; + } + + print ''; + if (!empty($field_info['help'])) { + print $form->textwithpicto($langs->trans($field_info['label']), $langs->trans($field_info['help'])); + } else { + print $langs->trans($field_info['label']); + } + print ''; + print ''; + print ''; + } + print '
    '; + if (!empty($field_info['picto'])) { + print img_picto('', $field_info['picto'], '', false, 0, 0, '', 'pictofixedwidth'); + } + if (in_array($field_info['type'], array('int', 'integer'))) { + $value = GETPOSTISSET($html_name) ?GETPOST($html_name, 'int') : $assetdepreciationoptions->$field_key; + } elseif ($field_info['type'] == 'double') { + $value = GETPOSTISSET($html_name) ? price2num(GETPOST($html_name, 'alphanohtml')) : $assetdepreciationoptions->$field_key; + } elseif (preg_match('/^(text|html)/', $field_info['type'])) { + $tmparray = explode(':', $field_info['type']); + if (!empty($tmparray[1])) { + $check = $tmparray[1]; + } else { + $check = 'restricthtml'; + } + $value = GETPOSTISSET($html_name) ? GETPOST($html_name, $check) : $assetdepreciationoptions->$field_key; + } elseif ($field_info['type'] == 'price') { + $value = GETPOSTISSET($html_name) ? price2num(GETPOST($html_name)) : ($assetdepreciationoptions->$field_key ? price2num($assetdepreciationoptions->$field_key) : (!empty($field_info['default']) ? dol_eval($field_info['default'], 1) : 0)); + } elseif ($field_key == 'lang') { + $value = GETPOSTISSET($html_name) ? GETPOST($html_name, 'aZ09') : $assetdepreciationoptions->lang; + } else { + $value = GETPOSTISSET($html_name) ? GETPOST($html_name, 'alpha') : $assetdepreciationoptions->$field_key; + } + if (!empty($field_info['noteditable'])) { + print $assetdepreciationoptions->showOutputField($field_info, $field_key, $value, '', '', $prefix_html_name, 0); + } else { + if ($field_key == 'lang') { + print img_picto('', 'language', 'class="pictofixedwidth"'); + print $formadmin->select_language($value, $html_name, 0, null, 1, 0, 0, 'minwidth300', 2); + } else { + print $assetdepreciationoptions->showInputField($field_info, $field_key, $value, '', '', $prefix_html_name, 0); + } + } + print '
    '; + print '
    '; + print '
    '; + print '
    '; + print '
    '; + } +} + +if (!empty($enabled_field_info)) { + $enabled_field_info = json_encode($enabled_field_info); + print << +SCRIPT; +} + +?> + diff --git a/htdocs/asset/tpl/depreciation_options_view.tpl.php b/htdocs/asset/tpl/depreciation_options_view.tpl.php new file mode 100644 index 00000000000..2660fbbaee7 --- /dev/null +++ b/htdocs/asset/tpl/depreciation_options_view.tpl.php @@ -0,0 +1,154 @@ + + * + * 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 + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Show extrafields. It also show fields from hook formAssetAccountancyCode. Need to have following variables defined: + * $object (asset, assetmodel, ...) + * $assetaccountancycodes + * $action + * $conf + * $langs + * + * $parameters + */ + +// Protection to avoid direct call of template +if (empty($object) || !is_object($object)) { + print "Error, template page can't be called as URL"; + exit; +} + +if (!is_object($form)) { + $form = new Form($db); +} + + +?> + +executeHooks('formAssetDeprecationOptions', $parameters, $object, $action); +print $hookmanager->resPrint; +if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); +} + +if (empty($reshook)) { + $class_type = get_class($object) == 'Asset' ? 0 : 1; + foreach ($assetdepreciationoptions->deprecation_options_fields as $mode_key => $mode_info) { + if (!empty($mode_info['enabled_field'])) { + $info = explode(':', $mode_info['enabled_field']); + if ($assetdepreciationoptions->deprecation_options[$info[0]][$info[1]] != $info[2]) { + continue; + } + } + + $assetdepreciationoptions->setInfosForMode($mode_key, $class_type, true); + + print load_fiche_titre($langs->trans($mode_info['label']), '', ''); + print '
    '; + print '
    '; + print '
    '; + print '' . "\n"; + $mode_info['fields'] = dol_sort_array($mode_info['fields'], 'position'); + foreach ($mode_info['fields'] as $field_key => $field_info) { + if (!empty($field_info['enabled_field'])) { + $info = explode(':', $field_info['enabled_field']); + if ($assetdepreciationoptions->deprecation_options[$info[0]][$info[1]] != $info[2]) { + continue; + } + } + // Discard if extrafield is a hidden field on form + if (abs($field_info['visible']) != 1 && abs($field_info['visible']) != 3 && abs($field_info['visible']) != 4 && abs($field_info['visible']) != 5) { + continue; + } + if (array_key_exists('enabled', $field_info) && isset($field_info['enabled']) && !verifCond($field_info['enabled'])) { + continue; // We don't want this field + } + if (!empty($field_info['column_break'])) { + print '
    '; + + // We close div and reopen for second column + print '
    '; + print '
    '; + + print '
    '; + print ''; + } + + $key = $mode_key . '_' . $field_key; + $value = $assetdepreciationoptions->deprecation_options[$mode_key][$field_key]; + + print ''; + if (!empty($field_info['help'])) { + print $form->textwithpicto($langs->trans($field_info['label']), $langs->trans($field_info['help'])); + } else { + if (isset($field_info['copytoclipboard']) && $field_info['copytoclipboard'] == 1) { + print showValueWithClipboardCPButton($value, 0, $langs->transnoentitiesnoconv($field_info['label'])); + } else { + print $langs->trans($field_info['label']); + } + } + print ''; + print ''; + print ''; + } + print '
    '; + if (in_array($field_info['type'], array('text', 'html'))) { + print '
    '; + } + if ($field_key == 'lang') { + $langs->load("languages"); + $labellang = ($value ? $langs->trans('Language_' . $value) : ''); + print picto_from_langcode($value, 'class="paddingrightonly saturatemedium opacitylow"'); + print $labellang; + } else { + if (isset($field_info['copytoclipboard']) && $field_info['copytoclipboard'] == 2) { + $out = $assetdepreciationoptions->showOutputField($field_info, $field_key, $value, '', '', $mode_key . '_', 0); + print showValueWithClipboardCPButton($out, 0, $out); + } else { + print $assetdepreciationoptions->showOutputField($field_info, $field_key, $value, '', '', $mode_key . '_', 0); + } + } + if (in_array($field_info['type'], array('text', 'html'))) { + print '
    '; + } + print '
    '; + print '
    '; + print '
    '; + print '
    '; + } +} + +?> + diff --git a/htdocs/asset/tpl/depreciation_view.tpl.php b/htdocs/asset/tpl/depreciation_view.tpl.php new file mode 100644 index 00000000000..2660fbbaee7 --- /dev/null +++ b/htdocs/asset/tpl/depreciation_view.tpl.php @@ -0,0 +1,154 @@ + + * + * 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 + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Show extrafields. It also show fields from hook formAssetAccountancyCode. Need to have following variables defined: + * $object (asset, assetmodel, ...) + * $assetaccountancycodes + * $action + * $conf + * $langs + * + * $parameters + */ + +// Protection to avoid direct call of template +if (empty($object) || !is_object($object)) { + print "Error, template page can't be called as URL"; + exit; +} + +if (!is_object($form)) { + $form = new Form($db); +} + + +?> + +executeHooks('formAssetDeprecationOptions', $parameters, $object, $action); +print $hookmanager->resPrint; +if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); +} + +if (empty($reshook)) { + $class_type = get_class($object) == 'Asset' ? 0 : 1; + foreach ($assetdepreciationoptions->deprecation_options_fields as $mode_key => $mode_info) { + if (!empty($mode_info['enabled_field'])) { + $info = explode(':', $mode_info['enabled_field']); + if ($assetdepreciationoptions->deprecation_options[$info[0]][$info[1]] != $info[2]) { + continue; + } + } + + $assetdepreciationoptions->setInfosForMode($mode_key, $class_type, true); + + print load_fiche_titre($langs->trans($mode_info['label']), '', ''); + print '
    '; + print '
    '; + print '
    '; + print '' . "\n"; + $mode_info['fields'] = dol_sort_array($mode_info['fields'], 'position'); + foreach ($mode_info['fields'] as $field_key => $field_info) { + if (!empty($field_info['enabled_field'])) { + $info = explode(':', $field_info['enabled_field']); + if ($assetdepreciationoptions->deprecation_options[$info[0]][$info[1]] != $info[2]) { + continue; + } + } + // Discard if extrafield is a hidden field on form + if (abs($field_info['visible']) != 1 && abs($field_info['visible']) != 3 && abs($field_info['visible']) != 4 && abs($field_info['visible']) != 5) { + continue; + } + if (array_key_exists('enabled', $field_info) && isset($field_info['enabled']) && !verifCond($field_info['enabled'])) { + continue; // We don't want this field + } + if (!empty($field_info['column_break'])) { + print '
    '; + + // We close div and reopen for second column + print '
    '; + print '
    '; + + print '
    '; + print ''; + } + + $key = $mode_key . '_' . $field_key; + $value = $assetdepreciationoptions->deprecation_options[$mode_key][$field_key]; + + print ''; + if (!empty($field_info['help'])) { + print $form->textwithpicto($langs->trans($field_info['label']), $langs->trans($field_info['help'])); + } else { + if (isset($field_info['copytoclipboard']) && $field_info['copytoclipboard'] == 1) { + print showValueWithClipboardCPButton($value, 0, $langs->transnoentitiesnoconv($field_info['label'])); + } else { + print $langs->trans($field_info['label']); + } + } + print ''; + print ''; + print ''; + } + print '
    '; + if (in_array($field_info['type'], array('text', 'html'))) { + print '
    '; + } + if ($field_key == 'lang') { + $langs->load("languages"); + $labellang = ($value ? $langs->trans('Language_' . $value) : ''); + print picto_from_langcode($value, 'class="paddingrightonly saturatemedium opacitylow"'); + print $labellang; + } else { + if (isset($field_info['copytoclipboard']) && $field_info['copytoclipboard'] == 2) { + $out = $assetdepreciationoptions->showOutputField($field_info, $field_key, $value, '', '', $mode_key . '_', 0); + print showValueWithClipboardCPButton($out, 0, $out); + } else { + print $assetdepreciationoptions->showOutputField($field_info, $field_key, $value, '', '', $mode_key . '_', 0); + } + } + if (in_array($field_info['type'], array('text', 'html'))) { + print '
    '; + } + print '
    '; + print '
    '; + print '
    '; + print '
    '; + } +} + +?> + diff --git a/htdocs/asset/tpl/linkedobjectblock.tpl.php b/htdocs/asset/tpl/linkedobjectblock.tpl.php new file mode 100644 index 00000000000..59df306c829 --- /dev/null +++ b/htdocs/asset/tpl/linkedobjectblock.tpl.php @@ -0,0 +1,81 @@ + + * Copyright (C) 2013 Juanjo Menent + * Copyright (C) 2014 Marcos García + * + * 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 + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +// Protection to avoid direct call of template +if (empty($conf) || !is_object($conf)) { + print "Error, template page can't be called as URL"; + exit; +} + +print "\n"; + +global $user; +global $noMoreLinkedObjectBlockAfter; + +$langs = $GLOBALS['langs']; +$linkedObjectBlock = $GLOBALS['linkedObjectBlock']; + +// Load translation files required by the page +$langs->load("assets"); + +$linkedObjectBlock = dol_sort_array($linkedObjectBlock, 'date', 'desc', 0, 0, 1); + +$total = 0; +$ilink = 0; +foreach ($linkedObjectBlock as $key => $objectlink) { + $ilink++; + + $trclass = 'oddeven'; + if ($ilink == count($linkedObjectBlock) && empty($noMoreLinkedObjectBlockAfter) && count($linkedObjectBlock) <= 1) { + $trclass .= ' liste_sub_total'; + } + echo '
    '.$langs->trans("Asset"); + if (!empty($showImportButton) && !empty($conf->global->MAIN_ENABLE_IMPORT_LINKED_OBJECT_LINES)) { + print ' '; + echo ''.$objectlink->getNomUrl(1).''.$objectlink->label.''.dol_print_date($objectlink->date_start, 'day').''; + if ($user->rights->asset->read) { + $total = $total + $objectlink->acquisition_value_ht; + echo price($objectlink->acquisition_value_ht); + } + echo ''.$objectlink->getLibStatut(3).''; + echo ''.img_picto($langs->transnoentitiesnoconv("RemoveLink"), 'unlink').''; + echo '
    '.$langs->trans("Total").''.price($total).'
    '."\n"; - - print ''; - print ''; - print ''; - print ''; - print ''; - print ''; - print ''; - print "\n"; - - $assettype = new AssetType($db); - - while ($i < $num) { - $objp = $db->fetch_object($result); - - $assettype->id = $objp->rowid; - $assettype->ref = $objp->rowid; - $assettype->label = $objp->rowid; - - print ''; - print ''; - print ''; - - print ''; - - print ''; - - print ''; - - if ($user->rights->asset->write) { - print ''; - } else { - print ''; - } - print ""; - $i++; - } - - // If no record found - if ($num == 0) { - $colspan = 6; - print ''; - } - - print "
    '.$langs->trans("Ref").''.$langs->trans("Label").''.$langs->trans("AccountancyCodeAsset").''.$langs->trans("AccountancyCodeDepreciationAsset").''.$langs->trans("AccountancyCodeDepreciationExpense").' 
    '; - print $assettype->getNomUrl(1); - //'.img_object($langs->trans("ShowType"),'group').' '.$objp->rowid.' - print ''.dol_escape_htmltag($objp->label).''; - if (!empty($conf->accounting->enabled)) { - $accountingaccount = new AccountingAccount($db); - $accountingaccount->fetch('', $objp->accountancy_code_asset, 1); - - print $accountingaccount->getNomUrl(0, 1, 1, '', 0); - } else { - print $objp->accountancy_code_asset; - } - print ''; - if (!empty($conf->accounting->enabled)) { - $accountingaccount2 = new AccountingAccount($db); - $accountingaccount2->fetch('', $objp->accountancy_code_depreciation_asset, 1); - - print $accountingaccount2->getNomUrl(0, 1, 1, '', 0); - } else { - print $objp->accountancy_code_depreciation_asset; - } - print ''; - if (!empty($conf->accounting->enabled)) { - $accountingaccount3 = new AccountingAccount($db); - $accountingaccount3->fetch('', $objp->accountancy_code_depreciation_expense, 1); - - print $accountingaccount3->getNomUrl(0, 1, 1, '', 0); - } else { - print $objp->accountancy_code_depreciation_expense; - } - print 'rowid.'">'.img_edit().' 
    '.$langs->trans("NoRecordFound").'
    "; - print '
    '; - - print ''; - } else { - dol_print_error($db); - } -} - - -/* ************************************************************************** */ -/* */ -/* Creation mode */ -/* */ -/* ************************************************************************** */ -if ($action == 'create') { - $object = new AssetType($db); - if (!empty($conf->accounting->enabled)) { - $formaccounting = new FormAccounting($db); - } - - print load_fiche_titre($langs->trans("NewAssetType"), '', $object->picto); - - print '
    '; - print ''; - print ''; - - print dol_get_fiche_head(''); - - print ''; - print ''; - - print ''; - - if (!empty($conf->accounting->enabled)) { - // Accountancy_code_asset - print ''; - print ''; - - // Accountancy_code_depreciation_expense - print ''; - print ''; - - // Accountancy_code_depreciation_expense - print ''; - print ''; - } else // For external software - { - // Accountancy_code_asset - print ''; - print ''; - - // Accountancy_code_depreciation_asset - print ''; - print ''; - - // Accountancy_code_depreciation_expense - print ''; - print ''; - } - - print ''; - - // Other attributes - $parameters = array(); - $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $object, $action); // Note that $action and $object may have been modified by hook - print $hookmanager->resPrint; - if (empty($reshook)) { - print $object->showOptionals($extrafields, 'create', $parameters); - } - print ''; - print "
    '.$langs->trans("Label").'
    '.$langs->trans("AccountancyCodeAsset").''; - print $formaccounting->select_account($object->accountancy_code_asset, 'accountancy_code_asset', 1, '', 1, 1); - print '
    '.$langs->trans("AccountancyCodeDepreciationAsset").''; - print $formaccounting->select_account($object->accountancy_code_depreciation_asset, 'accountancy_code_depreciation_asset', 1, '', 1, 1); - print '
    '.$langs->trans("AccountancyCodeDepreciationExpense").''; - print $formaccounting->select_account($object->accountancy_code_depreciation_expense, 'accountancy_code_depreciation_expense', 1, '', 1, 1); - print '
    '.$langs->trans("AccountancyCodeAsset").''; - print '
    '.$langs->trans("AccountancyCodeDepreciationAsset").''; - print '
    '.$langs->trans("AccountancyCodeDepreciationExpense").''; - print '
    '.$langs->trans("Description").''; - print '
    \n"; - - print dol_get_fiche_end(); - - print $form->buttonsSaveCancel("Add"); - - print "
    \n"; -} - -/* ************************************************************************** */ -/* */ -/* View mode */ -/* */ -/* ************************************************************************** */ -if ($rowid > 0) { - if ($action != 'edit') { - $object = new AssetType($db); - $object->fetch($rowid); - $object->fetch_optionals(); - - /* - * Confirmation suppression - */ - if ($action == 'delete') { - print $form->formconfirm($_SERVER['PHP_SELF']."?rowid=".$object->id, $langs->trans("DeleteAnAssetType"), $langs->trans("ConfirmDeleteAssetType", $object->label), "confirm_delete", '', 0, 1); - } - - $head = asset_type_prepare_head($object); - - print dol_get_fiche_head($head, 'card', $langs->trans("AssetType"), -1, 'asset'); - - $linkback = ''.$langs->trans("BackToList").''; - - $morehtmlref = '
    '; - // Ref asset type - $morehtmlref .= $form->editfieldkey("Label", 'label', $object->label, $object, $user->rights->asset->write, 'string', '', 0, 1); - $morehtmlref .= $form->editfieldval("Label", 'label', $object->label, $object, $user->rights->asset->write, 'string', '', null, null, '', 1); - $morehtmlref .= '
    '; - - dol_banner_tab($object, 'rowid', $linkback, 1, 'rowid', 'ref', $morehtmlref, '', 0, '', $morehtmlright); - - print '
    '; - print '
    '; - - print ''; - - print ''; - print ''; - print ''; - - print ''; - print ''; - print ''; - - print ''; - print ''; - print ''; - - print '"; - - // Other attributes - include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php'; - - print '
    '; - print $langs->trans("AccountancyCodeAsset"); - print ''; - if (!empty($conf->accounting->enabled)) { - $accountingaccount = new AccountingAccount($db); - $accountingaccount->fetch('', $object->accountancy_code_asset, 1); - - print $accountingaccount->getNomUrl(0, 1, 1, '', 1); - } else { - print $object->accountancy_code_asset; - } - print '
    '; - print $langs->trans("AccountancyCodeDepreciationAsset"); - print ''; - if (!empty($conf->accounting->enabled)) { - $accountingaccount2 = new AccountingAccount($db); - $accountingaccount2->fetch('', $object->accountancy_code_depreciation_asset, 1); - - print $accountingaccount2->getNomUrl(0, 1, 1, '', 1); - } else { - print $object->accountancy_code_depreciation_asset; - } - print '
    '; - print $langs->trans("AccountancyCodeDepreciationExpense"); - print ''; - if (!empty($conf->accounting->enabled)) { - $accountingaccount3 = new AccountingAccount($db); - $accountingaccount3->fetch('', $object->accountancy_code_depreciation_expense, 1); - - print $accountingaccount3->getNomUrl(0, 1, 1, '', 1); - } else { - print $object->accountancy_code_depreciation_expense; - } - print '
    '.$langs->trans("Description").''; - print nl2br($object->note)."
    '; - print '
    '; - - print dol_get_fiche_end(); - - /* - * Buttons - */ - - print '
    '; - - // Edit - if ($user->rights->asset->write) { - print ''; - } - - // Delete - if ($user->rights->asset->write) { - print ''; - } - - print "
    "; - } - - /* ************************************************************************** */ - /* */ - /* Edition mode */ - /* */ - /* ************************************************************************** */ - - if ($action == 'edit') { - $object = new AssetType($db); - $object->fetch($rowid); - $object->fetch_optionals(); - if (!empty($conf->accounting->enabled)) { - $formaccounting = new FormAccounting($db); - } - - $head = asset_type_prepare_head($object); - - print '
    '; - print ''; - print ''; - print ''; - - print dol_get_fiche_head($head, 'card', $langs->trans("AssetsType"), -1, 'setup'); - - print ''; - - print ''; - - print ''; - - if (!empty($conf->accounting->enabled)) { - // Accountancy_code_asset - print ''; - print ''; - - // Accountancy_code_depreciation_expense - print ''; - print ''; - - // Accountancy_code_depreciation_expense - print ''; - print ''; - } else // For external software - { - // Accountancy_code_asset - print ''; - print ''; - - // Accountancy_code_depreciation_asset - print ''; - print ''; - - // Accountancy_code_depreciation_expense - print ''; - print ''; - } - - print ''; - - // Other attributes - $parameters = array(); - $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $act, $action); // Note that $action and $object may have been modified by hook - print $hookmanager->resPrint; - if (empty($reshook)) { - print $object->showOptionals($extrafields, 'edit', $parameters); - } - - // Other attributes - include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_edit.tpl.php'; - - print '
    '.$langs->trans("Ref").''.$object->id.'
    '.$langs->trans("Label").'
    '.$langs->trans("AccountancyCodeAsset").''; - print $formaccounting->select_account($object->accountancy_code_asset, 'accountancy_code_asset', 1, '', 1, 1); - print '
    '.$langs->trans("AccountancyCodeDepreciationAsset").''; - print $formaccounting->select_account($object->accountancy_code_depreciation_asset, 'accountancy_code_depreciation_asset', 1, '', 1, 1); - print '
    '.$langs->trans("AccountancyCodeDepreciationExpense").''; - print $formaccounting->select_account($object->accountancy_code_depreciation_expense, 'accountancy_code_depreciation_expense', 1, '', 1, 1); - print '
    '.$langs->trans("AccountancyCodeAsset").''; - print '
    '.$langs->trans("AccountancyCodeDepreciationAsset").''; - print '
    '.$langs->trans("AccountancyCodeDepreciationExpense").''; - print '
    '.$langs->trans("Description").''; - print '
    '; - - print dol_get_fiche_end(); - - print $form->buttonsSaveCancel(); - - print "
    "; - } -} - -// End of page -llxFooter(); -$db->close(); From bb968562062e10b33f5bec529cb77a54f19c60b3 Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Mon, 14 Feb 2022 05:16:08 +0100 Subject: [PATCH 07/20] Lang --- htdocs/langs/en_US/admin.lang | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang index 74cda5437e1..cd90541f889 100644 --- a/htdocs/langs/en_US/admin.lang +++ b/htdocs/langs/en_US/admin.lang @@ -1068,6 +1068,7 @@ DictionaryExpenseTaxCat=Expense report - Transportation categories DictionaryExpenseTaxRange=Expense report - Range by transportation category DictionaryTransportMode=Intracomm report - Transport mode DictionaryBatchStatus=Product lot/serial Quality Control status +DictionaryAssetDisposalType=Type of disposal of assets TypeOfUnit=Type of unit SetupSaved=Setup saved SetupNotSaved=Setup not saved @@ -2220,4 +2221,4 @@ NoDeployedModulesFoundWithThisSearchCriteria=No modules found for these search c API_DISABLE_COMPRESSION=Disable compression of API responses EachTerminalHasItsOwnCounter=Each terminal use its own counter. FillAndSaveAccountIdAndSecret=Fill and save account ID and secret first -PreviousHash=Previous hash \ No newline at end of file +PreviousHash=Previous hash From 2d9e303abf1cc174cc830c6009bffd4513cc531e Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Mon, 14 Feb 2022 04:18:50 +0000 Subject: [PATCH 08/20] Fixing style errors. --- htdocs/asset/admin/setup.php | 48 +-- htdocs/asset/card.php | 2 +- htdocs/asset/class/asset.class.php | 314 +++++++++--------- .../class/assetdepreciationoptions.class.php | 48 +-- htdocs/asset/class/assetmodel.class.php | 8 +- htdocs/asset/document.php | 4 +- htdocs/asset/model/agenda.php | 52 +-- htdocs/asset/model/card.php | 16 +- htdocs/asset/model/list.php | 10 +- .../tpl/depreciation_options_edit.tpl.php | 6 +- 10 files changed, 254 insertions(+), 254 deletions(-) diff --git a/htdocs/asset/admin/setup.php b/htdocs/asset/admin/setup.php index b671f309138..85f8dc1e4c6 100644 --- a/htdocs/asset/admin/setup.php +++ b/htdocs/asset/admin/setup.php @@ -46,7 +46,7 @@ $scandir = GETPOST('scan_dir', 'alpha'); $type = 'asset'; $arrayofparameters = array( - 'ASSET_ACCOUNTANCY_CATEGORY'=>array('type'=>'accountancy_category', 'enabled'=>1), + 'ASSET_ACCOUNTANCY_CATEGORY'=>array('type'=>'accountancy_category', 'enabled'=>1), //'ASSET_MYPARAM1'=>array('type'=>'string', 'css'=>'minwidth500' ,'enabled'=>1), //'ASSET_MYPARAM2'=>array('type'=>'textarea','enabled'=>1), //'ASSET_MYPARAM3'=>array('type'=>'category:'.Categorie::TYPE_CUSTOMER, 'enabled'=>1), @@ -548,29 +548,29 @@ if ($action == 'edit') { } else { print ''; } - } elseif ($val['type'] == 'accountancy_category') { - $selected = (empty($conf->global->$constname) ? '' : $conf->global->$constname); - if (!empty($conf->accounting->enabled)) { - print ''; - // autosuggest from existing account types if found - print ''; - require_once DOL_DOCUMENT_ROOT . '/accountancy/class/accountancysystem.class.php'; - $accountsystem = new AccountancySystem($db); - $accountsystem->fetch($conf->global->CHARTOFACCOUNTS); - $sql = 'SELECT DISTINCT pcg_type FROM ' . MAIN_DB_PREFIX . 'accounting_account'; - $sql .= " WHERE fk_pcg_version = '" . $db->escape($accountsystem->ref) . "'"; - $sql .= ' AND entity in ('.getEntity('accounting_account', 0).')'; // Always limit to current entity. No sharing in accountancy. - $sql .= ' LIMIT 50000'; // just as a sanity check - $resql = $db->query($sql); - if ($resql) { - while ($obj = $db->fetch_object($resql)) { - print ''; - } else { - print ''; - } + } elseif ($val['type'] == 'accountancy_category') { + $selected = (empty($conf->global->$constname) ? '' : $conf->global->$constname); + if (!empty($conf->accounting->enabled)) { + print ''; + // autosuggest from existing account types if found + print ''; + require_once DOL_DOCUMENT_ROOT . '/accountancy/class/accountancysystem.class.php'; + $accountsystem = new AccountancySystem($db); + $accountsystem->fetch($conf->global->CHARTOFACCOUNTS); + $sql = 'SELECT DISTINCT pcg_type FROM ' . MAIN_DB_PREFIX . 'accounting_account'; + $sql .= " WHERE fk_pcg_version = '" . $db->escape($accountsystem->ref) . "'"; + $sql .= ' AND entity in ('.getEntity('accounting_account', 0).')'; // Always limit to current entity. No sharing in accountancy. + $sql .= ' LIMIT 50000'; // just as a sanity check + $resql = $db->query($sql); + if ($resql) { + while ($obj = $db->fetch_object($resql)) { + print ''; + } else { + print ''; + } } else { print ''; } diff --git a/htdocs/asset/card.php b/htdocs/asset/card.php index 83271e299f0..6b2e88ac630 100644 --- a/htdocs/asset/card.php +++ b/htdocs/asset/card.php @@ -293,7 +293,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ReOpen'), $langs->trans('AssetConfirmReOpenAsk', $object->ref), 'confirm_reopen', $formquestion, 'yes', 1); } // Clone confirmation -/* elseif ($action == 'clone') { + /* elseif ($action == 'clone') { // Create an array for form $formquestion = array(); $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ToClone'), $langs->trans('ConfirmCloneAsk', $object->ref), 'confirm_clone', $formquestion, 'yes', 1); diff --git a/htdocs/asset/class/asset.class.php b/htdocs/asset/class/asset.class.php index 76f50c136fd..c1ea4a130d8 100644 --- a/htdocs/asset/class/asset.class.php +++ b/htdocs/asset/class/asset.class.php @@ -258,89 +258,89 @@ class Asset extends CommonObject dol_syslog(__METHOD__, LOG_DEBUG); -// $object = new self($this->db); -// -// $this->db->begin(); -// -// // Load source object -// $result = $object->fetchCommon($fromid); -// if ($result > 0 && !empty($object->table_element_line)) { -// $object->fetchLines(); -// } -// -// // get lines so they will be clone -// //foreach($this->lines as $line) -// // $line->fetch_optionals(); -// -// // Reset some properties -// unset($object->id); -// unset($object->fk_user_creat); -// unset($object->import_key); -// -// // Clear fields -// if (property_exists($object, 'ref')) { -// $object->ref = empty($this->fields['ref']['default']) ? "Copy_Of_".$object->ref : $this->fields['ref']['default']; -// } -// if (property_exists($object, 'label')) { -// $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf")." ".$object->label : $this->fields['label']['default']; -// } -// if (property_exists($object, 'status')) { -// $object->status = self::STATUS_DRAFT; -// } -// if (property_exists($object, 'date_creation')) { -// $object->date_creation = dol_now(); -// } -// if (property_exists($object, 'date_modification')) { -// $object->date_modification = null; -// } -// // ... -// // Clear extrafields that are unique -// if (is_array($object->array_options) && count($object->array_options) > 0) { -// $extrafields->fetch_name_optionals_label($this->table_element); -// foreach ($object->array_options as $key => $option) { -// $shortkey = preg_replace('/options_/', '', $key); -// if (!empty($extrafields->attributes[$this->table_element]['unique'][$shortkey])) { -// //var_dump($key); var_dump($clonedObj->array_options[$key]); exit; -// unset($object->array_options[$key]); -// } -// } -// } -// -// // Create clone -// $object->context['createfromclone'] = 'createfromclone'; -// $result = $object->createCommon($user); -// if ($result < 0) { -// $error++; -// $this->error = $object->error; -// $this->errors = $object->errors; -// } -// -// if (!$error) { -// // copy internal contacts -// if ($this->copy_linked_contact($object, 'internal') < 0) { -// $error++; -// } -// } -// -// if (!$error) { -// // copy external contacts if same company -// if (property_exists($this, 'fk_soc') && $this->fk_soc == $object->socid) { -// if ($this->copy_linked_contact($object, 'external') < 0) { -// $error++; -// } -// } -// } -// -// unset($object->context['createfromclone']); -// -// // End -// if (!$error) { -// $this->db->commit(); -// return $object; -// } else { -// $this->db->rollback(); -// return -1; -// } + // $object = new self($this->db); + // + // $this->db->begin(); + // + // // Load source object + // $result = $object->fetchCommon($fromid); + // if ($result > 0 && !empty($object->table_element_line)) { + // $object->fetchLines(); + // } + // + // // get lines so they will be clone + // //foreach($this->lines as $line) + // // $line->fetch_optionals(); + // + // // Reset some properties + // unset($object->id); + // unset($object->fk_user_creat); + // unset($object->import_key); + // + // // Clear fields + // if (property_exists($object, 'ref')) { + // $object->ref = empty($this->fields['ref']['default']) ? "Copy_Of_".$object->ref : $this->fields['ref']['default']; + // } + // if (property_exists($object, 'label')) { + // $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf")." ".$object->label : $this->fields['label']['default']; + // } + // if (property_exists($object, 'status')) { + // $object->status = self::STATUS_DRAFT; + // } + // if (property_exists($object, 'date_creation')) { + // $object->date_creation = dol_now(); + // } + // if (property_exists($object, 'date_modification')) { + // $object->date_modification = null; + // } + // // ... + // // Clear extrafields that are unique + // if (is_array($object->array_options) && count($object->array_options) > 0) { + // $extrafields->fetch_name_optionals_label($this->table_element); + // foreach ($object->array_options as $key => $option) { + // $shortkey = preg_replace('/options_/', '', $key); + // if (!empty($extrafields->attributes[$this->table_element]['unique'][$shortkey])) { + // //var_dump($key); var_dump($clonedObj->array_options[$key]); exit; + // unset($object->array_options[$key]); + // } + // } + // } + // + // // Create clone + // $object->context['createfromclone'] = 'createfromclone'; + // $result = $object->createCommon($user); + // if ($result < 0) { + // $error++; + // $this->error = $object->error; + // $this->errors = $object->errors; + // } + // + // if (!$error) { + // // copy internal contacts + // if ($this->copy_linked_contact($object, 'internal') < 0) { + // $error++; + // } + // } + // + // if (!$error) { + // // copy external contacts if same company + // if (property_exists($this, 'fk_soc') && $this->fk_soc == $object->socid) { + // if ($this->copy_linked_contact($object, 'external') < 0) { + // $error++; + // } + // } + // } + // + // unset($object->context['createfromclone']); + // + // // End + // if (!$error) { + // $this->db->commit(); + // return $object; + // } else { + // $this->db->rollback(); + // return -1; + // } return -1; } @@ -656,7 +656,7 @@ class Asset extends CommonObject $sql .= " WHERE doc_type = 'asset'"; $sql .= ")"; $sql .= "SELECT ad.rowid, ad.depreciation_mode, ad.ref, ad.depreciation_date, ad.depreciation_ht, ad.cumulative_depreciation_ht"; - $sql .= ", " . $this->db->ifsql('iab.fk_docdet IS NOT NULL', 1 , 0) . " AS bookkeeping"; + $sql .= ", " . $this->db->ifsql('iab.fk_docdet IS NOT NULL', 1, 0) . " AS bookkeeping"; $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad"; $sql .= " LEFT JOIN in_accounting_bookkeeping as iab ON iab.fk_docdet = ad.rowid"; $sql .= " WHERE ad.fk_asset = " . $this->id; @@ -766,12 +766,12 @@ class Asset extends CommonObject $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)"; $sql .= " VALUES ( "; - $sql .= " " . (int)$this->id; + $sql .= " " . (int) $this->id; $sql .= ", '" . $this->db->escape($mode) . "'"; $sql .= ", '" . $this->db->escape($ref) . "'"; $sql .= ", '" . $this->db->idate($depreciation_date) . "'"; - $sql .= ", " . (double)$depreciation_ht; - $sql .= ", " . (double)$cumulative_depreciation_ht; + $sql .= ", " . (double) $depreciation_ht; + $sql .= ", " . (double) $cumulative_depreciation_ht; $sql .= ", '" . $this->db->escape($accountancy_code_debit) . "'"; $sql .= ", '" . $this->db->escape($accountancy_code_credit) . "'"; $sql .= ")"; @@ -919,18 +919,18 @@ class Asset extends CommonObject $depreciation_date_start = $this->date_start > $this->date_acquisition ? $this->date_start : $this->date_acquisition; $depreciation_date_end = dol_time_plus_duree($depreciation_date_start, $fields['duration'], $fields['duration_type'] == 1 ? 'm' : ($fields['duration_type'] == 2 ? 'd' : 'y')); $depreciation_amount = $fields['amount_base_depreciation_ht']; - if ($fields['duration_type'] == 2) { // Daily - $fiscal_period_start = $depreciation_date_start; - $fiscal_period_end = $depreciation_date_start; - } elseif ($fields['duration_type'] == 1) { // Monthly - $date_temp = dol_getdate($depreciation_date_start); - $fiscal_period_start = dol_get_first_day($date_temp['year'], $date_temp['mon'], false); - $fiscal_period_end = dol_get_last_day($date_temp['year'], $date_temp['mon'], false); - } else { // Annually - $fiscal_period_start = $init_fiscal_period_start; - $fiscal_period_end = $init_fiscal_period_end; - } - $cumulative_depreciation_ht = $last_cumulative_depreciation_ht; + if ($fields['duration_type'] == 2) { // Daily + $fiscal_period_start = $depreciation_date_start; + $fiscal_period_end = $depreciation_date_start; + } elseif ($fields['duration_type'] == 1) { // Monthly + $date_temp = dol_getdate($depreciation_date_start); + $fiscal_period_start = dol_get_first_day($date_temp['year'], $date_temp['mon'], false); + $fiscal_period_end = dol_get_last_day($date_temp['year'], $date_temp['mon'], false); + } else { // Annually + $fiscal_period_start = $init_fiscal_period_start; + $fiscal_period_end = $init_fiscal_period_end; + } + $cumulative_depreciation_ht = $last_cumulative_depreciation_ht; $depreciation_period_amount = $depreciation_amount - $this->reversal_amount_ht; $start_date = $depreciation_date_start; $disposal_date = isset($this->disposal_date) && $this->disposal_date !== "" ? $this->disposal_date : ""; @@ -972,12 +972,12 @@ class Asset extends CommonObject // futures depreciation lines //----------------------------------------------------- $nb_days_in_year = !empty($conf->global->ASSET_DEPRECIATION_DURATION_PER_YEAR) ? $conf->global->ASSET_DEPRECIATION_DURATION_PER_YEAR : 360; - $nb_days_in_month = !empty($conf->global->ASSET_DEPRECIATION_DURATION_PER_MONTH) ? $conf->global->ASSET_DEPRECIATION_DURATION_PER_MONTH : 30; - $period_amount = (double) price2num($depreciation_period_amount / $fields['duration'], 'MT'); - $first_period_found = false; + $nb_days_in_month = !empty($conf->global->ASSET_DEPRECIATION_DURATION_PER_MONTH) ? $conf->global->ASSET_DEPRECIATION_DURATION_PER_MONTH : 30; + $period_amount = (double) price2num($depreciation_period_amount / $fields['duration'], 'MT'); + $first_period_found = false; $first_period_date = isset($begin_period) && $begin_period > $fiscal_period_start ? $begin_period : $fiscal_period_start; - $ref_date_format = "%Y" . ($fields['duration_type'] == 1 || $fields['duration_type'] == 2 ? '-%m' : '') . ($fields['duration_type'] == 2 ? '-%d' : ''); + $ref_date_format = "%Y" . ($fields['duration_type'] == 1 || $fields['duration_type'] == 2 ? '-%m' : '') . ($fields['duration_type'] == 2 ? '-%d' : ''); // Loop security $idx_loop = 0; @@ -995,8 +995,8 @@ class Asset extends CommonObject $first_period_found = true; - $period_begin = dol_print_date($fiscal_period_start, $ref_date_format); - $period_end = dol_print_date($fiscal_period_end, $ref_date_format); + $period_begin = dol_print_date($fiscal_period_start, $ref_date_format); + $period_end = dol_print_date($fiscal_period_end, $ref_date_format); $ref = $period_begin . ($period_begin != $period_end ? ' - ' . $period_end : ''); if ($fiscal_period_start <= $disposal_date && $disposal_date <= $fiscal_period_end) { $ref .= ' - ' . $langs->transnoentitiesnoconv('AssetDisposal'); @@ -1004,24 +1004,24 @@ class Asset extends CommonObject $begin_date = $fiscal_period_start < $start_date && $start_date <= $fiscal_period_end ? $start_date : $fiscal_period_start; $end_date = $fiscal_period_start < $finish_date && $finish_date <= $fiscal_period_end ? $finish_date : $fiscal_period_end; - if ($fields['duration_type'] == 2) { // Daily - $depreciation_ht = $period_amount; - } elseif ($fields['duration_type'] == 1) { // Monthly - $nb_days = min($nb_days_in_month, num_between_day($begin_date, $end_date, 1)); - if ($nb_days >= 28) { - $date_temp = dol_getdate($begin_date); - if ($date_temp['mon'] == 2) { - $nb_days = 30; - } - } - $depreciation_ht = (double) price2num($period_amount * $nb_days / $nb_days_in_month, 'MT'); - } else { // Annually - $nb_days = min($nb_days_in_year, num_between_day($begin_date, $end_date, 1)); - $depreciation_ht = (double) price2num($period_amount * $nb_days / $nb_days_in_year, 'MT'); - } + if ($fields['duration_type'] == 2) { // Daily + $depreciation_ht = $period_amount; + } elseif ($fields['duration_type'] == 1) { // Monthly + $nb_days = min($nb_days_in_month, num_between_day($begin_date, $end_date, 1)); + if ($nb_days >= 28) { + $date_temp = dol_getdate($begin_date); + if ($date_temp['mon'] == 2) { + $nb_days = 30; + } + } + $depreciation_ht = (double) price2num($period_amount * $nb_days / $nb_days_in_month, 'MT'); + } else { // Annually + $nb_days = min($nb_days_in_year, num_between_day($begin_date, $end_date, 1)); + $depreciation_ht = (double) price2num($period_amount * $nb_days / $nb_days_in_year, 'MT'); + } - if ($fiscal_period_start <= $depreciation_date_end && $depreciation_date_end <= $fiscal_period_end) { // last period - $depreciation_ht = (double)price2num($depreciation_amount - $cumulative_depreciation_ht, 'MT'); + if ($fiscal_period_start <= $depreciation_date_end && $depreciation_date_end <= $fiscal_period_end) { // last period + $depreciation_ht = (double) price2num($depreciation_amount - $cumulative_depreciation_ht, 'MT'); $cumulative_depreciation_ht = $depreciation_amount; } else { $cumulative_depreciation_ht += $depreciation_ht; @@ -1034,15 +1034,15 @@ class Asset extends CommonObject } } - // Next fiscal period (+1 day/month/year) + // Next fiscal period (+1 day/month/year) $fiscal_period_start = dol_time_plus_duree($fiscal_period_end, 1, 'd'); - if ($fields['duration_type'] == 2) { // Daily - $fiscal_period_end = $fiscal_period_start; - } elseif ($fields['duration_type'] == 1) { // Monthly - $fiscal_period_end = dol_time_plus_duree(dol_time_plus_duree($fiscal_period_start, 1, 'm'), -1, 'd'); - } else { // Annually - $fiscal_period_end = dol_time_plus_duree(dol_time_plus_duree($fiscal_period_start, 1, 'y'), -1, 'd'); - } + if ($fields['duration_type'] == 2) { // Daily + $fiscal_period_end = $fiscal_period_start; + } elseif ($fields['duration_type'] == 1) { // Monthly + $fiscal_period_end = dol_time_plus_duree(dol_time_plus_duree($fiscal_period_start, 1, 'm'), -1, 'd'); + } else { // Annually + $fiscal_period_end = dol_time_plus_duree(dol_time_plus_duree($fiscal_period_start, 1, 'y'), -1, 'd'); + } $last_period_date = $disposal_date !== "" && $disposal_date < $depreciation_date_end ? $disposal_date : $depreciation_date_end; } while ($fiscal_period_start < $last_period_date); @@ -1561,31 +1561,31 @@ class Asset extends CommonObject * @param null|array $moreparams Array to provide more information * @return int 0 if KO, 1 if OK */ -// public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null) -// { -// global $conf, $langs; -// -// $result = 0; -// $includedocgeneration = 1; -// -// $langs->load("asset@asset"); -// -// if (!dol_strlen($modele)) { -// $modele = 'standard_asset'; -// -// if (!empty($this->model_pdf)) { -// $modele = $this->model_pdf; -// } elseif (!empty($conf->global->ASSET_ADDON_PDF)) { -// $modele = $conf->global->ASSET_ADDON_PDF; -// } -// } -// -// $modelpath = "core/modules/asset/doc/"; -// -// if ($includedocgeneration && !empty($modele)) { -// $result = $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams); -// } -// -// return $result; -// } + // public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null) + // { + // global $conf, $langs; + // + // $result = 0; + // $includedocgeneration = 1; + // + // $langs->load("asset@asset"); + // + // if (!dol_strlen($modele)) { + // $modele = 'standard_asset'; + // + // if (!empty($this->model_pdf)) { + // $modele = $this->model_pdf; + // } elseif (!empty($conf->global->ASSET_ADDON_PDF)) { + // $modele = $conf->global->ASSET_ADDON_PDF; + // } + // } + // + // $modelpath = "core/modules/asset/doc/"; + // + // if ($includedocgeneration && !empty($modele)) { + // $result = $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams); + // } + // + // return $result; + // } } diff --git a/htdocs/asset/class/assetdepreciationoptions.class.php b/htdocs/asset/class/assetdepreciationoptions.class.php index 3f447621be5..88cd9dad9fa 100644 --- a/htdocs/asset/class/assetdepreciationoptions.class.php +++ b/htdocs/asset/class/assetdepreciationoptions.class.php @@ -80,13 +80,13 @@ class AssetDepreciationOptions extends CommonObject 'depreciation_type' => array('type'=>'smallint', 'label'=>'AssetDepreciationOptionDepreciationType', 'enabled'=>'1', 'position'=>10, 'notnull'=>1, 'visible'=>1, 'default'=>'0', 'arrayofkeyval'=>array('0'=>'AssetDepreciationOptionDepreciationTypeLinear', '1'=>'AssetDepreciationOptionDepreciationTypeDegressive', '2'=>'AssetDepreciationOptionDepreciationTypeExceptional'), 'validate'=>'1',), 'degressive_coefficient' => array('type'=>'double(24,8)', 'label'=>'AssetDepreciationOptionDegressiveRate', 'enabled'=>'1', 'position'=>20, 'notnull'=>1, 'visible'=>1, 'default'=>'0', 'isameasure'=>'1', 'validate'=>'1','enabled_field' => 'economic:depreciation_type:1'), 'duration' => array('type'=>'integer', 'label'=>'AssetDepreciationOptionDuration', 'enabled'=>'1', 'position'=>30, 'notnull'=>1, 'visible'=>1, 'default'=>'0', 'isameasure'=>'1', 'validate'=>'1',), - 'duration_type' => array('type'=>'smallint', 'label'=>'AssetDepreciationOptionDurationType', 'enabled'=>'1', 'position'=>40, 'notnull'=>1, 'visible'=>1, 'default'=>'0', 'arrayofkeyval'=>array('0'=>'AssetDepreciationOptionDurationTypeAnnual', '1'=>'AssetDepreciationOptionDurationTypeMonthly'/*, '2'=>'AssetDepreciationOptionDurationTypeDaily'*/), 'validate'=>'1',), - 'rate' => array('type'=>'double(24,8)', 'label'=>'AssetDepreciationOptionRate', 'enabled'=>'1', 'position'=>50, 'visible'=>3, 'default'=>'0', 'isameasure'=>'1', 'validate'=>'1', 'computed' => '$object->asset_depreciation_options->getRate("economic")',), - 'accelerated_depreciation_option' => array('type'=>'boolean', 'label'=>'AssetDepreciationOptionAcceleratedDepreciation', 'enabled'=>'1', 'position'=>60, 'column_break' => true, 'notnull'=>0, 'default'=>'0', 'visible'=>1, 'validate'=>'1',), - 'amount_base_depreciation_ht' => array('type'=>'price', 'label'=>'AssetDepreciationOptionAmountBaseDepreciationHT', 'enabled'=>'isset($object)&&get_class($object)=="Asset"', 'only_on_asset'=>1, 'position'=>90, 'notnull'=>0, 'required'=>1, 'visible'=>1, 'default'=>'$object->reversal_amount_ht > 0 ? $object->reversal_amount_ht : $object->acquisition_value_ht', 'isameasure'=>'1', 'validate'=>'1',), - 'amount_base_deductible_ht' => array('type'=>'price', 'label'=>'AssetDepreciationOptionAmountBaseDeductibleHT', 'enabled'=>'isset($object)&&get_class($object)=="Asset"', 'only_on_asset'=>1, 'position'=>100, 'notnull'=>0, 'visible'=>1, 'default'=>'0', 'isameasure'=>'1', 'validate'=>'1',), - 'total_amount_last_depreciation_ht' => array('type'=>'price', 'label'=>'AssetDepreciationOptionTotalAmountLastDepreciationHT', 'enabled'=>'isset($object)&&get_class($object)=="Asset"', 'only_on_asset'=>1, 'position'=>110, 'noteditable'=> 1, 'notnull'=>0, 'visible'=>1, 'default'=>'0', 'isameasure'=>'1', 'validate'=>'1',), - ), + 'duration_type' => array('type'=>'smallint', 'label'=>'AssetDepreciationOptionDurationType', 'enabled'=>'1', 'position'=>40, 'notnull'=>1, 'visible'=>1, 'default'=>'0', 'arrayofkeyval'=>array('0'=>'AssetDepreciationOptionDurationTypeAnnual', '1'=>'AssetDepreciationOptionDurationTypeMonthly'/*, '2'=>'AssetDepreciationOptionDurationTypeDaily'*/), 'validate'=>'1',), + 'rate' => array('type'=>'double(24,8)', 'label'=>'AssetDepreciationOptionRate', 'enabled'=>'1', 'position'=>50, 'visible'=>3, 'default'=>'0', 'isameasure'=>'1', 'validate'=>'1', 'computed' => '$object->asset_depreciation_options->getRate("economic")',), + 'accelerated_depreciation_option' => array('type'=>'boolean', 'label'=>'AssetDepreciationOptionAcceleratedDepreciation', 'enabled'=>'1', 'position'=>60, 'column_break' => true, 'notnull'=>0, 'default'=>'0', 'visible'=>1, 'validate'=>'1',), + 'amount_base_depreciation_ht' => array('type'=>'price', 'label'=>'AssetDepreciationOptionAmountBaseDepreciationHT', 'enabled'=>'isset($object)&&get_class($object)=="Asset"', 'only_on_asset'=>1, 'position'=>90, 'notnull'=>0, 'required'=>1, 'visible'=>1, 'default'=>'$object->reversal_amount_ht > 0 ? $object->reversal_amount_ht : $object->acquisition_value_ht', 'isameasure'=>'1', 'validate'=>'1',), + 'amount_base_deductible_ht' => array('type'=>'price', 'label'=>'AssetDepreciationOptionAmountBaseDeductibleHT', 'enabled'=>'isset($object)&&get_class($object)=="Asset"', 'only_on_asset'=>1, 'position'=>100, 'notnull'=>0, 'visible'=>1, 'default'=>'0', 'isameasure'=>'1', 'validate'=>'1',), + 'total_amount_last_depreciation_ht' => array('type'=>'price', 'label'=>'AssetDepreciationOptionTotalAmountLastDepreciationHT', 'enabled'=>'isset($object)&&get_class($object)=="Asset"', 'only_on_asset'=>1, 'position'=>110, 'noteditable'=> 1, 'notnull'=>0, 'visible'=>1, 'default'=>'0', 'isameasure'=>'1', 'validate'=>'1',), + ), ), 'accelerated_depreciation' => array( 'label' => 'AssetDepreciationOptionAcceleratedDepreciation', @@ -96,7 +96,7 @@ class AssetDepreciationOptions extends CommonObject 'depreciation_type' => array('type'=>'smallint', 'label'=>'AssetDepreciationOptionDepreciationType', 'enabled'=>'1', 'position'=>10, 'notnull'=>1, 'visible'=>1, 'default'=>'0', 'arrayofkeyval'=>array('0'=>'AssetDepreciationOptionDepreciationTypeLinear', '1'=>'AssetDepreciationOptionDepreciationTypeDegressive', '2'=>'AssetDepreciationOptionDepreciationTypeExceptional'), 'validate'=>'1',), 'degressive_coefficient' => array('type'=>'double(24,8)', 'label'=>'AssetDepreciationOptionDegressiveRate', 'enabled'=>'1', 'position'=>20, 'notnull'=>1, 'visible'=>1, 'default'=>'0', 'isameasure'=>'1', 'validate'=>'1','enabled_field' => 'accelerated_depreciation:depreciation_type:1'), 'duration' => array('type'=>'integer', 'label'=>'AssetDepreciationOptionDuration', 'enabled'=>'1', 'position'=>30, 'notnull'=>1, 'visible'=>1, 'default'=>'0', 'isameasure'=>'1', 'validate'=>'1',), - 'duration_type' => array('type'=>'smallint', 'label'=>'AssetDepreciationOptionDurationType', 'enabled'=>'1', 'position'=>40, 'notnull'=>1, 'visible'=>1, 'default'=>'0', 'arrayofkeyval'=>array('0'=>'AssetDepreciationOptionDurationTypeAnnual', '1'=>'AssetDepreciationOptionDurationTypeMonthly'/*, '2'=>'AssetDepreciationOptionDurationTypeDaily'*/), 'validate'=>'1',), + 'duration_type' => array('type'=>'smallint', 'label'=>'AssetDepreciationOptionDurationType', 'enabled'=>'1', 'position'=>40, 'notnull'=>1, 'visible'=>1, 'default'=>'0', 'arrayofkeyval'=>array('0'=>'AssetDepreciationOptionDurationTypeAnnual', '1'=>'AssetDepreciationOptionDurationTypeMonthly'/*, '2'=>'AssetDepreciationOptionDurationTypeDaily'*/), 'validate'=>'1',), 'rate' => array('type'=>'double(24,8)', 'label'=>'AssetDepreciationOptionRate', 'enabled'=>'1', 'position'=>50, 'visible'=>3, 'default'=>'0', 'isameasure'=>'1', 'validate'=>'1', 'computed' => '$object->asset_depreciation_options->getRate("accelerated_depreciation")',), 'amount_base_depreciation_ht' => array('type'=>'price', 'label'=>'AssetDepreciationOptionAmountBaseDepreciationHT', 'enabled'=>'isset($object)&&get_class($object)=="Asset"', 'only_on_asset'=>1, 'position'=>80, 'column_break' => true, 'notnull'=>0, 'required'=>1, 'visible'=>1, 'default'=>'$object->reversal_amount_ht > 0 ? $object->reversal_amount_ht : $object->acquisition_value_ht', 'isameasure'=>'1', 'validate'=>'1',), 'amount_base_deductible_ht' => array('type'=>'price', 'label'=>'AssetDepreciationOptionAmountBaseDeductibleHT', 'enabled'=>'isset($object)&&get_class($object)=="Asset"', 'only_on_asset'=>1, 'position'=>90, 'notnull'=>0, 'visible'=>1, 'default'=>'0', 'isameasure'=>'1', 'validate'=>'1',), @@ -262,9 +262,9 @@ class AssetDepreciationOptions extends CommonObject $field_value = $value; if ($field_info['notnull'] > 0 && $field_value == '' && !is_null($field_info['default']) && $field_info['default'] == '(PROV)') { $field_value = '(PROV)'; - } elseif ((!empty($field_info['required']) || $field_info['notnull'] > 0) && $field_value == '' && !empty($field_info['default'])) { - $field_value = dol_eval($field_info['default'], 1); - } + } elseif ((!empty($field_info['required']) || $field_info['notnull'] > 0) && $field_value == '' && !empty($field_info['default'])) { + $field_value = dol_eval($field_info['default'], 1); + } if ($field_info['notnull'] > 0 && $field_value == '' && is_null($field_info['default'])) { $error++; setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv($field_info['label'])), null, 'errors'); @@ -412,7 +412,7 @@ class AssetDepreciationOptions extends CommonObject 'base_depreciation_ht' => $this->deprecation_options[$mode]['amount_base_depreciation_ht'], 'duration' => $this->deprecation_options[$mode]['duration'], 'duration_type' => $duration_type_list[$this->deprecation_options[$mode]['duration_type']], - 'rate' => $this->getRate($mode), + 'rate' => $this->getRate($mode), ); } @@ -530,17 +530,17 @@ class AssetDepreciationOptions extends CommonObject } } - /** - * Get rate - * - * @param string $mode Depreciation mode (economic, accelerated_depreciation, ...) - * @return string Rate of the provided mode option - */ - public function getRate($mode) - { - $duration = $this->deprecation_options[$mode]["duration"] > 0 ? $this->deprecation_options[$mode]["duration"] : 0; - $duration_type = $this->deprecation_options[$mode]["duration_type"] > 0 ? $this->deprecation_options[$mode]["duration_type"] : 0; + /** + * Get rate + * + * @param string $mode Depreciation mode (economic, accelerated_depreciation, ...) + * @return string Rate of the provided mode option + */ + public function getRate($mode) + { + $duration = $this->deprecation_options[$mode]["duration"] > 0 ? $this->deprecation_options[$mode]["duration"] : 0; + $duration_type = $this->deprecation_options[$mode]["duration_type"] > 0 ? $this->deprecation_options[$mode]["duration_type"] : 0; - return price(price2num($duration > 0 ? (100 * ($duration_type == 1 ? 12 : 1) / $duration) : 0, 2)); - } + return price(price2num($duration > 0 ? (100 * ($duration_type == 1 ? 12 : 1) / $duration) : 0, 2)); + } } diff --git a/htdocs/asset/class/assetmodel.class.php b/htdocs/asset/class/assetmodel.class.php index ec04bf75851..eae7b5d0fde 100644 --- a/htdocs/asset/class/assetmodel.class.php +++ b/htdocs/asset/class/assetmodel.class.php @@ -105,8 +105,8 @@ class AssetModel extends CommonObject 'ref' => array('type'=>'varchar(128)', 'label'=>'Ref', 'enabled'=>'1', 'position'=>20, 'notnull'=>1, 'visible'=>1, 'index'=>1, 'searchall'=>1, 'showoncombobox'=>'1', 'validate'=>'1'), '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',), 'asset_type' => array('type'=>'smallint', 'label'=>'AssetType', 'enabled'=>'1', 'position'=>40, 'notnull'=>1, 'visible'=>1, 'arrayofkeyval'=>array('0'=>'AssetTypeIntangible', '1'=>'AssetTypeTangible', '2'=>'AssetTypeInProgress', '3'=>'AssetTypeFinancial'), 'validate'=>'1',), - 'fk_pays' =>array('type'=>'integer:Ccountry:core/class/ccountry.class.php', 'label'=>'Country', 'enabled'=>1, 'visible'=>1, 'position'=>50), - 'note_public' => array('type'=>'html', 'label'=>'NotePublic', 'enabled'=>'1', 'position'=>300, 'notnull'=>0, 'visible'=>0, 'validate'=>'1',), + 'fk_pays' =>array('type'=>'integer:Ccountry:core/class/ccountry.class.php', 'label'=>'Country', 'enabled'=>1, 'visible'=>1, 'position'=>50), + 'note_public' => array('type'=>'html', 'label'=>'NotePublic', 'enabled'=>'1', 'position'=>300, 'notnull'=>0, 'visible'=>0, 'validate'=>'1',), '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,), @@ -461,9 +461,9 @@ class AssetModel extends CommonObject $sql .= ", date_validation = '" . $this->db->idate($now) . "'"; } if (!empty($this->fields['fk_user_valid'])) { - $sql .= ", fk_user_valid = " . ((int)$user->id); + $sql .= ", fk_user_valid = " . ((int) $user->id); } - $sql .= " WHERE rowid = " . ((int)$this->id); + $sql .= " WHERE rowid = " . ((int) $this->id); dol_syslog(get_class($this) . "::validate()", LOG_DEBUG); $resql = $this->db->query($sql); diff --git a/htdocs/asset/document.php b/htdocs/asset/document.php index c3f04feab91..96b222b26c1 100644 --- a/htdocs/asset/document.php +++ b/htdocs/asset/document.php @@ -142,9 +142,9 @@ if ($object->id) { $modulepart = 'asset'; $permissiontoadd = $user->rights->asset->write; -// $permissiontoadd = 1; + // $permissiontoadd = 1; $permtoedit = $user->rights->asset->write; -// $permtoedit = 1; + // $permtoedit = 1; $param = '&id=' . $object->id; //$relativepathwithnofile='asset/' . dol_sanitizeFileName($object->id).'/'; diff --git a/htdocs/asset/model/agenda.php b/htdocs/asset/model/agenda.php index 494c271668a..cd0365a1418 100644 --- a/htdocs/asset/model/agenda.php +++ b/htdocs/asset/model/agenda.php @@ -181,35 +181,35 @@ if ($object->id > 0) { print '
    '; -// if (!empty($conf->agenda->enabled)) { -// if (!empty($user->rights->agenda->myactions->create) || !empty($user->rights->agenda->allactions->create)) { -// print '' . $langs->trans("AddAction") . ''; -// } else { -// print '' . $langs->trans("AddAction") . ''; -// } -// } + // if (!empty($conf->agenda->enabled)) { + // if (!empty($user->rights->agenda->myactions->create) || !empty($user->rights->agenda->allactions->create)) { + // print '' . $langs->trans("AddAction") . ''; + // } else { + // print '' . $langs->trans("AddAction") . ''; + // } + // } print '
    '; -// if (!empty($conf->agenda->enabled) && (!empty($user->rights->agenda->myactions->read) || !empty($user->rights->agenda->allactions->read))) { -// $param = '&id=' . $object->id . '&socid=' . $socid; -// if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) { -// $param .= '&contextpage=' . urlencode($contextpage); -// } -// if ($limit > 0 && $limit != $conf->liste_limit) { -// $param .= '&limit=' . urlencode($limit); -// } -// -// -// print load_fiche_titre($langs->trans("ActionsOnAssetModel"), '', ''); -// -// // List of all actions -// $filters = array(); -// $filters['search_agenda_label'] = $search_agenda_label; -// -// // TODO Replace this with same code than into list.php -// show_actions_done($conf, $langs, $db, $object, null, 0, $actioncode, '', $filters, $sortfield, $sortorder, $object->module); -// } + // if (!empty($conf->agenda->enabled) && (!empty($user->rights->agenda->myactions->read) || !empty($user->rights->agenda->allactions->read))) { + // $param = '&id=' . $object->id . '&socid=' . $socid; + // if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) { + // $param .= '&contextpage=' . urlencode($contextpage); + // } + // if ($limit > 0 && $limit != $conf->liste_limit) { + // $param .= '&limit=' . urlencode($limit); + // } + // + // + // print load_fiche_titre($langs->trans("ActionsOnAssetModel"), '', ''); + // + // // List of all actions + // $filters = array(); + // $filters['search_agenda_label'] = $search_agenda_label; + // + // // TODO Replace this with same code than into list.php + // show_actions_done($conf, $langs, $db, $object, null, 0, $actioncode, '', $filters, $sortfield, $sortorder, $object->module); + // } } // End of page diff --git a/htdocs/asset/model/card.php b/htdocs/asset/model/card.php index 85e3ea207af..15b90e6dee3 100644 --- a/htdocs/asset/model/card.php +++ b/htdocs/asset/model/card.php @@ -313,14 +313,14 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea print '
    '; -// $MAXEVENT = 10; -// -// $morehtmlcenter = dolGetButtonTitle($langs->trans('SeeAll'), '', 'fa fa-list-alt imgforviewmode', DOL_URL_ROOT . '/asset/model/agenda.php?id=' . $object->id); -// -// // List of actions on element -// include_once DOL_DOCUMENT_ROOT . '/core/class/html.formactions.class.php'; -// $formactions = new FormActions($db); -// $somethingshown = $formactions->showactions($object, $object->element.'@'.$object->module, 0, 1, '', $MAXEVENT, '', $morehtmlright); + // $MAXEVENT = 10; + // + // $morehtmlcenter = dolGetButtonTitle($langs->trans('SeeAll'), '', 'fa fa-list-alt imgforviewmode', DOL_URL_ROOT . '/asset/model/agenda.php?id=' . $object->id); + // + // // List of actions on element + // include_once DOL_DOCUMENT_ROOT . '/core/class/html.formactions.class.php'; + // $formactions = new FormActions($db); + // $somethingshown = $formactions->showactions($object, $object->element.'@'.$object->module, 0, 1, '', $MAXEVENT, '', $morehtmlright); print '
    '; } diff --git a/htdocs/asset/model/list.php b/htdocs/asset/model/list.php index 57602b36e6d..a6423bb3a73 100644 --- a/htdocs/asset/model/list.php +++ b/htdocs/asset/model/list.php @@ -81,10 +81,10 @@ if (!$sortorder) { $search_all = GETPOST('search_all', 'alphanohtml'); $search = array(); foreach ($object->fields as $key => $val) { - if ($key == 'fk_pays' && !GETPOSTISSET('search_'.$key)) { - $search[$key] = $mysoc->country_id; - } elseif (GETPOST('search_'.$key, 'alpha') !== '') { - $search[$key] = GETPOST('search_'.$key, 'alpha'); + if ($key == 'fk_pays' && !GETPOSTISSET('search_'.$key)) { + $search[$key] = $mysoc->country_id; + } elseif (GETPOST('search_'.$key, 'alpha') !== '') { + $search[$key] = GETPOST('search_'.$key, 'alpha'); } if (preg_match('/^(date|timestamp|datetime)/', $val['type'])) { $search[$key.'_dtstart'] = dol_mktime(0, 0, 0, GETPOST('search_'.$key.'_dtstartmonth', 'int'), GETPOST('search_'.$key.'_dtstartday', 'int'), GETPOST('search_'.$key.'_dtstartyear', 'int')); @@ -166,7 +166,7 @@ if (empty($reshook)) { if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // All tests are required to be compatible with all browsers foreach ($object->fields as $key => $val) { $search[$key] = ''; - if ($key == 'fk_pays') $search[$key] = $mysoc->country_id; + if ($key == 'fk_pays') $search[$key] = $mysoc->country_id; if (preg_match('/^(date|timestamp|datetime)/', $val['type'])) { $search[$key.'_dtstart'] = ''; $search[$key.'_dtend'] = ''; diff --git a/htdocs/asset/tpl/depreciation_options_edit.tpl.php b/htdocs/asset/tpl/depreciation_options_edit.tpl.php index 140a19d5f2a..cef22936260 100644 --- a/htdocs/asset/tpl/depreciation_options_edit.tpl.php +++ b/htdocs/asset/tpl/depreciation_options_edit.tpl.php @@ -114,8 +114,8 @@ if (empty($reshook)) { } $more_class = ''; - if (!empty($field_info['required']) || (isset($field_info['notnull']) && $field_info['notnull'] > 0)) { - $more_class .= ' fieldrequired'; + if (!empty($field_info['required']) || (isset($field_info['notnull']) && $field_info['notnull'] > 0)) { + $more_class .= ' fieldrequired'; } if (preg_match('/^(text|html)/', $val['type'])) { $more_class .= ' tdtop'; @@ -146,7 +146,7 @@ if (empty($reshook)) { } $value = GETPOSTISSET($html_name) ? GETPOST($html_name, $check) : $assetdepreciationoptions->$field_key; } elseif ($field_info['type'] == 'price') { - $value = GETPOSTISSET($html_name) ? price2num(GETPOST($html_name)) : ($assetdepreciationoptions->$field_key ? price2num($assetdepreciationoptions->$field_key) : (!empty($field_info['default']) ? dol_eval($field_info['default'], 1) : 0)); + $value = GETPOSTISSET($html_name) ? price2num(GETPOST($html_name)) : ($assetdepreciationoptions->$field_key ? price2num($assetdepreciationoptions->$field_key) : (!empty($field_info['default']) ? dol_eval($field_info['default'], 1) : 0)); } elseif ($field_key == 'lang') { $value = GETPOSTISSET($html_name) ? GETPOST($html_name, 'aZ09') : $assetdepreciationoptions->lang; } else { From 99aa8dc2b115be14c0fc328d357f9ffbe5c1bf3d Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Mon, 14 Feb 2022 05:33:57 +0100 Subject: [PATCH 09/20] Lang --- htdocs/langs/en_US/assets.lang | 183 +++++++++++++++++++++++++++------ 1 file changed, 151 insertions(+), 32 deletions(-) diff --git a/htdocs/langs/en_US/assets.lang b/htdocs/langs/en_US/assets.lang index afafc98503f..d1d47b96f63 100644 --- a/htdocs/langs/en_US/assets.lang +++ b/htdocs/langs/en_US/assets.lang @@ -1,4 +1,4 @@ -# Copyright (C) 2018 Alexandre Spangaro +# Copyright (C) 2018-2022 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 @@ -16,52 +16,171 @@ # # Generic # -Assets = Assets -NewAsset = New asset -AccountancyCodeAsset = Accounting code (asset) -AccountancyCodeDepreciationAsset = Accounting code (depreciation asset account) -AccountancyCodeDepreciationExpense = Accounting code (depreciation expense account) -NewAssetType=New asset type -AssetsTypeSetup=Asset type setup -AssetTypeModified=Asset type modified -AssetType=Asset type +NewAsset=New asset +AccountancyCodeAsset=Accounting code (asset) +AccountancyCodeDepreciationAsset=Accounting code (depreciation asset account) +AccountancyCodeDepreciationExpense=Accounting code (depreciation expense account) AssetsLines=Assets DeleteType=Delete -DeleteAnAssetType=Delete an asset type -ConfirmDeleteAssetType=Are you sure you want to delete this asset type? -ShowTypeCard=Show type '%s' +DeleteAnAssetType=Delete an asset model +ConfirmDeleteAssetType=Are you sure you want to delete this asset model? +ShowTypeCard=Show model '%s' # Module label 'ModuleAssetsName' -ModuleAssetsName = Assets +ModuleAssetsName=Assets # Module description 'ModuleAssetsDesc' -ModuleAssetsDesc = Assets description +ModuleAssetsDesc=Assets description # # Admin page # -AssetsSetup = Assets setup -Settings = Settings -AssetsSetupPage = Assets setup page -ExtraFieldsAssetsType = Complementary attributes (Asset type) -AssetsType=Asset type -AssetsTypeId=Asset type id -AssetsTypeLabel=Asset type label -AssetsTypes=Assets types +AssetSetup=Assets setup +AssetSetupPage=Assets setup page +ExtraFieldsAssetModel=Complementary attributes (Asset's model) + +AssetsType=Asset model +AssetsTypeId=Asset model id +AssetsTypeLabel=Asset model label +AssetsTypes=Assets models +ASSET_ACCOUNTANCY_CATEGORY=Fixed asset accounting group # # Menu # -MenuAssets = Assets -MenuNewAsset = New asset -MenuTypeAssets = Type assets -MenuListAssets = List -MenuNewTypeAssets = New -MenuListTypeAssets = List +MenuAssets=Assets +MenuNewAsset=New asset +MenuAssetModels=Model assets +MenuListAssets=List +MenuNewAssetModel=New asset's model +MenuListAssetModels=List # # Module # +ConfirmDeleteAsset=Do you really want to remove this asset? + +# +# Tab +# +AssetDepreciationOptions=Depreciation options +AssetAccountancyCodes=Accounting accounts +AssetDepreciation=Depreciation + +# +# Asset +# Asset=Asset -NewAssetType=New asset type -NewAsset=New asset -ConfirmDeleteAsset=Are you sure you want to delete this asset ? +Assets=Assets +AssetReversalAmountHT=Reversal amount (without taxes) +AssetAcquisitionValueHT=Acquisition amount (without taxes) +AssetRecoveredVAT=Recovered VAT +AssetReversalDate=Reversal date +AssetDateAcquisition=Acquisition date +AssetDateStart=Date of start-up +AssetAcquisitionType=Type of acquisition +AssetAcquisitionTypeNew=New +AssetAcquisitionTypeOccasion=Used +AssetType=Type of asset +AssetTypeIntangible=Intangible +AssetTypeTangible=Tangible +AssetTypeInProgress=In progress +AssetTypeFinancial=Financial +AssetNotDepreciated=Not depreciated +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 +# +AssetInProgress=In progress +AssetDisposed=Disposed +AssetRecorded=Accounted + +# +# Asset disposal +# +AssetDisposalDate=Date of disposal +AssetDisposalAmount=Disposal value +AssetDisposalType=Type of disposal +AssetDisposalDepreciated=Depreciate the year of transfer +AssetDisposalSubjectToVat=Disposal subject to VAT + +# +# Asset model +# +AssetModel=Asset's model +AssetModels=Asset's models + +# +# Asset depreciation options +# +AssetDepreciationOptionEconomic=Economic depreciation +AssetDepreciationOptionAcceleratedDepreciation=Accelerated depreciation (tax) +AssetDepreciationOptionDepreciationType=Depreciation type +AssetDepreciationOptionDepreciationTypeLinear=Linear +AssetDepreciationOptionDepreciationTypeDegressive=Degressive +AssetDepreciationOptionDepreciationTypeExceptional=Exceptional +AssetDepreciationOptionDegressiveRate=Degressive rate +AssetDepreciationOptionAcceleratedDepreciation=Accelerated (tax) +AssetDepreciationOptionDuration=Duration +AssetDepreciationOptionDurationType=Type duration +AssetDepreciationOptionDurationTypeAnnual=Annual +AssetDepreciationOptionDurationTypeMonthly=Monthly +AssetDepreciationOptionDurationTypeDaily=Daily +AssetDepreciationOptionRate=Rate (%%) +AssetDepreciationOptionAmountBaseDepreciationHT=Depreciation base (excl. VAT) +AssetDepreciationOptionAmountBaseDeductibleHT=Deductible base (excl. VAT) +AssetDepreciationOptionTotalAmountLastDepreciationHT=Total amount last depreciation (excl. VAT) + +# +# Asset accountancy codes +# +AssetAccountancyCodeDepreciationEconomic=Economic depreciation +AssetAccountancyCodeAsset=Asset +AssetAccountancyCodeDepreciationAsset=Depreciation +AssetAccountancyCodeDepreciationExpense=Depreciation expense +AssetAccountancyCodeValueAssetSold=Value of asset disposed +AssetAccountancyCodeReceivableOnAssignment=Receivable on disposal +AssetAccountancyCodeProceedsFromSales=Proceeds from disposal +AssetAccountancyCodeVatCollected=Collected VAT +AssetAccountancyCodeVatDeductible=Recovered VAT on assets +AssetAccountancyCodeDepreciationAcceleratedDepreciation=Accelerated depreciation (tax) +AssetAccountancyCodeAcceleratedDepreciation=Account +AssetAccountancyCodeEndowmentAcceleratedDepreciation=Depreciation expense +AssetAccountancyCodeProvisionAcceleratedDepreciation=Repossession/Provision + +# +# Asset depreciation +# +AssetBaseDepreciationHT=Depreciation basis (excl. VAT) +AssetDepreciationBeginDate=Start of depreciation on +AssetDepreciationDuration=Duration +AssetDepreciationRate=Rate (%%) +AssetDepreciationDate=Depreciation date +AssetDepreciationHT=Depreciation (excl. VAT) +AssetCumulativeDepreciationHT=Cumulative depreciation (excl. VAT) +AssetResidualHT=Residual value (excl. VAT) +AssetDispatchedInBookkeeping=Depreciation recorded +AssetFutureDepreciationLine=Future depreciation +AssetDepreciationReversal=Reversal + +# +# Errors +# +AssetErrorAssetOrAssetModelIDNotProvide=Id of the asset or the model sound has not been provided +AssetErrorFetchAccountancyCodesForMode=Error when retrieving the accounting accounts for the '%s' depreciation mode +AssetErrorDeleteAccountancyCodesForMode=Error when deleting accounting accounts from the '%s' depreciation mode +AssetErrorInsertAccountancyCodesForMode=Error when inserting the accounting accounts of the depreciation mode '%s' +AssetErrorFetchDepreciationOptionsForMode=Error when retrieving options for the '%s' depreciation mode +AssetErrorDeleteDepreciationOptionsForMode=Error when deleting the '%s' depreciation mode options +AssetErrorInsertDepreciationOptionsForMode=Error when inserting the '%s' depreciation mode options +AssetErrorFetchDepreciationLines=Error when retrieving recorded depreciation lines +AssetErrorClearDepreciationLines=Error when purging recorded depreciation lines (reversal and future) +AssetErrorAddDepreciationLine=Error when adding a depreciation line +AssetErrorCalculationDepreciationLines=Error when calculating the depreciation lines (recovery and future) +AssetErrorReversalDateNotProvidedForMode=The reversal date is not provided for the '%s' depreciation method +AssetErrorReversalDateNotGreaterThanCurrentBeginFiscalDateForMode=The reversal date must be greater than or equal to the beginning of the current fiscal year for the '%s' depreciation method +AssetErrorReversalAmountNotProvidedForMode=The reversal amount is not provided for the depreciation mode '%s'. +AssetErrorFetchCumulativeDepreciation=Error when retrieving the accumulated depreciation amount from the depreciation line +AssetErrorSetLastCumulativeDepreciation=Error when recording the last accumulated depreciation amount From a17ac09fd05620fda3258c1211949f632fa1bb3d Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Mon, 14 Feb 2022 11:03:44 +0100 Subject: [PATCH 10/20] Resolve stickler-ci --- htdocs/accountancy/class/accountingjournal.class.php | 2 +- htdocs/accountancy/journal/variousjournal.php | 6 ++---- htdocs/asset/card.php | 5 ++--- htdocs/asset/class/assetaccountancycodes.class.php | 4 +++- htdocs/asset/model/card.php | 4 ++-- 5 files changed, 10 insertions(+), 11 deletions(-) diff --git a/htdocs/accountancy/class/accountingjournal.class.php b/htdocs/accountancy/class/accountingjournal.class.php index 5ccaa971e5c..16fb2a2bbff 100644 --- a/htdocs/accountancy/class/accountingjournal.class.php +++ b/htdocs/accountancy/class/accountingjournal.class.php @@ -1002,7 +1002,7 @@ class AccountingJournal extends CommonObject * @param string $account Accounting account number * @return array Accounting account infos */ - function getAccountingAccountInfos($account) + public function getAccountingAccountInfos($account) { if (!isset(self::$accounting_account_cached[$account])) { require_once DOL_DOCUMENT_ROOT . '/core/lib/accounting.lib.php'; diff --git a/htdocs/accountancy/journal/variousjournal.php b/htdocs/accountancy/journal/variousjournal.php index 378c0dbb915..b8e2092bdb8 100644 --- a/htdocs/accountancy/journal/variousjournal.php +++ b/htdocs/accountancy/journal/variousjournal.php @@ -121,10 +121,8 @@ if ($action == 'writebookkeeping') { } $reload = true; -} - -// Export -elseif ($action == 'exportcsv') { +} elseif ($action == 'exportcsv') { + // Export CSV $result = $object->exportCsv($journal_data, $date_end); if ($result < 0) { setEventMessages($object->error, $object->errors, 'errors'); diff --git a/htdocs/asset/card.php b/htdocs/asset/card.php index 6b2e88ac630..25baca3243f 100644 --- a/htdocs/asset/card.php +++ b/htdocs/asset/card.php @@ -253,9 +253,8 @@ 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); - } - // Disposal - elseif ($action == 'disposal') { + } elseif ($action == 'disposal') { + // Disposal $langs->load('bills'); $disposal_date = dol_mktime(12, 0, 0, GETPOST('disposal_datemonth', 'int'), GETPOST('disposal_dateday', 'int'), GETPOST('disposal_dateyear', 'int')); // for date without hour, we use gmt diff --git a/htdocs/asset/class/assetaccountancycodes.class.php b/htdocs/asset/class/assetaccountancycodes.class.php index 112aa1e3f35..1107c334c6f 100644 --- a/htdocs/asset/class/assetaccountancycodes.class.php +++ b/htdocs/asset/class/assetaccountancycodes.class.php @@ -80,6 +80,8 @@ class AssetAccountancyCodes extends CommonObject /** * Fill accountancy_codes property of object (using for data sent by forms) + * + * @return array Array of values */ public function setAccountancyCodesFromPost() { @@ -104,7 +106,7 @@ class AssetAccountancyCodes extends CommonObject public function fetchAccountancyCodes($asset_id = 0, $asset_model_id = 0) { global $langs, $hookmanager; - dol_syslog(__METHOD__ . " sset_id=$asset_id, asset_model_id=$asset_model_id"); + dol_syslog(__METHOD__ . " asset_id=$asset_id, asset_model_id=$asset_model_id"); $error = 0; $this->errors = array(); diff --git a/htdocs/asset/model/card.php b/htdocs/asset/model/card.php index 15b90e6dee3..3e0858da55e 100644 --- a/htdocs/asset/model/card.php +++ b/htdocs/asset/model/card.php @@ -221,8 +221,8 @@ 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('DeleteAssetModel'), $langs->trans('ConfirmDeleteObject'), 'confirm_delete', '', 0, 1); - } // Clone confirmation - elseif ($action == 'clone') { + } elseif ($action == 'clone') { + // Clone confirmation // Create an array for form $formquestion = array(); $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id, $langs->trans('ToClone'), $langs->trans('ConfirmCloneAsk', $object->ref), 'confirm_clone', $formquestion, 'yes', 1); From 0d1ee4e19f53d2454922c19d8c3e42838b348ee3 Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Mon, 14 Feb 2022 11:51:05 +0100 Subject: [PATCH 11/20] Fix stickler-ci --- htdocs/accountancy/journal/variousjournal.php | 2 +- test/phpunit/CodingPhpTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/accountancy/journal/variousjournal.php b/htdocs/accountancy/journal/variousjournal.php index b8e2092bdb8..6c9f529de5e 100644 --- a/htdocs/accountancy/journal/variousjournal.php +++ b/htdocs/accountancy/journal/variousjournal.php @@ -214,7 +214,7 @@ journalHead($nom, $nomlink, $period, $periodlink, $description, $builddate, $exp if ($object->nature == 4) { // Bank journal // Test that setup is complete (we are in accounting, so test on entity is always on $conf->entity only, no sharing allowed) - $sql = 'SELECT COUNT(rowid) as nb FROM ' . MAIN_DB_PREFIX . 'bank_account WHERE entity = ' . $conf->entity . ' AND fk_accountancy_journal IS NULL AND clos=0'; + $sql = "SELECT COUNT(rowid) as nb FROM " . MAIN_DB_PREFIX . "bank_account WHERE entity = " . $conf->entity . " AND fk_accountancy_journal IS NULL AND clos=0"; $resql = $db->query($sql); if ($resql) { $obj = $db->fetch_object($resql); diff --git a/test/phpunit/CodingPhpTest.php b/test/phpunit/CodingPhpTest.php index f7ae6d295ab..7a8a31167e6 100644 --- a/test/phpunit/CodingPhpTest.php +++ b/test/phpunit/CodingPhpTest.php @@ -324,7 +324,7 @@ class CodingPhpTest extends PHPUnit\Framework\TestCase $ok=false; break; } - $this->assertTrue($ok, 'Found a forged SQL string that mix on same line the use of \' for PHP string and PHP variables into file '.$file['relativename'].' Use " to forge PHP string like this: $sql = "SELET ".$myvar...'); + $this->assertTrue($ok, 'Found a forged SQL string that mix on same line the use of \' for PHP string and PHP variables into file '.$file['relativename'].' Use " to forge PHP string like this: $sql = "SELECT ".$myvar...'); // Check sql string VALUES ... , ".$xxx // with xxx that is not 'db-' (for $db->escape). It means we forget a ' if string, or an (int) if int, when forging sql request. From 1d974f67f09901c7cee90032ce6bc72647f50f65 Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Mon, 14 Feb 2022 16:17:19 +0100 Subject: [PATCH 12/20] Fix stickler-ci --- htdocs/accountancy/journal/variousjournal.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/htdocs/accountancy/journal/variousjournal.php b/htdocs/accountancy/journal/variousjournal.php index 6c9f529de5e..d924547e798 100644 --- a/htdocs/accountancy/journal/variousjournal.php +++ b/htdocs/accountancy/journal/variousjournal.php @@ -214,7 +214,11 @@ journalHead($nom, $nomlink, $period, $periodlink, $description, $builddate, $exp if ($object->nature == 4) { // Bank journal // Test that setup is complete (we are in accounting, so test on entity is always on $conf->entity only, no sharing allowed) - $sql = "SELECT COUNT(rowid) as nb FROM " . MAIN_DB_PREFIX . "bank_account WHERE entity = " . $conf->entity . " AND fk_accountancy_journal IS NULL AND clos=0"; + $sql = "SELECT COUNT(rowid) as nb"; + $sql .= " FROM " . MAIN_DB_PREFIX . "bank_account"; + $sql .= " WHERE entity = " .((int) $conf->entity); + $sql .= " AND fk_accountancy_journal IS NULL"; + $sql .= " AND clos=0"; $resql = $db->query($sql); if ($resql) { $obj = $db->fetch_object($resql); From 11d1d9a0afb3ee55edd9bcfacc2227c10a6eee21 Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Wed, 16 Feb 2022 05:17:38 +0100 Subject: [PATCH 13/20] Fix stickler-ci --- htdocs/accountancy/journal/variousjournal.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/accountancy/journal/variousjournal.php b/htdocs/accountancy/journal/variousjournal.php index d924547e798..7348821e15e 100644 --- a/htdocs/accountancy/journal/variousjournal.php +++ b/htdocs/accountancy/journal/variousjournal.php @@ -216,7 +216,7 @@ if ($object->nature == 4) { // Bank journal // Test that setup is complete (we are in accounting, so test on entity is always on $conf->entity only, no sharing allowed) $sql = "SELECT COUNT(rowid) as nb"; $sql .= " FROM " . MAIN_DB_PREFIX . "bank_account"; - $sql .= " WHERE entity = " .((int) $conf->entity); + $sql .= " WHERE entity = '" . ((int) $conf->entity) . "'"; $sql .= " AND fk_accountancy_journal IS NULL"; $sql .= " AND clos=0"; $resql = $db->query($sql); From 948f20c2b67ed5b869775cf962182336f5de41fc Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Wed, 16 Feb 2022 05:18:29 +0100 Subject: [PATCH 14/20] Add a graphical option to define duration per year for depreciation --- htdocs/asset/admin/setup.php | 2 +- htdocs/asset/class/asset.class.php | 2 +- htdocs/core/modules/modAsset.class.php | 9 +++++++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/htdocs/asset/admin/setup.php b/htdocs/asset/admin/setup.php index 85f8dc1e4c6..afa4777de3d 100644 --- a/htdocs/asset/admin/setup.php +++ b/htdocs/asset/admin/setup.php @@ -47,7 +47,7 @@ $type = 'asset'; $arrayofparameters = array( 'ASSET_ACCOUNTANCY_CATEGORY'=>array('type'=>'accountancy_category', 'enabled'=>1), - //'ASSET_MYPARAM1'=>array('type'=>'string', 'css'=>'minwidth500' ,'enabled'=>1), + 'ASSET_DEPRECIATION_DURATION_PER_YEAR'=>array('type'=>'string', 'css'=>'minwidth200', 'enabled'=>1), //'ASSET_MYPARAM2'=>array('type'=>'textarea','enabled'=>1), //'ASSET_MYPARAM3'=>array('type'=>'category:'.Categorie::TYPE_CUSTOMER, 'enabled'=>1), //'ASSET_MYPARAM4'=>array('type'=>'emailtemplate:thirdparty', 'enabled'=>1), diff --git a/htdocs/asset/class/asset.class.php b/htdocs/asset/class/asset.class.php index c1ea4a130d8..7be8aa9e024 100644 --- a/htdocs/asset/class/asset.class.php +++ b/htdocs/asset/class/asset.class.php @@ -971,7 +971,7 @@ class Asset extends CommonObject // futures depreciation lines //----------------------------------------------------- - $nb_days_in_year = !empty($conf->global->ASSET_DEPRECIATION_DURATION_PER_YEAR) ? $conf->global->ASSET_DEPRECIATION_DURATION_PER_YEAR : 360; + $nb_days_in_year = !empty($conf->global->ASSET_DEPRECIATION_DURATION_PER_YEAR) ? $conf->global->ASSET_DEPRECIATION_DURATION_PER_YEAR : 365; $nb_days_in_month = !empty($conf->global->ASSET_DEPRECIATION_DURATION_PER_MONTH) ? $conf->global->ASSET_DEPRECIATION_DURATION_PER_MONTH : 30; $period_amount = (double) price2num($depreciation_period_amount / $fields['duration'], 'MT'); $first_period_found = false; diff --git a/htdocs/core/modules/modAsset.class.php b/htdocs/core/modules/modAsset.class.php index 0fe334bc846..2146de367e1 100644 --- a/htdocs/core/modules/modAsset.class.php +++ b/htdocs/core/modules/modAsset.class.php @@ -103,6 +103,15 @@ class modAsset extends DolibarrModules // 1=>array('ASSETS_MYNEWCONST2','chaine','myvalue','This is another constant to add',0, 'current', 1) // ); $this->const = array(); + $this->const[1] = array( + "ASSET_DEPRECIATION_DURATION_PER_YEAR", + "chaine", + "365", + "Duration per year to calculate depreciation. In some case, can be 360 days", + 0, + 'current', + 1 + ); if (!isset($conf->asset) || !isset($conf->asset->enabled)) { From 9a0a222b6322d1992c344e7b2344e78cefb9501f Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Wed, 16 Feb 2022 14:21:45 +0100 Subject: [PATCH 15/20] Fix stickler-ci --- htdocs/accountancy/journal/variousjournal.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/accountancy/journal/variousjournal.php b/htdocs/accountancy/journal/variousjournal.php index 7348821e15e..1aea301f027 100644 --- a/htdocs/accountancy/journal/variousjournal.php +++ b/htdocs/accountancy/journal/variousjournal.php @@ -216,7 +216,7 @@ if ($object->nature == 4) { // Bank journal // Test that setup is complete (we are in accounting, so test on entity is always on $conf->entity only, no sharing allowed) $sql = "SELECT COUNT(rowid) as nb"; $sql .= " FROM " . MAIN_DB_PREFIX . "bank_account"; - $sql .= " WHERE entity = '" . ((int) $conf->entity) . "'"; + $sql .= " WHERE entity = " . (int) $conf->entity; $sql .= " AND fk_accountancy_journal IS NULL"; $sql .= " AND clos=0"; $resql = $db->query($sql); From 453449324e9664df2a4fb8b3ee4aca20240920c5 Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Wed, 16 Feb 2022 18:09:32 +0100 Subject: [PATCH 16/20] Fix travis --- htdocs/asset/class/asset.class.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/asset/class/asset.class.php b/htdocs/asset/class/asset.class.php index 7be8aa9e024..f6e07fe371c 100644 --- a/htdocs/asset/class/asset.class.php +++ b/htdocs/asset/class/asset.class.php @@ -1094,7 +1094,7 @@ class Asset extends CommonObject //----------------------------------------------------- $sql = "SELECT fk_asset, depreciation_mode, cumulative_depreciation_ht"; $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation"; - $sql .= " WHERE rowid = " . $asset_depreciation_id; + $sql .= " WHERE rowid = " . (int) $asset_depreciation_id; $resql = $this->db->query($sql); if (!$resql) { $this->errors[] = $langs->trans('AssetErrorFetchCumulativeDepreciation') . ': ' . $this->db->lasterror(); @@ -1105,7 +1105,7 @@ class Asset extends CommonObject if (!empty($options->deprecation_options_fields[$mode_key])) { $sql = "UPDATE " . MAIN_DB_PREFIX . $options->deprecation_options_fields[$mode_key]['table']; $sql .= " SET total_amount_last_depreciation_ht = " . $obj->cumulative_depreciation_ht; - $sql .= " WHERE fk_asset = " . $obj->fk_asset; + $sql .= " WHERE fk_asset = " . (int) $obj->fk_asset; $resql = $this->db->query($sql); if (!$resql) { $this->errors[] = $langs->trans('AssetErrorSetLastCumulativeDepreciation') . ': ' . $this->db->lasterror(); From ccbbc98f7a8f0977d5085a309e7c7c3b4dbaaa0d Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Thu, 17 Feb 2022 04:13:02 +0100 Subject: [PATCH 17/20] Fix travis --- htdocs/asset/class/asset.class.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/htdocs/asset/class/asset.class.php b/htdocs/asset/class/asset.class.php index f6e07fe371c..24731033d92 100644 --- a/htdocs/asset/class/asset.class.php +++ b/htdocs/asset/class/asset.class.php @@ -659,7 +659,7 @@ class Asset extends CommonObject $sql .= ", " . $this->db->ifsql('iab.fk_docdet IS NOT NULL', 1, 0) . " AS bookkeeping"; $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad"; $sql .= " LEFT JOIN in_accounting_bookkeeping as iab ON iab.fk_docdet = ad.rowid"; - $sql .= " WHERE ad.fk_asset = " . $this->id; + $sql .= " WHERE ad.fk_asset = " . (int) $this->id; $sql .= " ORDER BY ad.depreciation_date ASC"; $resql = $this->db->query($sql); @@ -714,7 +714,7 @@ class Asset extends CommonObject $sql .= "SELECT COUNT(*) AS has_bookkeeping"; $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad"; $sql .= " LEFT JOIN in_accounting_bookkeeping as iab ON iab.fk_docdet = ad.rowid"; - $sql .= " WHERE ad.fk_asset = " . $this->id; + $sql .= " WHERE ad.fk_asset = " . (int) $this->id; $sql .= " AND iab.fk_docdet IS NOT NULL"; $resql = $this->db->query($sql); @@ -838,7 +838,7 @@ class Asset extends CommonObject $modes[$mode_key] = $this->db->escape($mode_key); } $sql = "DELETE FROM " . MAIN_DB_PREFIX . "asset_depreciation"; - $sql .= " WHERE fk_asset = " . $this->id; + $sql .= " WHERE fk_asset = " . (int) $this->id; $sql .= " AND depreciation_mode NOT IN ('" . implode("', '", $modes) . "')"; $resql = $this->db->query($sql); @@ -872,7 +872,7 @@ class Asset extends CommonObject $sql .= "SELECT ad.depreciation_date, ad.cumulative_depreciation_ht"; $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad"; $sql .= " LEFT JOIN in_accounting_bookkeeping as iab ON iab.fk_docdet = ad.rowid"; - $sql .= " WHERE ad.fk_asset = " . $this->id; + $sql .= " WHERE ad.fk_asset = " . (int) $this->id; $sql .= " AND ad.depreciation_mode = '" . $this->db->escape($mode_key) . "'"; $sql .= " AND iab.fk_docdet IS NOT NULL"; $sql .= " ORDER BY ad.depreciation_date DESC"; @@ -893,7 +893,7 @@ class Asset extends CommonObject // Set last cumulative depreciation $sql = "UPDATE " . MAIN_DB_PREFIX . $options->deprecation_options_fields[$mode_key]['table']; $sql .= " SET total_amount_last_depreciation_ht = " . (empty($last_cumulative_depreciation_ht) ? 0 : $last_cumulative_depreciation_ht); - $sql .= " WHERE fk_asset = " . $this->id; + $sql .= " WHERE fk_asset = " . (int) $this->id; $resql = $this->db->query($sql); if (!$resql) { $this->errors[] = $langs->trans('AssetErrorSetLastCumulativeDepreciation') . ': ' . $this->db->lasterror(); @@ -904,7 +904,7 @@ class Asset extends CommonObject // Delete old lines $sql = "DELETE " . MAIN_DB_PREFIX . "asset_depreciation FROM " . MAIN_DB_PREFIX . "asset_depreciation"; $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"; - $sql .= " WHERE " . MAIN_DB_PREFIX . "asset_depreciation.fk_asset = " . $this->id; + $sql .= " WHERE " . MAIN_DB_PREFIX . "asset_depreciation.fk_asset = " . (int) $this->id; $sql .= " AND " . MAIN_DB_PREFIX . "asset_depreciation.depreciation_mode = '" . $this->db->escape($mode_key) . "'"; $sql .= " AND ab.fk_docdet IS NULL"; if ($last_depreciation_date !== "") $sql .= " AND " . MAIN_DB_PREFIX . "asset_depreciation.ref != ''"; From 33af0eb0fb10dc4ca9da98b8d9163f6372b18b9c Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Thu, 17 Feb 2022 05:21:48 +0100 Subject: [PATCH 18/20] Fix travis --- htdocs/asset/class/asset.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/asset/class/asset.class.php b/htdocs/asset/class/asset.class.php index 7727fe24f93..19c15839231 100644 --- a/htdocs/asset/class/asset.class.php +++ b/htdocs/asset/class/asset.class.php @@ -839,7 +839,7 @@ class Asset extends CommonObject } $sql = "DELETE FROM " . MAIN_DB_PREFIX . "asset_depreciation"; $sql .= " WHERE fk_asset = " . (int) $this->id; - $sql .= " AND depreciation_mode NOT IN ('" . implode("', '", $modes) . "')"; + $sql .= " AND depreciation_mode NOT IN ('" . $this->db->sanitize(implode("', '", $modes)) . "')"; $resql = $this->db->query($sql); if (!$resql) { From 96fcd7cae2e0e6953fab0038c565f446aca4f2e4 Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Thu, 17 Feb 2022 05:41:37 +0100 Subject: [PATCH 19/20] Fix travis --- htdocs/asset/class/assetaccountancycodes.class.php | 4 ++-- htdocs/asset/class/assetdepreciationoptions.class.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/htdocs/asset/class/assetaccountancycodes.class.php b/htdocs/asset/class/assetaccountancycodes.class.php index 1107c334c6f..720dd1e745d 100644 --- a/htdocs/asset/class/assetaccountancycodes.class.php +++ b/htdocs/asset/class/assetaccountancycodes.class.php @@ -142,7 +142,7 @@ class AssetAccountancyCodes extends CommonObject foreach ($this->accountancy_codes_fields as $mode_key => $mode_info) { $sql = "SELECT " . implode(',', array_keys($mode_info['fields'])); $sql .= " FROM " . MAIN_DB_PREFIX . $mode_info['table']; - $sql .= " WHERE " . ($asset_id > 0 ? " fk_asset = " . $asset_id : " fk_asset_model = " . $asset_model_id); + $sql .= " WHERE " . ($asset_id > 0 ? " fk_asset = " . (int) $asset_id : " fk_asset_model = " . (int) $asset_model_id); $resql = $this->db->query($sql); if ($resql) { @@ -216,7 +216,7 @@ class AssetAccountancyCodes extends CommonObject foreach ($this->accountancy_codes_fields as $mode_key => $mode_info) { // Delete old accountancy codes $sql = "DELETE FROM " . MAIN_DB_PREFIX . $mode_info['table']; - $sql .= " WHERE " . ($asset_id > 0 ? " fk_asset = " . $asset_id : " fk_asset_model = " . $asset_model_id); + $sql .= " WHERE " . ($asset_id > 0 ? " fk_asset = " . (int) $asset_id : " fk_asset_model = " . (int) $asset_model_id); $resql = $this->db->query($sql); if (!$resql) { $this->errors[] = $langs->trans('AssetErrorDeleteAccountancyCodesForMode', $mode_key) . ': ' . $this->db->lasterror(); diff --git a/htdocs/asset/class/assetdepreciationoptions.class.php b/htdocs/asset/class/assetdepreciationoptions.class.php index 88cd9dad9fa..79395111ba7 100644 --- a/htdocs/asset/class/assetdepreciationoptions.class.php +++ b/htdocs/asset/class/assetdepreciationoptions.class.php @@ -474,7 +474,7 @@ class AssetDepreciationOptions extends CommonObject foreach ($this->deprecation_options_fields as $mode_key => $mode_info) { // Delete old accountancy codes $sql = "DELETE FROM " . MAIN_DB_PREFIX . $mode_info['table']; - $sql .= " WHERE " . ($asset_id > 0 ? " fk_asset = " . $asset_id : " fk_asset_model = " . $asset_model_id); + $sql .= " WHERE " . ($asset_id > 0 ? " fk_asset = " . (int) $asset_id : " fk_asset_model = " . (int) $asset_model_id); $resql = $this->db->query($sql); if (!$resql) { $this->errors[] = $langs->trans('AssetErrorDeleteDepreciationOptionsForMode', $mode_key) . ': ' . $this->db->lasterror(); From 546b3dd4d5d060ef490872890d7322884db96455 Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Sun, 20 Feb 2022 05:17:06 +0100 Subject: [PATCH 20/20] Fix travis --- htdocs/asset/class/assetdepreciationoptions.class.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/asset/class/assetdepreciationoptions.class.php b/htdocs/asset/class/assetdepreciationoptions.class.php index 79395111ba7..ce2ddd73c08 100644 --- a/htdocs/asset/class/assetdepreciationoptions.class.php +++ b/htdocs/asset/class/assetdepreciationoptions.class.php @@ -309,7 +309,7 @@ class AssetDepreciationOptions extends CommonObject public function fetchDeprecationOptions($asset_id = 0, $asset_model_id = 0) { global $langs, $hookmanager; - dol_syslog(__METHOD__ . " sset_id=$asset_id, asset_model_id=$asset_model_id"); + dol_syslog(__METHOD__ . " asset_id=$asset_id, asset_model_id=$asset_model_id"); $error = 0; $this->errors = array(); @@ -346,7 +346,7 @@ class AssetDepreciationOptions extends CommonObject foreach ($this->deprecation_options_fields as $mode_key => $mode_info) { $this->setInfosForMode($mode_key, $class_type); - $result = $this->fetchCommon(0, '', " AND " . ($asset_id > 0 ? " fk_asset = " . $asset_id : " fk_asset_model = " . $asset_model_id)); + $result = $this->fetchCommon(0, '', " AND " . ($asset_id > 0 ? " fk_asset = " . (int) $asset_id : " fk_asset_model = " . (int) $asset_model_id)); if ($result < 0) { $this->errors = array_merge(array($langs->trans('AssetErrorFetchDepreciationOptionsForMode', $mode_key) . ':'), $this->errors); $error++;