diff --git a/ChangeLog.md b/ChangeLog.md index 0a710e3..8fb4cd6 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file. ## Release 1.4 +- FIX : Compat V23 - **11/12/2025** - 1.4.5 - FIX : Frequency on multiclone- **17/11/2025** - 1.4.4 - FIX : Compat V22 - **02/10/2025** - 1.4.3 - FIX : Fatal Unsupported operand type string instead of int - **26/02/2025** - 1.4.2 diff --git a/admin/multiclone_about.php b/admin/multiclone_about.php index 7a84499..ea5b030 100644 --- a/admin/multiclone_about.php +++ b/admin/multiclone_about.php @@ -23,9 +23,9 @@ * Put some comments here */ // Dolibarr environment -$res = @include("../../main.inc.php"); // From htdocs directory +$res = @include "../../main.inc.php"; // From htdocs directory if (! $res) { - $res = @include("../../../main.inc.php"); // From "custom" directory + $res = @include "../../../main.inc.php"; // From "custom" directory } // Libraries @@ -37,7 +37,7 @@ // Access control if (! $user->admin) { - accessforbidden(); + accessforbidden(); } /* @@ -48,17 +48,17 @@ // Subheader $linkback = '' - . $langs->trans("BackToModuleList") . ''; + . $langs->trans("BackToModuleList") . ''; print_fiche_titre($langs->trans($page_name), $linkback); // Configuration header $head = multicloneAdminPrepareHead(); dol_fiche_head( - $head, - 'about', - $langs->trans("Module104968Name"), - 0, - 'multiclone@multiclone' + $head, + 'about', + $langs->trans("Module104968Name"), + 0, + 'multiclone@multiclone' ); // About page goes here @@ -73,4 +73,4 @@ llxFooter(); -$db->close(); \ No newline at end of file +$db->close(); diff --git a/admin/multiclone_setup.php b/admin/multiclone_setup.php index 9ed22d5..93c4c53 100644 --- a/admin/multiclone_setup.php +++ b/admin/multiclone_setup.php @@ -1,6 +1,6 @@ - * Copyright (C) 2021 ATM Consulting +/* + * Copyright (C) 2015 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 @@ -13,276 +13,147 @@ * 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 . + * along with this program. If not, see . */ /** - * \file multiclone/admin/setup.php - * \ingroup multiclone - * \brief Multiclone setup page. + * \file admin/multiclone_setup.php + * \ingroup multiclone + * \brief This file is an example module setup page + * Put some comments here */ - -// 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--; +// Dolibarr environment +$res = @include "../../main.inc.php"; // From htdocs directory +if (! $res) { + $res = @include "../../../main.inc.php"; // From "custom" directory } -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"); - -global $langs, $user, $conf; -$inputCount = 1; // Libraries -require_once DOL_DOCUMENT_ROOT."/core/lib/admin.lib.php"; +require_once DOL_DOCUMENT_ROOT . "/core/lib/admin.lib.php"; require_once '../lib/multiclone.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php'; // Translations -$langs->loadLangs(array("multiclone@multiclone", "bills", "propal", "orders", "salaries", "compta", "admin")); +$langs->load("multiclone@multiclone"); // Access control -if(! $user->admin) accessforbidden(); +if (! $user->admin) { + accessforbidden(); +} // Parameters -$action = GETPOST('action', 'alpha'); +$action = GETPOST('action', 'aZ09'); $backtopage = GETPOST('backtopage', 'alpha'); +$modulepart = GETPOST('modulepart', 'aZ09'); // Used by actions_setmoduleoptions.inc.php $value = GETPOST('value', 'alpha'); +$label = GETPOST('label', 'alpha'); +$scandir = GETPOST('scan_dir', 'alpha'); +$type = 'myobject'; -/* - * Actions - */ - -if((float) DOL_VERSION >= 6) { - include DOL_DOCUMENT_ROOT.'/core/actions_setmoduleoptions.inc.php'; -} - -/* - * View - */ -$page_name = "multicloneSetup"; -llxHeader('', $langs->trans($page_name)); +$error = 0; +$setupnotempty = 0; -// Subheader -$linkback = ''. $langs->trans("BackToModuleList") . ''; +// Set this to 1 to use the factory to manage constants. Warning, the generated module will be compatible with version v15+ only +$useFormSetup = 1; +// Convert arrayofparameter into a formSetup object +if ($useFormSetup) { + require_once DOL_DOCUMENT_ROOT.'/core/class/html.formsetup.class.php'; + $formSetup = new FormSetup($db); -print load_fiche_titre($langs->trans($page_name), $linkback, 'title_setup'); + // Global + $formSetup->newItem('MULTICLONE_VALIDATE_PROPAL')->setAsYesNo(); + $formSetup->newItem('MULTICLONE_VALIDATE_ORDER')->setAsYesNo(); + $formSetup->newItem('MULTICLONE_VALIDATE_INVOICE')->setAsYesNo(); -// Configuration header -$head = multicloneAdminPrepareHead(); -print dol_get_fiche_head($head,'settings', $langs->trans("ModulemulticloneName"), -1,"multiclone@multiclone"); + //INVOICE SITUATION + $formSetup->newItem('AdvancedParameters')->setAsTitle(); -// Setup page goes here -$var = 0; + if (isModEnabled('propal')) { + $formSetup->newItem('MULTICLONE_ACTIVATE_FOR_PROPAL')->setAsYesNo(); + } -print '
'; -print ''; + if (isModEnabled('commande')) { + $formSetup->newItem('MULTICLONE_ACTIVATE_FOR_ORDER')->setAsYesNo(); + } -print ''; + if (isModEnabled('facture')) { + $formSetup->newItem('MULTICLONE_ACTIVATE_FOR_INVOICE')->setAsYesNo(); + } -_setupPrintTitle($langs->trans("Parameters")); + if (isModEnabled('fournisseur')) { + $formSetup->newItem('MULTICLONE_ACTIVATE_FOR_SUPPLIER_INVOICE')->setAsYesNo(); + } -_printOnOff('MULTICLONE_VALIDATE_PROPAL', $langs->trans("ValidatePropalOnClone")); -_printOnOff('MULTICLONE_VALIDATE_ORDER', $langs->trans("ValidateOrderOnClone")); -_printOnOff('MULTICLONE_VALIDATE_INVOICE', $langs->trans("ValidateInvoiceOnClone")); + if (!isModEnabled('tax')) { + $item = $formSetup->newItem('MULTICLONE_ACTIVATE_FOR_TAX')->setAsTitle(); + $item->nameText = $langs->trans('MULTICLONE_ACTIVATE_FOR_TAX'); + $item->fieldOutputOverride = ''.$langs->trans('FeatureRequireModTaxEnabled').''; + } else { + $formSetup->newItem('MULTICLONE_ACTIVATE_FOR_TAX')->setAsYesNo(); + } -_setupPrintTitle($langs->trans("AdvancedParameters")); + if (!isModEnabled('salaries')) { + $item = $formSetup->newItem('MULTICLONE_ACTIVATE_FOR_SALARY')->setAsTitle(); + $item->nameText = $langs->trans('MULTICLONE_ACTIVATE_FOR_SALARY'); + $item->fieldOutputOverride = ''.$langs->trans('FeatureRequireModSalariesEnabled').''; + } else { + $formSetup->newItem('MULTICLONE_ACTIVATE_FOR_SALARY')->setAsYesNo(); + } -if (isModEnabled('propal')) { - _printOnOff('MULTICLONE_ACTIVATE_FOR_PROPAL', $langs->trans("ActivateForObject", $langs->trans('Proposals'))); -} + if (!getDolGlobalInt('MULTICLONE_MAX_AUTHORIZED_CLONE_VALUE')) { + dolibarr_set_const($db, 'MULTICLONE_MAX_AUTHORIZED_CLONE_VALUE', 100, 'int', 0, '', $conf->entity); + } -if (isModEnabled('commande')) { - _printOnOff('MULTICLONE_ACTIVATE_FOR_ORDER', $langs->trans("ActivateForObject", $langs->trans('Orders'))); -} + $formSetup->newItem('MULTICLONE_MAX_AUTHORIZED_CLONE_VALUE')->setAsNumber(1, 100); -if (isModEnabled('facture')) { - _printOnOff('MULTICLONE_ACTIVATE_FOR_INVOICE', $langs->trans("ActivateForObject", $langs->trans('Invoices'))); + $setupnotempty = count($formSetup->items); } -if (isModEnabled('fournisseur')) { - _printOnOff('MULTICLONE_ACTIVATE_FOR_SUPPLIER_INVOICE', $langs->trans("ActivateForObject", $langs->trans('BillsSuppliers'))); -} - -if(!isModEnabled('tax')) { - _printInputFormPart('', $langs->trans("ActivateForObject", $langs->trans('SocialContributions')), '', array(), '', $langs->trans('FeatureRequireModTaxEnabled')); -} else { - _printOnOff('MULTICLONE_ACTIVATE_FOR_TAX', $langs->trans("ActivateForObject", $langs->trans('SocialContributions'))); -} - -if(!isModEnabled('salaries')) { - _printInputFormPart('', $langs->trans("ActivateForObject", $langs->trans('Salaries')), '', array(), '', $langs->trans('FeatureRequireModSalariesEnabled')); -} else { - _printOnOff('MULTICLONE_ACTIVATE_FOR_SALARY', $langs->trans("ActivateForObject", $langs->trans('Salaries'))); -} - - - -if (!getDolGlobalInt('MULTICLONE_MAX_AUTHORIZED_CLONE_VALUE')) { - dolibarr_set_const($db, 'MULTICLONE_MAX_AUTHORIZED_CLONE_VALUE', 100); -} - -$metas = array('type' => 'number', 'min' => 0, 'placeholder' => 100); -_printInputFormPart('MULTICLONE_MAX_AUTHORIZED_CLONE_VALUE', $langs->trans("MaxAuthorizedCloneValue"), '', $metas); - - -print '
'; - -_updateBtn(); - -print '
'; - -llxFooter(); - -$db->close(); - -/** - * Display title - * - * @param string $title - */ -function _setupPrintTitle($title = "", $width = 300) { - global $langs; - print ''; - print ''.$langs->trans($title).''."\n"; - print ''; -} +$dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']); -/** - * Print an update button - * - * @return void +/* + * Actions */ -function _updateBtn() { - global $langs; - print '
'; - print ''; - print '
'; -} -/** - * Print a On/Off button - * - * @param string $confkey the conf key - * @param bool $title Title of conf - * @param string $desc Description - * - * @return void - */ -function _printOnOff($confkey, $title = false, $desc = '') { - global $var, $bc, $langs; - print ''; - print ''.($title ? $title : $langs->trans($confkey)); - if(! empty($desc)) { - print '
'.$langs->trans($desc).''; - } - print ''; - print ' '; - print ''; - print ajax_constantonoff($confkey); - print ''; +if ($action == 'update' && !empty($user->admin)) { + $formSetup->saveConfFromPost(); } -/** - * Print a form part - * - * @param string $confkey the conf key - * @param bool $title Title of conf - * @param string $desc Description of - * @param array $metas html meta - * @param string $type type of input textarea or input - * @param bool $help help description - * - * @return void +/* + * View */ -function _printInputFormPart($confkey, $title = false, $desc = '', $metas = [], $type = 'input', $help = false, $moreHtmlBefore = '', $moreHtmlAfter = '') { - global $var, $bc, $langs, $conf, $db, $inputCount; - $var = ! $var; - _curentInputIndex(true); - $form = new Form($db); - - $defaultMetas = [ - 'name' => _curentInputValue() - ]; - if($type != 'textarea') { - $defaultMetas['type'] = 'text'; - $defaultMetas['value'] = getDolGlobalString($confkey); - } +$form = new Form($db); - $metas = array_merge($defaultMetas, $metas); - $metascompil = ''; - foreach($metas as $key => $values) { - $metascompil .= ' '.$key.'="'.$values.'" '; - } - - print ''; - print ''; - - if(! empty($help)) { - print $form->textwithtooltip(($title ? $title : $langs->trans($confkey)), $langs->trans($help), 2, 1, img_help(1, '')); - } - else { - print $title ? $title : $langs->trans($confkey); - } - - if(! empty($desc)) { - print '
'.$langs->trans($desc).''; - } - - print ''; - print ' '; - print ''; - - print $moreHtmlBefore; - - print _curentParam($confkey); - - print ''; - if($type == 'textarea') { - print ''; - } - else if($type == 'input') { - print ''; - } - else { - print $type; - } - - print $moreHtmlAfter; +$help_url = ''; +$page_name = "multicloneSetup"; +llxHeader('', $langs->trans($page_name), $help_url); - print ''; -} +// Subheader +$linkback = ''.$langs->trans("BackToModuleList").''; -function _curentInputIndex($next = false) { - global $inputCount; +print load_fiche_titre($langs->trans($page_name), $linkback, 'title_setup'); - if(empty($inputCount)) { - $inputCount = 1; - } +// Configuration header +$head = multicloneAdminPrepareHead(); - if($next) { - $inputCount++; - } +print dol_get_fiche_head($head, 'settings', $langs->trans($page_name), -1, "multiclone@multiclone"); - return $inputCount; +if ($action == 'edit') { + print $formSetup->generateOutput(true); + print '
'; +} elseif (!empty($formSetup->items)) { + print $formSetup->generateOutput(); + print '
'; + print ''.$langs->trans("Modify").''; + print '
'; +} else { + print '
'.$langs->trans("NothingToSetup"); } -function _curentParam($confkey) { - return ''; -} +// Page end +print dol_get_fiche_end(); -function _curentInputValue($offset = 0) { - return 'value'.(_curentInputIndex() + $offset); -} +llxFooter(); +$db->close(); diff --git a/class/multiclone.class.php b/class/multiclone.class.php index a519fab..c545cc9 100644 --- a/class/multiclone.class.php +++ b/class/multiclone.class.php @@ -1,7 +1,32 @@ . + */ + +/** + * Class multiclone + */ class multiclone { + /** + * Get confirm form for clone action + * + * @param CommonObject $object Object to clone + * + * @return string HTML form confirm + */ public static function getFormConfirmClone($object) { dol_include_once('/core/class/html.form.class.php'); @@ -9,34 +34,43 @@ public static function getFormConfirmClone($object) $langs->loadLangs(array('multiclone@multiclone', 'salaries')); $form = new Form($db); - $elem = $object->element; - $filter = 's.client IN(1,'.($object->element === 'propal' ? '2,' : '').'3)'; - if (version_compare(DOL_VERSION, '18', '>=')) $filter = '(s.client:IN:1,'.($object->element === 'propal' ? '2,' : '').'3)'; + $elem = $object->element; + $filter = 's.client IN(1,'.($object->element === 'propal' ? '2,' : '').'3)'; + if (version_compare(DOL_VERSION, '18', '>=')) $filter = '(s.client:IN:1,'.($object->element === 'propal' ? '2,' : '').'3)'; - if ($elem == 'salary' || $elem == 'chargesociales'){ - $other_question = array('type' => 'other', 'name' => 'userid', 'label' => $langs->trans("SelectUser"), 'value' => $form->select_dolusers($object->fk_user, 'userid', 1)); - } else { - $other_question = array('type' => 'other', 'name' => 'socid', 'label' => $langs->trans("SelectThirdParty"), 'value' => $form->select_company($object->socid, 'socid', $filter, '', 0, 0, array(), 0, 'minwidth300')); - } - $formquestion = array( - array('type' => 'other', 'name' => 'cloneqty', 'label' => $langs->trans("CloneQty"), 'value' => ''), - array('type' => 'other', 'name' => 'frequency', 'label' => $langs->trans("CloneFrequency"), 'value' => ''), - $other_question - ); + if ($elem == 'salary' || $elem == 'chargesociales') { + $other_question = array('type' => 'other', 'name' => 'userid', 'label' => $langs->trans("SelectUser"), 'value' => $form->select_dolusers($object->fk_user, 'userid', 1)); + } else { + $other_question = array('type' => 'other', 'name' => 'socid', 'label' => $langs->trans("SelectThirdParty"), 'value' => $form->select_company($object->socid, 'socid', $filter, '', 0, 0, array(), 0, 'minwidth300')); + } + $formquestion = array( + array('type' => 'other', 'name' => 'cloneqty', 'label' => $langs->trans("CloneQty"), 'value' => ''), + array('type' => 'other', 'name' => 'frequency', 'label' => $langs->trans("CloneFrequency"), 'value' => ''), + $other_question + ); - $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans("Clone"), $langs->trans("ConfirmClone$elem", $object->ref), 'confirm_multiclone', $formquestion, 'yes', 1); + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans("Clone"), $langs->trans("ConfirmClone$elem", $object->ref), 'confirm_multiclone', $formquestion, 'yes', 1); return $formconfirm; } - static function createFromCloneCustom($socid = 0, $object,$frequency=0) + /** + * Create a single clone with custom options + * + * @param int $socid Thirdparty id + * @param CommonObject $object Object to clone + * @param int $frequency Frequency in month for date shift + * + * @return int New object id or <0 if error + */ + public static function createFromCloneCustom($socid = 0, $object = null, $frequency = 0) { global $user, $hookmanager,$conf; $error = 0; $object->context['createfromclone'] = 'createfromclone'; - $object->context['createfromclonecustom'] = 'createfromclone'; + $object->context['createfromclonecustom'] = 'createfromclone'; $object->db->begin(); @@ -48,12 +82,10 @@ static function createFromCloneCustom($socid = 0, $object,$frequency=0) $objFrom = clone $object; // Change socid if needed - if (!empty($socid) && $socid != $object->socid) - { + if (!empty($socid) && $socid != $object->socid) { $objsoc = new Societe($object->db); - if ($objsoc->fetch($socid) > 0) - { + if ($objsoc->fetch($socid) > 0) { $object->socid = $objsoc->id; $object->cond_reglement_id = (!empty($objsoc->cond_reglement_id) ? $objsoc->cond_reglement_id : 0); $object->mode_reglement_id = (!empty($objsoc->mode_reglement_id) ? $objsoc->mode_reglement_id : 0); @@ -72,8 +104,8 @@ static function createFromCloneCustom($socid = 0, $object,$frequency=0) $object->user_author_id = $user->id; $object->user_valid = ''; $object->date = dol_now(); - if($object->element == 'facture' && ! empty($frequency))$object->date = strtotime("+$frequency month", $objFrom->date); - if($object->element == 'commande')$object->date_commande = dol_now(); + if ($object->element == 'facture' && ! empty($frequency))$object->date = strtotime("+$frequency month", $objFrom->date); + if ($object->element == 'commande')$object->date_commande = dol_now(); $object->date_creation = ''; $object->date_validation = ''; $object->ref_client = ''; @@ -82,8 +114,8 @@ static function createFromCloneCustom($socid = 0, $object,$frequency=0) $result = $object->create($user); $object->add_object_linked($object->element, $objFrom->id); - if($object->element == 'facture' && getDolGlobalInt('MULTICLONE_VALIDATE_INVOICE')) $object->validate($user); - else if(($object->element == 'propal' && getDolGlobalInt('MULTICLONE_VALIDATE_PROPAL')) || ($object->element == 'commande' && getDolGlobalInt('MULTICLONE_VALIDATE_ORDER'))) $object->valid($user); + if ($object->element == 'facture' && getDolGlobalInt('MULTICLONE_VALIDATE_INVOICE')) $object->validate($user); + elseif (($object->element == 'propal' && getDolGlobalInt('MULTICLONE_VALIDATE_PROPAL')) || ($object->element == 'commande' && getDolGlobalInt('MULTICLONE_VALIDATE_ORDER'))) $object->valid($user); if ($result < 0) $error++; @@ -93,288 +125,298 @@ static function createFromCloneCustom($socid = 0, $object,$frequency=0) unset($object->context['createfromclone']); // End - if (!$error) - { + if (!$error) { $object->db->commit(); return $object->id; - } - else - { + } else { $object->db->rollback(); return -1; } } - /** - * @param Object $object - * @param int $qty - * @param int $frequency - * @param int $socid - * @return void - * @throws Exception - */ - static function multiCreateFromClone($object, $qty, $frequency, $socid) + /** + * Create multiple clones from an object + * + * @param CommonObject $object Object to clone + * @param int $qty Number of clones to create + * @param int $frequency Frequency in month between each clone + * @param int $socid Thirdparty or user id (depending on element) + * + * @return void + * @throws Exception + */ + public static function multiCreateFromClone($object, $qty, $frequency, $socid) { - global $db, $langs, $user, $conf; - - $db->begin(); - $compteur = 0; - $error = 0; - $langs->load('multiclone@multiclone'); - - if (getDolGlobalInt('MULTICLONE_MAX_AUTHORIZED_CLONE_VALUE') && $qty > getDolGlobalInt('MULTICLONE_MAX_AUTHORIZED_CLONE_VALUE')) { - setEventMessage($langs->trans('MulticloneMaxAuthorizedValueReached', $qty, getDolGlobalInt('MULTICLONE_MAX_AUTHORIZED_CLONE_VALUE')), 'errors'); - header("Location: ".$_SERVER["PHP_SELF"]."?id=".$object->id); - exit; - } - - // Récupération des dates devant être clonées en fonction de l'objet - $TDatesToClone = self::getDateToClone($object); - - // Contrainte d'unicité sur la référence fournisseur (la référence fournisseur doit être unique si même tiers et même entité) - if ($object->element == 'invoice_supplier') $ref_supplier = $object->ref_supplier; - - while ($compteur<$qty){ - $compteur++; - switch ($object->element) { - case 'propal': - $propal = $object; - $id_clone = $propal->createFromClone($user); - if ($id_clone > 0) { - $propal_clone = new Propal($db); - $res = $propal_clone->fetch($id_clone); - if ($res < 0 ) { - $error++; - break; - } - - $TNewDates = self::calcNewDate($TDatesToClone, $frequency, $compteur); - - $propal_clone->date = $TNewDates[0]; - - //Unset de la date de livraison (la spec ne demande pas que cette date soit prise en compte dans le clone) - $propal_clone->delivery_date = null; - - //On définit le tiers concerné par le/les clones - $propal_clone->socid = $socid; - - if (getDolGlobalInt('MULTICLONE_VALIDATE_PROPAL')) $propal_clone->valid($user); - - $res_update = $propal_clone->update($user); - if ($res_update<0) { - $error++; - break; - } - } else { - $error++; - break; - } - break; - - case 'commande': - $order = $object; - $id_clone = $order->createFromClone($user); - if ($id_clone > 0) { - $order_clone = new Commande($db); - $res = $order_clone->fetch($id_clone); - if ($res < 0 ) { - $error++; - break; - } - - $TNewDates = self::calcNewDate($TDatesToClone, $frequency, $compteur); - - $order_clone->date_commande = $TNewDates[0]; - $order_clone->delivery_date = $TNewDates[1] ?? null; - - //On définit le tiers concerné par le/les clones - $order_clone->socid = $socid; - - if (getDolGlobalInt('MULTICLONE_VALIDATE_ORDER')) $order_clone->valid($user); - - $res_update = $order_clone->update($user); - if ($res_update<0) { - $error++; - break; - } - } else { - $error++; - break; - } - break; - - case 'facture': - $facture = $object; - $id_clone = $facture->createFromClone($user, $object->id); - if ($id_clone > 0) { - $facture_clone = new Facture($db); - $res = $facture_clone->fetch($id_clone); - if ($res < 0 ) { - $error++; - break; - } - - $TNewDates = self::calcNewDate($TDatesToClone, $frequency, $compteur); - - $facture_clone->date = $TNewDates[0]; - $facture_clone->date_lim_reglement = $TNewDates[1]; - - //On définit le tiers concerné par le/les clones - $facture_clone->socid = $socid; - //Conditions et mode de règlement ne sont pas clonés par la fonction CreateFromClone - $facture_clone->cond_reglement_id = $facture->cond_reglement_id; - $facture_clone->mode_reglement_id = $facture->mode_reglement_id; - - if(getDolGlobalInt('MULTICLONE_VALIDATE_INVOICE')) $facture_clone->validate($user); - - $res_update = $facture_clone->update($user); - if ($res_update<0) { - $error++; - break; - } - } else { - $error++; - break; - } - break; - - case 'invoice_supplier': - $supplier_invoice = $object; - $supplier_invoice->ref_supplier = $ref_supplier.'-'.$compteur; - $id_clone = $supplier_invoice->createFromClone($user, $object->id); - - if ($id_clone > 0) { - $supplier_invoice_clone = new FactureFournisseur($db); - $res = $supplier_invoice_clone->fetch($id_clone); - if ($res < 0 ) { - $error++; - break; - } - - $TNewDates = self::calcNewDate($TDatesToClone, $frequency, $compteur); - - $supplier_invoice_clone->date = $TNewDates[0]; - - //On définit le tiers concerné par le/les clones - $supplier_invoice_clone->socid = $socid; - - $res_update = $supplier_invoice_clone->update($user); - if ($res_update<0) { - $error++; - break; - } - } else { - $error++; - break; - } - break; - - case 'salary': - $salary = new Salary($db); - $res = $salary->fetch($object->id); - if ($res < 0 ) { - $error++; - break; - } - - //On vide l'id et la ref (comme le fait l'action confirm_clone du module salary) - //Ces champs seront remplis grâce à la fonction create - $salary->id = $salary->ref = null; - //Nommage des nouveaux salaires en fonction de la quantité demandée - $salary->label = $langs->trans("CopyOf") . ' ' . $object->label . ' (' . $compteur . ')'; - - $TNewDates = self::calcNewDate($TDatesToClone, $frequency, $compteur); - - $salary->datesp = $TNewDates[0]; - $salary->dateep = $TNewDates[1]; - - //On définit le salarié concerné par le/les clones - $salary->fk_user = $socid; - - //On crée le clone - $id_clone = $salary->create($user); - if ($id_clone <= 0) { - $error++; - break; - } - break; - - case 'chargesociales': - $charges = new ChargeSociales($db); - $res = $charges->fetch($object->id); - if ($res < 0 ) { - $error++; - break; - } - - //On vide l'id et la ref (comme le fait l'action confirm_clone du module chargesociales) - //Ces champs seront remplis grâce à la fonction create - $charges->id = $charges->ref = null; - //Nommage des nouvelles charges sociales en fonction de la quantité demandée - $charges->label = $object->label; - - $TNewDates = self::calcNewDate($TDatesToClone, $frequency, $compteur); - - $charges->date_ech = $TNewDates[0]; - $charges->period = $TNewDates[1]; - - //On définit le salarié concerné par le/les clones - $charges->fk_user = $socid; - - //On crée le clone - $id_clone = $charges->create($user); - if ($id_clone <= 0) { - $error++; - break; - } - break; - - default: - break; - } - } - - if ($error>0){ - $db->rollback(); - setEventMessage($langs->trans("ErrorMulticlone", $db->lasterror()), 'errors'); - } else { - $db->commit(); - $db->close(); - - header("Location: ".$_SERVER["PHP_SELF"]."?id=".$id_clone); - exit; - } + global $db, $langs, $user, $conf; + + $db->begin(); + $compteur = 0; + $error = 0; + $langs->load('multiclone@multiclone'); + + if (getDolGlobalInt('MULTICLONE_MAX_AUTHORIZED_CLONE_VALUE') && $qty > getDolGlobalInt('MULTICLONE_MAX_AUTHORIZED_CLONE_VALUE')) { + setEventMessage($langs->trans('MulticloneMaxAuthorizedValueReached', $qty, getDolGlobalInt('MULTICLONE_MAX_AUTHORIZED_CLONE_VALUE')), 'errors'); + header("Location: ".$_SERVER["PHP_SELF"]."?id=".$object->id); + exit; + } + + // Récupération des dates devant être clonées en fonction de l'objet + $TDatesToClone = self::getDateToClone($object); + + // Contrainte d'unicité sur la référence fournisseur (la référence fournisseur doit être unique si même tiers et même entité) + if ($object->element == 'invoice_supplier') $ref_supplier = $object->ref_supplier; + + while ($compteur<$qty) { + $compteur++; + switch ($object->element) { + case 'propal': + $propal = $object; + $id_clone = $propal->createFromClone($user); + if ($id_clone > 0) { + $propal_clone = new Propal($db); + $res = $propal_clone->fetch($id_clone); + if ($res < 0 ) { + $error++; + break; + } + + $TNewDates = self::calcNewDate($TDatesToClone, $frequency, $compteur); + + $propal_clone->date = $TNewDates[0]; + + //Unset de la date de livraison (la spec ne demande pas que cette date soit prise en compte dans le clone) + $propal_clone->delivery_date = null; + + //On définit le tiers concerné par le/les clones + $propal_clone->socid = $socid; + + if (getDolGlobalInt('MULTICLONE_VALIDATE_PROPAL')) $propal_clone->valid($user); + + $res_update = $propal_clone->update($user); + if ($res_update<0) { + $error++; + break; + } + } else { + $error++; + break; + } + break; + + case 'commande': + $order = $object; + $id_clone = $order->createFromClone($user); + if ($id_clone > 0) { + $order_clone = new Commande($db); + $res = $order_clone->fetch($id_clone); + if ($res < 0 ) { + $error++; + break; + } + + $TNewDates = self::calcNewDate($TDatesToClone, $frequency, $compteur); + + $order_clone->date_commande = $TNewDates[0]; + $order_clone->delivery_date = $TNewDates[1] ?? null; + + //On définit le tiers concerné par le/les clones + $order_clone->socid = $socid; + + if (getDolGlobalInt('MULTICLONE_VALIDATE_ORDER')) $order_clone->valid($user); + + $res_update = $order_clone->update($user); + if ($res_update<0) { + $error++; + break; + } + } else { + $error++; + break; + } + break; + + case 'facture': + $facture = $object; + $id_clone = $facture->createFromClone($user, $object->id); + if ($id_clone > 0) { + $facture_clone = new Facture($db); + $res = $facture_clone->fetch($id_clone); + if ($res < 0 ) { + $error++; + break; + } + + $TNewDates = self::calcNewDate($TDatesToClone, $frequency, $compteur); + + $facture_clone->date = $TNewDates[0]; + $facture_clone->date_lim_reglement = $TNewDates[1]; + + //On définit le tiers concerné par le/les clones + $facture_clone->socid = $socid; + //Conditions et mode de règlement ne sont pas clonés par la fonction CreateFromClone + $facture_clone->cond_reglement_id = $facture->cond_reglement_id; + $facture_clone->mode_reglement_id = $facture->mode_reglement_id; + + if (getDolGlobalInt('MULTICLONE_VALIDATE_INVOICE')) $facture_clone->validate($user); + + $res_update = $facture_clone->update($user); + if ($res_update<0) { + $error++; + break; + } + } else { + $error++; + break; + } + break; + + case 'invoice_supplier': + $supplier_invoice = $object; + $supplier_invoice->ref_supplier = $ref_supplier.'-'.$compteur; + $id_clone = $supplier_invoice->createFromClone($user, $object->id); + + if ($id_clone > 0) { + $supplier_invoice_clone = new FactureFournisseur($db); + $res = $supplier_invoice_clone->fetch($id_clone); + if ($res < 0 ) { + $error++; + break; + } + + $TNewDates = self::calcNewDate($TDatesToClone, $frequency, $compteur); + + $supplier_invoice_clone->date = $TNewDates[0]; + + //On définit le tiers concerné par le/les clones + $supplier_invoice_clone->socid = $socid; + + $res_update = $supplier_invoice_clone->update($user); + if ($res_update<0) { + $error++; + break; + } + } else { + $error++; + break; + } + break; + + case 'salary': + $salary = new Salary($db); + $res = $salary->fetch($object->id); + if ($res < 0 ) { + $error++; + break; + } + + //On vide l'id et la ref (comme le fait l'action confirm_clone du module salary) + //Ces champs seront remplis grâce à la fonction create + $salary->id = $salary->ref = null; + //Nommage des nouveaux salaires en fonction de la quantité demandée + $salary->label = $langs->trans("CopyOf") . ' ' . $object->label . ' (' . $compteur . ')'; + + $TNewDates = self::calcNewDate($TDatesToClone, $frequency, $compteur); + + $salary->datesp = $TNewDates[0]; + $salary->dateep = $TNewDates[1]; + + //On définit le salarié concerné par le/les clones + $salary->fk_user = $socid; + + //On crée le clone + $id_clone = $salary->create($user); + if ($id_clone <= 0) { + $error++; + break; + } + break; + + case 'chargesociales': + $charges = new ChargeSociales($db); + $res = $charges->fetch($object->id); + if ($res < 0 ) { + $error++; + break; + } + + //On vide l'id et la ref (comme le fait l'action confirm_clone du module chargesociales) + //Ces champs seront remplis grâce à la fonction create + $charges->id = $charges->ref = null; + //Nommage des nouvelles charges sociales en fonction de la quantité demandée + $charges->label = $object->label; + + $TNewDates = self::calcNewDate($TDatesToClone, $frequency, $compteur); + + $charges->date_ech = $TNewDates[0]; + $charges->period = $TNewDates[1]; + + //On définit le salarié concerné par le/les clones + $charges->fk_user = $socid; + + //On crée le clone + $id_clone = $charges->create($user); + if ($id_clone <= 0) { + $error++; + break; + } + break; + + default: + break; + } + } + + if ($error>0) { + $db->rollback(); + setEventMessage($langs->trans("ErrorMulticlone", $db->lasterror()), 'errors'); + } else { + $db->commit(); + $db->close(); + + header("Location: ".$_SERVER["PHP_SELF"]."?id=".$id_clone); + exit; + } } - static function setFactureDate($objFrom,$object,$frequency) + /** + * Set dates on cloned invoice + * + * @param Facture $objFrom Source invoice + * @param Facture $object Target invoice (clone) + * @param int $frequency Frequency in month + * + * @return void + */ + public static function setFactureDate($objFrom, $object, $frequency) { global $db; $old_date_lim_reglement = $objFrom->date_lim_reglement; - $object->date=strtotime("+$frequency month", $objFrom->date); + $object->date=strtotime("+$frequency month", $objFrom->date); $new_date_lim_reglement = $object->calculate_date_lim_reglement(); if ($new_date_lim_reglement > $old_date_lim_reglement) $object->date_lim_reglement = $new_date_lim_reglement; if ($object->date_lim_reglement < $object->date) $object->date_lim_reglement = $object->date; $sql = 'UPDATE '.MAIN_DB_PREFIX.'facture SET datef="'.$db->idate($object->date).'", date_lim_reglement="'. $db->idate($object->date_lim_reglement).'" WHERE rowid='.$object->id; $resql = $db->query($sql); - } - /** - * @param array $TDatesToClone - * @param int $frequency - * @param int $compteur - * @return array - * @throws Exception - */ - static function calcNewDate($TDatesToClone, $frequency, $compteur) - { - //On calcule les nouvelles dates - if (! empty($TDatesToClone)) { - - $TNewDates = array(); - foreach ($TDatesToClone as $i => $dateToClone) { + /** + * Calculate new dates from original ones + * + * @param array $TDatesToClone Array of timestamps to shift + * @param int $frequency Frequency in month + * @param int $compteur Clone counter (1..N) + * + * @return array Array of new timestamps + * @throws Exception + */ + public static function calcNewDate($TDatesToClone, $frequency, $compteur) + { + //On calcule les nouvelles dates + if (! empty($TDatesToClone)) { + $TNewDates = array(); + foreach ($TDatesToClone as $i => $dateToClone) { if (!empty($dateToClone)) { $object_date_origin[$i] = date('Y-m-d', intval($dateToClone)); $last_day_of_this_month[$i] = date("Y-m-t", intval($dateToClone)); @@ -388,54 +430,56 @@ static function calcNewDate($TDatesToClone, $frequency, $compteur) $TNewDates[] = $object_newdate->getTimestamp(); } - } - } - - return $TNewDates; - } - - /** - * @param Object $object - * @return array - */ - static function getDateToClone($object) - { - $TDatesToClone = array(); - - switch ($object->element) { - case 'propal' : - $TDatesToClone['origin_date'] = $object->date; - break; - - case 'commande': - $TDatesToClone['origin_date'] = $object->date; - $TDatesToClone['origin_delivery_date'] = $object->delivery_date; - break; - - case 'facture' : - $TDatesToClone['origin_date'] = $object->date; - $TDatesToClone['origin_date_lim_reglement'] = $object->date_lim_reglement; - break; - - case 'invoice_supplier': - $TDatesToClone['origin_date'] = $object->date; - break; - - case 'salary' : - $TDatesToClone['origin_datesp'] = $object->datesp; - $TDatesToClone['origin_dateep'] = $object->dateep; - break; - - case 'chargesociales' : - $TDatesToClone['origin_dateech'] = $object->date_ech; - $TDatesToClone['origin_period'] = $object->periode; - break; - - default: - break; - } - - return $TDatesToClone; - } -} + } + } + + return $TNewDates; + } + + /** + * Get dates to be cloned depending on object type + * + * @param CommonObject $object Object to analyze + * + * @return array Array of timestamps to clone + */ + public static function getDateToClone($object) + { + $TDatesToClone = array(); + + switch ($object->element) { + case 'propal' : + $TDatesToClone['origin_date'] = $object->date; + break; + + case 'commande': + $TDatesToClone['origin_date'] = $object->date; + $TDatesToClone['origin_delivery_date'] = $object->delivery_date; + break; + + case 'facture' : + $TDatesToClone['origin_date'] = $object->date; + $TDatesToClone['origin_date_lim_reglement'] = $object->date_lim_reglement; + break; + + case 'invoice_supplier': + $TDatesToClone['origin_date'] = $object->date; + break; + + case 'salary' : + $TDatesToClone['origin_datesp'] = $object->datesp; + $TDatesToClone['origin_dateep'] = $object->dateep; + break; + + case 'chargesociales' : + $TDatesToClone['origin_dateech'] = $object->date_ech; + $TDatesToClone['origin_period'] = $object->periode; + break; + + default: + break; + } + return $TDatesToClone; + } +} diff --git a/config.default.php b/config.default.php index 6f928c0..40c090f 100644 --- a/config.default.php +++ b/config.default.php @@ -1,26 +1,37 @@ . + */ + if (is_file('../main.inc.php'))$dir = '../'; +elseif (is_file('../../../main.inc.php'))$dir = '../../../'; +else $dir = '../../'; - if(!defined('INC_FROM_DOLIBARR') && defined('INC_FROM_CRON_SCRIPT')) { - include($dir."master.inc.php"); - } - elseif(!defined('INC_FROM_DOLIBARR')) { - include($dir."main.inc.php"); - } else { - global $dolibarr_main_db_host, $dolibarr_main_db_name, $dolibarr_main_db_user, $dolibarr_main_db_pass; - } - if(!defined('DB_HOST')) { - define('DB_HOST',$dolibarr_main_db_host); - define('DB_NAME',$dolibarr_main_db_name); - define('DB_USER',$dolibarr_main_db_user); - define('DB_PASS',$dolibarr_main_db_pass); - define('DB_DRIVER',$dolibarr_main_db_type); - } - - +if (!defined('INC_FROM_DOLIBARR') && defined('INC_FROM_CRON_SCRIPT')) { + include $dir."master.inc.php"; +} elseif (!defined('INC_FROM_DOLIBARR')) { + include $dir."main.inc.php"; +} else { + global $dolibarr_main_db_host, $dolibarr_main_db_name, $dolibarr_main_db_user, $dolibarr_main_db_pass; +} +if (!defined('DB_HOST')) { + define('DB_HOST', $dolibarr_main_db_host); + define('DB_NAME', $dolibarr_main_db_name); + define('DB_USER', $dolibarr_main_db_user); + define('DB_PASS', $dolibarr_main_db_pass); + define('DB_DRIVER', $dolibarr_main_db_type); +} diff --git a/config.php b/config.php index 720094e..fe26e23 100644 --- a/config.php +++ b/config.php @@ -1,4 +1,18 @@ . + */ require __DIR__.'/config.default.php'; - diff --git a/core/modules/modmulticlone.class.php b/core/modules/modmulticlone.class.php index f2c77d7..81e5e0d 100644 --- a/core/modules/modmulticlone.class.php +++ b/core/modules/modmulticlone.class.php @@ -38,11 +38,11 @@ class modmulticlone extends DolibarrModules * * @param DoliDB $db Database handler */ - function __construct($db) + public function __construct($db) { - global $langs,$conf; + global $langs,$conf; - $this->db = $db; + $this->db = $db; $this->editor_name = 'ATM Consulting'; $this->editor_url = 'https://www.atm-consulting.fr'; @@ -57,11 +57,11 @@ function __construct($db) // It is used to group modules in module setup page $this->family = "ATM Consulting"; // Module label (no space allowed), used if translation string 'ModuleXXXName' not found (where XXX is value of numeric property 'numero' of module) - $this->name = preg_replace('/^mod/i','',get_class($this)); + $this->name = preg_replace('/^mod/i', '', get_class($this)); // Module description, used if translation string 'ModuleXXXDesc' not found (where XXX is value of numeric property 'numero' of module) $this->description = "Permettre de cloner en spécifiant le nombre de clones et la fréquence en mois"; // Possible values for version are: 'development', 'experimental', 'dolibarr' or version - $this->version = '1.4.4'; + $this->version = '1.4.5'; // Key used in llx_const table to save module status enabled/disabled (where MYMODULE is value of property name of module in uppercase) $this->const_name = 'MAIN_MODULE_'.strtoupper($this->name); // Where to store the module in setup page (0=common,1=interface,2=others,3=very specific) @@ -85,22 +85,22 @@ function __construct($db) // 'barcode' => 0, // Set this to 1 if module has its own barcode directory (core/modules/barcode) // 'models' => 0, // Set this to 1 if module has its own models directory (core/modules/xxx) // 'css' => array('/multiclone/css/multiclone.css.php'), // Set this to relative path of css file if module has its own css file - // 'js' => array('/multiclone/js/multiclone.js'), // Set this to relative path of js file if module must load a js on all pages + // 'js' => array('/multiclone/js/multiclone.js'), // Set this to relative path of js file if module must load a js on all pages // 'hooks' => array('hookcontext1','hookcontext2') // Set here all hooks context managed by module // 'dir' => array('output' => 'othermodulename'), // To force the default directories names // 'workflow' => array('WORKFLOW_MODULE1_YOURACTIONTYPE_MODULE2'=>array('enabled'=>'! empty($conf->module1->enabled) && ! empty($conf->module2->enabled)', 'picto'=>'yourpicto@multiclone')) // Set here all workflow context managed by module // ); $this->module_parts = array( - 'triggers' => 1, - 'hooks' => array( - 'ordercard', - 'invoicecard', - 'propalcard', - 'salarycard', - 'taxcard', - 'invoicesuppliercard' - ) - ); + 'triggers' => 1, + 'hooks' => array( + 'ordercard', + 'invoicecard', + 'propalcard', + 'salarycard', + 'taxcard', + 'invoicesuppliercard' + ) + ); // Data directories to create when module is enabled. // Example: this->dirs = array("/multiclone/temp"); @@ -126,9 +126,9 @@ function __construct($db) $this->const = array(); // Array to add new pages in new tabs - // Example: $this->tabs = array('objecttype:+tabname1:Title1:multiclone@multiclone:$user->rights->multiclone->read:/multiclone/mynewtab1.php?id=__ID__', // To add a new tab identified by code tabname1 - // 'objecttype:+tabname2:Title2:multiclone@multiclone:$user->rights->othermodule->read:/multiclone/mynewtab2.php?id=__ID__', // To add another new tab identified by code tabname2 - // 'objecttype:-tabname:NU:conditiontoremove'); // To remove an existing tab identified by code tabname + // Example: $this->tabs = array('objecttype:+tabname1:Title1:multiclone@multiclone:$user->hasRight('multiclone', 'read'):/multiclone/mynewtab1.php?id=__ID__', // To add a new tab identified by code tabname1 + // 'objecttype:+tabname2:Title2:multiclone@multiclone:$user->hasRight('othermodule', 'read'):/multiclone/mynewtab2.php?id=__ID__', // To add another new tab identified by code tabname2 + // 'objecttype:-tabname:NU:conditiontoremove'); // To remove an existing tab identified by code tabname // where objecttype can be // 'categories_x' to add a tab in category view (replace 'x' by type of category (0=product, 1=supplier, 2=customer, 3=member) // 'contact' to add a tab in contact view @@ -149,34 +149,33 @@ function __construct($db) // 'stock' to add a tab in stock view // 'thirdparty' to add a tab in third party view // 'user' to add a tab in user view - $this->tabs = array(); - - // Dictionaries - if (!isModEnabled('multiclone')) - { - $conf->multiclone=new stdClass(); - $conf->multiclone->enabled=0; - } + $this->tabs = array(); + + // Dictionaries + if (!isModEnabled('multiclone')) { + $conf->multiclone=new stdClass(); + $conf->multiclone->enabled=0; + } $this->dictionaries=array(); - /* Example: - if (! isset($conf->multiclone->enabled)) $conf->multiclone->enabled=0; // This is to avoid warnings - $this->dictionaries=array( - 'langs'=>'multiclone@multiclone', - 'tabname'=>array(MAIN_DB_PREFIX."table1",MAIN_DB_PREFIX."table2",MAIN_DB_PREFIX."table3"), // List of tables we want to see into dictonnary editor - 'tablib'=>array("Table1","Table2","Table3"), // Label of tables - 'tabsql'=>array('SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table1 as f','SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table2 as f','SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table3 as f'), // Request to select fields - 'tabsqlsort'=>array("label ASC","label ASC","label ASC"), // Sort order - 'tabfield'=>array("code,label","code,label","code,label"), // List of fields (result of select to show dictionary) - 'tabfieldvalue'=>array("code,label","code,label","code,label"), // List of fields (list of fields to edit a record) - 'tabfieldinsert'=>array("code,label","code,label","code,label"), // List of fields (list of fields for insert) - 'tabrowid'=>array("rowid","rowid","rowid"), // Name of columns with primary key (try to always name it 'rowid') - 'tabcond'=>array($conf->multiclone->enabled,$conf->multiclone->enabled,$conf->multiclone->enabled) // Condition to show each dictionary - ); - */ - - // Boxes + /* Example: + if (! isset($conf->multiclone->enabled)) $conf->multiclone->enabled=0; // This is to avoid warnings + $this->dictionaries=array( + 'langs'=>'multiclone@multiclone', + 'tabname'=>array(MAIN_DB_PREFIX."table1",MAIN_DB_PREFIX."table2",MAIN_DB_PREFIX."table3"), // List of tables we want to see into dictonnary editor + 'tablib'=>array("Table1","Table2","Table3"), // Label of tables + 'tabsql'=>array('SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table1 as f','SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table2 as f','SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table3 as f'), // Request to select fields + 'tabsqlsort'=>array("label ASC","label ASC","label ASC"), // Sort order + 'tabfield'=>array("code,label","code,label","code,label"), // List of fields (result of select to show dictionary) + 'tabfieldvalue'=>array("code,label","code,label","code,label"), // List of fields (list of fields to edit a record) + 'tabfieldinsert'=>array("code,label","code,label","code,label"), // List of fields (list of fields for insert) + 'tabrowid'=>array("rowid","rowid","rowid"), // Name of columns with primary key (try to always name it 'rowid') + 'tabcond'=>array($conf->multiclone->enabled,$conf->multiclone->enabled,$conf->multiclone->enabled) // Condition to show each dictionary + ); + */ + + // Boxes // Add here list of php file(s) stored in core/boxes that contains class to show a box. - $this->boxes = array(); // List of boxes + $this->boxes = array(); // List of boxes // Example: //$this->boxes=array(array(0=>array('file'=>'myboxa.php','note'=>'','enabledbydefaulton'=>'Home'),1=>array('file'=>'myboxb.php','note'=>''),2=>array('file'=>'myboxc.php','note'=>''));); @@ -189,24 +188,24 @@ function __construct($db) // $this->rights[$r][0] = $this->numero . $r; // Permission id (must not be already used) // $this->rights[$r][1] = 'Permision label'; // Permission label // $this->rights[$r][3] = 1; // Permission by default for new user (0/1) - // $this->rights[$r][4] = 'level1'; // In php code, permission will be checked by test if ($user->rights->permkey->level1->level2) - // $this->rights[$r][5] = 'level2'; // In php code, permission will be checked by test if ($user->rights->permkey->level1->level2) + // $this->rights[$r][4] = 'level1'; // In php code, permission will be checked by test if ($user->hasRight('permkey', 'level1', 'level2')) + // $this->rights[$r][5] = 'level2'; // In php code, permission will be checked by test if ($user->hasRight('permkey', 'level1', 'level2')) // $r++; -/* + /* $this->rights[$r][0] = $this->numero . $r; // Permission id (must not be already used) $this->rights[$r][1] = 'multiclone_read'; // Permission label $this->rights[$r][3] = 1; // Permission by default for new user (0/1) - $this->rights[$r][4] = 'read'; // In php code, permission will be checked by test if ($user->rights->permkey->level1->level2) - $this->rights[$r][5] = ''; // In php code, permission will be checked by test if ($user->rights->permkey->level1->level2) + $this->rights[$r][4] = 'read'; // In php code, permission will be checked by test if ($user->hasRight('permkey', 'level1', 'level2')) + $this->rights[$r][5] = ''; // In php code, permission will be checked by test if ($user->hasRight('permkey', 'level1', 'level2')) $r++; $this->rights[$r][0] = $this->numero . $r; // Permission id (must not be already used) $this->rights[$r][1] = 'multiclone_write'; // Permission label $this->rights[$r][3] = 1; // Permission by default for new user (0/1) - $this->rights[$r][4] = 'write'; // In php code, permission will be checked by test if ($user->rights->permkey->level1->level2) - $this->rights[$r][5] = ''; // In php code, permission will be checked by test if ($user->rights->permkey->level1->level2) + $this->rights[$r][4] = 'write'; // In php code, permission will be checked by test if ($user->hasRight('permkey', 'level1', 'level2')) + $this->rights[$r][5] = ''; // In php code, permission will be checked by test if ($user->hasRight('permkey', 'level1', 'level2')) $r++; -*/ + */ // Main menu entries $this->menu = array(); // List of menus to add @@ -224,7 +223,7 @@ function __construct($db) // 'langs'=>'multiclone@multiclone', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. // 'position'=>100, // 'enabled'=>'$conf->multiclone->enabled', // Define condition to show or hide menu entry. Use '$conf->multiclone->enabled' if entry must be visible if module is enabled. - // 'perms'=>'1', // Use 'perms'=>'$user->rights->multiclone->level1->level2' if you want your menu with a permission rules + // 'perms'=>'1', // Use 'perms'=>'$user->hasRight('multiclone', 'level1', 'level2')' if you want your menu with a permission rules // 'target'=>'', // 'user'=>2); // 0=Menu for internal users, 1=external users, 2=both // $r++; @@ -239,12 +238,12 @@ function __construct($db) // 'langs'=>'multiclone@multiclone', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. // 'position'=>100, // 'enabled'=>'$conf->multiclone->enabled', // Define condition to show or hide menu entry. Use '$conf->multiclone->enabled' if entry must be visible if module is enabled. Use '$leftmenu==\'system\'' to show if leftmenu system is selected. - // 'perms'=>'1', // Use 'perms'=>'$user->rights->multiclone->level1->level2' if you want your menu with a permission rules + // 'perms'=>'1', // Use 'perms'=>'$user->hasRight('multiclone', 'level1', 'level2')' if you want your menu with a permission rules // 'target'=>'', // 'user'=>2); // 0=Menu for internal users, 1=external users, 2=both // $r++; -/* + /* $this->menu[$r]=array( 'fk_menu'=>0, // Put 0 if this is a top menu 'type'=>'top', // This is a Top menu entry @@ -255,7 +254,7 @@ function __construct($db) 'langs'=>'multiclone@multiclone', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. 'position'=>100+$r, 'enabled'=>'$conf->multiclone->enabled', // Define condition to show or hide menu entry. Use '$conf->missionorder->enabled' if entry must be visible if module is enabled. - 'perms'=>'$user->rights->multiclone->read', // Use 'perms'=>'$user->rights->missionorder->level1->level2' if you want your menu with a permission rules + 'perms'=>'$user->hasRight('multiclone', 'read')', // Use 'perms'=>'$user->hasRight('missionorder', 'level1', 'level2')' if you want your menu with a permission rules 'target'=>'', 'user'=>2 ); @@ -271,7 +270,7 @@ function __construct($db) 'langs'=>'multiclone@multiclone', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. 'position'=>100+$r, 'enabled'=>'$conf->multiclone->enabled', // Define condition to show or hide menu entry. Use '$conf->missionorder->enabled' if entry must be visible if module is enabled. - 'perms'=>'$user->rights->multiclone->read', // Use 'perms'=>'$user->rights->missionorder->level1->level2' if you want your menu with a permission rules + 'perms'=>'$user->hasRight('multiclone', 'read')', // Use 'perms'=>'$user->hasRight('missionorder', 'level1', 'level2')' if you want your menu with a permission rules 'target'=>'', 'user'=>2 ); @@ -287,7 +286,7 @@ function __construct($db) 'langs'=>'multiclone@multiclone', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. 'position'=>100+$r, 'enabled'=> '$conf->multiclone->enabled', // Define condition to show or hide menu entry. Use '$conf->missionorder->enabled' if entry must be visible if module is enabled. Use '$leftmenu==\'system\'' to show if leftmenu system is selected. - 'perms'=> '$user->rights->multiclone->write', // Use 'perms'=>'$user->rights->missionorder->level1->level2' if you want your menu with a permission rules + 'perms'=> '$user->hasRight('multiclone', 'write')', // Use 'perms'=>'$user->hasRight('missionorder', 'level1', 'level2')' if you want your menu with a permission rules 'target'=>'', 'user'=>2 ); // 0=Menu for internal users, 1=external users, 2=both @@ -304,12 +303,12 @@ function __construct($db) 'langs'=>'multiclone@multiclone', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. 'position'=>100+$r, 'enabled'=> '$conf->multiclone->enabled', // Define condition to show or hide menu entry. Use '$conf->missionorder->enabled' if entry must be visible if module is enabled. Use '$leftmenu==\'system\'' to show if leftmenu system is selected. - 'perms'=> '$user->rights->multiclone->write', // Use 'perms'=>'$user->rights->missionorder->level1->level2' if you want your menu with a permission rules + 'perms'=> '$user->hasRight('multiclone', 'write')', // Use 'perms'=>'$user->hasRight('missionorder', 'level1', 'level2')' if you want your menu with a permission rules 'target'=>'', 'user'=>2 ); // 0=Menu for internal users, 1=external users, 2=both $r++; -*/ + */ // Exports $r=1; @@ -317,7 +316,7 @@ function __construct($db) // Example: // $this->export_code[$r]=$this->rights_class.'_'.$r; // $this->export_label[$r]='CustomersInvoicesAndInvoiceLines'; // Translation key (used only if key ExportDataset_xxx_z not found) - // $this->export_enabled[$r]='1'; // Condition to show export in list (ie: '$user->id==3'). Set to 1 to always show when module is enabled. + // $this->export_enabled[$r]='1'; // Condition to show export in list (ie: '$user->id==3'). Set to 1 to always show when module is enabled. // $this->export_permission[$r]=array(array("facture","facture","export")); // $this->export_fields_array[$r]=array('s.rowid'=>"IdCompany",'s.nom'=>'CompanyName','s.address'=>'Address','s.zip'=>'Zip','s.town'=>'Town','s.fk_pays'=>'Country','s.phone'=>'Phone','s.siren'=>'ProfId1','s.siret'=>'ProfId2','s.ape'=>'ProfId3','s.idprof4'=>'ProfId4','s.code_compta'=>'CustomerAccountancyCode','s.code_compta_fournisseur'=>'SupplierAccountancyCode','f.rowid'=>"InvoiceId",'f.facnumber'=>"InvoiceRef",'f.datec'=>"InvoiceDateCreation",'f.datef'=>"DateInvoice",'f.total'=>"TotalHT",'f.total_ttc'=>"TotalTTC",'f.tva'=>"TotalVAT",'f.paye'=>"InvoicePaid",'f.fk_statut'=>'InvoiceStatus','f.note'=>"InvoiceNote",'fd.rowid'=>'LineId','fd.description'=>"LineDescription",'fd.price'=>"LineUnitPrice",'fd.tva_tx'=>"LineVATRate",'fd.qty'=>"LineQty",'fd.total_ht'=>"LineTotalHT",'fd.total_tva'=>"LineTotalTVA",'fd.total_ttc'=>"LineTotalTTC",'fd.date_start'=>"DateStart",'fd.date_end'=>"DateEnd",'fd.fk_product'=>'ProductId','p.ref'=>'ProductRef'); // $this->export_entities_array[$r]=array('s.rowid'=>"company",'s.nom'=>'company','s.address'=>'company','s.zip'=>'company','s.town'=>'company','s.fk_pays'=>'company','s.phone'=>'company','s.siren'=>'company','s.siret'=>'company','s.ape'=>'company','s.idprof4'=>'company','s.code_compta'=>'company','s.code_compta_fournisseur'=>'company','f.rowid'=>"invoice",'f.facnumber'=>"invoice",'f.datec'=>"invoice",'f.datef'=>"invoice",'f.total'=>"invoice",'f.total_ttc'=>"invoice",'f.tva'=>"invoice",'f.paye'=>"invoice",'f.fk_statut'=>'invoice','f.note'=>"invoice",'fd.rowid'=>'invoice_line','fd.description'=>"invoice_line",'fd.price'=>"invoice_line",'fd.total_ht'=>"invoice_line",'fd.total_tva'=>"invoice_line",'fd.total_ttc'=>"invoice_line",'fd.tva_tx'=>"invoice_line",'fd.qty'=>"invoice_line",'fd.date_start'=>"invoice_line",'fd.date_end'=>"invoice_line",'fd.fk_product'=>'product','p.ref'=>'product'); @@ -334,14 +333,14 @@ function __construct($db) * The init function add constants, boxes, permissions and menus (defined in constructor) into Dolibarr database. * It also creates data directories * - * @param string $options Options when enabling module ('', 'noboxes') + * @param string $options Options when enabling module ('', 'noboxes') * @return int 1 if OK, 0 if KO */ - function init($options='') + public function init($options = '') { $sql = array(); - define('INC_FROM_DOLIBARR',true); + define('INC_FROM_DOLIBARR', true); dol_include_once('/multiclone/config.php'); dol_include_once('/multiclone/script/create-maj-base.php'); @@ -356,14 +355,13 @@ function init($options='') * Remove from database constants, boxes and permissions from Dolibarr database. * Data directories are not deleted * - * @param string $options Options when enabling module ('', 'noboxes') + * @param string $options Options when enabling module ('', 'noboxes') * @return int 1 if OK, 0 if KO */ - function remove($options='') + public function remove($options = '') { $sql = array(); return $this->_remove($sql, $options); } - } diff --git a/core/triggers/interface_99_modmulticlone_multiclonetrigger.class.php b/core/triggers/interface_99_modmulticlone_multiclonetrigger.class.php index 0878f30..0610344 100644 --- a/core/triggers/interface_99_modmulticlone_multiclonetrigger.class.php +++ b/core/triggers/interface_99_modmulticlone_multiclonetrigger.class.php @@ -55,7 +55,7 @@ public function __construct($db) ."They are provided for tutorial purpose only."; // 'development', 'experimental', 'dolibarr' or version $this->version = 'development'; - $this->picto = 'multiclone@multiclone'; + $this->picto = 'multiclone.png'; } /** @@ -88,43 +88,39 @@ public function getVersion() global $langs; $langs->load("admin"); - if ($this->version == 'development') - { + if ($this->version == 'development') { return $langs->trans("Development"); - } - elseif ($this->version == 'experimental') + } elseif ($this->version == 'experimental') return $langs->trans("Experimental"); elseif ($this->version == 'dolibarr') return DOL_VERSION; elseif ($this->version) return $this->version; - else - { + else { return $langs->trans("Unknown"); } } /** * Function called when a Dolibarrr business event is done. - * All functions "run_trigger" are triggered if file - * is inside directory core/triggers - * - * @param string $action Event action code - * @param Commande|Facture|Propal $object Object - * @param User $user Object user - * @param Translate $langs Object langs - * @param conf $conf Object conf - * @return int <0 if KO, 0 if no triggered ran, >0 if OK - */ - public function run_trigger($action, $object, $user, $langs, $conf) + * All functions "run_trigger" are triggered if file + * is inside directory core/triggers + * + * @param string $action Event action code + * @param Commande|Facture|Propal $object Object + * @param User $user Object user + * @param Translate $langs Object langs + * @param conf $conf Object conf + * @return int <0 if KO, 0 if no triggered ran, >0 if OK + */ + public function runTrigger($action, $object, $user, $langs, $conf) { // Put here code you want to execute when a Dolibarr business events occurs. // Data and type of action are stored into $object and $action // Users - global $user, $db, $conf; + global $user, $db, $conf; return 0; } - } diff --git a/langs/fr_FR/multiclone.lang b/langs/fr_FR/multiclone.lang index 485a38b..298b7c7 100644 --- a/langs/fr_FR/multiclone.lang +++ b/langs/fr_FR/multiclone.lang @@ -64,11 +64,16 @@ WarningNoPaymentDeadlineSet=Attention : la date limite de règlement de la fact #SETUP PAGE BackToModuleList = Retour à la liste des modules AdvancedParameters = Paramètres avancés -ValidatePropalOnClone = Passer au statut "validé" les propositions lors du clonage -ValidateOrderOnClone = Passer au statut "validé" les commandes lors du clonage -ValidateInvoiceOnClone = Passer au statut "validé" les factures lors du clonage -ActivateForObject = Activer Multiclone sur les %s -MaxAuthorizedCloneValue = Valeur maximale de clones autorisée (100 par défaut) +MULTICLONE_VALIDATE_PROPAL = Passer au statut "validé" les propositions lors du clonage +MULTICLONE_VALIDATE_ORDER = Passer au statut "validé" les commandes lors du clonage +MULTICLONE_VALIDATE_INVOICE = Passer au statut "validé" les factures lors du clonage +MULTICLONE_ACTIVATE_FOR_PROPAL = Activer Multiclone sur les propositions commerciales +MULTICLONE_ACTIVATE_FOR_ORDER = Activer Multiclone sur les commandes +MULTICLONE_ACTIVATE_FOR_INVOICE = Activer Multiclone sur les factures +MULTICLONE_ACTIVATE_FOR_SUPPLIER_INVOICE = Activer Multiclone sur les factures fournisseur +MULTICLONE_ACTIVATE_FOR_TAX = Activer Multiclone sur les Charges fiscales ou sociales +MULTICLONE_ACTIVATE_FOR_SALARY = Activer Multiclone sur les Salaires +MULTICLONE_MAX_AUTHORIZED_CLONE_VALUE = Valeur maximale de clones autorisée (100 par défaut) FeatureNotAvailableForThisDolVersion = Fonctionnalité non disponible avec votre version actuelle de Dolibarr.
Nécessite la version 16.0 de Dolibarr. FeatureRequireModSalariesEnabled=Nécessite que le module Salaires soit activé. -FeatureRequireModTaxEnabled=Nécessite que le module Taxes soit activé. \ No newline at end of file +FeatureRequireModTaxEnabled=Nécessite que le module Taxes soit activé. diff --git a/lib/multiclone.lib.php b/lib/multiclone.lib.php index 8f25514..fe8f069 100644 --- a/lib/multiclone.lib.php +++ b/lib/multiclone.lib.php @@ -21,37 +21,38 @@ * \ingroup multiclone * \brief This file is an example module library * Put some comments here + * + * @return array Tab header prepared for admin page */ - function multicloneAdminPrepareHead() { - global $langs, $conf, $object; + global $langs, $conf, $object; - $langs->load("multiclone@multiclone"); + $langs->load("multiclone@multiclone"); - $h = 0; - $head = array(); + $h = 0; + $head = array(); - $head[$h][0] = dol_buildpath("/multiclone/admin/multiclone_setup.php", 1); - $head[$h][1] = $langs->trans("Parameters"); - $head[$h][2] = 'settings'; - $h++; - $head[$h][0] = dol_buildpath("/multiclone/admin/multiclone_about.php", 1); - $head[$h][1] = $langs->trans("About"); - $head[$h][2] = 'about'; - $h++; + $head[$h][0] = dol_buildpath("/multiclone/admin/multiclone_setup.php", 1); + $head[$h][1] = $langs->trans("Parameters"); + $head[$h][2] = 'settings'; + $h++; + $head[$h][0] = dol_buildpath("/multiclone/admin/multiclone_about.php", 1); + $head[$h][1] = $langs->trans("About"); + $head[$h][2] = 'about'; + $h++; - // Show more tabs from modules - // Entries must be declared in modules descriptor with line - //$this->tabs = array( - // 'entity:+tabname:Title:@multiclone:/multiclone/mypage.php?id=__ID__' - //); // to add new tab - //$this->tabs = array( - // 'entity:-tabname:Title:@multiclone:/multiclone/mypage.php?id=__ID__' - //); // to remove a tab - complete_head_from_modules($conf, $langs, $object, $head, $h, 'multiclone'); + // Show more tabs from modules + // Entries must be declared in modules descriptor with line + //$this->tabs = array( + // 'entity:+tabname:Title:@multiclone:/multiclone/mypage.php?id=__ID__' + //); // to add new tab + //$this->tabs = array( + // 'entity:-tabname:Title:@multiclone:/multiclone/mypage.php?id=__ID__' + //); // to remove a tab + complete_head_from_modules($conf, $langs, $object, $head, $h, 'multiclone'); - return $head; + return $head; } /** @@ -62,44 +63,49 @@ function multicloneAdminPrepareHead() */ function multiclone_prepare_head(Tmulticlone $object) { - global $db, $langs, $conf, $user; - $h = 0; - $head = array(); - $head[$h][0] = dol_buildpath('/multiclone/card.php', 1).'?id='.$object->getId(); - $head[$h][1] = $langs->trans("multicloneCard"); - $head[$h][2] = 'card'; - $h++; - + global $db, $langs, $conf, $user; + $h = 0; + $head = array(); + $head[$h][0] = dol_buildpath('/multiclone/card.php', 1).'?id='.$object->getId(); + $head[$h][1] = $langs->trans("multicloneCard"); + $head[$h][2] = 'card'; + $h++; + // Show more tabs from modules - // Entries must be declared in modules descriptor with line - // $this->tabs = array('entity:+tabname:Title:@multiclone:/multiclone/mypage.php?id=__ID__'); to add new tab - // $this->tabs = array('entity:-tabname:Title:@multiclone:/multiclone/mypage.php?id=__ID__'); to remove a tab - complete_head_from_modules($conf,$langs,$object,$head,$h,'multiclone'); - + // Entries must be declared in modules descriptor with line + // $this->tabs = array('entity:+tabname:Title:@multiclone:/multiclone/mypage.php?id=__ID__'); to add new tab + // $this->tabs = array('entity:-tabname:Title:@multiclone:/multiclone/mypage.php?id=__ID__'); to remove a tab + complete_head_from_modules($conf, $langs, $object, $head, $h, 'multiclone'); + return $head; } +/** + * Build confirmation forms for multiclone actions. + * + * @param TPDOdb $PDOdb Database handler + * @param Form $form Dolibarr form helper + * @param CommonObject $object Object concerned by the action + * @param string $action Current action + * + * @return string HTML form confirm + */ function getFormConfirmmulticlone(&$PDOdb, &$form, &$object, $action) { - global $langs,$conf,$user; + global $langs,$conf,$user; - $formconfirm = ''; + $formconfirm = ''; - if ($action == 'validate' && $user->hasRight('multiclone', 'write')) - { - $text = $langs->trans('ConfirmValidatemulticlone', $object->ref); - $formconfirm = $form->formconfirm($_SERVER['PHP_SELF'] . '?id=' . $object->id, $langs->trans('Validatemulticlone'), $text, 'confirm_validate', '', 0, 1); - } - elseif ($action == 'delete' && $user->hasRight('multiclone', 'write')) - { - $text = $langs->trans('ConfirmDeletemulticlone'); - $formconfirm = $form->formconfirm($_SERVER['PHP_SELF'] . '?id=' . $object->id, $langs->trans('Deletemulticlone'), $text, 'confirm_delete', '', 0, 1); - } - elseif ($action == 'clone' && $user->hasRight('multiclone', 'write')) - { - $text = $langs->trans('ConfirmClonemulticlone', $object->ref); - $formconfirm = $form->formconfirm($_SERVER['PHP_SELF'] . '?id=' . $object->id, $langs->trans('Clonemulticlone'), $text, 'confirm_clone', '', 0, 1); - } + if ($action == 'validate' && $user->hasRight('multiclone', 'write')) { + $text = $langs->trans('ConfirmValidatemulticlone', $object->ref); + $formconfirm = $form->formconfirm($_SERVER['PHP_SELF'] . '?id=' . $object->id, $langs->trans('Validatemulticlone'), $text, 'confirm_validate', '', 0, 1); + } elseif ($action == 'delete' && $user->hasRight('multiclone', 'write')) { + $text = $langs->trans('ConfirmDeletemulticlone'); + $formconfirm = $form->formconfirm($_SERVER['PHP_SELF'] . '?id=' . $object->id, $langs->trans('Deletemulticlone'), $text, 'confirm_delete', '', 0, 1); + } elseif ($action == 'clone' && $user->hasRight('multiclone', 'write')) { + $text = $langs->trans('ConfirmClonemulticlone', $object->ref); + $formconfirm = $form->formconfirm($_SERVER['PHP_SELF'] . '?id=' . $object->id, $langs->trans('Clonemulticlone'), $text, 'confirm_clone', '', 0, 1); + } - return $formconfirm; -} \ No newline at end of file + return $formconfirm; +} diff --git a/tpl/card.tpl.php b/tpl/card.tpl.php index a2689d7..4709ffe 100644 --- a/tpl/card.tpl.php +++ b/tpl/card.tpl.php @@ -1,3 +1,20 @@ + + @@ -23,33 +40,33 @@ [onshow;block=begin;when [view.mode]='edit']
- + [onshow;block=begin;when [object.getId()]+-0] [onshow;block=end] - + [onshow;block=begin;when [object.getId()]=0] [onshow;block=end] - + - +
[onshow;block=end] [onshow;block=begin;when [view.mode]!='edit']
[onshow;block=begin;when [user.rights.multiclone.write;noerr]=1] - + [onshow;block=begin;when [object.status]=[Tmulticlone.STATUS_DRAFT]] [onshow;block=end] - + [onshow;block=begin;when [object.status]=[Tmulticlone.STATUS_VALIDATED]] @@ -64,7 +81,7 @@ [onshow;block=end] - + [onshow;block=end]
-[onshow;block=end] \ No newline at end of file +[onshow;block=end] diff --git a/tpl/linkedobjectblock.tpl.php b/tpl/linkedobjectblock.tpl.php index 08f046e..0fe83eb 100644 --- a/tpl/linkedobjectblock.tpl.php +++ b/tpl/linkedobjectblock.tpl.php @@ -43,21 +43,20 @@ $objectlink) -{ +foreach ($linkedObjectBlock as $key => $objectlink) { $var=!$var; -?> + ?> > - + - + -
getNomUrl(1); ?>getNomUrl(1); ?> label; ?>date_maj,'day'); ?>date_maj, 'day'); ?> getLibStatut(0); ?> ">transnoentitiesnoconv("RemoveLink")); ?>
- \ No newline at end of file +