From 9e667e015597258eb2003ed067b0956017281431 Mon Sep 17 00:00:00 2001 From: Quentin VIAL-GOUTEYRON Date: Wed, 9 Feb 2022 15:55:21 +0100 Subject: [PATCH 001/255] NEW Needed nets bom --- htdocs/bom/bom_net_needs.php | 354 +++++++++++++++++++++++++++++++++ htdocs/bom/class/bom.class.php | 55 +++++ htdocs/bom/lib/bom.lib.php | 5 + htdocs/langs/en_US/mrp.lang | 3 + 4 files changed, 417 insertions(+) create mode 100644 htdocs/bom/bom_net_needs.php diff --git a/htdocs/bom/bom_net_needs.php b/htdocs/bom/bom_net_needs.php new file mode 100644 index 00000000000..399aa8aa739 --- /dev/null +++ b/htdocs/bom/bom_net_needs.php @@ -0,0 +1,354 @@ + + * 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 . + */ + +/** + * \file htdocs/bom/bom_net_needs.php + * \ingroup bom + * \brief Page to create/edit/view bom + */ + +// Load Dolibarr environment +require '../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; +require_once DOL_DOCUMENT_ROOT.'/bom/class/bom.class.php'; +require_once DOL_DOCUMENT_ROOT.'/bom/lib/bom.lib.php'; + +// Load translation files required by the page +$langs->loadLangs(array("mrp", "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') : 'bomnet_needs'; // To manage different context of search +$backtopage = GETPOST('backtopage', 'alpha'); + + + +// Initialize technical objects +$object = new BOM($db); +$extrafields = new ExtraFields($db); +$diroutputmassaction = $conf->bom->dir_output.'/temp/massgeneration/'.$user->id; +$hookmanager->initHooks(array('bomnetneeds')); // 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. +if ($object->id > 0) { + $object->calculateCosts(); +} + + + +// Security check - Protection if external user +//if ($user->socid > 0) accessforbidden(); +//if ($user->socid > 0) $socid = $user->socid; +$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +$result = restrictedArea($user, 'bom', $object->id, 'bom_bom', '', '', 'rowid', $isdraft); + +$permissionnote = $user->rights->bom->write; // Used by the include of actions_setnotes.inc.php +$permissiondellink = $user->rights->bom->write; // Used by the include of actions_dellink.inc.php +$permissiontoadd = $user->rights->bom->write; // Used by the include of actions_addupdatedelete.inc.php and actions_lineupdown.inc.php +$permissiontodelete = $user->rights->bom->delete || ($permissiontoadd && isset($object->status) && $object->status == $object::STATUS_DRAFT); +$upload_dir = $conf->bom->multidir_output[isset($object->entity) ? $object->entity : 1]; + + +/* + * 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.'/bom/bom_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.'/bom/bom_net_needs.php?id='.($id > 0 ? $id : '__ID__'); + } + } + } + if($action == 'treeview') $object->getNetNeedsTree($TChildBom,1); + else $object->getNetNeeds($TChildBom, 1); + +} + + +/* + * View + */ + +$form = new Form($db); +$formfile = new FormFile($db); + + +$title = $langs->trans('BOM'); +$help_url ='EN:Module_BOM'; +llxHeader('', $title, $help_url); + + +// Part to edit record +if (($id || $ref) && $action == 'edit') { + print load_fiche_titre($langs->trans("BillOfMaterials"), '', 'cubes'); + + print '
'; + print ''; + print ''; + print ''; + print ''; + + print dol_get_fiche_head(); + + //$object->fields['keyfield']['disabled'] = 1; + + 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("Create"); + + print '
'; +} + +// Part to show record +if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'create'))) { + $head = bomPrepareHead($object); + print dol_get_fiche_head($head, 'net_needs', $langs->trans("BillOfMaterials"), -1, 'bom'); + + $formconfirm = ''; + + // Call Hook formConfirm + $parameters = array('formConfirm' => $formconfirm, 'lineid' => $lineid); + $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 + $keyforbreak = 'duration'; + include DOL_DOCUMENT_ROOT.'/core/tpl/commonfields_view.tpl.php'; + + print ''; + print ''; + + // Other attributes + include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php'; + + print '
'.$form->textwithpicto($langs->trans("TotalCost"), $langs->trans("BOMTotalCost")).''.price($object->total_cost).'
'.$langs->trans("UnitCost").''.price($object->unit_cost).'
'; + print '
'; + print '
'; + + print '
'; + + print dol_get_fiche_end(); + + + + /* + * Lines + */ + print ''; + print "\n"; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + if(! empty($TChildBom)) { + if($action == 'treeview') { + foreach($TChildBom as $fk_bom => $TProduct) { + $repeatChar = ' '; + if(! empty($TProduct['bom'])) { + if($TProduct['parentid'] != $object->id) print ''; + else print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + } + if(! empty($TProduct['product'])) { + foreach($TProduct['product'] as $fk_product => $TInfos) { + $prod = new Product($db); + $prod->fetch($fk_product); + $prod->load_virtual_stock(); + if(empty($prod->stock_reel)) $prod->stock_reel = 0; + if($fk_bom != $object->id) print ''; + else print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + } + } + } + } + else { + foreach($TChildBom as $fk_product => $qty) { + $prod = new Product($db); + $prod->fetch($fk_product); + $prod->load_virtual_stock(); + if(empty($prod->stock_reel)) $prod->stock_reel = 0; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + } + } + } + print ''; + print '
'.$langs->trans('Product'); + if(! empty($conf->global->BOM_SUB_BOM) && $action == 'treeview') { + print '   '.img_picto('', 'folder-open', 'class="paddingright"').$langs->trans("ExpandAll").'  '; + print ''.img_picto('', 'folder', 'class="paddingright"').$langs->trans("UndoExpandAll").' '; + } + print ''.$langs->trans('Quantity').''.$langs->trans('PhysicalStock').''.$langs->trans('VirtualStock').'
'.str_repeat($repeatChar, $TProduct['level']).$TProduct['bom']->getNomUrl(1); + print ' '; + print img_picto('', 'folder-open'); + print ''; + print ''.$TProduct['qty'].'
'.str_repeat($repeatChar, $TInfos['level']).$prod->getNomUrl(1).''.$TInfos['qty'].''.$prod->stock_reel.''.$prod->stock_theorique.'
'.$prod->getNomUrl(1).''.$qty.''.$prod->stock_reel.''.$prod->stock_theorique.'
'; + + + + /* + * ButAction + */ + 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($action != 'treeview') print ''.$langs->trans("DisplayInTreeStructure").''."\n"; + else print ''.$langs->trans("BackToStandardView").''."\n"; + } + + print '
'; + + + ?> + + + + close(); diff --git a/htdocs/bom/class/bom.class.php b/htdocs/bom/class/bom.class.php index 5f732c47300..7acc2749fad 100644 --- a/htdocs/bom/class/bom.class.php +++ b/htdocs/bom/class/bom.class.php @@ -1085,6 +1085,7 @@ class BOM extends CommonObject $res = $bom_child->fetch($line->fk_bom_child); if ($res>0) { $bom_child->calculateCosts(); + $line->childBom[] = $bom_child; $this->total_cost += $bom_child->total_cost; } else { $this->error = $bom_child->error; @@ -1101,6 +1102,55 @@ class BOM extends CommonObject } } } + + /** + * Get Net needs by product + * + * @param array $TNetNeeds + * @param int $qty + * @return void + */ + public function getNetNeeds(&$TNetNeeds = array(), $qty = 0) { + if(! empty($this->lines)) { + foreach($this->lines as $line) { + if(! empty($line->childBom)) { + foreach($line->childBom as $childBom) $childBom->getNetNeeds($TNetNeeds, $line->qty*$qty); + } + else { + $TNetNeeds[$line->fk_product] += $line->qty*$qty; + } + } + } + } + + /** + * Get Net needs Tree by product or bom + * + * @param array $TNetNeeds + * @param int $qty + * @param int $level + * @return void + */ + public function getNetNeedsTree(&$TNetNeeds = array(), $qty = 0, $level = 0) { + if(! empty($this->lines)) { + foreach($this->lines as $line) { + if(! empty($line->childBom)) { + foreach($line->childBom as $childBom) { + $TNetNeeds[$childBom->id]['bom'] = $childBom; + $TNetNeeds[$childBom->id]['parentid'] = $this->id; + $TNetNeeds[$childBom->id]['qty'] = $line->qty*$qty; + $TNetNeeds[$childBom->id]['level'] = $level; + $childBom->getNetNeedsTree($TNetNeeds, $line->qty*$qty, $level+1); + } + } + else { + $TNetNeeds[$this->id]['product'][$line->fk_product]['qty'] += $line->qty * $qty; + $TNetNeeds[$this->id]['product'][$line->fk_product]['level'] = $level; + } + } + } + } + } @@ -1227,6 +1277,11 @@ class BOMLine extends CommonObjectLine public $unit_cost = 0; + /** + * @var Bom array of Bom in line + */ + public $childBom = array(); + /** * Constructor * diff --git a/htdocs/bom/lib/bom.lib.php b/htdocs/bom/lib/bom.lib.php index 805ba304c1d..954959d5d7a 100644 --- a/htdocs/bom/lib/bom.lib.php +++ b/htdocs/bom/lib/bom.lib.php @@ -84,6 +84,11 @@ function bomPrepareHead($object) $head[$h][2] = 'card'; $h++; + $head[$h][0] = DOL_URL_ROOT."/bom/bom_net_needs.php?id=".$object->id; + $head[$h][1] = $langs->trans("BOMNetNeeds"); + $head[$h][2] = 'net_needs'; + $h++; + if (isset($object->fields['note_public']) || isset($object->fields['note_private'])) { $nbNote = 0; if (!empty($object->note_private)) { diff --git a/htdocs/langs/en_US/mrp.lang b/htdocs/langs/en_US/mrp.lang index 74bed0d9186..ca902380935 100644 --- a/htdocs/langs/en_US/mrp.lang +++ b/htdocs/langs/en_US/mrp.lang @@ -107,3 +107,6 @@ THMEstimatedHelp=This rate makes it possible to define a forecast cost of the it BOM=Bill Of Materials CollapseBOMHelp=You can define the default display of the details of the nomenclature in the configuration of the BOM module MOAndLines=Manufacturing Orders and lines +BOMNetNeeds=Net Needs +DisplayInTreeStructure=Display in tree structure +BackToStandardView=Back to standard view \ No newline at end of file From 2260276bed0c7d02a480efa7b395daf580dd9287 Mon Sep 17 00:00:00 2001 From: Quentin VIAL-GOUTEYRON Date: Thu, 10 Feb 2022 10:09:36 +0100 Subject: [PATCH 002/255] add tooltip --- htdocs/bom/bom_net_needs.php | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/htdocs/bom/bom_net_needs.php b/htdocs/bom/bom_net_needs.php index 399aa8aa739..dcd6764d74a 100644 --- a/htdocs/bom/bom_net_needs.php +++ b/htdocs/bom/bom_net_needs.php @@ -220,6 +220,16 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea /* * Lines */ + $text_stock_options = $langs->trans("RealStockDesc").'
'; + $text_stock_options .= $langs->trans("RealStockWillAutomaticallyWhen").'
'; + $text_stock_options .= (! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT) || ! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT_CLOSE) ? '- '.$langs->trans("DeStockOnShipment").'
' : ''); + $text_stock_options .= (! empty($conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER) ? '- '.$langs->trans("DeStockOnValidateOrder").'
' : ''); + $text_stock_options .= (! empty($conf->global->STOCK_CALCULATE_ON_BILL) ? '- '.$langs->trans("DeStockOnBill").'
' : ''); + $text_stock_options .= (! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_BILL) ? '- '.$langs->trans("ReStockOnBill").'
' : ''); + $text_stock_options .= (! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER) ? '- '.$langs->trans("ReStockOnValidateOrder").'
' : ''); + $text_stock_options .= (! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER) ? '- '.$langs->trans("ReStockOnDispatchOrder").'
' : ''); + $text_stock_options .= (!empty($conf->global->STOCK_CALCULATE_ON_RECEPTION) || !empty($conf->global->STOCK_CALCULATE_ON_RECEPTION_CLOSE) ? '- '.$langs->trans("StockOnReception").'
' : ''); + print ''; print "\n"; print ''; @@ -230,8 +240,8 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea } print ''; print ''; - print ''; - print ''; + print ''; + print ''; print ''; if(! empty($TChildBom)) { if($action == 'treeview') { From 7cf94486098fbdcedada47441e85f6eff4d20d5a Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Thu, 10 Feb 2022 09:22:53 +0000 Subject: [PATCH 003/255] Fixing style errors. --- htdocs/bom/bom_net_needs.php | 43 ++++++++++++++++------------------ htdocs/bom/class/bom.class.php | 29 +++++++++++------------ 2 files changed, 34 insertions(+), 38 deletions(-) diff --git a/htdocs/bom/bom_net_needs.php b/htdocs/bom/bom_net_needs.php index dcd6764d74a..e9f408498f0 100644 --- a/htdocs/bom/bom_net_needs.php +++ b/htdocs/bom/bom_net_needs.php @@ -110,9 +110,8 @@ if (empty($reshook)) { } } } - if($action == 'treeview') $object->getNetNeedsTree($TChildBom,1); + if ($action == 'treeview') $object->getNetNeedsTree($TChildBom, 1); else $object->getNetNeeds($TChildBom, 1); - } @@ -234,7 +233,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea print "\n"; print ''; print ''; print ''; print ''; - if(! empty($TChildBom)) { - if($action == 'treeview') { - foreach($TChildBom as $fk_bom => $TProduct) { + if (! empty($TChildBom)) { + if ($action == 'treeview') { + foreach ($TChildBom as $fk_bom => $TProduct) { $repeatChar = ' '; - if(! empty($TProduct['bom'])) { - if($TProduct['parentid'] != $object->id) print ''; + if (! empty($TProduct['bom'])) { + if ($TProduct['parentid'] != $object->id) print ''; else print ''; print ''; print ''; } - if(! empty($TProduct['product'])) { - foreach($TProduct['product'] as $fk_product => $TInfos) { + if (! empty($TProduct['product'])) { + foreach ($TProduct['product'] as $fk_product => $TInfos) { $prod = new Product($db); $prod->fetch($fk_product); $prod->load_virtual_stock(); - if(empty($prod->stock_reel)) $prod->stock_reel = 0; - if($fk_bom != $object->id) print ''; + if (empty($prod->stock_reel)) $prod->stock_reel = 0; + if ($fk_bom != $object->id) print ''; else print ''; print ''; print ''; @@ -276,13 +275,12 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea } } } - } - else { - foreach($TChildBom as $fk_product => $qty) { + } else { + foreach ($TChildBom as $fk_product => $qty) { $prod = new Product($db); $prod->fetch($fk_product); $prod->load_virtual_stock(); - if(empty($prod->stock_reel)) $prod->stock_reel = 0; + if (empty($prod->stock_reel)) $prod->stock_reel = 0; print ''; print ''; print ''; @@ -297,18 +295,18 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea - /* - * ButAction - */ + /* + * ButAction + */ 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) { + if ($reshook < 0) { setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); } - if(empty($reshook)) { - if($action != 'treeview') print ''.$langs->trans("DisplayInTreeStructure").''."\n"; + if (empty($reshook)) { + if ($action != 'treeview') print ''.$langs->trans("DisplayInTreeStructure").''."\n"; else print ''.$langs->trans("BackToStandardView").''."\n"; } @@ -356,7 +354,6 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea lines)) { - foreach($this->lines as $line) { - if(! empty($line->childBom)) { - foreach($line->childBom as $childBom) $childBom->getNetNeeds($TNetNeeds, $line->qty*$qty); - } - else { + public function getNetNeeds(&$TNetNeeds = array(), $qty = 0) + { + if (! empty($this->lines)) { + foreach ($this->lines as $line) { + if (! empty($line->childBom)) { + foreach ($line->childBom as $childBom) $childBom->getNetNeeds($TNetNeeds, $line->qty*$qty); + } else { $TNetNeeds[$line->fk_product] += $line->qty*$qty; } } @@ -1131,26 +1131,25 @@ class BOM extends CommonObject * @param int $level * @return void */ - public function getNetNeedsTree(&$TNetNeeds = array(), $qty = 0, $level = 0) { - if(! empty($this->lines)) { - foreach($this->lines as $line) { - if(! empty($line->childBom)) { - foreach($line->childBom as $childBom) { + public function getNetNeedsTree(&$TNetNeeds = array(), $qty = 0, $level = 0) + { + if (! empty($this->lines)) { + foreach ($this->lines as $line) { + if (! empty($line->childBom)) { + foreach ($line->childBom as $childBom) { $TNetNeeds[$childBom->id]['bom'] = $childBom; $TNetNeeds[$childBom->id]['parentid'] = $this->id; $TNetNeeds[$childBom->id]['qty'] = $line->qty*$qty; $TNetNeeds[$childBom->id]['level'] = $level; $childBom->getNetNeedsTree($TNetNeeds, $line->qty*$qty, $level+1); } - } - else { + } else { $TNetNeeds[$this->id]['product'][$line->fk_product]['qty'] += $line->qty * $qty; $TNetNeeds[$this->id]['product'][$line->fk_product]['level'] = $level; } } } } - } From dd0202de47a702d9ad100c66c2250c8d7b78d9e4 Mon Sep 17 00:00:00 2001 From: Quentin VIAL-GOUTEYRON Date: Thu, 10 Feb 2022 10:46:04 +0100 Subject: [PATCH 004/255] fix comment doc --- htdocs/bom/class/bom.class.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/htdocs/bom/class/bom.class.php b/htdocs/bom/class/bom.class.php index 75cf0e3a65e..17d17edad8d 100644 --- a/htdocs/bom/class/bom.class.php +++ b/htdocs/bom/class/bom.class.php @@ -1106,8 +1106,8 @@ class BOM extends CommonObject /** * Get Net needs by product * - * @param array $TNetNeeds - * @param int $qty + * @param array $TNetNeeds Array of ChildBom and infos linked to + * @param int $qty qty needed * @return void */ public function getNetNeeds(&$TNetNeeds = array(), $qty = 0) @@ -1126,9 +1126,9 @@ class BOM extends CommonObject /** * Get Net needs Tree by product or bom * - * @param array $TNetNeeds - * @param int $qty - * @param int $level + * @param array $TNetNeeds Array of ChildBom and infos linked to + * @param int $qty qty needed + * @param int $level level of recursivity * @return void */ public function getNetNeedsTree(&$TNetNeeds = array(), $qty = 0, $level = 0) From cd955930b6ead7a8bcd2e99623d6917bdd06401c Mon Sep 17 00:00:00 2001 From: Quentin VIAL-GOUTEYRON Date: Thu, 10 Feb 2022 15:00:55 +0100 Subject: [PATCH 005/255] change bt link --- htdocs/bom/bom_net_needs.php | 39 +++--------------------------------- htdocs/langs/en_US/mrp.lang | 4 ++-- 2 files changed, 5 insertions(+), 38 deletions(-) diff --git a/htdocs/bom/bom_net_needs.php b/htdocs/bom/bom_net_needs.php index e9f408498f0..4b2d5cdecab 100644 --- a/htdocs/bom/bom_net_needs.php +++ b/htdocs/bom/bom_net_needs.php @@ -128,36 +128,6 @@ $help_url ='EN:Module_BOM'; llxHeader('', $title, $help_url); -// Part to edit record -if (($id || $ref) && $action == 'edit') { - print load_fiche_titre($langs->trans("BillOfMaterials"), '', 'cubes'); - - print '
'; - print ''; - print ''; - print ''; - print ''; - - print dol_get_fiche_head(); - - //$object->fields['keyfield']['disabled'] = 1; - - print '
'.$langs->trans('Quantity').''.$langs->trans('PhysicalStock').''.$langs->trans('VirtualStock').''.$form->textwithpicto($langs->trans("PhysicalStock"), $text_stock_options, 1).''.$form->textwithpicto($langs->trans("VirtualStock"), $langs->trans("VirtualStockDesc")).'
'.$langs->trans('Product'); - if(! empty($conf->global->BOM_SUB_BOM) && $action == 'treeview') { + if (! empty($conf->global->BOM_SUB_BOM) && $action == 'treeview') { print '   '.img_picto('', 'folder-open', 'class="paddingright"').$langs->trans("ExpandAll").'  '; print ''.img_picto('', 'folder', 'class="paddingright"').$langs->trans("UndoExpandAll").' '; } @@ -243,12 +242,12 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea print ''.$form->textwithpicto($langs->trans("PhysicalStock"), $text_stock_options, 1).''.$form->textwithpicto($langs->trans("VirtualStock"), $langs->trans("VirtualStockDesc")).'
'.str_repeat($repeatChar, $TProduct['level']).$TProduct['bom']->getNomUrl(1); print ' '; @@ -260,13 +259,13 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea print '
'.str_repeat($repeatChar, $TInfos['level']).$prod->getNomUrl(1).''.$TInfos['qty'].'
'.$prod->getNomUrl(1).''.$qty.'
'."\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("Create"); - - print ''; -} // Part to show record if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'create'))) { @@ -214,7 +184,10 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea print dol_get_fiche_end(); + $viewlink = dolGetButtonTitle($langs->trans('GroupByProduct'), '', 'fa fa-list-alt imgforviewmode', $_SERVER['PHP_SELF'].'?id='.$object->id.'&token='.newToken(), '', 1, array('morecss' => 'reposition '.($action !== 'treeview' ? 'btnTitleSelected':''))); + $viewlink .= dolGetButtonTitle($langs->trans('TreeStructure'), '', 'fa fa-stream imgforviewmode', $_SERVER['PHP_SELF'].'?id='.$object->id.'&action=treeview&token='.newToken(), '', 1, array('morecss' => 'reposition marginleftonly '.($action == 'treeview' ? 'btnTitleSelected':''))); + print load_fiche_titre($langs->trans("BillOfMaterials"), $viewlink, 'cubes'); /* * Lines @@ -304,12 +277,6 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea if ($reshook < 0) { setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); } - - if (empty($reshook)) { - if ($action != 'treeview') print ''.$langs->trans("DisplayInTreeStructure").''."\n"; - else print ''.$langs->trans("BackToStandardView").''."\n"; - } - print ''; diff --git a/htdocs/langs/en_US/mrp.lang b/htdocs/langs/en_US/mrp.lang index ca902380935..4dc74122ea9 100644 --- a/htdocs/langs/en_US/mrp.lang +++ b/htdocs/langs/en_US/mrp.lang @@ -108,5 +108,5 @@ BOM=Bill Of Materials CollapseBOMHelp=You can define the default display of the details of the nomenclature in the configuration of the BOM module MOAndLines=Manufacturing Orders and lines BOMNetNeeds=Net Needs -DisplayInTreeStructure=Display in tree structure -BackToStandardView=Back to standard view \ No newline at end of file +TreeStructure=Tree structure +GroupByProduct=Group by product \ No newline at end of file From d819d427c303c74b31695131a2e73045675fddba Mon Sep 17 00:00:00 2001 From: Quentin VIAL-GOUTEYRON Date: Thu, 10 Feb 2022 16:46:19 +0100 Subject: [PATCH 006/255] FIX sort amount ht --- htdocs/compta/stats/cabyprodserv.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/compta/stats/cabyprodserv.php b/htdocs/compta/stats/cabyprodserv.php index ba09d7e6551..67267288b7a 100644 --- a/htdocs/compta/stats/cabyprodserv.php +++ b/htdocs/compta/stats/cabyprodserv.php @@ -375,7 +375,7 @@ if ($modecompta == 'CREANCES-DETTES') $_SERVER["PHP_SELF"], "amount", "", - $classslink, + $paramslink, 'class="right"', $sortfield, $sortorder From 39bd5dd6dce2b5eb8e380c6ce7724a107411515f Mon Sep 17 00:00:00 2001 From: Thomas Negre Date: Thu, 3 Feb 2022 12:08:39 +0100 Subject: [PATCH 007/255] ticket config : add TICKET_AUTO_READ_WHEN_CREATED_FROM_BACKEND option to config panel --- htdocs/admin/ticket.php | 27 ++++++++++++++++++++++++--- htdocs/langs/en_US/main.lang | 1 + htdocs/langs/en_US/ticket.lang | 3 +++ htdocs/langs/fr_FR/main.lang | 1 + htdocs/langs/fr_FR/ticket.lang | 3 +++ 5 files changed, 32 insertions(+), 3 deletions(-) diff --git a/htdocs/admin/ticket.php b/htdocs/admin/ticket.php index f4e5b4f3fad..1805f5de34d 100644 --- a/htdocs/admin/ticket.php +++ b/htdocs/admin/ticket.php @@ -178,8 +178,14 @@ if ($action == 'setvarother') { $error++; } - $param_auto_assign = GETPOST('TICKET_AUTO_ASSIGN_USER_CREATE', 'alpha'); - $res = dolibarr_set_const($db, 'TICKET_AUTO_ASSIGN_USER_CREATE', $param_auto_assign, 'chaine', 0, '', $conf->entity); + $param_auto_assign = GETPOST('TICKET_AUTO_READ_WHEN_CREATED_FROM_BACKEND', 'alpha'); + $res = dolibarr_set_const($db, 'TICKET_AUTO_READ_WHEN_CREATED_FROM_BACKEND', $param_auto_assign, 'chaine', 0, '', $conf->entity); + if (!($res > 0)) { + $error++; + } + + $param_auto_read = GETPOST('TICKET_AUTO_ASSIGN_USER_CREATE', 'alpha'); + $res = dolibarr_set_const($db, 'TICKET_AUTO_ASSIGN_USER_CREATE', $param_auto_read, 'chaine', 0, '', $conf->entity); if (!($res > 0)) { $error++; } @@ -470,7 +476,7 @@ if (!$conf->use_javascript_ajax) { print ''; } -print load_fiche_titre($langs->trans("Other"), '', ''); +print load_fiche_titre($langs->trans("Workflow"), '', ''); print ''; print ''; @@ -479,6 +485,21 @@ print ''; print ''; print "\n"; +// Auto mark ticket read when created from backoffice +print ''; +print ''; +print ''; +print ''; + // Auto assign ticket at user who created it print ''; print ''; } +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 ''; + } + print ''; + print ''; } print '
'.$langs->trans("TicketsAutoReadTicket").''; +if ($conf->use_javascript_ajax) { + print ajax_constantonoff('TICKET_AUTO_READ_WHEN_CREATED_FROM_BACKEND'); +} else { + $arrval = array('0' => $langs->trans("No"), '1' => $langs->trans("Yes")); + print $form->selectarray("TICKET_AUTO_READ_WHEN_CREATED_FROM_BACKEND", $arrval, $conf->global->TICKET_AUTO_READ_WHEN_CREATED_FROM_BACKEND); +} +print ''; +print $form->textwithpicto('', $langs->trans("TicketsAutoReadTicketHelp"), 1, 'help'); +print '
'.$langs->trans("TicketsAutoAssignTicket").''; diff --git a/htdocs/langs/en_US/main.lang b/htdocs/langs/en_US/main.lang index 2d850927782..2867c7b853b 100644 --- a/htdocs/langs/en_US/main.lang +++ b/htdocs/langs/en_US/main.lang @@ -517,6 +517,7 @@ or=or Other=Other Others=Others OtherInformations=Other information +Workflow=Workflow Quantity=Quantity Qty=Qty ChangedBy=Changed by diff --git a/htdocs/langs/en_US/ticket.lang b/htdocs/langs/en_US/ticket.lang index d38358eb74d..222efad8ba2 100644 --- a/htdocs/langs/en_US/ticket.lang +++ b/htdocs/langs/en_US/ticket.lang @@ -136,6 +136,9 @@ TicketsPublicNotificationNewMessage=Send email(s) when a new message/comment is TicketsPublicNotificationNewMessageHelp=Send email(s) when a new message is added from public interface (to assigned user or the notifications email to (update) and/or the notifications email to) TicketPublicNotificationNewMessageDefaultEmail=Notifications email to (update) TicketPublicNotificationNewMessageDefaultEmailHelp=Send an email to this address for each new message notifications if the ticket doesn't have a user assigned to it or if the user doesn't have any known email. +TicketsAutoReadTicket=Automatically mark the ticket as read +TicketsAutoReadTicketHelp=Automatically mark the ticket as read when created from backoffice. + # # Index & list page # diff --git a/htdocs/langs/fr_FR/main.lang b/htdocs/langs/fr_FR/main.lang index 63c5192a01f..12778f337dd 100644 --- a/htdocs/langs/fr_FR/main.lang +++ b/htdocs/langs/fr_FR/main.lang @@ -517,6 +517,7 @@ or=ou Other=Autre Others=Autres OtherInformations=Autre information +Workflow=Processus de travail Quantity=Quantité Qty=Qté ChangedBy=Modifié par diff --git a/htdocs/langs/fr_FR/ticket.lang b/htdocs/langs/fr_FR/ticket.lang index 91850194533..bc51a7627fd 100644 --- a/htdocs/langs/fr_FR/ticket.lang +++ b/htdocs/langs/fr_FR/ticket.lang @@ -136,6 +136,9 @@ TicketsPublicNotificationNewMessage=Envoyer un ou des emails lorsqu’un nouveau TicketsPublicNotificationNewMessageHelp=Envoyer un (des) courriel(s) lorsqu’un nouveau message est ajouté à partir de l’interface publique (à l’utilisateur désigné ou au courriel de notification (mise à jour) et/ou au courriel de notification) TicketPublicNotificationNewMessageDefaultEmail=Emails de notifications à (mise à jour) TicketPublicNotificationNewMessageDefaultEmailHelp=Envoyez un email à cette adresse email pour chaque nouveau message de notifications si le ticket n'a pas d'utilisateur assigné ou si l'utilisateur n'a pas d'email connu. +TicketsAutoReadTicket=Automatiquement marquer le ticket comme lu +TicketsAutoReadTicketHelp=Automatiquement marquer le ticket comme lu s'il est créé depuis le backoffice. + # # Index & list page # From c5d1310373a4a7f41806a412c66986a6e3cc84b3 Mon Sep 17 00:00:00 2001 From: Thomas Negre Date: Thu, 3 Feb 2022 12:23:58 +0100 Subject: [PATCH 008/255] handle workflow constants in appropriate category --- htdocs/admin/ticket.php | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/htdocs/admin/ticket.php b/htdocs/admin/ticket.php index 1805f5de34d..e6a6208324e 100644 --- a/htdocs/admin/ticket.php +++ b/htdocs/admin/ticket.php @@ -143,6 +143,20 @@ if ($action == 'updateMask') { } } +if ($action == 'setvarworkflow') { + $param_auto_read = GETPOST('TICKET_AUTO_READ_WHEN_CREATED_FROM_BACKEND', 'alpha'); + $res = dolibarr_set_const($db, 'TICKET_AUTO_READ_WHEN_CREATED_FROM_BACKEND', $param_auto_read, 'chaine', 0, '', $conf->entity); + if (!($res > 0)) { + $error++; + } + + $param_auto_assign = GETPOST('TICKET_AUTO_ASSIGN_USER_CREATE', 'alpha'); + $res = dolibarr_set_const($db, 'TICKET_AUTO_ASSIGN_USER_CREATE', $param_auto_assign, 'chaine', 0, '', $conf->entity); + if (!($res > 0)) { + $error++; + } +} + if ($action == 'setvarother') { $param_must_exists = GETPOST('TICKET_EMAIL_MUST_EXISTS', 'alpha'); $res = dolibarr_set_const($db, 'TICKET_EMAIL_MUST_EXISTS', $param_must_exists, 'chaine', 0, '', $conf->entity); @@ -177,18 +191,6 @@ if ($action == 'setvarother') { if (!($res > 0)) { $error++; } - - $param_auto_assign = GETPOST('TICKET_AUTO_READ_WHEN_CREATED_FROM_BACKEND', 'alpha'); - $res = dolibarr_set_const($db, 'TICKET_AUTO_READ_WHEN_CREATED_FROM_BACKEND', $param_auto_assign, 'chaine', 0, '', $conf->entity); - if (!($res > 0)) { - $error++; - } - - $param_auto_read = GETPOST('TICKET_AUTO_ASSIGN_USER_CREATE', 'alpha'); - $res = dolibarr_set_const($db, 'TICKET_AUTO_ASSIGN_USER_CREATE', $param_auto_read, 'chaine', 0, '', $conf->entity); - if (!($res > 0)) { - $error++; - } } @@ -473,7 +475,7 @@ print '
'; if (!$conf->use_javascript_ajax) { print '
'; print ''; - print ''; + print ''; } print load_fiche_titre($langs->trans("Workflow"), '', ''); From 4c5ddcf0300a59b1b50f388299e73d3014ce3f88 Mon Sep 17 00:00:00 2001 From: Thomas Negre Date: Thu, 10 Feb 2022 17:57:28 +0100 Subject: [PATCH 009/255] ticket config: add constant TICKET_AUTO_READ_WHEN_CREATED_FROM_BACKEND to admin panel --- htdocs/core/modules/modTicket.class.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/htdocs/core/modules/modTicket.class.php b/htdocs/core/modules/modTicket.class.php index 01561b40b01..6091a245bfa 100644 --- a/htdocs/core/modules/modTicket.class.php +++ b/htdocs/core/modules/modTicket.class.php @@ -106,7 +106,8 @@ class modTicket extends DolibarrModules $this->const = array( 1 => array('TICKET_ENABLE_PUBLIC_INTERFACE', 'chaine', '0', 'Enable ticket public interface', 0), 2 => array('TICKET_ADDON', 'chaine', 'mod_ticket_simple', 'Ticket ref module', 0), - 3 => array('TICKET_ADDON_PDF_ODT_PATH', 'chaine', 'DOL_DATA_ROOT/doctemplates/tickets', 'Ticket templates ODT/ODS directory for templates', 0) + 3 => array('TICKET_ADDON_PDF_ODT_PATH', 'chaine', 'DOL_DATA_ROOT/doctemplates/tickets', 'Ticket templates ODT/ODS directory for templates', 0), + 4 => array('TICKET_AUTO_READ_WHEN_CREATED_FROM_BACKEND', 'chaine', 0, 'Automatically mark ticket as read when created from backend', 0) ); From 88a33c730a6a977d2310a32e8c2ec2297da9a28e Mon Sep 17 00:00:00 2001 From: Alfredo Altamirano Date: Fri, 11 Feb 2022 02:01:25 -0600 Subject: [PATCH 010/255] FIX #20042 Update Mexican legal entities --- .../mysql/data/llx_c_forme_juridique.sql | 25 ++++++++++++++----- .../install/mysql/migration/14.0.0-15.0.0.sql | 23 +++++++++++++++++ 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/htdocs/install/mysql/data/llx_c_forme_juridique.sql b/htdocs/install/mysql/data/llx_c_forme_juridique.sql index 7af5d28df8c..a1293084a52 100644 --- a/htdocs/install/mysql/data/llx_c_forme_juridique.sql +++ b/htdocs/install/mysql/data/llx_c_forme_juridique.sql @@ -302,12 +302,25 @@ INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (152, INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (152, '15210', 'Mauritius Trusts', 1); -- Mexique -INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15401', 'Sociedad en nombre colectivo', 1); -INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15402', 'Sociedad en comandita simple', 1); -INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15403', 'Sociedad de responsabilidad limitada', 1); -INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15404', 'Sociedad anónima', 1); -INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15405', 'Sociedad en comandita por acciones', 1); -INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15406', 'Sociedad cooperativa', 1); +INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15401', '601 - General de Ley Personas Morales', 1); +INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15402', '603 - Personas Morales con Fines no Lucrativos', 1); +INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15403', '605 - Sueldos y Salarios e Ingresos Asimilados a Salarios', 1); +INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15404', '606 - Arrendamiento', 1); +INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15405', '607 - Régimen de Enajenación o Adquisición de Bienes', 1); +INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15406', '608 - Demás ingresos', 1); +INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15407', '610 - Residentes en el Extranjero sin Establecimiento Permanente en México', 1); +INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15408', '611 - Ingresos por Dividendos (socios y accionistas)', 1); +INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15409', '612 - Personas Físicas con Actividades Empresariales y Profesionales', 1); +INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15410', '614 - Ingresos por intereses', 1); +INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15411', '615 - Régimen de los ingresos por obtención de premios', 1); +INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15412', '616 - Sin obligaciones fiscales', 1); +INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15413', '620 - Sociedades Cooperativas de Producción que optan por diferir sus ingresos', 1); +INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15414', '621 - Incorporación Fiscal', 1); +INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15415', '622 - Actividades Agrícolas, Ganaderas, Silvícolas y Pesqueras', 1); +INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15416', '623 - Opcional para Grupos de Sociedades', 1); +INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15417', '624 - Coordinados', 1); +INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15418', '625 - Régimen de las Actividades Empresariales con ingresos a través de Plataformas Tecnológicas', 1); +INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15419', '626 - Régimen Simplificado de Confianza', 1); -- Luxembourg INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (140, '14001', 'Entreprise individuelle', 1); diff --git a/htdocs/install/mysql/migration/14.0.0-15.0.0.sql b/htdocs/install/mysql/migration/14.0.0-15.0.0.sql index 7be62695d50..69d7c93af5f 100644 --- a/htdocs/install/mysql/migration/14.0.0-15.0.0.sql +++ b/htdocs/install/mysql/migration/14.0.0-15.0.0.sql @@ -506,3 +506,26 @@ INSERT INTO llx_c_action_trigger (code,label,description,elementtype,rang) value INSERT INTO llx_c_action_trigger (code,label,description,elementtype,rang) values ('HOLIDAY_APPROVE','Holiday aprouved','Executed when a holiday is aprouved','holiday',803); INSERT INTO llx_c_action_trigger (code,label,description,elementtype,rang) values ('HOLIDAY_CANCEL','Holiday canceled','Executed when a holiday is canceled','holiday',802); INSERT INTO llx_c_action_trigger (code,label,description,elementtype,rang) values ('HOLIDAY_DELETE','Holiday deleted','Executed when a holiday is deleted','holiday',804); + +-- Delete old mexican legal forms +DELETE FROM llx_c_forme_juridique WHERE code IN ('15401', '15402', '15403', '15404', '15405', '15406'); + +INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15401', '601 - General de Ley Personas Morales', 1); +INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15402', '603 - Personas Morales con Fines no Lucrativos', 1); +INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15403', '605 - Sueldos y Salarios e Ingresos Asimilados a Salarios', 1); +INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15404', '606 - Arrendamiento', 1); +INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15405', '607 - Régimen de Enajenación o Adquisición de Bienes', 1); +INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15406', '608 - Demás ingresos', 1); +INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15407', '610 - Residentes en el Extranjero sin Establecimiento Permanente en México', 1); +INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15408', '611 - Ingresos por Dividendos (socios y accionistas)', 1); +INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15409', '612 - Personas Físicas con Actividades Empresariales y Profesionales', 1); +INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15410', '614 - Ingresos por intereses', 1); +INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15411', '615 - Régimen de los ingresos por obtención de premios', 1); +INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15412', '616 - Sin obligaciones fiscales', 1); +INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15413', '620 - Sociedades Cooperativas de Producción que optan por diferir sus ingresos', 1); +INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15414', '621 - Incorporación Fiscal', 1); +INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15415', '622 - Actividades Agrícolas, Ganaderas, Silvícolas y Pesqueras', 1); +INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15416', '623 - Opcional para Grupos de Sociedades', 1); +INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15417', '624 - Coordinados', 1); +INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15418', '625 - Régimen de las Actividades Empresariales con ingresos a través de Plataformas Tecnológicas', 1); +INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15419', '626 - Régimen Simplificado de Confianza', 1); From 455247565d68132add664def71a36fc19f418024 Mon Sep 17 00:00:00 2001 From: atm-arnaud Date: Fri, 11 Feb 2022 11:40:45 +0100 Subject: [PATCH 011/255] FIX wrong user author --- htdocs/societe/class/societe.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/societe/class/societe.class.php b/htdocs/societe/class/societe.class.php index c8b381280b1..3d1637019e9 100644 --- a/htdocs/societe/class/societe.class.php +++ b/htdocs/societe/class/societe.class.php @@ -875,8 +875,8 @@ class Societe extends CommonObject $sql .= ", name_alias"; $sql .= ", entity"; $sql .= ", datec"; - $sql .= ", fk_typent"; $sql .= ", fk_user_creat"; + $sql .= ", fk_typent"; $sql .= ", canvas"; $sql .= ", status"; $sql .= ", ref_ext"; From c552030b69863a34404e3e00d3045ff4d7e95818 Mon Sep 17 00:00:00 2001 From: Marc GUENNEUGUES Date: Fri, 11 Feb 2022 15:18:38 +0100 Subject: [PATCH 012/255] Fix urlencode breaking links in Market Place page --- htdocs/admin/dolistore/class/dolistore.class.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/htdocs/admin/dolistore/class/dolistore.class.php b/htdocs/admin/dolistore/class/dolistore.class.php index 546ef1d57a6..f672cf05a52 100644 --- a/htdocs/admin/dolistore/class/dolistore.class.php +++ b/htdocs/admin/dolistore/class/dolistore.class.php @@ -267,9 +267,9 @@ class Dolistore // add image or default ? if ($product->id_default_image != '') { - $image_url = DOL_URL_ROOT.'/admin/dolistore/ajax/image.php?id_product='.((int) $product->id).'&id_image='.((int) $product->id_default_image); - $images = ''; - $images .= ''; + $image_url = DOL_URL_ROOT.'/admin/dolistore/ajax/image.php?id_product='.urlencode(((int) $product->id)).'&id_image='.urlencode(((int) $product->id_default_image)); + $images = ''; + $images .= ''; } else { $images = ''; } @@ -277,11 +277,11 @@ class Dolistore // free or pay ? if ($product->price > 0) { $price = '

'.price(price2num($product->price, 'MT'), 0, $langs, 1, -1, -1, 'EUR').' '.$langs->trans("HT").'

'; - $download_link = ''; + $download_link = ''; } else { $price = '

'.$langs->trans('Free').'

'; - $download_link = ''; - $download_link .= '

'; + $download_link = ''; + $download_link .= '

'; } // Set and check version From 11e15255bd2c373972b07c52ef007c27987b7838 Mon Sep 17 00:00:00 2001 From: ptibogxiv Date: Sat, 12 Feb 2022 16:59:29 +0100 Subject: [PATCH 013/255] FIX API REST for setup values --- htdocs/api/class/api_setup.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/api/class/api_setup.class.php b/htdocs/api/class/api_setup.class.php index 85a45e9ff45..e937980e96d 100644 --- a/htdocs/api/class/api_setup.class.php +++ b/htdocs/api/class/api_setup.class.php @@ -1112,7 +1112,7 @@ class Setup extends DolibarrApi $sql = "SELECT rowid AS id, zip, town, fk_county, fk_pays AS fk_country"; $sql .= " FROM ".MAIN_DB_PREFIX."c_ziptown as t"; - $sql .= " AND t.active = ".$active; + $sql .= " WHERE t.active = ".$active; if ($zipcode) { $sql .= " AND t.zip LIKE '%".$this->db->escape($zipcode)."%'"; } From a5a8f30939b503dc277b899351351cf8e07684de Mon Sep 17 00:00:00 2001 From: ptibogxiv Date: Sat, 12 Feb 2022 17:08:43 +0100 Subject: [PATCH 014/255] FIX API REST setup bad words --- htdocs/api/class/api_setup.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/api/class/api_setup.class.php b/htdocs/api/class/api_setup.class.php index 15a29c0e18b..97039d599ef 100644 --- a/htdocs/api/class/api_setup.class.php +++ b/htdocs/api/class/api_setup.class.php @@ -1774,7 +1774,7 @@ class Setup extends DolibarrApi $result = $establishment->fetch($id); if ($result < 0) { - throw new RestException(503, 'Error when retrieving state : '.$establishment->error); + throw new RestException(503, 'Error when retrieving establishment : '.$establishment->error); } elseif ($result == 0) { throw new RestException(404, 'Establishment not found'); } From 54af0cf47a887ce29388f40e24886712a2875dd1 Mon Sep 17 00:00:00 2001 From: ptibogxiv Date: Sat, 12 Feb 2022 19:02:00 +0100 Subject: [PATCH 015/255] NEW API REST filter states by country --- htdocs/api/class/api_setup.class.php | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/htdocs/api/class/api_setup.class.php b/htdocs/api/class/api_setup.class.php index 15a29c0e18b..33b7c4f9f95 100644 --- a/htdocs/api/class/api_setup.class.php +++ b/htdocs/api/class/api_setup.class.php @@ -239,7 +239,6 @@ class Setup extends DolibarrApi return $list; } - /** * Get the list of states/provinces. * @@ -252,22 +251,29 @@ class Setup extends DolibarrApi * @param string $sortorder Sort order * @param int $limit Number of items per page * @param int $page Page number (starting from zero) - * @param string $filter To filter the countries by name + * @param string $country To filter on country + * @param string $filter To filter the states by name * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)" - * @return array List of countries + * @return array List of states * * @url GET dictionary/states * * @throws RestException */ - public function getListOfStates($sortfield = "code_departement", $sortorder = 'ASC', $limit = 100, $page = 0, $filter = '', $sqlfilters = '') + public function getListOfStates($sortfield = "code_departement", $sortorder = 'ASC', $limit = 100, $page = 0, $country = '', $filter = '', $sqlfilters = '') { $list = array(); // Note: The filter is not applied in the SQL request because it must // be applied to the translated names, not to the names in database. - $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."c_departements as t"; + $sql = "SELECT t.rowid FROM ".MAIN_DB_PREFIX."c_departements as t"; + if ($country) { + $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_regions as d ON t.fk_region = d.code_region"; + } $sql .= " WHERE 1 = 1"; + if ($country) { + $sql .= " AND d.fk_pays = '".$this->db->escape($country)."'"; + } // Add sql filters if ($sqlfilters) { $errormessage = ''; From 8d3e97bab98324f5c29b8603ccb130d849a214c3 Mon Sep 17 00:00:00 2001 From: ptibogxiv Date: Sat, 12 Feb 2022 19:21:07 +0100 Subject: [PATCH 016/255] Update api_setup.class.php --- htdocs/api/class/api_setup.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/api/class/api_setup.class.php b/htdocs/api/class/api_setup.class.php index e937980e96d..1b687e09d28 100644 --- a/htdocs/api/class/api_setup.class.php +++ b/htdocs/api/class/api_setup.class.php @@ -1098,7 +1098,7 @@ class Setup extends DolibarrApi * @param int $page Page number (starting from zero) * @param string $zipcode To filter on zipcode * @param string $town To filter on city name - * @param int $active Payment term is active or not {@min 0} {@max 1} + * @param int $active Town is active or not {@min 0} {@max 1} * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)" * @return array List of towns * From f2b88c6d7c0cebd0e6960bd4f167d7ef64bebc93 Mon Sep 17 00:00:00 2001 From: ptibogxiv Date: Sun, 13 Feb 2022 10:09:39 +0100 Subject: [PATCH 017/255] Update api_setup.class.php --- htdocs/api/class/api_setup.class.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/htdocs/api/class/api_setup.class.php b/htdocs/api/class/api_setup.class.php index 33b7c4f9f95..0c9e602e70c 100644 --- a/htdocs/api/class/api_setup.class.php +++ b/htdocs/api/class/api_setup.class.php @@ -251,7 +251,7 @@ class Setup extends DolibarrApi * @param string $sortorder Sort order * @param int $limit Number of items per page * @param int $page Page number (starting from zero) - * @param string $country To filter on country + * @param int $country To filter on country * @param string $filter To filter the states by name * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)" * @return array List of states @@ -260,7 +260,7 @@ class Setup extends DolibarrApi * * @throws RestException */ - public function getListOfStates($sortfield = "code_departement", $sortorder = 'ASC', $limit = 100, $page = 0, $country = '', $filter = '', $sqlfilters = '') + public function getListOfStates($sortfield = "code_departement", $sortorder = 'ASC', $limit = 100, $page = 0, $country = 0, $filter = '', $sqlfilters = '') { $list = array(); @@ -272,7 +272,7 @@ class Setup extends DolibarrApi } $sql .= " WHERE 1 = 1"; if ($country) { - $sql .= " AND d.fk_pays = '".$this->db->escape($country)."'"; + $sql .= " AND d.fk_pays = ".((int) $country); } // Add sql filters if ($sqlfilters) { From 061dd565cc4337fc1e63fd5598ef462ff2be13a1 Mon Sep 17 00:00:00 2001 From: ptibogxiv Date: Sun, 13 Feb 2022 13:22:01 +0100 Subject: [PATCH 018/255] Update api_setup.class.php --- htdocs/api/class/api_setup.class.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/htdocs/api/class/api_setup.class.php b/htdocs/api/class/api_setup.class.php index 0c9e602e70c..87b4af4c98c 100644 --- a/htdocs/api/class/api_setup.class.php +++ b/htdocs/api/class/api_setup.class.php @@ -1307,7 +1307,7 @@ class Setup extends DolibarrApi * @param string $sortorder Sort order * @param int $limit Number of items per page * @param int $page Page number (starting from zero) - * @param string $country To filter on country + * @param int $country To filter on country * @param int $active Lega form is active or not {@min 0} {@max 1} * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)" * @return array List of legal form @@ -1316,7 +1316,7 @@ class Setup extends DolibarrApi * * @throws RestException */ - public function getListOfLegalForm($sortfield = "rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $country = '', $active = 1, $sqlfilters = '') + public function getListOfLegalForm($sortfield = "rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $country = 0, $active = 1, $sqlfilters = '') { $list = array(); @@ -1324,7 +1324,7 @@ class Setup extends DolibarrApi $sql .= " FROM ".MAIN_DB_PREFIX."c_forme_juridique as t"; $sql .= " WHERE t.active = ".((int) $active); if ($country) { - $sql .= " AND t.fk_pays = '".$this->db->escape($country)."'"; + $sql .= " AND t.fk_pays = ".((int) $country); } // Add sql filters if ($sqlfilters) { From 9349e2df7cffc0fb631651655f44f8c36a57bb89 Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Sun, 13 Feb 2022 21:11:45 +0100 Subject: [PATCH 019/255] FIX Accountancy - Order by accounting account on summary page --- htdocs/accountancy/customer/index.php | 1 + htdocs/accountancy/expensereport/index.php | 1 + htdocs/accountancy/supplier/index.php | 1 + 3 files changed, 3 insertions(+) diff --git a/htdocs/accountancy/customer/index.php b/htdocs/accountancy/customer/index.php index a88524ec5d4..c233134f562 100644 --- a/htdocs/accountancy/customer/index.php +++ b/htdocs/accountancy/customer/index.php @@ -403,6 +403,7 @@ if (!empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) { } $sql .= " AND aa.account_number IS NOT NULL"; $sql .= " GROUP BY fd.fk_code_ventilation,aa.account_number,aa.label"; +$sql .= ' ORDER BY aa.account_number'; dol_syslog('htdocs/accountancy/customer/index.php'); $resql = $db->query($sql); diff --git a/htdocs/accountancy/expensereport/index.php b/htdocs/accountancy/expensereport/index.php index 0e3bda39521..2d9c8ac4f1c 100644 --- a/htdocs/accountancy/expensereport/index.php +++ b/htdocs/accountancy/expensereport/index.php @@ -188,6 +188,7 @@ $sql .= " AND er.fk_statut IN (".ExpenseReport::STATUS_APPROVED.", ".ExpenseRepo $sql .= " AND er.entity IN (".getEntity('expensereport', 0).")"; // We don't share object for accountancy $sql .= " AND aa.account_number IS NULL"; $sql .= " GROUP BY erd.fk_code_ventilation,aa.account_number,aa.label"; +$sql .= ' ORDER BY aa.account_number'; dol_syslog('/accountancy/expensereport/index.php:: sql='.$sql); $resql = $db->query($sql); diff --git a/htdocs/accountancy/supplier/index.php b/htdocs/accountancy/supplier/index.php index 585121f7c36..9ea8fd0a307 100644 --- a/htdocs/accountancy/supplier/index.php +++ b/htdocs/accountancy/supplier/index.php @@ -300,6 +300,7 @@ $sql .= " AND ffd.product_type <= 2"; $sql .= " AND ff.entity IN (".getEntity('facture_fourn', 0).")"; // We don't share object for accountancy $sql .= " AND aa.account_number IS NULL"; $sql .= " GROUP BY ffd.fk_code_ventilation,aa.account_number,aa.label"; +$sql .= ' ORDER BY aa.account_number'; dol_syslog('htdocs/accountancy/supplier/index.php'); $resql = $db->query($sql); From 65934498061cbd6aecc44855814a2cd90c948fa7 Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Mon, 14 Feb 2022 04:20:42 +0100 Subject: [PATCH 020/255] 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 021/255] 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 022/255] 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 023/255] 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').''; + $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 ''; $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 024/255] 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 ''; From d869adb370f1ce725c2d4c08b850e637e52471af Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Mon, 14 Feb 2022 05:15:28 +0100 Subject: [PATCH 025/255] 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 026/255] 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 027/255] 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 028/255] 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 15b7f37027c0591a18b5c223abe8173de8ee1524 Mon Sep 17 00:00:00 2001 From: Regis Houssin Date: Mon, 14 Feb 2022 09:08:58 +0100 Subject: [PATCH 029/255] FIX missing default or current value --- htdocs/compta/bank/card.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/htdocs/compta/bank/card.php b/htdocs/compta/bank/card.php index 73edd31755d..62b97f6d100 100644 --- a/htdocs/compta/bank/card.php +++ b/htdocs/compta/bank/card.php @@ -358,7 +358,7 @@ if ($action == 'create') { // Type print ''.$langs->trans("AccountType").''; print ''; - $formbank->selectTypeOfBankAccount(GETPOSTISSET("type") ? GETPOST('type', 'alpha') : Account::TYPE_CURRENT, 'type'); + $formbank->selectTypeOfBankAccount(GETPOSTISSET("type") ? GETPOST('type', 'int') : Account::TYPE_CURRENT, 'type'); print ''; // Currency @@ -471,7 +471,7 @@ if ($action == 'create') { print ''; print '
    '; - $type = GETPOST('type'); + $type = (GETPOSTISSET("type") ? GETPOST('type', 'int') : Account::TYPE_CURRENT); // add default value if ($type == Account::TYPE_SAVINGS || $type == Account::TYPE_CURRENT) { print ''; @@ -857,7 +857,7 @@ if ($action == 'create') { // Type print ''; print ''; // Currency @@ -1002,7 +1002,8 @@ if ($action == 'create') { print '
    '.$langs->trans("AccountType").''; - $formbank->selectTypeOfBankAccount((GETPOSTISSET('type') ? GETPOST('type', 'alpha') : $object->type), 'type'); + $formbank->selectTypeOfBankAccount((GETPOSTISSET('type') ? GETPOST('type', 'int') : $object->type), 'type'); print '
    '; - if (GETPOST("type") == Account::TYPE_SAVINGS || GETPOST("type") == Account::TYPE_CURRENT) { + $type = (GETPOSTISSET('type') ? GETPOST('type', 'int') : $object->type); // add default current value + if ($type == Account::TYPE_SAVINGS || $type == Account::TYPE_CURRENT) { print '
    '; //print '
    '; From a17ac09fd05620fda3258c1211949f632fa1bb3d Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Mon, 14 Feb 2022 11:03:44 +0100 Subject: [PATCH 030/255] 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 031/255] 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 a3c1c707a438bdfac186f2317e514cdab9fe0e06 Mon Sep 17 00:00:00 2001 From: lmarcouiller Date: Mon, 14 Feb 2022 12:09:57 +0100 Subject: [PATCH 032/255] Close #19930 : tag management in KM list --- htdocs/categories/class/categorie.class.php | 3 +- .../knowledgerecord_list.php | 63 ++++++++++++++++++- 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/htdocs/categories/class/categorie.class.php b/htdocs/categories/class/categorie.class.php index 5ffed2e5e4b..c5da89a2c49 100644 --- a/htdocs/categories/class/categorie.class.php +++ b/htdocs/categories/class/categorie.class.php @@ -185,7 +185,8 @@ class Categorie extends CommonObject 'contact' => 'socpeople', 'account' => 'bank_account', // old for bank account 'project' => 'projet', - 'warehouse'=> 'entrepot' + 'warehouse'=> 'entrepot', + 'knowledgemanagement' => 'knowledgemanagement_knowledgerecord' ); /** diff --git a/htdocs/knowledgemanagement/knowledgerecord_list.php b/htdocs/knowledgemanagement/knowledgerecord_list.php index aed45b1db26..88d7e46506d 100644 --- a/htdocs/knowledgemanagement/knowledgerecord_list.php +++ b/htdocs/knowledgemanagement/knowledgerecord_list.php @@ -34,6 +34,9 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; require_once DOL_DOCUMENT_ROOT.'/knowledgemanagement/class/knowledgerecord.class.php'; // for other modules +if (!empty($conf->categorie->enabled)) { + dol_include_once('/categories/class/categorie.class.php'); +} //dol_include_once('/othermodule/class/otherobject.class.php'); // Load translation files required by the page @@ -51,6 +54,13 @@ $optioncss = GETPOST('optioncss', 'aZ'); // Option for the css output (always '' $id = GETPOST('id', 'int'); +$searchCategoryKnowledgemanagementList = GETPOST('search_category_knowledgemanagement_list', 'array'); +$searchCategoryKnowledgemanagementOperator = 0; +if (GETPOSTISSET('formfilteraction')) { + $searchCategoryKnowledgemanagementOperator = GETPOST('search_category_knowledgemanagement_operator', 'int'); +} elseif (!empty($conf->global->MAIN_SEARCH_CAT_OR_BY_DEFAULT)) { + $searchCategoryKnowledgemanagementOperator = $conf->global->MAIN_SEARCH_CAT_OR_BY_DEFAULT; +} // Load variable for pagination $limit = GETPOST('limit', 'int') ? GETPOST('limit', 'int') : $conf->liste_limit; $sortfield = GETPOST('sortfield', 'aZ09comma'); @@ -186,6 +196,10 @@ if (empty($reshook)) { || 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 } + if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { + $searchCategoryKnowledgemanagementOperator = 0; + $searchCategoryKnowledgemanagementList = array(); + } // Mass actions $objectclass = 'KnowledgeRecord'; @@ -229,9 +243,12 @@ $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 (!empty($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)"; } +if (!empty($searchCategoryKnowledgemanagementList) || !empty($catid)) { + $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX."categorie_knowledgemanagement as ck ON t.rowid = ck.fk_knowledgemanagement"; // We'll need this table joined to the select in order to filter by categ +} // Add table from hooks $parameters = array(); $reshook = $hookmanager->executeHooks('printFieldListFrom', $parameters, $object); // Note that $action and $object may have been modified by hook @@ -270,6 +287,32 @@ foreach ($search as $key => $val) { } } } +//Search for tag/category +$searchCategoryKnowledgemanagementSqlList = array(); +if ($searchCategoryKnowledgemanagementOperator == 1) { + foreach ($searchCategoryKnowledgemanagementList as $searchCategoryKnowledgemanagement) { + if (intval($searchCategoryKnowledgemanagement) == -2) { + $searchCategoryKnowledgemanagementSqlList[] = "ck.fk_categorie IS NULL"; + } elseif (intval($searchCategoryKnowledgemanagement) > 0) { + $searchCategoryKnowledgemanagementSqlList[] = "ck.fk_categorie = ".$db->escape($searchCategoryKnowledgemanagement); + } + } + if (!empty($searchCategoryKnowledgemanagementSqlList)) { + $sql .= " AND (".implode(' OR ', $searchCategoryKnowledgemanagementSqlList).")"; + } +} else { + foreach ($searchCategoryKnowledgemanagementList as $searchCategoryKnowledgemanagement) { + if (intval($searchCategoryKnowledgemanagement) == -2) { + $searchCategoryKnowledgemanagementSqlList[] = "ck.fk_categorie IS NULL"; + } elseif (intval($searchCategoryKnowledgemanagement) > 0) { + $searchCategoryKnowledgemanagementSqlList[] = "t.rowid IN (SELECT fk_knowledgemanagement FROM ".MAIN_DB_PREFIX."categorie_knowledgemanagement WHERE fk_categorie = ".((int) $searchCategoryKnowledgemanagement).")"; + } + } + if (!empty($searchCategoryKnowledgemanagementSqlList)) { + $sql .= " AND (".implode(' AND ', $searchCategoryKnowledgemanagementSqlList).")"; + } +} + if ($search_all) { $sql .= natural_search(array_keys($fieldstosearchall), $search_all); } @@ -379,6 +422,11 @@ $arrayofmassactions = array( if ($permissiontodelete) { $arrayofmassactions['predelete'] = img_picto('', 'delete', 'class="pictofixedwidth"').$langs->trans("Delete"); } + +if ($user->rights->knowledgemanagement->knowledgerecord->write) { + $arrayofmassactions['preaffecttag'] = img_picto('', 'category', 'class="pictofixedwidth"').$langs->trans("AffectTag"); +} + if (GETPOST('nomassaction', 'int') || in_array($massaction, array('presend', 'predelete'))) { $arrayofmassactions = array(); } @@ -418,6 +466,18 @@ $moreforfilter = ''; $moreforfilter.= $langs->trans('MyFilter') . ': '; $moreforfilter.= '';*/ +// Filter on categories +$moreforfilter = ''; +if (!empty($conf->categorie->enabled) && $user->rights->categorie->lire) { + $moreforfilter .= '
    '; + $moreforfilter .= img_picto($langs->trans('Categories'), 'category', 'class="pictofixedwidth"'); + $categoriesKnowledgeArr = $form->select_all_categories(Categorie::TYPE_KNOWLEDGEMANAGEMENT, '', '', 64, 0, 1); + $categoriesKnowledgeArr[-2] = '- '.$langs->trans('NotCategorized').' -'; + $moreforfilter .= Form::multiselectarray('search_category_knowledgemanagement_list', $categoriesKnowledgeArr, $searchCategoryKnowledgemanagementList, 0, 0, 'minwidth300'); + $moreforfilter .= ' '; + $moreforfilter .= '
    '; +} + $parameters = array(); $reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters, $object); // Note that $action and $object may have been modified by hook if (empty($reshook)) { @@ -547,6 +607,7 @@ while ($i < ($limit ? min($num, $limit) : $num)) { // Show here line of result print ''; + $totalarray['nbfield'] = 0; 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'))) { From 562c3cf9585bae4489730d9c753caad607c4c3bc Mon Sep 17 00:00:00 2001 From: Adrien Raze Date: Mon, 14 Feb 2022 14:15:38 +0100 Subject: [PATCH 033/255] FIX : There's no field "ref" in llx_facture_fourn_rec table --- htdocs/install/mysql/tables/llx_facture_fourn_rec.key.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/install/mysql/tables/llx_facture_fourn_rec.key.sql b/htdocs/install/mysql/tables/llx_facture_fourn_rec.key.sql index b3065fdb5d6..b82e75d85d6 100644 --- a/htdocs/install/mysql/tables/llx_facture_fourn_rec.key.sql +++ b/htdocs/install/mysql/tables/llx_facture_fourn_rec.key.sql @@ -16,7 +16,7 @@ -- ============================================================================ -ALTER TABLE llx_facture_fourn_rec ADD UNIQUE INDEX uk_facture_fourn_rec_ref (ref, entity); +ALTER TABLE llx_facture_fourn_rec ADD UNIQUE INDEX uk_facture_fourn_rec_ref (titre, entity); ALTER TABLE llx_facture_fourn_rec ADD UNIQUE INDEX uk_facture_fourn_rec_ref_supplier (ref_supplier, fk_soc, entity); ALTER TABLE llx_facture_fourn_rec ADD INDEX idx_facture_fourn_rec_date_lim_reglement (date_lim_reglement); From 3305965c854cda61e9742e9b5ede6b7002c6d4d9 Mon Sep 17 00:00:00 2001 From: Adrien Raze Date: Mon, 14 Feb 2022 15:04:12 +0100 Subject: [PATCH 034/255] FIX : Error with selectForForms function --- htdocs/core/class/html.form.class.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 09225f97158..b29093d7176 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -7379,10 +7379,7 @@ class Form $objecttmp = null; - $InfoFieldList = explode(":", $objectdesc, 4); - $vartmp = $InfoFieldList[3]; - $InfoFieldList[4] = preg_replace('/^.*:(\w*)$/', '\1', $vartmp); // take the sort field - $InfoFieldList[3] = preg_replace('/:\w*$/', '', $vartmp); // take the filter field + $InfoFieldList = explode(":", $objectdesc); $classname = $InfoFieldList[0]; $classpath = $InfoFieldList[1]; From 1d974f67f09901c7cee90032ce6bc72647f50f65 Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Mon, 14 Feb 2022 16:17:19 +0100 Subject: [PATCH 035/255] 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 34d2e0b8b406a01c103df1498a3af995550931ec Mon Sep 17 00:00:00 2001 From: Adrien Raze Date: Tue, 15 Feb 2022 10:29:42 +0100 Subject: [PATCH 036/255] FIX : Fixed sub bom costs problems --- htdocs/bom/bom_card.php | 2 +- htdocs/bom/class/bom.class.php | 2 +- htdocs/bom/tpl/objectline_view.tpl.php | 22 ++++++++++++++-------- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/htdocs/bom/bom_card.php b/htdocs/bom/bom_card.php index cbd730e5d23..6f748df22e4 100644 --- a/htdocs/bom/bom_card.php +++ b/htdocs/bom/bom_card.php @@ -518,7 +518,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea // Common attributes $keyforbreak = 'duration'; include DOL_DOCUMENT_ROOT.'/core/tpl/commonfields_view.tpl.php'; - + $object->calculateCosts(); print ''.$form->textwithpicto($langs->trans("TotalCost"), $langs->trans("BOMTotalCost")).''.price($object->total_cost).''; print ''.$langs->trans("UnitCost").''.price($object->unit_cost).''; diff --git a/htdocs/bom/class/bom.class.php b/htdocs/bom/class/bom.class.php index 5f732c47300..4bdf349eae5 100644 --- a/htdocs/bom/class/bom.class.php +++ b/htdocs/bom/class/bom.class.php @@ -1085,7 +1085,7 @@ class BOM extends CommonObject $res = $bom_child->fetch($line->fk_bom_child); if ($res>0) { $bom_child->calculateCosts(); - $this->total_cost += $bom_child->total_cost; + $this->total_cost += $bom_child->total_cost * $line->qty; } else { $this->error = $bom_child->error; return -2; diff --git a/htdocs/bom/tpl/objectline_view.tpl.php b/htdocs/bom/tpl/objectline_view.tpl.php index b72ed043581..14cfd22c39e 100644 --- a/htdocs/bom/tpl/objectline_view.tpl.php +++ b/htdocs/bom/tpl/objectline_view.tpl.php @@ -180,6 +180,7 @@ if ($action == 'selectlines') { print ''; // Select of all the sub-BOM lines +// From this pont to the end of the file, we only take care of sub-BOM lines $sql = 'SELECT rowid, fk_bom_child, fk_product, qty FROM '.MAIN_DB_PREFIX.'bom_bomline AS bl'; $sql.= ' WHERE fk_bom ='. (int) $tmpbom->id; $resql = $object->db->query($sql); @@ -191,7 +192,9 @@ if ($resql) { $sub_bom_product->fetch($obj->fk_product); $sub_bom = new BOM($object->db); - $sub_bom->fetch($obj->fk_bom_child); + if(!empty($obj->fk_bom_child)){ + $sub_bom->fetch($obj->fk_bom_child); + } $sub_bom_line = new BOMLine($object->db); $sub_bom_line->fetch($obj->rowid); @@ -233,20 +236,23 @@ if ($resql) { // Efficiency print ''.$sub_bom_line->efficiency.''; - // Cost price if it's defined - if ($sub_bom_product->cost_price > 0) { - print ''.price($sub_bom_product->cost_price * $line->qty).''; - $total_cost+= $sub_bom_product->cost_price * $line->qty; + if(!empty($sub_bom->id)){ + $sub_bom->calculateCosts(); + print ''.price($sub_bom->total_cost * $sub_bom_line->qty * $line->qty).''; + $total_cost+= $sub_bom->total_cost * $sub_bom_line->qty * $line->qty; + } elseif ($sub_bom_product->cost_price > 0) { + print ''.price($sub_bom_product->cost_price * $sub_bom_line->qty * $line->qty).''; + $total_cost+= $sub_bom_product->cost_price * $sub_bom_line->qty * $line->qty; } elseif ($sub_bom_product->pmp > 0) { // PMP if cost price isn't defined - print ''.price($sub_bom_product->pmp * $line->qty).''; - $total_cost.= $sub_bom_product->pmp * $line->qty; + print ''.price($sub_bom_product->pmp * $sub_bom_line->qty * $line->qty).''; + $total_cost.= $sub_bom_product->pmp * $sub_bom_line->qty * $line->qty; } else { // Minimum purchase price if cost price and PMP aren't defined $sql_supplier_price = 'SELECT MIN(price) AS min_price, quantity AS qty FROM '.MAIN_DB_PREFIX.'product_fournisseur_price'; $sql_supplier_price.= ' WHERE fk_product = '. (int) $sub_bom_product->id; $resql_supplier_price = $object->db->query($sql_supplier_price); if ($resql_supplier_price) { $obj = $object->db->fetch_object($resql_supplier_price); - $line_cost = $obj->min_price/$obj->qty * $sub_bom_line->qty; + $line_cost = $obj->min_price/$obj->qty * $sub_bom_line->qty * $line->qty; print ''.price($line_cost).''; $total_cost+= $line_cost; From 885d188be341e8187f626074b7f52535973f4847 Mon Sep 17 00:00:00 2001 From: lmarcouiller Date: Tue, 15 Feb 2022 10:41:55 +0100 Subject: [PATCH 037/255] use of require_once --- htdocs/knowledgemanagement/knowledgerecord_list.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/knowledgemanagement/knowledgerecord_list.php b/htdocs/knowledgemanagement/knowledgerecord_list.php index 88d7e46506d..675f6e4397f 100644 --- a/htdocs/knowledgemanagement/knowledgerecord_list.php +++ b/htdocs/knowledgemanagement/knowledgerecord_list.php @@ -35,7 +35,7 @@ require_once DOL_DOCUMENT_ROOT.'/knowledgemanagement/class/knowledgerecord.class // for other modules if (!empty($conf->categorie->enabled)) { - dol_include_once('/categories/class/categorie.class.php'); + require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; } //dol_include_once('/othermodule/class/otherobject.class.php'); From 11d1d9a0afb3ee55edd9bcfacc2227c10a6eee21 Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Wed, 16 Feb 2022 05:17:38 +0100 Subject: [PATCH 038/255] 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 039/255] 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 392f468a13d58b213cec92e868b5e9f4416039c3 Mon Sep 17 00:00:00 2001 From: Vincent Dieltiens Date: Wed, 16 Feb 2022 09:59:18 +0100 Subject: [PATCH 040/255] allow to add more CSS and more params on html fields --- htdocs/core/class/commonobject.class.php | 2 +- htdocs/core/class/doleditor.class.php | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index 87f6ba693fc..ac6d67c3f30 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -6693,7 +6693,7 @@ abstract class CommonObject if (!preg_match('/search_/', $keyprefix)) { // If keyprefix is search_ or search_options_, we must just use a simple text field require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php'; $doleditor = new DolEditor($keyprefix.$key.$keysuffix, $value, '', 200, 'dolibarr_notes', 'In', false, false, !empty($conf->fckeditor->enabled) && $conf->global->FCKEDITOR_ENABLE_SOCIETE, ROWS_5, '90%'); - $out = $doleditor->Create(1); + $out = $doleditor->Create(1, '', true, '', '', $moreparam, $morecss); } else { $out = ''; } diff --git a/htdocs/core/class/doleditor.class.php b/htdocs/core/class/doleditor.class.php index da98719d828..22300b53e9e 100644 --- a/htdocs/core/class/doleditor.class.php +++ b/htdocs/core/class/doleditor.class.php @@ -121,9 +121,11 @@ class DolEditor * @param boolean $disallowAnyContent Disallow to use any content. true=restrict to a predefined list of allowed elements. Used by CKEditor only. * @param string $titlecontent Show title content before editor area. Used by ACE editor only. * @param string $option For ACE editor, set the source language ('html', 'php', 'javascript', ...) + * @param string $moreparams Add extra tags to the textarea + * @param string $morecss Add extra css to the textarea * @return void|string */ - public function Create($noprint = 0, $morejs = '', $disallowAnyContent = true, $titlecontent = '', $option = '') + public function Create($noprint = 0, $morejs = '', $disallowAnyContent = true, $titlecontent = '', $option = '', $moreparam = '', $morecss = '') { // phpcs:enable global $conf, $langs; @@ -141,7 +143,7 @@ class DolEditor //$out.= ''; From 9a0a222b6322d1992c344e7b2344e78cefb9501f Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Wed, 16 Feb 2022 14:21:45 +0100 Subject: [PATCH 041/255] 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 1a41232181e9d7802f0edabe4e9285fd9f2b6c07 Mon Sep 17 00:00:00 2001 From: Atm-Gregr Date: Wed, 16 Feb 2022 15:24:35 +0100 Subject: [PATCH 042/255] add vacant position option --- htdocs/hrm/class/position.class.php | 77 ++++++++++++++++++++++++++++- htdocs/hrm/position_list.php | 4 ++ htdocs/langs/fr_FR/hrm.lang | 2 + 3 files changed, 81 insertions(+), 2 deletions(-) diff --git a/htdocs/hrm/class/position.class.php b/htdocs/hrm/class/position.class.php index 2401791bb5f..f3cc82f92fe 100644 --- a/htdocs/hrm/class/position.class.php +++ b/htdocs/hrm/class/position.class.php @@ -109,7 +109,7 @@ class Position extends CommonObject '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_contrat' => array('type'=>'integer:Contrat:contrat/class/contrat.class.php', 'label'=>'fk_contrat', 'enabled'=>'1', 'position'=>50, 'notnull'=>0, 'visible'=>0,), - 'fk_user' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'Employee', 'enabled'=>'1', 'position'=>55, 'notnull'=>0, 'visible'=>1,), + 'fk_user' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'Employee', 'enabled'=>'1', 'position'=>55, 'notnull'=>1, 'visible'=>1, 'default'=>0), 'fk_job' => array('type'=>'integer:Job:/hrm/class/job.class.php', 'label'=>'Job', 'enabled'=>'1', 'position'=>56, 'notnull'=>1, 'visible'=>1,), 'date_start' => array('type'=>'date', 'label'=>'DateStart', 'enabled'=>'1', 'position'=>51, 'notnull'=>1, 'visible'=>1,), 'date_end' => array('type'=>'date', 'label'=>'DateEnd', 'enabled'=>'1', 'position'=>52, 'notnull'=>0, 'visible'=>1,), @@ -842,7 +842,80 @@ class Position extends CommonObject return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode); } - /** + /** + * Return HTML string to put an input field into a page + * Code very similar with showInputField of extra fields + * + * @param array $val Array of properties for field to show + * @param string $key Key of attribute + * @param string $value Preselected value to show (for date type it must be in timestamp format, for amount or price it must be a php numeric value) + * @param string $moreparam To add more parameters on html input tag + * @param string $keysuffix Prefix string to add into name and id of field (can be used to avoid duplicate names) + * @param string $keyprefix Suffix string to add into name and id of field (can be used to avoid duplicate names) + * @param string|int $morecss Value for css to define style/length of field. May also be a numeric. + * @return string + */ + public function showInputField($val, $key, $value, $moreparam = '', $keysuffix = '', $keyprefix = '', $morecss = 0, $nonewbutton = 0) + { + global $langs; + + if($key == 'fk_user') + { + $vacantId = $keyprefix.$key.'vacant'.$keysuffix; + + $out = parent::showInputField($val, $key, $value, $moreparam, $keysuffix, $keyprefix, $morecss); + $out.= ''; + + ?> + + fk_user == 0) + { + return $langs->trans("VacantPosition"); + } + return parent::showOutputField($val, $key, $value, $moreparam, $keysuffix, $keyprefix, $morecss); + } + + + /** * Load the info information in the object * * @param int $id Id of object diff --git a/htdocs/hrm/position_list.php b/htdocs/hrm/position_list.php index d6ed72c2612..0e0f561ebb2 100644 --- a/htdocs/hrm/position_list.php +++ b/htdocs/hrm/position_list.php @@ -270,6 +270,10 @@ foreach ($search as $key => $val) { } } } +$vacant = GETPOST('vacant', 'alphanohtml') === 'on'; +if($vacant) { + $sql .= ' AND t.fk_user = 0'; +} if ($search_all) { $sql .= natural_search(array_keys($fieldstosearchall), $search_all); } diff --git a/htdocs/langs/fr_FR/hrm.lang b/htdocs/langs/fr_FR/hrm.lang index d47596fe95e..fd0bddcc2eb 100644 --- a/htdocs/langs/fr_FR/hrm.lang +++ b/htdocs/langs/fr_FR/hrm.lang @@ -79,3 +79,5 @@ NoEval=Aucune évaluation effectuée pour cet employé HowManyUserWithThisMaxNote=Nombre d'employés avec ce niveau HighestRank=Plus haut niveau SkillComparison=Comparaison des compétences +VacantPosition=Poste vacant +VacantCheckboxHelper=Cocher cette option affichera le(s) poste(s) comme non pourvu(s) From 7868aa305b8e0cea98f4dc01101f10107b9c5d57 Mon Sep 17 00:00:00 2001 From: Atm-Gregr Date: Wed, 16 Feb 2022 15:48:23 +0100 Subject: [PATCH 043/255] fix filter --- htdocs/hrm/position_list.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/hrm/position_list.php b/htdocs/hrm/position_list.php index 0e0f561ebb2..11e6d3c9abf 100644 --- a/htdocs/hrm/position_list.php +++ b/htdocs/hrm/position_list.php @@ -270,7 +270,7 @@ foreach ($search as $key => $val) { } } } -$vacant = GETPOST('vacant', 'alphanohtml') === 'on'; +$vacant = GETPOST('search_fk_uservacant', 'alphanohtml') === 'on'; if($vacant) { $sql .= ' AND t.fk_user = 0'; } From dbcbda642a3531f3c115a8f0e26fef5aa725d658 Mon Sep 17 00:00:00 2001 From: Atm-Gregr Date: Wed, 16 Feb 2022 15:53:06 +0100 Subject: [PATCH 044/255] fix sticker 1 --- htdocs/hrm/class/position.class.php | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/htdocs/hrm/class/position.class.php b/htdocs/hrm/class/position.class.php index f3cc82f92fe..bc74f96cee9 100644 --- a/htdocs/hrm/class/position.class.php +++ b/htdocs/hrm/class/position.class.php @@ -855,22 +855,20 @@ class Position extends CommonObject * @param string|int $morecss Value for css to define style/length of field. May also be a numeric. * @return string */ - public function showInputField($val, $key, $value, $moreparam = '', $keysuffix = '', $keyprefix = '', $morecss = 0, $nonewbutton = 0) - { + public function showInputField($val, $key, $value, $moreparam = '', $keysuffix = '', $keyprefix = '', $morecss = 0, $nonewbutton = 0) { global $langs; - if($key == 'fk_user') - { + if($key == 'fk_user') { $vacantId = $keyprefix.$key.'vacant'.$keysuffix; $out = parent::showInputField($val, $key, $value, $moreparam, $keysuffix, $keyprefix, $morecss); - $out.= ''; + $out .= ''; ?> fk_user == 0) - { + if($key == 'fk_user' && $this->fk_user == 0) { return $langs->trans("VacantPosition"); } return parent::showOutputField($val, $key, $value, $moreparam, $keysuffix, $keyprefix, $morecss); From 30d3a782dea288fe7dcc305e3e2cf49841e0fb64 Mon Sep 17 00:00:00 2001 From: Atm-Gregr Date: Wed, 16 Feb 2022 16:30:54 +0100 Subject: [PATCH 045/255] precommit stickler --- htdocs/hrm/class/position.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/hrm/class/position.class.php b/htdocs/hrm/class/position.class.php index bc74f96cee9..2bba18c131a 100644 --- a/htdocs/hrm/class/position.class.php +++ b/htdocs/hrm/class/position.class.php @@ -1141,7 +1141,7 @@ require_once DOL_DOCUMENT_ROOT . '/core/class/commonobjectline.class.php'; class PositionLine extends CommonObjectLine { // To complete with content of an object PositionLine - // We should have a field rowid, fk_position and position + // We should have a field rowid , fk_position and position /** * @var int Does object support extrafields ? 0=No, 1=Yes From 453449324e9664df2a4fb8b3ee4aca20240920c5 Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Wed, 16 Feb 2022 18:09:32 +0100 Subject: [PATCH 046/255] 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 047/255] 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 048/255] 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 049/255] 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 1c8c98ac0f22b61ffcd05b4a672fa92d9329df2d Mon Sep 17 00:00:00 2001 From: Thomas Negre Date: Thu, 17 Feb 2022 09:53:36 +0100 Subject: [PATCH 050/255] fix ticket public interface: When sending an email to the customer, If a custom URL had been provided for ticket public interface, the link provided in the email did lead to the index of the public interface. We want it to lead to /view.php --- htdocs/public/ticket/create_ticket.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/public/ticket/create_ticket.php b/htdocs/public/ticket/create_ticket.php index 29ec7983930..31b44f39b18 100644 --- a/htdocs/public/ticket/create_ticket.php +++ b/htdocs/public/ticket/create_ticket.php @@ -211,7 +211,7 @@ if ($action == 'create_ticket' && GETPOST('add', 'alpha')) { $message .= ($conf->global->TICKET_MESSAGE_MAIL_NEW ? $conf->global->TICKET_MESSAGE_MAIL_NEW : $langs->transnoentities('TicketNewEmailBody'))."\n\n"; $message .= $langs->transnoentities('TicketNewEmailBodyInfosTicket')."\n"; - $url_public_ticket = ($conf->global->TICKET_URL_PUBLIC_INTERFACE ? $conf->global->TICKET_URL_PUBLIC_INTERFACE.'/' : dol_buildpath('/public/ticket/view.php', 2)).'?track_id='.$object->track_id; + $url_public_ticket = ($conf->global->TICKET_URL_PUBLIC_INTERFACE ? $conf->global->TICKET_URL_PUBLIC_INTERFACE : dol_buildpath('/public/ticket', 2)).'/view.php?track_id='.$object->track_id; $infos_new_ticket = $langs->transnoentities('TicketNewEmailBodyInfosTrackId', ''.$object->track_id.'')."\n"; $infos_new_ticket .= $langs->transnoentities('TicketNewEmailBodyInfosTrackUrl')."\n\n"; From aea9c2e4275de16ae066fd03ca77d16f7e65391a Mon Sep 17 00:00:00 2001 From: lmarcouiller Date: Thu, 17 Feb 2022 10:22:58 +0100 Subject: [PATCH 051/255] Fix : fix php 8.0 warnings --- htdocs/adherents/agenda.php | 3 +++ htdocs/adherents/card.php | 1 + htdocs/adherents/subscription.php | 2 ++ htdocs/core/tpl/login.tpl.php | 2 +- 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/htdocs/adherents/agenda.php b/htdocs/adherents/agenda.php index cb942ba3176..9132dae5802 100644 --- a/htdocs/adherents/agenda.php +++ b/htdocs/adherents/agenda.php @@ -65,6 +65,9 @@ if (GETPOST('actioncode', 'array')) { } $search_agenda_label = GETPOST('search_agenda_label'); +// Get object canvas (By default, this is not defined, so standard usage of dolibarr) +$objcanvas = null; + // Security check $result = restrictedArea($user, 'adherent', $id); diff --git a/htdocs/adherents/card.php b/htdocs/adherents/card.php index a2e3779d52b..caf2bbe61d6 100644 --- a/htdocs/adherents/card.php +++ b/htdocs/adherents/card.php @@ -55,6 +55,7 @@ $id = GETPOST('id') ?GETPOST('id', 'int') : $rowid; $typeid = GETPOST('typeid', 'int'); $userid = GETPOST('userid', 'int'); $socid = GETPOST('socid', 'int'); +$ref = GETPOST('ref', 'alpha'); if (!empty($conf->mailmanspip->enabled)) { include_once DOL_DOCUMENT_ROOT.'/mailmanspip/class/mailmanspip.class.php'; diff --git a/htdocs/adherents/subscription.php b/htdocs/adherents/subscription.php index ac2555b4deb..5f578869e6e 100644 --- a/htdocs/adherents/subscription.php +++ b/htdocs/adherents/subscription.php @@ -40,6 +40,8 @@ require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingjournal.class.php'; $langs->loadLangs(array("companies", "bills", "members", "users", "mails", 'other')); +$optioncss = GETPOST('optioncss', 'aZ'); // Option for the css output (always '' except when 'print') + $action = GETPOST('action', 'aZ09'); $confirm = GETPOST('confirm', 'alpha'); $id = GETPOST('rowid', 'int') ?GETPOST('rowid', 'int') : GETPOST('id', 'int'); diff --git a/htdocs/core/tpl/login.tpl.php b/htdocs/core/tpl/login.tpl.php index c07e01570c2..70f4f51290c 100644 --- a/htdocs/core/tpl/login.tpl.php +++ b/htdocs/core/tpl/login.tpl.php @@ -31,7 +31,7 @@ if (empty($conf) || !is_object($conf)) { } // DDOS protection -$size = (int) $_SERVER['CONTENT_LENGTH']; +$size = (int) !empty($_SERVER['CONTENT_LENGTH'])?$_SERVER['CONTENT_LENGTH']:0; if ($size > 10000) { http_response_code(413); $langs->loadLangs(array("errors", "install")); From 13cfe858f23d5b132597206c5ca674f5fe27a8f4 Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Thu, 17 Feb 2022 09:53:02 +0000 Subject: [PATCH 052/255] Fixing style errors. --- htdocs/bom/bom_card.php | 2 +- htdocs/bom/tpl/objectline_view.tpl.php | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/htdocs/bom/bom_card.php b/htdocs/bom/bom_card.php index 6f748df22e4..f6e40b511f1 100644 --- a/htdocs/bom/bom_card.php +++ b/htdocs/bom/bom_card.php @@ -518,7 +518,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea // Common attributes $keyforbreak = 'duration'; include DOL_DOCUMENT_ROOT.'/core/tpl/commonfields_view.tpl.php'; - $object->calculateCosts(); + $object->calculateCosts(); print ''.$form->textwithpicto($langs->trans("TotalCost"), $langs->trans("BOMTotalCost")).''.price($object->total_cost).''; print ''.$langs->trans("UnitCost").''.price($object->unit_cost).''; diff --git a/htdocs/bom/tpl/objectline_view.tpl.php b/htdocs/bom/tpl/objectline_view.tpl.php index 14cfd22c39e..8040310ea53 100644 --- a/htdocs/bom/tpl/objectline_view.tpl.php +++ b/htdocs/bom/tpl/objectline_view.tpl.php @@ -192,9 +192,9 @@ if ($resql) { $sub_bom_product->fetch($obj->fk_product); $sub_bom = new BOM($object->db); - if(!empty($obj->fk_bom_child)){ + if (!empty($obj->fk_bom_child)) { $sub_bom->fetch($obj->fk_bom_child); - } + } $sub_bom_line = new BOMLine($object->db); $sub_bom_line->fetch($obj->rowid); @@ -236,11 +236,11 @@ if ($resql) { // Efficiency print ''.$sub_bom_line->efficiency.''; - if(!empty($sub_bom->id)){ - $sub_bom->calculateCosts(); - print ''.price($sub_bom->total_cost * $sub_bom_line->qty * $line->qty).''; + if (!empty($sub_bom->id)) { + $sub_bom->calculateCosts(); + print ''.price($sub_bom->total_cost * $sub_bom_line->qty * $line->qty).''; $total_cost+= $sub_bom->total_cost * $sub_bom_line->qty * $line->qty; - } elseif ($sub_bom_product->cost_price > 0) { + } elseif ($sub_bom_product->cost_price > 0) { print ''.price($sub_bom_product->cost_price * $sub_bom_line->qty * $line->qty).''; $total_cost+= $sub_bom_product->cost_price * $sub_bom_line->qty * $line->qty; } elseif ($sub_bom_product->pmp > 0) { // PMP if cost price isn't defined From 1ad8700810096cb8b5964a7cdda14881f965ce45 Mon Sep 17 00:00:00 2001 From: Thomas Negre Date: Thu, 17 Feb 2022 11:08:23 +0100 Subject: [PATCH 053/255] empty commit to force travis try rebuild From bb08341dc3a5029e8cc988b5962a90e47d7a67aa Mon Sep 17 00:00:00 2001 From: Henry Date: Thu, 17 Feb 2022 18:34:23 +0800 Subject: [PATCH 054/255] to disable the default pdf generation --- htdocs/fourn/class/fournisseur.commande.class.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/htdocs/fourn/class/fournisseur.commande.class.php b/htdocs/fourn/class/fournisseur.commande.class.php index ed978010a33..8a0e0de299e 100644 --- a/htdocs/fourn/class/fournisseur.commande.class.php +++ b/htdocs/fourn/class/fournisseur.commande.class.php @@ -3132,18 +3132,19 @@ class CommandeFournisseur extends CommonOrder $outputlangs->load("products"); if (!dol_strlen($modele)) { - $modele = 'muscadet'; - + $modele = ''; if ($this->model_pdf) { $modele = $this->model_pdf; } elseif (!empty($conf->global->COMMANDE_SUPPLIER_ADDON_PDF)) { $modele = $conf->global->COMMANDE_SUPPLIER_ADDON_PDF; } } - - $modelpath = "core/modules/supplier_order/doc/"; - - return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams); + if (empty($modele)) { + return 0; + } else { + $modelpath = "core/modules/supplier_order/doc/"; + return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams); + } } /** From c529af90c66ae1271fda99c4c102c007db538b90 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 17 Feb 2022 12:06:48 +0100 Subject: [PATCH 055/255] Fix trans --- htdocs/admin/tools/dolibarr_export.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/htdocs/admin/tools/dolibarr_export.php b/htdocs/admin/tools/dolibarr_export.php index 4f6977ffb41..092f3a57170 100644 --- a/htdocs/admin/tools/dolibarr_export.php +++ b/htdocs/admin/tools/dolibarr_export.php @@ -546,6 +546,7 @@ print ''; print ''; +$title = $langs->trans("BackupZipWizard"); print "
    \n"; print "\n"; @@ -564,7 +565,7 @@ print ''; print '
    '; -print load_fiche_titre($title ? $title : $langs->trans("BackupZipWizard")); +print load_fiche_titre($title); print '
    '; $prefix = 'documents'; From 85327f28b0ad0cb2c1e958f461ef0d41f462f479 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 17 Feb 2022 19:12:24 +0100 Subject: [PATCH 056/255] Update login.tpl.php --- htdocs/core/tpl/login.tpl.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/tpl/login.tpl.php b/htdocs/core/tpl/login.tpl.php index 70f4f51290c..27356c96795 100644 --- a/htdocs/core/tpl/login.tpl.php +++ b/htdocs/core/tpl/login.tpl.php @@ -31,7 +31,7 @@ if (empty($conf) || !is_object($conf)) { } // DDOS protection -$size = (int) !empty($_SERVER['CONTENT_LENGTH'])?$_SERVER['CONTENT_LENGTH']:0; +$size = (empty($_SERVER['CONTENT_LENGTH']) ? 0 : (int) $_SERVER['CONTENT_LENGTH']); if ($size > 10000) { http_response_code(413); $langs->loadLangs(array("errors", "install")); From 2e744a4517cf59fd939856ac1d97e7d054511c6d Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 17 Feb 2022 19:18:22 +0100 Subject: [PATCH 057/255] Update create_ticket.php --- htdocs/public/ticket/create_ticket.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/public/ticket/create_ticket.php b/htdocs/public/ticket/create_ticket.php index 31b44f39b18..1c9ca3aafe0 100644 --- a/htdocs/public/ticket/create_ticket.php +++ b/htdocs/public/ticket/create_ticket.php @@ -211,7 +211,7 @@ if ($action == 'create_ticket' && GETPOST('add', 'alpha')) { $message .= ($conf->global->TICKET_MESSAGE_MAIL_NEW ? $conf->global->TICKET_MESSAGE_MAIL_NEW : $langs->transnoentities('TicketNewEmailBody'))."\n\n"; $message .= $langs->transnoentities('TicketNewEmailBodyInfosTicket')."\n"; - $url_public_ticket = ($conf->global->TICKET_URL_PUBLIC_INTERFACE ? $conf->global->TICKET_URL_PUBLIC_INTERFACE : dol_buildpath('/public/ticket', 2)).'/view.php?track_id='.$object->track_id; + $url_public_ticket = ($conf->global->TICKET_URL_PUBLIC_INTERFACE ? $conf->global->TICKET_URL_PUBLIC_INTERFACE.'/view.php' : dol_buildpath('/public/ticket/view.php', 2)).'?track_id='.$object->track_id; $infos_new_ticket = $langs->transnoentities('TicketNewEmailBodyInfosTrackId', ''.$object->track_id.'')."\n"; $infos_new_ticket .= $langs->transnoentities('TicketNewEmailBodyInfosTrackUrl')."\n\n"; From 68beafe599c0e91f5c8777d2e402eaf2a357e952 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 17 Feb 2022 19:24:44 +0100 Subject: [PATCH 058/255] Removed useless indexes --- htdocs/install/mysql/tables/llx_facture_fourn_rec.key.sql | 2 -- 1 file changed, 2 deletions(-) diff --git a/htdocs/install/mysql/tables/llx_facture_fourn_rec.key.sql b/htdocs/install/mysql/tables/llx_facture_fourn_rec.key.sql index b82e75d85d6..c5a451e030f 100644 --- a/htdocs/install/mysql/tables/llx_facture_fourn_rec.key.sql +++ b/htdocs/install/mysql/tables/llx_facture_fourn_rec.key.sql @@ -17,9 +17,7 @@ ALTER TABLE llx_facture_fourn_rec ADD UNIQUE INDEX uk_facture_fourn_rec_ref (titre, entity); -ALTER TABLE llx_facture_fourn_rec ADD UNIQUE INDEX uk_facture_fourn_rec_ref_supplier (ref_supplier, fk_soc, entity); -ALTER TABLE llx_facture_fourn_rec ADD INDEX idx_facture_fourn_rec_date_lim_reglement (date_lim_reglement); ALTER TABLE llx_facture_fourn_rec ADD INDEX idx_facture_fourn_rec_fk_soc (fk_soc); ALTER TABLE llx_facture_fourn_rec ADD INDEX idx_facture_fourn_rec_fk_user_author (fk_user_author); ALTER TABLE llx_facture_fourn_rec ADD INDEX idx_facture_fourn_rec_fk_projet (fk_projet); From c20d82499920c1c0028d681700e7b80770e884ac Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 17 Feb 2022 19:30:18 +0100 Subject: [PATCH 059/255] Tables of module ticket are create only when module is enabled. --- htdocs/core/modules/modTicket.class.php | 5 +++++ .../tables/{llx_ticket.key.sql => llx_ticket-ticket.key.sql} | 0 .../mysql/tables/{llx_ticket.sql => llx_ticket-ticket.sql} | 0 ...afields.key.sql => llx_ticket_extrafields-ticket.key.sql} | 0 ...ket_extrafields.sql => llx_ticket_extrafields-ticket.sql} | 0 5 files changed, 5 insertions(+) rename htdocs/install/mysql/tables/{llx_ticket.key.sql => llx_ticket-ticket.key.sql} (100%) rename htdocs/install/mysql/tables/{llx_ticket.sql => llx_ticket-ticket.sql} (100%) rename htdocs/install/mysql/tables/{llx_ticket_extrafields.key.sql => llx_ticket_extrafields-ticket.key.sql} (100%) rename htdocs/install/mysql/tables/{llx_ticket_extrafields.sql => llx_ticket_extrafields-ticket.sql} (100%) diff --git a/htdocs/core/modules/modTicket.class.php b/htdocs/core/modules/modTicket.class.php index 01561b40b01..50922ed884e 100644 --- a/htdocs/core/modules/modTicket.class.php +++ b/htdocs/core/modules/modTicket.class.php @@ -320,6 +320,11 @@ class modTicket extends DolibarrModules { global $conf, $langs; + $result = $this->_load_tables('/install/mysql/tables/', 'ticket'); + if ($result < 0) { + return -1; // Do not activate module if error 'not allowed' returned when loading module SQL queries (the _load_table run sql with run_sql with the error allowed parameter set to 'default') + } + // Permissions $this->remove($options); diff --git a/htdocs/install/mysql/tables/llx_ticket.key.sql b/htdocs/install/mysql/tables/llx_ticket-ticket.key.sql similarity index 100% rename from htdocs/install/mysql/tables/llx_ticket.key.sql rename to htdocs/install/mysql/tables/llx_ticket-ticket.key.sql diff --git a/htdocs/install/mysql/tables/llx_ticket.sql b/htdocs/install/mysql/tables/llx_ticket-ticket.sql similarity index 100% rename from htdocs/install/mysql/tables/llx_ticket.sql rename to htdocs/install/mysql/tables/llx_ticket-ticket.sql diff --git a/htdocs/install/mysql/tables/llx_ticket_extrafields.key.sql b/htdocs/install/mysql/tables/llx_ticket_extrafields-ticket.key.sql similarity index 100% rename from htdocs/install/mysql/tables/llx_ticket_extrafields.key.sql rename to htdocs/install/mysql/tables/llx_ticket_extrafields-ticket.key.sql diff --git a/htdocs/install/mysql/tables/llx_ticket_extrafields.sql b/htdocs/install/mysql/tables/llx_ticket_extrafields-ticket.sql similarity index 100% rename from htdocs/install/mysql/tables/llx_ticket_extrafields.sql rename to htdocs/install/mysql/tables/llx_ticket_extrafields-ticket.sql From b393a1277fbd4c7c8661ed43008d928a343bab4a Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 17 Feb 2022 19:50:21 +0100 Subject: [PATCH 060/255] Update 14.0.0-15.0.0.sql --- htdocs/install/mysql/migration/14.0.0-15.0.0.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/install/mysql/migration/14.0.0-15.0.0.sql b/htdocs/install/mysql/migration/14.0.0-15.0.0.sql index 69d7c93af5f..b57d995c251 100644 --- a/htdocs/install/mysql/migration/14.0.0-15.0.0.sql +++ b/htdocs/install/mysql/migration/14.0.0-15.0.0.sql @@ -507,8 +507,8 @@ INSERT INTO llx_c_action_trigger (code,label,description,elementtype,rang) value INSERT INTO llx_c_action_trigger (code,label,description,elementtype,rang) values ('HOLIDAY_CANCEL','Holiday canceled','Executed when a holiday is canceled','holiday',802); INSERT INTO llx_c_action_trigger (code,label,description,elementtype,rang) values ('HOLIDAY_DELETE','Holiday deleted','Executed when a holiday is deleted','holiday',804); --- Delete old mexican legal forms -DELETE FROM llx_c_forme_juridique WHERE code IN ('15401', '15402', '15403', '15404', '15405', '15406'); +-- We do not delete old mexican legal forms because they may have been used. User will have to insert the new one manually not inserted because of conflict if he need them. +--DELETE FROM llx_c_forme_juridique WHERE code IN ('15401', '15402', '15403', '15404', '15405', '15406'); INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15401', '601 - General de Ley Personas Morales', 1); INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle, active) VALUES (154, '15402', '603 - Personas Morales con Fines no Lucrativos', 1); From 39bb854ef877d29e814a42b73899841e90851c0b Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 17 Feb 2022 19:57:45 +0100 Subject: [PATCH 061/255] Update ticket.php --- htdocs/admin/ticket.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/admin/ticket.php b/htdocs/admin/ticket.php index e6a6208324e..fc8a5e8e0b9 100644 --- a/htdocs/admin/ticket.php +++ b/htdocs/admin/ticket.php @@ -478,7 +478,7 @@ if (!$conf->use_javascript_ajax) { print ''; } -print load_fiche_titre($langs->trans("Workflow"), '', ''); +print load_fiche_titre($langs->trans("Other"), '', ''); print ''; print ''; From 21ebedc755df6fe81534bbde73d6d7ef49911e6c Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 17 Feb 2022 20:10:09 +0100 Subject: [PATCH 062/255] Fix trans --- htdocs/langs/en_US/ticket.lang | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/langs/en_US/ticket.lang b/htdocs/langs/en_US/ticket.lang index 222efad8ba2..38b199f7260 100644 --- a/htdocs/langs/en_US/ticket.lang +++ b/htdocs/langs/en_US/ticket.lang @@ -136,8 +136,8 @@ TicketsPublicNotificationNewMessage=Send email(s) when a new message/comment is TicketsPublicNotificationNewMessageHelp=Send email(s) when a new message is added from public interface (to assigned user or the notifications email to (update) and/or the notifications email to) TicketPublicNotificationNewMessageDefaultEmail=Notifications email to (update) TicketPublicNotificationNewMessageDefaultEmailHelp=Send an email to this address for each new message notifications if the ticket doesn't have a user assigned to it or if the user doesn't have any known email. -TicketsAutoReadTicket=Automatically mark the ticket as read -TicketsAutoReadTicketHelp=Automatically mark the ticket as read when created from backoffice. +TicketsAutoReadTicket=Automatically mark the ticket as read (when created from backoffice) +TicketsAutoReadTicketHelp=Automatically mark the ticket as read when created from backoffice. When ticket is create from the public interface, ticket remains with the status "Not Read". # # Index & list page From 4fb651817ed2d8429f5c4b9711de253b4c6d40c9 Mon Sep 17 00:00:00 2001 From: UT from dolibit <45215329+dolibit-ut@users.noreply.github.com> Date: Thu, 17 Feb 2022 20:27:19 +0100 Subject: [PATCH 063/255] Update README http://pad.asp-software.org/padgen.php --- build/pad/README | 1 + 1 file changed, 1 insertion(+) diff --git a/build/pad/README b/build/pad/README index 3cbc171686c..241d27d01c2 100644 --- a/build/pad/README +++ b/build/pad/README @@ -1,6 +1,7 @@ README (English) ################################################## Building PAD files +http://pad.asp-software.org/padgen.php ################################################## This directory contains files and docs used to build From 3ad95d55a5beb4718afa5d0471f31c64e773fa8d Mon Sep 17 00:00:00 2001 From: UT from dolibit <45215329+dolibit-ut@users.noreply.github.com> Date: Thu, 17 Feb 2022 20:36:07 +0100 Subject: [PATCH 064/255] Update dolibarr.pl return ( "14.0.5", "13.0.5", "12.0.5", "11.0.5", "10.0.7", "9.0.4", "8.0.6", "7.0.5" ); $ver >= 14.0 ? "dolibarr\\-(12\\.0\\.[0-9\\.]+)\\.tgz" : $ver >= 13.0 ? "dolibarr\\-(12\\.0\\.[0-9\\.]+)\\.tgz" : --- build/perl/virtualmin/dolibarr.pl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build/perl/virtualmin/dolibarr.pl b/build/perl/virtualmin/dolibarr.pl index 8b6a9888db0..b5bacf59356 100644 --- a/build/perl/virtualmin/dolibarr.pl +++ b/build/perl/virtualmin/dolibarr.pl @@ -30,7 +30,7 @@ return "Regis Houssin"; # script_dolibarr_versions() sub script_dolibarr_versions { -return ( "12.0.3", "11.0.5", "10.0.7", "9.0.4", "8.0.6", "7.0.5" ); +return ( "14.0.5", "13.0.5", "12.0.5", "11.0.5", "10.0.7", "9.0.4", "8.0.6", "7.0.5" ); } sub script_dolibarr_release @@ -400,6 +400,8 @@ sub script_dolibarr_check_latest { local ($ver) = @_; local @vers = &osdn_package_versions("dolibarr", + $ver >= 14.0 ? "dolibarr\\-(12\\.0\\.[0-9\\.]+)\\.tgz" : + $ver >= 13.0 ? "dolibarr\\-(12\\.0\\.[0-9\\.]+)\\.tgz" : $ver >= 12.0 ? "dolibarr\\-(12\\.0\\.[0-9\\.]+)\\.tgz" : $ver >= 11.0 ? "dolibarr\\-(11\\.0\\.[0-9\\.]+)\\.tgz" : $ver >= 10.0 ? "dolibarr\\-(10\\.0\\.[0-9\\.]+)\\.tgz" : From b013c9a15f7d6e2266fc41d2c542b421e2830aba Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 17 Feb 2022 20:37:39 +0100 Subject: [PATCH 065/255] Fix duplicate div --- htdocs/core/lib/functions.lib.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 9fed70a1fe1..7be3f5e3351 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -2011,7 +2011,6 @@ function dol_banner_tab($object, $paramid, $morehtml = '', $shownav = 1, $fieldi } if (empty($phototoshow)) { // Show No photo link (picto of object) - $morehtmlleft .= '
    '; if ($object->element == 'action') { $width = 80; $cssclass = 'photorefcenter'; @@ -2029,8 +2028,6 @@ function dol_banner_tab($object, $paramid, $morehtml = '', $shownav = 1, $fieldi $morehtmlleft .= '
    '; $morehtmlleft .= $nophoto; $morehtmlleft .= '
    '; - - $morehtmlleft .= '
    '; } } } From 9fd34b264fd20808ed136e11e2b96b8a5e9709e1 Mon Sep 17 00:00:00 2001 From: UT from dolibit <45215329+dolibit-ut@users.noreply.github.com> Date: Thu, 17 Feb 2022 21:05:23 +0100 Subject: [PATCH 066/255] Update README https://doxygen.dolibarr.org/ --- dev/examples/code/README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/examples/code/README b/dev/examples/code/README index b7c31558de5..bf3dd3f4969 100644 --- a/dev/examples/code/README +++ b/dev/examples/code/README @@ -5,4 +5,4 @@ This directory contains samples of code to use Dolibarr business classes to buil external interfaces that need to read/update data from/into Dolibarr. You can also have a look at the Dolibarr doxygen doc that describes all files and classes: -http://www.dolibarr.org/html_doxygen/index.html +https://doxygen.dolibarr.org/ From b01fbba039311d15eeca3e961bf0d5bbfc724a7c Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 17 Feb 2022 23:41:31 +0100 Subject: [PATCH 067/255] Fix packages --- build/rpm/dolibarr_fedora.spec | 1 - build/rpm/dolibarr_generic.spec | 1 - build/rpm/dolibarr_mandriva.spec | 1 - build/rpm/dolibarr_opensuse.spec | 1 - 4 files changed, 4 deletions(-) diff --git a/build/rpm/dolibarr_fedora.spec b/build/rpm/dolibarr_fedora.spec index dc23cff5486..27130244d00 100755 --- a/build/rpm/dolibarr_fedora.spec +++ b/build/rpm/dolibarr_fedora.spec @@ -166,7 +166,6 @@ done >>%{name}.lang %_datadir/dolibarr/htdocs/blockedlog %_datadir/dolibarr/htdocs/bookmarks %_datadir/dolibarr/htdocs/bom -%_datadir/dolibarr/htdocs/cashdesk %_datadir/dolibarr/htdocs/categories %_datadir/dolibarr/htdocs/collab %_datadir/dolibarr/htdocs/comm diff --git a/build/rpm/dolibarr_generic.spec b/build/rpm/dolibarr_generic.spec index a446a7bd5d6..aeddd5526f8 100755 --- a/build/rpm/dolibarr_generic.spec +++ b/build/rpm/dolibarr_generic.spec @@ -247,7 +247,6 @@ done >>%{name}.lang %_datadir/dolibarr/htdocs/blockedlog %_datadir/dolibarr/htdocs/bookmarks %_datadir/dolibarr/htdocs/bom -%_datadir/dolibarr/htdocs/cashdesk %_datadir/dolibarr/htdocs/categories %_datadir/dolibarr/htdocs/collab %_datadir/dolibarr/htdocs/comm diff --git a/build/rpm/dolibarr_mandriva.spec b/build/rpm/dolibarr_mandriva.spec index 78d90080258..a1e4dffc781 100755 --- a/build/rpm/dolibarr_mandriva.spec +++ b/build/rpm/dolibarr_mandriva.spec @@ -163,7 +163,6 @@ done >>%{name}.lang %_datadir/dolibarr/htdocs/blockedlog %_datadir/dolibarr/htdocs/bookmarks %_datadir/dolibarr/htdocs/bom -%_datadir/dolibarr/htdocs/cashdesk %_datadir/dolibarr/htdocs/categories %_datadir/dolibarr/htdocs/collab %_datadir/dolibarr/htdocs/comm diff --git a/build/rpm/dolibarr_opensuse.spec b/build/rpm/dolibarr_opensuse.spec index edae0126653..aed2d76ed29 100755 --- a/build/rpm/dolibarr_opensuse.spec +++ b/build/rpm/dolibarr_opensuse.spec @@ -174,7 +174,6 @@ done >>%{name}.lang %_datadir/dolibarr/htdocs/blockedlog %_datadir/dolibarr/htdocs/bookmarks %_datadir/dolibarr/htdocs/bom -%_datadir/dolibarr/htdocs/cashdesk %_datadir/dolibarr/htdocs/categories %_datadir/dolibarr/htdocs/collab %_datadir/dolibarr/htdocs/comm From c32cc660a364617c2cac6412e270d70d80952530 Mon Sep 17 00:00:00 2001 From: Henry Date: Fri, 18 Feb 2022 08:16:56 +0800 Subject: [PATCH 068/255] Update list.php --- htdocs/fourn/commande/list.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/htdocs/fourn/commande/list.php b/htdocs/fourn/commande/list.php index eb13ead4fbd..72fc7a7439c 100644 --- a/htdocs/fourn/commande/list.php +++ b/htdocs/fourn/commande/list.php @@ -1274,9 +1274,7 @@ if ($resql) { $projectstatic = new Project($db); $i = 0; - $totalarray = array(); - $totalarray['nbfield'] = 0; - $totalarray['val'] = array(); + $totalarray = array('nbfield' => 0, 'val' => array(), 'pos' => array()); $totalarray['val']['cf.total_ht'] = 0; $totalarray['val']['cf.total_ttc'] = 0; while ($i < min($num, $limit)) { From 7a457478d5fe213596bdd784d0c936a785abd82b Mon Sep 17 00:00:00 2001 From: Maxime Kohlhaas Date: Fri, 18 Feb 2022 08:23:12 +0100 Subject: [PATCH 069/255] Fix : add missing formobjectoptions hook on 3 cards --- htdocs/compta/prelevement/card.php | 9 ++++++++- htdocs/loan/card.php | 5 +++++ htdocs/opensurvey/card.php | 8 ++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/htdocs/compta/prelevement/card.php b/htdocs/compta/prelevement/card.php index d4311abe112..a076299b4cd 100644 --- a/htdocs/compta/prelevement/card.php +++ b/htdocs/compta/prelevement/card.php @@ -238,7 +238,14 @@ if ($id > 0 || $ref) { $modulepart = 'paymentbybanktransfer'; } print ''.$relativepath.''; - 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; + + print ''; print '
    '; diff --git a/htdocs/loan/card.php b/htdocs/loan/card.php index 88701e35166..4bc539c1ff0 100644 --- a/htdocs/loan/card.php +++ b/htdocs/loan/card.php @@ -618,6 +618,11 @@ if ($id > 0) { } 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; + print ''; print ''; diff --git a/htdocs/opensurvey/card.php b/htdocs/opensurvey/card.php index 773571b7b1c..3f822679350 100644 --- a/htdocs/opensurvey/card.php +++ b/htdocs/opensurvey/card.php @@ -54,6 +54,9 @@ if ($result <= 0) { exit; } +// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context +$hookmanager->initHooks(array('surveycard', 'globalcard')); + $expiredate = dol_mktime(0, 0, 0, GETPOST('expiremonth'), GETPOST('expireday'), GETPOST('expireyear')); @@ -338,6 +341,11 @@ if ($action != 'edit') { 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; + print ''; print ''; From 3f109aa911e50c9f2f0257fc02131ed3d773863a Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Fri, 18 Feb 2022 09:24:12 +0100 Subject: [PATCH 070/255] FIX Accountancy - On manual transaction with multicompany - Function transformTransaction can validate & delete transaction of an other entity --- .../accountancy/class/bookkeeping.class.php | 44 ++++++++++--------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/htdocs/accountancy/class/bookkeeping.class.php b/htdocs/accountancy/class/bookkeeping.class.php index 43dcce8c646..5635df3c8e7 100644 --- a/htdocs/accountancy/class/bookkeeping.class.php +++ b/htdocs/accountancy/class/bookkeeping.class.php @@ -331,7 +331,7 @@ class BookKeeping extends CommonObject if (empty($this->piece_num)) { $sqlnum = "SELECT MAX(piece_num)+1 as maxpiecenum"; $sqlnum .= " FROM ".MAIN_DB_PREFIX.$this->table_element; - $sqlnum .= " WHERE entity = ".$conf->entity; // Do not use getEntity for accounting features + $sqlnum .= " WHERE entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features $resqlnum = $this->db->query($sqlnum); if ($resqlnum) { @@ -736,7 +736,7 @@ class BookKeeping extends CommonObject $sql .= " t.date_validated as date_validation"; $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.$mode.' as t'; $sql .= ' WHERE 1 = 1'; - $sql .= " AND entity IN (".getEntity('accountancy').")"; + $sql .= " AND entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features if (null !== $ref) { $sql .= " AND t.ref = '".$this->db->escape($ref)."'"; } else { @@ -881,7 +881,7 @@ class BookKeeping extends CommonObject } $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t'; $sql .= ' WHERE 1 = 1'; - $sql .= " AND entity IN (".getEntity('accountancy').")"; + $sql .= " AND entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features if (count($sqlwhere) > 0) { $sql .= ' AND '.implode(' '.$filtermode.' ', $sqlwhere); } @@ -1037,7 +1037,7 @@ class BookKeeping extends CommonObject } } } - $sql .= ' WHERE t.entity IN ('.getEntity('accountancy').')'; + $sql .= ' WHERE t.entity = ' . ((int) $conf->entity); // Do not use getEntity for accounting features if ($showAlreadyExportMovements == 0) { $sql .= " AND t.date_export IS NULL"; } @@ -1157,7 +1157,7 @@ class BookKeeping extends CommonObject } } } - $sql .= ' WHERE entity IN ('.getEntity('accountancy').')'; + $sql .= ' WHERE entity = ' . ((int) $conf->entity); // Do not use getEntity for accounting features if (count($sqlwhere) > 0) { $sql .= ' AND '.implode(' '.$filtermode.' ', $sqlwhere); } @@ -1454,7 +1454,7 @@ class BookKeeping extends CommonObject */ public function deleteByYearAndJournal($delyear = 0, $journal = '', $mode = '', $delmonth = 0) { - global $langs; + global $conf, $langs; if (empty($delyear) && empty($journal)) { $this->error = 'ErrorOneFieldRequired'; @@ -1475,7 +1475,7 @@ class BookKeeping extends CommonObject if (!empty($journal)) { $sql .= " AND code_journal = '".$this->db->escape($journal)."'"; } - $sql .= " AND entity IN (".getEntity('accountancy').")"; + $sql .= " AND entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features // Exclusion of validated entries at the time of deletion $sql .= " AND date_validated IS NULL"; @@ -1514,7 +1514,7 @@ class BookKeeping extends CommonObject $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element; $sql .= " WHERE piece_num = ".(int) $piecenum; $sql .= " AND date_validated IS NULL"; // For security, exclusion of validated entries at the time of deletion - $sql .= " AND entity IN (".getEntity('accountancy').")"; + $sql .= " AND entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features $resql = $this->db->query($sql); @@ -1636,7 +1636,7 @@ class BookKeeping extends CommonObject } $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element.$mode; $sql .= " WHERE piece_num = ".$piecenum; - $sql .= " AND entity IN (".getEntity('accountancy').")"; + $sql .= " AND entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features dol_syslog(__METHOD__, LOG_DEBUG); $result = $this->db->query($sql); @@ -1674,9 +1674,9 @@ class BookKeeping extends CommonObject global $conf; $sql = "SELECT MAX(piece_num)+1 as max FROM ".MAIN_DB_PREFIX.$this->table_element.$mode; - $sql .= " WHERE entity IN (".getEntity('accountancy').")"; + $sql .= " WHERE entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features - dol_syslog(get_class($this)."getNextNumMvt sql=".$sql, LOG_DEBUG); + dol_syslog(get_class($this)."::getNextNumMvt sql=".$sql, LOG_DEBUG); $result = $this->db->query($sql); if ($result) { @@ -1717,7 +1717,7 @@ class BookKeeping extends CommonObject } $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element.$mode; $sql .= " WHERE piece_num = ".$piecenum; - $sql .= " AND entity IN (".getEntity('accountancy').")"; + $sql .= " AND entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features dol_syslog(__METHOD__, LOG_DEBUG); $result = $this->db->query($sql); @@ -1780,7 +1780,7 @@ class BookKeeping extends CommonObject $sql .= " montant as amount, sens, fk_user_author, import_key, code_journal, piece_num,"; $sql .= " date_validated as date_validation"; $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element; - $sql .= " WHERE entity IN (".getEntity('accountancy').")"; + $sql .= " WHERE entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features dol_syslog(get_class($this)."::export_bookkeeping", LOG_DEBUG); @@ -1836,6 +1836,8 @@ class BookKeeping extends CommonObject */ public function transformTransaction($direction = 0, $piece_num = '') { + global $conf; + $error = 0; $this->db->begin(); @@ -1855,14 +1857,14 @@ class BookKeeping extends CommonObject $sql .= ' doc_ref, fk_doc, fk_docdet, entity, thirdparty_code, subledger_account, subledger_label,'; $sql .= ' numero_compte, label_compte, label_operation, debit, credit,'; $sql .= ' montant, sens, fk_user_author, import_key, code_journal, journal_label, '.$next_piecenum.", '".$this->db->idate($now)."'"; - $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.'_tmp WHERE piece_num = '.((int) $piece_num); + $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.'_tmp WHERE piece_num = '.((int) $piece_num).' AND entity = ' .((int) $conf->entity); $resql = $this->db->query($sql); if (!$resql) { $error++; $this->errors[] = 'Error '.$this->db->lasterror(); dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR); } - $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.'_tmp WHERE piece_num = '.((int) $piece_num); + $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.'_tmp WHERE piece_num = '.((int) $piece_num).' AND entity = ' .((int) $conf->entity); $resql = $this->db->query($sql); if (!$resql) { $error++; @@ -1870,7 +1872,7 @@ class BookKeeping extends CommonObject dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR); } } elseif ($direction == 1) { - $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.'_tmp WHERE piece_num = '.((int) $piece_num); + $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.'_tmp WHERE piece_num = '.((int) $piece_num).' AND entity = ' .((int) $conf->entity); $resql = $this->db->query($sql); if (!$resql) { $error++; @@ -1885,14 +1887,14 @@ class BookKeeping extends CommonObject $sql .= ' doc_ref, fk_doc, fk_docdet, thirdparty_code, subledger_account, subledger_label,'; $sql .= ' numero_compte, label_compte, label_operation, debit, credit,'; $sql .= ' montant, sens, fk_user_author, import_key, code_journal, journal_label, piece_num'; - $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' WHERE piece_num = '.((int) $piece_num); + $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' WHERE piece_num = '.((int) $piece_num).' AND entity = ' .((int) $conf->entity); $resql = $this->db->query($sql); if (!$resql) { $error++; $this->errors[] = 'Error '.$this->db->lasterror(); dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR); } - $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.'_tmp WHERE piece_num = '.((int) $piece_num); + $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.'_tmp WHERE piece_num = '.((int) $piece_num).' AND entity = ' .((int) $conf->entity); $resql = $this->db->query($sql); if (!$resql) { $error++; @@ -1947,7 +1949,7 @@ class BookKeeping extends CommonObject $sql .= " AND aa.active = 1"; $sql .= " INNER JOIN ".MAIN_DB_PREFIX."accounting_system as asy ON aa.fk_pcg_version = asy.pcg_version"; $sql .= " AND asy.rowid = ".((int) $pcgver); - $sql .= " AND ab.entity IN (".getEntity('accountancy').")"; + $sql .= " AND ab.entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features $sql .= " ORDER BY account_number ASC"; dol_syslog(get_class($this)."::select_account", LOG_DEBUG); @@ -2011,7 +2013,7 @@ class BookKeeping extends CommonObject $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."accounting_account as parent ON aa.account_parent = parent.rowid AND parent.active = 1"; $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."accounting_account as root ON parent.account_parent = root.rowid AND root.active = 1"; $sql .= " WHERE aa.account_number = '".$this->db->escape($account)."'"; - $sql .= " AND aa.entity IN (".getEntity('accountancy').")"; + $sql .= " AND aa.entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features dol_syslog(get_class($this)."::select_account sql=".$sql, LOG_DEBUG); $resql = $this->db->query($sql); @@ -2051,7 +2053,7 @@ class BookKeeping extends CommonObject $sql .= " AND asy.rowid = ".((int) $pcgver); $sql .= " AND aa.active = 1"; $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_accounting_category as cat ON aa.fk_accounting_category = cat.rowid"; - $sql .= " WHERE aa.entity IN (".getEntity('accountancy').")"; + $sql .= " WHERE aa.entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features dol_syslog(get_class($this)."::select_account sql=".$sql, LOG_DEBUG); $resql = $this->db->query($sql); From 12c825ba84e4402b0ae329064db182423ed2cadc Mon Sep 17 00:00:00 2001 From: atm-greg Date: Fri, 18 Feb 2022 10:50:00 +0100 Subject: [PATCH 071/255] fix rounding for price and display currency --- htdocs/core/class/extrafields.class.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/htdocs/core/class/extrafields.class.php b/htdocs/core/class/extrafields.class.php index f8e5726d344..c0dc9c6a96f 100644 --- a/htdocs/core/class/extrafields.class.php +++ b/htdocs/core/class/extrafields.class.php @@ -1679,7 +1679,8 @@ class ExtraFields } elseif ($type == 'price') { //$value = price($value, 0, $langs, 0, 0, -1, $conf->currency); if ($value || $value == '0') { - $value = price($value, 0, $langs, 0, 0, -1); + $value = price($value, 0, $langs, 0, $conf->global->MAIN_MAX_DECIMALS_TOT, -1).' '.$langs->getCurrencySymbol($conf->currency); + } } elseif ($type == 'select') { $valstr = (!empty($param['options'][$value]) ? $param['options'][$value] : ''); From b5afa2777422e3ee8b207b79f9592925f9d89ce4 Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Fri, 18 Feb 2022 10:09:38 +0000 Subject: [PATCH 072/255] Fixing style errors. --- htdocs/core/class/extrafields.class.php | 1 - 1 file changed, 1 deletion(-) diff --git a/htdocs/core/class/extrafields.class.php b/htdocs/core/class/extrafields.class.php index c0dc9c6a96f..7a449f3e7ea 100644 --- a/htdocs/core/class/extrafields.class.php +++ b/htdocs/core/class/extrafields.class.php @@ -1680,7 +1680,6 @@ class ExtraFields //$value = price($value, 0, $langs, 0, 0, -1, $conf->currency); if ($value || $value == '0') { $value = price($value, 0, $langs, 0, $conf->global->MAIN_MAX_DECIMALS_TOT, -1).' '.$langs->getCurrencySymbol($conf->currency); - } } elseif ($type == 'select') { $valstr = (!empty($param['options'][$value]) ? $param['options'][$value] : ''); From aec2579c41b23213ed427fb99188fb695e771df3 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 18 Feb 2022 12:22:53 +0100 Subject: [PATCH 073/255] Clean code --- htdocs/projet/admin/website.php | 27 ------------- htdocs/recruitment/admin/public_interface.php | 38 ------------------- 2 files changed, 65 deletions(-) diff --git a/htdocs/projet/admin/website.php b/htdocs/projet/admin/website.php index 1af6b72c196..25497fef436 100644 --- a/htdocs/projet/admin/website.php +++ b/htdocs/projet/admin/website.php @@ -111,33 +111,6 @@ if (empty($conf->global->PROJECT_ENABLE_PUBLIC)) { print $enabledisablehtml; print ''; -/* -print '
    '; - -if (!empty($conf->global->PROJECT_ENABLE_PUBLIC)) { - print '
    '; - - print ''; - - print ''; - print ''; - print ''; - print "\n"; - - // param - print '\n"; - - print '
    '.$langs->trans("Parameter").''.$langs->trans("Value").'
    '; - print $langs->trans("CanEditAmount"); - print ''; - print $form->selectyesno("MEMBER_NEWFORM_EDITAMOUNT", (!empty($conf->global->MEMBER_NEWFORM_EDITAMOUNT) ? $conf->global->MEMBER_NEWFORM_EDITAMOUNT : 0), 1); - print "
    '; - - print '
    '; - print ''; - print '
    '; -} -*/ print dol_get_fiche_end(); diff --git a/htdocs/recruitment/admin/public_interface.php b/htdocs/recruitment/admin/public_interface.php index 3d431d026bc..b091cdea7a0 100644 --- a/htdocs/recruitment/admin/public_interface.php +++ b/htdocs/recruitment/admin/public_interface.php @@ -126,44 +126,6 @@ if (!empty($conf->global->RECRUITMENT_ENABLE_PUBLIC_INTERFACE)) { print ''.$langs->trans("Value").''; print "\n"; - // Force Type - $adht = new AdherentType($db); - print ''; - print $langs->trans("ForceMemberType"); - print ''; - $listofval = array(); - $listofval += $adht->liste_array(); - $forcetype = $conf->global->MEMBER_NEWFORM_FORCETYPE ?: -1; - print $form->selectarray("MEMBER_NEWFORM_FORCETYPE", $listofval, $forcetype, count($listofval) > 1 ? 1 : 0); - print "\n"; - - // Amount - print ''; - print $langs->trans("DefaultAmount"); - print ''; - print ''; - print "\n"; - - // Can edit - print ''; - print $langs->trans("CanEditAmount"); - print ''; - print $form->selectyesno("MEMBER_NEWFORM_EDITAMOUNT", (!empty($conf->global->MEMBER_NEWFORM_EDITAMOUNT) ? $conf->global->MEMBER_NEWFORM_EDITAMOUNT : 0), 1); - print "\n"; - - // Jump to an online payment page - print ''; - print $langs->trans("MEMBER_NEWFORM_PAYONLINE"); - print ''; - $listofval = array(); - $listofval['-1'] = $langs->trans('No'); - $listofval['all'] = $langs->trans('Yes').' ('.$langs->trans("VisitorCanChooseItsPaymentMode").')'; - if (!empty($conf->paybox->enabled)) $listofval['paybox'] = 'Paybox'; - if (!empty($conf->paypal->enabled)) $listofval['paypal'] = 'PayPal'; - if (!empty($conf->stripe->enabled)) $listofval['stripe'] = 'Stripe'; - print $form->selectarray("MEMBER_NEWFORM_PAYONLINE", $listofval, (!empty($conf->global->MEMBER_NEWFORM_PAYONLINE) ? $conf->global->MEMBER_NEWFORM_PAYONLINE : ''), 0); - print "\n"; - print ''; print '
    '; From 3ab2308124757a12ef70f459e7d723708baefc86 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 18 Feb 2022 12:36:05 +0100 Subject: [PATCH 074/255] Clean code --- htdocs/public/eventorganization/attendee_new.php | 10 ---------- htdocs/public/members/new.php | 1 + htdocs/public/payment/newpayment.php | 8 ++++---- htdocs/public/payment/paymentok.php | 13 ++++++++++++- htdocs/public/project/suggestbooth.php | 10 ---------- htdocs/public/project/suggestconference.php | 10 ---------- 6 files changed, 17 insertions(+), 35 deletions(-) diff --git a/htdocs/public/eventorganization/attendee_new.php b/htdocs/public/eventorganization/attendee_new.php index b350ece39f4..55303bcb00e 100644 --- a/htdocs/public/eventorganization/attendee_new.php +++ b/htdocs/public/eventorganization/attendee_new.php @@ -19,16 +19,6 @@ * \file htdocs/public/eventorganization/attendee_new.php * \ingroup project * \brief Example of form to subscribe to an event - * - * Note that you can add following constant to change behaviour of page - * MEMBER_NEWFORM_AMOUNT Default amount for auto-subscribe form - * MEMBER_NEWFORM_EDITAMOUNT 0 or 1 = Amount can be edited - * MEMBER_NEWFORM_PAYONLINE Suggest payment with paypal, paybox or stripe - * MEMBER_NEWFORM_DOLIBARRTURNOVER Show field turnover (specific for dolibarr foundation) - * MEMBER_URL_REDIRECT_SUBSCRIPTION Url to redirect once subscribe submitted - * MEMBER_NEWFORM_FORCETYPE Force type of member - * MEMBER_NEWFORM_FORCEMORPHY Force nature of member (mor/phy) - * MEMBER_NEWFORM_FORCECOUNTRYCODE Force country */ if (!defined('NOLOGIN')) { diff --git a/htdocs/public/members/new.php b/htdocs/public/members/new.php index 6589f2a17d0..055ffec56f9 100644 --- a/htdocs/public/members/new.php +++ b/htdocs/public/members/new.php @@ -30,6 +30,7 @@ * Note that you can add following constant to change behaviour of page * MEMBER_NEWFORM_AMOUNT Default amount for auto-subscribe form * MEMBER_NEWFORM_EDITAMOUNT 0 or 1 = Amount can be edited + * MEMBER_MIN_AMOUNT Minimum amount * MEMBER_NEWFORM_PAYONLINE Suggest payment with paypal, paybox or stripe * MEMBER_NEWFORM_DOLIBARRTURNOVER Show field turnover (specific for dolibarr foundation) * MEMBER_URL_REDIRECT_SUBSCRIPTION Url to redirect once subscribe submitted diff --git a/htdocs/public/payment/newpayment.php b/htdocs/public/payment/newpayment.php index 5158e294fb2..d25e14288f8 100644 --- a/htdocs/public/payment/newpayment.php +++ b/htdocs/public/payment/newpayment.php @@ -481,7 +481,7 @@ if ($action == 'dopayment') { // Called when choosing Stripe mode. -// When using the Charge API architecture, this code is called after clicking the 'dopayment' with the Charge API architecture. +// When using the old Charge API architecture, this code is called after clicking the 'dopayment' with the Charge API architecture. // When using the PaymentIntent API architecture, the Stripe customer was already created when creating PaymentIntent when showing payment page, and the payment is already ok when action=charge. if ($action == 'charge' && !empty($conf->stripe->enabled)) { $amountstripe = $amount; @@ -728,7 +728,7 @@ if ($action == 'charge' && !empty($conf->stripe->enabled)) { } } - // When using the PaymentIntent API architecture + // When using the PaymentIntent API architecture (mode set on by default into conf.class.php) if (!empty($conf->global->STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION)) { $service = 'StripeTest'; $servicestatus = 0; @@ -793,8 +793,8 @@ if ($action == 'charge' && !empty($conf->stripe->enabled)) { $remoteip = getUserRemoteIP(); $_SESSION["onlinetoken"] = $stripeToken; - $_SESSION["FinalPaymentAmt"] = $amount; - $_SESSION["currencyCodeType"] = $currency; + $_SESSION["FinalPaymentAmt"] = $amount; // amount really paid (coming from Stripe). Will be used for check in paymentok.php. + $_SESSION["currencyCodeType"] = $currency; // currency really used for payment (coming from Stripe). Will be used for check in paymentok.php. $_SESSION["paymentType"] = ''; $_SESSION['ipaddress'] = ($remoteip ? $remoteip : 'unknown'); // Payer ip $_SESSION['payerID'] = is_object($customer) ? $customer->id : ''; diff --git a/htdocs/public/payment/paymentok.php b/htdocs/public/payment/paymentok.php index c822bfcdf96..ea86f28a894 100644 --- a/htdocs/public/payment/paymentok.php +++ b/htdocs/public/payment/paymentok.php @@ -417,7 +417,7 @@ if ($ispaymentok) { // Do action only if $FinalPaymentAmt is set (session variable is cleaned after this page to avoid duplicate actions when page is POST a second time) if (!empty($FinalPaymentAmt) && $paymentTypeId > 0) { // Security protection: - if (empty($conf->global->MEMBER_NEWFORM_EDITAMOUNT)) { // If we didn't allow members to choose their membership amount + if (empty($conf->global->MEMBER_NEWFORM_EDITAMOUNT)) { // If we didn't allow members to choose their membership amount (if free amount is allowed, no need to check) if ($object->status == $object::STATUS_DRAFT) { // If the member is not yet validated, we check that the amount is the same as expected. $typeid = $object->typeid; @@ -440,6 +440,17 @@ if ($ispaymentok) { } } + // Security protection: + if (!empty($conf->global->MEMBER_MIN_AMOUNT)) { + if ($FinalPaymentAmt < $conf->global->MEMBER_MIN_AMOUNT) { + $error++; + $errmsg = 'Value of FinalPayment ('.$FinalPaymentAmt.') is lower than the minimum allowed ('.$conf->global->MEMBER_MIN_AMOUNT.'). May be a hack to try to pay a different amount ?'; + $postactionmessages[] = $errmsg; + $ispostactionok = -1; + dol_syslog("Failed to validate member (amount lower than minimum): ".$errmsg, LOG_ERR, 0, '_payment'); + } + } + // Security protection: if ($currencyCodeType && $currencyCodeType != $conf->currency) { // Check that currency is the good one $error++; diff --git a/htdocs/public/project/suggestbooth.php b/htdocs/public/project/suggestbooth.php index c0bcdc751c6..39c2a57700e 100644 --- a/htdocs/public/project/suggestbooth.php +++ b/htdocs/public/project/suggestbooth.php @@ -19,16 +19,6 @@ * \file htdocs/public/project/suggestbooth.php * \ingroup member * \brief Example of form to suggest a booth - * - * Note that you can add following constant to change behaviour of page - * MEMBER_NEWFORM_AMOUNT Default amount for auto-subscribe form - * MEMBER_NEWFORM_EDITAMOUNT 0 or 1 = Amount can be edited - * MEMBER_NEWFORM_PAYONLINE Suggest payment with paypal, paybox or stripe - * MEMBER_NEWFORM_DOLIBARRTURNOVER Show field turnover (specific for dolibarr foundation) - * MEMBER_URL_REDIRECT_SUBSCRIPTION Url to redirect once subscribe submitted - * MEMBER_NEWFORM_FORCETYPE Force type of member - * MEMBER_NEWFORM_FORCEMORPHY Force nature of member (mor/phy) - * MEMBER_NEWFORM_FORCECOUNTRYCODE Force country */ if (!defined('NOLOGIN')) { diff --git a/htdocs/public/project/suggestconference.php b/htdocs/public/project/suggestconference.php index f2a919c0aa2..b97777c3a9a 100644 --- a/htdocs/public/project/suggestconference.php +++ b/htdocs/public/project/suggestconference.php @@ -19,16 +19,6 @@ * \file htdocs/public/project/suggestconference.php * \ingroup member * \brief Example of form to suggest a conference - * - * Note that you can add following constant to change behaviour of page - * MEMBER_NEWFORM_AMOUNT Default amount for auto-subscribe form - * MEMBER_NEWFORM_EDITAMOUNT 0 or 1 = Amount can be edited - * MEMBER_NEWFORM_PAYONLINE Suggest payment with paypal, paybox or stripe - * MEMBER_NEWFORM_DOLIBARRTURNOVER Show field turnover (specific for dolibarr foundation) - * MEMBER_URL_REDIRECT_SUBSCRIPTION Url to redirect once subscribe submitted - * MEMBER_NEWFORM_FORCETYPE Force type of member - * MEMBER_NEWFORM_FORCEMORPHY Force nature of member (mor/phy) - * MEMBER_NEWFORM_FORCECOUNTRYCODE Force country */ if (!defined('NOLOGIN')) { From 8a0ee772d3d722f446f9fa253805934426b638c3 Mon Sep 17 00:00:00 2001 From: UT from dolibit <45215329+dolibit-ut@users.noreply.github.com> Date: Fri, 18 Feb 2022 13:10:38 +0100 Subject: [PATCH 075/255] add GitHub INSERT INTO llx_c_socialnetworks (entity, code, label, url, icon, active) VALUES ( 1, 'github', 'GitHub', 'https://www.github.com/{socialid}', '', 0); --- htdocs/install/mysql/data/llx_c_socialnetworks.sql | 1 + 1 file changed, 1 insertion(+) diff --git a/htdocs/install/mysql/data/llx_c_socialnetworks.sql b/htdocs/install/mysql/data/llx_c_socialnetworks.sql index 5bfbcf090d9..468086291fc 100644 --- a/htdocs/install/mysql/data/llx_c_socialnetworks.sql +++ b/htdocs/install/mysql/data/llx_c_socialnetworks.sql @@ -36,6 +36,7 @@ INSERT INTO llx_c_socialnetworks (entity, code, label, url, icon, active) VALUES INSERT INTO llx_c_socialnetworks (entity, code, label, url, icon, active) VALUES ( 1, 'flickr', 'Flickr', '{socialid}', 'fa-flickr', 0); INSERT INTO llx_c_socialnetworks (entity, code, label, url, icon, active) VALUES ( 1, 'gifycat', 'Gificat', '{socialid}', '', 0); INSERT INTO llx_c_socialnetworks (entity, code, label, url, icon, active) VALUES ( 1, 'giphy', 'Giphy', '{socialid}', '', 0); +INSERT INTO llx_c_socialnetworks (entity, code, label, url, icon, active) VALUES ( 1, 'github', 'GitHub', 'https://www.github.com/{socialid}', '', 0); INSERT INTO llx_c_socialnetworks (entity, code, label, url, icon, active) VALUES ( 1, 'googleplus', 'GooglePlus', 'https://www.googleplus.com/{socialid}', 'fa-google-plus-g', 0); INSERT INTO llx_c_socialnetworks (entity, code, label, url, icon, active) VALUES ( 1, 'instagram', 'Instagram', 'https://www.instagram.com/{socialid}', 'fa-instagram', 1); INSERT INTO llx_c_socialnetworks (entity, code, label, url, icon, active) VALUES ( 1, 'linkedin', 'LinkedIn', 'https://www.linkedin.com/{socialid}', 'fa-linkedin', 1); From dee5d8f9e865a051617c23162b75bd6174fad059 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 18 Feb 2022 13:45:28 +0100 Subject: [PATCH 076/255] Standardize name of button --- .../core/modules/barcode/mod_barcode_product_standard.php | 2 +- htdocs/core/modules/bom/doc/doc_generic_bom_odt.modules.php | 2 +- .../modules/commande/doc/doc_generic_order_odt.modules.php | 2 +- .../expedition/doc/doc_generic_shipment_odt.modules.php | 2 +- .../modules/facture/doc/doc_generic_invoice_odt.modules.php | 2 +- .../modules/member/doc/doc_generic_member_odt.class.php | 2 +- htdocs/core/modules/mrp/doc/doc_generic_mo_odt.modules.php | 2 +- .../modules/product/doc/doc_generic_product_odt.modules.php | 2 +- htdocs/core/modules/product/mod_codeproduct_elephant.php | 2 +- .../modules/project/doc/doc_generic_project_odt.modules.php | 2 +- .../project/task/doc/doc_generic_task_odt.modules.php | 2 +- .../propale/doc/doc_generic_proposal_odt.modules.php | 2 +- .../reception/doc/doc_generic_reception_odt.modules.php | 2 +- htdocs/core/modules/societe/doc/doc_generic_odt.modules.php | 2 +- htdocs/core/modules/societe/mod_codeclient_elephant.php | 2 +- htdocs/core/modules/societe/mod_codecompta_aquarium.php | 2 +- htdocs/core/modules/societe/mod_codecompta_digitaria.php | 2 +- .../modules/stock/doc/doc_generic_stock_odt.modules.php | 2 +- .../doc/doc_generic_supplier_order_odt.modules.php | 2 +- .../doc/doc_generic_supplier_proposal_odt.modules.php | 2 +- .../modules/ticket/doc/doc_generic_ticket_odt.modules.php | 2 +- .../core/modules/user/doc/doc_generic_user_odt.modules.php | 2 +- .../usergroup/doc/doc_generic_usergroup_odt.modules.php | 2 +- .../mymodule/doc/doc_generic_myobject_odt.modules.php | 2 +- .../doc/doc_generic_recruitmentjobposition_odt.modules.php | 2 +- htdocs/societe/admin/societe.php | 6 +++--- 26 files changed, 28 insertions(+), 28 deletions(-) diff --git a/htdocs/core/modules/barcode/mod_barcode_product_standard.php b/htdocs/core/modules/barcode/mod_barcode_product_standard.php index a0197f18cd3..c101001af4c 100644 --- a/htdocs/core/modules/barcode/mod_barcode_product_standard.php +++ b/htdocs/core/modules/barcode/mod_barcode_product_standard.php @@ -109,7 +109,7 @@ class mod_barcode_product_standard extends ModeleNumRefBarCode //$texte.= ''.$langs->trans("Mask").' ('.$langs->trans("BarCodeModel").'):'; $texte .= ''.$langs->trans("Mask").':'; $texte .= ''.$form->textwithpicto('', $tooltip, 1, 1).''; - $texte .= '  '; + $texte .= '  '; $texte .= ''; $texte .= ''; diff --git a/htdocs/core/modules/bom/doc/doc_generic_bom_odt.modules.php b/htdocs/core/modules/bom/doc/doc_generic_bom_odt.modules.php index 463cbc46a24..761aae99142 100644 --- a/htdocs/core/modules/bom/doc/doc_generic_bom_odt.modules.php +++ b/htdocs/core/modules/bom/doc/doc_generic_bom_odt.modules.php @@ -152,7 +152,7 @@ class doc_generic_bom_odt extends ModelePDFBom $texte .= $conf->global->BOM_ADDON_PDF_ODT_PATH; $texte .= ''; $texte .= '
    '; - $texte .= ''; + $texte .= ''; $texte .= '
    '; // Scan directories diff --git a/htdocs/core/modules/commande/doc/doc_generic_order_odt.modules.php b/htdocs/core/modules/commande/doc/doc_generic_order_odt.modules.php index b98d403d8f7..c59d1c40ee9 100644 --- a/htdocs/core/modules/commande/doc/doc_generic_order_odt.modules.php +++ b/htdocs/core/modules/commande/doc/doc_generic_order_odt.modules.php @@ -160,7 +160,7 @@ class doc_generic_order_odt extends ModelePDFCommandes $texte .= $conf->global->COMMANDE_ADDON_PDF_ODT_PATH; $texte .= ''; $texte .= '
    '; - $texte .= ''; + $texte .= ''; $texte .= '
    '; // Scan directories diff --git a/htdocs/core/modules/expedition/doc/doc_generic_shipment_odt.modules.php b/htdocs/core/modules/expedition/doc/doc_generic_shipment_odt.modules.php index 2dd33bab141..a916bcc534f 100644 --- a/htdocs/core/modules/expedition/doc/doc_generic_shipment_odt.modules.php +++ b/htdocs/core/modules/expedition/doc/doc_generic_shipment_odt.modules.php @@ -160,7 +160,7 @@ class doc_generic_shipment_odt extends ModelePdfExpedition $texte .= $conf->global->EXPEDITION_ADDON_PDF_ODT_PATH; $texte .= ''; $texte .= '
    '; - $texte .= ''; + $texte .= ''; $texte .= '
    '; // Scan directories diff --git a/htdocs/core/modules/facture/doc/doc_generic_invoice_odt.modules.php b/htdocs/core/modules/facture/doc/doc_generic_invoice_odt.modules.php index b8bfcdc16ac..9c0088bd398 100644 --- a/htdocs/core/modules/facture/doc/doc_generic_invoice_odt.modules.php +++ b/htdocs/core/modules/facture/doc/doc_generic_invoice_odt.modules.php @@ -159,7 +159,7 @@ class doc_generic_invoice_odt extends ModelePDFFactures $texte .= $conf->global->FACTURE_ADDON_PDF_ODT_PATH; $texte .= ''; $texte .= '
    '; - $texte .= ''; + $texte .= ''; $texte .= '
    '; // Scan directories diff --git a/htdocs/core/modules/member/doc/doc_generic_member_odt.class.php b/htdocs/core/modules/member/doc/doc_generic_member_odt.class.php index 4f1c20a464e..91d2248fb48 100644 --- a/htdocs/core/modules/member/doc/doc_generic_member_odt.class.php +++ b/htdocs/core/modules/member/doc/doc_generic_member_odt.class.php @@ -155,7 +155,7 @@ class doc_generic_member_odt extends ModelePDFMember $texte .= $conf->global->MEMBER_ADDON_PDF_ODT_PATH; $texte .= ''; $texte .= '
    '; - $texte .= ''; + $texte .= ''; $texte .= '
    '; // Scan directories diff --git a/htdocs/core/modules/mrp/doc/doc_generic_mo_odt.modules.php b/htdocs/core/modules/mrp/doc/doc_generic_mo_odt.modules.php index 07f5d5d1890..1df69d7ae53 100644 --- a/htdocs/core/modules/mrp/doc/doc_generic_mo_odt.modules.php +++ b/htdocs/core/modules/mrp/doc/doc_generic_mo_odt.modules.php @@ -159,7 +159,7 @@ class doc_generic_mo_odt extends ModelePDFMo $texte .= $conf->global->MRP_MO_ADDON_PDF_ODT_PATH; $texte .= ''; $texte .= '
    '; - $texte .= ''; + $texte .= ''; $texte .= '
    '; // Scan directories diff --git a/htdocs/core/modules/product/doc/doc_generic_product_odt.modules.php b/htdocs/core/modules/product/doc/doc_generic_product_odt.modules.php index 7fff122ec57..c1f6769579a 100644 --- a/htdocs/core/modules/product/doc/doc_generic_product_odt.modules.php +++ b/htdocs/core/modules/product/doc/doc_generic_product_odt.modules.php @@ -157,7 +157,7 @@ class doc_generic_product_odt extends ModelePDFProduct $texte .= $conf->global->PRODUCT_ADDON_PDF_ODT_PATH; $texte .= ''; $texte .= '
    '; - $texte .= ''; + $texte .= ''; $texte .= '
    '; // Scan directories diff --git a/htdocs/core/modules/product/mod_codeproduct_elephant.php b/htdocs/core/modules/product/mod_codeproduct_elephant.php index 40b1f324cdd..ff724ab209d 100644 --- a/htdocs/core/modules/product/mod_codeproduct_elephant.php +++ b/htdocs/core/modules/product/mod_codeproduct_elephant.php @@ -119,7 +119,7 @@ class mod_codeproduct_elephant extends ModeleProductCode $texte .= ''.$langs->trans("Mask").' ('.$langs->trans("ProductCodeModel").'):'; $texte .= ''.$form->textwithpicto('', $tooltip, 1, 1).''; - $texte .= '  '; + $texte .= '  '; $texte .= ''; diff --git a/htdocs/core/modules/project/doc/doc_generic_project_odt.modules.php b/htdocs/core/modules/project/doc/doc_generic_project_odt.modules.php index bad6a369ba6..d653ed760a6 100644 --- a/htdocs/core/modules/project/doc/doc_generic_project_odt.modules.php +++ b/htdocs/core/modules/project/doc/doc_generic_project_odt.modules.php @@ -450,7 +450,7 @@ class doc_generic_project_odt extends ModelePDFProjects $texte .= $conf->global->PROJECT_ADDON_PDF_ODT_PATH; $texte .= ''; $texte .= '
    '; - $texte .= ''; + $texte .= ''; $texte .= '
    '; // Scan directories diff --git a/htdocs/core/modules/project/task/doc/doc_generic_task_odt.modules.php b/htdocs/core/modules/project/task/doc/doc_generic_task_odt.modules.php index 1fd0f9c23ee..7849e46edbe 100644 --- a/htdocs/core/modules/project/task/doc/doc_generic_task_odt.modules.php +++ b/htdocs/core/modules/project/task/doc/doc_generic_task_odt.modules.php @@ -417,7 +417,7 @@ class doc_generic_task_odt extends ModelePDFTask $texte .= $conf->global->PROJECT_TASK_ADDON_PDF_ODT_PATH; $texte .= ''; $texte .= '
    '; - $texte .= ''; + $texte .= ''; $texte .= '
    '; // Scan directories diff --git a/htdocs/core/modules/propale/doc/doc_generic_proposal_odt.modules.php b/htdocs/core/modules/propale/doc/doc_generic_proposal_odt.modules.php index e636645f6c8..e2e3ffd2a21 100644 --- a/htdocs/core/modules/propale/doc/doc_generic_proposal_odt.modules.php +++ b/htdocs/core/modules/propale/doc/doc_generic_proposal_odt.modules.php @@ -161,7 +161,7 @@ class doc_generic_proposal_odt extends ModelePDFPropales $texte .= $conf->global->PROPALE_ADDON_PDF_ODT_PATH; $texte .= ''; $texte .= '
    '; - $texte .= ''; + $texte .= ''; $texte .= '
    '; // Scan directories diff --git a/htdocs/core/modules/reception/doc/doc_generic_reception_odt.modules.php b/htdocs/core/modules/reception/doc/doc_generic_reception_odt.modules.php index 7fde8e26c82..f8fd829591d 100644 --- a/htdocs/core/modules/reception/doc/doc_generic_reception_odt.modules.php +++ b/htdocs/core/modules/reception/doc/doc_generic_reception_odt.modules.php @@ -153,7 +153,7 @@ class doc_generic_reception_odt extends ModelePdfReception $texte .= $conf->global->RECEPTION_ADDON_PDF_ODT_PATH; $texte .= ''; $texte .= '
    '; - $texte .= ''; + $texte .= ''; $texte .= '
    '; // Scan directories diff --git a/htdocs/core/modules/societe/doc/doc_generic_odt.modules.php b/htdocs/core/modules/societe/doc/doc_generic_odt.modules.php index aaa9c03c6e7..3a62eb22937 100644 --- a/htdocs/core/modules/societe/doc/doc_generic_odt.modules.php +++ b/htdocs/core/modules/societe/doc/doc_generic_odt.modules.php @@ -143,7 +143,7 @@ class doc_generic_odt extends ModeleThirdPartyDoc $texte .= ''; $texte .= ''; $texte .= '  '; - $texte .= ''; + $texte .= ''; $texte .= ''; $texte .= ''; $texte .= ''; diff --git a/htdocs/core/modules/societe/mod_codeclient_elephant.php b/htdocs/core/modules/societe/mod_codeclient_elephant.php index 6079120a305..0142457cd40 100644 --- a/htdocs/core/modules/societe/mod_codeclient_elephant.php +++ b/htdocs/core/modules/societe/mod_codeclient_elephant.php @@ -135,7 +135,7 @@ class mod_codeclient_elephant extends ModeleThirdPartyCode $texte .= ''.$langs->trans("Mask").' ('.$langs->trans("CustomerCodeModel").'):'; $texte .= ''.$form->textwithpicto('', $tooltip, 1, 1).''; - $texte .= '  '; + $texte .= '  '; $texte .= ''; diff --git a/htdocs/core/modules/societe/mod_codecompta_aquarium.php b/htdocs/core/modules/societe/mod_codecompta_aquarium.php index ff5d737872a..4d1d01db682 100644 --- a/htdocs/core/modules/societe/mod_codecompta_aquarium.php +++ b/htdocs/core/modules/societe/mod_codecompta_aquarium.php @@ -103,7 +103,7 @@ class mod_codecompta_aquarium extends ModeleAccountancyCode $texte .= $langs->trans('COMPANY_AQUARIUM_CLEAN_REGEX').' = '.$conf->global->COMPANY_AQUARIUM_CLEAN_REGEX."
    \n"; } $texte .= ''; - $texte .= ''; + $texte .= ''; $texte .= ''; $texte .= ''; diff --git a/htdocs/core/modules/societe/mod_codecompta_digitaria.php b/htdocs/core/modules/societe/mod_codecompta_digitaria.php index 217e027d152..dddd01a602d 100644 --- a/htdocs/core/modules/societe/mod_codecompta_digitaria.php +++ b/htdocs/core/modules/societe/mod_codecompta_digitaria.php @@ -126,7 +126,7 @@ class mod_codecompta_digitaria extends ModeleAccountancyCode $texte .= $langs->trans('COMPANY_DIGITARIA_UNIQUE_CODE').' = '.yn(1)."
    \n"; } $texte .= ''; - $texte .= ''; + $texte .= ''; $texte .= ''; $texte .= ''; diff --git a/htdocs/core/modules/stock/doc/doc_generic_stock_odt.modules.php b/htdocs/core/modules/stock/doc/doc_generic_stock_odt.modules.php index c3e26e591c7..1fb120d4d29 100644 --- a/htdocs/core/modules/stock/doc/doc_generic_stock_odt.modules.php +++ b/htdocs/core/modules/stock/doc/doc_generic_stock_odt.modules.php @@ -156,7 +156,7 @@ class doc_generic_stock_odt extends ModelePDFStock $texte .= $conf->global->STOCK_ADDON_PDF_ODT_PATH; $texte .= ''; $texte .= '
    '; - $texte .= ''; + $texte .= ''; $texte .= '
    '; // Scan directories diff --git a/htdocs/core/modules/supplier_order/doc/doc_generic_supplier_order_odt.modules.php b/htdocs/core/modules/supplier_order/doc/doc_generic_supplier_order_odt.modules.php index 436622d6451..68caf286682 100644 --- a/htdocs/core/modules/supplier_order/doc/doc_generic_supplier_order_odt.modules.php +++ b/htdocs/core/modules/supplier_order/doc/doc_generic_supplier_order_odt.modules.php @@ -160,7 +160,7 @@ class doc_generic_supplier_order_odt extends ModelePDFSuppliersOrders $texte .= $conf->global->SUPPLIER_ORDER_ADDON_PDF_ODT_PATH; $texte .= ''; $texte .= '
    '; - $texte .= ''; + $texte .= ''; $texte .= '
    '; // Scan directories diff --git a/htdocs/core/modules/supplier_proposal/doc/doc_generic_supplier_proposal_odt.modules.php b/htdocs/core/modules/supplier_proposal/doc/doc_generic_supplier_proposal_odt.modules.php index 04f6ed49012..c79ee188213 100644 --- a/htdocs/core/modules/supplier_proposal/doc/doc_generic_supplier_proposal_odt.modules.php +++ b/htdocs/core/modules/supplier_proposal/doc/doc_generic_supplier_proposal_odt.modules.php @@ -163,7 +163,7 @@ class doc_generic_supplier_proposal_odt extends ModelePDFSupplierProposal $texte .= $conf->global->SUPPLIER_PROPOSAL_ADDON_PDF_ODT_PATH; $texte .= ''; $texte .= '
    '; - $texte .= ''; + $texte .= ''; $texte .= '
    '; // Scan directories diff --git a/htdocs/core/modules/ticket/doc/doc_generic_ticket_odt.modules.php b/htdocs/core/modules/ticket/doc/doc_generic_ticket_odt.modules.php index 86b9d44ad9b..d69da78aacc 100644 --- a/htdocs/core/modules/ticket/doc/doc_generic_ticket_odt.modules.php +++ b/htdocs/core/modules/ticket/doc/doc_generic_ticket_odt.modules.php @@ -151,7 +151,7 @@ class doc_generic_ticket_odt extends ModelePDFTicket $texte .= $conf->global->TICKET_ADDON_PDF_ODT_PATH; $texte .= ''; $texte .= '
    '; - $texte .= ''; + $texte .= ''; $texte .= '
    '; // Scan directories diff --git a/htdocs/core/modules/user/doc/doc_generic_user_odt.modules.php b/htdocs/core/modules/user/doc/doc_generic_user_odt.modules.php index 656eb88ecaa..353d35fc182 100644 --- a/htdocs/core/modules/user/doc/doc_generic_user_odt.modules.php +++ b/htdocs/core/modules/user/doc/doc_generic_user_odt.modules.php @@ -160,7 +160,7 @@ class doc_generic_user_odt extends ModelePDFUser $texte .= $conf->global->USER_ADDON_PDF_ODT_PATH; $texte .= ''; $texte .= '
    '; - $texte .= ''; + $texte .= ''; $texte .= '
    '; // Scan directories diff --git a/htdocs/core/modules/usergroup/doc/doc_generic_usergroup_odt.modules.php b/htdocs/core/modules/usergroup/doc/doc_generic_usergroup_odt.modules.php index e1c83023df9..7ba82f5825e 100644 --- a/htdocs/core/modules/usergroup/doc/doc_generic_usergroup_odt.modules.php +++ b/htdocs/core/modules/usergroup/doc/doc_generic_usergroup_odt.modules.php @@ -163,7 +163,7 @@ class doc_generic_usergroup_odt extends ModelePDFUserGroup $texte .= $conf->global->USERGROUP_ADDON_PDF_ODT_PATH; $texte .= ''; $texte .= '
    '; - $texte .= ''; + $texte .= ''; $texte .= '
    '; // Scan directories diff --git a/htdocs/modulebuilder/template/core/modules/mymodule/doc/doc_generic_myobject_odt.modules.php b/htdocs/modulebuilder/template/core/modules/mymodule/doc/doc_generic_myobject_odt.modules.php index 8040c13d606..689503f0dee 100644 --- a/htdocs/modulebuilder/template/core/modules/mymodule/doc/doc_generic_myobject_odt.modules.php +++ b/htdocs/modulebuilder/template/core/modules/mymodule/doc/doc_generic_myobject_odt.modules.php @@ -159,7 +159,7 @@ class doc_generic_myobject_odt extends ModelePDFMyObject $texte .= $conf->global->MYMODULE_MYOBJECT_ADDON_PDF_ODT_PATH; $texte .= ''; $texte .= '
    '; - $texte .= ''; + $texte .= ''; $texte .= '
    '; // Scan directories diff --git a/htdocs/recruitment/core/modules/recruitment/doc/doc_generic_recruitmentjobposition_odt.modules.php b/htdocs/recruitment/core/modules/recruitment/doc/doc_generic_recruitmentjobposition_odt.modules.php index e818a0816a9..e2b7c545aa9 100644 --- a/htdocs/recruitment/core/modules/recruitment/doc/doc_generic_recruitmentjobposition_odt.modules.php +++ b/htdocs/recruitment/core/modules/recruitment/doc/doc_generic_recruitmentjobposition_odt.modules.php @@ -158,7 +158,7 @@ class doc_generic_recruitmentjobposition_odt extends ModelePDFRecruitmentJobPosi $texte .= $conf->global->RECRUITMENT_RECRUITMENTJOBPOSITION_ADDON_PDF_ODT_PATH; $texte .= ''; $texte .= '
    '; - $texte .= ''; + $texte .= ''; $texte .= '
    '; // Scan directories diff --git a/htdocs/societe/admin/societe.php b/htdocs/societe/admin/societe.php index 193dfc43cad..236551c1c2e 100644 --- a/htdocs/societe/admin/societe.php +++ b/htdocs/societe/admin/societe.php @@ -780,7 +780,7 @@ if (!$conf->use_javascript_ajax) { ); print $form->selectarray("activate_COMPANY_USE_SEARCH_TO_SELECT", $arrval, (property_exists($conf->global, 'COMPANY_USE_SEARCH_TO_SELECT')?$conf->global->COMPANY_USE_SEARCH_TO_SELECT:''), 0, 0, 0, '', 0, 0, 0, '', 'minwidth75imp'); print ''; - print ''; + print ''; print ""; } print ''; @@ -801,7 +801,7 @@ if (!$conf->use_javascript_ajax) { ); print $form->selectarray("activate_CONTACT_USE_SEARCH_TO_SELECT", $arrval, (property_exists($conf->global, 'CONTACT_USE_SEARCH_TO_SELECT')?$conf->global->CONTACT_USE_SEARCH_TO_SELECT:''), 0, 0, 0, '', 0, 0, 0, '', 'minwidth75imp'); print ''; - print ''; + print ''; print ""; } print ''; @@ -905,7 +905,7 @@ if (empty($conf->global->SOCIETE_DISABLE_PROSPECTSCUSTOMERS)) { print $formcompany->selectProspectCustomerType((property_exists($conf->global, 'THIRDPARTY_CUSTOMERTYPE_BY_DEFAULT')?$conf->global->THIRDPARTY_CUSTOMERTYPE_BY_DEFAULT:''), 'defaultcustomertype', 'defaultcustomertype', 'admin'); print ''; print ''; - print ''; + print ''; print ''; print ''; } From 694ea8830bb6744e0f1be81c870a8d2d5b29e28d Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 18 Feb 2022 13:46:12 +0100 Subject: [PATCH 077/255] Fix missing name and type into template --- htdocs/adherents/admin/member.php | 86 ++++++++++--------- .../modules/member/doc/pdf_standard.class.php | 26 ++++++ 2 files changed, 73 insertions(+), 39 deletions(-) diff --git a/htdocs/adherents/admin/member.php b/htdocs/adherents/admin/member.php index 39587521c4d..2b6a0838fe1 100644 --- a/htdocs/adherents/admin/member.php +++ b/htdocs/adherents/admin/member.php @@ -196,6 +196,9 @@ print '
    '; print ''; print ''; + +// Mains options + print load_fiche_titre($langs->trans("MemberMainOptions"), '', ''); print '
    '; @@ -286,51 +289,15 @@ print '
    '; print '
    '; -print '
    '; - - -/* - * Edit info of model document - */ -$constantes = array( - 'ADHERENT_CARD_TYPE', - //'ADHERENT_CARD_BACKGROUND', - 'ADHERENT_CARD_HEADER_TEXT', - 'ADHERENT_CARD_TEXT', - 'ADHERENT_CARD_TEXT_RIGHT', - 'ADHERENT_CARD_FOOTER_TEXT' -); - -print load_fiche_titre($langs->trans("MembersCards"), '', ''); - -$helptext = '*'.$langs->trans("FollowingConstantsWillBeSubstituted").'
    '; -$helptext .= '__DOL_MAIN_URL_ROOT__, __ID__, __FIRSTNAME__, __LASTNAME__, __FULLNAME__, __LOGIN__, __PASSWORD__, '; -$helptext .= '__COMPANY__, __ADDRESS__, __ZIP__, __TOWN__, __COUNTRY__, __EMAIL__, __BIRTH__, __PHOTO__, __TYPE__, '; -$helptext .= '__YEAR__, __MONTH__, __DAY__'; - -form_constantes($constantes, 0, $helptext); print '
    '; -/* - * Edit info of model document - */ -$constantes = array('ADHERENT_ETIQUETTE_TYPE', 'ADHERENT_ETIQUETTE_TEXT'); - -print load_fiche_titre($langs->trans("MembersTickets"), '', ''); - -$helptext = '*'.$langs->trans("FollowingConstantsWillBeSubstituted").'
    '; -$helptext .= '__DOL_MAIN_URL_ROOT__, __ID__, __FIRSTNAME__, __LASTNAME__, __FULLNAME__, __LOGIN__, __PASSWORD__, '; -$helptext .= '__COMPANY__, __ADDRESS__, __ZIP__, __TOWN__, __COUNTRY__, __EMAIL__, __BIRTH__, __PHOTO__, __TYPE__, '; -$helptext .= '__YEAR__, __MONTH__, __DAY__'; - -form_constantes($constantes, 0, $helptext); $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']); // Defined model definition table $def = array(); -$sql = "SELECT nom"; +$sql = "SELECT nom as name"; $sql .= " FROM ".MAIN_DB_PREFIX."document_model"; $sql .= " WHERE type = '".$db->escape($type)."'"; $sql .= " AND entity = ".$conf->entity; @@ -339,14 +306,15 @@ if ($resql) { $i = 0; $num_rows = $db->num_rows($resql); while ($i < $num_rows) { - $array = $db->fetch_array($resql); - array_push($def, $array[0]); + $obj = $db->fetch_object($resql); + array_push($def, $obj->name); $i++; } } else { dol_print_error($db); } + print load_fiche_titre($langs->trans("MembersDocModules"), '', ''); print '
    '; @@ -460,6 +428,46 @@ foreach ($dirmodels as $reldir) { print ''; print '
    '; + +/* + * Edit info of model document + */ +$constantes = array( + 'ADHERENT_CARD_TYPE', + //'ADHERENT_CARD_BACKGROUND', + 'ADHERENT_CARD_HEADER_TEXT', + 'ADHERENT_CARD_TEXT', + 'ADHERENT_CARD_TEXT_RIGHT', + 'ADHERENT_CARD_FOOTER_TEXT' +); + +print load_fiche_titre($langs->trans("MembersCards"), '', ''); + +$helptext = '*'.$langs->trans("FollowingConstantsWillBeSubstituted").'
    '; +$helptext .= '__DOL_MAIN_URL_ROOT__, __ID__, __FIRSTNAME__, __LASTNAME__, __FULLNAME__, __LOGIN__, __PASSWORD__, '; +$helptext .= '__COMPANY__, __ADDRESS__, __ZIP__, __TOWN__, __COUNTRY__, __EMAIL__, __BIRTH__, __PHOTO__, __TYPE__, '; +$helptext .= '__YEAR__, __MONTH__, __DAY__'; + +form_constantes($constantes, 0, $helptext); + +print '
    '; + + +/* + * Edit info of model document + */ +$constantes = array('ADHERENT_ETIQUETTE_TYPE', 'ADHERENT_ETIQUETTE_TEXT'); + +print load_fiche_titre($langs->trans("MembersTickets"), '', ''); + +$helptext = '*'.$langs->trans("FollowingConstantsWillBeSubstituted").'
    '; +$helptext .= '__DOL_MAIN_URL_ROOT__, __ID__, __FIRSTNAME__, __LASTNAME__, __FULLNAME__, __LOGIN__, __PASSWORD__, '; +$helptext .= '__COMPANY__, __ADDRESS__, __ZIP__, __TOWN__, __COUNTRY__, __EMAIL__, __BIRTH__, __PHOTO__, __TYPE__, '; +$helptext .= '__YEAR__, __MONTH__, __DAY__'; + +form_constantes($constantes, 0, $helptext); + + print "
    "; print dol_get_fiche_end(); diff --git a/htdocs/core/modules/member/doc/pdf_standard.class.php b/htdocs/core/modules/member/doc/pdf_standard.class.php index 15f3260c4d2..d39afdd9420 100644 --- a/htdocs/core/modules/member/doc/pdf_standard.class.php +++ b/htdocs/core/modules/member/doc/pdf_standard.class.php @@ -33,6 +33,32 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/commonstickergenerator.class.php'; */ class pdf_standard extends CommonStickerGenerator { + /** + * Dolibarr version of the loaded document + * @var string + */ + public $version = 'dolibarr'; + + + /** + * 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('PDFStandard'); + //$this->update_main_doc_field = 1; // Save the name of generated file as the main doc when generating a doc with this template + + $this->type = 'html'; + } /** * Output a sticker on page at position _COUNTX, _COUNTY (_COUNTX and _COUNTY start from 0) From 61e91656e0073a31296c2961692d9cae06d09f76 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 18 Feb 2022 14:14:34 +0100 Subject: [PATCH 078/255] FIX setup of member module FIX generation of business cards --- htdocs/adherents/admin/member.php | 9 +++++++++ htdocs/core/class/commonobject.class.php | 3 +-- htdocs/core/lib/admin.lib.php | 5 +++-- htdocs/core/modules/member/doc/pdf_standard.class.php | 6 +++--- htdocs/langs/en_US/admin.lang | 3 ++- 5 files changed, 18 insertions(+), 8 deletions(-) diff --git a/htdocs/adherents/admin/member.php b/htdocs/adherents/admin/member.php index 2b6a0838fe1..d51dd8ef730 100644 --- a/htdocs/adherents/admin/member.php +++ b/htdocs/adherents/admin/member.php @@ -429,6 +429,14 @@ print ''; print ''; + +/* +TODO Use a global form instead of embeded form into table +print '
    '; +print ''; +print ''; +*/ + /* * Edit info of model document */ @@ -467,6 +475,7 @@ $helptext .= '__YEAR__, __MONTH__, __DAY__'; form_constantes($constantes, 0, $helptext); +//print '
    '; print "
    "; diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index 8ab59689976..8dabc902e5c 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -5292,8 +5292,7 @@ abstract class CommonObject $sav_charset_output = $outputlangs->charset_output; if (in_array(get_class($this), array('Adherent'))) { - $arrayofrecords = array(); // The write_file of templates of adherent class need this var - $resultwritefile = $obj->write_file($this, $outputlangs, $srctemplatepath, 'member', 1, $moreparams); + $resultwritefile = $obj->write_file($this, $outputlangs, $srctemplatepath, 'member', 1, 'tmp_cards', $moreparams); } else { $resultwritefile = $obj->write_file($this, $outputlangs, $srctemplatepath, $hidedetails, $hidedesc, $hideref, $moreparams); } diff --git a/htdocs/core/lib/admin.lib.php b/htdocs/core/lib/admin.lib.php index 448677002df..a068f5fb5f5 100644 --- a/htdocs/core/lib/admin.lib.php +++ b/htdocs/core/lib/admin.lib.php @@ -1627,6 +1627,7 @@ function form_constantes($tableau, $strictw3c = 0, $helptext = '', $text = 'Valu if (empty($strictw3c)) { print "\n".'
    '; print ''; + print ''; } print ''; @@ -1733,7 +1734,7 @@ function form_constantes($tableau, $strictw3c = 0, $helptext = '', $text = 'Valu // Submit if (empty($strictw3c)) { print ''; - print ''; + print ''; print ""; } @@ -1748,7 +1749,7 @@ function form_constantes($tableau, $strictw3c = 0, $helptext = '', $text = 'Valu print ''; if (!empty($strictw3c) && $strictw3c == 1) { - print '
    '; + print '
    '; print "
    \n"; } } diff --git a/htdocs/core/modules/member/doc/pdf_standard.class.php b/htdocs/core/modules/member/doc/pdf_standard.class.php index d39afdd9420..0fc13cbe134 100644 --- a/htdocs/core/modules/member/doc/pdf_standard.class.php +++ b/htdocs/core/modules/member/doc/pdf_standard.class.php @@ -50,14 +50,14 @@ class pdf_standard extends CommonStickerGenerator global $conf, $langs, $mysoc; // Translations - $langs->loadLangs(array("main", "bills")); + $langs->loadLangs(array("main", "admin")); $this->db = $db; $this->name = "standard"; - $this->description = $langs->trans('PDFStandard'); + $this->description = $langs->trans('TemplateforBusinessCards'); //$this->update_main_doc_field = 1; // Save the name of generated file as the main doc when generating a doc with this template - $this->type = 'html'; + $this->type = 'pdf-various-sizes'; } /** diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang index 3506f024eea..5af3fe19592 100644 --- a/htdocs/langs/en_US/admin.lang +++ b/htdocs/langs/en_US/admin.lang @@ -2218,4 +2218,5 @@ 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 -LateWarningAfter="Late" warning after \ No newline at end of file +LateWarningAfter="Late" warning after +TemplateforBusinessCards=Template for a business card in different size \ No newline at end of file From 30cde100ffd55c0f513434cb06f79c515cd18a0b Mon Sep 17 00:00:00 2001 From: Atm-Gregr Date: Fri, 18 Feb 2022 14:41:29 +0100 Subject: [PATCH 079/255] trad us --- htdocs/langs/en_US/hrm.lang | 3 +++ 1 file changed, 3 insertions(+) diff --git a/htdocs/langs/en_US/hrm.lang b/htdocs/langs/en_US/hrm.lang index c571ec6ca8a..ab3628026c5 100644 --- a/htdocs/langs/en_US/hrm.lang +++ b/htdocs/langs/en_US/hrm.lang @@ -79,3 +79,6 @@ NoEval=No evaluation done for this employee HowManyUserWithThisMaxNote=Number of users with this rank HighestRank=Highest rank SkillComparison=Skill comparison +ActionsOnJob=Events on this job +VacantPosition=job vacancy +VacantCheckboxHelper=Checking this option will show unfilled positions (job vacancy) From e41e0f069a5d2be4041e7df58a769c2d47b3e14f Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 18 Feb 2022 15:09:52 +0100 Subject: [PATCH 080/255] Fix creator in PDF. Add log to help to find strange bug --- htdocs/core/modules/facture/doc/pdf_crabe.modules.php | 9 +++++++-- htdocs/core/modules/facture/doc/pdf_sponge.modules.php | 8 ++++++-- htdocs/langs/en_US/members.lang | 2 +- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/htdocs/core/modules/facture/doc/pdf_crabe.modules.php b/htdocs/core/modules/facture/doc/pdf_crabe.modules.php index b9ceb3e346b..0760b85c65c 100644 --- a/htdocs/core/modules/facture/doc/pdf_crabe.modules.php +++ b/htdocs/core/modules/facture/doc/pdf_crabe.modules.php @@ -366,7 +366,7 @@ class pdf_crabe extends ModelePDFFactures $pdf->SetTitle($outputlangs->convToOutputCharset($object->ref)); $pdf->SetSubject($outputlangs->transnoentities("PdfInvoiceTitle")); $pdf->SetCreator("Dolibarr ".DOL_VERSION); - $pdf->SetAuthor($outputlangs->convToOutputCharset($user->getFullName($outputlangs))); + $pdf->SetAuthor($mysoc->name.($user->id > 0 ? ' - '.$outputlangs->convToOutputCharset($user->getFullName($outputlangs)) : '')); $pdf->SetKeyWords($outputlangs->convToOutputCharset($object->ref)." ".$outputlangs->transnoentities("PdfInvoiceTitle")." ".$outputlangs->convToOutputCharset($object->thirdparty->name)); if (!empty($conf->global->MAIN_DISABLE_PDF_COMPRESSION)) { $pdf->SetCompression(false); @@ -374,10 +374,14 @@ class pdf_crabe extends ModelePDFFactures // Set certificate $cert = empty($user->conf->CERTIFICATE_CRT) ? '' : $user->conf->CERTIFICATE_CRT; + $certprivate = empty($user->conf->CERTIFICATE_CRT_PRIVATE) ? '' : $user->conf->CERTIFICATE_CRT_PRIVATE; // 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 (!$certprivate) { + $certprivate = empty($conf->global->CERTIFICATE_CRT_PRIVATE) ? '' : $conf->global->CERTIFICATE_CRT_PRIVATE; + } // If a certificate is found if ($cert) { $info = array( @@ -386,7 +390,7 @@ class pdf_crabe extends ModelePDFFactures 'Reason' => 'INVOICE', 'ContactInfo' => $this->emetteur->email ); - $pdf->setSignature($cert, $cert, $this->emetteur->name, '', 2, $info); + $pdf->setSignature($cert, $certprivate, $this->emetteur->name, '', 2, $info); } $pdf->SetMargins($this->marge_gauche, $this->marge_haute, $this->marge_droite); // Left, Top, Right @@ -814,6 +818,7 @@ class pdf_crabe extends ModelePDFFactures $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, 1, 0, $object->multicurrency_code); $bottomlasttab = $this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforfooter + 1; } + dol_syslog("bottomlasttab=".$bottomlasttab." this->page_hauteur=".$this->page_hauteur." heightforinfotot=".$heightforinfotot." heightforfreetext=".$heightforfreetext." heightforfooter=".$heightforfooter); // Display info area $posy = $this->_tableau_info($pdf, $object, $bottomlasttab, $outputlangs, $outputlangsbis); diff --git a/htdocs/core/modules/facture/doc/pdf_sponge.modules.php b/htdocs/core/modules/facture/doc/pdf_sponge.modules.php index c1666545891..910790db51f 100644 --- a/htdocs/core/modules/facture/doc/pdf_sponge.modules.php +++ b/htdocs/core/modules/facture/doc/pdf_sponge.modules.php @@ -367,7 +367,7 @@ class pdf_sponge extends ModelePDFFactures $pdf->SetTitle($outputlangs->convToOutputCharset($object->ref)); $pdf->SetSubject($outputlangs->transnoentities("PdfInvoiceTitle")); $pdf->SetCreator("Dolibarr ".DOL_VERSION); - $pdf->SetAuthor($outputlangs->convToOutputCharset($user->getFullName($outputlangs))); + $pdf->SetAuthor($mysoc->name.($user->id > 0 ? ' - '.$outputlangs->convToOutputCharset($user->getFullName($outputlangs)) : '')); $pdf->SetKeyWords($outputlangs->convToOutputCharset($object->ref)." ".$outputlangs->transnoentities("PdfInvoiceTitle")." ".$outputlangs->convToOutputCharset($object->thirdparty->name)); if (!empty($conf->global->MAIN_DISABLE_PDF_COMPRESSION)) { $pdf->SetCompression(false); @@ -375,10 +375,14 @@ class pdf_sponge extends ModelePDFFactures // Set certificate $cert = empty($user->conf->CERTIFICATE_CRT) ? '' : $user->conf->CERTIFICATE_CRT; + $certprivate = empty($user->conf->CERTIFICATE_CRT_PRIVATE) ? '' : $user->conf->CERTIFICATE_CRT_PRIVATE; // 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 (!$certprivate) { + $certprivate = empty($conf->global->CERTIFICATE_CRT_PRIVATE) ? '' : $conf->global->CERTIFICATE_CRT_PRIVATE; + } // If a certificate is found if ($cert) { $info = array( @@ -387,7 +391,7 @@ class pdf_sponge extends ModelePDFFactures 'Reason' => 'INVOICE', 'ContactInfo' => $this->emetteur->email ); - $pdf->setSignature($cert, $cert, $this->emetteur->name, '', 2, $info); + $pdf->setSignature($cert, $certprivate, $this->emetteur->name, '', 2, $info); } $pdf->SetMargins($this->marge_gauche, $this->marge_haute, $this->marge_droite); // Left, Top, Right diff --git a/htdocs/langs/en_US/members.lang b/htdocs/langs/en_US/members.lang index 9605e7a8df7..8646c40b98f 100644 --- a/htdocs/langs/en_US/members.lang +++ b/htdocs/langs/en_US/members.lang @@ -159,7 +159,7 @@ HTPasswordExport=htpassword file generation NoThirdPartyAssociatedToMember=No third party associated with this member MembersAndSubscriptions=Members and Contributions MoreActions=Complementary action on recording -MoreActionsOnSubscription=Complementary action, suggested by default when recording a contribution +MoreActionsOnSubscription=Complementary action suggested by default when recording a contribution, also done automatially on online payment of a contribution MoreActionBankDirect=Create a direct entry on bank account MoreActionBankViaInvoice=Create an invoice, and a payment on bank account MoreActionInvoiceOnly=Create an invoice with no payment From 87a5defbd32d655aa211a7b053d0cade849192ad Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 18 Feb 2022 15:11:54 +0100 Subject: [PATCH 081/255] Comment --- htdocs/societe/class/societe.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/societe/class/societe.class.php b/htdocs/societe/class/societe.class.php index a0793e914e9..8a5f8166106 100644 --- a/htdocs/societe/class/societe.class.php +++ b/htdocs/societe/class/societe.class.php @@ -2329,7 +2329,7 @@ class Societe extends CommonObject /** * Return array of sales representatives * - * @param User $user Object user + * @param User $user Object user (not used) * @param int $mode 0=Array with properties, 1=Array of id. * @param string $sortfield List of sort fields, separated by comma. Example: 't1.fielda,t2.fieldb' * @param string $sortorder Sort order, separated by comma. Example: 'ASC,DESC'; From f4f03d03f22c28b258efe855014006353ec2b1ab Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 18 Feb 2022 15:23:13 +0100 Subject: [PATCH 082/255] Fix link --- htdocs/core/boxes/box_members_last_subscriptions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/boxes/box_members_last_subscriptions.php b/htdocs/core/boxes/box_members_last_subscriptions.php index 930b4d3a874..39ae0140ca4 100644 --- a/htdocs/core/boxes/box_members_last_subscriptions.php +++ b/htdocs/core/boxes/box_members_last_subscriptions.php @@ -142,7 +142,7 @@ class box_members_last_subscriptions extends ModeleBoxes $this->info_box_contents[$line][] = array( 'td' => 'class="tdoverflowmax150 maxwidth150onsmartphone"', - 'text' => $staticmember->getNomUrl(-1, 32, 'subscription'), + 'text' => $staticmember->getNomUrl(-1, 32, 'card'), 'asis' => 1, ); From cd9c1acafece00cdc1098c310a3395fcfaf6a01e Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 18 Feb 2022 16:09:23 +0100 Subject: [PATCH 083/255] Fix missing token --- htdocs/main.inc.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/htdocs/main.inc.php b/htdocs/main.inc.php index 287185515e2..3f8da14338b 100644 --- a/htdocs/main.inc.php +++ b/htdocs/main.inc.php @@ -3213,6 +3213,7 @@ if (!function_exists("llxFooter")) { id:id; ?> , element:'element ?>' , action:'DOC_PREVIEW' + , token: '' } ); }); @@ -3222,6 +3223,7 @@ if (!function_exists("llxFooter")) { id:id; ?> , element:'element ?>' , action:'DOC_DOWNLOAD' + , token: '' } ); }); From 3d9cdbf13693e683bc847d9aec7666e00dec41d6 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 18 Feb 2022 16:24:11 +0100 Subject: [PATCH 084/255] FIX Debug v15 --- htdocs/adherents/class/adherent.class.php | 1 + htdocs/compta/paiement/class/paiement.class.php | 2 +- htdocs/core/lib/functions.lib.php | 1 + htdocs/core/modules/facture/doc/pdf_crabe.modules.php | 4 ++-- htdocs/core/modules/facture/doc/pdf_sponge.modules.php | 4 ++-- htdocs/public/payment/paymentok.php | 2 +- 6 files changed, 8 insertions(+), 6 deletions(-) diff --git a/htdocs/adherents/class/adherent.class.php b/htdocs/adherents/class/adherent.class.php index 1d12ad16194..1faa9271623 100644 --- a/htdocs/adherents/class/adherent.class.php +++ b/htdocs/adherents/class/adherent.class.php @@ -1805,6 +1805,7 @@ class Adherent extends CommonObject $paiement = new Paiement($this->db); $paiement->datepaye = $paymentdate; $paiement->amounts = $amounts; + $paiement->paiementcode = $operation; $paiement->paiementid = dol_getIdFromCode($this->db, $operation, 'c_paiement', 'code', 'id', 1); $paiement->num_payment = $num_chq; $paiement->note_public = $label; diff --git a/htdocs/compta/paiement/class/paiement.class.php b/htdocs/compta/paiement/class/paiement.class.php index 2a8522ab05b..ab68ac7f9b1 100644 --- a/htdocs/compta/paiement/class/paiement.class.php +++ b/htdocs/compta/paiement/class/paiement.class.php @@ -613,7 +613,7 @@ class Paiement extends CommonObject // Insert payment into llx_bank $bank_line_id = $acc->addline( $this->datepaye, - $this->paiementid, // Payment mode id or code ("CHQ or VIR for example") + $this->paiementcode ? $this->paiementcode : $this->paiementid, // Payment mode code ('CB', 'CHQ' or 'VIR' for example). Use payment id if not defined for backward compatibility. $label, $totalamount, // Sign must be positive when we receive money (customer payment), negative when you give money (supplier invoice or credit note) $this->num_payment, diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 7be3f5e3351..7668489c8ea 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -10373,6 +10373,7 @@ function newToken() /** * Return the value of token currently saved into session with name 'token'. + * For ajax call, you must use this token as a parameter of the call into the js calling script (the called ajax php page must also set constant NOTOKENRENEWAL). * * @return string */ diff --git a/htdocs/core/modules/facture/doc/pdf_crabe.modules.php b/htdocs/core/modules/facture/doc/pdf_crabe.modules.php index 0760b85c65c..63a68f7b802 100644 --- a/htdocs/core/modules/facture/doc/pdf_crabe.modules.php +++ b/htdocs/core/modules/facture/doc/pdf_crabe.modules.php @@ -1181,9 +1181,9 @@ class pdf_crabe extends ModelePDFFactures $pdf->SetXY($this->marge_gauche, $posy); $pdf->writeHTMLCell(80, 5, '', '', dol_htmlentitiesbr($linktopay), 0, 1); - } - $posy = $pdf->GetY() + 1; + $posy = $pdf->GetY() + 1; + } } // Show payment mode CHQ diff --git a/htdocs/core/modules/facture/doc/pdf_sponge.modules.php b/htdocs/core/modules/facture/doc/pdf_sponge.modules.php index 910790db51f..7f3b543ebba 100644 --- a/htdocs/core/modules/facture/doc/pdf_sponge.modules.php +++ b/htdocs/core/modules/facture/doc/pdf_sponge.modules.php @@ -1259,9 +1259,9 @@ class pdf_sponge extends ModelePDFFactures $pdf->SetXY($this->marge_gauche, $posy); $pdf->writeHTMLCell(80, 5, '', '', dol_htmlentitiesbr($linktopay), 0, 1); - } - $posy = $pdf->GetY() + 1; + $posy = $pdf->GetY() + 1; + } } // Show payment mode CHQ diff --git a/htdocs/public/payment/paymentok.php b/htdocs/public/payment/paymentok.php index ea86f28a894..499ff2c4e31 100644 --- a/htdocs/public/payment/paymentok.php +++ b/htdocs/public/payment/paymentok.php @@ -412,7 +412,7 @@ if ($ispaymentok) { $paymentTypeId = dol_getIdFromCode($db, $paymentType, 'c_paiement', 'code', 'id', 1); } - dol_syslog("FinalPaymentAmt=".$FinalPaymentAmt." paymentTypeId=".$paymentTypeId." currencyCodeType=".$currencyCodeType, LOG_DEBUG, 0, '_payment'); + dol_syslog("FinalPaymentAmt=".$FinalPaymentAmt." paymentTypeId=".$paymentTypeId." paymentType=".$paymentType." currencyCodeType=".$currencyCodeType, LOG_DEBUG, 0, '_payment'); // Do action only if $FinalPaymentAmt is set (session variable is cleaned after this page to avoid duplicate actions when page is POST a second time) if (!empty($FinalPaymentAmt) && $paymentTypeId > 0) { From 1107a60b58eb690902ebd14b4f52597ae051c077 Mon Sep 17 00:00:00 2001 From: lvessiller Date: Fri, 18 Feb 2022 16:53:55 +0100 Subject: [PATCH 085/255] FIX compute rule in FEC import --- .../class/accountancyimport.class.php | 6 ++--- .../modules/import/import_csv.modules.php | 23 +++++++++++++++++++ .../modules/import/import_xlsx.modules.php | 23 +++++++++++++++++++ htdocs/imports/import.php | 7 +++--- 4 files changed, 53 insertions(+), 6 deletions(-) diff --git a/htdocs/accountancy/class/accountancyimport.class.php b/htdocs/accountancy/class/accountancyimport.class.php index ece843515e2..ea88534b6ed 100644 --- a/htdocs/accountancy/class/accountancyimport.class.php +++ b/htdocs/accountancy/class/accountancyimport.class.php @@ -55,8 +55,8 @@ class AccountancyImport $fieldname = $fieldArr[1]; } - $debit = trim($arrayrecord[11]['val']); - $credit = trim($arrayrecord[12]['val']); + $debit = floatval(trim($arrayrecord[11]['val'])); + $credit = floatval(trim($arrayrecord[12]['val'])); if (!empty($debit)) { $amount = $debit; } else { @@ -86,7 +86,7 @@ class AccountancyImport $fieldname = $fieldArr[1]; } - $debit = trim($arrayrecord[11]['val']); + $debit = floatval(trim($arrayrecord[11]['val'])); if (!empty($debit)) { $sens = 'D'; } else { diff --git a/htdocs/core/modules/import/import_csv.modules.php b/htdocs/core/modules/import/import_csv.modules.php index 35f0e4bc2f9..78c8f5e104f 100644 --- a/htdocs/core/modules/import/import_csv.modules.php +++ b/htdocs/core/modules/import/import_csv.modules.php @@ -736,6 +736,29 @@ class ImportCsv extends ModeleImports $tmp = explode('-', $val, 2); $listfields[] = preg_replace('/^'.preg_quote($alias, '/').'\./', '', $key); $listvalues[] = "'".$tmp[1]."'"; + } elseif (preg_match('/^rule-/', $val)) { + $fieldname = $key; + if (!empty($objimport->array_import_convertvalue[0][$fieldname])) { + if ($objimport->array_import_convertvalue[0][$fieldname]['rule'] == 'compute') { + $file = (empty($objimport->array_import_convertvalue[0][$fieldname]['classfile']) ? $objimport->array_import_convertvalue[0][$fieldname]['file'] : $objimport->array_import_convertvalue[0][$fieldname]['classfile']); + $class = $objimport->array_import_convertvalue[0][$fieldname]['class']; + $method = $objimport->array_import_convertvalue[0][$fieldname]['method']; + $resultload = dol_include_once($file); + if (empty($resultload)) { + dol_print_error('', 'Error trying to call file=' . $file . ', class=' . $class . ', method=' . $method); + break; + } + $classinstance = new $class($this->db); + $res = call_user_func_array(array($classinstance, $method), array(&$arrayrecord, $fieldname, &$listfields, &$listvalues)); + if ($res < 0) { + if (!empty($objimport->array_import_convertvalue[0][$fieldname]['dict'])) $this->errors[$error]['lib'] = $langs->trans('ErrorFieldValueNotIn', $key, end($listvalues), 'code', $langs->transnoentitiesnoconv($objimport->array_import_convertvalue[0][$fieldname]['dict'])); + else $this->errors[$error]['lib'] = 'ErrorFieldValueNotIn'; + $this->errors[$error]['type'] = 'FOREIGNKEY'; + $errorforthistable++; + $error++; + } + } + } } else { $this->errors[$error]['lib'] = 'Bad value of profile setup '.$val.' for array_import_fieldshidden'; $this->errors[$error]['type'] = 'Import profile setup'; diff --git a/htdocs/core/modules/import/import_xlsx.modules.php b/htdocs/core/modules/import/import_xlsx.modules.php index ed14ae31ebb..38c9cd8c56a 100644 --- a/htdocs/core/modules/import/import_xlsx.modules.php +++ b/htdocs/core/modules/import/import_xlsx.modules.php @@ -777,6 +777,29 @@ class ImportXlsx extends ModeleImports $tmp = explode('-', $val, 2); $listfields[] = preg_replace('/^' . preg_quote($alias, '/') . '\./', '', $key); $listvalues[] = "'" . $tmp[1] . "'"; + } elseif (preg_match('/^rule-/', $val)) { + $fieldname = $key; + if (!empty($objimport->array_import_convertvalue[0][$fieldname])) { + if ($objimport->array_import_convertvalue[0][$fieldname]['rule'] == 'compute') { + $file = (empty($objimport->array_import_convertvalue[0][$fieldname]['classfile']) ? $objimport->array_import_convertvalue[0][$fieldname]['file'] : $objimport->array_import_convertvalue[0][$fieldname]['classfile']); + $class = $objimport->array_import_convertvalue[0][$fieldname]['class']; + $method = $objimport->array_import_convertvalue[0][$fieldname]['method']; + $resultload = dol_include_once($file); + if (empty($resultload)) { + dol_print_error('', 'Error trying to call file=' . $file . ', class=' . $class . ', method=' . $method); + break; + } + $classinstance = new $class($this->db); + $res = call_user_func_array(array($classinstance, $method), array(&$arrayrecord, $fieldname, &$listfields, &$listvalues)); + if ($res < 0) { + if (!empty($objimport->array_import_convertvalue[0][$fieldname]['dict'])) $this->errors[$error]['lib'] = $langs->trans('ErrorFieldValueNotIn', $key, end($listvalues), 'code', $langs->transnoentitiesnoconv($objimport->array_import_convertvalue[0][$fieldname]['dict'])); + else $this->errors[$error]['lib'] = 'ErrorFieldValueNotIn'; + $this->errors[$error]['type'] = 'FOREIGNKEY'; + $errorforthistable++; + $error++; + } + } + } } else { $this->errors[$error]['lib'] = 'Bad value of profile setup ' . $val . ' for array_import_fieldshidden'; $this->errors[$error]['type'] = 'Import profile setup'; diff --git a/htdocs/imports/import.php b/htdocs/imports/import.php index ff9b839d1d5..c477df5eb77 100644 --- a/htdocs/imports/import.php +++ b/htdocs/imports/import.php @@ -141,6 +141,7 @@ $endatlinenb = (GETPOST('endatlinenb') ? GETPOST('endatlinenb') : ''); $updatekeys = (GETPOST('updatekeys', 'array') ? GETPOST('updatekeys', 'array') : array()); $separator = (GETPOST('separator', 'nohtml') ? GETPOST('separator', 'nohtml') : (!empty($conf->global->IMPORT_CSV_SEPARATOR_TO_USE) ? $conf->global->IMPORT_CSV_SEPARATOR_TO_USE : ',')); $enclosure = (GETPOST('enclosure', 'nohtml') ? GETPOST('enclosure', 'nohtml') : '"'); +$separator_used = str_replace('\t', "\t", $separator); $objimport = new Import($db); $objimport->load_arrays($user, ($step == 1 ? '' : $datatoimport)); @@ -773,7 +774,7 @@ if ($step == 4 && $datatoimport) { require_once $dir.$file; $obj = new $classname($db, $datatoimport); if ($model == 'csv') { - $obj->separator = $separator; + $obj->separator = $separator_used; $obj->enclosure = $enclosure; } if ($model == 'xlsx') { @@ -1334,7 +1335,7 @@ if ($step == 5 && $datatoimport) { require_once $dir.$file; $obj = new $classname($db, $datatoimport); if ($model == 'csv') { - $obj->separator = $separator; + $obj->separator = $separator_used; $obj->enclosure = $enclosure; } @@ -1783,7 +1784,7 @@ if ($step == 6 && $datatoimport) { require_once $dir.$file; $obj = new $classname($db, $datatoimport); if ($model == 'csv') { - $obj->separator = $separator; + $obj->separator = $separator_used; $obj->enclosure = $enclosure; } From 0517e2e2d33699d3fd2088dd0d51429f8f75108f Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 18 Feb 2022 18:35:21 +0100 Subject: [PATCH 086/255] Fix error --- htdocs/compta/paiement/class/paiement.class.php | 2 +- htdocs/hrm/class/skill.class.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/compta/paiement/class/paiement.class.php b/htdocs/compta/paiement/class/paiement.class.php index a59998f0165..84d1b007e09 100644 --- a/htdocs/compta/paiement/class/paiement.class.php +++ b/htdocs/compta/paiement/class/paiement.class.php @@ -1151,7 +1151,7 @@ class Paiement extends CommonObject */ public function getNomUrl($withpicto = 0, $option = '', $mode = 'withlistofinvoices', $notooltip = 0, $morecss = '') { - global $conf, $langs; + global $conf, $langs, $hookmanager; if (!empty($conf->dol_no_mouse_hover)) { $notooltip = 1; // Force disable tooltips diff --git a/htdocs/hrm/class/skill.class.php b/htdocs/hrm/class/skill.class.php index 448538c39a8..724c14b93c0 100644 --- a/htdocs/hrm/class/skill.class.php +++ b/htdocs/hrm/class/skill.class.php @@ -853,7 +853,7 @@ class Skill extends CommonObject //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : ''); global $action, $hookmanager; - $hookmanager->initHooks(array('jobdao')); + $hookmanager->initHooks(array('skilldao')); $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) { From 5eb4d3408c3c4fd3303002efe6a71e8032ddbc94 Mon Sep 17 00:00:00 2001 From: Romain DESCHAMPS Date: Fri, 18 Feb 2022 19:31:42 +0100 Subject: [PATCH 087/255] Update param_ihm.php --- htdocs/user/param_ihm.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/htdocs/user/param_ihm.php b/htdocs/user/param_ihm.php index 72f9b075be9..0d2729d904f 100644 --- a/htdocs/user/param_ihm.php +++ b/htdocs/user/param_ihm.php @@ -207,6 +207,9 @@ if (!empty($conf->adherent->enabled)) { if (!empty($conf->agenda->enabled)) { $tmparray['comm/action/index.php?mainmenu=agenda&leftmenu='] = 'Agenda'; } +if (!empty($conf->ticket->enabled)) { + $tmparray['ticket/list.php?mainmenu=ticket&leftmenu='] = 'Tickets'; +} $head = user_prepare_head($object); From 05f0f1733d275a393d5aa5192eb8ec53f7485d09 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 18 Feb 2022 21:52:33 +0100 Subject: [PATCH 088/255] Merge branch '15.0' of git@github.com:Dolibarr/dolibarr.git into 15.0 --- htdocs/hrm/class/position.class.php | 1 + 1 file changed, 1 insertion(+) diff --git a/htdocs/hrm/class/position.class.php b/htdocs/hrm/class/position.class.php index d9df0624b0b..ada58998238 100644 --- a/htdocs/hrm/class/position.class.php +++ b/htdocs/hrm/class/position.class.php @@ -853,6 +853,7 @@ class Position extends CommonObject * @param string $keysuffix Prefix string to add into name and id of field (can be used to avoid duplicate names) * @param string $keyprefix Suffix string to add into name and id of field (can be used to avoid duplicate names) * @param string|int $morecss Value for css to define style/length of field. May also be a numeric. + * @param int $nonewbutton Do not show new button * @return string */ public function showInputField($val, $key, $value, $moreparam = '', $keysuffix = '', $keyprefix = '', $morecss = 0, $nonewbutton = 0) From 6b8793e1711269310bf1f044a7d904b4baf548cf Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sat, 19 Feb 2022 00:41:45 +0100 Subject: [PATCH 089/255] Fix sql error on web service --- htdocs/webservices/server_supplier_invoice.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/webservices/server_supplier_invoice.php b/htdocs/webservices/server_supplier_invoice.php index 926fa8f6418..1581d569f27 100644 --- a/htdocs/webservices/server_supplier_invoice.php +++ b/htdocs/webservices/server_supplier_invoice.php @@ -350,8 +350,8 @@ function getSupplierInvoicesForThirdParty($authentication, $idthirdparty) if (!$error) { $linesinvoice = array(); - $sql .= "SELECT f.rowid as facid"; - $sql .= " FROM '.MAIN_DB_PREFIX.'facture_fourn as f"; + $sql = "SELECT f.rowid as facid"; + $sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f"; $sql .= " WHERE f.entity = ".((int) $conf->entity); if ($idthirdparty != 'all') { $sql .= " AND f.fk_soc = ".((int) $idthirdparty); From 996dcdde8262544692b8eb25e04869417f6c0332 Mon Sep 17 00:00:00 2001 From: ptibogxiv Date: Sat, 19 Feb 2022 18:34:53 +0100 Subject: [PATCH 090/255] FIX error with php8 --- htdocs/admin/system/filecheck.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/admin/system/filecheck.php b/htdocs/admin/system/filecheck.php index 1f183e1b730..0d5a5673db1 100644 --- a/htdocs/admin/system/filecheck.php +++ b/htdocs/admin/system/filecheck.php @@ -416,7 +416,7 @@ if (empty($error) && !empty($xml)) { $outexpectedchecksum = ($checksumtoget ? $checksumtoget : $langs->trans("Unknown")); if ($checksumget == $checksumtoget) { - if (count($file_list['added'])) { + if (is_countable($file_list['added'])) { $resultcode = 'warning'; $resultcomment = 'FileIntegrityIsOkButFilesWereAdded'; $outcurrentchecksum = $checksumget.' - '.$langs->trans($resultcomment).''; From 546b3dd4d5d060ef490872890d7322884db96455 Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Sun, 20 Feb 2022 05:17:06 +0100 Subject: [PATCH 091/255] 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++; From b8d82671b3df6d603f75c3553920629e3921eab9 Mon Sep 17 00:00:00 2001 From: ptibogxiv Date: Sun, 20 Feb 2022 10:39:59 +0100 Subject: [PATCH 092/255] Update filecheck.php --- htdocs/admin/system/filecheck.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/admin/system/filecheck.php b/htdocs/admin/system/filecheck.php index 0d5a5673db1..10edae1a24b 100644 --- a/htdocs/admin/system/filecheck.php +++ b/htdocs/admin/system/filecheck.php @@ -416,7 +416,7 @@ if (empty($error) && !empty($xml)) { $outexpectedchecksum = ($checksumtoget ? $checksumtoget : $langs->trans("Unknown")); if ($checksumget == $checksumtoget) { - if (is_countable($file_list['added'])) { + if (is_array($file_list['added']) && count($file_list['added'])) { $resultcode = 'warning'; $resultcomment = 'FileIntegrityIsOkButFilesWereAdded'; $outcurrentchecksum = $checksumget.' - '.$langs->trans($resultcomment).''; From 678c3bdb76c09db995401176c3b9a7de7ec0d1ed Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 20 Feb 2022 18:07:10 +0100 Subject: [PATCH 093/255] Fix switch to login page --- htdocs/main.inc.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/htdocs/main.inc.php b/htdocs/main.inc.php index 3f8da14338b..46315f2d688 100644 --- a/htdocs/main.inc.php +++ b/htdocs/main.inc.php @@ -533,7 +533,10 @@ if ((!defined('NOCSRFCHECK') && empty($dolibarr_nocsrfcheck) && getDolGlobalInt( dol_syslog("--- Access to ".(empty($_SERVER["REQUEST_METHOD"]) ? '' : $_SERVER["REQUEST_METHOD"].' ').$_SERVER["PHP_SELF"]." refused by CSRF protection (invalid token), so we disable POST and some GET parameters - referer=".$_SERVER['HTTP_REFERER'].", action=".GETPOST('action', 'aZ09').", _GET|POST['token']=".GETPOST('token', 'alpha').", _SESSION['token']=".$_SESSION['token'], LOG_WARNING); //print 'Unset POST by CSRF protection in main.inc.php.'; // Do not output anything because this create problems when using the BACK button on browsers. setEventMessages('SecurityTokenHasExpiredSoActionHasBeenCanceledPleaseRetry', null, 'warnings'); - if (isset($_POST['id'])) $savid = ((int) $_POST['id']); + $savid = null; + if (isset($_POST['id'])) { + $savid = ((int) $_POST['id']); + } unset($_POST); //unset($_POST['action']); unset($_POST['massaction']); //unset($_POST['confirm']); unset($_POST['confirmmassaction']); @@ -541,7 +544,10 @@ if ((!defined('NOCSRFCHECK') && empty($dolibarr_nocsrfcheck) && getDolGlobalInt( unset($_GET['action']); unset($_GET['confirmmassaction']); unset($_GET['massaction']); - if (isset($savid)) $_POST['id'] = ((int) $savid); + unset($_GET['token']); // TODO Make a redirect if we have a token in url to remove it ? + if (isset($savid)) { + $_POST['id'] = ((int) $savid); + } } // Note: There is another CSRF protection into the filefunc.inc.php From 3a2fcaae6cddd38d3ded4c2b0dbeb4abead9d9bb Mon Sep 17 00:00:00 2001 From: steve Date: Mon, 21 Feb 2022 10:12:28 +0100 Subject: [PATCH 094/255] wip: SendMail dolGetButtonAction --- htdocs/user/card.php | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/htdocs/user/card.php b/htdocs/user/card.php index be91f302b97..63ced51d852 100644 --- a/htdocs/user/card.php +++ b/htdocs/user/card.php @@ -1827,10 +1827,20 @@ if ($action == 'create' || $action == 'adduserldap') { if (empty($user->socid)) { if (!empty($object->email)) { $langs->load("mails"); - print ''; + // TODO Replace div with dolGetButtonAction + print dolGetButtonAction($langs->trans('SendMail'), '', 'default', $_SERVER['PHP_SELF'] . '?id=' . $object->id . '&action=presend&mode=init#formmailbeforetitle', ''); + //print ''; } else { $langs->load("mails"); - print ''; + // TODO Replace div with dolGetButtonAction + //$params = array( + // 'attr' => array( + // 'title' => $langs->trans('ImpersonateButtonDescription'), + // 'class' => 'classfortooltip' + // ) + //); + print dolGetButtonAction($langs->trans('SendMail'), '', 'default', $_SERVER['PHP_SELF'] . '?id=' . $object->id . '&action=presend&mode=init#formmailbeforetitle', '', $permissiontoadd, $params); + //print ''; } } From 0e3ec0502866ed5f242baf228e2800ab99bceb13 Mon Sep 17 00:00:00 2001 From: steve Date: Mon, 21 Feb 2022 11:12:06 +0100 Subject: [PATCH 095/255] wip: dolGetButtonAction Nomail --- htdocs/user/card.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/user/card.php b/htdocs/user/card.php index 63ced51d852..3f16f690127 100644 --- a/htdocs/user/card.php +++ b/htdocs/user/card.php @@ -1839,7 +1839,7 @@ if ($action == 'create' || $action == 'adduserldap') { // 'class' => 'classfortooltip' // ) //); - print dolGetButtonAction($langs->trans('SendMail'), '', 'default', $_SERVER['PHP_SELF'] . '?id=' . $object->id . '&action=presend&mode=init#formmailbeforetitle', '', $permissiontoadd, $params); + print dolGetButtonAction($langs->trans('SendMail'), '', 'default', $_SERVER['PHP_SELF'] . '?id=' . $object->id . '&action=presend&mode=init#formmailbeforetitle', ''); //print ''; } } From 7b655a1ae2cc79c5da9abe5461fc5131e701fce1 Mon Sep 17 00:00:00 2001 From: atm-greg Date: Mon, 21 Feb 2022 11:25:28 +0100 Subject: [PATCH 096/255] fix missing hooks and line total for totalizable extrafields --- htdocs/reception/list.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/htdocs/reception/list.php b/htdocs/reception/list.php index 8f07d1bede7..9f98202099a 100644 --- a/htdocs/reception/list.php +++ b/htdocs/reception/list.php @@ -491,6 +491,9 @@ $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."delivery as l ON l.rowid = ee.fk_target"; if (!$user->rights->societe->client->voir && !$socid) { // Internal user with no permission to see all $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; } +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldListFrom', $parameters, $object); // Note that $action and $object may have been modified by hook +$sql .= $hookmanager->resPrint; $sql .= " WHERE e.entity IN (".getEntity('reception').")"; if (!$user->rights->societe->client->voir && !$socid) { // Internal user with no permission to see all $sql .= " AND e.fk_soc = sc.fk_soc"; @@ -976,6 +979,9 @@ while ($i < min($num, $limit)) { { }*/ print "\n"; + if (!$i) { + $totalarray['nbfield']++; + } } if (!empty($arrayfields['l.ref']['checked']) || !empty($arrayfields['l.date_delivery']['checked'])) { @@ -1071,6 +1077,13 @@ if ($num == 0) { print ''.$langs->trans("NoRecordFound").''; } +// Show total line +include DOL_DOCUMENT_ROOT.'/core/tpl/list_print_total.tpl.php'; + +$parameters = array('arrayfields'=>$arrayfields, 'sql'=>$sql); +$reshook = $hookmanager->executeHooks('printFieldListFooter', $parameters); // Note that $action and $object may have been modified by hook +print $hookmanager->resPrint; + print ""; print ""; print ''; From 9e6f782907fe8e6cc7d79429a1cb994fc7ed82f4 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 21 Feb 2022 11:26:03 +0100 Subject: [PATCH 097/255] Clean code --- htdocs/core/class/events.class.php | 2 +- htdocs/core/lib/security2.lib.php | 3 ++- htdocs/main.inc.php | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/htdocs/core/class/events.class.php b/htdocs/core/class/events.class.php index 104f1567d44..63b5e5e494b 100644 --- a/htdocs/core/class/events.class.php +++ b/htdocs/core/class/events.class.php @@ -167,7 +167,7 @@ class Events // extends CommonObject $sql .= " '".$this->db->escape(getUserRemoteIP())."',"; $sql .= " ".($this->user_agent ? "'".$this->db->escape(dol_trunc($this->user_agent, 250))."'" : 'NULL').","; $sql .= " '".$this->db->idate($this->dateevent)."',"; - $sql .= " ".($user->id ? "'".$this->db->escape($user->id)."'" : 'NULL').","; + $sql .= " ".($user->id > 0 ? ((int) $user->id) : 'NULL').","; $sql .= " '".$this->db->escape(dol_trunc($this->description, 250))."',"; $sql .= " '".$this->db->escape(dol_getprefix())."'"; $sql .= ")"; diff --git a/htdocs/core/lib/security2.lib.php b/htdocs/core/lib/security2.lib.php index a37a77712c3..e156c83b147 100644 --- a/htdocs/core/lib/security2.lib.php +++ b/htdocs/core/lib/security2.lib.php @@ -187,7 +187,8 @@ if (!function_exists('dol_loginfunction')) { $template_dir = DOL_DOCUMENT_ROOT."/core/tpl/"; } - // Set cookie for timeout management + // Set cookie for timeout management. We set it as a cookie so we will be able to use it to set timeout on next page before the session start + // and the conf file is loaded. $prefix = dol_getprefix(''); $sessiontimeout = 'DOLSESSTIMEOUT_'.$prefix; if (!empty($conf->global->MAIN_SESSION_TIMEOUT)) { diff --git a/htdocs/main.inc.php b/htdocs/main.inc.php index 8ddcce45285..88ed3a12f3a 100644 --- a/htdocs/main.inc.php +++ b/htdocs/main.inc.php @@ -282,7 +282,7 @@ if (!empty($php_session_save_handler) && $php_session_save_handler == 'db') { // Init session. Name of session is specific to Dolibarr instance. // Must be done after the include of filefunc.inc.php so global variables of conf file are defined (like $dolibarr_main_instance_unique_id or $dolibarr_main_force_https). -// Note: the function dol_getprefix is defined into functions.lib.php but may have been defined to return a different key to manage another area to protect. +// Note: the function dol_getprefix() is defined into functions.lib.php but may have been defined to return a different key to manage another area to protect. $prefix = dol_getprefix(''); $sessionname = 'DOLSESSID_'.$prefix; $sessiontimeout = 'DOLSESSTIMEOUT_'.$prefix; From e8c48a06c0822b1b477e212cb77bc73cc6ccf0f7 Mon Sep 17 00:00:00 2001 From: Thomas Negre Date: Thu, 27 Jan 2022 11:26:16 +0100 Subject: [PATCH 098/255] Correct typos in ticket.lib --- htdocs/core/lib/ticket.lib.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/core/lib/ticket.lib.php b/htdocs/core/lib/ticket.lib.php index 3599c17887f..2e70bfba3b9 100644 --- a/htdocs/core/lib/ticket.lib.php +++ b/htdocs/core/lib/ticket.lib.php @@ -476,7 +476,7 @@ function show_ticket_messaging($conf, $langs, $db, $filterobj, $objcon = '', $no if ($sql) { // May not be defined if module Agenda is not enabled and mailing module disabled too $sql .= $db->order($sortfield_new, $sortorder); - dol_syslog("company.lib::show_actions_done", LOG_DEBUG); + dol_syslog("ticket.lib::show_ticket_messaging", LOG_DEBUG); $resql = $db->query($sql); if ($resql) { $i = 0; @@ -491,7 +491,7 @@ function show_ticket_messaging($conf, $langs, $db, $filterobj, $objcon = '', $no $result = $contactaction->fetchResources(); if ($result < 0) { dol_print_error($db); - setEventMessage("company.lib::show_actions_done Error fetch ressource", 'errors'); + setEventMessage("ticket.lib::show_ticket_messaging Error fetch ressource", 'errors'); } //if ($donetodo == 'todo') $sql.= " AND ((a.percent >= 0 AND a.percent < 100) OR (a.percent = -1 AND a.datep > '".$db->idate($now)."'))"; From bf9ca1caaa370504448c966cad9c73539adccc86 Mon Sep 17 00:00:00 2001 From: Thomas Negre Date: Mon, 7 Feb 2022 12:30:47 +0100 Subject: [PATCH 099/255] new : allow to display a warning on untreated tickets. Introduces options TICKET_DELAY_BEFORE_FIRST_RESPONSE and TICKET_DELAY_SINCE_LAST_RESPONSE --- htdocs/ticket/list.php | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/htdocs/ticket/list.php b/htdocs/ticket/list.php index b2548807be4..bfb0c8dcbea 100644 --- a/htdocs/ticket/list.php +++ b/htdocs/ticket/list.php @@ -329,8 +329,6 @@ if (empty($reshook)) { $form = new Form($db); $formTicket = new FormTicket($db); -$now = dol_now(); - $user_temp = new User($db); $socstatic = new Societe($db); @@ -942,6 +940,7 @@ if (isset($extrafields->attributes[$object->table_element]['computed']) && is_ar $i = 0; $totalarray = array(); $totalarray['nbfield'] = 0; +$now = dol_now(); $cacheofoutputfield = array(); while ($i < ($limit ? min($num, $limit) : $num)) { @@ -956,6 +955,7 @@ while ($i < ($limit ? min($num, $limit) : $num)) { // 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'; @@ -1033,6 +1033,26 @@ while ($i < ($limit ? min($num, $limit) : $num)) { } } elseif (in_array($val['type'], array('date', 'datetime', 'timestamp'))) { print $object->showOutputField($val, $key, $db->jdate($obj->$key), ''); + } elseif ($key == 'ref') { + print $object->showOutputField($val, $key, $obj->$key, ''); + + // display a warning on untreated tickets + $is_open = ($object->status != Ticket::STATUS_CLOSED && $object->status != Ticket::STATUS_CANCELED ); + $should_show_warning = (!empty($conf->global->TICKET_DELAY_SINCE_LAST_RESPONSE) || !empty($conf->global->TICKET_DELAY_BEFORE_FIRST_RESPONSE)); + if ($is_open && $should_show_warning) { + $date_last_msg_sent = (int) $object->date_last_msg_sent; + $hour_diff = ($now - $date_last_msg_sent) / 3600 ; + + if (!empty($conf->global->TICKET_DELAY_BEFORE_FIRST_RESPONSE && $date_last_msg_sent == 0)) { + $creation_date = $object->datec; + $hour_diff_creation = ($now - $creation_date) / 3600 ; + if ($hour_diff_creation > $conf->global->TICKET_DELAY_BEFORE_FIRST_RESPONSE) { + print " " . img_picto($langs->trans('Late') . ' : ' . $langs->trans('TicketsDelayForFirstResponseTooLong', $conf->global->TICKET_DELAY_BEFORE_FIRST_RESPONSE), 'warning', 'style="color: red;"', false, 0, 0, '', ''); + } + } elseif (!empty($conf->global->TICKET_DELAY_SINCE_LAST_RESPONSE) && $hour_diff > $conf->global->TICKET_DELAY_SINCE_LAST_RESPONSE) { + print " " . img_picto($langs->trans('Late') . ' : ' . $langs->trans('TicketsDelayFromLastResponseTooLong', $conf->global->TICKET_DELAY_SINCE_LAST_RESPONSE), 'warning'); + } + } } else { // Example: key=fk_soc, obj->key=123 val=array('type'=>'integer', ... $tmp = explode(':', $val['type']); if ($tmp[0] == 'integer' && !empty($tmp[1]) && class_exists($tmp[1])) { From ffbe0946354a8681801ee4b73b8195d40ff6dafa Mon Sep 17 00:00:00 2001 From: Thomas Negre Date: Thu, 27 Jan 2022 17:02:09 +0100 Subject: [PATCH 100/255] Add strings for ticket warnings --- htdocs/langs/en_US/ticket.lang | 2 ++ 1 file changed, 2 insertions(+) diff --git a/htdocs/langs/en_US/ticket.lang b/htdocs/langs/en_US/ticket.lang index 38b199f7260..710ae491973 100644 --- a/htdocs/langs/en_US/ticket.lang +++ b/htdocs/langs/en_US/ticket.lang @@ -244,6 +244,8 @@ TicketNotNotifyTiersAtCreate=Not notify company at create Unread=Unread TicketNotCreatedFromPublicInterface=Not available. Ticket was not created from public interface. ErrorTicketRefRequired=Ticket reference name is required +TicketsDelayForFirstResponseTooLong=Too much time elapsed since ticket opening without any answer. +TicketsDelayFromLastResponseTooLong=Too much time elapsed since last answer on this ticket. # # Logs From ad3f7b531e13f1a43a2bb2c7fe0d395f5a01bb18 Mon Sep 17 00:00:00 2001 From: Thomas Negre Date: Fri, 28 Jan 2022 14:31:11 +0100 Subject: [PATCH 101/255] add constants declarations in the module class --- htdocs/core/modules/modTicket.class.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/htdocs/core/modules/modTicket.class.php b/htdocs/core/modules/modTicket.class.php index 68cb3f45551..0ae6b00b1c3 100644 --- a/htdocs/core/modules/modTicket.class.php +++ b/htdocs/core/modules/modTicket.class.php @@ -107,7 +107,9 @@ class modTicket extends DolibarrModules 1 => array('TICKET_ENABLE_PUBLIC_INTERFACE', 'chaine', '0', 'Enable ticket public interface', 0), 2 => array('TICKET_ADDON', 'chaine', 'mod_ticket_simple', 'Ticket ref module', 0), 3 => array('TICKET_ADDON_PDF_ODT_PATH', 'chaine', 'DOL_DATA_ROOT/doctemplates/tickets', 'Ticket templates ODT/ODS directory for templates', 0), - 4 => array('TICKET_AUTO_READ_WHEN_CREATED_FROM_BACKEND', 'chaine', 0, 'Automatically mark ticket as read when created from backend', 0) + 4 => array('TICKET_AUTO_READ_WHEN_CREATED_FROM_BACKEND', 'chaine', 0, 'Automatically mark ticket as read when created from backend', 0), + 5 => array('TICKET_DELAY_BEFORE_FIRST_RESPONSE', 'chaine', '0', 'Maximum wanted elapsed time before a first answer to a ticket (in hours). Display a warning in tickets list if not respected.', 0), + 6 => array('TICKET_DELAY_SINCE_LAST_RESPONSE', 'chaine', '0', 'Maximum wanted elapsed time between two answers on the same ticket (in hours). Display a warning in tickets list if not respected.', 0) ); From 5d10d6cb781993d879691cabb80b01d922335cc9 Mon Sep 17 00:00:00 2001 From: Thomas Negre Date: Fri, 28 Jan 2022 16:38:31 +0100 Subject: [PATCH 102/255] allow delays configuration from ticket module params --- htdocs/admin/ticket.php | 48 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/htdocs/admin/ticket.php b/htdocs/admin/ticket.php index fc8a5e8e0b9..c36f6ae1d1b 100644 --- a/htdocs/admin/ticket.php +++ b/htdocs/admin/ticket.php @@ -191,6 +191,18 @@ if ($action == 'setvarother') { if (!($res > 0)) { $error++; } + + $param_delay_first_response = GETPOST('delay_first_response', 'int'); + $res = dolibarr_set_const($db, 'TICKET_DELAY_BEFORE_FIRST_RESPONSE', $param_delay_first_response, 'chaine', 0, '', $conf->entity); + if (!($res > 0)) { + $error++; + } + + $param_delay_between_responses = GETPOST('delay_between_responses', 'int'); + $res = dolibarr_set_const($db, 'TICKET_DELAY_SINCE_LAST_RESPONSE', $param_delay_between_responses, 'chaine', 0, '', $conf->entity); + if (!($res > 0)) { + $error++; + } } @@ -503,7 +515,8 @@ print ''; print ''; // Auto assign ticket at user who created it -print ''.$langs->trans("TicketsAutoAssignTicket").''; +print ''; +print ''.$langs->trans("TicketsAutoAssignTicket").''; print ''; if ($conf->use_javascript_ajax) { print ajax_constantonoff('TICKET_AUTO_ASSIGN_USER_CREATE'); @@ -517,12 +530,41 @@ print $form->textwithpicto('', $langs->trans("TicketsAutoAssignTicketHelp"), 1, print ''; print ''; -print '
    '; - if (!$conf->use_javascript_ajax) { print ''; } +// Define wanted maximum time elapsed before answers to tickets +print '
    '; +print ''; + +print ''; +print ''.$langs->trans("TicketsDelayBeforeFirstAnswer").""; +print ' + + + '; +print ''; +print $form->textwithpicto('', $langs->trans("TicketsDelayBeforeFirstAnswerHelp"), 1, 'help'); +print ''; +print ''; + +print ''; +print ''.$langs->trans("TicketsDelayBetweenAnswers").""; +print ' + + + '; +print ''; +print $form->textwithpicto('', $langs->trans("TicketsDelayBetweenAnswersHelp"), 1, 'help'); +print ''; +print ''; + +print '
    '; + +print '
    '; + + // Admin var of module print load_fiche_titre($langs->trans("Notification"), '', ''); From cdbf0bdf6faac8d424731d172307884ca6f1e357 Mon Sep 17 00:00:00 2001 From: Thomas Negre Date: Mon, 31 Jan 2022 09:45:20 +0100 Subject: [PATCH 103/255] add translation strings --- htdocs/langs/en_US/ticket.lang | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/htdocs/langs/en_US/ticket.lang b/htdocs/langs/en_US/ticket.lang index 710ae491973..9dfc4874cc5 100644 --- a/htdocs/langs/en_US/ticket.lang +++ b/htdocs/langs/en_US/ticket.lang @@ -138,6 +138,10 @@ TicketPublicNotificationNewMessageDefaultEmail=Notifications email to (update) TicketPublicNotificationNewMessageDefaultEmailHelp=Send an email to this address for each new message notifications if the ticket doesn't have a user assigned to it or if the user doesn't have any known email. TicketsAutoReadTicket=Automatically mark the ticket as read (when created from backoffice) TicketsAutoReadTicketHelp=Automatically mark the ticket as read when created from backoffice. When ticket is create from the public interface, ticket remains with the status "Not Read". +TicketsDelayBeforeFirstAnswer=A new ticket should receive a first answer before (hours): +TicketsDelayBeforeFirstAnswerHelp=If a new ticket has not received an answer after this time period (in hours), an important warning icon will be displayed in the list view. +TicketsDelayBetweenAnswers=An unresolved ticket should not be unactive during (hours): +TicketsDelayBetweenAnswersHelp=If an unresolved ticket that has already received an answer has not had further interaction after this time period (in hours), a warning icon will be displayed in the list view. # # Index & list page From d769d856e745b8d5c55251a4689822fb2a2a2684 Mon Sep 17 00:00:00 2001 From: Thomas Negre Date: Thu, 10 Feb 2022 11:15:11 +0100 Subject: [PATCH 104/255] fix $object->status not being set. Avoid using $object->fk_statut. --- htdocs/ticket/list.php | 1 + 1 file changed, 1 insertion(+) diff --git a/htdocs/ticket/list.php b/htdocs/ticket/list.php index bfb0c8dcbea..c7f603056b4 100644 --- a/htdocs/ticket/list.php +++ b/htdocs/ticket/list.php @@ -951,6 +951,7 @@ while ($i < ($limit ? min($num, $limit) : $num)) { // Store properties in $object $object->setVarsFromFetchObj($obj); + $object->status = $object->fk_statut; // fk_statut is deprecated // Show here line of result print ''; From 00e6d2786dc7c92abff39e5d909e54532a6acb8b Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 21 Feb 2022 12:21:43 +0100 Subject: [PATCH 105/255] Do not use dol_hash anymore for the name of cookies. --- htdocs/core/lib/functions.lib.php | 25 ++++++++++--------- htdocs/main.inc.php | 3 +-- .../public/eventorganization/attendee_new.php | 1 - .../eventorganization/subscriptionok.php | 2 +- htdocs/public/payment/newpayment.php | 3 --- htdocs/public/payment/paymentok.php | 2 -- htdocs/public/project/index.php | 3 --- htdocs/public/project/suggestbooth.php | 1 - htdocs/public/project/suggestconference.php | 1 - htdocs/public/project/viewandvote.php | 2 +- 10 files changed, 16 insertions(+), 27 deletions(-) diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 236c76e3bf5..86c1cbe0888 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -870,31 +870,32 @@ if (!function_exists('dol_getprefix')) { * Return a prefix to use for this Dolibarr instance, for session/cookie names or email id. * The prefix is unique for instance and avoid conflict between multi-instances, even when having two instances with same root dir * or two instances in same virtual servers. + * This function must not use dol_hash (that is used for password hash) and need to have all context $conf loaded. * * @param string $mode '' (prefix for session name) or 'email' (prefix for email id) * @return string A calculated prefix */ function dol_getprefix($mode = '') { - // If prefix is for email (we need to have $conf alreayd loaded for this case) + // If prefix is for email (we need to have $conf already loaded for this case) if ($mode == 'email') { global $conf; - if (!empty($conf->global->MAIL_PREFIX_FOR_EMAIL_ID)) { // If MAIL_PREFIX_FOR_EMAIL_ID is set (a value initialized with a random value is recommended) + if (!empty($conf->global->MAIL_PREFIX_FOR_EMAIL_ID)) { // If MAIL_PREFIX_FOR_EMAIL_ID is set if ($conf->global->MAIL_PREFIX_FOR_EMAIL_ID != 'SERVER_NAME') { return $conf->global->MAIL_PREFIX_FOR_EMAIL_ID; - } elseif (isset($_SERVER["SERVER_NAME"])) { + } elseif (isset($_SERVER["SERVER_NAME"])) { // If MAIL_PREFIX_FOR_EMAIL_ID is set to 'SERVER_NAME' return $_SERVER["SERVER_NAME"]; } } - // The recommended value (may be not defined for old versions) + // The recommended value if MAIL_PREFIX_FOR_EMAIL_ID is not defined (may be not defined for old versions) if (!empty($conf->file->instance_unique_id)) { - return $conf->file->instance_unique_id; + return sha1('dolibarr'.$conf->file->instance_unique_id); } - // For backward compatibility - return dol_hash(DOL_DOCUMENT_ROOT.DOL_URL_ROOT, '3'); + // For backward compatibility when instance_unique_id is not set + return sha1(DOL_DOCUMENT_ROOT.DOL_URL_ROOT); } // If prefix is for session (no need to have $conf loaded) @@ -903,15 +904,15 @@ if (!function_exists('dol_getprefix')) { // The recommended value (may be not defined for old versions) if (!empty($tmp_instance_unique_id)) { - return $tmp_instance_unique_id; + return sha1('dolibarr'.$tmp_instance_unique_id); } - // For backward compatibility + // For backward compatibility when instance_unique_id is not set if (isset($_SERVER["SERVER_NAME"]) && isset($_SERVER["DOCUMENT_ROOT"])) { - return dol_hash($_SERVER["SERVER_NAME"].$_SERVER["DOCUMENT_ROOT"].DOL_DOCUMENT_ROOT.DOL_URL_ROOT, '3'); + return sha1($_SERVER["SERVER_NAME"].$_SERVER["DOCUMENT_ROOT"].DOL_DOCUMENT_ROOT.DOL_URL_ROOT); + } else { + return sha1(DOL_DOCUMENT_ROOT.DOL_URL_ROOT); } - - return dol_hash(DOL_DOCUMENT_ROOT.DOL_URL_ROOT, '3'); } } diff --git a/htdocs/main.inc.php b/htdocs/main.inc.php index 88ed3a12f3a..093813f5776 100644 --- a/htdocs/main.inc.php +++ b/htdocs/main.inc.php @@ -290,7 +290,6 @@ if (!empty($_COOKIE[$sessiontimeout])) { ini_set('session.gc_maxlifetime', $_COOKIE[$sessiontimeout]); } - // This create lock, released by session_write_close() or end of page. // We need this lock as long as we read/write $_SESSION ['vars']. We can remove lock when finished. if (!defined('NOSESSION')) { @@ -3263,7 +3262,7 @@ if (!function_exists("llxFooter")) { $forceping = GETPOST('forceping', 'alpha'); if (($_SERVER["PHP_SELF"] == DOL_URL_ROOT.'/index.php') || $forceping) { //print ''; - $hash_unique_id = md5('dolibarr'.$conf->file->instance_unique_id); + $hash_unique_id = md5('dolibarr'.$conf->file->instance_unique_id); // Do not use dol_hash(), must not change if salt changes. if (empty($conf->global->MAIN_FIRST_PING_OK_DATE) || (!empty($conf->file->instance_unique_id) && ($hash_unique_id != $conf->global->MAIN_FIRST_PING_OK_ID) && ($conf->global->MAIN_FIRST_PING_OK_ID != 'disabled')) diff --git a/htdocs/public/eventorganization/attendee_new.php b/htdocs/public/eventorganization/attendee_new.php index 55303bcb00e..a7cdd1ceda8 100644 --- a/htdocs/public/eventorganization/attendee_new.php +++ b/htdocs/public/eventorganization/attendee_new.php @@ -56,7 +56,6 @@ require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/paymentterm.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php'; -global $dolibarr_main_instance_unique_id; global $dolibarr_main_url_root; // Init vars diff --git a/htdocs/public/eventorganization/subscriptionok.php b/htdocs/public/eventorganization/subscriptionok.php index 4a81084223d..8acf3daba78 100644 --- a/htdocs/public/eventorganization/subscriptionok.php +++ b/htdocs/public/eventorganization/subscriptionok.php @@ -57,7 +57,7 @@ if (!empty($conf->paypal->enabled)) { require_once DOL_DOCUMENT_ROOT.'/paypal/lib/paypalfunctions.lib.php'; } -global $dolibarr_main_instance_unique_id, $dolibarr_main_url_root, $mysoc; +global $dolibarr_main_url_root, $mysoc; $langs->loadLangs(array("main", "companies", "install", "other", "eventorganization")); diff --git a/htdocs/public/payment/newpayment.php b/htdocs/public/payment/newpayment.php index d25e14288f8..7bb61a708c5 100644 --- a/htdocs/public/payment/newpayment.php +++ b/htdocs/public/payment/newpayment.php @@ -70,9 +70,6 @@ include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; $hookmanager = new HookManager($db); $hookmanager->initHooks(array('newpayment')); -// For encryption -global $dolibarr_main_instance_unique_id; - // Load translation files $langs->loadLangs(array("main", "other", "dict", "bills", "companies", "errors", "paybox", "paypal", "stripe")); // File with generic data diff --git a/htdocs/public/payment/paymentok.php b/htdocs/public/payment/paymentok.php index 499ff2c4e31..9765af89f7e 100644 --- a/htdocs/public/payment/paymentok.php +++ b/htdocs/public/payment/paymentok.php @@ -61,8 +61,6 @@ if (!empty($conf->paypal->enabled)) { require_once DOL_DOCUMENT_ROOT.'/paypal/lib/paypalfunctions.lib.php'; } -global $dolibarr_main_instance_unique_id; - $langs->loadLangs(array("main", "other", "dict", "bills", "companies", "paybox", "paypal")); // Clean parameters diff --git a/htdocs/public/project/index.php b/htdocs/public/project/index.php index 5f450a6c557..0add64bb700 100644 --- a/htdocs/public/project/index.php +++ b/htdocs/public/project/index.php @@ -54,9 +54,6 @@ include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; $hookmanager = new HookManager($db); $hookmanager->initHooks(array('newpayment')); -// For encryption -global $dolibarr_main_instance_unique_id; - // Load translation files $langs->loadLangs(array("other", "dict", "bills", "companies", "errors", "paybox", "paypal", "stripe")); // File with generic data diff --git a/htdocs/public/project/suggestbooth.php b/htdocs/public/project/suggestbooth.php index 39c2a57700e..cb1b1089b0c 100644 --- a/htdocs/public/project/suggestbooth.php +++ b/htdocs/public/project/suggestbooth.php @@ -56,7 +56,6 @@ require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php'; require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/paymentterm.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; -global $dolibarr_main_instance_unique_id; global $dolibarr_main_url_root; // Init vars diff --git a/htdocs/public/project/suggestconference.php b/htdocs/public/project/suggestconference.php index b97777c3a9a..22589c941d2 100644 --- a/htdocs/public/project/suggestconference.php +++ b/htdocs/public/project/suggestconference.php @@ -56,7 +56,6 @@ require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php'; require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/paymentterm.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; -global $dolibarr_main_instance_unique_id; global $dolibarr_main_url_root; // Init vars diff --git a/htdocs/public/project/viewandvote.php b/htdocs/public/project/viewandvote.php index e680df15a1c..805eb8cfdd1 100644 --- a/htdocs/public/project/viewandvote.php +++ b/htdocs/public/project/viewandvote.php @@ -56,7 +56,7 @@ $hookmanager = new HookManager($db); $hookmanager->initHooks(array('newpayment')); // For encryption -global $dolibarr_main_instance_unique_id, $dolibarr_main_url_root; +global $dolibarr_main_url_root; // Load translation files $langs->loadLangs(array("main", "other", "dict", "bills", "companies", "errors", "paybox", "paypal", "stripe")); // File with generic data From c78ec56c8f6e035886f85d98b0764c91da04807d Mon Sep 17 00:00:00 2001 From: steve Date: Mon, 21 Feb 2022 14:43:00 +0100 Subject: [PATCH 106/255] feat: dolGetButtonAction for sendmail --- htdocs/user/card.php | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/htdocs/user/card.php b/htdocs/user/card.php index 3f16f690127..dbc93bd0a2c 100644 --- a/htdocs/user/card.php +++ b/htdocs/user/card.php @@ -1825,23 +1825,21 @@ if ($action == 'create' || $action == 'adduserldap') { $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook if (empty($reshook)) { if (empty($user->socid)) { + $canSendMail = false; + $params = array( + 'attr' => array( + 'title' => $langs->trans('SendMail'), + 'class' => 'classfortooltip' + ) + ); if (!empty($object->email)) { $langs->load("mails"); - // TODO Replace div with dolGetButtonAction - print dolGetButtonAction($langs->trans('SendMail'), '', 'default', $_SERVER['PHP_SELF'] . '?id=' . $object->id . '&action=presend&mode=init#formmailbeforetitle', ''); - //print ''; + $canSendMail = true; } else { $langs->load("mails"); - // TODO Replace div with dolGetButtonAction - //$params = array( - // 'attr' => array( - // 'title' => $langs->trans('ImpersonateButtonDescription'), - // 'class' => 'classfortooltip' - // ) - //); - print dolGetButtonAction($langs->trans('SendMail'), '', 'default', $_SERVER['PHP_SELF'] . '?id=' . $object->id . '&action=presend&mode=init#formmailbeforetitle', ''); - //print ''; + $params['attr']['title'] = $langs->trans('NoEMail'); } + print dolGetButtonAction($langs->trans('SendMail'), '', 'default', $_SERVER['PHP_SELF'] . '?id=' . $object->id . '&action=presend&mode=init#formmailbeforetitle', '', $canSendMail, $params); } if ($caneditfield && (empty($conf->multicompany->enabled) || !$user->entity || ($object->entity == $conf->entity) || ($conf->global->MULTICOMPANY_TRANSVERSE_MODE && $conf->entity == 1))) { From 2e02b3fcae1ccfd42183f83f58bc42058c57140f Mon Sep 17 00:00:00 2001 From: atm-lena Date: Mon, 21 Feb 2022 14:58:47 +0100 Subject: [PATCH 107/255] Ajout table "llx_inventory_extrafields" --- .../install/mysql/migration/15.0.0-16.0.0.sql | 9 ++++++- .../tables/llx_inventory_extrafields.key.sql | 21 +++++++++++++++ .../tables/llx_inventory_extrafields.sql | 27 +++++++++++++++++++ 3 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 htdocs/install/mysql/tables/llx_inventory_extrafields.key.sql create mode 100644 htdocs/install/mysql/tables/llx_inventory_extrafields.sql diff --git a/htdocs/install/mysql/migration/15.0.0-16.0.0.sql b/htdocs/install/mysql/migration/15.0.0-16.0.0.sql index b78e53bd287..cbf3c8fadc5 100644 --- a/htdocs/install/mysql/migration/15.0.0-16.0.0.sql +++ b/htdocs/install/mysql/migration/15.0.0-16.0.0.sql @@ -237,4 +237,11 @@ ALTER TABLE llx_advtargetemailing RENAME TO llx_mailing_advtarget; ALTER TABLE llx_mailing ADD UNIQUE uk_mailing(titre, entity); - +create table llx_inventory_extrafields +( + rowid integer AUTO_INCREMENT PRIMARY KEY, + tms timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + fk_object integer NOT NULL, + import_key varchar(14) -- import key +) ENGINE=innodb; +ALTER TABLE llx_inventory_extrafields ADD INDEX idx_inventory_extrafields (fk_object); diff --git a/htdocs/install/mysql/tables/llx_inventory_extrafields.key.sql b/htdocs/install/mysql/tables/llx_inventory_extrafields.key.sql new file mode 100644 index 00000000000..ecfd1de723e --- /dev/null +++ b/htdocs/install/mysql/tables/llx_inventory_extrafields.key.sql @@ -0,0 +1,21 @@ +-- =================================================================== +-- Copyright (C) 2022 Laurent Destailleur +-- Copyright (C) 2022 ATM Consulting +-- +-- 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 . +-- +-- =================================================================== + + +ALTER TABLE llx_inventory_extrafields ADD INDEX idx_inventory_extrafields (fk_object); diff --git a/htdocs/install/mysql/tables/llx_inventory_extrafields.sql b/htdocs/install/mysql/tables/llx_inventory_extrafields.sql new file mode 100644 index 00000000000..f6a6a59e0a1 --- /dev/null +++ b/htdocs/install/mysql/tables/llx_inventory_extrafields.sql @@ -0,0 +1,27 @@ +-- ======================================================================== +-- Copyright (C) 2022 Laurent Destailleur +-- Copyright (C) 2022 ATM Consulting + +-- 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 . +-- +-- ======================================================================== + +create table llx_inventory_extrafields +( + rowid integer AUTO_INCREMENT PRIMARY KEY, + tms timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + fk_object integer NOT NULL, + import_key varchar(14) -- import key +) ENGINE=innodb; + From 8bbbc843eb66afaa40e0ae9772a554f7d5b8c88d Mon Sep 17 00:00:00 2001 From: atm-lena Date: Mon, 21 Feb 2022 15:20:22 +0100 Subject: [PATCH 108/255] =?UTF-8?q?Ajout=20onglet=20param=C3=A8tres=20"Inv?= =?UTF-8?q?entaire=20extrafields"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- htdocs/core/lib/stock.lib.php | 5 + .../product/admin/inventory_extrafields.php | 123 ++++++++++++++++++ 2 files changed, 128 insertions(+) create mode 100644 htdocs/product/admin/inventory_extrafields.php diff --git a/htdocs/core/lib/stock.lib.php b/htdocs/core/lib/stock.lib.php index 066bf2165be..c6b1bdefe6c 100644 --- a/htdocs/core/lib/stock.lib.php +++ b/htdocs/core/lib/stock.lib.php @@ -114,6 +114,11 @@ function stock_admin_prepare_head() $head[$h][2] = 'stockMouvementAttributes'; $h++; + $head[$h][0] = DOL_URL_ROOT.'/product/admin/inventory_extrafields.php'; + $head[$h][1] = $langs->trans("InventoryExtraFields"); + $head[$h][2] = 'inventoryAttributes'; + $h++; + complete_head_from_modules($conf, $langs, null, $head, $h, 'stock_admin', 'remove'); return $head; diff --git a/htdocs/product/admin/inventory_extrafields.php b/htdocs/product/admin/inventory_extrafields.php new file mode 100644 index 00000000000..c4566c60741 --- /dev/null +++ b/htdocs/product/admin/inventory_extrafields.php @@ -0,0 +1,123 @@ + + * 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 + * + * 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/product/admin/inventory_extrafields.php + * \ingroup stock + * \brief Page to setup extra fields of inventory + */ + +// Load Dolibarr environment +$res = 0; +// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined) +if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) $res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php"; +// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME +$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME']; $tmp2 = realpath(__FILE__); $i = strlen($tmp) - 1; $j = strlen($tmp2) - 1; +while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) { $i--; $j--; } +if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) $res = @include substr($tmp, 0, ($i + 1))."/main.inc.php"; +if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) $res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php"; +// Try main.inc.php using relative path +if (!$res && file_exists("../../main.inc.php")) $res = @include "../../main.inc.php"; +if (!$res && file_exists("../../../main.inc.php")) $res = @include "../../../main.inc.php"; +if (!$res) die("Include of main fails"); + +require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/stock.lib.php'; + +// Load translation files required by the page +$langs->loadLangs(array('stock@stock', 'admin')); + +$extrafields = new ExtraFields($db); +$form = new Form($db); + +// List of supported format +$tmptype2label = ExtraFields::$type2label; +$type2label = array(''); +foreach ($tmptype2label as $key => $val) $type2label[$key] = $langs->transnoentitiesnoconv($val); + +$action = GETPOST('action', 'aZ09'); +$attrname = GETPOST('attrname', 'alpha'); +$elementtype = 'inventory'; //Must be the $table_element of the class that manage extrafield + +if (!$user->admin) accessforbidden(); + + +/* + * Actions + */ + +require DOL_DOCUMENT_ROOT.'/core/actions_extrafields.inc.php'; + + + +/* + * View + */ + + +llxHeader('', $langs->trans("InventorySetup"), $help_url); + + +$linkback = ''.$langs->trans("BackToModuleList").''; +print load_fiche_titre($langs->trans("StockSetup"), $linkback, 'title_setup'); + + +$head = stock_admin_prepare_head(); + +print dol_get_fiche_head($head, 'inventoryAttributes', $langs->trans("InventoryExtraFields"), -1, 'account'); + +require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_view.tpl.php'; + +print dol_get_fiche_end(); + + +// Buttons +if ($action != 'create' && $action != 'edit') { + print '
    '; + print "".$langs->trans("NewAttribute").""; + print "
    "; +} + + +/* + * Creation of an optional field + */ +if ($action == 'create') { + print '
    '; + print load_fiche_titre($langs->trans('NewAttribute')); + + require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_add.tpl.php'; +} + +/* + * Edition of an optional field + */ +if ($action == 'edit' && !empty($attrname)) { + print "
    "; + print load_fiche_titre($langs->trans("FieldEdition", $attrname)); + + require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_edit.tpl.php'; +} + +// End of page +llxFooter(); +$db->close(); From dd6d0a118a74915c33d93768e3d2619697f65857 Mon Sep 17 00:00:00 2001 From: atm-lena Date: Mon, 21 Feb 2022 15:28:38 +0100 Subject: [PATCH 109/255] Translation --- htdocs/langs/en_US/admin.lang | 3 ++- htdocs/langs/en_US/products.lang | 1 + htdocs/product/admin/inventory_extrafields.php | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang index 1e94ecbfdf0..426e1186868 100644 --- a/htdocs/langs/en_US/admin.lang +++ b/htdocs/langs/en_US/admin.lang @@ -2222,4 +2222,5 @@ EachTerminalHasItsOwnCounter=Each terminal use its own counter. FillAndSaveAccountIdAndSecret=Fill and save account ID and secret first PreviousHash=Previous hash LateWarningAfter="Late" warning after -TemplateforBusinessCards=Template for a business card in different size \ No newline at end of file +TemplateforBusinessCards=Template for a business card in different size +InventorySetup= Inventory Setup diff --git a/htdocs/langs/en_US/products.lang b/htdocs/langs/en_US/products.lang index 14715670882..960bf02eb46 100644 --- a/htdocs/langs/en_US/products.lang +++ b/htdocs/langs/en_US/products.lang @@ -411,3 +411,4 @@ Rank=Rank SwitchOnSaleStatus=Switch on sale status SwitchOnPurchaseStatus=Switch on purchase status StockMouvementExtraFields= Extra Fields (stock mouvement) +InventoryExtraFields= Extra Fields (inventory) diff --git a/htdocs/product/admin/inventory_extrafields.php b/htdocs/product/admin/inventory_extrafields.php index c4566c60741..d21328da336 100644 --- a/htdocs/product/admin/inventory_extrafields.php +++ b/htdocs/product/admin/inventory_extrafields.php @@ -78,7 +78,7 @@ llxHeader('', $langs->trans("InventorySetup"), $help_url); $linkback = ''.$langs->trans("BackToModuleList").''; -print load_fiche_titre($langs->trans("StockSetup"), $linkback, 'title_setup'); +print load_fiche_titre($langs->trans("InventorySetup"), $linkback, 'title_setup'); $head = stock_admin_prepare_head(); From 5647a0436991bdae03f37bcd3c20da6512c1e3e1 Mon Sep 17 00:00:00 2001 From: BENKE Charlene <1179011+defrance@users.noreply.github.com> Date: Mon, 21 Feb 2022 16:50:12 +0100 Subject: [PATCH 110/255] fix : bad redirection after create we have __ID__ on url redirect, so repplace it with the $id value --- htdocs/product/stock/card.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/htdocs/product/stock/card.php b/htdocs/product/stock/card.php index 8389d63e843..c784ff3317e 100644 --- a/htdocs/product/stock/card.php +++ b/htdocs/product/stock/card.php @@ -159,6 +159,8 @@ if (empty($reshook)) { $categories = GETPOST('categories', 'array'); $object->setCategories($categories); if (!empty($backtopage)) { + + $backtopage = str_replace("__ID__", $id, $backtopage); header("Location: ".$backtopage); exit; } else { From 97ed94fbda6d76b68c2db0c3399731a18754f981 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 21 Feb 2022 16:54:07 +0100 Subject: [PATCH 111/255] NEW Support html content for multiselect component. --- htdocs/categories/edit.php | 2 ++ htdocs/core/class/html.form.class.php | 10 ++++------ htdocs/theme/eldy/global.inc.php | 4 ++++ htdocs/theme/md/style.css.php | 4 ++++ 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/htdocs/categories/edit.php b/htdocs/categories/edit.php index 2b3ffc95c41..518889b85b3 100644 --- a/htdocs/categories/edit.php +++ b/htdocs/categories/edit.php @@ -178,7 +178,9 @@ print ''; // Parent category print ''.$langs->trans("In").''; +print img_picto('', 'category', 'class="pictofixedwidth"'); print $form->select_all_categories($type, $object->fk_parent, 'parent', 64, $object->id); +print ajax_combobox('parent'); print ''; $parameters = array(); diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 8f112b9aa98..fa7fb264995 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -8123,12 +8123,9 @@ class Form $out .= "\n".''; - print ' - '.$langs->trans("ShowHideDetails").''; + print ' - '.$langs->trans("ShowHideDetails").''; //} print ''."\n"; diff --git a/htdocs/install/default.css b/htdocs/install/default.css index d18e54c0c1c..e7bbe6c7771 100644 --- a/htdocs/install/default.css +++ b/htdocs/install/default.css @@ -32,6 +32,10 @@ vertical-align: middle; } +.right { + text-align: right; +} + .opacitymedium { opacity: 0.5; } diff --git a/htdocs/install/upgrade.php b/htdocs/install/upgrade.php index 53cd1755dda..25dd1ee84fd 100644 --- a/htdocs/install/upgrade.php +++ b/htdocs/install/upgrade.php @@ -235,8 +235,12 @@ if (!GETPOST('action', 'aZ09') || preg_match('/upgrade/i', GETPOST('action', 'aZ // Force l'affichage de la progression if ($ok) { - print ''.$langs->trans("PleaseBePatient").''; + print ''.$langs->trans("PleaseBePatient").''; + print ''; + flush(); + + print ''; } @@ -401,6 +405,7 @@ if (!GETPOST('action', 'aZ09') || preg_match('/upgrade/i', GETPOST('action', 'aZ } } + if (empty($actiondone)) { print '
    '.$langs->trans("ErrorWrongParameters").'
    '; } From c7077ef1d7d7d61f248e50f419197efc330084ab Mon Sep 17 00:00:00 2001 From: Steve Date: Wed, 23 Feb 2022 14:49:12 +0100 Subject: [PATCH 145/255] fix: send mail title --- htdocs/user/card.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/user/card.php b/htdocs/user/card.php index 3b1567bacfc..64d698e2615 100644 --- a/htdocs/user/card.php +++ b/htdocs/user/card.php @@ -1833,7 +1833,7 @@ if ($action == 'create' || $action == 'adduserldap') { $canSendMail = false; $params = array( 'attr' => array( - 'title' => $langs->trans('SendMail'), + 'title' => '', 'class' => 'classfortooltip' ) ); From b99557e60c0a65775c5ecface5a1800d61be681d Mon Sep 17 00:00:00 2001 From: Steve Date: Wed, 23 Feb 2022 14:59:39 +0100 Subject: [PATCH 146/255] fix: feedback travis --- htdocs/user/card.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/user/card.php b/htdocs/user/card.php index 64d698e2615..0c2c667a46d 100644 --- a/htdocs/user/card.php +++ b/htdocs/user/card.php @@ -1938,7 +1938,7 @@ if ($action == 'create' || $action == 'adduserldap') { - //Select mail models is same action as presend + // Select mail models is same action as presend if (GETPOST('modelselected')) { $action = 'presend'; } From 6047e4e90be3bdf6819ae7d50d106ba8711ad98f Mon Sep 17 00:00:00 2001 From: Steve Date: Wed, 23 Feb 2022 15:06:58 +0100 Subject: [PATCH 147/255] fix: travis + stickler --- htdocs/user/card.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/user/card.php b/htdocs/user/card.php index 0c2c667a46d..64d698e2615 100644 --- a/htdocs/user/card.php +++ b/htdocs/user/card.php @@ -1938,7 +1938,7 @@ if ($action == 'create' || $action == 'adduserldap') { - // Select mail models is same action as presend + //Select mail models is same action as presend if (GETPOST('modelselected')) { $action = 'presend'; } From bd6c547b4d6621593759c11413a5265fad761599 Mon Sep 17 00:00:00 2001 From: Steve Date: Wed, 23 Feb 2022 15:20:45 +0100 Subject: [PATCH 148/255] fix: merge develop --- htdocs/user/card.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/user/card.php b/htdocs/user/card.php index 64d698e2615..0c2c667a46d 100644 --- a/htdocs/user/card.php +++ b/htdocs/user/card.php @@ -1938,7 +1938,7 @@ if ($action == 'create' || $action == 'adduserldap') { - //Select mail models is same action as presend + // Select mail models is same action as presend if (GETPOST('modelselected')) { $action = 'presend'; } From ed6f4b4ee1a0cf96ec64427623c41ff0055fd2b4 Mon Sep 17 00:00:00 2001 From: atm-lena Date: Wed, 23 Feb 2022 15:33:51 +0100 Subject: [PATCH 149/255] Display Salary Paiement on compta report --- htdocs/compta/resultat/clientfourn.php | 4 +++- htdocs/compta/resultat/index.php | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/htdocs/compta/resultat/clientfourn.php b/htdocs/compta/resultat/clientfourn.php index b5aca49aaae..f650244d677 100644 --- a/htdocs/compta/resultat/clientfourn.php +++ b/htdocs/compta/resultat/clientfourn.php @@ -857,7 +857,7 @@ if ($modecompta == 'BOOKKEEPING') { if ($modecompta == 'CREANCES-DETTES' || $modecompta == 'RECETTES-DEPENSES') { if ($modecompta == 'CREANCES-DETTES') { - $column = 'p.datev'; + $column = 'b.datev'; } else { $column = 'p.datep'; } @@ -865,6 +865,7 @@ if ($modecompta == 'BOOKKEEPING') { $sql = "SELECT u.rowid, u.firstname, u.lastname, s.fk_user as fk_user, p.label as label, date_format($column,'%Y-%m') as dm, sum(p.amount) as amount"; $sql .= " FROM ".MAIN_DB_PREFIX."payment_salary as p"; $sql .= " INNER JOIN ".MAIN_DB_PREFIX."salary as s ON s.rowid=p.fk_salary"; + $sql .= " INNER JOIN ".MAIN_DB_PREFIX."bank as b ON p.fk_bank=b.rowid"; $sql .= " INNER JOIN ".MAIN_DB_PREFIX."user as u ON u.rowid=s.fk_user"; $sql .= " WHERE p.entity IN (".getEntity('payment_salary').")"; if (!empty($date_start) && !empty($date_end)) { @@ -876,6 +877,7 @@ if ($modecompta == 'BOOKKEEPING') { $sql .= " UNION "; $sql .= " SELECT u.rowid, u.firstname, u.lastname, p.fk_user as fk_user, p.label as label, date_format($column,'%Y-%m') as dm, sum(p.amount) as amount"; $sql .= " FROM ".MAIN_DB_PREFIX."payment_salary as p"; + $sql .= " INNER JOIN ".MAIN_DB_PREFIX."bank as b ON p.fk_bank=b.rowid"; $sql .= " INNER JOIN ".MAIN_DB_PREFIX."user as u ON u.rowid=p.fk_user"; $sql .= " WHERE p.entity IN (".getEntity('payment_salary').")"; if (!empty($date_start) && !empty($date_end)) { diff --git a/htdocs/compta/resultat/index.php b/htdocs/compta/resultat/index.php index 2d4ea6fc9e0..5f10013f294 100644 --- a/htdocs/compta/resultat/index.php +++ b/htdocs/compta/resultat/index.php @@ -611,7 +611,7 @@ if (!empty($conf->tax->enabled) && ($modecompta == 'CREANCES-DETTES' || $modecom if (!empty($conf->salaries->enabled) && ($modecompta == 'CREANCES-DETTES' || $modecompta == "RECETTES-DEPENSES")) { if ($modecompta == 'CREANCES-DETTES') { - $column = 'p.datev'; + $column = 'b.datev'; } if ($modecompta == "RECETTES-DEPENSES") { $column = 'p.datep'; @@ -621,6 +621,7 @@ if (!empty($conf->salaries->enabled) && ($modecompta == 'CREANCES-DETTES' || $mo $subtotal_ttc = 0; $sql = "SELECT p.label as nom, date_format(".$column.",'%Y-%m') as dm, sum(p.amount) as amount"; $sql .= " FROM ".MAIN_DB_PREFIX."payment_salary as p"; + $sql .= " INNER JOIN ".MAIN_DB_PREFIX."bank as b ON p.fk_bank=b.rowid"; $sql .= " WHERE p.entity IN (".getEntity('payment_salary').")"; if (!empty($date_start) && !empty($date_end)) { $sql .= " AND ".$column." >= '".$db->idate($date_start)."' AND ".$column." <= '".$db->idate($date_end)."'"; From f70e97bafac657e5bce22c8e3bfe99999d247a48 Mon Sep 17 00:00:00 2001 From: Steve Date: Wed, 23 Feb 2022 15:45:50 +0100 Subject: [PATCH 150/255] fix: travis --- htdocs/user/card.php | 1 - 1 file changed, 1 deletion(-) diff --git a/htdocs/user/card.php b/htdocs/user/card.php index 0c2c667a46d..762da1f83cc 100644 --- a/htdocs/user/card.php +++ b/htdocs/user/card.php @@ -1823,7 +1823,6 @@ if ($action == 'create' || $action == 'adduserldap') { /* * Buttons actions */ - print '
    '; $parameters = array(); From 80d85b42395c8d3978a14410d901c0ca5d899082 Mon Sep 17 00:00:00 2001 From: Thomas Negre Date: Wed, 23 Feb 2022 16:17:18 +0100 Subject: [PATCH 151/255] db migration: add a column in llx_bank_account to store the expected SEPA format concerning PmtTpInf. --- htdocs/install/mysql/migration/15.0.0-16.0.0.sql | 2 ++ 1 file changed, 2 insertions(+) diff --git a/htdocs/install/mysql/migration/15.0.0-16.0.0.sql b/htdocs/install/mysql/migration/15.0.0-16.0.0.sql index cbf3c8fadc5..957a16152b8 100644 --- a/htdocs/install/mysql/migration/15.0.0-16.0.0.sql +++ b/htdocs/install/mysql/migration/15.0.0-16.0.0.sql @@ -245,3 +245,5 @@ create table llx_inventory_extrafields import_key varchar(14) -- import key ) ENGINE=innodb; ALTER TABLE llx_inventory_extrafields ADD INDEX idx_inventory_extrafields (fk_object); + +ALTER TABLE llx_bank_account ADD COLUMN pti_in_ctti integer DEFAULT 0 AFTER domiciliation; From 6136de6a4afe3cc124d86788750f706df48c645c Mon Sep 17 00:00:00 2001 From: Thomas Negre Date: Wed, 23 Feb 2022 12:11:40 +0100 Subject: [PATCH 152/255] add 'pti_in_ctti' property for Account object. Update related methods. --- htdocs/compta/bank/class/account.class.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/htdocs/compta/bank/class/account.class.php b/htdocs/compta/bank/class/account.class.php index cb2de5aca46..f0f1b54dd7b 100644 --- a/htdocs/compta/bank/class/account.class.php +++ b/htdocs/compta/bank/class/account.class.php @@ -145,6 +145,12 @@ class Account extends CommonObject */ public $iban_prefix; + /** + * XML SEPA format: place Payment Type Information (PmtTpInf) in Credit Transfer Transaction Information (CdtTrfTxInf) + * @var int + */ + public $pti_in_ctti = 0; + /** * Name of account holder * @var string @@ -680,6 +686,7 @@ class Account extends CommonObject $sql .= ", bic"; $sql .= ", iban_prefix"; $sql .= ", domiciliation"; + $sql .= ", pti_in_ctti"; $sql .= ", proprio"; $sql .= ", owner_address"; $sql .= ", currency_code"; @@ -706,6 +713,7 @@ class Account extends CommonObject $sql .= ", '".$this->db->escape($this->bic)."'"; $sql .= ", '".$this->db->escape($this->iban)."'"; $sql .= ", '".$this->db->escape($this->domiciliation)."'"; + $sql .= ", ".((int) $this->pti_in_ctti); $sql .= ", '".$this->db->escape($this->proprio)."'"; $sql .= ", '".$this->db->escape($this->owner_address)."'"; $sql .= ", '".$this->db->escape($this->currency_code)."'"; @@ -828,6 +836,7 @@ class Account extends CommonObject $sql .= ",bic='".$this->db->escape($this->bic)."'"; $sql .= ",iban_prefix = '".$this->db->escape($this->iban)."'"; $sql .= ",domiciliation='".$this->db->escape($this->domiciliation)."'"; + $sql .= ",pti_in_ctti=".((int) $this->pti_in_ctti); $sql .= ",proprio = '".$this->db->escape($this->proprio)."'"; $sql .= ",owner_address = '".$this->db->escape($this->owner_address)."'"; @@ -949,7 +958,7 @@ class Account extends CommonObject $sql = "SELECT ba.rowid, ba.ref, ba.label, ba.bank, ba.number, ba.courant, ba.clos, ba.rappro, ba.url,"; $sql .= " ba.code_banque, ba.code_guichet, ba.cle_rib, ba.bic, ba.iban_prefix as iban,"; - $sql .= " ba.domiciliation, ba.proprio, ba.owner_address, ba.state_id, ba.fk_pays as country_id,"; + $sql .= " ba.domiciliation, ba.pti_in_ctti, ba.proprio, ba.owner_address, ba.state_id, ba.fk_pays as country_id,"; $sql .= " ba.account_number, ba.fk_accountancy_journal, ba.currency_code,"; $sql .= " ba.min_allowed, ba.min_desired, ba.comment,"; $sql .= " ba.datec as date_creation, ba.tms as date_update, ba.ics, ba.ics_transfer,"; @@ -992,6 +1001,7 @@ class Account extends CommonObject $this->bic = $obj->bic; $this->iban = $obj->iban; $this->domiciliation = $obj->domiciliation; + $this->pti_in_ctti = $obj->pti_in_ctti; $this->proprio = $obj->proprio; $this->owner_address = $obj->owner_address; From 7a13112ad8e142e51130c718cd1c7007d7708486 Mon Sep 17 00:00:00 2001 From: Thomas Negre Date: Wed, 23 Feb 2022 11:41:42 +0100 Subject: [PATCH 153/255] bank card interface modification to allow configuration of payment type information in SEPA XML --- htdocs/compta/bank/card.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/htdocs/compta/bank/card.php b/htdocs/compta/bank/card.php index 4e37268756d..0d9ea0ecfb3 100644 --- a/htdocs/compta/bank/card.php +++ b/htdocs/compta/bank/card.php @@ -124,6 +124,7 @@ if (empty($reshook)) { $object->bic = trim(GETPOST("bic")); $object->iban = trim(GETPOST("iban")); $object->domiciliation = trim(GETPOST("domiciliation", "nohtml")); + $object->pti_in_ctti = empty(GETPOST("pti_in_ctti")) ? 0 : 1; $object->proprio = trim(GETPOST("proprio", 'alphanohtml')); $object->owner_address = trim(GETPOST("owner_address", 'nohtml')); @@ -224,6 +225,7 @@ if (empty($reshook)) { $object->bic = trim(GETPOST("bic")); $object->iban = trim(GETPOST("iban")); $object->domiciliation = trim(GETPOST("domiciliation", "nohtml")); + $object->pti_in_ctti = empty(GETPOST("pti_in_ctti")) ? 0 : 1; $object->proprio = trim(GETPOST("proprio", 'alphanohtml')); $object->owner_address = trim(GETPOST("owner_address", 'nohtml')); @@ -537,6 +539,11 @@ if ($action == 'create') { print '
    '; print ''; + print ''; + print ''; + print ''; // Duration - Time spent print 'attributes[$object->table_element]['label'])) { print ' trextrafields_collapse_last'; } - print '">'; + print '"'; + if (empty($extrafields->expand_display[$collapse_group])) { + print ' style="display: none;"'; + } + print '>'; $extrafields_collapse_num_old = $extrafields_collapse_num; print ''; } print ''; print ''; print ''; @@ -394,12 +417,11 @@ if ($result) { print ''; // Accounting account affected - print ''; - print ''; print ""; diff --git a/htdocs/accountancy/expensereport/list.php b/htdocs/accountancy/expensereport/list.php index 863001c3bc0..908159cbe1c 100644 --- a/htdocs/accountancy/expensereport/list.php +++ b/htdocs/accountancy/expensereport/list.php @@ -1,6 +1,6 @@ - * Copyright (C) 2013-2017 Alexandre Spangaro + * Copyright (C) 2013-2022 Alexandre Spangaro * Copyright (C) 2014-2015 Ari Elbaz (elarifr) * Copyright (C) 2013-2014 Florian Henry * Copyright (C) 2014 Juanjo Menent s @@ -30,9 +30,9 @@ require '../../main.inc.php'; require_once DOL_DOCUMENT_ROOT.'/expensereport/class/expensereport.class.php'; require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formaccounting.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingaccount.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php'; -require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; // Load translation files required by the page @@ -59,9 +59,14 @@ $search_desc = GETPOST('search_desc', 'alpha'); $search_amount = GETPOST('search_amount', 'alpha'); $search_account = GETPOST('search_account', 'alpha'); $search_vat = GETPOST('search_vat', 'alpha'); -$search_day = GETPOST("search_day", "int"); -$search_month = GETPOST("search_month", "int"); -$search_year = GETPOST("search_year", "int"); +$search_date_startday = GETPOST('search_date_startday', 'int'); +$search_date_startmonth = GETPOST('search_date_startmonth', 'int'); +$search_date_startyear = GETPOST('search_date_startyear', 'int'); +$search_date_endday = GETPOST('search_date_endday', 'int'); +$search_date_endmonth = GETPOST('search_date_endmonth', 'int'); +$search_date_endyear = GETPOST('search_date_endyear', 'int'); +$search_date_start = dol_mktime(0, 0, 0, $search_date_startmonth, $search_date_startday, $search_date_startyear); // Use tzserver +$search_date_end = dol_mktime(23, 59, 59, $search_date_endmonth, $search_date_endday, $search_date_endyear); // Load variable for pagination $limit = GETPOST('limit', 'int') ?GETPOST('limit', 'int') : (empty($conf->global->ACCOUNTING_LIMIT_LIST_VENTILATION) ? $conf->liste_limit : $conf->global->ACCOUNTING_LIMIT_LIST_VENTILATION); @@ -83,6 +88,9 @@ if (!$sortorder) { } } +// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context +$hookmanager->initHooks(array('accountancyexpensereportlist')); + $formaccounting = new FormAccounting($db); $accounting = new AccountingAccount($db); @@ -101,7 +109,7 @@ if (empty($user->rights->accounting->mouvements->lire)) { /* - * Action + * Actions */ if (GETPOST('cancel', 'alpha')) { @@ -111,30 +119,47 @@ if (!GETPOST('confirmmassaction', 'alpha') && $massaction != 'presend' && $massa $massaction = ''; } -// Purge search criteria -if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // All test are required to be compatible with all browsers - $search_login = ''; - $search_expensereport = ''; - $search_label = ''; - $search_desc = ''; - $search_amount = ''; - $search_account = ''; - $search_vat = ''; - $search_day = ''; - $search_month = ''; - $search_year = ''; +$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)) { + // Purge search criteria + if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // All test are required to be compatible with all browsers + $search_login = ''; + $search_expensereport = ''; + $search_label = ''; + $search_desc = ''; + $search_amount = ''; + $search_account = ''; + $search_vat = ''; + $search_date_startday = ''; + $search_date_startmonth = ''; + $search_date_startyear = ''; + $search_date_endday = ''; + $search_date_endmonth = ''; + $search_date_endyear = ''; + $search_date_start = ''; + $search_date_end = ''; + $search_country = ''; + $search_tvaintra = ''; + } + // Mass actions -$objectclass = 'ExpenseReport'; -$objectlabel = 'ExpenseReport'; -$permissiontoread = $user->rights->expensereport->read; -$permissiontodelete = $user->rights->expensereport->delete; -$uploaddir = $conf->expensereport->dir_output; -include DOL_DOCUMENT_ROOT.'/core/actions_massactions.inc.php'; + $objectclass = 'ExpenseReport'; + $objectlabel = 'ExpenseReport'; + $permissiontoread = $user->rights->expensereport->read; + $permissiontodelete = $user->rights->expensereport->delete; + $uploaddir = $conf->expensereport->dir_output; + include DOL_DOCUMENT_ROOT . '/core/actions_massactions.inc.php'; +} + if ($massaction == 'ventil' && $user->rights->accounting->bind->write) { $msg = ''; + //print '
    ' . $langs->trans("Processing") . '...
    '; if (!empty($mesCasesCochees)) { $msg = '
    '.$langs->trans("SelectedLines").': '.count($mesCasesCochees).'
    '; @@ -159,7 +184,7 @@ if ($massaction == 'ventil' && $user->rights->accounting->bind->write) { $accountventilated = new AccountingAccount($db); $accountventilated->fetch($monCompte, '', 1); - dol_syslog('accountancy/expensereport/list.php', LOG_DEBUG); + dol_syslog('accountancy/expensereport/list.php:: sql='.$sql, LOG_DEBUG); if ($db->query($sql)) { $msg .= '
    '.$langs->trans("LineOfExpenseReport").' '.$monId.' - '.$langs->trans("VentilatedinAccount").' : '.length_accountg($accountventilated->account_number).'
    '; $ok++; @@ -201,6 +226,9 @@ $sql .= " erd.rowid, erd.fk_c_type_fees, erd.comments, erd.total_ht as price, er $sql .= " f.id as type_fees_id, f.code as type_fees_code, f.label as type_fees_label, f.accountancy_code as code_buy,"; $sql .= " u.rowid as userid, u.login, u.lastname, u.firstname, u.email, u.gender, u.employee, u.photo, u.statut,"; $sql .= " aa.rowid as aarowid"; +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters); // Note that $action and $object may have been modified by hook +$sql .= $hookmanager->resPrint; $sql .= " FROM ".MAIN_DB_PREFIX."expensereport as er"; $sql .= " INNER JOIN ".MAIN_DB_PREFIX."expensereport_det as erd ON er.rowid = erd.fk_expensereport"; $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_type_fees as f ON f.id = erd.fk_c_type_fees"; @@ -233,9 +261,19 @@ if (strlen(trim($search_account))) { if (strlen(trim($search_vat))) { $sql .= natural_search("erd.tva_tx", $search_vat, 1); } -$sql .= dolSqlDateFilter('erd.date', $search_day, $search_month, $search_year); +if ($search_date_start) { + $sql .= " AND erd.date >= '".$db->idate($search_date_start)."'"; +} +if ($search_date_end) { + $sql .= " AND erd.date <= '".$db->idate($search_date_end)."'"; +} $sql .= " AND er.entity IN (".getEntity('expensereport', 0).")"; // We don't share object for accountancy +// Add where from hooks +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters); // Note that $action and $object may have been modified by hook +$sql .= $hookmanager->resPrint; + $sql .= $db->order($sortfield, $sortorder); // Count total nb of records @@ -251,7 +289,13 @@ if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { $sql .= $db->plimit($limit + 1, $offset); -dol_syslog('accountancy/expensereport/list.php'); +dol_syslog("accountancy/expensereport/list.php", LOG_DEBUG); +// MAX_JOIN_SIZE can be very low (ex: 300000) on some limited configurations (ex: https://www.online.net/fr/hosting/online-perso) +// This big SELECT command may exceed the MAX_JOIN_SIZE limit => Therefore we use SQL_BIG_SELECTS=1 to disable the MAX_JOIN_SIZE security +if ($db->type == 'mysqli') { + $db->query("SET SQL_BIG_SELECTS=1"); +} + $result = $db->query($sql); if ($result) { $num_lines = $db->num_rows($result); @@ -272,14 +316,23 @@ if ($result) { if ($search_lineid) { $param .= '&search_lineid='.urlencode($search_lineid); } - if ($search_day) { - $param .= '&search_day='.urlencode($search_day); + if ($search_date_startday) { + $param .= '&search_date_startday='.urlencode($search_date_startday); } - if ($search_month) { - $param .= '&search_month='.urlencode($search_month); + if ($search_date_startmonth) { + $param .= '&search_date_startmonth='.urlencode($search_date_startmonth); } - if ($search_year) { - $param .= '&search_year='.urlencode($search_year); + if ($search_date_startyear) { + $param .= '&search_date_startyear='.urlencode($search_date_startyear); + } + if ($search_date_endday) { + $param .= '&search_date_endday='.urlencode($search_date_endday); + } + if ($search_date_endmonth) { + $param .= '&search_date_endmonth='.urlencode($search_date_endmonth); + } + if ($search_date_endyear) { + $param .= '&search_date_endyear='.urlencode($search_date_endyear); } if ($search_expensereport) { $param .= '&search_expensereport='.urlencode($search_expensereport); @@ -302,7 +355,6 @@ if ($result) { ); $massactionbutton = $form->selectMassAction('ventil', $arrayofmassactions, 1); - print ''."\n"; print ''; if ($optioncss != '') { @@ -335,20 +387,21 @@ if ($result) { if (!empty($conf->global->ACCOUNTANCY_USE_EXPENSE_REPORT_VALIDATION_DATE)) { print '
    '; } - print ''; print ''; print ''; - print ''; - print ''; + print ''; + print ''; print ''; print ''; - print ''; @@ -468,6 +521,9 @@ if ($result) { } else { print $db->error(); } +if ($db->type == 'mysqli') { + $db->query("SET SQL_BIG_SELECTS=0"); // Enable MAX_JOIN_SIZE limitation +} // Add code to auto check the box when we select an account print ''; + } + return $out; } From c0dd96a45654aa8f85f5fcc7278bfcc510cf97bb Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Fri, 25 Feb 2022 10:36:02 +0000 Subject: [PATCH 182/255] Fixing style errors. --- htdocs/accountancy/bookkeeping/card.php | 5 ++--- htdocs/core/class/html.formaccounting.class.php | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/htdocs/accountancy/bookkeeping/card.php b/htdocs/accountancy/bookkeeping/card.php index df43f28bd1f..01e78cf4d27 100644 --- a/htdocs/accountancy/bookkeeping/card.php +++ b/htdocs/accountancy/bookkeeping/card.php @@ -659,7 +659,7 @@ if ($action == 'create') { // Also, it is not possible to use a value that is not in the list. // Also, the label is not automatically filled when a value is selected. if (!empty($conf->global->ACCOUNTANCY_COMBO_FOR_AUX)) { - print $formaccounting->select_auxaccount((GETPOSTISSET("subledger_account") ? GETPOST("subledger_account", "alpha") : $line->subledger_account), 'subledger_account', 1,'maxwidth250','','subledger_label'); + print $formaccounting->select_auxaccount((GETPOSTISSET("subledger_account") ? GETPOST("subledger_account", "alpha") : $line->subledger_account), 'subledger_account', 1, 'maxwidth250', '', 'subledger_label'); } else { print 'subledger_account).'" placeholder="'.dol_escape_htmltag($langs->trans("SubledgerAccount")).'">'; } @@ -728,7 +728,7 @@ if ($action == 'create') { // Also, it is not possible to use a value that is not in the list. // Also, the label is not automatically filled when a value is selected. if (!empty($conf->global->ACCOUNTANCY_COMBO_FOR_AUX)) { - print $formaccounting->select_auxaccount('', 'subledger_account', 1,'maxwidth250','','subledger_label'); + print $formaccounting->select_auxaccount('', 'subledger_account', 1, 'maxwidth250', '', 'subledger_label'); } else { print ''; } @@ -758,7 +758,6 @@ if ($action == 'create') { print ""; } print ''; - } } } else { diff --git a/htdocs/core/class/html.formaccounting.class.php b/htdocs/core/class/html.formaccounting.class.php index 638d3a4bdfd..645e045a903 100644 --- a/htdocs/core/class/html.formaccounting.class.php +++ b/htdocs/core/class/html.formaccounting.class.php @@ -518,7 +518,7 @@ class FormAccounting extends Form '; } - + return $out; } From a9450f5673e60320ed86e2ffd84dafaa3398cf3f Mon Sep 17 00:00:00 2001 From: Anthony Berton <34568357+bb2a@users.noreply.github.com> Date: Fri, 25 Feb 2022 11:50:41 +0100 Subject: [PATCH 183/255] Update societe.php --- htdocs/societe/admin/societe.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/societe/admin/societe.php b/htdocs/societe/admin/societe.php index 95e1d5e47cb..3d7725c7d19 100644 --- a/htdocs/societe/admin/societe.php +++ b/htdocs/societe/admin/societe.php @@ -612,7 +612,7 @@ foreach ($dirsociete as $dirroot) { // Preview print ''; } -if (!empty($arrayfields['e.shipping_method_id']['checked'])) { +if (!empty($arrayfields['e.fk_shipping_method']['checked'])) { // Delivery method print '\n"; } - if (!empty($arrayfields['e.shipping_method_id']['checked'])) { + if (!empty($arrayfields['e.fk_shipping_method']['checked'])) { // Get code using getLabelFromKey $code=$langs->getLabelFromKey($db, $shipment->shipping_method_id, 'c_shipment_mode', 'rowid', 'code'); print ''; + // Date print ''; @@ -1378,15 +1395,6 @@ if ($action == 'create') { } print ''; - - $line = new FichinterLigne($db); - $line->fetch($objp->rowid); - - $extrafields->fetch_name_optionals_label($line->table_element); - - $line->fetch_optionals(); - - print $line->showOptionals($extrafields, 'view', array('colspan'=>5)); } // Line in update mode @@ -1405,6 +1413,22 @@ if ($action == 'create') { require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php'; $doleditor = new DolEditor('np_desc', $objp->description, '', 164, 'dolibarr_details', '', false, true, $conf->global->FCKEDITOR_ENABLE_DETAILS, ROWS_2, '90%'); $doleditor->Create(); + + $objectline = new FichinterLigne($db); + $objectline->fetch($objp->rowid); + $objectline->fetch_optionals(); + + $extrafields->fetch_name_optionals_label($objectline->table_element); + + if (!empty($extrafields)) { + $temps = $objectline->showOptionals($extrafields, 'edit', array(), '', '', 1, 'line'); + if (!empty($temps)) { + print '
    '; + print $temps; + print '
    '; + } + } + print ''; // Date d'intervention @@ -1431,14 +1455,6 @@ if ($action == 'create') { print ''; print ''; print ''."\n"; - - $line = new FichinterLigne($db); - $line->fetch($objp->rowid); - - $extrafields->fetch_name_optionals_label($line->table_element); - $line->fetch_optionals(); - - print $line->showOptionals($extrafields, 'edit', array('colspan'=>5)); } $i++; @@ -1481,6 +1497,20 @@ if ($action == 'create') { $doleditor = new DolEditor('np_desc', GETPOST('np_desc', 'restricthtml'), '', 100, 'dolibarr_details', '', false, true, $conf->global->FCKEDITOR_ENABLE_DETAILS, ROWS_2, '90%'); $doleditor->Create(); } + + $objectline = new FichinterLigne($db); + $extrafields->fetch_name_optionals_label($objectline->table_element); + + if (is_object($objectline)) { + $temps = $objectline->showOptionals($extrafields, 'create', array(), '', '', 1, 'line'); + + if (!empty($temps)) { + print '
    '; + print $temps; + print '
    '; + } + } + print ''; // Date intervention @@ -1513,14 +1543,6 @@ if ($action == 'create') { print ''; print ''; - //Line extrafield - - $lineadd = new FichinterLigne($db); - - $extrafields->fetch_name_optionals_label($lineadd->table_element); - - print $lineadd->showOptionals($extrafields, 'edit', array('colspan'=>5)); - if (!$num) { print '
    '.$langs->trans($bickey).'
    '.$langs->trans("SEPAXMLPlacePaymentTypeInformationInCreditTransfertransactionInformation").' '; + print img_picto($langs->trans("SEPAXMLPlacePaymentTypeInformationInCreditTransfertransactionInformationHelp"), 'info'); + print '
    '.$langs->trans("BankAccountDomiciliation").''; print ''; + print ''; print ''; - $durationtouse = ($_POST['timespent_duration'] ? $_POST['timespent_duration'] : ''); + $durationtouse = (GETPOST('timespent_duration') ? GETPOST('timespent_duration') : ''); if (GETPOSTISSET('timespent_durationhour') || GETPOSTISSET('timespent_durationmin')) { $durationtouse = (GETPOST('timespent_durationhour') * 3600 + GETPOST('timespent_durationmin') * 60); } From 118b211807f2b5ddffe4db03d6c7289d08feba1e Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 24 Feb 2022 12:37:20 +0100 Subject: [PATCH 165/255] Fix error on null --- htdocs/core/lib/functions.lib.php | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index aea77cd018d..3b0e90c9013 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -6582,16 +6582,18 @@ function dol_string_onlythesehtmlattributes($stringtoclean, $allowed_attributes } elseif (in_array($attrs->item($ii)->name, array('style'))) { $valuetoclean = $attrs->item($ii)->value; - do { - $oldvaluetoclean = $valuetoclean; - $valuetoclean = preg_replace('/\/\*.*\*\//m', '', $valuetoclean); // clean css comments - $valuetoclean = preg_replace('/position\s*:\s*[a-z]+/mi', '', $valuetoclean); - if ($els->item($i)->tagName == 'a') { // more paranoiac cleaning for clickable tags. - $valuetoclean = preg_replace('/display\s*://m', '', $valuetoclean); - $valuetoclean = preg_replace('/z-index\s*://m', '', $valuetoclean); - $valuetoclean = preg_replace('/\s+(top|left|right|bottom)\s*://m', '', $valuetoclean); - } - } while ($oldvaluetoclean != $valuetoclean); + if (isset($valuetoclean)) { + do { + $oldvaluetoclean = $valuetoclean; + $valuetoclean = preg_replace('/\/\*.*\*\//m', '', $valuetoclean); // clean css comments + $valuetoclean = preg_replace('/position\s*:\s*[a-z]+/mi', '', $valuetoclean); + if ($els->item($i)->tagName == 'a') { // more paranoiac cleaning for clickable tags. + $valuetoclean = preg_replace('/display\s*://m', '', $valuetoclean); + $valuetoclean = preg_replace('/z-index\s*://m', '', $valuetoclean); + $valuetoclean = preg_replace('/\s+(top|left|right|bottom)\s*://m', '', $valuetoclean); + } + } while ($oldvaluetoclean != $valuetoclean); + } $attrs->item($ii)->value = $valuetoclean; } From a6e7a41e98ba057b1117e982af4b3a3409ed9135 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 24 Feb 2022 12:54:33 +0100 Subject: [PATCH 166/255] FIX Reduce flash effect on collapse extrafield FIX Reduce flash effect on edit inline feature. --- htdocs/core/class/extrafields.class.php | 86 +++++++++++++----------- htdocs/core/class/html.form.class.php | 12 ++-- htdocs/core/tpl/extrafields_view.tpl.php | 9 ++- htdocs/theme/eldy/global.inc.php | 22 +++--- htdocs/theme/md/style.css.php | 17 +++-- 5 files changed, 85 insertions(+), 61 deletions(-) diff --git a/htdocs/core/class/extrafields.class.php b/htdocs/core/class/extrafields.class.php index 31c33716233..319447b0996 100644 --- a/htdocs/core/class/extrafields.class.php +++ b/htdocs/core/class/extrafields.class.php @@ -66,6 +66,11 @@ class ExtraFields */ public $attributes; + /** + * @var array Array with boolean of status of groups + */ + public $expand_display; + /** * @var string Error code (or message) */ @@ -1866,55 +1871,58 @@ class ExtraFields $colspan=0; } + $extrafield_param = $this->attributes[$object->table_element]['param'][$key]; + $extrafield_param_list = array(); + if (!empty($extrafield_param) && is_array($extrafield_param)) { + $extrafield_param_list = array_keys($extrafield_param['options']); + } + $extrafield_collapse_display_value = -1; + $expand_display = false; + if (is_array($extrafield_param_list) && count($extrafield_param_list) > 0) { + $extrafield_collapse_display_value = intval($extrafield_param_list[0]); + $expand_display = ((isset($_COOKIE['DOLCOLLAPSE_'.$object->table_element.'_extrafields_'.$key]) || GETPOST('ignorecollapsesetup', 'int')) ? ($_COOKIE['DOLCOLLAPSE_'.$object->table_element.'_extrafields_'.$key] ? true : false) : ($extrafield_collapse_display_value == 2 ? false : true)); + } + $out = '<'.$tagtype.' id="trextrafieldseparator'.$key.(!empty($object->id)?'_'.$object->id:'').'" class="trextrafieldseparator trextrafieldseparator'.$key.(!empty($object->id)?'_'.$object->id:'').'">'; $out .= '<'.$tagtype_dyn.' '.(!empty($colspan)?'colspan="' . $colspan . '"':'').'>'; // Some js code will be injected here to manage the collapsing of extrafields - $out .=''; + $out .= ' '; + $out .= ''; $out .= $langs->trans($this->attributes[$object->table_element]['label'][$key]); $out .= ''; $out .= ''; $out .= ''; - $extrafield_param = $this->attributes[$object->table_element]['param'][$key]; - if (!empty($extrafield_param) && is_array($extrafield_param)) { - $extrafield_param_list = array_keys($extrafield_param['options']); + if ($extrafield_collapse_display_value == 1 || $extrafield_collapse_display_value == 2) { + // Set the collapse_display status to cookie in priority or if ignorecollapsesetup is 1, if cookie and ignorecollapsesetup not defined, use the setup. + $extrafields_collapse_num = $this->attributes[$object->table_element]['pos'][$key].(!empty($object->id)?'_'.$object->id:''); + $this->expand_display[$extrafields_collapse_num] = $expand_display; - if (count($extrafield_param_list) > 0) { - $extrafield_collapse_display_value = intval($extrafield_param_list[0]); - if ($extrafield_collapse_display_value == 1 || $extrafield_collapse_display_value == 2) { - // Set the collapse_display status to cookie in priority or if ignorecollapsesetup is 1, if cookie and ignorecollapsesetup not defined, use the setup. - $collapse_display = ((isset($_COOKIE['DOLCOLLAPSE_'.$object->table_element.'_extrafields_'.$key]) || GETPOST('ignorecollapsesetup', 'int')) ? ($_COOKIE['DOLCOLLAPSE_'.$object->table_element.'_extrafields_'.$key] ? true : false) : ($extrafield_collapse_display_value == 2 ? false : true)); - $extrafields_collapse_num = $this->attributes[$object->table_element]['pos'][$key].(!empty($object->id)?'_'.$object->id:''); - - if (!empty($conf->use_javascript_ajax)) { - $out .= ''."\n"; - $out .= ''."\n"; - } + if (!empty($conf->use_javascript_ajax)) { + $out .= ''."\n"; + $out .= ''."\n"; } } diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 68fe5152407..b4f1daf9674 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -141,9 +141,9 @@ class Form } } } else { - if (empty($notabletag) && GETPOST('action', 'aZ09') != 'edit'.$htmlname && $perm) { + //if (empty($notabletag) && GETPOST('action', 'aZ09') != 'edit'.$htmlname && $perm) { $ret .= ''; - } + //} if (empty($notabletag) && GETPOST('action', 'aZ09') != 'edit'.$htmlname && $perm) { $ret .= ''; } - if (empty($notabletag) && GETPOST('action', 'aZ09') != 'edit'.$htmlname && $perm) { + //if (empty($notabletag) && GETPOST('action', 'aZ09') != 'edit'.$htmlname && $perm) { $ret .= '
    '; - } + //} if ($fieldrequired) { $ret .= ''; } @@ -158,9 +158,9 @@ class Form if (!empty($notabletag)) { $ret .= ' '; } - if (empty($notabletag) && GETPOST('action', 'aZ09') != 'edit'.$htmlname && $perm) { + //if (empty($notabletag) && GETPOST('action', 'aZ09') != 'edit'.$htmlname && $perm) { $ret .= ''; } @@ -176,9 +176,9 @@ class Form if (empty($notabletag) && GETPOST('action', 'aZ09') != 'edit'.$htmlname && $perm) { $ret .= '
    '; - } + //} } return $ret; diff --git a/htdocs/core/tpl/extrafields_view.tpl.php b/htdocs/core/tpl/extrafields_view.tpl.php index b5656c89339..8afa9a16ff0 100644 --- a/htdocs/core/tpl/extrafields_view.tpl.php +++ b/htdocs/core/tpl/extrafields_view.tpl.php @@ -125,14 +125,19 @@ if (empty($reshook) && isset($extrafields->attributes[$object->table_element]['l $lastseparatorkeyfound = $tmpkeyextra; } else { - print '
    '; print ''; diff --git a/htdocs/theme/eldy/global.inc.php b/htdocs/theme/eldy/global.inc.php index b55ad42182c..74807d8f216 100644 --- a/htdocs/theme/eldy/global.inc.php +++ b/htdocs/theme/eldy/global.inc.php @@ -223,7 +223,7 @@ input { padding-left: 5px; } select { - padding-top: 5px; + padding-top: 4px; padding-right: 4px; padding-bottom: 5px; padding-left: 2px; @@ -550,6 +550,13 @@ div#moretabsList, div#moretabsListaction { hr { border: 0; border-top: 1px solid #ccc; } .tabBar hr { margin-top: 20px; margin-bottom: 17px; } + +table.tableforfield .button:not(.bordertransp):not(.buttonpayment), +table.tableforfield .buttonDelete:not(.bordertransp):not(.buttonpayment) { + margin-bottom: 2px; + margin-top: 2px; +} + .button:not(.bordertransp):not(.buttonpayment), .buttonDelete:not(.bordertransp):not(.buttonpayment) { margin-bottom: 3px; @@ -3495,11 +3502,10 @@ table.border, table.bordernooddeven, table.dataTable, .table-border, .table-bord table.borderplus { border: 1px solid #BBB; } -.border tbody tr, .bordernooddeven tbody tr, .border tbody tr td, .bordernooddeven tbody tr td, div.tabBar table.border tr, div.tabBar table.border tr td, div.tabBar div.border .table-border-row, div.tabBar div.border .table-key-border-col, div.tabBar div.border .table-val-border-col { - height: 22px; -} +.border tbody tr, .bordernooddeven tbody tr, .border tbody tr td, .bordernooddeven tbody tr td, +div.tabBar table.border tr, div.tabBar table.border tr td, div.tabBar div.border .table-border-row, div.tabBar div.border .table-key-border-col, div.tabBar div.border .table-val-border-col, tr.liste_titre.box_titre td table td, .bordernooddeven tr td { - height: 22px; + height: 28px; } div.tabBar div.border .table-border-row, div.tabBar div.border .table-key-border-col, div.tabBar .table-val-border-col { @@ -3507,17 +3513,15 @@ div.tabBar div.border .table-border-row, div.tabBar div.border .table-key-border } div .tdtop { vertical-align: top !important; - /*padding-top: 10px !important; - padding-bottom: 2px !important; */ } table.border td, table.bordernooddeven td, div.border div div.tagtd { - padding: 5px 2px 5px 2px; + padding: 2px 2px 2px 2px; border-collapse: collapse; } div.tabBar .fichecenter table.border>tbody>tr>td, div.tabBar .fichecenter div.border div div.tagtd, div.tabBar div.border div div.tagtd { - padding-top: 5px; + padding-top: 2px; border-bottom: 1px solid #E0E0E0; } diff --git a/htdocs/theme/md/style.css.php b/htdocs/theme/md/style.css.php index 5c5b4992806..11e15869f45 100644 --- a/htdocs/theme/md/style.css.php +++ b/htdocs/theme/md/style.css.php @@ -730,6 +730,14 @@ div#moretabsList, div#moretabsListaction { } hr { border: 0; border-top: 1px solid #ccc; } +.tabBar hr { margin-top: 20px; margin-bottom: 17px; } + + +table.tableforfield .button:not(.bordertransp):not(.buttonpayment), +table.tableforfield .buttonDelete:not(.bordertransp):not(.buttonpayment) { + margin-bottom: 2px; + margin-top: 2px; +} .button:not(.bordertransp):not(.buttonpayment), .buttonDelete:not(.bordertransp):not(.buttonpayment) { border-color: #c5c5c5; @@ -3564,15 +3572,14 @@ table.borderplus { border: 1px solid #BBB; } -.border tbody tr, .bordernooddeven tbody tr, .border tbody tr td, .bordernooddeven tbody tr td, div.tabBar table.border tr, div.tabBar table.border tr td, div.tabBar div.border .table-border-row, div.tabBar div.border .table-key-border-col, div.tabBar div.border .table-val-border-col { - height: 26px; -} +.border tbody tr, .bordernooddeven tbody tr, .border tbody tr td, .bordernooddeven tbody tr td, +div.tabBar table.border tr, div.tabBar table.border tr td, div.tabBar div.border .table-border-row, div.tabBar div.border .table-key-border-col, div.tabBar div.border .table-val-border-col, tr.liste_titre.box_titre td table td, .bordernooddeven tr td { - height: 26px; + height: 28px; } table.border td, table.bordernooddeven td, div.border div div.tagtd { - padding: 4px 4px 4px 4px; + padding: 3px 4px 3px 4px; border: 1px solid #f0f0f0; border-collapse: collapse; } From ba3856f9e9f6b424ceeae7007e7105ee984cfb34 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 24 Feb 2022 14:14:04 +0100 Subject: [PATCH 167/255] Fix regression --- htdocs/core/class/extrafields.class.php | 2 +- htdocs/core/class/html.form.class.php | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/htdocs/core/class/extrafields.class.php b/htdocs/core/class/extrafields.class.php index 319447b0996..e9b23bfdbd9 100644 --- a/htdocs/core/class/extrafields.class.php +++ b/htdocs/core/class/extrafields.class.php @@ -1886,7 +1886,7 @@ class ExtraFields $out = '<'.$tagtype.' id="trextrafieldseparator'.$key.(!empty($object->id)?'_'.$object->id:'').'" class="trextrafieldseparator trextrafieldseparator'.$key.(!empty($object->id)?'_'.$object->id:'').'">'; $out .= '<'.$tagtype_dyn.' '.(!empty($colspan)?'colspan="' . $colspan . '"':'').'>'; // Some js code will be injected here to manage the collapsing of extrafields - $out .= ' '; + $out .= ' '; $out .= ''; $out .= $langs->trans($this->attributes[$object->table_element]['label'][$key]); $out .= ''; diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index b4f1daf9674..6e5c0a572d2 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -141,9 +141,9 @@ class Form } } } else { - //if (empty($notabletag) && GETPOST('action', 'aZ09') != 'edit'.$htmlname && $perm) { + if (empty($notabletag) && $perm) { $ret .= '
    '; - //} - if (empty($notabletag) && GETPOST('action', 'aZ09') != 'edit'.$htmlname && $perm) { + } + if (empty($notabletag) && $perm) { $ret .= ''; } - //if (empty($notabletag) && GETPOST('action', 'aZ09') != 'edit'.$htmlname && $perm) { + if (empty($notabletag) && $perm) { $ret .= '
    '; - //} + } if ($fieldrequired) { $ret .= ''; } @@ -158,10 +158,10 @@ class Form if (!empty($notabletag)) { $ret .= ' '; } - //if (empty($notabletag) && GETPOST('action', 'aZ09') != 'edit'.$htmlname && $perm) { + if (empty($notabletag) && $perm) { $ret .= ''; } if ($htmlname && GETPOST('action', 'aZ09') != 'edit'.$htmlname && $perm) { @@ -173,12 +173,12 @@ class Form if (!empty($notabletag) && $notabletag == 3) { $ret .= ' '; } - if (empty($notabletag) && GETPOST('action', 'aZ09') != 'edit'.$htmlname && $perm) { + if (empty($notabletag) && $perm) { $ret .= '
    '; - //} + } } return $ret; From 4d2dde0fe48d335a434a0e88a5101d878d1c7b7e Mon Sep 17 00:00:00 2001 From: Thomas Negre Date: Thu, 24 Feb 2022 14:34:06 +0100 Subject: [PATCH 168/255] fix bookmarks info bubble --- htdocs/bookmarks/bookmarks.lib.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/bookmarks/bookmarks.lib.php b/htdocs/bookmarks/bookmarks.lib.php index d24ba63ef55..f8daff1cd14 100644 --- a/htdocs/bookmarks/bookmarks.lib.php +++ b/htdocs/bookmarks/bookmarks.lib.php @@ -66,7 +66,7 @@ function printDropdownBookmarksList() // Url to list bookmark - $listbtn = ''; + $listbtn = ''; $listbtn .= img_picto('', 'bookmark', 'class="paddingright"').$langs->trans('Bookmarks').''; // Url to go on create new bookmark page From 517562b465eee56d3b1df297086e4fe39cfe091d Mon Sep 17 00:00:00 2001 From: Gauthier PC portable 024 Date: Thu, 24 Feb 2022 15:26:11 +0100 Subject: [PATCH 169/255] NEW : solde() function evolution to be able to get solde until a chosen date --- htdocs/compta/bank/class/account.class.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/htdocs/compta/bank/class/account.class.php b/htdocs/compta/bank/class/account.class.php index cb2de5aca46..655c49bcc44 100644 --- a/htdocs/compta/bank/class/account.class.php +++ b/htdocs/compta/bank/class/account.class.php @@ -1188,9 +1188,11 @@ class Account extends CommonObject * Return current sold * * @param int $option 1=Exclude future operation date (this is to exclude input made in advance and have real account sold) - * @return int Current sold (value date <= today) + * @param tms $date_end Date until we want to get bank account sold + * @param string $field dateo or datev + * @return int current sold (value date <= today) */ - public function solde($option = 0) + public function solde($option = 0, $date_end='', $field='dateo') { $solde = 0; @@ -1198,7 +1200,7 @@ class Account extends CommonObject $sql .= " FROM ".MAIN_DB_PREFIX."bank"; $sql .= " WHERE fk_account = ".((int) $this->id); if ($option == 1) { - $sql .= " AND dateo <= '".$this->db->idate(dol_now())."'"; + $sql .= " AND ".$this->db->escape($field)." <= '".(!empty($date_end) ? $this->db->idate($date_end) : $this->db->idate(dol_now()))."'"; } $resql = $this->db->query($sql); From a0bc41cdba3fd8561f2ed84c5dc6aa3511413c0f Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Thu, 24 Feb 2022 14:32:59 +0000 Subject: [PATCH 170/255] Fixing style errors. --- htdocs/compta/bank/class/account.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/compta/bank/class/account.class.php b/htdocs/compta/bank/class/account.class.php index 655c49bcc44..18fc015fb2d 100644 --- a/htdocs/compta/bank/class/account.class.php +++ b/htdocs/compta/bank/class/account.class.php @@ -1192,7 +1192,7 @@ class Account extends CommonObject * @param string $field dateo or datev * @return int current sold (value date <= today) */ - public function solde($option = 0, $date_end='', $field='dateo') + public function solde($option = 0, $date_end = '', $field = 'dateo') { $solde = 0; From f0c5fe31f818f743cfefe62d880c25e1e1faed56 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 24 Feb 2022 17:49:52 +0100 Subject: [PATCH 171/255] FIX #yogosha9083 --- htdocs/main.inc.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/htdocs/main.inc.php b/htdocs/main.inc.php index 624c7bd6e73..9a9da452a44 100644 --- a/htdocs/main.inc.php +++ b/htdocs/main.inc.php @@ -97,15 +97,15 @@ function testSqlAndScriptInject($val, $type) //$val = preg_replace_callback('/&#(x?[0-9][0-9a-f]+;?)/i', 'realCharForNumericEntities', $val); // Sometimes we have entities without the ; at end so html_entity_decode does not work but entities is still interpreted by browser. $val = preg_replace_callback('/&#(x?[0-9][0-9a-f]+;?)/i', function ($m) { return realCharForNumericEntities($m); }, $val); + + // We clean string because some hacks try to obfuscate evil strings by inserting non printable chars. Example: 'java(ascci09)scr(ascii00)ipt' is processed like 'javascript' (whatever is place of evil ascii char) + // We should use dol_string_nounprintableascii but function is not yet loaded/available + $val = preg_replace('/[\x00-\x1F\x7F]/u', '', $val); // /u operator makes UTF8 valid characters being ignored so are not included into the replace + // We clean html comments because some hacks try to obfuscate evil strings by inserting HTML comments. Example: onerror=alert(1) + $val = preg_replace('//', '', $val); } while ($oldval != $val); //print "after decoding $val\n"; - // We clean string because some hacks try to obfuscate evil strings by inserting non printable chars. Example: 'java(ascci09)scr(ascii00)ipt' is processed like 'javascript' (whatever is place of evil ascii char) - // We should use dol_string_nounprintableascii but function is not yet loaded/available - $val = preg_replace('/[\x00-\x1F\x7F]/u', '', $val); // /u operator makes UTF8 valid characters being ignored so are not included into the replace - // We clean html comments because some hacks try to obfuscate evil strings by inserting HTML comments. Example: onerror=alert(1) - $val = preg_replace('//', '', $val); - $inj = 0; // For SQL Injection (only GET are used to scan for such injection strings) if ($type == 1 || $type == 3) { From 98da84f9b2594124841659ab00b887a59a219f92 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 24 Feb 2022 18:15:04 +0100 Subject: [PATCH 172/255] FIX #yogosha9086 --- htdocs/core/lib/website.lib.php | 4 +++ htdocs/website/index.php | 48 ++++++++++++++++++++++----------- 2 files changed, 36 insertions(+), 16 deletions(-) diff --git a/htdocs/core/lib/website.lib.php b/htdocs/core/lib/website.lib.php index ea40cb2dd7e..138be225166 100644 --- a/htdocs/core/lib/website.lib.php +++ b/htdocs/core/lib/website.lib.php @@ -31,6 +31,8 @@ */ function dolStripPhpCode($str, $replacewith = '') { + $str = str_replace('\n*/ims', '/<\/html>\n*/ims'), array('', ''), $dataposted); + $dataposted = str_replace('\n";*/ - $htmlheadercontent .= preg_replace(array('/\n*/ims', '/<\/html>\n*/ims'), array('', ''), GETPOST('WEBSITE_HTML_HEADER', 'none')); + $htmlheadercontent .= $dataposted."\n"; /*$htmlheadercontent.= "\n".'"."\n";*/ - $htmlheadercontent = trim($htmlheadercontent)."\n"; - $result = dolSaveHtmlHeader($filehtmlheader, $htmlheadercontent); if (!$result) { $error++; @@ -1443,10 +1445,12 @@ if ($action == 'updatecss' && $usercanedit) { $error++; } + $dataposted = trim(GETPOST('WEBSITE_CSS_INLINE', 'none')); + $dataposted = str_replace('\n"; - $csscontent .= trim(GETPOST('WEBSITE_CSS_INLINE', 'none'))."\n"; + $csscontent .= $dataposted."\n"; $csscontent .= '\n"; - $jscontent .= trim(GETPOST('WEBSITE_JS_INLINE', 'none'))."\n"; + $jscontent .= $dataposted."\n"; $jscontent .= '\n";*/ - $robotcontent .= trim(GETPOST('WEBSITE_ROBOT', 'restricthtml'))."\n"; + $robotcontent .= $dataposted."\n"; /*$robotcontent.= "\n".'\n"; - $manifestjsoncontent .= trim(GETPOST('WEBSITE_MANIFEST_JSON', 'none'))."\n"; + $manifestjsoncontent .= $dataposted."\n"; $manifestjsoncontent .= '\n";*/ - $readmecontent .= trim(GETPOST('WEBSITE_README', 'restricthtml'))."\n"; + $readmecontent .= $dataposted."\n"; /*$readmecontent.= ' Date: Thu, 24 Feb 2022 18:29:24 +0100 Subject: [PATCH 173/255] FIX #yogosha9083 --- htdocs/opensurvey/card.php | 10 +++++----- htdocs/public/opensurvey/studs.php | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/htdocs/opensurvey/card.php b/htdocs/opensurvey/card.php index 3f822679350..bc018a2dda1 100644 --- a/htdocs/opensurvey/card.php +++ b/htdocs/opensurvey/card.php @@ -137,18 +137,18 @@ if (empty($reshook)) { if (GETPOST('ajoutcomment')) { $error = 0; - if (!GETPOST('comment')) { + if (!GETPOST('comment', "alphanohtml")) { $error++; setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Comment")), null, 'errors'); } - if (!GETPOST('commentuser')) { + if (!GETPOST('commentuser', "alphanohtml")) { $error++; setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("User")), null, 'errors'); } if (!$error) { - $comment = (string) GETPOST("comment", "restricthtml"); - $comment_user = (string) GETPOST('commentuser', "restricthtml"); + $comment = (string) GETPOST("comment", "alphanohtml"); + $comment_user = (string) GETPOST('commentuser', "alphanohtml"); $resql = $object->addComment($comment, $comment_user); @@ -422,7 +422,7 @@ print '
    '; if ($object->allow_comments) { print $langs->trans("AddACommentForPoll").'
    '; print '
    '."\n"; - print $langs->trans("Name").': '."\n"; + print $langs->trans("Name").': '."\n"; print '
    '."\n"; } diff --git a/htdocs/public/opensurvey/studs.php b/htdocs/public/opensurvey/studs.php index c14935d6708..a1c9efed6c3 100644 --- a/htdocs/public/opensurvey/studs.php +++ b/htdocs/public/opensurvey/studs.php @@ -79,8 +79,8 @@ if (GETPOST('ajoutcomment', 'alpha')) { $error = 0; - $comment = GETPOST("comment", 'restricthtml'); - $comment_user = GETPOST('commentuser', 'nohtml'); + $comment = GETPOST("comment", 'alphanohtml'); + $comment_user = GETPOST('commentuser', 'alphanohtml'); if (!$comment) { $error++; @@ -780,9 +780,9 @@ if ($comments) { if ($object->allow_comments) { print '
    '.$langs->trans("AddACommentForPoll")."
    \n"; - print '
    '."\n"; + print '
    '."\n"; print $langs->trans("Name").': '; - print '   '."\n"; + print '   '."\n"; print '
    '."\n"; print ''."\n"; From 8c61a29051e1225cf050bc5e2d11b0d95e62e890 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 25 Feb 2022 01:30:34 +0100 Subject: [PATCH 174/255] Show value of short_open_tags --- htdocs/admin/system/security.php | 1 + 1 file changed, 1 insertion(+) diff --git a/htdocs/admin/system/security.php b/htdocs/admin/system/security.php index 9321fa11c12..c48acebe140 100644 --- a/htdocs/admin/system/security.php +++ b/htdocs/admin/system/security.php @@ -99,6 +99,7 @@ if (!ini_get('session.cookie_samesite') || ini_get('session.cookie_samesite') == } print "
    \n"; print "PHP open_basedir = ".(ini_get('open_basedir') ? ini_get('open_basedir') : yn(0).'   ('.$langs->trans("RecommendedValueIs", $langs->transnoentitiesnoconv("ARestrictedPath").', '.$langs->transnoentitiesnoconv("Example").': '.$_SERVER["DOCUMENT_ROOT"].','.DOL_DATA_ROOT).')')."
    \n"; +print "PHP short_open_tag = ".((empty(ini_get('short_open_tag')) || ini_get('short_open_tag') == 'Off') ? yn(0) : img_warning().' '.yn(0)).'   ('.$langs->trans("RecommendedValueIs", $langs->transnoentitiesnoconv("No")).')'."
    \n"; print "PHP allow_url_fopen = ".(ini_get('allow_url_fopen') ? img_picto($langs->trans("YouShouldSetThisToOff"), 'warning').' '.ini_get('allow_url_fopen') : yn(0)).'   ('.$langs->trans("RecommendedValueIs", $langs->transnoentitiesnoconv("No")).")
    \n"; print "PHP allow_url_include = ".(ini_get('allow_url_include') ? img_picto($langs->trans("YouShouldSetThisToOff"), 'warning').' '.ini_get('allow_url_include') : yn(0)).'   ('.$langs->trans("RecommendedValueIs", $langs->transnoentitiesnoconv("No")).")
    \n"; //print "PHP safe_mode = ".(ini_get('safe_mode') ? ini_get('safe_mode') : yn(0)).'   '.$langs->trans("Deprecated")." (removed in PHP 5.4)
    \n"; From c097ee533187cbf1619f8fd4f3c5fa8ea8f14dd8 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 25 Feb 2022 01:49:38 +0100 Subject: [PATCH 175/255] FIX #yogosha9089 --- htdocs/core/lib/website2.lib.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/htdocs/core/lib/website2.lib.php b/htdocs/core/lib/website2.lib.php index 64111e295d2..f61bd298c62 100644 --- a/htdocs/core/lib/website2.lib.php +++ b/htdocs/core/lib/website2.lib.php @@ -647,6 +647,11 @@ function checkPHPCode($phpfullcodestringold, $phpfullcodestring) break; } } + // Check dynamic functions $xxx( + if (preg_match('/\$[a-z0-9_]+\(/ims', $phpfullcodestring)) { + $error++; + setEventMessages($langs->trans("DynamicPHPCodeContainsAForbiddenInstruction", '$...('), null, 'errors'); + } if (!$error && empty($user->rights->website->writephp)) { if ($phpfullcodestringold != $phpfullcodestring) { From 6b4c4f19aba356a05b76735a91747df9a7848019 Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Fri, 25 Feb 2022 04:55:55 +0100 Subject: [PATCH 176/255] NEW Accountancy - Add date from/to on expense report binding & uniformize --- htdocs/accountancy/expensereport/lines.php | 78 +++++++---- htdocs/accountancy/expensereport/list.php | 142 ++++++++++++++------- 2 files changed, 149 insertions(+), 71 deletions(-) diff --git a/htdocs/accountancy/expensereport/lines.php b/htdocs/accountancy/expensereport/lines.php index fb3bf1a6e04..ff7b9295693 100644 --- a/htdocs/accountancy/expensereport/lines.php +++ b/htdocs/accountancy/expensereport/lines.php @@ -1,6 +1,6 @@ - * Copyright (C) 2013-2017 Alexandre Spangaro + * Copyright (C) 2013-2022 Alexandre Spangaro * Copyright (C) 2014-2015 Ari Elbaz (elarifr) * Copyright (C) 2013-2016 Florian Henry * Copyright (C) 2014 Juanjo Menent @@ -26,8 +26,8 @@ */ require '../../main.inc.php'; -require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formaccounting.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; require_once DOL_DOCUMENT_ROOT.'/expensereport/class/expensereport.class.php'; require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingaccount.class.php'; require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php'; @@ -49,9 +49,14 @@ $search_desc = GETPOST('search_desc', 'alpha'); $search_amount = GETPOST('search_amount', 'alpha'); $search_account = GETPOST('search_account', 'alpha'); $search_vat = GETPOST('search_vat', 'alpha'); -$search_day = GETPOST("search_day", "int"); -$search_month = GETPOST("search_month", "int"); -$search_year = GETPOST("search_year", "int"); +$search_date_startday = GETPOST('search_date_startday', 'int'); +$search_date_startmonth = GETPOST('search_date_startmonth', 'int'); +$search_date_startyear = GETPOST('search_date_startyear', 'int'); +$search_date_endday = GETPOST('search_date_endday', 'int'); +$search_date_endmonth = GETPOST('search_date_endmonth', 'int'); +$search_date_endyear = GETPOST('search_date_endyear', 'int'); +$search_date_start = dol_mktime(0, 0, 0, $search_date_startmonth, $search_date_startday, $search_date_startyear); // Use tzserver +$search_date_end = dol_mktime(23, 59, 59, $search_date_endmonth, $search_date_endday, $search_date_endyear); // Load variable for pagination $limit = GETPOST('limit', 'int') ?GETPOST('limit', 'int') : (empty($conf->global->ACCOUNTING_LIMIT_LIST_VENTILATION) ? $conf->liste_limit : $conf->global->ACCOUNTING_LIMIT_LIST_VENTILATION); @@ -61,9 +66,9 @@ $page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("pa if (empty($page) || $page < 0) { $page = 0; } +$offset = $limit * $page; $pageprev = $page - 1; $pagenext = $page + 1; -$offset = $limit * $page; if (!$sortfield) { $sortfield = "erd.date, erd.rowid"; } @@ -101,9 +106,14 @@ if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x' $search_amount = ''; $search_account = ''; $search_vat = ''; - $search_day = ''; - $search_month = ''; - $search_year = ''; + $search_date_startday = ''; + $search_date_startmonth = ''; + $search_date_startyear = ''; + $search_date_endday = ''; + $search_date_endmonth = ''; + $search_date_endyear = ''; + $search_date_start = ''; + $search_date_end = ''; } if (is_array($changeaccount) && count($changeaccount) > 0 && $user->rights->accounting->bind->write) { @@ -204,7 +214,12 @@ if (strlen(trim($search_account))) { if (strlen(trim($search_vat))) { $sql .= natural_search("erd.tva_tx", price2num($search_vat), 1); } -$sql .= dolSqlDateFilter('erd.date', $search_day, $search_month, $search_year); +if ($search_date_start) { + $sql .= " AND erd.date >= '".$db->idate($search_date_start)."'"; +} +if ($search_date_end) { + $sql .= " AND erd.date <= '".$db->idate($search_date_end)."'"; +} $sql .= " AND er.entity IN (".getEntity('expensereport', 0).")"; // We don't share object for accountancy $sql .= $db->order($sortfield, $sortorder); @@ -222,9 +237,8 @@ if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { $sql .= $db->plimit($limit + 1, $offset); -dol_syslog('accountancy/expensereport/lines.php::list'); +dol_syslog("accountancy/expensereport/lines.php", LOG_DEBUG); $result = $db->query($sql); - if ($result) { $num_lines = $db->num_rows($result); $i = 0; @@ -254,14 +268,23 @@ if ($result) { if ($search_vat) { $param .= "&search_vat=".urlencode($search_vat); } - if ($search_day) { - $param .= '&search_day='.urlencode($search_day); + if ($search_date_startday) { + $param .= '&search_date_startday='.urlencode($search_date_startday); } - if ($search_month) { - $param .= '&search_month='.urlencode($search_month); + if ($search_date_startmonth) { + $param .= '&search_date_startmonth='.urlencode($search_date_startmonth); } - if ($search_year) { - $param .= '&search_year='.urlencode($search_year); + if ($search_date_startyear) { + $param .= '&search_date_startyear='.urlencode($search_date_startyear); + } + if ($search_date_endday) { + $param .= '&search_date_endday='.urlencode($search_date_endday); + } + if ($search_date_endmonth) { + $param .= '&search_date_endmonth='.urlencode($search_date_endmonth); + } + if ($search_date_endyear) { + $param .= '&search_date_endyear='.urlencode($search_date_endyear); } print '
    '."\n"; @@ -276,12 +299,11 @@ if ($result) { print ''; print_barre_liste($langs->trans("ExpenseReportLinesDone"), $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num_lines, $nbtotalofrecords, 'title_accountancy', 0, '', '', $limit); - print ''.$langs->trans("DescVentilDoneExpenseReport").'
    '; - print '
    '.$langs->trans("ChangeAccount").'
    '; + print '
    '.$langs->trans("ChangeAccount").' '; print $formaccounting->select_account($account_parent, 'account_parent', 2, array(), 0, 0, 'maxwidth300 maxwidthonsmartphone valignmiddle'); - print '
    '; + print '
    '; $moreforfilter = ''; @@ -296,11 +318,12 @@ if ($result) { print '
    '; - if (!empty($conf->global->MAIN_LIST_FILTER_ON_DAY)) { - print ''; - } - print ''; - $formother->select_year($search_year, 'search_year', 1, 20, 5); + print '
    '; + print $form->selectDate($search_date_start ? $search_date_start : -1, 'search_date_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('From')); + print '
    '; + print '
    '; + print $form->selectDate($search_date_end ? $search_date_end : -1, 'search_date_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('to')); + print '
    '; print '
    '.vatrate($objp->tva_tx.($objp->vat_src_code ? ' ('.$objp->vat_src_code.')' : '')).''; + print ''; print $accountingaccountstatic->getNomUrl(0, 1, 1, '', 1); print ' '; print img_edit(); print '
    '; - if (!empty($conf->global->MAIN_LIST_FILTER_ON_DAY)) { - print ''; - } - print ''; - $formother->select_year($search_year, 'search_year', 1, 20, 5); + print ''; + print '
    '; + print $form->selectDate($search_date_start ? $search_date_start : -1, 'search_date_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('From')); + print '
    '; + print '
    '; + print $form->selectDate($search_date_end ? $search_date_end : -1, 'search_date_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('to')); + print '
    '; print '
    '; + print ''; $searchpicto = $form->showFilterButtons(); print $searchpicto; print ''; if ($module->type == 'pdf') { - $linkspec = ''.img_object($langs->trans("Preview"), 'bill').''; + $linkspec = ''.img_object($langs->trans("Preview"), 'pdf').''; } else { $linkspec = img_object($langs->trans("PreviewNotAvailable"), 'generic'); } From cb862246131978fa1c62cde353f6c813216f5681 Mon Sep 17 00:00:00 2001 From: Sylvain Legrand Date: Fri, 25 Feb 2022 09:33:08 +0100 Subject: [PATCH 184/255] new : allow to show all logos on a table --- htdocs/core/lib/files.lib.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/htdocs/core/lib/files.lib.php b/htdocs/core/lib/files.lib.php index d1364598c07..04c3a481d00 100644 --- a/htdocs/core/lib/files.lib.php +++ b/htdocs/core/lib/files.lib.php @@ -987,7 +987,7 @@ function dol_unescapefile($filename) */ function dolCheckVirus($src_file) { - global $conf; + global $conf, $db; if (!empty($conf->global->MAIN_ANTIVIRUS_COMMAND)) { if (!class_exists('AntiVir')) { @@ -2371,6 +2371,10 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, // Wrapping for users photos $accessallowed = 1; $original_file = $conf->user->dir_output.'/'.$original_file; + } elseif (($modulepart == 'companylogo') && !empty($conf->mycompany->dir_output)) { + // Wrapping for users logos + $accessallowed = 1; + $original_file = $conf->mycompany->dir_output.'/logos/'.$original_file; } elseif ($modulepart == 'memberphoto' && !empty($conf->adherent->dir_output)) { // Wrapping for members photos $accessallowed = 1; From be95662ece21162f475fb42876cff87e2843cf06 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 25 Feb 2022 13:19:01 +0100 Subject: [PATCH 185/255] Revert "NEW : accoutancy : subleger label input automatic filling when selecting subleger account in select2 list" --- htdocs/accountancy/bookkeeping/card.php | 4 ++-- htdocs/core/class/html.formaccounting.class.php | 15 +-------------- 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/htdocs/accountancy/bookkeeping/card.php b/htdocs/accountancy/bookkeeping/card.php index 01e78cf4d27..c156a388735 100644 --- a/htdocs/accountancy/bookkeeping/card.php +++ b/htdocs/accountancy/bookkeeping/card.php @@ -659,7 +659,7 @@ if ($action == 'create') { // Also, it is not possible to use a value that is not in the list. // Also, the label is not automatically filled when a value is selected. if (!empty($conf->global->ACCOUNTANCY_COMBO_FOR_AUX)) { - print $formaccounting->select_auxaccount((GETPOSTISSET("subledger_account") ? GETPOST("subledger_account", "alpha") : $line->subledger_account), 'subledger_account', 1, 'maxwidth250', '', 'subledger_label'); + print $formaccounting->select_auxaccount((GETPOSTISSET("subledger_account") ? GETPOST("subledger_account", "alpha") : $line->subledger_account), 'subledger_account', 1); } else { print 'subledger_account).'" placeholder="'.dol_escape_htmltag($langs->trans("SubledgerAccount")).'">'; } @@ -728,7 +728,7 @@ if ($action == 'create') { // Also, it is not possible to use a value that is not in the list. // Also, the label is not automatically filled when a value is selected. if (!empty($conf->global->ACCOUNTANCY_COMBO_FOR_AUX)) { - print $formaccounting->select_auxaccount('', 'subledger_account', 1, 'maxwidth250', '', 'subledger_label'); + print $formaccounting->select_auxaccount('', 'subledger_account', 1); } else { print ''; } diff --git a/htdocs/core/class/html.formaccounting.class.php b/htdocs/core/class/html.formaccounting.class.php index 645e045a903..dc6e6d8c6cd 100644 --- a/htdocs/core/class/html.formaccounting.class.php +++ b/htdocs/core/class/html.formaccounting.class.php @@ -441,7 +441,7 @@ class FormAccounting extends Form * @param string $usecache Key to use to store result into a cache. Next call with same key will reuse the cache. * @return string String with HTML select */ - public function select_auxaccount($selectid, $htmlname = 'account_num_aux', $showempty = 0, $morecss = 'maxwidth250', $usecache = '', $labelhtmlname = '') + public function select_auxaccount($selectid, $htmlname = 'account_num_aux', $showempty = 0, $morecss = 'maxwidth250', $usecache = '') { // phpcs:enable @@ -505,19 +505,6 @@ class FormAccounting extends Form // Build select $out .= Form::selectarray($htmlname, $aux_account, $selectid, ($showempty ? (is_numeric($showempty) ? 1 : $showempty): 0), 0, 0, '', 0, 0, 0, '', $morecss, 1); - //automatic filling if we give the name of the subledger_label input - if (!empty($labelhtmlname)) { - $out .= ''; - } return $out; } From 84db3437bd60524105b93f98da0ab4a5adf510a5 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 25 Feb 2022 14:13:42 +0100 Subject: [PATCH 186/255] Add missing ' in command --- htdocs/admin/tools/export_files.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/admin/tools/export_files.php b/htdocs/admin/tools/export_files.php index 36be1f273ff..a3c20d0dffc 100644 --- a/htdocs/admin/tools/export_files.php +++ b/htdocs/admin/tools/export_files.php @@ -173,7 +173,7 @@ if ($compression == 'zip') { // We also exclude '/temp/' dir and 'documents/admin/documents' // We make escapement here and call executeCLI without escapement because we don't want to have the '*.log' escaped. - $cmd = "tar -cf ".escapeshellcmd($outputdir."/".$file)." --exclude-vcs --exclude-caches-all --exclude='temp' --exclude='*.log' --exclude='*.pdf_preview-*.png' --exclude='documents/admin/documents' -C '".escapeshellcmd(dol_sanitizePathName($dirtoswitch))."' '".escapeshellcmd(dol_sanitizeFileName($dirtocompress))."'"; + $cmd = "tar -cf '".escapeshellcmd($outputdir."/".$file)."' --exclude-vcs --exclude-caches-all --exclude='temp' --exclude='*.log' --exclude='*.pdf_preview-*.png' --exclude='documents/admin/documents' -C '".escapeshellcmd(dol_sanitizePathName($dirtoswitch))."' '".escapeshellcmd(dol_sanitizeFileName($dirtocompress))."'"; $result = $utils->executeCLI($cmd, $outputfile, 0, null, 1); From 722b1de2b7fb9914e23599929a686a97ff7e53da Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Fri, 25 Feb 2022 15:10:10 +0000 Subject: [PATCH 187/255] Fixing style errors. --- htdocs/accountancy/bookkeeping/card.php | 4 ++-- htdocs/core/class/html.formaccounting.class.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/htdocs/accountancy/bookkeeping/card.php b/htdocs/accountancy/bookkeeping/card.php index ce284598820..5b645796a32 100644 --- a/htdocs/accountancy/bookkeeping/card.php +++ b/htdocs/accountancy/bookkeeping/card.php @@ -663,7 +663,7 @@ if ($action == 'create') { // Also, it is not possible to use a value that is not in the list. // Also, the label is not automatically filled when a value is selected. if (!empty($conf->global->ACCOUNTANCY_COMBO_FOR_AUX)) { - print $formaccounting->select_auxaccount((GETPOSTISSET("subledger_account") ? GETPOST("subledger_account", "alpha") : $line->subledger_account), 'subledger_account', 1,'maxwidth250','','subledger_label'); + print $formaccounting->select_auxaccount((GETPOSTISSET("subledger_account") ? GETPOST("subledger_account", "alpha") : $line->subledger_account), 'subledger_account', 1, 'maxwidth250', '', 'subledger_label'); } else { print 'subledger_account).'" placeholder="'.dol_escape_htmltag($langs->trans("SubledgerAccount")).'">'; } @@ -746,7 +746,7 @@ if ($action == 'create') { // Also, it is not possible to use a value that is not in the list. // Also, the label is not automatically filled when a value is selected. if (!empty($conf->global->ACCOUNTANCY_COMBO_FOR_AUX)) { - print $formaccounting->select_auxaccount('', 'subledger_account', 1,'maxwidth250','','subledger_label'); + print $formaccounting->select_auxaccount('', 'subledger_account', 1, 'maxwidth250', '', 'subledger_label'); } else { print ''; } diff --git a/htdocs/core/class/html.formaccounting.class.php b/htdocs/core/class/html.formaccounting.class.php index 44a52ae7721..3dc81333e7f 100644 --- a/htdocs/core/class/html.formaccounting.class.php +++ b/htdocs/core/class/html.formaccounting.class.php @@ -518,7 +518,7 @@ class FormAccounting extends Form '; } - + return $out; } From c242a0561bbb4c000df21d337b492732597aaf27 Mon Sep 17 00:00:00 2001 From: Francis Appels Date: Fri, 25 Feb 2022 16:11:16 +0100 Subject: [PATCH 188/255] Fix shipping list, e.shipping_method_id should be e.fk_shipping_method. Disabled searchall for shipping method, does not work. --- htdocs/expedition/list.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/htdocs/expedition/list.php b/htdocs/expedition/list.php index 378d95e00c8..2d81c5e0545 100644 --- a/htdocs/expedition/list.php +++ b/htdocs/expedition/list.php @@ -116,7 +116,7 @@ $fieldstosearchall = array( 'e.ref'=>"Ref", 's.nom'=>"ThirdParty", 'e.note_public'=>'NotePublic', - 'e.shipping_method_id'=>'SendingMethod', + //'e.fk_shipping_method'=>'SendingMethod', // TODO fix this, does not work 'e.tracking_number'=>"TrackingNumber", ); if (empty($user->socid)) { @@ -134,7 +134,7 @@ $arrayfields = array( 'country.code_iso'=>array('label'=>$langs->trans("Country"), 'checked'=>0, 'position'=>7), 'typent.code'=>array('label'=>$langs->trans("ThirdPartyType"), 'checked'=>$checkedtypetiers, 'position'=>8), 'e.date_delivery'=>array('label'=>$langs->trans("DateDeliveryPlanned"), 'checked'=>1, 'position'=>9), - 'e.shipping_method_id'=>array('label'=>$langs->trans('SendingMethod'), 'checked'=>1, 'position'=>10), + 'e.fk_shipping_method'=>array('label'=>$langs->trans('SendingMethod'), 'checked'=>1, 'position'=>10), 'e.tracking_number'=>array('label'=>$langs->trans("TrackingNumber"), 'checked'=>1, 'position'=>11), 'e.weight'=>array('label'=>$langs->trans("Weight"), 'checked'=>0, 'position'=>12), 'e.datec'=>array('label'=>$langs->trans("DateCreation"), 'checked'=>0, 'position'=>500), @@ -654,7 +654,7 @@ if (!empty($arrayfields['e.date_delivery']['checked'])) { print ''; print ''; $shipment->fetch_delivery_methods(); @@ -751,8 +751,8 @@ if (!empty($arrayfields['e.weight']['checked'])) { if (!empty($arrayfields['e.date_delivery']['checked'])) { print_liste_field_titre($arrayfields['e.date_delivery']['label'], $_SERVER["PHP_SELF"], "e.date_delivery", "", $param, '', $sortfield, $sortorder, 'center '); } -if (!empty($arrayfields['e.shipping_method_id']['checked'])) { - print_liste_field_titre($arrayfields['e.shipping_method_id']['label'], $_SERVER["PHP_SELF"], "e.fk_shipping_method", "", $param, '', $sortfield, $sortorder, 'center '); +if (!empty($arrayfields['e.fk_shipping_method']['checked'])) { + print_liste_field_titre($arrayfields['e.fk_shipping_method']['label'], $_SERVER["PHP_SELF"], "e.fk_shipping_method", "", $param, '', $sortfield, $sortorder, 'center '); } if (!empty($arrayfields['e.tracking_number']['checked'])) { print_liste_field_titre($arrayfields['e.tracking_number']['label'], $_SERVER["PHP_SELF"], "e.tracking_number", "", $param, '', $sortfield, $sortorder, 'center '); @@ -901,7 +901,7 @@ while ($i < min($num, $limit)) { print dol_print_date($db->jdate($obj->delivery_date), "dayhour"); print "'; From 4082de422f38a284c3c1baad7c60b7d50d4e878b Mon Sep 17 00:00:00 2001 From: Yoan Mollard Date: Fri, 25 Feb 2022 16:27:55 +0100 Subject: [PATCH 189/255] Set default ticket type to OTHER if no default exists --- htdocs/install/mysql/data/llx_c_ticket_type.sql | 2 +- htdocs/install/mysql/migration/15.0.0-16.0.0.sql | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/htdocs/install/mysql/data/llx_c_ticket_type.sql b/htdocs/install/mysql/data/llx_c_ticket_type.sql index 3b6fda322ad..85a85b0a63d 100644 --- a/htdocs/install/mysql/data/llx_c_ticket_type.sql +++ b/htdocs/install/mysql/data/llx_c_ticket_type.sql @@ -23,4 +23,4 @@ INSERT INTO llx_c_ticket_type (code, pos, label, active, use_default, descriptio INSERT INTO llx_c_ticket_type (code, pos, label, active, use_default, description) VALUES('PROBLEM', '22', 'Problem', 0, 0, NULL); INSERT INTO llx_c_ticket_type (code, pos, label, active, use_default, description) VALUES('REQUEST', '25', 'Change or enhancement request', 1, 0, NULL); INSERT INTO llx_c_ticket_type (code, pos, label, active, use_default, description) VALUES('PROJECT', '30', 'Project', 0, 0, NULL); -INSERT INTO llx_c_ticket_type (code, pos, label, active, use_default, description) VALUES('OTHER', '40', 'Other', 1, 0, NULL); +INSERT INTO llx_c_ticket_type (code, pos, label, active, use_default, description) VALUES('OTHER', '40', 'Other', 1, 1, NULL); diff --git a/htdocs/install/mysql/migration/15.0.0-16.0.0.sql b/htdocs/install/mysql/migration/15.0.0-16.0.0.sql index 03261a5fe62..5e4cf4adfad 100644 --- a/htdocs/install/mysql/migration/15.0.0-16.0.0.sql +++ b/htdocs/install/mysql/migration/15.0.0-16.0.0.sql @@ -251,3 +251,5 @@ ALTER TABLE llx_reception MODIFY COLUMN ref_supplier varchar(128); ALTER TABLE llx_bank_account ADD COLUMN pti_in_ctti smallint DEFAULT 0 AFTER domiciliation; +-- Set default ticket type to OTHER if no default exists +UPDATE llx_c_ticket_type SET use_default=1 WHERE code='OTHER' AND NOT EXISTS(SELECT * FROM (SELECT * FROM llx_c_ticket_type) AS t WHERE use_default=1); \ No newline at end of file From b989c257ad956c79a5d990a1f51e733790416c79 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 25 Feb 2022 18:53:21 +0100 Subject: [PATCH 190/255] Fix report on salaries --- htdocs/compta/resultat/clientfourn.php | 45 ++++++++++++-------------- htdocs/compta/resultat/index.php | 27 ++++++++++------ 2 files changed, 38 insertions(+), 34 deletions(-) diff --git a/htdocs/compta/resultat/clientfourn.php b/htdocs/compta/resultat/clientfourn.php index f650244d677..8f71015517c 100644 --- a/htdocs/compta/resultat/clientfourn.php +++ b/htdocs/compta/resultat/clientfourn.php @@ -857,34 +857,29 @@ if ($modecompta == 'BOOKKEEPING') { if ($modecompta == 'CREANCES-DETTES' || $modecompta == 'RECETTES-DEPENSES') { if ($modecompta == 'CREANCES-DETTES') { - $column = 'b.datev'; + $column = 's.dateep'; // We use the date of end of period of salary + + $sql = "SELECT u.rowid, u.firstname, u.lastname, s.fk_user as fk_user, s.label as label, date_format($column,'%Y-%m') as dm, sum(s.amount) as amount"; + $sql .= " FROM ".MAIN_DB_PREFIX."salary as s"; + $sql .= " INNER JOIN ".MAIN_DB_PREFIX."user as u ON u.rowid = s.fk_user"; + $sql .= " WHERE s.entity IN (".getEntity('salary').")"; + if (!empty($date_start) && !empty($date_end)) { + $sql .= " AND $column >= '".$db->idate($date_start)."' AND $column <= '".$db->idate($date_end)."'"; + } + $sql .= " GROUP BY u.rowid, u.firstname, u.lastname, s.fk_user, s.label, dm"; } else { $column = 'p.datep'; + $sql = "SELECT u.rowid, u.firstname, u.lastname, s.fk_user as fk_user, p.label as label, date_format($column,'%Y-%m') as dm, sum(p.amount) as amount"; + $sql .= " FROM ".MAIN_DB_PREFIX."payment_salary as p"; + $sql .= " INNER JOIN ".MAIN_DB_PREFIX."salary as s ON s.rowid = p.fk_salary"; + $sql .= " INNER JOIN ".MAIN_DB_PREFIX."user as u ON u.rowid = s.fk_user"; + $sql .= " WHERE p.entity IN (".getEntity('payment_salary').")"; + if (!empty($date_start) && !empty($date_end)) { + $sql .= " AND $column >= '".$db->idate($date_start)."' AND $column <= '".$db->idate($date_end)."'"; + } + $sql .= " GROUP BY u.rowid, u.firstname, u.lastname, s.fk_user, p.label, dm"; } - $sql = "SELECT u.rowid, u.firstname, u.lastname, s.fk_user as fk_user, p.label as label, date_format($column,'%Y-%m') as dm, sum(p.amount) as amount"; - $sql .= " FROM ".MAIN_DB_PREFIX."payment_salary as p"; - $sql .= " INNER JOIN ".MAIN_DB_PREFIX."salary as s ON s.rowid=p.fk_salary"; - $sql .= " INNER JOIN ".MAIN_DB_PREFIX."bank as b ON p.fk_bank=b.rowid"; - $sql .= " INNER JOIN ".MAIN_DB_PREFIX."user as u ON u.rowid=s.fk_user"; - $sql .= " WHERE p.entity IN (".getEntity('payment_salary').")"; - if (!empty($date_start) && !empty($date_end)) { - $sql .= " AND $column >= '".$db->idate($date_start)."' AND $column <= '".$db->idate($date_end)."'"; - } - $sql .= " GROUP BY u.rowid, u.firstname, u.lastname, s.fk_user, p.label, dm"; - - // For backward compatibility with old module salary - $sql .= " UNION "; - $sql .= " SELECT u.rowid, u.firstname, u.lastname, p.fk_user as fk_user, p.label as label, date_format($column,'%Y-%m') as dm, sum(p.amount) as amount"; - $sql .= " FROM ".MAIN_DB_PREFIX."payment_salary as p"; - $sql .= " INNER JOIN ".MAIN_DB_PREFIX."bank as b ON p.fk_bank=b.rowid"; - $sql .= " INNER JOIN ".MAIN_DB_PREFIX."user as u ON u.rowid=p.fk_user"; - $sql .= " WHERE p.entity IN (".getEntity('payment_salary').")"; - if (!empty($date_start) && !empty($date_end)) { - $sql .= " AND $column >= '".$db->idate($date_start)."' AND $column <= '".$db->idate($date_end)."'"; - } - $sql .= " GROUP BY u.rowid, u.firstname, u.lastname, p.fk_user, p.label, dm"; - $newsortfield = $sortfield; if ($newsortfield == 's.nom, s.rowid') { $newsortfield = 'u.firstname, u.lastname'; @@ -898,7 +893,7 @@ if ($modecompta == 'BOOKKEEPING') { $sql .= $db->order($newsortfield, $sortorder); } - dol_syslog("get payment salaries"); + dol_syslog("get salaries"); $result = $db->query($sql); $subtotal_ht = 0; $subtotal_ttc = 0; diff --git a/htdocs/compta/resultat/index.php b/htdocs/compta/resultat/index.php index 5f10013f294..2d3ba90cd7d 100644 --- a/htdocs/compta/resultat/index.php +++ b/htdocs/compta/resultat/index.php @@ -611,22 +611,31 @@ if (!empty($conf->tax->enabled) && ($modecompta == 'CREANCES-DETTES' || $modecom if (!empty($conf->salaries->enabled) && ($modecompta == 'CREANCES-DETTES' || $modecompta == "RECETTES-DEPENSES")) { if ($modecompta == 'CREANCES-DETTES') { - $column = 'b.datev'; + $column = 's.dateep'; // we use the date of end of period of salary + + $sql = "SELECT s.label as nom, date_format(".$column.",'%Y-%m') as dm, sum(s.amount) as amount"; + $sql .= " FROM ".MAIN_DB_PREFIX."salary as s"; + $sql .= " WHERE s.entity IN (".getEntity('salary').")"; + if (!empty($date_start) && !empty($date_end)) { + $sql .= " AND ".$column." >= '".$db->idate($date_start)."' AND ".$column." <= '".$db->idate($date_end)."'"; + } + $sql .= " GROUP BY s.label, dm"; } if ($modecompta == "RECETTES-DEPENSES") { $column = 'p.datep'; + + $sql = "SELECT p.label as nom, date_format(".$column.",'%Y-%m') as dm, sum(p.amount) as amount"; + $sql .= " FROM ".MAIN_DB_PREFIX."payment_salary as p"; + $sql .= " INNER JOIN ".MAIN_DB_PREFIX."salary as s ON p.fk_salary = s.rowid"; + $sql .= " WHERE p.entity IN (".getEntity('payment_salary').")"; + if (!empty($date_start) && !empty($date_end)) { + $sql .= " AND ".$column." >= '".$db->idate($date_start)."' AND ".$column." <= '".$db->idate($date_end)."'"; + } + $sql .= " GROUP BY p.label, dm"; } $subtotal_ht = 0; $subtotal_ttc = 0; - $sql = "SELECT p.label as nom, date_format(".$column.",'%Y-%m') as dm, sum(p.amount) as amount"; - $sql .= " FROM ".MAIN_DB_PREFIX."payment_salary as p"; - $sql .= " INNER JOIN ".MAIN_DB_PREFIX."bank as b ON p.fk_bank=b.rowid"; - $sql .= " WHERE p.entity IN (".getEntity('payment_salary').")"; - if (!empty($date_start) && !empty($date_end)) { - $sql .= " AND ".$column." >= '".$db->idate($date_start)."' AND ".$column." <= '".$db->idate($date_end)."'"; - } - $sql .= " GROUP BY p.label, dm"; dol_syslog("get social salaries payments"); $result = $db->query($sql); From 488049c6a657df9004bacdaef595b247cdb9b80f Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 25 Feb 2022 20:36:40 +0100 Subject: [PATCH 191/255] FIX bad position of extrafields for interventions --- htdocs/core/class/commonobject.class.php | 2 +- htdocs/core/tpl/objectline_create.tpl.php | 2 +- htdocs/fichinter/card.php | 72 +++++++++++++++-------- 3 files changed, 49 insertions(+), 27 deletions(-) diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index 8dabc902e5c..4b3d6fca2d3 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -7699,7 +7699,7 @@ abstract class CommonObject if (empty($reshook)) { if (key_exists('label', $extrafields->attributes[$this->table_element]) && is_array($extrafields->attributes[$this->table_element]['label']) && count($extrafields->attributes[$this->table_element]['label']) > 0) { $out .= "\n"; - $out .= ' '; + $out .= ' '; $out .= "\n"; $extrafields_collapse_num = ''; diff --git a/htdocs/core/tpl/objectline_create.tpl.php b/htdocs/core/tpl/objectline_create.tpl.php index 8d21a789648..daef20542a5 100644 --- a/htdocs/core/tpl/objectline_create.tpl.php +++ b/htdocs/core/tpl/objectline_create.tpl.php @@ -354,7 +354,7 @@ if ($nolinesbefore) { } if (is_object($objectline)) { $temps = $objectline->showOptionals($extrafields, 'create', array(), '', '', 1, 'line'); - ; + if (!empty($temps)) { print '
    '; print $temps; diff --git a/htdocs/fichinter/card.php b/htdocs/fichinter/card.php index a58a62b5ffd..e02a601c9cd 100644 --- a/htdocs/fichinter/card.php +++ b/htdocs/fichinter/card.php @@ -1342,6 +1342,23 @@ if ($action == 'create') { print ''; // ancre pour retourner sur la ligne print dol_htmlentitiesbr($objp->description); + $objectline = new FichinterLigne($db); + $objectline->fetch($objp->rowid); + $objectline->fetch_optionals(); + + $extrafields->fetch_name_optionals_label($objectline->table_element); + + if (!empty($extrafields)) { + $temps = $objectline->showOptionals($extrafields, 'view', array(), '', '', 1, 'line'); + if (!empty($temps)) { + print '
    '; + print $temps; + print '
    '; + } + } + + print '
    '.(empty($conf->global->FICHINTER_DATE_WITHOUT_HOUR) ?dol_print_date($db->jdate($objp->date_intervention), 'dayhour') : dol_print_date($db->jdate($objp->date_intervention), 'day')).'
    '; } From acf6d195005b55b1ecb2c818c30af3e6a45d040a Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 25 Feb 2022 21:45:29 +0100 Subject: [PATCH 192/255] Fix CSS --- htdocs/core/class/html.form.class.php | 15 ++++++++------- htdocs/core/class/html.formcategory.class.php | 4 ++-- htdocs/core/class/html.formother.class.php | 19 ++++++++++--------- htdocs/projet/list.php | 6 +++--- 4 files changed, 23 insertions(+), 21 deletions(-) diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 6e5c0a572d2..1bdd1161770 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -1599,7 +1599,7 @@ class Form * @param string $exclude List of contacts id to exclude * @param string $limitto Disable answers that are not id in this array list * @param integer $showfunction Add function into label - * @param string $moreclass Add more class to class style + * @param string $morecss Add more class to class style * @param integer $showsoc Add company into label * @param int $forcecombo Force to use combo box * @param array $events Event options. Example: array(array('method'=>'getContacts', 'url'=>dol_buildpath('/core/ajax/contacts.php',1), 'htmlname'=>'contactid', 'params'=>array('add-customer-contact'=>'disabled'))) @@ -1609,10 +1609,10 @@ class Form * @return int <0 if KO, Nb of contact in list if OK * @deprecated You can use selectcontacts directly (warning order of param was changed) */ - public function select_contacts($socid, $selected = '', $htmlname = 'contactid', $showempty = 0, $exclude = '', $limitto = '', $showfunction = 0, $moreclass = '', $showsoc = 0, $forcecombo = 0, $events = array(), $options_only = false, $moreparam = '', $htmlid = '') + public function select_contacts($socid, $selected = '', $htmlname = 'contactid', $showempty = 0, $exclude = '', $limitto = '', $showfunction = 0, $morecss = '', $showsoc = 0, $forcecombo = 0, $events = array(), $options_only = false, $moreparam = '', $htmlid = '') { // phpcs:enable - print $this->selectcontacts($socid, $selected, $htmlname, $showempty, $exclude, $limitto, $showfunction, $moreclass, $options_only, $showsoc, $forcecombo, $events, $moreparam, $htmlid); + print $this->selectcontacts($socid, $selected, $htmlname, $showempty, $exclude, $limitto, $showfunction, $morecss, $options_only, $showsoc, $forcecombo, $events, $moreparam, $htmlid); return $this->num; } @@ -1629,7 +1629,7 @@ class Form * @param string $exclude List of contacts id to exclude * @param string $limitto Disable answers that are not id in this array list * @param integer $showfunction Add function into label - * @param string $moreclass Add more class to class style + * @param string $morecss Add more class to class style * @param bool $options_only Return options only (for ajax treatment) * @param integer $showsoc Add company into label * @param int $forcecombo Force to use combo box (so no ajax beautify effect) @@ -1640,7 +1640,7 @@ class Form * @param integer $disableifempty Set tag 'disabled' on select if there is no choice * @return int|string <0 if KO, HTML with select string if OK. */ - public function selectcontacts($socid, $selected = '', $htmlname = 'contactid', $showempty = 0, $exclude = '', $limitto = '', $showfunction = 0, $moreclass = '', $options_only = false, $showsoc = 0, $forcecombo = 0, $events = array(), $moreparam = '', $htmlid = '', $multiple = false, $disableifempty = 0) + public function selectcontacts($socid, $selected = '', $htmlname = 'contactid', $showempty = 0, $exclude = '', $limitto = '', $showfunction = 0, $morecss = '', $options_only = false, $showsoc = 0, $forcecombo = 0, $events = array(), $moreparam = '', $htmlid = '', $multiple = false, $disableifempty = 0) { global $conf, $langs, $hookmanager, $action; @@ -1687,7 +1687,7 @@ class Form $num = $this->db->num_rows($resql); if ($htmlname != 'none' && !$options_only) { - $out .= ''; } if ($showempty && ! is_numeric($showempty)) { @@ -2085,7 +2085,7 @@ class Form if ($num) { // Enhance with select2 include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php'; - $out = ajax_combobox($htmlname).$out; + $out .= ajax_combobox($htmlname); } } else { dol_print_error($this->db); @@ -2094,6 +2094,7 @@ class Form if ($outputmode) { return $outarray; } + return $out; } diff --git a/htdocs/core/class/html.formcategory.class.php b/htdocs/core/class/html.formcategory.class.php index 518a8f93290..1a2c02deb54 100644 --- a/htdocs/core/class/html.formcategory.class.php +++ b/htdocs/core/class/html.formcategory.class.php @@ -49,13 +49,13 @@ class FormCategory extends Form $categoryArray = $this->select_all_categories($type, "", "", 64, 0, 1); $categoryArray[-2] = "- ".$langs->trans('NotCategorized')." -"; - $tmptitle = $langs->trans("Category"); + $tmptitle = $langs->transnoentitiesnoconv("Category"); $filter = ''; $filter .= '
    '; $filter .= img_picto($tmptitle, 'category', 'class="pictofixedwidth"'); //$filter .= $langs->trans('Categories').": "; - $filter .= Form::multiselectarray($htmlName, $categoryArray, $preSelected, 0, 0, "minwidth300", 0, 0, '', '', $tmptitle); + $filter .= Form::multiselectarray($htmlName, $categoryArray, $preSelected, 0, 0, "minwidth300 widthcentpercentminusx", 0, 0, '', '', $tmptitle); $filter .= "
    "; return $filter; diff --git a/htdocs/core/class/html.formother.class.php b/htdocs/core/class/html.formother.class.php index 0c55a1fd853..f1f0a846f93 100644 --- a/htdocs/core/class/html.formother.class.php +++ b/htdocs/core/class/html.formother.class.php @@ -473,15 +473,6 @@ class FormOther $langs->load('users'); $out = ''; - // Enhance with select2 - if ($conf->use_javascript_ajax) { - include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php'; - - $comboenhancement = ajax_combobox($htmlname); - if ($comboenhancement) { - $out .= $comboenhancement; - } - } $reshook = $hookmanager->executeHooks('addSQLWhereFilterOnSelectSalesRep', array(), $this, $action); @@ -622,6 +613,16 @@ class FormOther $out .= ''; + // Enhance with select2 + if ($conf->use_javascript_ajax) { + include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php'; + + $comboenhancement = ajax_combobox($htmlname); + if ($comboenhancement) { + $out .= $comboenhancement; + } + } + return $out; } diff --git a/htdocs/projet/list.php b/htdocs/projet/list.php index b19bc407537..54cb72f744e 100644 --- a/htdocs/projet/list.php +++ b/htdocs/projet/list.php @@ -821,12 +821,12 @@ $includeonly = ''; if (empty($user->rights->user->user->lire)) { $includeonly = array($user->id); } -$moreforfilter .= img_picto($tmptitle, 'user', 'class="pictofixedwidth"').$form->select_dolusers($search_project_user ? $search_project_user : '', 'search_project_user', $tmptitle, '', 0, $includeonly, '', 0, 0, 0, '', 0, '', 'maxwidth250'); +$moreforfilter .= img_picto($tmptitle, 'user', 'class="pictofixedwidth"').$form->select_dolusers($search_project_user ? $search_project_user : '', 'search_project_user', $tmptitle, '', 0, $includeonly, '', 0, 0, 0, '', 0, '', 'maxwidth250 widthcentpercentminusx'); $moreforfilter .= ''; $moreforfilter .= '
    '; $tmptitle = $langs->trans('ProjectsWithThisContact'); -$moreforfilter .= img_picto($tmptitle, 'user', 'class="pictofixedwidth"').$form->selectcontacts(0, $search_project_contact ? $search_project_contact : '', 'search_project_contact', $tmptitle); +$moreforfilter .= img_picto($tmptitle, 'user', 'class="pictofixedwidth"').$form->selectcontacts(0, $search_project_contact ? $search_project_contact : '', 'search_project_contact', $tmptitle, '', '', 0, 'maxwidth250 widthcentpercentminusx'); $moreforfilter .= '
    '; // If the user can view thirdparties other than his' @@ -834,7 +834,7 @@ if ($user->rights->societe->client->voir || $socid) { $langs->load("commercial"); $moreforfilter .= '
    '; $tmptitle = $langs->trans('ThirdPartiesOfSaleRepresentative'); - $moreforfilter .= img_picto($tmptitle, 'user', 'class="pictofixedwidth"').$formother->select_salesrepresentatives($search_sale, 'search_sale', $user, 0, $tmptitle, 'maxwidth250'); + $moreforfilter .= img_picto($tmptitle, 'user', 'class="pictofixedwidth"').$formother->select_salesrepresentatives($search_sale, 'search_sale', $user, 0, $tmptitle, 'maxwidth250 widthcentpercentminusx'); $moreforfilter .= '
    '; } From eba20957f3572965aa029a7c0e4e47624b534964 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 25 Feb 2022 21:45:29 +0100 Subject: [PATCH 193/255] Fix CSS Conflicts: htdocs/projet/list.php --- htdocs/core/class/html.form.class.php | 15 ++++++++------- htdocs/core/class/html.formcategory.class.php | 4 ++-- htdocs/core/class/html.formother.class.php | 19 ++++++++++--------- htdocs/projet/list.php | 4 ++-- 4 files changed, 22 insertions(+), 20 deletions(-) diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 8a0b66e0b78..f25c9aad9d3 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -1599,7 +1599,7 @@ class Form * @param string $exclude List of contacts id to exclude * @param string $limitto Disable answers that are not id in this array list * @param integer $showfunction Add function into label - * @param string $moreclass Add more class to class style + * @param string $morecss Add more class to class style * @param integer $showsoc Add company into label * @param int $forcecombo Force to use combo box * @param array $events Event options. Example: array(array('method'=>'getContacts', 'url'=>dol_buildpath('/core/ajax/contacts.php',1), 'htmlname'=>'contactid', 'params'=>array('add-customer-contact'=>'disabled'))) @@ -1609,10 +1609,10 @@ class Form * @return int <0 if KO, Nb of contact in list if OK * @deprecated You can use selectcontacts directly (warning order of param was changed) */ - public function select_contacts($socid, $selected = '', $htmlname = 'contactid', $showempty = 0, $exclude = '', $limitto = '', $showfunction = 0, $moreclass = '', $showsoc = 0, $forcecombo = 0, $events = array(), $options_only = false, $moreparam = '', $htmlid = '') + public function select_contacts($socid, $selected = '', $htmlname = 'contactid', $showempty = 0, $exclude = '', $limitto = '', $showfunction = 0, $morecss = '', $showsoc = 0, $forcecombo = 0, $events = array(), $options_only = false, $moreparam = '', $htmlid = '') { // phpcs:enable - print $this->selectcontacts($socid, $selected, $htmlname, $showempty, $exclude, $limitto, $showfunction, $moreclass, $options_only, $showsoc, $forcecombo, $events, $moreparam, $htmlid); + print $this->selectcontacts($socid, $selected, $htmlname, $showempty, $exclude, $limitto, $showfunction, $morecss, $options_only, $showsoc, $forcecombo, $events, $moreparam, $htmlid); return $this->num; } @@ -1629,7 +1629,7 @@ class Form * @param string $exclude List of contacts id to exclude * @param string $limitto Disable answers that are not id in this array list * @param integer $showfunction Add function into label - * @param string $moreclass Add more class to class style + * @param string $morecss Add more class to class style * @param bool $options_only Return options only (for ajax treatment) * @param integer $showsoc Add company into label * @param int $forcecombo Force to use combo box (so no ajax beautify effect) @@ -1640,7 +1640,7 @@ class Form * @param integer $disableifempty Set tag 'disabled' on select if there is no choice * @return int|string <0 if KO, HTML with select string if OK. */ - public function selectcontacts($socid, $selected = '', $htmlname = 'contactid', $showempty = 0, $exclude = '', $limitto = '', $showfunction = 0, $moreclass = '', $options_only = false, $showsoc = 0, $forcecombo = 0, $events = array(), $moreparam = '', $htmlid = '', $multiple = false, $disableifempty = 0) + public function selectcontacts($socid, $selected = '', $htmlname = 'contactid', $showempty = 0, $exclude = '', $limitto = '', $showfunction = 0, $morecss = '', $options_only = false, $showsoc = 0, $forcecombo = 0, $events = array(), $moreparam = '', $htmlid = '', $multiple = false, $disableifempty = 0) { global $conf, $langs, $hookmanager, $action; @@ -1687,7 +1687,7 @@ class Form $num = $this->db->num_rows($resql); if ($htmlname != 'none' && !$options_only) { - $out .= ''; } if (($showempty == 1 || ($showempty == 3 && $num > 1)) && !$multiple) { @@ -2080,7 +2080,7 @@ class Form if ($num) { // Enhance with select2 include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php'; - $out = ajax_combobox($htmlname).$out; + $out .= ajax_combobox($htmlname); } } else { dol_print_error($this->db); @@ -2089,6 +2089,7 @@ class Form if ($outputmode) { return $outarray; } + return $out; } diff --git a/htdocs/core/class/html.formcategory.class.php b/htdocs/core/class/html.formcategory.class.php index 518a8f93290..1a2c02deb54 100644 --- a/htdocs/core/class/html.formcategory.class.php +++ b/htdocs/core/class/html.formcategory.class.php @@ -49,13 +49,13 @@ class FormCategory extends Form $categoryArray = $this->select_all_categories($type, "", "", 64, 0, 1); $categoryArray[-2] = "- ".$langs->trans('NotCategorized')." -"; - $tmptitle = $langs->trans("Category"); + $tmptitle = $langs->transnoentitiesnoconv("Category"); $filter = ''; $filter .= '
    '; $filter .= img_picto($tmptitle, 'category', 'class="pictofixedwidth"'); //$filter .= $langs->trans('Categories').": "; - $filter .= Form::multiselectarray($htmlName, $categoryArray, $preSelected, 0, 0, "minwidth300", 0, 0, '', '', $tmptitle); + $filter .= Form::multiselectarray($htmlName, $categoryArray, $preSelected, 0, 0, "minwidth300 widthcentpercentminusx", 0, 0, '', '', $tmptitle); $filter .= "
    "; return $filter; diff --git a/htdocs/core/class/html.formother.class.php b/htdocs/core/class/html.formother.class.php index 2b7466628a5..aa0e5486761 100644 --- a/htdocs/core/class/html.formother.class.php +++ b/htdocs/core/class/html.formother.class.php @@ -473,15 +473,6 @@ class FormOther $langs->load('users'); $out = ''; - // Enhance with select2 - if ($conf->use_javascript_ajax) { - include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php'; - - $comboenhancement = ajax_combobox($htmlname); - if ($comboenhancement) { - $out .= $comboenhancement; - } - } $reshook = $hookmanager->executeHooks('addSQLWhereFilterOnSelectSalesRep', array(), $this, $action); @@ -622,6 +613,16 @@ class FormOther $out .= ''; + // Enhance with select2 + if ($conf->use_javascript_ajax) { + include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php'; + + $comboenhancement = ajax_combobox($htmlname); + if ($comboenhancement) { + $out .= $comboenhancement; + } + } + return $out; } diff --git a/htdocs/projet/list.php b/htdocs/projet/list.php index 6019011956a..552022f883f 100644 --- a/htdocs/projet/list.php +++ b/htdocs/projet/list.php @@ -806,7 +806,7 @@ $includeonly = ''; if (empty($user->rights->user->user->lire)) { $includeonly = array($user->id); } -$moreforfilter .= img_picto($tmptitle, 'user', 'class="pictofixedwidth"').$form->select_dolusers($search_project_user ? $search_project_user : '', 'search_project_user', $tmptitle, '', 0, $includeonly, '', 0, 0, 0, '', 0, '', 'maxwidth250'); +$moreforfilter .= img_picto($tmptitle, 'user', 'class="pictofixedwidth"').$form->select_dolusers($search_project_user ? $search_project_user : '', 'search_project_user', $tmptitle, '', 0, $includeonly, '', 0, 0, 0, '', 0, '', 'maxwidth250 widthcentpercentminusx'); $moreforfilter .= ''; // If the user can view thirdparties other than his' @@ -814,7 +814,7 @@ if ($user->rights->societe->client->voir || $socid) { $langs->load("commercial"); $moreforfilter .= '
    '; $tmptitle = $langs->trans('ThirdPartiesOfSaleRepresentative'); - $moreforfilter .= img_picto($tmptitle, 'user', 'class="pictofixedwidth"').$formother->select_salesrepresentatives($search_sale, 'search_sale', $user, 0, $tmptitle, 'maxwidth250'); + $moreforfilter .= img_picto($tmptitle, 'user', 'class="pictofixedwidth"').$formother->select_salesrepresentatives($search_sale, 'search_sale', $user, 0, $tmptitle, 'maxwidth250 widthcentpercentminusx'); $moreforfilter .= '
    '; } From fb0e2f9c6c87fcaa05c59212a62573d5b9c9c2be Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sat, 26 Feb 2022 01:00:22 +0100 Subject: [PATCH 194/255] FIX #yogosha9095 --- htdocs/core/lib/geturl.lib.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/htdocs/core/lib/geturl.lib.php b/htdocs/core/lib/geturl.lib.php index 50ae7c33561..1f6c088ac1b 100644 --- a/htdocs/core/lib/geturl.lib.php +++ b/htdocs/core/lib/geturl.lib.php @@ -215,7 +215,14 @@ function getURLContent($url, $postorget = 'GET', $param = '', $followlocation = } // Common check on ip (local and external) - $arrayofmetadataserver = array('100.100.100.200' => 'Alibaba', '192.0.0.192'=> 'Oracle', '192.80.8.124'=>'Packet'); + // See list on https://tagmerge.com/gist/a7b9d57ff8ec11d63642f8778609a0b8 + // Not evasive url that ar enot IP are excluded by test on IP v4/v6 validity. + $arrayofmetadataserver = array( + '100.100.100.200' => 'Alibaba', + '192.0.0.192' => 'Oracle', + '192.80.8.124' => 'Packet', + '100.88.222.5' => 'Tencent cloud', + ); foreach ($arrayofmetadataserver as $ipofmetadataserver => $nameofmetadataserver) { if ($iptocheck == $ipofmetadataserver) { $info['http_code'] = 400; From 18a8eac1cd4f79757abd6f48c86e486d6135cfcb Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Sat, 26 Feb 2022 07:17:44 +0100 Subject: [PATCH 195/255] Modify fix --- htdocs/compta/facture/card.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/htdocs/compta/facture/card.php b/htdocs/compta/facture/card.php index ff39e29ab00..6fdccb366c2 100644 --- a/htdocs/compta/facture/card.php +++ b/htdocs/compta/facture/card.php @@ -3009,9 +3009,7 @@ if ($action == 'create') { } // when bank account is empty (means not override by payment mode form a other object, like third-party), try to use default value - if (empty($fk_account)) { - $fk_account = GETPOST("fk_account", 'int'); - } + $fk_account = GETPOSTISSET("fk_account") ? GETPOST("fk_account", 'int') : $fk_account; if (!empty($soc->id)) { $absolute_discount = $soc->getAvailableDiscounts(); @@ -3616,7 +3614,7 @@ if ($action == 'create') { if (!empty($conf->banque->enabled)) { print ''.$langs->trans('BankAccount').''; print img_picto('', 'bank_account', 'class="pictofixedwidth"'); - print $form->select_comptes(GETPOSTISSET('fk_account') ? GETPOST('fk_account') : $fk_account, 'fk_account', 0, '', 1, '', 0, 'maxwidth200 widthcentpercentminusx', 1); + print $form->select_comptes($fk_account, 'fk_account', 0, '', 1, '', 0, 'maxwidth200 widthcentpercentminusx', 1); print ''; } From 3e41c9cb9769ebabaf7b5ffcdccfe95e28d17c68 Mon Sep 17 00:00:00 2001 From: Francis Appels Date: Sat, 26 Feb 2022 11:13:02 +0100 Subject: [PATCH 196/255] FIX: Show product photo on Supplier order Cornas model. --- .../supplier_order/doc/pdf_cornas.modules.php | 41 +++++++++---------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/htdocs/core/modules/supplier_order/doc/pdf_cornas.modules.php b/htdocs/core/modules/supplier_order/doc/pdf_cornas.modules.php index 5fcd0ee20de..8d8df36e088 100644 --- a/htdocs/core/modules/supplier_order/doc/pdf_cornas.modules.php +++ b/htdocs/core/modules/supplier_order/doc/pdf_cornas.modules.php @@ -546,31 +546,30 @@ class pdf_cornas extends ModelePDFSuppliersOrders $posYAfterDescription = 0; // We start with Photo of product line - if (!empty($imglinesize['width']) && !empty($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); - } - if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) { - $this->_pagehead($pdf, $object, 0, $outputlangs); - } - $pdf->setPage($pageposbefore + 1); + 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; + $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; + // 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($imglinesize['width']) && !empty($imglinesize['height'])) { - $curX = $this->posxpicture - 1; - $pdf->Image($realpatharray[$i], $curX + (($this->posxtva - $this->posxpicture - $imglinesize['width']) / 2), $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']; + 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 $curX = $this->posxdesc - 1; From 5d0408f7af4bef67ea24b5ab469968feac1f600e Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sat, 26 Feb 2022 19:15:40 +0100 Subject: [PATCH 197/255] Fix filter on member list --- htdocs/adherents/list.php | 8 ++++---- htdocs/projet/list.php | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/htdocs/adherents/list.php b/htdocs/adherents/list.php index 322c08bd77c..996f2d16c8d 100644 --- a/htdocs/adherents/list.php +++ b/htdocs/adherents/list.php @@ -307,7 +307,7 @@ $memberstatic = new Adherent($db); $now = dol_now(); -if (!empty($search_categ) || !empty($catid)) { +if ((!empty($search_categ) && $search_categ > 0) || !empty($catid)) { $sql = "SELECT DISTINCT"; } else { $sql = "SELECT"; @@ -336,7 +336,7 @@ $sql .= " FROM ".MAIN_DB_PREFIX."adherent as d"; if (!empty($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 (d.rowid = ef.fk_object)"; } -if (!empty($search_categ) || !empty($catid)) { +if ((!empty($search_categ) && $search_categ > 0) || !empty($catid)) { // We need this table joined to the select in order to filter by categ $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX."categorie_member as cm ON d.rowid = cm.fk_member"; } @@ -540,7 +540,7 @@ if ($search_login) { if ($search_email) { $param .= "&search_email=".urlencode($search_email); } -if ($search_categ) { +if ($search_categ > 0 || $search_categ == -2) { $param .= "&search_categ=".urlencode($search_categ); } if ($search_company) { @@ -573,7 +573,7 @@ if ($search_phone_mobile != '') { if ($search_filter && $search_filter != '-1') { $param .= "&search_filter=".urlencode($search_filter); } -if ($search_status != "" && $search_status != Adherent::STATUS_DRAFT) { +if ($search_status != "" && $search_status != -3) { $param .= "&search_status=".urlencode($search_status); } if ($search_type > 0) { diff --git a/htdocs/projet/list.php b/htdocs/projet/list.php index 552022f883f..cc9099b463b 100644 --- a/htdocs/projet/list.php +++ b/htdocs/projet/list.php @@ -687,7 +687,7 @@ if ($search_opp_percent != '') { if ($search_public != '') { $param .= '&search_public='.urlencode($search_public); } -if ($search_project_user != '') { +if ($search_project_user > 0) { $param .= '&search_project_user='.urlencode($search_project_user); } if ($search_sale > 0) { From 2ce50b6c00cb830552f614a787de657428fb1a33 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sat, 26 Feb 2022 19:30:46 +0100 Subject: [PATCH 198/255] CSS --- htdocs/theme/eldy/global.inc.php | 4 ++-- htdocs/theme/md/style.css.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/htdocs/theme/eldy/global.inc.php b/htdocs/theme/eldy/global.inc.php index f26e9765db2..b88cecda187 100644 --- a/htdocs/theme/eldy/global.inc.php +++ b/htdocs/theme/eldy/global.inc.php @@ -5210,7 +5210,7 @@ td.cal_other_month { /* ============================================================================== */ /* CSS for treeview */ -.treeview ul { background-color: transparent !important; margin-bottom: 4px !important; margin-top: 0 !important; padding-top: 8px !important; } +.treeview ul { background-color: transparent !important; margin-bottom: 4px !important; margin-top: 0 !important; padding-top: 2px !important; } .treeview li { background-color: transparent !important; padding: 0 0 0 16px !important; min-height: 30px; } .treeview .hover { color: var(--colortextlink) !important; text-decoration: underline !important; } .treeview .hitarea { margin-top: 3px; } @@ -6223,7 +6223,7 @@ span.noborderoncategories a, li.noborderoncategories a { /* vertical-align: top; */ } span.noborderoncategories { - padding: 4px 5px 0px 5px; + padding: 3px 5px 3px 5px; display: inline-block; } .categtextwhite, .treeview .categtextwhite.hover { diff --git a/htdocs/theme/md/style.css.php b/htdocs/theme/md/style.css.php index aeb25a84933..15c9ef74612 100644 --- a/htdocs/theme/md/style.css.php +++ b/htdocs/theme/md/style.css.php @@ -6063,7 +6063,7 @@ span.noborderoncategories a, li.noborderoncategories a { line-height: normal; } span.noborderoncategories { - padding: 3px 5px 0px 5px; + padding: 3px 5px 3px 5px; } .categtextwhite, .treeview .categtextwhite.hover { color: #fff !important; From b598671484ee0ddae7ab85c6339dcee1b01d3b7b Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 27 Feb 2022 14:46:40 +0100 Subject: [PATCH 199/255] NEW ACE Editor is restored at same cursor position after a save --- htdocs/core/class/doleditor.class.php | 18 +++++++++++---- htdocs/website/index.php | 33 ++++++++++++++++++--------- 2 files changed, 35 insertions(+), 16 deletions(-) diff --git a/htdocs/core/class/doleditor.class.php b/htdocs/core/class/doleditor.class.php index da98719d828..60de007ee6c 100644 --- a/htdocs/core/class/doleditor.class.php +++ b/htdocs/core/class/doleditor.class.php @@ -44,6 +44,8 @@ class DolEditor public $height; public $width; public $readonly; + public $posx; + public $posy; /** @@ -64,8 +66,9 @@ class DolEditor * @param int $rows Size of rows for textarea tool * @param string $cols Size of cols for textarea tool (textarea number of cols '70' or percent 'x%') * @param int $readonly 0=Read/Edit, 1=Read only + * @param array $poscursor Array for initial cursor position array('x'=>x, 'y'=>y) */ - public function __construct($htmlname, $content, $width = '', $height = 200, $toolbarname = 'Basic', $toolbarlocation = 'In', $toolbarstartexpanded = false, $uselocalbrowser = true, $okforextendededitor = true, $rows = 0, $cols = 0, $readonly = 0) + public function __construct($htmlname, $content, $width = '', $height = 200, $toolbarname = 'Basic', $toolbarlocation = 'In', $toolbarstartexpanded = false, $uselocalbrowser = true, $okforextendededitor = true, $rows = 0, $cols = 0, $readonly = 0, $poscursor = array()) { global $conf, $langs; @@ -106,8 +109,10 @@ class DolEditor $this->toolbarstartexpanded = $toolbarstartexpanded; $this->rows = max(ROWS_3, $rows); $this->cols = (preg_match('/%/', $cols) ? $cols : max(40, $cols)); // If $cols is a percent, we keep it, otherwise, we take max - $this->height = $height; + $this->height = $height; $this->width = $width; + $this->posx = empty($poscursor['x']) ? 0 : $poscursor['x']; + $this->posy = empty($poscursor['y']) ? 0 : $poscursor['y']; } } @@ -257,9 +262,12 @@ class DolEditor $out .= ''."\n"; } + } else { + $this->expand_display[$collapse_group] = 1; } return $out; diff --git a/htdocs/core/tpl/extrafields_view.tpl.php b/htdocs/core/tpl/extrafields_view.tpl.php index 8afa9a16ff0..f14052766ee 100644 --- a/htdocs/core/tpl/extrafields_view.tpl.php +++ b/htdocs/core/tpl/extrafields_view.tpl.php @@ -107,19 +107,7 @@ if (empty($reshook) && isset($extrafields->attributes[$object->table_element]['l // Print line tr of extra field if ($extrafields->attributes[$object->table_element]['type'][$tmpkeyextra] == 'separate') { - $extrafields_collapse_num = ''; - $extrafield_param = $extrafields->attributes[$object->table_element]['param'][$tmpkeyextra]; - if (!empty($extrafield_param) && is_array($extrafield_param)) { - $extrafield_param_list = array_keys($extrafield_param['options']); - - if (count($extrafield_param_list) > 0) { - $extrafield_collapse_display_value = intval($extrafield_param_list[0]); - - if ($extrafield_collapse_display_value == 1 || $extrafield_collapse_display_value == 2) { - $extrafields_collapse_num = $extrafields->attributes[$object->table_element]['pos'][$tmpkeyextra]; - } - } - } + $extrafields_collapse_num = $tmpkeyextra; print $extrafields->showSeparator($tmpkeyextra, $object); From 8c94c2f98cbb881914923b28db57a35cf20926e3 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 1 Mar 2022 04:10:50 +0100 Subject: [PATCH 225/255] Fix collapse icon --- htdocs/core/class/extrafields.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/class/extrafields.class.php b/htdocs/core/class/extrafields.class.php index 054676aca5d..b75a6d02f99 100644 --- a/htdocs/core/class/extrafields.class.php +++ b/htdocs/core/class/extrafields.class.php @@ -1886,7 +1886,7 @@ class ExtraFields $out = '<'.$tagtype.' id="trextrafieldseparator'.$key.(!empty($object->id)?'_'.$object->id:'').'" class="trextrafieldseparator trextrafieldseparator'.$key.(!empty($object->id)?'_'.$object->id:'').'">'; $out .= '<'.$tagtype_dyn.' '.(!empty($colspan)?'colspan="' . $colspan . '"':'').'>'; // Some js code will be injected here to manage the collapsing of extrafields - $out .= ' '; + $out .= ' '; $out .= ''; $out .= $langs->trans($this->attributes[$object->table_element]['label'][$key]); $out .= ''; From bd288f980d271ad8ebb9c24646d5d654e733af90 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 1 Mar 2022 14:52:47 +0100 Subject: [PATCH 226/255] FIX On large proposal or invoice, fix n(n+1) sql into a n sql. --- htdocs/comm/propal/class/propal.class.php | 16 +++++++++++----- htdocs/commande/class/commande.class.php | 15 +++++++++++---- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/htdocs/comm/propal/class/propal.class.php b/htdocs/comm/propal/class/propal.class.php index fd3bbfe7171..26c01ebd044 100644 --- a/htdocs/comm/propal/class/propal.class.php +++ b/htdocs/comm/propal/class/propal.class.php @@ -552,10 +552,11 @@ class Propal extends CommonObject * @param int $origin_id Depend on global conf MAIN_CREATEFROM_KEEP_LINE_ORIGIN_INFORMATION can be Id of origin object (aka line id), else object id * @param double $pu_ht_devise Unit price in currency * @param int $fk_remise_except Id discount if line is from a discount + * @param int $noupdateafterinsertline No update after insert of line * @return int >0 if OK, <0 if KO * @see add_product() */ - public function addline($desc, $pu_ht, $qty, $txtva, $txlocaltax1 = 0.0, $txlocaltax2 = 0.0, $fk_product = 0, $remise_percent = 0.0, $price_base_type = 'HT', $pu_ttc = 0.0, $info_bits = 0, $type = 0, $rang = -1, $special_code = 0, $fk_parent_line = 0, $fk_fournprice = 0, $pa_ht = 0, $label = '', $date_start = '', $date_end = '', $array_options = 0, $fk_unit = null, $origin = '', $origin_id = 0, $pu_ht_devise = 0, $fk_remise_except = 0) + public function addline($desc, $pu_ht, $qty, $txtva, $txlocaltax1 = 0.0, $txlocaltax2 = 0.0, $fk_product = 0, $remise_percent = 0.0, $price_base_type = 'HT', $pu_ttc = 0.0, $info_bits = 0, $type = 0, $rang = -1, $special_code = 0, $fk_parent_line = 0, $fk_fournprice = 0, $pa_ht = 0, $label = '', $date_start = '', $date_end = '', $array_options = 0, $fk_unit = null, $origin = '', $origin_id = 0, $pu_ht_devise = 0, $fk_remise_except = 0, $noupdateafterinsertline = 0) { global $mysoc, $conf, $langs; @@ -744,7 +745,9 @@ class Propal extends CommonObject } // Mise a jour informations denormalisees au niveau de la propale meme - $result = $this->update_price(1, 'auto', 0, $mysoc); // This method is designed to add line from user input so total calculation must be done using 'auto' mode. + if (empty($noupdateafterinsertline)) { + $result = $this->update_price(1, 'auto', 0, $mysoc); // This method is designed to add line from user input so total calculation must be done using 'auto' mode. + } if ($result > 0) { $this->db->commit(); @@ -1007,7 +1010,7 @@ class Propal extends CommonObject */ public function create($user, $notrigger = 0) { - global $conf, $hookmanager; + global $conf, $hookmanager, $mysoc; $error = 0; $now = dol_now(); @@ -1236,7 +1239,10 @@ class Propal extends CommonObject $line->array_options, $line->fk_unit, $origintype, - $originid + $originid, + 0, + 0, + 1 ); if ($result < 0) { @@ -1265,7 +1271,7 @@ class Propal extends CommonObject if (!$error) { // Mise a jour infos denormalisees - $resql = $this->update_price(1); + $resql = $this->update_price(1, 'auto', 0, $mysoc); if ($resql) { $action = 'update'; diff --git a/htdocs/commande/class/commande.class.php b/htdocs/commande/class/commande.class.php index 48b7e499dbb..429996ee314 100644 --- a/htdocs/commande/class/commande.class.php +++ b/htdocs/commande/class/commande.class.php @@ -872,7 +872,7 @@ class Commande extends CommonOrder */ public function create($user, $notrigger = 0) { - global $conf, $langs; + global $conf, $langs, $mysoc; $error = 0; // Clean parameters @@ -1039,7 +1039,8 @@ class Commande extends CommonOrder $origintype, $originid, 0, - $line->ref_ext + $line->ref_ext, + 1 ); if ($result < 0) { if ($result != self::STOCK_NOT_ENOUGH_FOR_ORDER) { @@ -1056,6 +1057,8 @@ class Commande extends CommonOrder } } + $result = $this->update_price(1, 'auto', 0, $mysoc); // This method is designed to add line from user input so total calculation must be done using 'auto' mode. + // update ref $initialref = '(PROV'.$this->id.')'; if (!empty($this->ref)) { @@ -1433,6 +1436,7 @@ class Commande extends CommonOrder * @param int $origin_id Depend on global conf MAIN_CREATEFROM_KEEP_LINE_ORIGIN_INFORMATION can be Id of origin object (aka line id), else object id * @param double $pu_ht_devise Unit price in currency * @param string $ref_ext line external reference + * @param int $noupdateafterinsertline No update after insert of line * @return int >0 if OK, <0 if KO * * @see add_product() @@ -1442,7 +1446,7 @@ class Commande extends CommonOrder * par l'appelant par la methode get_default_tva(societe_vendeuse,societe_acheteuse,produit) * et le desc doit deja avoir la bonne valeur (a l'appelant de gerer le multilangue) */ - public function addline($desc, $pu_ht, $qty, $txtva, $txlocaltax1 = 0, $txlocaltax2 = 0, $fk_product = 0, $remise_percent = 0, $info_bits = 0, $fk_remise_except = 0, $price_base_type = 'HT', $pu_ttc = 0, $date_start = '', $date_end = '', $type = 0, $rang = -1, $special_code = 0, $fk_parent_line = 0, $fk_fournprice = null, $pa_ht = 0, $label = '', $array_options = 0, $fk_unit = null, $origin = '', $origin_id = 0, $pu_ht_devise = 0, $ref_ext = '') + public function addline($desc, $pu_ht, $qty, $txtva, $txlocaltax1 = 0, $txlocaltax2 = 0, $fk_product = 0, $remise_percent = 0, $info_bits = 0, $fk_remise_except = 0, $price_base_type = 'HT', $pu_ttc = 0, $date_start = '', $date_end = '', $type = 0, $rang = -1, $special_code = 0, $fk_parent_line = 0, $fk_fournprice = null, $pa_ht = 0, $label = '', $array_options = 0, $fk_unit = null, $origin = '', $origin_id = 0, $pu_ht_devise = 0, $ref_ext = '', $noupdateafterinsertline = 0) { global $mysoc, $conf, $langs, $user; @@ -1653,7 +1657,10 @@ class Commande extends CommonOrder } // Mise a jour informations denormalisees au niveau de la commande meme - $result = $this->update_price(1, 'auto', 0, $mysoc); // This method is designed to add line from user input so total calculation must be done using 'auto' mode. + if (empty($noupdateafterinsertline)) { + $result = $this->update_price(1, 'auto', 0, $mysoc); // This method is designed to add line from user input so total calculation must be done using 'auto' mode. + } + if ($result > 0) { $this->db->commit(); return $this->line->id; From d76e002822b6f34628a11ed41f26db8e4f644671 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 1 Mar 2022 15:17:03 +0100 Subject: [PATCH 227/255] Fix explanation on setup page --- htdocs/admin/receiptprinter.php | 21 +++++++++------------ htdocs/langs/en_US/receiptprinter.lang | 2 +- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/htdocs/admin/receiptprinter.php b/htdocs/admin/receiptprinter.php index a2758304527..cb625dbe039 100644 --- a/htdocs/admin/receiptprinter.php +++ b/htdocs/admin/receiptprinter.php @@ -304,7 +304,15 @@ if ($mode == 'config' && $user->admin) { print ''; print ''.$langs->trans("Name").''; print ''.$langs->trans("Type").''; - print ''.$langs->trans("Profile").''; + print ''; + $htmltext = $langs->trans("PROFILE_DEFAULT").' = '.$langs->trans("PROFILE_DEFAULT_HELP").'
    '; + $htmltext .= $langs->trans("PROFILE_SIMPLE").' = '.$langs->trans("PROFILE_SIMPLE_HELP").'
    '; + $htmltext .= $langs->trans("PROFILE_EPOSTEP").' = '.$langs->trans("PROFILE_EPOSTEP_HELP").'
    '; + $htmltext .= $langs->trans("PROFILE_P822D").' = '.$langs->trans("PROFILE_P822D_HELP").'
    '; + $htmltext .= $langs->trans("PROFILE_STAR").' = '.$langs->trans("PROFILE_STAR_HELP").'
    '; + + print $form->textwithpicto($langs->trans("Profile"), $htmltext); + print ''; print ''.$langs->trans("Parameters").''; print ''; print "\n"; @@ -386,17 +394,6 @@ if ($mode == 'config' && $user->admin) { print ''; print '
    '; - - - print load_fiche_titre($langs->trans("ReceiptPrinterProfileDesc"), '', '')."\n"; - - print ''."\n"; - print ''; - print ''; - print ''; - print ''; - print ''; - print '
    '.$langs->trans("PROFILE_DEFAULT").':'.$langs->trans("PROFILE_DEFAULT_HELP").'
    '.$langs->trans("PROFILE_SIMPLE").':'.$langs->trans("PROFILE_SIMPLE_HELP").'
    '.$langs->trans("PROFILE_EPOSTEP").':'.$langs->trans("PROFILE_EPOSTEP_HELP").'
    '.$langs->trans("PROFILE_P822D").':'.$langs->trans("PROFILE_P822D_HELP").'
    '.$langs->trans("PROFILE_STAR").':'.$langs->trans("PROFILE_STAR_HELP").'
    '; } // mode = template diff --git a/htdocs/langs/en_US/receiptprinter.lang b/htdocs/langs/en_US/receiptprinter.lang index 284c4fa61fa..eb115682726 100644 --- a/htdocs/langs/en_US/receiptprinter.lang +++ b/htdocs/langs/en_US/receiptprinter.lang @@ -7,7 +7,7 @@ TestSentToPrinter=Test Sent To Printer %s ReceiptPrinter=Receipt printers ReceiptPrinterDesc=Setup of receipt printers ReceiptPrinterTemplateDesc=Setup of Templates -ReceiptPrinterTypeDesc=Description of Receipt Printer's type +ReceiptPrinterTypeDesc=Example of possible values for the field "Parameters" according to the type of driver ReceiptPrinterProfileDesc=Description of Receipt Printer's Profile ListPrinters=List of Printers SetupReceiptTemplate=Template Setup From 2a48dd349e7de0d4a38e448b0d2ecbe25e968075 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 1 Mar 2022 16:38:06 +0100 Subject: [PATCH 228/255] Fix #hunterb03d4415-d4f9-48c8-9ae2-d3aa248027b5 --- htdocs/admin/emailcollector_list.php | 4 +-- htdocs/admin/mails_templates.php | 2 +- htdocs/admin/menus/edit.php | 6 ++--- htdocs/bom/bom_list.php | 2 +- .../compta/cashcontrol/cashcontrol_list.php | 4 +-- htdocs/compta/facture/list.php | 4 +-- htdocs/compta/resultat/result.php | 8 +++--- htdocs/core/boxes/box_scheduled_jobs.php | 2 +- htdocs/core/class/commonobject.class.php | 18 ++++++------- htdocs/core/class/extrafields.class.php | 14 +++++----- htdocs/core/class/html.form.class.php | 2 +- htdocs/core/class/html.formother.class.php | 8 +++--- htdocs/core/class/menu.class.php | 2 +- htdocs/core/class/translate.class.php | 4 +-- htdocs/core/customreports.php | 10 +++---- htdocs/core/lib/functions.lib.php | 26 +++++++++++++------ .../core/tpl/admin_extrafields_view.tpl.php | 2 +- .../tpl/extrafields_list_array_fields.tpl.php | 4 +-- .../tpl/extrafields_list_print_fields.tpl.php | 2 +- .../conferenceorbooth_list.php | 4 +-- .../conferenceorboothattendee_list.php | 4 +-- htdocs/hrm/evaluation_list.php | 4 +-- htdocs/hrm/job_list.php | 4 +-- htdocs/hrm/position.php | 4 +-- htdocs/hrm/position_list.php | 4 +-- htdocs/hrm/skill_card.php | 4 +-- htdocs/hrm/skill_list.php | 4 +-- .../knowledgerecord_list.php | 4 +-- htdocs/mrp/mo_list.php | 4 +-- htdocs/partnership/partnership_list.php | 4 +-- htdocs/product/inventory/list.php | 4 +-- htdocs/product/list.php | 4 +-- htdocs/product/stock/list.php | 4 +-- htdocs/product/stock/productlot_list.php | 4 +-- htdocs/projet/class/task.class.php | 1 + htdocs/projet/list.php | 4 +-- .../recruitmentcandidature_list.php | 4 +-- .../recruitmentjobposition_list.php | 4 +-- htdocs/salaries/list.php | 4 +-- htdocs/salaries/payments.php | 4 +-- htdocs/ticket/list.php | 4 +-- htdocs/workstation/workstation_list.php | 6 ++--- test/phpunit/SecurityTest.php | 24 +++++++++++++++-- 43 files changed, 135 insertions(+), 104 deletions(-) diff --git a/htdocs/admin/emailcollector_list.php b/htdocs/admin/emailcollector_list.php index af137a1ecdb..9e93dd78b86 100644 --- a/htdocs/admin/emailcollector_list.php +++ b/htdocs/admin/emailcollector_list.php @@ -109,11 +109,11 @@ $arrayfields = array(); foreach ($object->fields as $key => $val) { // If $val['visible']==0, then we never show the field if (!empty($val['visible'])) { - $visible = dol_eval($val['visible'], 1); + $visible = dol_eval($val['visible'], 1, 1, '1'); $arrayfields['t.'.$key] = array( 'label'=>$val['label'], 'checked'=>(($visible < 0) ? 0 : 1), - 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)), + 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')), 'position'=>$val['position'] ); } diff --git a/htdocs/admin/mails_templates.php b/htdocs/admin/mails_templates.php index fb3a1ccf702..803f3b74536 100644 --- a/htdocs/admin/mails_templates.php +++ b/htdocs/admin/mails_templates.php @@ -1034,7 +1034,7 @@ if ($resql) { continue; // It means this is a type of template not into elementList (may be because enabled condition of this type is false because module is not enabled) } // Test on 'enabled' - if (!dol_eval($obj->enabled, 1)) { + if (!dol_eval($obj->enabled, 1, 1, '1')) { $i++; continue; // Email template not qualified } diff --git a/htdocs/admin/menus/edit.php b/htdocs/admin/menus/edit.php index 02c46d8ca35..a9e2fe9287f 100644 --- a/htdocs/admin/menus/edit.php +++ b/htdocs/admin/menus/edit.php @@ -464,7 +464,7 @@ if ($action == 'create') { } print ''; print ''.$langs->trans('DetailMenuIdParent'); - print ', '.$langs->trans("Example").': fk_mainmenu=abc&fk_leftmenu=def'; + print ', '.$langs->trans("Example").': fk_mainmenu=abc&fk_leftmenu=def'; print ''; // Niveau @@ -496,7 +496,7 @@ if ($action == 'create') { print ''.$langs->trans('Enabled').''; print ''.$langs->trans('DetailEnabled'); if (!empty($menu->enabled)) { - print ' ('.$langs->trans("ConditionIsCurrently").': '.yn(dol_eval($menu->enabled, 1)).')'; + print ' ('.$langs->trans("ConditionIsCurrently").': '.yn(dol_eval($menu->enabled, 1, 1, '1')).')'; } print ''; @@ -504,7 +504,7 @@ if ($action == 'create') { print ''.$langs->trans('Rights').''; print ''.$langs->trans('DetailRight'); if (!empty($menu->perms)) { - print ' ('.$langs->trans("ConditionIsCurrently").': '.yn(dol_eval($menu->perms, 1)).')'; + print ' ('.$langs->trans("ConditionIsCurrently").': '.yn(dol_eval($menu->perms, 1, 1, '1')).')'; } print ''; diff --git a/htdocs/bom/bom_list.php b/htdocs/bom/bom_list.php index 3cc0dc1753a..48798db9b8f 100644 --- a/htdocs/bom/bom_list.php +++ b/htdocs/bom/bom_list.php @@ -106,7 +106,7 @@ foreach ($object->fields as $key => $val) { $arrayfields['t.'.$key] = array( 'label'=>$val['label'], 'checked'=>(($visible < 0) ? 0 : 1), - 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)), + 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')), 'position'=>$val['position'], 'help'=> isset($val['help']) ? $val['help'] : '' ); diff --git a/htdocs/compta/cashcontrol/cashcontrol_list.php b/htdocs/compta/cashcontrol/cashcontrol_list.php index 89781fcb211..7822819c06a 100644 --- a/htdocs/compta/cashcontrol/cashcontrol_list.php +++ b/htdocs/compta/cashcontrol/cashcontrol_list.php @@ -104,11 +104,11 @@ $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); + $visible = (int) dol_eval($val['visible'], 1, 1, '1'); $arrayfields['t.'.$key] = array( 'label'=>$val['label'], 'checked'=>(($visible < 0) ? 0 : 1), - 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)), + 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')), 'position'=>$val['position'], 'help'=> isset($val['help']) ? $val['help'] : '' ); diff --git a/htdocs/compta/facture/list.php b/htdocs/compta/facture/list.php index 0e3acc45d25..35318174999 100644 --- a/htdocs/compta/facture/list.php +++ b/htdocs/compta/facture/list.php @@ -261,14 +261,14 @@ if (getDolGlobalString("INVOICE_USE_SITUATION") && $conf->global->INVOICE_USE_RE 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); + $visible = (int) dol_eval($val['visible'], 1, 1, '1'); $newkey = ''; if (array_key_exists($key, $arrayfields)) { $newkey = $key; } elseif (array_key_exists('t.'.$key, $arrayfields)) { $newkey = 't.'.$key; } elseif (array_key_exists('f.'.$key, $arrayfields)) { $newkey = 'f.'.$key; } elseif (array_key_exists('s.'.$key, $arrayfields)) { $newkey = 's.'.$key; } if ($newkey) { $arrayfields[$newkey] = array( 'label'=>$val['label'], 'checked'=>(($visible < 0) ? 0 : 1), - 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)), + 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')), 'position'=>$val['position'], 'help' => empty($val['help']) ? '' : $val['help'], ); diff --git a/htdocs/compta/resultat/result.php b/htdocs/compta/resultat/result.php index 635531ab86b..c296d4037e5 100644 --- a/htdocs/compta/resultat/result.php +++ b/htdocs/compta/resultat/result.php @@ -334,7 +334,7 @@ if ($modecompta == 'CREANCES-DETTES') { //var_dump($result); //$r = $AccCat->calculate($result); - $r = dol_eval($result, 1); + $r = dol_eval($result, 1, 1, '1'); //var_dump($r); print ''.price($r).''; @@ -353,7 +353,7 @@ if ($modecompta == 'CREANCES-DETTES') { $result = strtr($formula, $vars); //$r = $AccCat->calculate($result); - $r = dol_eval($result, 1); + $r = dol_eval($result, 1, 1, 1); print ''.price($r).''; $sommes[$code]['N'] += $r; @@ -367,7 +367,7 @@ if ($modecompta == 'CREANCES-DETTES') { $result = strtr($formula, $vars); //$r = $AccCat->calculate($result); - $r = dol_eval($result, 1); + $r = dol_eval($result, 1, 1, 1); print ''.price($r).''; $sommes[$code]['M'][$k] += $r; @@ -381,7 +381,7 @@ if ($modecompta == 'CREANCES-DETTES') { $result = strtr($formula, $vars); //$r = $AccCat->calculate($result); - $r = dol_eval($result, 1); + $r = dol_eval($result, 1, 1, 1); print ''.price($r).''; $sommes[$code]['M'][$k] += $r; diff --git a/htdocs/core/boxes/box_scheduled_jobs.php b/htdocs/core/boxes/box_scheduled_jobs.php index 94695034cce..f2195659654 100644 --- a/htdocs/core/boxes/box_scheduled_jobs.php +++ b/htdocs/core/boxes/box_scheduled_jobs.php @@ -102,7 +102,7 @@ class box_scheduled_jobs extends ModeleBoxes while ($i < $num) { $objp = $this->db->fetch_object($result); - if (dol_eval($objp->test, 1, 1)) { + if (dol_eval($objp->test, 1, 1, '')) { $nextrun = $this->db->jdate($objp->datenextrun); if (empty($nextrun)) { $nextrun = $this->db->jdate($objp->datestart); diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index 4b3d6fca2d3..179f1255306 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -5675,12 +5675,12 @@ abstract class CommonObject $enabled = 1; if (isset($this->fields[$key]['enabled'])) { - $enabled = dol_eval($this->fields[$key]['enabled'], 1); + $enabled = dol_eval($this->fields[$key]['enabled'], 1, 1, '1'); } /*$perms = 1; if (isset($this->fields[$key]['perms'])) { - $perms = dol_eval($this->fields[$key]['perms'], 1); + $perms = dol_eval($this->fields[$key]['perms'], 1, 1, '1'); }*/ if (empty($enabled)) { continue; @@ -5836,7 +5836,7 @@ abstract class CommonObject if (!empty($extrafields) && !empty($extrafields->attributes[$this->table_element]['computed'][$key])) { //var_dump($conf->disable_compute); if (empty($conf->disable_compute)) { - $this->array_options["options_".$key] = dol_eval($extrafields->attributes[$this->table_element]['computed'][$key], 1, 0); + $this->array_options["options_".$key] = dol_eval($extrafields->attributes[$this->table_element]['computed'][$key], 1, 0, ''); } } } @@ -5967,7 +5967,7 @@ abstract class CommonObject if (!empty($attrfieldcomputed)) { if (!empty($conf->global->MAIN_STORE_COMPUTED_EXTRAFIELDS)) { - $value = dol_eval($attrfieldcomputed, 1, 0); + $value = dol_eval($attrfieldcomputed, 1, 0, ''); dol_syslog($langs->trans("Extrafieldcomputed")." sur ".$attributeLabel."(".$value.")", LOG_DEBUG); $new_array_options[$key] = $value; } else { @@ -6334,7 +6334,7 @@ abstract class CommonObject if (!empty($attrfieldcomputed)) { if (!empty($conf->global->MAIN_STORE_COMPUTED_EXTRAFIELDS)) { - $value = dol_eval($attrfieldcomputed, 1, 0); + $value = dol_eval($attrfieldcomputed, 1, 0, ''); dol_syslog($langs->trans("Extrafieldcomputed")." sur ".$attributeLabel."(".$value.")", LOG_DEBUG); $this->array_options["options_".$key] = $value; } else { @@ -7188,7 +7188,7 @@ abstract class CommonObject if ($computed) { // Make the eval of compute string //var_dump($computed); - $value = dol_eval($computed, 1, 0); + $value = dol_eval($computed, 1, 0, ''); } if (empty($morecss)) { @@ -7713,7 +7713,7 @@ abstract class CommonObject // Test on 'enabled' ('enabled' is different than 'list' = 'visibility') $enabled = 1; if ($enabled && isset($extrafields->attributes[$this->table_element]['enabled'][$key])) { - $enabled = dol_eval($extrafields->attributes[$this->table_element]['enabled'][$key], 1); + $enabled = dol_eval($extrafields->attributes[$this->table_element]['enabled'][$key], 1, 1, '1'); } if (empty($enabled)) { continue; @@ -7721,12 +7721,12 @@ abstract class CommonObject $visibility = 1; if ($visibility && isset($extrafields->attributes[$this->table_element]['list'][$key])) { - $visibility = dol_eval($extrafields->attributes[$this->table_element]['list'][$key], 1); + $visibility = dol_eval($extrafields->attributes[$this->table_element]['list'][$key], 1, 1, '1'); } $perms = 1; if ($perms && isset($extrafields->attributes[$this->table_element]['perms'][$key])) { - $perms = dol_eval($extrafields->attributes[$this->table_element]['perms'][$key], 1); + $perms = dol_eval($extrafields->attributes[$this->table_element]['perms'][$key], 1, 1, '1'); } if (($mode == 'create') && abs($visibility) != 1 && abs($visibility) != 3) { diff --git a/htdocs/core/class/extrafields.class.php b/htdocs/core/class/extrafields.class.php index 2b827d06f36..ff45a028d51 100644 --- a/htdocs/core/class/extrafields.class.php +++ b/htdocs/core/class/extrafields.class.php @@ -915,9 +915,9 @@ class ExtraFields $unique = $this->attributes[$extrafieldsobjectkey]['unique'][$key]; $required = $this->attributes[$extrafieldsobjectkey]['required'][$key]; $param = $this->attributes[$extrafieldsobjectkey]['param'][$key]; - $perms = dol_eval($this->attributes[$extrafieldsobjectkey]['perms'][$key], 1); + $perms = dol_eval($this->attributes[$extrafieldsobjectkey]['perms'][$key], 1, 1, '1'); $langfile = $this->attributes[$extrafieldsobjectkey]['langfile'][$key]; - $list = dol_eval($this->attributes[$extrafieldsobjectkey]['list'][$key], 1); + $list = dol_eval($this->attributes[$extrafieldsobjectkey]['list'][$key], 1, 1, '1'); $totalizable = $this->attributes[$extrafieldsobjectkey]['totalizable'][$key]; $help = $this->attributes[$extrafieldsobjectkey]['help'][$key]; $hidden = (empty($list) ? 1 : 0); // If empty, we are sure it is hidden, otherwise we show. If it depends on mode (view/create/edit form or list, this must be filtered by caller) @@ -1505,9 +1505,9 @@ class ExtraFields $unique = $this->attributes[$extrafieldsobjectkey]['unique'][$key]; $required = $this->attributes[$extrafieldsobjectkey]['required'][$key]; $param = $this->attributes[$extrafieldsobjectkey]['param'][$key]; - $perms = dol_eval($this->attributes[$extrafieldsobjectkey]['perms'][$key], 1); + $perms = dol_eval($this->attributes[$extrafieldsobjectkey]['perms'][$key], 1, 1, '1'); $langfile = $this->attributes[$extrafieldsobjectkey]['langfile'][$key]; - $list = dol_eval($this->attributes[$extrafieldsobjectkey]['list'][$key], 1); + $list = dol_eval($this->attributes[$extrafieldsobjectkey]['list'][$key], 1, 1, '1'); $help = $this->attributes[$extrafieldsobjectkey]['help'][$key]; $hidden = (empty($list) ? 1 : 0); // If $list empty, we are sure it is hidden, otherwise we show. If it depends on mode (view/create/edit form or list, this must be filtered by caller) } else { @@ -1959,17 +1959,17 @@ class ExtraFields $enabled = 1; if (isset($this->attributes[$object->table_element]['enabled'][$key])) { // 'enabled' is often a condition on module enabled or not - $enabled = dol_eval($this->attributes[$object->table_element]['enabled'][$key], 1); + $enabled = dol_eval($this->attributes[$object->table_element]['enabled'][$key], 1, 1, '1'); } $visibility = 1; if (isset($this->attributes[$object->table_element]['list'][$key])) { // 'list' is option for visibility - $visibility = dol_eval($this->attributes[$object->table_element]['list'][$key], 1); + $visibility = dol_eval($this->attributes[$object->table_element]['list'][$key], 1, 1, '1'); } $perms = 1; if (isset($this->attributes[$object->table_element]['perms'][$key])) { - $perms = dol_eval($this->attributes[$object->table_element]['perms'][$key], 1); + $perms = dol_eval($this->attributes[$object->table_element]['perms'][$key], 1, 1, '1'); } if (empty($enabled)) { continue; diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index f25c9aad9d3..975e6ed86ea 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -7424,7 +7424,7 @@ class Form if (!empty($objecttmp->fields)) { // For object that declare it, it is better to use declared fields (like societe, contact, ...) $tmpfieldstoshow = ''; foreach ($objecttmp->fields as $key => $val) { - if (!dol_eval($val['enabled'], 1, 1)) { + if (!dol_eval($val['enabled'], 1, 1, 1, '1')) { continue; } if (!empty($val['showoncombobox'])) { diff --git a/htdocs/core/class/html.formother.class.php b/htdocs/core/class/html.formother.class.php index aa0e5486761..6dae77dffa4 100644 --- a/htdocs/core/class/html.formother.class.php +++ b/htdocs/core/class/html.formother.class.php @@ -1501,10 +1501,10 @@ class FormOther 'parent', 'photo', 'socialnetworks', 'webservices_url', 'webservices_key'))) { continue; } - if (isset($val['enabled']) && !dol_eval($val['enabled'], 1)) { + if (isset($val['enabled']) && !dol_eval($val['enabled'], 1, 1, '1')) { continue; } - if (isset($val['visible']) && !dol_eval($val['visible'], 1)) { + if (isset($val['visible']) && !dol_eval($val['visible'], 1, 1, '1')) { continue; } if (preg_match('/^fk_/', $key) && !preg_match('/^fk_statu/', $key)) { @@ -1575,10 +1575,10 @@ class FormOther 'parent', 'photo', 'socialnetworks', 'webservices_url', 'webservices_key'))) { continue; } - if (isset($val['enabled']) && !dol_eval($val['enabled'], 1)) { + if (isset($val['enabled']) && !dol_eval($val['enabled'], 1, 1, '1')) { continue; } - if (isset($val['visible']) && !dol_eval($val['visible'], 1)) { + if (isset($val['visible']) && !dol_eval($val['visible'], 1, 1, '1')) { continue; } if (preg_match('/^fk_/', $key) && !preg_match('/^fk_statu/', $key)) { diff --git a/htdocs/core/class/menu.class.php b/htdocs/core/class/menu.class.php index e88ec701320..eab31288cca 100644 --- a/htdocs/core/class/menu.class.php +++ b/htdocs/core/class/menu.class.php @@ -119,7 +119,7 @@ class Menu { $nb = 0; foreach ($this->liste as $val) { - //if (dol_eval($val['enabled'], 1)) $nb++; + //if (dol_eval($val['enabled'], 1, 1, '1')) $nb++; if (!empty($val['enabled'])) { $nb++; // $val['enabled'] is already evaluated to 0 or 1, no need for dol_eval() } diff --git a/htdocs/core/class/translate.class.php b/htdocs/core/class/translate.class.php index f881447cd67..5bfdbc7e0f1 100644 --- a/htdocs/core/class/translate.class.php +++ b/htdocs/core/class/translate.class.php @@ -656,7 +656,7 @@ class Translate return $str; } else { // Translation is not available - //if ($key[0] == '$') { return dol_eval($key,1); } + //if ($key[0] == '$') { return dol_eval($key, 1, 1, '1'); } return $this->getTradFromKey($key); } } @@ -722,7 +722,7 @@ class Translate return $str; } else { if ($key[0] == '$') { - return dol_eval($key, 1); + return dol_eval($key, 1, 1, '1'); } return $this->getTradFromKey($key); } diff --git a/htdocs/core/customreports.php b/htdocs/core/customreports.php index fafd1c015e8..0ff8ebc4e64 100644 --- a/htdocs/core/customreports.php +++ b/htdocs/core/customreports.php @@ -371,7 +371,7 @@ print '
    '; print '
    '.$langs->trans("StatisticsOn").'
    '; $newarrayoftype = array(); foreach ($arrayoftype as $key => $val) { - if (dol_eval($val['enabled'], 1)) { + if (dol_eval($val['enabled'], 1, 1, '1')) { $newarrayoftype[$key] = $arrayoftype[$key]; } if ($val['langs']) { @@ -402,7 +402,7 @@ print '
    '; // Add measures into array print '
    '; foreach ($object->fields as $key => $val) { - if (!empty($val['isameasure']) && (!isset($val['enabled']) || dol_eval($val['enabled'], 1))) { + if (!empty($val['isameasure']) && (!isset($val['enabled']) || dol_eval($val['enabled'], 1, 1, '1'))) { $arrayofmesures['t.'.$key.'-sum'] = $langs->trans($val['label']).' ('.$langs->trans("Sum").')'; $arrayofmesures['t.'.$key.'-average'] = $langs->trans($val['label']).' ('.$langs->trans("Average").')'; $arrayofmesures['t.'.$key.'-min'] = $langs->trans($val['label']).' ('.$langs->trans("Minimum").')'; @@ -412,7 +412,7 @@ foreach ($object->fields as $key => $val) { // Add extrafields to Measures if ($object->isextrafieldmanaged) { foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) { - if (!empty($extrafields->attributes[$object->table_element]['totalizable'][$key]) && (!isset($extrafields->attributes[$object->table_element]['enabled'][$key]) || dol_eval($extrafields->attributes[$object->table_element]['enabled'][$key], 1))) { + if (!empty($extrafields->attributes[$object->table_element]['totalizable'][$key]) && (!isset($extrafields->attributes[$object->table_element]['enabled'][$key]) || dol_eval($extrafields->attributes[$object->table_element]['enabled'][$key], 1, 1, '1'))) { $arrayofmesures['te.'.$key.'-sum'] = $langs->trans($extrafields->attributes[$object->table_element]['label'][$key]).' ('.$langs->trans("Sum").')'; $arrayofmesures['te.'.$key.'-average'] = $langs->trans($extrafields->attributes[$object->table_element]['label'][$key]).' ('.$langs->trans("Average").')'; $arrayofmesures['te.'.$key.'-min'] = $langs->trans($extrafields->attributes[$object->table_element]['label'][$key]).' ('.$langs->trans("Minimum").')'; @@ -443,7 +443,7 @@ if ($mode == 'grid') { // YAxis print '
    '; foreach ($object->fields as $key => $val) { - if (empty($val['measure']) && (!isset($val['enabled']) || dol_eval($val['enabled'], 1))) { + if (empty($val['measure']) && (!isset($val['enabled']) || dol_eval($val['enabled'], 1, 1, '1'))) { if (in_array($key, array('id', 'rowid', 'entity', 'last_main_doc', 'extraparams'))) { continue; } @@ -464,7 +464,7 @@ if ($mode == 'grid') { // Add measure from extrafields if ($object->isextrafieldmanaged) { foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) { - if (!empty($extrafields->attributes[$object->table_element]['totalizable'][$key]) && (!isset($extrafields->attributes[$object->table_element]['enabled'][$key]) || dol_eval($extrafields->attributes[$object->table_element]['enabled'][$key], 1))) { + if (!empty($extrafields->attributes[$object->table_element]['totalizable'][$key]) && (!isset($extrafields->attributes[$object->table_element]['enabled'][$key]) || dol_eval($extrafields->attributes[$object->table_element]['enabled'][$key], 1, 1, '1'))) { $arrayofyaxis['te.'.$key] = array('label' => $extrafields->attributes[$object->table_element]['label'][$key], 'position' => (int) $extrafields->attributes[$object->table_element]['pos'][$key]); } } diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 513534ba38c..c6476f98a11 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -8188,12 +8188,13 @@ function verifCond($strToEvaluate) * Replace eval function to add more security. * This function is called by verifCond() or trans() and transnoentitiesnoconv(). * - * @param string $s String to evaluate - * @param int $returnvalue 0=No return (used to execute eval($a=something)). 1=Value of eval is returned (used to eval($something)). - * @param int $hideerrors 1=Hide errors - * @return mixed Nothing or return result of eval + * @param string $s String to evaluate + * @param int $returnvalue 0=No return (used to execute eval($a=something)). 1=Value of eval is returned (used to eval($something)). + * @param int $hideerrors 1=Hide errors + * @param string $onlysimplestring Accept only simple string with char 'a-z0-9\s$_->&|='; + * @return mixed Nothing or return result of eval */ -function dol_eval($s, $returnvalue = 0, $hideerrors = 1) +function dol_eval($s, $returnvalue = 0, $hideerrors = 1, $onlysimplestring = '1') { // Only global variables can be changed by eval function and returned to caller global $db, $langs, $user, $conf, $website, $websitepage; @@ -8205,9 +8206,18 @@ function dol_eval($s, $returnvalue = 0, $hideerrors = 1) global $obj; // To get $obj used into list when dol_eval is used for computed fields and $obj is not yet $object global $soc; // For backward compatibility - // Replace dangerous char (used for RCE), we allow only PHP variable testing. + // Test dangerous char (used for RCE), we allow only PHP variable testing. + if ($onlysimplestring == '1') { + //print preg_quote('$_->&|', '/'); + if (preg_match('/[^a-z0-9\s'.preg_quote('$_->&|=', '/').']/i', $s)) { + return 'Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s; + } + } if (strpos($s, '`') !== false) { - return 'Bad string syntax to evaluate: '.$s; + return 'Bad string syntax to evaluate (backtick char is forbidden): '.$s; + } + if (strpos($s, '.') !== false) { + return 'Bad string syntax to evaluate (dot char is forbidden): '.$s; } // We block use of php exec or php file functions @@ -8215,7 +8225,7 @@ function dol_eval($s, $returnvalue = 0, $hideerrors = 1) $forbiddenphpstrings = array_merge($forbiddenphpstrings, array('_ENV', '_SESSION', '_COOKIE', '_GET', '_POST', '_REQUEST')); $forbiddenphpfunctions = array("exec", "passthru", "shell_exec", "system", "proc_open", "popen", "eval", "dol_eval", "executeCLI"); - $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("fopen", "file_put_contents", "fputs", "fputscsv", "fwrite", "fpassthru", "unlink", "mkdir", "rmdir", "symlink", "touch", "umask")); + $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("fopen", "file_put_contents", "fputs", "fputscsv", "fwrite", "fpassthru", "require", "include", "mkdir", "rmdir", "symlink", "touch", "unlink", "umask")); $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("function", "call_user_func")); $forbiddenphpregex = 'global\s+\$|\b('.implode('|', $forbiddenphpfunctions).')\b'; diff --git a/htdocs/core/tpl/admin_extrafields_view.tpl.php b/htdocs/core/tpl/admin_extrafields_view.tpl.php index d1145229db7..369f60ea201 100644 --- a/htdocs/core/tpl/admin_extrafields_view.tpl.php +++ b/htdocs/core/tpl/admin_extrafields_view.tpl.php @@ -73,7 +73,7 @@ print "\n"; if (isset($extrafields->attributes[$elementtype]['type']) && is_array($extrafields->attributes[$elementtype]['type']) && count($extrafields->attributes[$elementtype]['type'])) { foreach ($extrafields->attributes[$elementtype]['type'] as $key => $value) { - /*if (! dol_eval($extrafields->attributes[$elementtype]['enabled'][$key], 1)) { + /*if (! dol_eval($extrafields->attributes[$elementtype]['enabled'][$key], 1, 1, '1')) { // TODO Uncomment this to exclude extrafields of modules not enabled. Add a link to "Show extrafields disabled" // continue; }*/ diff --git a/htdocs/core/tpl/extrafields_list_array_fields.tpl.php b/htdocs/core/tpl/extrafields_list_array_fields.tpl.php index 36eeee89627..b704891da16 100644 --- a/htdocs/core/tpl/extrafields_list_array_fields.tpl.php +++ b/htdocs/core/tpl/extrafields_list_array_fields.tpl.php @@ -23,9 +23,9 @@ if (!empty($extrafieldsobjectkey)) { // $extrafieldsobject is the $object->table $arrayfields[$extrafieldsobjectprefix.$key] = array( 'label' => $extrafields->attributes[$extrafieldsobjectkey]['label'][$key], 'type' => $extrafields->attributes[$extrafieldsobjectkey]['type'][$key], - 'checked' => ((dol_eval($extrafields->attributes[$extrafieldsobjectkey]['list'][$key], 1) <= 0) ? 0 : 1), + 'checked' => ((dol_eval($extrafields->attributes[$extrafieldsobjectkey]['list'][$key], 1, 1, '1') <= 0) ? 0 : 1), 'position' => $extrafields->attributes[$extrafieldsobjectkey]['pos'][$key], - 'enabled' => (abs((int) $extrafields->attributes[$extrafieldsobjectkey]['list'][$key]) != 3 && dol_eval($extrafields->attributes[$extrafieldsobjectkey]['perms'][$key], 1)), + 'enabled' => (abs((int) $extrafields->attributes[$extrafieldsobjectkey]['list'][$key]) != 3 && dol_eval($extrafields->attributes[$extrafieldsobjectkey]['perms'][$key], 1, 1, '1')), 'langfile' => $extrafields->attributes[$extrafieldsobjectkey]['langfile'][$key], 'help' => $extrafields->attributes[$extrafieldsobjectkey]['help'][$key], ); diff --git a/htdocs/core/tpl/extrafields_list_print_fields.tpl.php b/htdocs/core/tpl/extrafields_list_print_fields.tpl.php index 80d6cd7da56..00c2739e3f8 100644 --- a/htdocs/core/tpl/extrafields_list_print_fields.tpl.php +++ b/htdocs/core/tpl/extrafields_list_print_fields.tpl.php @@ -38,7 +38,7 @@ if (!empty($extrafieldsobjectkey) && !empty($extrafields->attributes[$extrafield //var_dump($extrafields->attributes[$extrafieldsobjectkey]['computed'][$key]); //var_dump($obj); //var_dump($extrafields->attributes[$extrafieldsobjectkey]['computed'][$key]); - $value = dol_eval($extrafields->attributes[$extrafieldsobjectkey]['computed'][$key], 1); + $value = dol_eval($extrafields->attributes[$extrafieldsobjectkey]['computed'][$key], 1, 1, '0'); //var_dump($value); } diff --git a/htdocs/eventorganization/conferenceorbooth_list.php b/htdocs/eventorganization/conferenceorbooth_list.php index d105ad05c43..943205adca2 100644 --- a/htdocs/eventorganization/conferenceorbooth_list.php +++ b/htdocs/eventorganization/conferenceorbooth_list.php @@ -114,11 +114,11 @@ $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); + $visible = (int) dol_eval($val['visible'], 1, 1, '1'); $arrayfields['t.'.$key] = array( 'label'=>$val['label'], 'checked'=>(($visible < 0) ? 0 : 1), - 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)), + 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')), 'position'=>$val['position'], 'help'=> isset($val['help']) ? $val['help'] : '' ); diff --git a/htdocs/eventorganization/conferenceorboothattendee_list.php b/htdocs/eventorganization/conferenceorboothattendee_list.php index e084c68cfe7..ab2699187b2 100644 --- a/htdocs/eventorganization/conferenceorboothattendee_list.php +++ b/htdocs/eventorganization/conferenceorboothattendee_list.php @@ -122,11 +122,11 @@ $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); + $visible = (int) dol_eval($val['visible'], 1, 1, '1'); $arrayfields['t.'.$key] = array( 'label'=>$val['label'], 'checked'=>(($visible < 0) ? 0 : 1), - 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)), + 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')), 'position'=>$val['position'], 'help'=> isset($val['help']) ? $val['help'] : '' ); diff --git a/htdocs/hrm/evaluation_list.php b/htdocs/hrm/evaluation_list.php index 35189f11b87..ad99573b096 100644 --- a/htdocs/hrm/evaluation_list.php +++ b/htdocs/hrm/evaluation_list.php @@ -114,11 +114,11 @@ $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); + $visible = (int) dol_eval($val['visible'], 1, 1, '1'); $arrayfields['t.'.$key] = array( 'label'=>$val['label'], 'checked'=>(($visible < 0) ? 0 : 1), - 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)), + 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')), 'position'=>$val['position'], 'help'=> isset($val['help']) ? $val['help'] : '' ); diff --git a/htdocs/hrm/job_list.php b/htdocs/hrm/job_list.php index 55363d729b5..7644ea1fd0f 100644 --- a/htdocs/hrm/job_list.php +++ b/htdocs/hrm/job_list.php @@ -114,11 +114,11 @@ $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); + $visible = (int) dol_eval($val['visible'], 1, 1, '1'); $arrayfields['t.'.$key] = array( 'label'=>$val['label'], 'checked'=>(($visible < 0) ? 0 : 1), - 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)), + 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')), 'position'=>$val['position'], 'help'=> isset($val['help']) ? $val['help'] : '' ); diff --git a/htdocs/hrm/position.php b/htdocs/hrm/position.php index d36d352e895..253945e6c5a 100644 --- a/htdocs/hrm/position.php +++ b/htdocs/hrm/position.php @@ -357,11 +357,11 @@ function DisplayPositionList() 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); + $visible = (int) dol_eval($val['visible'], 1, 1, '1'); $arrayfields['t.' . $key] = array( 'label' => $val['label'], 'checked' => (($visible < 0) ? 0 : 1), - 'enabled' => ($visible != 3 && dol_eval($val['enabled'], 1)), + 'enabled' => ($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')), 'position' => $val['position'], 'help' => isset($val['help']) ? $val['help'] : '' ); diff --git a/htdocs/hrm/position_list.php b/htdocs/hrm/position_list.php index 1585ed1e03f..13315a2a9bc 100644 --- a/htdocs/hrm/position_list.php +++ b/htdocs/hrm/position_list.php @@ -114,11 +114,11 @@ $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); + $visible = (int) dol_eval($val['visible'], 1, 1, '1'); $arrayfields['t.'.$key] = array( 'label'=>$val['label'], 'checked'=>(($visible < 0) ? 0 : 1), - 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)), + 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')), 'position'=>$val['position'], 'help'=> isset($val['help']) ? $val['help'] : '' ); diff --git a/htdocs/hrm/skill_card.php b/htdocs/hrm/skill_card.php index a06cf40952a..7c63bb2cff7 100644 --- a/htdocs/hrm/skill_card.php +++ b/htdocs/hrm/skill_card.php @@ -538,11 +538,11 @@ if ($action != "create" && $action != "edit") { foreach ($objectline->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); + $visible = (int) dol_eval($val['visible'], 1, 1, '1'); $arrayfields['t.' . $key] = array( 'label' => $val['label'], 'checked' => (($visible < 0) ? 0 : 1), - 'enabled' => ($visible != 3 && dol_eval($val['enabled'], 1)), + 'enabled' => ($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')), 'position' => $val['position'], 'help' => isset($val['help']) ? $val['help'] : '' ); diff --git a/htdocs/hrm/skill_list.php b/htdocs/hrm/skill_list.php index 1fc5440e589..8ef800b3ffc 100644 --- a/htdocs/hrm/skill_list.php +++ b/htdocs/hrm/skill_list.php @@ -114,11 +114,11 @@ $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); + $visible = (int) dol_eval($val['visible'], 1, 1, '1'); $arrayfields['t.'.$key] = array( 'label'=>$val['label'], 'checked'=>(($visible < 0) ? 0 : 1), - 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)), + 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')), 'position'=>$val['position'], 'help'=> isset($val['help']) ? $val['help'] : '' ); diff --git a/htdocs/knowledgemanagement/knowledgerecord_list.php b/htdocs/knowledgemanagement/knowledgerecord_list.php index aed45b1db26..c4440028e49 100644 --- a/htdocs/knowledgemanagement/knowledgerecord_list.php +++ b/htdocs/knowledgemanagement/knowledgerecord_list.php @@ -114,11 +114,11 @@ $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); + $visible = (int) dol_eval($val['visible'], 1, 1, '1'); $arrayfields['t.'.$key] = array( 'label'=>$val['label'], 'checked'=>(($visible < 0) ? 0 : 1), - 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)), + 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')), 'position'=>$val['position'], 'help'=> isset($val['help']) ? $val['help'] : '' ); diff --git a/htdocs/mrp/mo_list.php b/htdocs/mrp/mo_list.php index e5648cad5f7..6e15a71e517 100644 --- a/htdocs/mrp/mo_list.php +++ b/htdocs/mrp/mo_list.php @@ -109,11 +109,11 @@ $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); + $visible = (int) dol_eval($val['visible'], 1, 1, '1'); $arrayfields['t.'.$key] = array( 'label'=>$val['label'], 'checked'=>(($visible < 0) ? 0 : 1), - 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)), + 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')), 'position'=>$val['position'], 'help'=> isset($val['help']) ? $val['help'] : '' ); diff --git a/htdocs/partnership/partnership_list.php b/htdocs/partnership/partnership_list.php index 89394960632..dc9958fa3df 100644 --- a/htdocs/partnership/partnership_list.php +++ b/htdocs/partnership/partnership_list.php @@ -118,11 +118,11 @@ $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); + $visible = (int) dol_eval($val['visible'], 1, 1, '1'); $arrayfields['t.'.$key] = array( 'label'=>$val['label'], 'checked'=>(($visible < 0) ? 0 : 1), - 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)), + 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')), 'position'=>$val['position'], 'help'=> isset($val['help']) ? $val['help'] : '' ); diff --git a/htdocs/product/inventory/list.php b/htdocs/product/inventory/list.php index 41e43fdf433..c4548b3aa66 100644 --- a/htdocs/product/inventory/list.php +++ b/htdocs/product/inventory/list.php @@ -102,11 +102,11 @@ $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); + $visible = (int) dol_eval($val['visible'], 1, 1, '1'); $arrayfields['t.'.$key] = array( 'label'=>$val['label'], 'checked'=>(($visible < 0) ? 0 : 1), - 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)), + 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')), 'position'=>$val['position'], 'help'=> isset($val['help']) ? $val['help'] : '' ); diff --git a/htdocs/product/list.php b/htdocs/product/list.php index a3ec599dea8..26dbf18e439 100644 --- a/htdocs/product/list.php +++ b/htdocs/product/list.php @@ -244,11 +244,11 @@ $arrayfields = array( /*foreach ($object->fields as $key => $val) { // If $val['visible']==0, then we never show the field if (!empty($val['visible'])) { - $visible = dol_eval($val['visible'], 1); + $visible = dol_eval($val['visible'], 1, 1, '1'); $arrayfields['p.'.$key] = array( 'label'=>$val['label'], 'checked'=>(($visible < 0) ? 0 : 1), - 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)), + 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')), 'position'=>$val['position'] ); } diff --git a/htdocs/product/stock/list.php b/htdocs/product/stock/list.php index 8f24fb9c110..93c963e0065 100644 --- a/htdocs/product/stock/list.php +++ b/htdocs/product/stock/list.php @@ -117,11 +117,11 @@ $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); + $visible = (int) dol_eval($val['visible'], 1, 1, '1'); $arrayfields['t.'.$key] = array( 'label'=>$val['label'], 'checked'=>(($visible < 0) ? 0 : 1), - 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)), + 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')), 'position'=>$val['position'], 'help'=> isset($val['help']) ? $val['help'] : 'help' ); diff --git a/htdocs/product/stock/productlot_list.php b/htdocs/product/stock/productlot_list.php index e5a8b05902e..92172643096 100644 --- a/htdocs/product/stock/productlot_list.php +++ b/htdocs/product/stock/productlot_list.php @@ -104,11 +104,11 @@ $arrayfields = array(); foreach ($object->fields as $key => $val) { // If $val['visible']==0, then we never show the field if (!empty($val['visible'])) { - $visible = dol_eval($val['visible'], 1); + $visible = dol_eval($val['visible'], 1, 1, '1'); $arrayfields['t.'.$key] = array( 'label'=>$val['label'], 'checked'=>(($visible < 0) ? 0 : 1), - 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)), + 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')), 'position'=>$val['position'] ); } diff --git a/htdocs/projet/class/task.class.php b/htdocs/projet/class/task.class.php index 56db0bd2a64..3eeb1bb1e4c 100644 --- a/htdocs/projet/class/task.class.php +++ b/htdocs/projet/class/task.class.php @@ -27,6 +27,7 @@ */ require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/commonobjectline.class.php'; require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php'; diff --git a/htdocs/projet/list.php b/htdocs/projet/list.php index cc9099b463b..36c2fc942b5 100644 --- a/htdocs/projet/list.php +++ b/htdocs/projet/list.php @@ -182,11 +182,11 @@ $arrayfields = array(); foreach ($object->fields as $key => $val) { // If $val['visible']==0, then we never show the field if (!empty($val['visible'])) { - $visible = dol_eval($val['visible'], 1); + $visible = dol_eval($val['visible'], 1, 1, '1'); $arrayfields['p.'.$key] = array( 'label'=>$val['label'], 'checked'=>(($visible < 0) ? 0 : 1), - 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)), + 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')), 'position'=>$val['position'], 'help'=> isset($val['help']) ? $val['help'] : '' ); diff --git a/htdocs/recruitment/recruitmentcandidature_list.php b/htdocs/recruitment/recruitmentcandidature_list.php index f16b8c3dcf9..05cf56636ea 100644 --- a/htdocs/recruitment/recruitmentcandidature_list.php +++ b/htdocs/recruitment/recruitmentcandidature_list.php @@ -151,11 +151,11 @@ $arrayfields = array(); foreach ($object->fields as $key => $val) { // If $val['visible']==0, then we never show the field if (!empty($val['visible'])) { - $visible = dol_eval($val['visible'], 1); + $visible = dol_eval($val['visible'], 1, 1, '1'); $arrayfields['t.'.$key] = array( 'label'=>$val['label'], 'checked'=>(($visible < 0) ? 0 : 1), - 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)), + 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')), 'position'=>$val['position'] ); } diff --git a/htdocs/recruitment/recruitmentjobposition_list.php b/htdocs/recruitment/recruitmentjobposition_list.php index f0935bc8798..c4a43d0bab4 100644 --- a/htdocs/recruitment/recruitmentjobposition_list.php +++ b/htdocs/recruitment/recruitmentjobposition_list.php @@ -153,11 +153,11 @@ $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); + $visible = (int) dol_eval($val['visible'], 1, 1, '1'); $arrayfields['t.'.$key] = array( 'label'=>$val['label'], 'checked'=>(($visible < 0) ? 0 : 1), - 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)), + 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')), 'position'=>$val['position'], 'help'=> isset($val['help']) ? $val['help'] : '' ); diff --git a/htdocs/salaries/list.php b/htdocs/salaries/list.php index 7a8b3ebca10..2e77c29cd01 100644 --- a/htdocs/salaries/list.php +++ b/htdocs/salaries/list.php @@ -134,11 +134,11 @@ $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); + $visible = (int) dol_eval($val['visible'], 1, 1, '1'); $arrayfields['t.'.$key] = array( 'label'=>$val['label'], 'checked'=>(($visible < 0) ? 0 : 1), - 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)), + 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')), 'position'=>$val['position'], 'help'=> isset($val['help']) ? $val['help'] : '' ); diff --git a/htdocs/salaries/payments.php b/htdocs/salaries/payments.php index 77cbae397f0..58f5546216f 100644 --- a/htdocs/salaries/payments.php +++ b/htdocs/salaries/payments.php @@ -129,11 +129,11 @@ $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); + $visible = (int) dol_eval($val['visible'], 1, 1, '1'); $arrayfields['t.'.$key] = array( 'label'=>$val['label'], 'checked'=>(($visible < 0) ? 0 : 1), - 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)), + 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')), 'position'=>$val['position'], 'help'=> isset($val['help']) ? $val['help'] : '' ); diff --git a/htdocs/ticket/list.php b/htdocs/ticket/list.php index b2548807be4..f489c9218fc 100644 --- a/htdocs/ticket/list.php +++ b/htdocs/ticket/list.php @@ -136,11 +136,11 @@ $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); + $visible = (int) dol_eval($val['visible'], 1, 1, '1'); $arrayfields['t.'.$key] = array( 'label'=>$val['label'], 'checked'=>(($visible < 0) ? 0 : 1), - 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)), + 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')), 'position'=>$val['position'], 'help'=> isset($val['help']) ? $val['help'] : '' ); diff --git a/htdocs/workstation/workstation_list.php b/htdocs/workstation/workstation_list.php index 25dcc44de65..0d17232c9db 100644 --- a/htdocs/workstation/workstation_list.php +++ b/htdocs/workstation/workstation_list.php @@ -108,11 +108,11 @@ $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); + $visible = (int) dol_eval($val['visible'], 1, 1, '1'); $arrayfields['t.'.$key] = array( 'label'=>$val['label'], 'checked'=>(($visible < 0) ? 0 : 1), - 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)), + 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')), 'position'=>$val['position'], 'help' => empty($val['help']) ? '' : $val['help'] ); @@ -130,7 +130,7 @@ $arrayfields['wug.fk_usergroup'] = array( $arrayfields['wr.fk_resource'] = array( 'label'=>$langs->trans('Resources'), 'checked'=>(($visible < 0) ? 0 : 1), - 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)), + 'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')), 'position'=>1001, 'help' => empty($val['help']) ? '' : $val['help'] ); diff --git a/test/phpunit/SecurityTest.php b/test/phpunit/SecurityTest.php index 15e4eaa8bda..a687e6adbd7 100644 --- a/test/phpunit/SecurityTest.php +++ b/test/phpunit/SecurityTest.php @@ -875,11 +875,18 @@ class SecurityTest extends PHPUnit\Framework\TestCase include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php'; include_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php'; - $result=dol_eval('(($reloadedobj = new Task($db)) && ($reloadedobj->fetchNoCompute($object->id) > 0) && ($secondloadedobj = new Project($db)) && ($secondloadedobj->fetchNoCompute($reloadedobj->fk_project) > 0)) ? $secondloadedobj->ref: "Parent project not found"', 1, 1); + + $s = '(($reloadedobj = new Task($db)) && ($reloadedobj->fetchNoCompute($object->id) > 0) && ($secondloadedobj = new Project($db)) && ($secondloadedobj->fetchNoCompute($reloadedobj->fk_project) > 0)) ? $secondloadedobj->ref: "Parent project not found"'; + $result=dol_eval($s, 1, 1, ''); print "result = ".$result."\n"; $this->assertEquals('Parent project not found', $result); - $result=dol_eval('$a=function() { }; $a;', 1, 1); + $s = '(($reloadedobj = new Task($db)) && ($reloadedobj->fetchNoCompute($object->id) > 0) && ($secondloadedobj = new Project($db)) && ($secondloadedobj->fetchNoCompute($reloadedobj->fk_project) > 0)) ? $secondloadedobj->ref: \'Parent project not found\''; + $result=dol_eval($s, 1, 1, ''); + print "result = ".$result."\n"; + $this->assertEquals('Parent project not found', $result); + + $result=dol_eval('$a=function() { }; $a;', 1, 1, ''); print "result = ".$result."\n"; $this->assertContains('Bad string syntax to evaluate', $result); @@ -898,5 +905,18 @@ class SecurityTest extends PHPUnit\Framework\TestCase $result=dol_eval('`ls`', 1, 0); print "result = ".$result."\n"; $this->assertContains('Bad string syntax to evaluate', $result); + + $result=dol_eval("('ex'.'ec')('echo abc')", 1, 0); + print "result = ".$result."\n"; + $this->assertContains('Bad string syntax to evaluate', $result); + + // Case with param onlysimplestring = 1 + $result=dol_eval('1 && $conf->abc->doesnotexist1 && $conf->def->doesnotexist1', 1, 0); // Should return false and not a 'Bad string syntax to evaluate ...' + print "result = ".$result."\n"; + $this->assertFalse($result); + + $result=dol_eval("(\$a.'aa')", 1, 0); + print "result = ".$result."\n"; + $this->assertContains('Bad string syntax to evaluate', $result); } } From 237b6fc9226e1c3e87d68ddce1f2dc9229473f63 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 1 Mar 2022 17:07:28 +0100 Subject: [PATCH 229/255] Fix value recommended --- htdocs/admin/system/security.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/admin/system/security.php b/htdocs/admin/system/security.php index 9321fa11c12..eb3a6d7c884 100644 --- a/htdocs/admin/system/security.php +++ b/htdocs/admin/system/security.php @@ -444,7 +444,7 @@ print '
    '; print 'MAIN_RESTRICTHTML_REMOVE_ALSO_BAD_ATTRIBUTES = '.(empty($conf->global->MAIN_RESTRICTHTML_REMOVE_ALSO_BAD_ATTRIBUTES) ? ''.$langs->trans("Undefined").'   ('.$langs->trans("Recommended").': 1)' : $conf->global->MAIN_RESTRICTHTML_REMOVE_ALSO_BAD_ATTRIBUTES)."
    "; print '
    '; -print 'MAIN_SECURITY_CSRF_WITH_TOKEN = '.(empty($conf->global->MAIN_SECURITY_CSRF_WITH_TOKEN) ? ''.$langs->trans("Undefined").'   ('.$langs->trans("Recommended").': 2)' : $conf->global->MAIN_SECURITY_CSRF_WITH_TOKEN)."
    "; +print 'MAIN_SECURITY_CSRF_WITH_TOKEN = '.(empty($conf->global->MAIN_SECURITY_CSRF_WITH_TOKEN) ? ''.$langs->trans("Undefined").'' : $conf->global->MAIN_SECURITY_CSRF_WITH_TOKEN).'   ('.$langs->trans("Recommended").': 2)'."
    "; print '
    '; print 'MAIN_SECURITY_CSRF_TOKEN_RENEWAL_ON_EACH_CALL = '.(empty($conf->global->MAIN_SECURITY_CSRF_TOKEN_RENEWAL_ON_EACH_CALL) ? ''.$langs->trans("Undefined").'   ('.$langs->trans("Recommended").': '.$langs->trans("Undefined").' '.$langs->trans("or").' 0)' : $conf->global->MAIN_SECURITY_CSRF_TOKEN_RENEWAL_ON_EACH_CALL)."
    "; From b79ad197ec3760f844e37a8d52f63ea47ea162a1 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 1 Mar 2022 17:29:22 +0100 Subject: [PATCH 230/255] FIX Missing the field date start/end in export supplier invoice/order --- htdocs/core/modules/modFournisseur.class.php | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/htdocs/core/modules/modFournisseur.class.php b/htdocs/core/modules/modFournisseur.class.php index 0f730f773bb..a9760c62c04 100644 --- a/htdocs/core/modules/modFournisseur.class.php +++ b/htdocs/core/modules/modFournisseur.class.php @@ -293,7 +293,8 @@ class modFournisseur extends DolibarrModules 'f.rowid'=>"InvoiceId", 'f.ref'=>"InvoiceRef", 'f.ref_supplier'=>"RefSupplier", 'f.datec'=>"InvoiceDateCreation", 'f.datef'=>"DateInvoice", 'f.date_lim_reglement'=>'DateMaxPayment', 'f.total_ht'=>"TotalHT", 'f.total_ttc'=>"TotalTTC", 'f.total_tva'=>"TotalVAT", 'f.paye'=>"InvoicePaid", 'f.fk_statut'=>'InvoiceStatus', 'f.note_public'=>"InvoiceNote", 'fd.rowid'=>'LineId', 'fd.description'=>"LineDescription", 'fd.tva_tx'=>"LineVATRate", 'fd.qty'=>"LineQty", 'fd.remise_percent'=>"Discount", 'fd.total_ht'=>"LineTotalHT", - 'fd.total_ttc'=>"LineTotalTTC", 'fd.tva'=>"LineTotalVAT", 'fd.product_type'=>'TypeOfLineServiceOrProduct', 'fd.fk_product'=>'ProductId', + 'fd.total_ttc'=>"LineTotalTTC", 'fd.tva'=>"LineTotalVAT", 'fd.date_start'=>"DateStart", 'fd.date_end'=>"DateEnd", 'fd.special_code'=>'SpecialCode', + 'fd.product_type'=>'TypeOfLineServiceOrProduct', 'fd.fk_product'=>'ProductId', 'p.ref'=>'ProductRef', 'p.label'=>'ProductLabel', 'p.accountancy_code_buy'=>'ProductAccountancyBuyCode', 'project.rowid'=>'ProjectId', 'project.ref'=>'ProjectRef', 'project.title'=>'ProjectLabel' ); @@ -314,7 +315,8 @@ class modFournisseur extends DolibarrModules 's.nom'=>'Text', 'ps.nom'=>'Text', 's.address'=>'Text', 's.zip'=>'Text', 's.town'=>'Text', 'c.code'=>'Text', 's.phone'=>'Text', 's.siren'=>'Text', 's.siret'=>'Text', 's.ape'=>'Text', 's.idprof4'=>'Text', 's.idprof5'=>'Text', 's.idprof6'=>'Text', 's.code_compta'=>'Text', 's.code_compta_fournisseur'=>'Text', 's.tva_intra'=>'Text', 'f.ref'=>"Text", 'f.ref_supplier'=>"Text", 'f.datec'=>"Date", 'f.datef'=>"Date", 'f.date_lim_reglement'=>'Date', 'f.total_ht'=>"Numeric", 'f.total_ttc'=>"Numeric", 'f.total_tva'=>"Numeric", 'f.paye'=>"Boolean", 'f.fk_statut'=>'Status', 'f.note_public'=>"Text", 'fd.description'=>"Text", 'fd.tva_tx'=>"Text", - 'fd.qty'=>"Numeric", 'fd.total_ht'=>"Numeric", 'fd.total_ttc'=>"Numeric", 'fd.tva'=>"Numeric", 'fd.product_type'=>'Numeric', 'fd.fk_product'=>'List:product:label', + 'fd.qty'=>"Numeric", 'fd.total_ht'=>"Numeric", 'fd.total_ttc'=>"Numeric", 'fd.tva'=>"Numeric", 'fd.date_start'=>"Date", 'fd.date_end'=>"Date", 'fd.special_code'=>"Numeric", + 'fd.product_type'=>'Numeric', 'fd.fk_product'=>'List:product:label', 'p.ref'=>'Text', 'p.label'=>'Text', 'project.ref'=>'Text', 'project.title'=>'Text' ); $this->export_entities_array[$r] = array( @@ -322,7 +324,8 @@ class modFournisseur extends DolibarrModules 's.ape'=>'company', 's.idprof4'=>'company', 's.idprof5'=>'company', 's.idprof6'=>'company', 's.code_compta'=>'company', 's.code_compta_fournisseur'=>'company', 's.tva_intra'=>'company', 'f.rowid'=>"invoice", 'f.ref'=>"invoice", 'f.ref_supplier'=>"invoice", 'f.datec'=>"invoice", 'f.datef'=>"invoice", 'f.date_lim_reglement'=>'invoice', 'f.total_ht'=>"invoice", 'f.total_ttc'=>"invoice", 'f.total_tva'=>"invoice", 'f.paye'=>"invoice", 'f.fk_statut'=>'invoice', 'f.note_public'=>"invoice", 'fd.rowid'=>'invoice_line', 'fd.description'=>"invoice_line", 'fd.tva_tx'=>"invoice_line", 'fd.qty'=>"invoice_line", - 'fd.remise_percent'=>"invoice_line", 'fd.total_ht'=>"invoice_line", 'fd.total_ttc'=>"invoice_line", 'fd.tva'=>"invoice_line", 'fd.product_type'=>'invoice_line', 'fd.fk_product'=>'product', + 'fd.remise_percent'=>"invoice_line", 'fd.total_ht'=>"invoice_line", 'fd.total_ttc'=>"invoice_line", 'fd.tva'=>"invoice_line", 'fd.date_start'=>"invoice_line", 'fd.date_end'=>"invoice_line", 'fd.special_code'=>"invoice_line", + 'fd.product_type'=>'invoice_line', 'fd.fk_product'=>'product', 'p.ref'=>'product', 'p.label'=>'product', 'p.accountancy_code_buy'=>'product', 'project.rowid'=>'project', 'project.ref'=>'project', 'project.title'=>'project' ); $this->export_dependencies_array[$r] = array('invoice_line'=>'fd.rowid', 'product'=>'fd.rowid'); // To add unique key if we ask a field of a child to avoid the DISTINCT to discard them @@ -432,7 +435,8 @@ class modFournisseur extends DolibarrModules 'f.total_ht'=>"TotalHT", 'f.total_ttc'=>"TotalTTC", 'f.total_tva'=>"TotalVAT", 'f.fk_statut'=>'Status', 'f.date_valid'=>'DateValidation', 'f.date_approve'=>'DateApprove', 'f.date_approve2'=>'DateApprove2', 'f.note_public'=>"NotePublic", 'f.note_private'=>"NotePrivate", 'uv.login'=>'UserValidation', 'ua1.login'=>'ApprovedBy', 'ua2.login'=>'ApprovedBy2', 'fd.rowid'=>'LineId', 'fd.description'=>"LineDescription", 'fd.tva_tx'=>"LineVATRate", 'fd.qty'=>"LineQty", 'fd.remise_percent'=>"Discount", 'fd.total_ht'=>"LineTotalHT", 'fd.total_ttc'=>"LineTotalTTC", - 'fd.total_tva'=>"LineTotalVAT", 'fd.product_type'=>'TypeOfLineServiceOrProduct', 'fd.ref'=>'RefSupplier', 'fd.fk_product'=>'ProductId', + 'fd.total_tva'=>"LineTotalVAT", 'fd.date_start'=>"DateStart", 'fd.date_end'=>"DateEnd", 'fd.special_code'=>'SpecialCode', + 'fd.product_type'=>'TypeOfLineServiceOrProduct', 'fd.ref'=>'RefSupplier', 'fd.fk_product'=>'ProductId', 'p.ref'=>'ProductRef', 'p.label'=>'ProductLabel', 'project.rowid'=>'ProjectId', 'project.ref'=>'ProjectRef', 'project.title'=>'ProjectLabel' ); if (!empty($conf->multicurrency->enabled)) { @@ -452,13 +456,15 @@ class modFournisseur extends DolibarrModules 'f.date_creation'=>"Date", 'f.date_commande'=>"Date", 'f.date_livraison'=>"Date", 'f.total_ht'=>"Numeric", 'f.total_ttc'=>"Numeric", 'f.total_tva'=>"Numeric", 'f.fk_statut'=>'Status', 'f.date_valid'=>'Date', 'f.date_approve'=>'Date', 'f.date_approve2'=>'Date', 'f.note_public'=>"Text", 'f.note_private'=>"Text", 'fd.description'=>"Text", 'fd.tva_tx'=>"Numeric", 'fd.qty'=>"Numeric", 'fd.remise_percent'=>"Numeric", 'fd.total_ht'=>"Numeric", 'fd.total_ttc'=>"Numeric", 'fd.total_tva'=>"Numeric", + 'fd.date_start'=>"Date", 'fd.date_end'=>"Date", 'fd.special_code'=>"Numeric", 'fd.product_type'=>'Numeric', 'fd.ref'=>'Text', 'fd.fk_product'=>'List:product:label', 'p.ref'=>'Text', 'p.label'=>'Text', 'project.ref'=>'Text', 'project.title'=>'Text' ); $this->export_entities_array[$r] = array( 's.rowid'=>"company", 's.nom'=>'company', 'ps.nom'=>'company', 's.address'=>'company', 's.zip'=>'company', 's.town'=>'company', 'c.code'=>'company', 's.phone'=>'company', 's.siren'=>'company', 's.siret'=>'company', 's.ape'=>'company', 's.idprof4'=>'company', 's.idprof5'=>'company', 's.idprof6'=>'company', 's.tva_intra'=>'company', 'uv.login'=>'user', 'ua1.login'=>'user', 'ua2.login'=>'user', 'fd.rowid'=>'order_line', 'fd.description'=>"order_line", 'fd.tva_tx'=>"order_line", 'fd.qty'=>"order_line", 'fd.remise_percent'=>"order_line", - 'fd.total_ht'=>"order_line", 'fd.total_ttc'=>"order_line", 'fd.total_tva'=>"order_line", 'fd.product_type'=>'order_line', 'fd.ref'=>'order_line', 'fd.fk_product'=>'product', + 'fd.total_ht'=>"order_line", 'fd.total_ttc'=>"order_line", 'fd.total_tva'=>"order_line", 'fd.date_start'=>"order_line", 'fd.date_end'=>"order_line", 'fd.special_code'=>"order_line", + 'fd.product_type'=>'order_line', 'fd.ref'=>'order_line', 'fd.fk_product'=>'product', 'p.ref'=>'product', 'p.label'=>'product', 'project.rowid'=>'project', 'project.ref'=>'project', 'project.title'=>'project' ); $this->export_dependencies_array[$r] = array('order_line'=>'fd.rowid', 'product'=>'fd.rowid'); // To add unique key if we ask a field of a child to avoid the DISTINCT to discard them From 883f13b38892c8e98ef6f1cf456129aba7d914a1 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 1 Mar 2022 18:14:24 +0100 Subject: [PATCH 231/255] Fix regression verifCond --- htdocs/core/lib/functions.lib.php | 27 ++++++++++++++++++++++----- test/phpunit/SecurityTest.php | 8 ++++++-- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index c6476f98a11..c6ceadf0a71 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -8167,7 +8167,7 @@ function dol_getIdFromCode($db, $key, $tablename, $fieldkey = 'code', $fieldid = * Verify if condition in string is ok or not * * @param string $strToEvaluate String with condition to check - * @return boolean True or False. Note: It returns True if $strToEvaluate is '' + * @return boolean True or False. Note: It returns also True if $strToEvaluate is '' */ function verifCond($strToEvaluate) { @@ -8178,8 +8178,10 @@ function verifCond($strToEvaluate) //print $strToEvaluate."
    \n"; $rights = true; if (isset($strToEvaluate) && $strToEvaluate !== '') { - $str = 'if(!('.$strToEvaluate.')) { $rights = false; }'; - dol_eval($str); // The dol_eval must contains all the global $xxx used into a condition + $str = 'if(!('.$strToEvaluate.')) $rights = false;'; + dol_eval($str, 0, 1, '2'); // The dol_eval must contains all the global $xxx used into a condition + //$rep = dol_eval($strToEvaluate, 1, 1 , '1'); // The dol_eval must contains all the global $xxx used into a condition + //$rights = ($rep ? true : false); } return $rights; } @@ -8191,7 +8193,7 @@ function verifCond($strToEvaluate) * @param string $s String to evaluate * @param int $returnvalue 0=No return (used to execute eval($a=something)). 1=Value of eval is returned (used to eval($something)). * @param int $hideerrors 1=Hide errors - * @param string $onlysimplestring Accept only simple string with char 'a-z0-9\s$_->&|='; + * @param string $onlysimplestring 0=Accept all chars, 1=Accept only simple string with char 'a-z0-9\s$_->&|=';, 2=Accept also '!?():";' * @return mixed Nothing or return result of eval */ function dol_eval($s, $returnvalue = 0, $hideerrors = 1, $onlysimplestring = '1') @@ -8210,7 +8212,22 @@ function dol_eval($s, $returnvalue = 0, $hideerrors = 1, $onlysimplestring = '1' if ($onlysimplestring == '1') { //print preg_quote('$_->&|', '/'); if (preg_match('/[^a-z0-9\s'.preg_quote('$_->&|=', '/').']/i', $s)) { - return 'Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s; + if ($returnvalue) { + return 'Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s; + } else { + dol_syslog('Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s); + return ''; + } + } + } elseif ($onlysimplestring == '2') { + //print preg_quote('$_->&|', '/'); + if (preg_match('/[^a-z0-9\s'.preg_quote('$_->&|=!?():";', '/').']/i', $s)) { + if ($returnvalue) { + return 'Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s; + } else { + dol_syslog('Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s); + return ''; + } } } if (strpos($s, '`') !== false) { diff --git a/test/phpunit/SecurityTest.php b/test/phpunit/SecurityTest.php index a687e6adbd7..7194c1cbfd4 100644 --- a/test/phpunit/SecurityTest.php +++ b/test/phpunit/SecurityTest.php @@ -876,12 +876,12 @@ class SecurityTest extends PHPUnit\Framework\TestCase include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php'; include_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php'; - $s = '(($reloadedobj = new Task($db)) && ($reloadedobj->fetchNoCompute($object->id) > 0) && ($secondloadedobj = new Project($db)) && ($secondloadedobj->fetchNoCompute($reloadedobj->fk_project) > 0)) ? $secondloadedobj->ref: "Parent project not found"'; + $s = '(($reloadedobj = new Task($db)) && ($reloadedobj->fetchNoCompute($object->id) > 0) && ($secondloadedobj = new Project($db)) && ($secondloadedobj->fetchNoCompute($reloadedobj->fk_project) > 0)) ? $secondloadedobj->ref : "Parent project not found"'; $result=dol_eval($s, 1, 1, ''); print "result = ".$result."\n"; $this->assertEquals('Parent project not found', $result); - $s = '(($reloadedobj = new Task($db)) && ($reloadedobj->fetchNoCompute($object->id) > 0) && ($secondloadedobj = new Project($db)) && ($secondloadedobj->fetchNoCompute($reloadedobj->fk_project) > 0)) ? $secondloadedobj->ref: \'Parent project not found\''; + $s = '(($reloadedobj = new Task($db)) && ($reloadedobj->fetchNoCompute($object->id) > 0) && ($secondloadedobj = new Project($db)) && ($secondloadedobj->fetchNoCompute($reloadedobj->fk_project) > 0)) ? $secondloadedobj->ref : \'Parent project not found\''; $result=dol_eval($s, 1, 1, ''); print "result = ".$result."\n"; $this->assertEquals('Parent project not found', $result); @@ -910,6 +910,10 @@ class SecurityTest extends PHPUnit\Framework\TestCase print "result = ".$result."\n"; $this->assertContains('Bad string syntax to evaluate', $result); + $result=dol_eval("sprintf(\"%s%s\", \"ex\", \"ec\")('echo abc')", 1, 0, ''); + print "result = ".$result."\n"; + $this->assertContains('Bad string syntax to evaluate', $result); + // Case with param onlysimplestring = 1 $result=dol_eval('1 && $conf->abc->doesnotexist1 && $conf->def->doesnotexist1', 1, 0); // Should return false and not a 'Bad string syntax to evaluate ...' print "result = ".$result."\n"; From e5fd841fe356d35a1121a16161e73ddcaf2e0595 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 1 Mar 2022 18:21:30 +0100 Subject: [PATCH 232/255] Make verifCond more robust against RCE --- htdocs/core/lib/functions.lib.php | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index de5e3f7201b..75832d42d0a 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -8308,10 +8308,10 @@ function verifCond($strToEvaluate) //print $strToEvaluate."
    \n"; $rights = true; if (isset($strToEvaluate) && $strToEvaluate !== '') { - $str = 'if(!('.$strToEvaluate.')) $rights = false;'; - dol_eval($str, 0, 1, '2'); // The dol_eval must contains all the global $xxx used into a condition - //$rep = dol_eval($strToEvaluate, 1, 1 , '1'); // The dol_eval must contains all the global $xxx used into a condition - //$rights = ($rep ? true : false); + //$str = 'if(!('.$strToEvaluate.')) $rights = false;'; + //dol_eval($str, 0, 1, '2'); // The dol_eval must contains all the global $xxx used into a condition + $rep = dol_eval($strToEvaluate, 1, 1, '1'); // The dol_eval must contains all the global $xxx used into a condition + $rights = ($rep ? true : false); } return $rights; } @@ -8338,10 +8338,10 @@ function dol_eval($s, $returnvalue = 0, $hideerrors = 1, $onlysimplestring = '1' global $obj; // To get $obj used into list when dol_eval is used for computed fields and $obj is not yet $object global $soc; // For backward compatibility - // Test dangerous char (used for RCE), we allow only PHP variable testing. + // Test on dangerous char (used for RCE), we allow only characters to make PHP variable testing. if ($onlysimplestring == '1') { //print preg_quote('$_->&|', '/'); - if (preg_match('/[^a-z0-9\s'.preg_quote('$_->&|=', '/').']/i', $s)) { + if (preg_match('/[^a-z0-9\s'.preg_quote('$_->&|=!?:', '/').']/i', $s)) { if ($returnvalue) { return 'Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s; } else { @@ -8360,6 +8360,9 @@ function dol_eval($s, $returnvalue = 0, $hideerrors = 1, $onlysimplestring = '1' } } } + if (strpos($s, '::') !== false) { + return 'Bad string syntax to evaluate (double : char is forbidden): '.$s; + } if (strpos($s, '`') !== false) { return 'Bad string syntax to evaluate (backtick char is forbidden): '.$s; } From 2e38caa950aab06339d3e7f4abb5fc4d522cd26b Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 1 Mar 2022 18:22:09 +0100 Subject: [PATCH 233/255] phpunit --- test/phpunit/SecurityTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/phpunit/SecurityTest.php b/test/phpunit/SecurityTest.php index 7194c1cbfd4..636309f2349 100644 --- a/test/phpunit/SecurityTest.php +++ b/test/phpunit/SecurityTest.php @@ -910,7 +910,7 @@ class SecurityTest extends PHPUnit\Framework\TestCase print "result = ".$result."\n"; $this->assertContains('Bad string syntax to evaluate', $result); - $result=dol_eval("sprintf(\"%s%s\", \"ex\", \"ec\")('echo abc')", 1, 0, ''); + $result=dol_eval("sprintf(\"%s%s\", \"ex\", \"ec\")('echo abc')", 1, 0); print "result = ".$result."\n"; $this->assertContains('Bad string syntax to evaluate', $result); From 762de973ebea283e2746ddcbdd6ad437c44c59ec Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 1 Mar 2022 18:43:16 +0100 Subject: [PATCH 234/255] Fix sql injection --- htdocs/core/lib/security.lib.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/lib/security.lib.php b/htdocs/core/lib/security.lib.php index ccdfa261fc8..44d6f5c739b 100644 --- a/htdocs/core/lib/security.lib.php +++ b/htdocs/core/lib/security.lib.php @@ -289,7 +289,7 @@ function restrictedArea($user, $features, $objectid = 0, $tableandshare = '', $f } if ($dbt_select != 'rowid' && $dbt_select != 'id') { - $objectid = "'".$objectid."'"; + $objectid = "'".$db->escape($objectid)."'"; } // Features/modules to check From 7c253c7e2882e9679274acad971f1ec51b2daf4e Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 1 Mar 2022 18:46:55 +0100 Subject: [PATCH 235/255] Clean code --- htdocs/core/lib/security.lib.php | 33 +++++++++++-------------- htdocs/workstation/workstation_note.php | 5 ---- 2 files changed, 15 insertions(+), 23 deletions(-) diff --git a/htdocs/core/lib/security.lib.php b/htdocs/core/lib/security.lib.php index 44d6f5c739b..ce94d6128dc 100644 --- a/htdocs/core/lib/security.lib.php +++ b/htdocs/core/lib/security.lib.php @@ -216,19 +216,19 @@ function dolGetLdapPasswordHash($password, $type = 'md5') * If GETPOST('action','aZ09') defined, we also check write and delete permission. * This method check permission on module then call checkUserAccessToObject() for permission on object (according to entity and socid of user). * - * @param User $user User to check - * @param string $features Features to check (it must be module $object->element. Can be a 'or' check with 'levela|levelb'. - * Examples: 'societe', 'contact', 'produit&service', 'produit|service', ...) - * This is used to check permission $user->rights->features->... - * @param int $objectid Object ID if we want to check a particular record (optional) is linked to a owned thirdparty (optional). - * @param string $tableandshare 'TableName&SharedElement' with Tablename is table where object is stored. SharedElement is an optional key to define where to check entity for multicompany module. Param not used if objectid is null (optional). - * @param string $feature2 Feature to check, second level of permission (optional). Can be a 'or' check with 'sublevela|sublevelb'. - * This is used to check permission $user->rights->features->feature2... - * @param string $dbt_keyfield Field name for socid foreign key if not fk_soc. Not used if objectid is null (optional) - * @param string $dbt_select Field name for select if not rowid. Not used if objectid is null (optional) - * @param int $isdraft 1=The object with id=$objectid is a draft - * @param int $mode Mode (0=default, 1=return with not die) - * @return int If mode = 0 (default): Always 1, die process if not allowed. If mode = 1: Return 0 if access not allowed. + * @param User $user User to check + * @param string $features Features to check (it must be module $object->element. Can be a 'or' check with 'levela|levelb'. + * Examples: 'societe', 'contact', 'produit&service', 'produit|service', ...) + * This is used to check permission $user->rights->features->... + * @param int $objectid Object ID if we want to check a particular record (optional) is linked to a owned thirdparty (optional). + * @param string $tableandshare 'TableName&SharedElement' with Tablename is table where object is stored. SharedElement is an optional key to define where to check entity for multicompany module. Param not used if objectid is null (optional). + * @param string $feature2 Feature to check, second level of permission (optional). Can be a 'or' check with 'sublevela|sublevelb'. + * This is used to check permission $user->rights->features->feature2... + * @param string $dbt_keyfield Field name for socid foreign key if not fk_soc. Not used if objectid is null (optional) + * @param string $dbt_select Field name for select if not rowid. Not used if objectid is null (optional) + * @param int $isdraft 1=The object with id=$objectid is a draft + * @param int $mode Mode (0=default, 1=return with not die) + * @return int If mode = 0 (default): Always 1, die process if not allowed. If mode = 1: Return 0 if access not allowed. * @see dol_check_secure_access_document(), checkUserAccessToObject() */ function restrictedArea($user, $features, $objectid = 0, $tableandshare = '', $feature2 = '', $dbt_keyfield = 'fk_soc', $dbt_select = 'rowid', $isdraft = 0, $mode = 0) @@ -236,6 +236,8 @@ function restrictedArea($user, $features, $objectid = 0, $tableandshare = '', $f global $db, $conf; global $hookmanager; + $objectid = ((int) $objectid); // For the case value is coming from a non sanitized user input + //dol_syslog("functions.lib:restrictedArea $feature, $objectid, $dbtablename, $feature2, $dbt_socfield, $dbt_select, $isdraft"); //print "user_id=".$user->id.", features=".$features.", feature2=".$feature2.", objectid=".$objectid; //print ", dbtablename=".$dbtablename.", dbt_socfield=".$dbt_keyfield.", dbt_select=".$dbt_select; @@ -270,7 +272,6 @@ function restrictedArea($user, $features, $objectid = 0, $tableandshare = '', $f $features = 'produit'; } - // Get more permissions checks from hooks $parameters = array('features'=>$features, 'originalfeatures'=>$originalfeatures, 'objectid'=>$objectid, 'dbt_select'=>$dbt_select, 'idtype'=>$dbt_select, 'isdraft'=>$isdraft); $reshook = $hookmanager->executeHooks('restrictedArea', $parameters); @@ -288,10 +289,6 @@ function restrictedArea($user, $features, $objectid = 0, $tableandshare = '', $f return 1; } - if ($dbt_select != 'rowid' && $dbt_select != 'id') { - $objectid = "'".$db->escape($objectid)."'"; - } - // Features/modules to check $featuresarray = array($features); if (preg_match('/&/', $features)) { diff --git a/htdocs/workstation/workstation_note.php b/htdocs/workstation/workstation_note.php index ebe8d99af16..3685b7daf4e 100644 --- a/htdocs/workstation/workstation_note.php +++ b/htdocs/workstation/workstation_note.php @@ -46,11 +46,6 @@ $hookmanager->initHooks(array('workstationnote', 'globalcard')); // Note that co // 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, 'workstation', $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)) { From 3e1580475c1b0855fe33de7ad657467661ad6f9b Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 1 Mar 2022 18:22:09 +0100 Subject: [PATCH 236/255] Fix phpunit --- htdocs/core/lib/functions.lib.php | 2 +- test/phpunit/SecurityTest.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index c6ceadf0a71..191ad2da21f 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -8211,7 +8211,7 @@ function dol_eval($s, $returnvalue = 0, $hideerrors = 1, $onlysimplestring = '1' // Test dangerous char (used for RCE), we allow only PHP variable testing. if ($onlysimplestring == '1') { //print preg_quote('$_->&|', '/'); - if (preg_match('/[^a-z0-9\s'.preg_quote('$_->&|=', '/').']/i', $s)) { + if (preg_match('/[^a-z0-9\s'.preg_quote('$_->&|=!?():"', '/').']/i', $s)) { if ($returnvalue) { return 'Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s; } else { diff --git a/test/phpunit/SecurityTest.php b/test/phpunit/SecurityTest.php index 7194c1cbfd4..b96887b6152 100644 --- a/test/phpunit/SecurityTest.php +++ b/test/phpunit/SecurityTest.php @@ -910,12 +910,12 @@ class SecurityTest extends PHPUnit\Framework\TestCase print "result = ".$result."\n"; $this->assertContains('Bad string syntax to evaluate', $result); - $result=dol_eval("sprintf(\"%s%s\", \"ex\", \"ec\")('echo abc')", 1, 0, ''); + $result=dol_eval("sprintf(\"%s%s\", \"ex\", \"ec\")('echo abc')", 1, 0); print "result = ".$result."\n"; $this->assertContains('Bad string syntax to evaluate', $result); // Case with param onlysimplestring = 1 - $result=dol_eval('1 && $conf->abc->doesnotexist1 && $conf->def->doesnotexist1', 1, 0); // Should return false and not a 'Bad string syntax to evaluate ...' + $result=dol_eval('1 && getDolGlobalInt("doesnotexist1") && $conf->global->MAIN_FEATURES_LEVEL', 1, 0); // Should return false and not a 'Bad string syntax to evaluate ...' print "result = ".$result."\n"; $this->assertFalse($result); From 8051128665cfcc8bb14c7ca9b5b6d942b278dc31 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 2 Mar 2022 11:37:19 +0100 Subject: [PATCH 237/255] Split section experimental and stable --- htdocs/admin/system/security.php | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/htdocs/admin/system/security.php b/htdocs/admin/system/security.php index eb3a6d7c884..118fab39f80 100644 --- a/htdocs/admin/system/security.php +++ b/htdocs/admin/system/security.php @@ -405,7 +405,7 @@ print '

    '; print '
    '; -print load_fiche_titre($langs->trans("OtherSetup").' ('.$langs->trans("Experimental").')', '', 'folder'); +print load_fiche_titre($langs->trans("OtherSetup"), '', 'folder'); //print ''.$langs->trans("PasswordEncryption").': '; @@ -438,19 +438,24 @@ print '
    '; print 'MAIN_ALWAYS_CREATE_LOCK_AFTER_LAST_UPGRADE = '.(empty($conf->global->MAIN_ALWAYS_CREATE_LOCK_AFTER_LAST_UPGRADE) ? ''.$langs->trans("Undefined").'' : $conf->global->MAIN_ALWAYS_CREATE_LOCK_AFTER_LAST_UPGRADE).'   ('.$langs->trans("Recommended").': 1)
    '; print '
    '; +print 'MAIN_SECURITY_CSRF_WITH_TOKEN = '.(empty($conf->global->MAIN_SECURITY_CSRF_WITH_TOKEN) ? ''.$langs->trans("Undefined").'' : $conf->global->MAIN_SECURITY_CSRF_WITH_TOKEN).'   ('.$langs->trans("Recommended").': 2)'."
    "; +print '
    '; + +print '
    '; +print '
    '; + + +print load_fiche_titre($langs->trans("OtherSetup").' ('.$langs->trans("Experimental").')', '', 'folder'); + print 'MAIN_RESTRICTHTML_ONLY_VALID_HTML = '.(empty($conf->global->MAIN_RESTRICTHTML_ONLY_VALID_HTML) ? ''.$langs->trans("Undefined").'   ('.$langs->trans("Recommended").': 1)' : $conf->global->MAIN_RESTRICTHTML_ONLY_VALID_HTML)."
    "; print '
    '; print 'MAIN_RESTRICTHTML_REMOVE_ALSO_BAD_ATTRIBUTES = '.(empty($conf->global->MAIN_RESTRICTHTML_REMOVE_ALSO_BAD_ATTRIBUTES) ? ''.$langs->trans("Undefined").'   ('.$langs->trans("Recommended").': 1)' : $conf->global->MAIN_RESTRICTHTML_REMOVE_ALSO_BAD_ATTRIBUTES)."
    "; print '
    '; -print 'MAIN_SECURITY_CSRF_WITH_TOKEN = '.(empty($conf->global->MAIN_SECURITY_CSRF_WITH_TOKEN) ? ''.$langs->trans("Undefined").'' : $conf->global->MAIN_SECURITY_CSRF_WITH_TOKEN).'   ('.$langs->trans("Recommended").': 2)'."
    "; -print '
    '; - print 'MAIN_SECURITY_CSRF_TOKEN_RENEWAL_ON_EACH_CALL = '.(empty($conf->global->MAIN_SECURITY_CSRF_TOKEN_RENEWAL_ON_EACH_CALL) ? ''.$langs->trans("Undefined").'   ('.$langs->trans("Recommended").': '.$langs->trans("Undefined").' '.$langs->trans("or").' 0)' : $conf->global->MAIN_SECURITY_CSRF_TOKEN_RENEWAL_ON_EACH_CALL)."
    "; print '
    '; - print 'MAIN_EXEC_USE_POPEN = '; if (empty($conf->global->MAIN_EXEC_USE_POPEN)) { print ''.$langs->trans("Undefined").''; From 5ffac5f3ee16abd1764e4345992ba1074bab202f Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 2 Mar 2022 11:38:32 +0100 Subject: [PATCH 238/255] Fix typo --- htdocs/core/modules/modAccounting.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/modules/modAccounting.class.php b/htdocs/core/modules/modAccounting.class.php index e0bf3a9bbc5..21b20d063ed 100644 --- a/htdocs/core/modules/modAccounting.class.php +++ b/htdocs/core/modules/modAccounting.class.php @@ -256,7 +256,7 @@ class modAccounting extends DolibarrModules $r++; $this->export_code[$r] = $this->rights_class.'_'.$r; $this->export_label[$r] = 'Chartofaccounts'; - $this->export_icon[$r] = 'accounting'; + $this->export_icon[$r] = $this->picto; $this->export_permission[$r] = array(array("accounting", "chartofaccount")); $this->export_fields_array[$r] = array('ac.rowid'=>'ChartofaccountsId', 'ac.pcg_version'=>'Chartofaccounts', 'aa.rowid'=>'ID', 'aa.account_number'=>"AccountAccounting", 'aa.label'=>"Label", 'aa.account_parent'=>"Accountparent", 'aa.pcg_type'=>"Pcgtype", 'aa.active'=>'Status'); $this->export_TypeFields_array[$r] = array('ac.rowid'=>'List:accounting_system:pcg_version', 'ac.pcg_version'=>'Text', 'aa.rowid'=>'Numeric', 'aa.account_number'=>"Text", 'aa.label'=>"Text", 'aa.account_parent'=>"Text", 'aa.pcg_type'=>'Text', 'aa.active'=>'Status'); From d15c30359004b07d61830dc69eb8ae5d88b55ee2 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 2 Mar 2022 11:57:19 +0100 Subject: [PATCH 239/255] Fix missing button --- htdocs/website/index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/website/index.php b/htdocs/website/index.php index cdf425e3ae3..8ac4d612264 100644 --- a/htdocs/website/index.php +++ b/htdocs/website/index.php @@ -2807,7 +2807,7 @@ if (!GETPOST('hide_websitemenu')) { print $langs->trans("PageContainer").': '; print ''; - print ''; + print ''; print 'ref).'" class="button bordertransp"'.$disabled.' title="'.dol_escape_htmltag($langs->trans("AddPage")).'">'; print ''; From 66b0f253b69b2147825ab61b15638ce42e3cd25c Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 2 Mar 2022 12:41:21 +0100 Subject: [PATCH 240/255] Clean code --- htdocs/core/class/doleditor.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/class/doleditor.class.php b/htdocs/core/class/doleditor.class.php index 927674942e7..89f6df0cd32 100644 --- a/htdocs/core/class/doleditor.class.php +++ b/htdocs/core/class/doleditor.class.php @@ -316,7 +316,7 @@ class DolEditor jQuery(".buttonforacesave").click(function() { console.log("We click on savefile button for component '.$this->htmlname.'"); var aceEditor = window.ace.edit("'.$this->htmlname.'aceeditorid") - console.log(aceEditor.getSession().getValue()); + //console.log(aceEditor.getSession().getValue()); jQuery("#'.$this->htmlname.'").val(aceEditor.getSession().getValue()); /*if (jQuery("#'.$this->htmlname.'").html().length > 0) return true; else return false;*/ From a7cb3fa492349c5ddf154a7095be253d58aa84a1 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 2 Mar 2022 14:44:14 +0100 Subject: [PATCH 241/255] Clean log --- htdocs/core/class/doleditor.class.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/htdocs/core/class/doleditor.class.php b/htdocs/core/class/doleditor.class.php index 4266fd983c3..93c0a2445dc 100644 --- a/htdocs/core/class/doleditor.class.php +++ b/htdocs/core/class/doleditor.class.php @@ -330,7 +330,7 @@ class DolEditor var aceEditor = window.ace.edit("'.$this->htmlname.'aceeditorid"); if (aceEditor) { var cursorPos = aceEditor.getCursorPosition(); - console.log(cursorPos); + //console.log(cursorPos); if (cursorPos) { jQuery("#'.$this->htmlname.'_x").val(cursorPos.column); jQuery("#'.$this->htmlname.'_y").val(cursorPos.row); @@ -340,6 +340,7 @@ class DolEditor jQuery("#'.$this->htmlname.'").val(aceEditor.getSession().getValue()); /*if (jQuery("#'.$this->htmlname.'").html().length > 0) return true; else return false;*/ + return true; } else { console.log("Failed to retrieve js object ACE from its name"); return false; From 940417efe2869db1613926ce59b219d25afdafca Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 2 Mar 2022 15:13:17 +0100 Subject: [PATCH 242/255] FIX payment not completed when using Paypal. --- htdocs/public/payment/paymentok.php | 72 +++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 5 deletions(-) diff --git a/htdocs/public/payment/paymentok.php b/htdocs/public/payment/paymentok.php index 499ff2c4e31..5bf78e9e17a 100644 --- a/htdocs/public/payment/paymentok.php +++ b/htdocs/public/payment/paymentok.php @@ -245,7 +245,7 @@ if (!empty($conf->paypal->enabled)) { $fulltag = $FULLTAG; $payerID = $PAYPALPAYERID; // Set by newpayment.php - $paymentType = $_SESSION['PaymentType']; + $paymentType = $_SESSION['PaymentType']; // Value can be 'Mark', 'Sole', 'Sale' for example $currencyCodeType = $_SESSION['currencyCodeType']; $FinalPaymentAmt = $_SESSION["FinalPaymentAmt"]; // From env @@ -406,10 +406,19 @@ if ($ispaymentok) { $paymentTypeId = $conf->global->STRIPE_PAYMENT_MODE_FOR_PAYMENTS; } if (empty($paymentTypeId)) { + dol_syslog("paymentType = ".$paymentType, LOG_DEBUG, 0, '_payment'); + if (empty($paymentType)) { $paymentType = 'CB'; } + // May return nothing when paymentType means nothing + // (for example when paymentType is 'Mark', 'Sole', 'Sale', for paypal) $paymentTypeId = dol_getIdFromCode($db, $paymentType, 'c_paiement', 'code', 'id', 1); + + // If previous line has returned nothing, we force to get the ID of payment of Credit Card (hard coded code 'CB'). + if (empty($paymentTypeId) || $paymentTypeId < 0) { + $paymentTypeId = dol_getIdFromCode($db, 'CB', 'c_paiement', 'code', 'id', 1); + } } dol_syslog("FinalPaymentAmt=".$FinalPaymentAmt." paymentTypeId=".$paymentTypeId." paymentType=".$paymentType." currencyCodeType=".$currencyCodeType, LOG_DEBUG, 0, '_payment'); @@ -783,10 +792,19 @@ if ($ispaymentok) { $paymentTypeId = $conf->global->STRIPE_PAYMENT_MODE_FOR_PAYMENTS; } if (empty($paymentTypeId)) { + dol_syslog("paymentType = ".$paymentType, LOG_DEBUG, 0, '_payment'); + if (empty($paymentType)) { $paymentType = 'CB'; } + // May return nothing when paymentType means nothing + // (for example when paymentType is 'Mark', 'Sole', 'Sale', for paypal) $paymentTypeId = dol_getIdFromCode($db, $paymentType, 'c_paiement', 'code', 'id', 1); + + // If previous line has returned nothing, we force to get the ID of payment of Credit Card (hard coded code 'CB'). + if (empty($paymentTypeId) || $paymentTypeId < 0) { + $paymentTypeId = dol_getIdFromCode($db, 'CB', 'c_paiement', 'code', 'id', 1); + } } // Do action only if $FinalPaymentAmt is set (session variable is cleaned after this page to avoid duplicate actions when page is POST a second time) @@ -876,12 +894,29 @@ if ($ispaymentok) { $FinalPaymentAmt = $_SESSION["FinalPaymentAmt"]; $paymentTypeId = 0; - if ($paymentmethod == 'paybox') $paymentTypeId = $conf->global->PAYBOX_PAYMENT_MODE_FOR_PAYMENTS; - if ($paymentmethod == 'paypal') $paymentTypeId = $conf->global->PAYPAL_PAYMENT_MODE_FOR_PAYMENTS; - if ($paymentmethod == 'stripe') $paymentTypeId = $conf->global->STRIPE_PAYMENT_MODE_FOR_PAYMENTS; + if ($paymentmethod == 'paybox') { + $paymentTypeId = $conf->global->PAYBOX_PAYMENT_MODE_FOR_PAYMENTS; + } + if ($paymentmethod == 'paypal') { + $paymentTypeId = $conf->global->PAYPAL_PAYMENT_MODE_FOR_PAYMENTS; + } + if ($paymentmethod == 'stripe') { + $paymentTypeId = $conf->global->STRIPE_PAYMENT_MODE_FOR_PAYMENTS; + } if (empty($paymentTypeId)) { - if (empty($paymentType)) $paymentType = 'CB'; + dol_syslog("paymentType = ".$paymentType, LOG_DEBUG, 0, '_payment'); + + if (empty($paymentType)) { + $paymentType = 'CB'; + } + // May return nothing when paymentType means nothing + // (for example when paymentType is 'Mark', 'Sole', 'Sale', for paypal) $paymentTypeId = dol_getIdFromCode($db, $paymentType, 'c_paiement', 'code', 'id', 1); + + // If previous line has returned nothing, we force to get the ID of payment of Credit Card (hard coded code 'CB'). + if (empty($paymentTypeId) || $paymentTypeId < 0) { + $paymentTypeId = dol_getIdFromCode($db, 'CB', 'c_paiement', 'code', 'id', 1); + } } // Do action only if $FinalPaymentAmt is set (session variable is cleaned after this page to avoid duplicate actions when page is POST a second time) @@ -986,10 +1021,19 @@ if ($ispaymentok) { $paymentTypeId = $conf->global->STRIPE_PAYMENT_MODE_FOR_PAYMENTS; } if (empty($paymentTypeId)) { + dol_syslog("paymentType = ".$paymentType, LOG_DEBUG, 0, '_payment'); + if (empty($paymentType)) { $paymentType = 'CB'; } + // May return nothing when paymentType means nothing + // (for example when paymentType is 'Mark', 'Sole', 'Sale', for paypal) $paymentTypeId = dol_getIdFromCode($db, $paymentType, 'c_paiement', 'code', 'id', 1); + + // If previous line has returned nothing, we force to get the ID of payment of Credit Card (hard coded code 'CB'). + if (empty($paymentTypeId) || $paymentTypeId < 0) { + $paymentTypeId = dol_getIdFromCode($db, 'CB', 'c_paiement', 'code', 'id', 1); + } } // Do action only if $FinalPaymentAmt is set (session variable is cleaned after this page to avoid duplicate actions when page is POST a second time) @@ -1091,10 +1135,19 @@ if ($ispaymentok) { $paymentTypeId = $conf->global->STRIPE_PAYMENT_MODE_FOR_PAYMENTS; } if (empty($paymentTypeId)) { + dol_syslog("paymentType = ".$paymentType, LOG_DEBUG, 0, '_payment'); + if (empty($paymentType)) { $paymentType = 'CB'; } + // May return nothing when paymentType means nothing + // (for example when paymentType is 'Mark', 'Sole', 'Sale', for paypal) $paymentTypeId = dol_getIdFromCode($db, $paymentType, 'c_paiement', 'code', 'id', 1); + + // If previous line has returned nothing, we force to get the ID of payment of Credit Card (hard coded code 'CB'). + if (empty($paymentTypeId) || $paymentTypeId < 0) { + $paymentTypeId = dol_getIdFromCode($db, 'CB', 'c_paiement', 'code', 'id', 1); + } } // Do action only if $FinalPaymentAmt is set (session variable is cleaned after this page to avoid duplicate actions when page is POST a second time) @@ -1272,10 +1325,19 @@ if ($ispaymentok) { $paymentTypeId = $conf->global->STRIPE_PAYMENT_MODE_FOR_PAYMENTS; } if (empty($paymentTypeId)) { + dol_syslog("paymentType = ".$paymentType, LOG_DEBUG, 0, '_payment'); + if (empty($paymentType)) { $paymentType = 'CB'; } + // May return nothing when paymentType means nothing + // (for example when paymentType is 'Mark', 'Sole', 'Sale', for paypal) $paymentTypeId = dol_getIdFromCode($db, $paymentType, 'c_paiement', 'code', 'id', 1); + + // If previous line has returned nothing, we force to get the ID of payment of Credit Card (hard coded code 'CB'). + if (empty($paymentTypeId) || $paymentTypeId < 0) { + $paymentTypeId = dol_getIdFromCode($db, 'CB', 'c_paiement', 'code', 'id', 1); + } } // Do action only if $FinalPaymentAmt is set (session variable is cleaned after this page to avoid duplicate actions when page is POST a second time) From 987b32ef196bc63467243aec071b2940de806641 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 2 Mar 2022 22:04:44 +0100 Subject: [PATCH 243/255] Fix a default value is creating a letal blocking situation --- htdocs/accountancy/bookkeeping/list.php | 4 ++-- htdocs/core/class/html.form.class.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/htdocs/accountancy/bookkeeping/list.php b/htdocs/accountancy/bookkeeping/list.php index b67b134e3e1..b2d05452416 100644 --- a/htdocs/accountancy/bookkeeping/list.php +++ b/htdocs/accountancy/bookkeeping/list.php @@ -682,13 +682,13 @@ if ($action == 'export_file') { 'name' => 'notifiedexportdate', 'type' => 'checkbox', 'label' => $langs->trans('NotifiedExportDate'), - 'value' => (!empty($conf->global->ACCOUNTING_DEFAULT_NOT_NOTIFIED_EXPORT_DATE) ? 'false' : 'true'), + 'value' => (empty($conf->global->ACCOUNTING_DEFAULT_NOTIFIED_EXPORT_DATE) ? '' : 'true'), ); $form_question['notifiedvalidationdate'] = array( 'name' => 'notifiedvalidationdate', 'type' => 'checkbox', 'label' => $langs->trans('NotifiedValidationDate'), - 'value' => (!empty($conf->global->ACCOUNTING_DEFAULT_NOT_NOTIFIED_VALIDATION_DATE) ? 'false' : 'true'), + 'value' => (empty($conf->global->ACCOUNTING_DEFAULT_NOTIFIED_VALIDATION_DATE) ? '' : 'true'), ); $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?'.$param, $langs->trans("ExportFilteredList").' ('.$listofformat[$formatexportset].')', $langs->trans('ConfirmExportFile'), 'export_fileconfirm', $form_question, '', 1, 300, 600); diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 975e6ed86ea..87d3d63cec1 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -4807,7 +4807,7 @@ class Form $more .= '
    '; $more .= '
    '.$input['label'].'
    '; $more .= ' Date: Wed, 2 Mar 2022 22:04:44 +0100 Subject: [PATCH 244/255] Fix a default value is creating a letal blocking situation --- htdocs/accountancy/bookkeeping/list.php | 4 ++-- htdocs/core/class/html.form.class.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/htdocs/accountancy/bookkeeping/list.php b/htdocs/accountancy/bookkeeping/list.php index b67b134e3e1..d110f74a6a6 100644 --- a/htdocs/accountancy/bookkeeping/list.php +++ b/htdocs/accountancy/bookkeeping/list.php @@ -682,13 +682,13 @@ if ($action == 'export_file') { 'name' => 'notifiedexportdate', 'type' => 'checkbox', 'label' => $langs->trans('NotifiedExportDate'), - 'value' => (!empty($conf->global->ACCOUNTING_DEFAULT_NOT_NOTIFIED_EXPORT_DATE) ? 'false' : 'true'), + 'value' => (empty($conf->global->ACCOUNTING_DEFAULT_NOTIFIED_EXPORT_DATE) ? false : true), ); $form_question['notifiedvalidationdate'] = array( 'name' => 'notifiedvalidationdate', 'type' => 'checkbox', 'label' => $langs->trans('NotifiedValidationDate'), - 'value' => (!empty($conf->global->ACCOUNTING_DEFAULT_NOT_NOTIFIED_VALIDATION_DATE) ? 'false' : 'true'), + 'value' => (empty($conf->global->ACCOUNTING_DEFAULT_NOTIFIED_VALIDATION_DATE) ? false : true), ); $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?'.$param, $langs->trans("ExportFilteredList").' ('.$listofformat[$formatexportset].')', $langs->trans('ConfirmExportFile'), 'export_fileconfirm', $form_question, '', 1, 300, 600); diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 975e6ed86ea..87d3d63cec1 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -4807,7 +4807,7 @@ class Form $more .= '
    '; $more .= '
    '.$input['label'].'
    '; $more .= ' Date: Wed, 2 Mar 2022 22:20:05 +0100 Subject: [PATCH 245/255] Fix label of menu --- htdocs/accountancy/closure/index.php | 1 - htdocs/langs/en_US/accountancy.lang | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/htdocs/accountancy/closure/index.php b/htdocs/accountancy/closure/index.php index 6b578bcab71..f02eda61bf6 100644 --- a/htdocs/accountancy/closure/index.php +++ b/htdocs/accountancy/closure/index.php @@ -13,7 +13,6 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - * */ /** diff --git a/htdocs/langs/en_US/accountancy.lang b/htdocs/langs/en_US/accountancy.lang index a44c819aa78..6f9d74de7c8 100644 --- a/htdocs/langs/en_US/accountancy.lang +++ b/htdocs/langs/en_US/accountancy.lang @@ -282,7 +282,7 @@ DescClosure=Consult here the number of movements by month who are not validated OverviewOfMovementsNotValidated=Step 1/ Overview of movements not validated. (Necessary to close a fiscal year) AllMovementsWereRecordedAsValidated=All movements were recorded as validated NotAllMovementsCouldBeRecordedAsValidated=Not all movements could be recorded as validated -ValidateMovements=Validate movements +ValidateMovements=Validate and lock record... DescValidateMovements=Any modification or deletion of writing, lettering and deletes will be prohibited. All entries for an exercise must be validated otherwise closing will not be possible ValidateHistory=Bind Automatically From a9a2928e632bbeda9d2dd91af10222e6da39e766 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 3 Mar 2022 00:13:35 +0100 Subject: [PATCH 246/255] Responsive --- htdocs/bookmarks/card.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/htdocs/bookmarks/card.php b/htdocs/bookmarks/card.php index 8833978e054..bbc92a83ef1 100644 --- a/htdocs/bookmarks/card.php +++ b/htdocs/bookmarks/card.php @@ -160,7 +160,7 @@ if ($action == 'create') { print ''; - print ''; + print ''; dol_set_focus('#titlebookmark'); // Url @@ -230,9 +230,9 @@ if ($id > 0 && !preg_match('/^add/i', $action)) { print ''; From 3c3d6ab0da5ddf470c766ac339b2328f9268d9e4 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 3 Mar 2022 01:17:44 +0100 Subject: [PATCH 247/255] Fix regression. Add unit test to detect it. --- htdocs/core/lib/functions.lib.php | 31 ++++++++++++++++++------ htdocs/core/modules/modBarcode.class.php | 3 ++- test/phpunit/SecurityTest.php | 9 +++++++ 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 191ad2da21f..9f9435fcdc2 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -8167,7 +8167,7 @@ function dol_getIdFromCode($db, $key, $tablename, $fieldkey = 'code', $fieldid = * Verify if condition in string is ok or not * * @param string $strToEvaluate String with condition to check - * @return boolean True or False. Note: It returns also True if $strToEvaluate is '' + * @return boolean True or False. Note: It returns also True if $strToEvaluate is '' or if error */ function verifCond($strToEvaluate) { @@ -8180,8 +8180,10 @@ function verifCond($strToEvaluate) if (isset($strToEvaluate) && $strToEvaluate !== '') { $str = 'if(!('.$strToEvaluate.')) $rights = false;'; dol_eval($str, 0, 1, '2'); // The dol_eval must contains all the global $xxx used into a condition - //$rep = dol_eval($strToEvaluate, 1, 1 , '1'); // The dol_eval must contains all the global $xxx used into a condition + //var_dump($strToEvaluate); + //$rep = dol_eval($strToEvaluate, 1, 1 , '2'); // The dol_eval must contains all the global $xxx used into a condition //$rights = ($rep ? true : false); + //var_dump($rights); } return $rights; } @@ -8193,7 +8195,7 @@ function verifCond($strToEvaluate) * @param string $s String to evaluate * @param int $returnvalue 0=No return (used to execute eval($a=something)). 1=Value of eval is returned (used to eval($something)). * @param int $hideerrors 1=Hide errors - * @param string $onlysimplestring 0=Accept all chars, 1=Accept only simple string with char 'a-z0-9\s$_->&|=';, 2=Accept also '!?():";' + * @param string $onlysimplestring 0=Accept all chars, 1=Accept only simple string with char 'a-z0-9\s$_->&|=';, 2=Accept also '!?():"\';,/' * @return mixed Nothing or return result of eval */ function dol_eval($s, $returnvalue = 0, $hideerrors = 1, $onlysimplestring = '1') @@ -8221,7 +8223,7 @@ function dol_eval($s, $returnvalue = 0, $hideerrors = 1, $onlysimplestring = '1' } } elseif ($onlysimplestring == '2') { //print preg_quote('$_->&|', '/'); - if (preg_match('/[^a-z0-9\s'.preg_quote('$_->&|=!?():";', '/').']/i', $s)) { + if (preg_match('/[^a-z0-9\s'.preg_quote('^$_->&|=!?():"\';,/', '/').']/i', $s)) { if ($returnvalue) { return 'Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s; } else { @@ -8231,10 +8233,20 @@ function dol_eval($s, $returnvalue = 0, $hideerrors = 1, $onlysimplestring = '1' } } if (strpos($s, '`') !== false) { - return 'Bad string syntax to evaluate (backtick char is forbidden): '.$s; + if ($returnvalue) { + return 'Bad string syntax to evaluate (backtick char is forbidden): '.$s; + } else { + dol_syslog('Bad string syntax to evaluate (backtick char is forbidden): '.$s); + return ''; + } } if (strpos($s, '.') !== false) { - return 'Bad string syntax to evaluate (dot char is forbidden): '.$s; + if ($returnvalue) { + return 'Bad string syntax to evaluate (dot char is forbidden): '.$s; + } else { + dol_syslog('Bad string syntax to evaluate (dot char is forbidden): '.$s); + return ''; + } } // We block use of php exec or php file functions @@ -8256,7 +8268,12 @@ function dol_eval($s, $returnvalue = 0, $hideerrors = 1, $onlysimplestring = '1' if (strpos($s, '__forbiddenstring__') !== false) { dol_syslog('Bad string syntax to evaluate: '.$s, LOG_WARNING); - return 'Bad string syntax to evaluate: '.$s; + if ($returnvalue) { + return 'Bad string syntax to evaluate: '.$s; + } else { + dol_syslog('Bad string syntax to evaluate: '.$s); + return ''; + } } //print $s."
    \n"; diff --git a/htdocs/core/modules/modBarcode.class.php b/htdocs/core/modules/modBarcode.class.php index 877dca880f7..ced58f9b6c4 100644 --- a/htdocs/core/modules/modBarcode.class.php +++ b/htdocs/core/modules/modBarcode.class.php @@ -33,7 +33,6 @@ include_once DOL_DOCUMENT_ROOT.'/core/modules/DolibarrModules.class.php'; */ class modBarcode extends DolibarrModules { - /** * Constructor. Define names, constants, directories, boxes, permissions * @@ -94,6 +93,7 @@ class modBarcode extends DolibarrModules // Main menu entries $r = 0; + // A menu entry for the Tools top menu $this->menu[$r] = array( 'fk_menu'=>'fk_mainmenu=tools', // Use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode 'mainmenu'=>'tools', @@ -111,6 +111,7 @@ class modBarcode extends DolibarrModules ); $r++; + // A menu entry for the left menu $this->menu[$r] = array( 'fk_menu'=>'fk_mainmenu=home,fk_leftmenu=admintools', // Use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode 'type'=>'left', // This is a Left menu entry diff --git a/test/phpunit/SecurityTest.php b/test/phpunit/SecurityTest.php index b96887b6152..e9a19dd576a 100644 --- a/test/phpunit/SecurityTest.php +++ b/test/phpunit/SecurityTest.php @@ -914,7 +914,16 @@ class SecurityTest extends PHPUnit\Framework\TestCase print "result = ".$result."\n"; $this->assertContains('Bad string syntax to evaluate', $result); + global $leftmenu; + $leftmenu = 'admintools'; + $conf->barcode->enabled = 1; + $result=dol_eval('$conf->barcode->enabled && preg_match(\'/^(admintools|all)/\',$leftmenu)', 1, 0, '2'); + print "result = ".$result."\n"; + $this->assertTrue($result); + + // Case with param onlysimplestring = 1 + $result=dol_eval('1 && getDolGlobalInt("doesnotexist1") && $conf->global->MAIN_FEATURES_LEVEL', 1, 0); // Should return false and not a 'Bad string syntax to evaluate ...' print "result = ".$result."\n"; $this->assertFalse($result); From cdf603a7b39c082d32b84900eb0d7e0d986e8c51 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 3 Mar 2022 02:02:04 +0100 Subject: [PATCH 248/255] Prepare v16 --- ChangeLog | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/ChangeLog b/ChangeLog index a9a42c8d878..08d445cdfc7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,32 @@ English Dolibarr ChangeLog -------------------------------------------------------------- +***** ChangeLog for 16.0.0 compared to 15.0.0 ***** + +For users: +--------------- + +NEW: ... + + + Modules +NEW: Experimental module Event Organization Management +NEW: Experimental module Workstations Management +NEW: Experimental module Partnership Management + + +For developers: +--------------- + +NEW: + +Following changes may create regressions for some external modules, but were necessary to make Dolibarr better: +* verifCond('stringtoevaluate') now return false when string contains a bad syntax content instead of true. + + + + + ***** ChangeLog for 15.0.0 compared to 14.0.0 ***** For users: From 88944656be2b220a225c8d1170bc76e9abaa6eb7 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 3 Mar 2022 02:05:13 +0100 Subject: [PATCH 249/255] Doc --- htdocs/core/lib/functions.lib.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index bc07728080f..d8595c15bbf 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -8311,7 +8311,7 @@ function verifCond($strToEvaluate) //$str = 'if(!('.$strToEvaluate.')) $rights = false;'; //dol_eval($str, 0, 1, '2'); // The dol_eval must contains all the global $xxx used into a condition //var_dump($strToEvaluate); - $rep = dol_eval($strToEvaluate, 1, 1, '1'); // The dol_eval must contains all the global $xxx used into a condition + $rep = dol_eval($strToEvaluate, 1, 1, '1'); // The dol_eval must contains all the global $xxx for all variables $xxx found into the string condition $rights = (($rep && strpos($rep, 'Bad string syntax to evaluate') === false) ? true : false); //var_dump($rights); } From 246474b39b06a306ccdb46d48d40daf399492c51 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 3 Mar 2022 02:15:52 +0100 Subject: [PATCH 250/255] Fix phpunit --- test/phpunit/SecurityTest.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/phpunit/SecurityTest.php b/test/phpunit/SecurityTest.php index e9a19dd576a..ccbb0b38ded 100644 --- a/test/phpunit/SecurityTest.php +++ b/test/phpunit/SecurityTest.php @@ -916,8 +916,7 @@ class SecurityTest extends PHPUnit\Framework\TestCase global $leftmenu; $leftmenu = 'admintools'; - $conf->barcode->enabled = 1; - $result=dol_eval('$conf->barcode->enabled && preg_match(\'/^(admintools|all)/\',$leftmenu)', 1, 0, '2'); + $result=dol_eval('$conf->currency && preg_match(\'/^(admintools|all)/\',$leftmenu)', 1, 0, '2'); print "result = ".$result."\n"; $this->assertTrue($result); From 2837c938e6c358022782aac90e9c93a17eb251b7 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 3 Mar 2022 09:41:15 +0100 Subject: [PATCH 251/255] Fix help easier to understand to avoid lethal situations. Fix reponsive --- htdocs/accountancy/bookkeeping/list.php | 52 +++++++++++++++---------- htdocs/core/class/html.form.class.php | 2 + htdocs/langs/en_US/accountancy.lang | 13 ++++--- htdocs/theme/eldy/global.inc.php | 4 ++ 4 files changed, 44 insertions(+), 27 deletions(-) diff --git a/htdocs/accountancy/bookkeeping/list.php b/htdocs/accountancy/bookkeeping/list.php index d110f74a6a6..d6236af5d02 100644 --- a/htdocs/accountancy/bookkeeping/list.php +++ b/htdocs/accountancy/bookkeeping/list.php @@ -190,7 +190,7 @@ $arrayfields = array( 't.date_creation'=>array('label'=>$langs->trans("DateCreation"), 'checked'=>0), 't.tms'=>array('label'=>$langs->trans("DateModification"), 'checked'=>0), 't.date_export'=>array('label'=>$langs->trans("DateExport"), 'checked'=>1), - 't.date_validated'=>array('label'=>$langs->trans("DateValidation"), 'checked'=>1), + 't.date_validated'=>array('label'=>$langs->trans("DateValidationAndLock"), 'checked'=>1), ); if (empty($conf->global->ACCOUNTING_ENABLE_LETTERING)) { @@ -678,19 +678,28 @@ $formconfirm = ''; if ($action == 'export_file') { $form_question = array(); + // If 1 or not set, we check by default. + $checked = (!isset($conf->global->ACCOUNTING_DEFAULT_NOT_NOTIFIED_EXPORT_DATE) || !empty($conf->global->ACCOUNTING_DEFAULT_NOT_NOTIFIED_EXPORT_DATE)); $form_question['notifiedexportdate'] = array( 'name' => 'notifiedexportdate', 'type' => 'checkbox', 'label' => $langs->trans('NotifiedExportDate'), - 'value' => (empty($conf->global->ACCOUNTING_DEFAULT_NOTIFIED_EXPORT_DATE) ? false : true), + 'value' => $checked, ); + + $form_question['separator'] = array('name'=>'separator', 'type'=>'separator'); + + // If 0 or not set, we NOT check by default. + $checked = (isset($conf->global->ACCOUNTING_DEFAULT_NOT_NOTIFIED_VALIDATION_DATE) || !empty($conf->global->ACCOUNTING_DEFAULT_NOT_NOTIFIED_VALIDATION_DATE)); $form_question['notifiedvalidationdate'] = array( 'name' => 'notifiedvalidationdate', 'type' => 'checkbox', 'label' => $langs->trans('NotifiedValidationDate'), - 'value' => (empty($conf->global->ACCOUNTING_DEFAULT_NOTIFIED_VALIDATION_DATE) ? false : true), + 'value' => $checked, ); + $form_question['separator2'] = array('name'=>'separator2', 'type'=>'separator'); + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?'.$param, $langs->trans("ExportFilteredList").' ('.$listofformat[$formatexportset].')', $langs->trans('ConfirmExportFile'), 'export_fileconfirm', $form_question, '', 1, 300, 600); } @@ -823,7 +832,7 @@ if (!empty($arrayfields['t.piece_num']['checked'])) { // Code journal if (!empty($arrayfields['t.code_journal']['checked'])) { print '
    '; } // Date document @@ -845,10 +854,10 @@ if (!empty($arrayfields['t.doc_ref']['checked'])) { if (!empty($arrayfields['t.numero_compte']['checked'])) { print ''; } @@ -1125,24 +1134,25 @@ while ($i < min($num, $limit)) { // Other type } - print '\n"; if (!$i) { $totalarray['nbfield']++; @@ -1167,7 +1177,7 @@ while ($i < min($num, $limit)) { // Label operation if (!empty($arrayfields['t.label_operation']['checked'])) { - print ''; + print ''; if (!$i) { $totalarray['nbfield']++; } @@ -1228,7 +1238,7 @@ while ($i < min($num, $limit)) { // Exported operation date if (!empty($arrayfields['t.date_export']['checked'])) { - print ''; + print ''; if (!$i) { $totalarray['nbfield']++; } @@ -1236,7 +1246,7 @@ while ($i < min($num, $limit)) { // Validated operation date if (!empty($arrayfields['t.date_validated']['checked'])) { - print ''; + print ''; if (!$i) { $totalarray['nbfield']++; } diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 87d3d63cec1..ed73218c609 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -4863,6 +4863,8 @@ class Form $moreonecolumn .= ''."\n"; } elseif ($input['type'] == 'hidden') { // Do nothing more, already added by a previous loop + } elseif ($input['type'] == 'separator') { + $more .= '
    '; } else { $more .= 'Error type '.$input['type'].' for the confirm box is not a supported type'; } diff --git a/htdocs/langs/en_US/accountancy.lang b/htdocs/langs/en_US/accountancy.lang index 6f9d74de7c8..fd5ff8461fe 100644 --- a/htdocs/langs/en_US/accountancy.lang +++ b/htdocs/langs/en_US/accountancy.lang @@ -219,12 +219,12 @@ ByPredefinedAccountGroups=By predefined groups ByPersonalizedAccountGroups=By personalized groups ByYear=By year NotMatch=Not Set -DeleteMvt=Delete some operation lines from accounting +DeleteMvt=Delete some lines from accounting DelMonth=Month to delete DelYear=Year to delete DelJournal=Journal to delete -ConfirmDeleteMvt=This will delete all operation lines of the accounting for the year/month and/or for a specific journal (At least one criterion is required). You will have to reuse the feature '%s' to have the deleted record back in the ledger. -ConfirmDeleteMvtPartial=This will delete the transaction from the accounting (all operation lines related to the same transaction will be deleted) +ConfirmDeleteMvt=This will delete all lines in accountancy for the year/month and/or for a specific journal (At least one criterion is required). You will have to reuse the feature '%s' to have the deleted record back in the ledger. +ConfirmDeleteMvtPartial=This will delete the transaction from the accounting (all lines related to the same transaction will be deleted) FinanceJournal=Finance journal ExpenseReportsJournal=Expense reports journal DescFinanceJournal=Finance journal including all the types of payments by bank account @@ -301,7 +301,7 @@ Accounted=Accounted in ledger NotYetAccounted=Not yet transferred to accounting ShowTutorial=Show Tutorial NotReconciled=Not reconciled -WarningRecordWithoutSubledgerAreExcluded=Warning, all operations without subledger account defined are filtered and excluded from this view +WarningRecordWithoutSubledgerAreExcluded=Warning, all lines without subledger account defined are filtered and excluded from this view ## Admin BindingOptions=Binding options @@ -329,8 +329,9 @@ ACCOUNTING_DISABLE_BINDING_ON_PURCHASES=Disable binding & transfer in accountanc ACCOUNTING_DISABLE_BINDING_ON_EXPENSEREPORTS=Disable binding & transfer in accountancy on expense reports (expense reports will not be taken into account in accounting) ## Export -NotifiedExportDate=Flag exported lines as exported (modification of the lines will not be possible) -NotifiedValidationDate=Validate the exported entries (modification or deletion of the lines will not be possible) +NotifiedExportDate=Flag exported lines as Exported (to modify a line, you will need to delete the whole transaction and re-transfert it into accounting) +NotifiedValidationDate=Validate and Lock the exported entries (same effect than the "Closure" feature, modification and deletion of the lines will DEFINITELY not be possible) +DateValidationAndLock=Date validation and lock ConfirmExportFile=Confirmation of the generation of the accounting export file ? ExportDraftJournal=Export draft journal Modelcsv=Model of export diff --git a/htdocs/theme/eldy/global.inc.php b/htdocs/theme/eldy/global.inc.php index b88cecda187..a4020edccdb 100644 --- a/htdocs/theme/eldy/global.inc.php +++ b/htdocs/theme/eldy/global.inc.php @@ -6204,6 +6204,10 @@ span#select2-boxbookmark-container { overflow: hidden; } +ul.select2-results__options li { + font-size: 0.95em; +} + /* ============================================================================== */ /* For categories */ From 8655592aea6b21149488ef74205d0a16e9d351d0 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 3 Mar 2022 09:51:12 +0100 Subject: [PATCH 252/255] Fix bad merge --- test/phpunit/SecurityTest.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/phpunit/SecurityTest.php b/test/phpunit/SecurityTest.php index 3782bf9de85..eabfe389174 100644 --- a/test/phpunit/SecurityTest.php +++ b/test/phpunit/SecurityTest.php @@ -917,15 +917,13 @@ class SecurityTest extends PHPUnit\Framework\TestCase global $leftmenu; // Used into strings to eval $leftmenu = 'AAA'; - $conf->barcode->enabled = 1; $result=dol_eval('$conf->currency && preg_match(\'/^(AAA|BBB)/\',$leftmenu)', 1, 1, '1'); print "result = ".$result."\n"; $this->assertTrue($result); // Same with syntax error $leftmenu = 'XXX'; - $conf->barcode->enabled = 1; - $result=dol_eval('$conf->barcode->enabled && preg_match(\'/^(AAA|BBB)/\',$leftmenu)', 1, 1, '1'); + $result=dol_eval('$conf->currency && preg_match(\'/^(AAA|BBB)/\',$leftmenu)', 1, 1, '1'); print "result = ".$result."\n"; $this->assertFalse($result); From 82e2f8706a3a30df08bacd684191e6e413c1c7f9 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 4 Mar 2022 11:22:08 +0100 Subject: [PATCH 253/255] Doc --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index a9a42c8d878..a65a8f21329 100644 --- a/ChangeLog +++ b/ChangeLog @@ -10,6 +10,7 @@ For users: NEW: Online proposal signature NEW: Can define some max limit on expense report (per period, per type or expense, ...) +NEW: Provide a special pages for bookmarks and multicompany for a better use of some mobile applications (like DoliDroid) NEW: Allow the use of __NEWREF__ to get for example the new reference a draft order will get after validation. NEW: Add option to disable globaly some notifications emails. NEW: #18401 Add __NEWREF__ subtitute to get new object reference. From 444abbbc0e85cc5b318f57578f0715aa656a07e1 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 4 Mar 2022 16:44:33 +0100 Subject: [PATCH 254/255] Fix regression --- htdocs/fourn/class/fournisseur.commande.class.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/htdocs/fourn/class/fournisseur.commande.class.php b/htdocs/fourn/class/fournisseur.commande.class.php index 614130097c5..528bda30442 100644 --- a/htdocs/fourn/class/fournisseur.commande.class.php +++ b/htdocs/fourn/class/fournisseur.commande.class.php @@ -470,15 +470,15 @@ class CommandeFournisseur extends CommonOrder $sql .= " FROM ".MAIN_DB_PREFIX."commande_fournisseurdet as l"; $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON l.fk_product = p.rowid'; if (!empty($conf->global->PRODUCT_USE_SUPPLIER_PACKAGING)) { - $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_fournisseur_price as pfp ON pfp.entity IN (".getEntity('product_fournisseur_price').") AND l.fk_product = pfp.fk_product and l.ref = pfp.ref_fourn AND pfp.fk_soc = ".((int) $this->socid); + $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_fournisseur_price as pfp ON pfp.entity IN (".getEntity('product_fournisseur_price').") AND l.fk_product = pfp.fk_product and l.ref = pfp.ref_fourn AND l.qty >= pfp.quantity AND pfp.fk_soc = ".((int) $this->socid); } $sql .= " WHERE l.fk_commande = ".$this->id; if ($only_product) { $sql .= ' AND p.fk_product_type = 0'; } if (!empty($conf->global->PRODUCT_USE_SUPPLIER_PACKAGING)) { - $sql.= " AND l.qty >= pfp.quantity "; - $sql.= " GROUP BY l.rowid HAVING max_qty = MAX(pfp.quantity) "; + $sql.= " GROUP BY l.rowid"; + $sql.= " HAVING (max_qty = MAX(pfp.quantity) OR max_qty IS NULL)"; } $sql .= " ORDER BY l.rang, l.rowid"; //print $sql; @@ -3528,11 +3528,11 @@ class CommandeFournisseurLigne extends CommonOrderLine $sql .= ' FROM '.MAIN_DB_PREFIX.'commande_fournisseurdet as cd'; $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON cd.fk_product = p.rowid'; if (!empty($conf->global->PRODUCT_USE_SUPPLIER_PACKAGING)) { - $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_fournisseur_price as pfp ON pfp.entity IN (".getEntity('product_fournisseur_price').") AND cd.fk_product = pfp.fk_product and cd.ref = pfp.ref_fourn"; + $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_fournisseur_price as pfp ON pfp.entity IN (".getEntity('product_fournisseur_price').") AND cd.fk_product = pfp.fk_product and cd.ref = pfp.ref_fourn AND cd.qty >= pfp.quantity"; } $sql .= ' WHERE cd.rowid = '.((int) $rowid); if (!empty($conf->global->PRODUCT_USE_SUPPLIER_PACKAGING)) { - $sql .= " AND cd.qty >= pfp.quantity GROUP BY cd.rowid HAVING max_qty = MAX(pfp.quantity)"; + $sql .= " GROUP BY cd.rowid HAVING (max_qty = MAX(pfp.quantity) OR max_qty IS NULL)"; } $result = $this->db->query($sql); if ($result) { From 792dcc63349c88761a71590f490990e65c779235 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 4 Mar 2022 19:14:57 +0100 Subject: [PATCH 255/255] FIX creation of the shipment if order contains services - 2/2 --- htdocs/expedition/card.php | 1 + 1 file changed, 1 insertion(+) diff --git a/htdocs/expedition/card.php b/htdocs/expedition/card.php index 743930767dd..4bec4220c6c 100644 --- a/htdocs/expedition/card.php +++ b/htdocs/expedition/card.php @@ -1194,6 +1194,7 @@ if ($action == 'create') { print ''; } else { if (! empty($conf->global->SHIPMENT_GETS_ALL_ORDER_PRODUCTS)) { + print ''; print ''; }
    '.$langs->trans("BookmarkTitle").''.$langs->trans("SetHereATitleForLink").'
    '.$langs->trans("BookmarkTitle").''.$langs->trans("SetHereATitleForLink").'
    '; if ($action == 'edit') { - print 'title).'">'; + print 'title).'">'; } else { - print $object->title; + print dol_escape_htmltag($object->title); } print '
    '; - print $formaccounting->multi_select_journal($search_ledger_code, 'search_ledger_code', 0, 1, 1, 1, 'maxwidth150'); + print $formaccounting->multi_select_journal($search_ledger_code, 'search_ledger_code', 0, 1, 1, 1, 'small maxwidth150'); print ''; print '
    '; - print $formaccounting->select_account($search_accountancy_code_start, 'search_accountancy_code_start', $langs->trans('From'), array(), 1, 1, 'maxwidth200', 'account'); + print $formaccounting->select_account($search_accountancy_code_start, 'search_accountancy_code_start', $langs->trans('From'), array(), 1, 1, 'maxwidth150', 'account'); print '
    '; print '
    '; - print $formaccounting->select_account($search_accountancy_code_end, 'search_accountancy_code_end', $langs->trans('to'), array(), 1, 1, 'maxwidth200', 'account'); + print $formaccounting->select_account($search_accountancy_code_end, 'search_accountancy_code_end', $langs->trans('to'), array(), 1, 1, 'maxwidth150', 'account'); print '
    '; print '
    '; - - print ''; - // Picto + Ref - print '
    '; - + $labeltoshow = ''; + $labeltoshowalt = ''; if ($line->doc_type == 'customer_invoice' || $line->doc_type == 'supplier_invoice' || $line->doc_type == 'expense_report') { - print $objectstatic->getNomUrl(1, '', 0, 0, '', 0, -1, 1); - print $documentlink; + $labeltoshow .= $objectstatic->getNomUrl(1, '', 0, 0, '', 0, -1, 1); + $labeltoshow .= $documentlink; + $labeltoshowalt .= $objectstatic->ref; } elseif ($line->doc_type == 'bank') { - print $objectstatic->getNomUrl(1); + $labeltoshow .= $objectstatic->getNomUrl(1); + $labeltoshowalt .= $objectstatic->ref; $bank_ref = strstr($line->doc_ref, '-'); - print " " . $bank_ref; + $labeltoshow .= " " . $bank_ref; + $labeltoshowalt .= " " . $bank_ref; } else { - print $line->doc_ref; + $labeltoshow .= $line->doc_ref; + $labeltoshowalt .= $line->doc_ref; } - print '
    '; + print '
    '; + print $labeltoshow; print "'.$line->label_operation.''.dol_escape_htmltag($line->label_operation).''.dol_print_date($line->date_export, 'dayhour').''.dol_print_date($line->date_export, 'dayhour').''.dol_print_date($line->date_validation, 'dayhour').''.dol_print_date($line->date_validation, 'dayhour').'