diff --git a/ChangeLog b/ChangeLog index 350a29fe051..13b5981c8de 100644 --- a/ChangeLog +++ b/ChangeLog @@ -30,20 +30,20 @@ NEW: #21000 Added columns 'alias_name' on project, supplier invoice, supplier or NEW: #21780 Add pid field to Cronjob class and store PID on job execution NEW: #21395 Added option for dark theme mode in display - color and theme NEW: #21397 added option to auto define barcode numbers for third-parties in barcode module setup -NEW: #21399 +NEW: #21399 add image for event_array NEW: #21442 Enhancement of module builder init NEW: #21654 add bank account number used on invoices for debit -NEW: #22048 Added notes to productlot module +NEW: #22048 added notes to productlot module NEW: #22298 Bank - Add salaries & vat in the tab of planned entries of a bank account -NEW: #22328 -NEW: #22424 +NEW: #22328 OAuth admin +NEW: #22424 online signature for contracts NEW: #22500 member module set up made easier NEW: #22527 projects and thirdparties can be viewed as conversation ("Message" view), like events/agenda. NEW: #22546 can now set user supervisors using mass action in htdocs/user NEW: #22594 can chose if VAT ID is unique or not for third parties NEW: #22622 all partnerships displayed on tab partnership of a thirdparty and member NEW: #22676 massaction for updating product prices -NEW: #22735 Massaction to affect users on projects +NEW: #22735 massaction to affect users on projects NEW: #25594 can chose if VAT ID is unique or not for third parties NEW: #4482 adding js to hide/show advanced option on the export data page @@ -57,27 +57,17 @@ NEW: Add max size send for "backup and link to mail" option NEW: Add method httponly_accessforbidden() NEW: Add more advices into the Setup security page NEW: Add new global variable for keeping the previous signature information on proposale (case of reopen a proposale) -NEW: Add objectLink on expedition -NEW: Add oldcopy to Ticket so triggers intercepting TICKET_MODIFY have access to old values of the updated properties NEW: Add option --force on CLI cron_run_jobs.php NEW: Add option "Show price on the generated documents for receptions" -NEW: invoice export : add accounting affectation -NEW: label on products categories filter -NEW: manage no email with thirdparties (better for GDPR) NEW: Manage VAT on all lines on purchases cycle -NEW: On a bank reconciled line, we can modify the bank receipt NEW: parent company column and filter in invoice and order list -NEW: possibility to select scopes with checkbox for Oauth tokens -NEW: private and public note on user, thirdparty and contact list +NEW: private and public note columns on user, thirdparty and contact lists NEW: Public counters feature -NEW: Saved token of OAUTH module are now encrypted into llx_oauth_token NEW: Save one click to select on delivery ack, on emails. NEW: scheduled job to send unpaid invoice reminder can now use the cc and bcc from email template -NEW: experimental SMTP using PhpImap allowing OAuth2 authentication (need to add option MAIN_IMAP_USE_PHPIMAP) NEW: can substitue project title in mail template NEW: The purge of files can purge only if older than a number of seconds NEW: Update ActionComm type_code on email message ticket -NEW: Finance - VAT - Admin - Add information on deadline day for submission of VAT declaration NEW: Add the target to select attendees of event for emailings NEW: add redirect on action confirm addconsumedline and addproduceline NEW: Add the referrer-policy to "same-origin" by default on all public pages. @@ -87,17 +77,18 @@ NEW: Can enter the unit price including the VAT NEW: Can invoice task time per different services NEW: Can set a commercial discount by entering amount including VAT NEW: Can set start and end dates and comment on button "Activate all services" -NEW: can sort and preselected best supplier price NEW: show date delivery planned on orders linked to company and product NEW: filter on reception dates (from / to) in cheque paiement card -NEW: Accountancy - Add a graphic option to enable lettering function - FPC21 -NEW: Accountancy - Add a way to clean some words when you generate thirdparty accounting account -NEW: Accountancy - Added an option during export to export or not the lettering FPC21 +NEW: Accountancy - add a graphic option to enable lettering function - FPC21 +NEW: Accountancy - add a way to clean some words when you generate thirdparty accounting account +NEW: Accountancy - added an option during export to export or not the lettering FPC21 +NEW: Accountancy - Invoice export : add accounting affectation NEW: Accountancy - Manage supplier deposit with specific account NEW: Accountancy - Model Digitaria - Add a way to clean some words when you generate thirdparty accounting account FPC22 NEW: Agenda - start a simple support of recurrent events on agenda NEW: Bank - add salaries & VAT in tab planned entries +NEW: Bank - on a bank reconciled line, we can modify the bank receipt NEW: Contracts - add a method doAutoRenewContracts that can be used as a cron task NEW: Contracts - default template of contract is not mandatory NEW: Contracts - Manage Position (Rank) on Contract Lines @@ -108,22 +99,29 @@ NEW: EMail - can send an email on scheduled job error NEW: EMail - on a form to send an email, we show all emails of all contacts of object NEW: EMail - add the SMTP header References on ticket email created by email NEW: EMail - add substitution key __SENDEREMAIL_SIGNATURE__ +NEW: EMail - experimental SMTP using PhpImap allowing OAuth2 authentication (need to add option MAIN_IMAP_USE_PHPIMAP) NEW: EMail-Collector - add IMAP port setting NEW: EMail-Collector - add a button "Test collect" -NEW: Export - Add " as enclosure by default for CSV export. Keep removing CR/LF. NEW: Event-Organization - add date event (!= date project) and location on event organization +NEW: Expedition - add objectLink on expedition +NEW: Export - Add " as enclosure by default for CSV export. Keep removing CR/LF. NEW: Extrafields - add badge in admin extrafields setup NEW: Extrafields - can edit property css, cssview, csslist on extrafields NEW: Extrafields - default values in extrafields are not more limited to 255 char. NEW: Extrafields - field price with currency NEW: Extrafields - support IP type to store IP addresses +NEW: Finance - VAT - Admin - Add information on deadline day for submission of VAT declaration NEW: Interventions - enable online signature for interventions -NEW: Invoice - Add french mention on pdf when vat debit option is on +NEW: Invoice - add french mention on PDF when VAT debit option is on NEW: Members - default_lang for members -NEW: Members - Table of membership types +NEW: Members - table of membership types NEW: Members - add free membership amounts at the membership type level +NEW: OAuth - possibility to select scopes with checkbox for OAuth tokens +NEW: OAuth - saved token of OAUTH module are now encrypted into llx_oauth_token NEW: Orders - resize parent company column in order list -NEW: Products supplier price - autofill default supplier VAT +NEW: Products - Categories - label on products categories filter +NEW: Products - Supplier price - autofill default supplier VAT +NEW: Products - Supplier price - can sort and preselected best supplier price NEW: Projects - add author on list NEW: Projects - add thirdparty column to the time list (projet/tasks/time.php) NEW: Proposals - show delivery mode on PDF for proposals @@ -144,8 +142,10 @@ NEW: TakePOS - display currency in TakePOS menu NEW: TakePOS - Header Scroll in TakePOS NEW: TakePOS - Receipt preview in TakePOS setup NEW: TakePOS - support of Stripe Terminal with TakePOS +NEW: Thirdparty - manage no email with thirdparties (better for GDPR) NEW: Thirdparty - set thirdparty type with company modify trigger NEW: Tickets - change filter type on tickets list into a multiselect combo +NEW: Tickets - add oldcopy to Ticket so triggers intercepting TICKET_MODIFY have access to old values of the updated properties NEW: Website - can delete a whole website if disabled NEW: Website - can remove a website template NEW: Website - can set header "Strict-Transport-Security" in web sites. @@ -176,11 +176,16 @@ NEW: Security: add fail2ban rules examples to limit access to /public pages Option / Const for System: NEW: FICHINTER_ALLOW_EXTERNAL_DOWNLOAD +NEW: MAIN_CHECKBOX_LEFT_COLUMN +NEW: MAIN_EMAIL_SUPPORT_ACK +NEW: MAIN_IMAP_USE_PHPIMAP NEW: MAIN_SEARCH_CATEGORY_PRODUCT_ON_LISTS - const to show category customer filter +NEW: PRODUCT_ALLOW_EXTERNAL_DOWNLOAD NEW: PRODUCTBATCH_SHOW_WAREHOUSE_ON_SHIPMENT - showing warehouse on PDF NEW: PRODUIT_DESC_IN_FORM accept - desktop only or +smartphone NEW: PROPAL_BYPASS_VALIDATED_STATUS NEW: PROPAL_NEW_AS_SIGNED +NEW: PROPAL_SKIP_ACCEPT_REFUSE NEW: TIMESPENT_ALWAYS_UPDATE_THM - when it's on we always check current thm of user to update it in task time line Localisation: @@ -238,25 +243,38 @@ Following changes may create regressions for some external modules, but were nec * Rename the substitution for project label instead of project title in substitution variables -***** ChangeLog for 16.0.4 compared to 16.0.2 ***** +***** ChangeLog for 16.0.4 compared to 16.0.3 ***** FIX: Amount of localtax1 and 2 not correctly save on purchase order (the rate was saved instead) FIX: #20415 FIX: #21280 FIX: #23008 FIX: #22271 +FIX: #22524 FIX: #22837 +FIX: #22964 +FIX: #23012 FIX: #23019 Impossible to add task times to an existing draft invoice FIX: #23072 FIX: #23087 FIX: #23115 FIX: #23116 FIX: #23281 +FIX: #23420 : wrong check on $search_categ value causing FATAL ERROR +FIX: Accountancy - Quadra export +FIX: add border left on image product when conf activated +FIX: Add missing token when deleting template inn order_supplier admin menu +FIX: Amount of localtax1 and 2 not correctly save on purchase order (the +FIX: API access for deactivated users FIX: bad selection of barcode numbering module FIX: Can't see all time spent by all user FIX: CI FIX: CommonObject - showOptionals - Display blank td when MAIN_VIEW_LINE_NUMBER is enabled and action is confirm_valid FIX: Documents API inconsistency +FIX: Empty FormSetup emailTemplate type IF empty fieldvalue +FIX: Errors Handling for CreateFrom Hooks +FIX: error with dol_banner_tab, ref is needed +FIX: ExpenseReport card was not reloaded after addline FIX: #23075 FIX: #23117 FIX: get multicurrency infos of propal when create order from propal with "WORKFLOW_PROPAL_AUTOCREATE_ORDER" conf @@ -264,12 +282,16 @@ FIX: Give predictable order to inventory lines FIX: include class multicurrency FIX: methods declaration (backport fix 67b9a7dc07d708231d12b5e58800334d4a01ef98) FIX: multicurrency_tx and not currency_tx -FIX: PGSQL Integer type does not have a free length +FIX: on public ticket list, only the page 1 was accessible. Other pages were 404 error. +FIX: PGSQL Integer type does not have a free lenght +FIX: PGSQL Int type does not have a free lenght FIX: Product list in setup.php in new Module FIX: propal and order stats broken on Tag+User(retricted customer list) FIX: saving of numbering module for jobs FIX: Stickler FIX: travis +FIX: wrong check on $search_categ value causing fatal error +FIX: wrong stock list with multicompany and without stock sharing ***** ChangeLog for 16.0.3 compared to 16.0.2 ***** diff --git a/htdocs/adherents/card.php b/htdocs/adherents/card.php index f57bb2e312d..f9a43e47f0f 100644 --- a/htdocs/adherents/card.php +++ b/htdocs/adherents/card.php @@ -674,7 +674,7 @@ if (empty($reshook)) { $moreinheader = 'X-Dolibarr-Info: send_an_email by adherents/card.php'."\r\n"; - $result = $object->send_an_email($texttosend, $subjecttosend, array(), array(), array(), "", "", 0, -1, '', $moreinheader); + $result = $object->sendEmail($texttosend, $subjecttosend, array(), array(), array(), "", "", 0, -1, '', $moreinheader); if ($result < 0) { $error++; setEventMessages($object->error, $object->errors, 'errors'); @@ -745,7 +745,7 @@ if (empty($reshook)) { $moreinheader = 'X-Dolibarr-Info: send_an_email by adherents/card.php'."\r\n"; - $result = $object->send_an_email($texttosend, $subjecttosend, array(), array(), array(), "", "", 0, -1, '', $moreinheader); + $result = $object->sendEmail($texttosend, $subjecttosend, array(), array(), array(), "", "", 0, -1, '', $moreinheader); if ($result < 0) { $error++; setEventMessages($object->error, $object->errors, 'errors'); @@ -816,7 +816,7 @@ if (empty($reshook)) { $moreinheader = 'X-Dolibarr-Info: send_an_email by adherents/card.php'."\r\n"; - $result = $object->send_an_email($texttosend, $subjecttosend, array(), array(), array(), "", "", 0, -1, '', $moreinheader); + $result = $object->sendEmail($texttosend, $subjecttosend, array(), array(), array(), "", "", 0, -1, '', $moreinheader); if ($result < 0) { $error++; setEventMessages($object->error, $object->errors, 'errors'); diff --git a/htdocs/adherents/class/adherent.class.php b/htdocs/adherents/class/adherent.class.php index e2b7cda5e07..b0ca0986ffb 100644 --- a/htdocs/adherents/class/adherent.class.php +++ b/htdocs/adherents/class/adherent.class.php @@ -440,11 +440,37 @@ class Adherent extends CommonObject * @param int $msgishtml 1=String IS already html, 0=String IS NOT html, -1=Unknown need autodetection * @param string $errors_to erros to * @param string $moreinheader Add more html headers + * @deprecated since V18 + * @see sendEmail * @return int <0 if KO, >0 if OK */ public function send_an_email($text, $subject, $filename_list = array(), $mimetype_list = array(), $mimefilename_list = array(), $addr_cc = "", $addr_bcc = "", $deliveryreceipt = 0, $msgishtml = -1, $errors_to = '', $moreinheader = '') { // phpcs:enable + dol_syslog('Warning using deprecated Adherent::send_an_email', LOG_WARNING); + + return $this->sendEmail($text, $subject, $filename_list, $mimetype_list, $mimefilename_list, $addr_cc, $addr_bcc, $deliveryreceipt, $msgishtml, $errors_to, $moreinheader); + } + + /** + * Function sending an email to the current member with the text supplied in parameter. + * + * @param string $text Content of message (not html entities encoded) + * @param string $subject Subject of message + * @param array $filename_list Array of attached files + * @param array $mimetype_list Array of mime types of attached files + * @param array $mimefilename_list Array of public names of attached files + * @param string $addr_cc Email cc + * @param string $addr_bcc Email bcc + * @param int $deliveryreceipt Ask a delivery receipt + * @param int $msgishtml 1=String IS already html, 0=String IS NOT html, -1=Unknown need autodetection + * @param string $errors_to erros to + * @param string $moreinheader Add more html headers + * @since V18 + * @return int <0 if KO, >0 if OK + */ + public function sendEmail($text, $subject, $filename_list = array(), $mimetype_list = array(), $mimefilename_list = array(), $addr_cc = "", $addr_bcc = "", $deliveryreceipt = 0, $msgishtml = -1, $errors_to = '', $moreinheader = '') + { global $conf, $langs; // Detect if message is HTML diff --git a/htdocs/adherents/subscription.php b/htdocs/adherents/subscription.php index 8c423d53029..004bd7eaf4b 100644 --- a/htdocs/adherents/subscription.php +++ b/htdocs/adherents/subscription.php @@ -405,7 +405,7 @@ if ($user->hasRight('adherent', 'cotisation', 'creer') && $action == 'subscripti $moreinheader = 'X-Dolibarr-Info: send_an_email by adherents/subscription.php'."\r\n"; - $result = $object->send_an_email($texttosend, $subjecttosend, $listofpaths, $listofmimes, $listofnames, "", "", 0, -1, '', $moreinheader); + $result = $object->sendEmail($texttosend, $subjecttosend, $listofpaths, $listofmimes, $listofnames, "", "", 0, -1, '', $moreinheader); if ($result < 0) { $errmsg = $object->error; setEventMessages($object->error, $object->errors, 'errors'); diff --git a/htdocs/admin/index.php b/htdocs/admin/index.php index 87b49c95468..8a563191303 100644 --- a/htdocs/admin/index.php +++ b/htdocs/admin/index.php @@ -105,10 +105,15 @@ print '
'; print '
'; +$nbmodulesnotautoenabled = count($conf->modules); +if (in_array('fckeditor', $conf->modules)) $nbmodulesnotautoenabled--; +if (in_array('export', $conf->modules)) $nbmodulesnotautoenabled--; +if (in_array('import', $conf->modules)) $nbmodulesnotautoenabled--; + // Show info setup module print img_picto('', 'cog', 'class="paddingright valignmiddle double"').' '.$langs->trans("SetupDescriptionLink", DOL_URL_ROOT.'/admin/modules.php?mainmenu=home', $langs->transnoentities("Setup"), $langs->transnoentities("Modules")); print '

'.$langs->trans("SetupDescription4b"); -if (count($conf->modules) <= (empty($conf->global->MAIN_MIN_NB_ENABLED_MODULE_FOR_WARNING) ? 1 : $conf->global->MAIN_MIN_NB_ENABLED_MODULE_FOR_WARNING)) { // If only minimal initial modules enabled +if ($nbmodulesnotautoenabled <= getDolGlobalInt('MAIN_MIN_NB_ENABLED_MODULE_FOR_WARNING', 1)) { // If only minimal initial modules enabled $langs->load("errors"); $warnpicto = img_warning($langs->trans("WarningEnableYourModulesApplications"), 'style="padding-right: 6px;"'); print '
'.$warnpicto.$langs->trans("WarningEnableYourModulesApplications").'
'; diff --git a/htdocs/admin/modules.php b/htdocs/admin/modules.php index 837c76adadf..a42ecc5c34d 100644 --- a/htdocs/admin/modules.php +++ b/htdocs/admin/modules.php @@ -379,99 +379,95 @@ foreach ($modulesdir as $dir) { try { $res = include_once $dir.$file; // A class already exists in a different file will send a non catchable fatal error. if (class_exists($modName)) { - try { - $objMod = new $modName($db); - $modNameLoaded[$modName] = $dir; - if (!$objMod->numero > 0 && $modName != 'modUser') { - dol_syslog('The module descriptor '.$modName.' must have a numero property', LOG_ERR); - } - $j = $objMod->numero; + $objMod = new $modName($db); + $modNameLoaded[$modName] = $dir; + if (!$objMod->numero > 0 && $modName != 'modUser') { + dol_syslog('The module descriptor '.$modName.' must have a numero property', LOG_ERR); + } + $j = $objMod->numero; - $modulequalified = 1; + $modulequalified = 1; - // We discard modules according to features level (PS: if module is activated we always show it) - $const_name = 'MAIN_MODULE_'.strtoupper(preg_replace('/^mod/i', '', get_class($objMod))); - if ($objMod->version == 'development' && (empty($conf->global->$const_name) && ($conf->global->MAIN_FEATURES_LEVEL < 2))) { - $modulequalified = 0; - } - if ($objMod->version == 'experimental' && (empty($conf->global->$const_name) && ($conf->global->MAIN_FEATURES_LEVEL < 1))) { - $modulequalified = 0; - } - if (preg_match('/deprecated/', $objMod->version) && (empty($conf->global->$const_name) && ($conf->global->MAIN_FEATURES_LEVEL >= 0))) { - $modulequalified = 0; - } + // We discard modules according to features level (PS: if module is activated we always show it) + $const_name = 'MAIN_MODULE_'.strtoupper(preg_replace('/^mod/i', '', get_class($objMod))); + if ($objMod->version == 'development' && (empty($conf->global->$const_name) && ($conf->global->MAIN_FEATURES_LEVEL < 2))) { + $modulequalified = 0; + } + if ($objMod->version == 'experimental' && (empty($conf->global->$const_name) && ($conf->global->MAIN_FEATURES_LEVEL < 1))) { + $modulequalified = 0; + } + if (preg_match('/deprecated/', $objMod->version) && (empty($conf->global->$const_name) && ($conf->global->MAIN_FEATURES_LEVEL >= 0))) { + $modulequalified = 0; + } - // We discard modules according to property ->hidden - if (!empty($objMod->hidden)) { - $modulequalified = 0; - } + // We discard modules according to property ->hidden + if (!empty($objMod->hidden)) { + $modulequalified = 0; + } - if ($modulequalified > 0) { - $publisher = dol_escape_htmltag($objMod->getPublisher()); - $external = ($objMod->isCoreOrExternalModule() == 'external'); - if ($external) { - if ($publisher) { - $arrayofnatures['external_'.$publisher] = $langs->trans("External").' - '.$publisher; - } else { - $arrayofnatures['external_'] = $langs->trans("External").' - '.$langs->trans("UnknownPublishers"); - } - } - ksort($arrayofnatures); - - // Define array $categ with categ with at least one qualified module - $filename[$i] = $modName; - $modules[$modName] = $objMod; - - // Gives the possibility to the module, to provide his own family info and position of this family - if (is_array($objMod->familyinfo) && !empty($objMod->familyinfo)) { - $familyinfo = array_merge($familyinfo, $objMod->familyinfo); - $familykey = key($objMod->familyinfo); + if ($modulequalified > 0) { + $publisher = dol_escape_htmltag($objMod->getPublisher()); + $external = ($objMod->isCoreOrExternalModule() == 'external'); + if ($external) { + if ($publisher) { + $arrayofnatures['external_'.$publisher] = $langs->trans("External").' - '.$publisher; } else { - $familykey = $objMod->family; + $arrayofnatures['external_'] = $langs->trans("External").' - '.$langs->trans("UnknownPublishers"); } + } + ksort($arrayofnatures); - $moduleposition = ($objMod->module_position ? $objMod->module_position : '50'); - if ($objMod->isCoreOrExternalModule() == 'external' && $moduleposition < 100000) { - // an external module should never return a value lower than '80'. - $moduleposition = '80'; // External modules at end by default - } + // Define array $categ with categ with at least one qualified module + $filename[$i] = $modName; + $modules[$modName] = $objMod; - // Add list of warnings to show into arrayofwarnings and arrayofwarningsext - if (!empty($objMod->warnings_activation)) { - $arrayofwarnings[$modName] = $objMod->warnings_activation; - } - if (!empty($objMod->warnings_activation_ext)) { - $arrayofwarningsext[$modName] = $objMod->warnings_activation_ext; - } - - $familyposition = (empty($familyinfo[$familykey]['position']) ? 0 : $familyinfo[$familykey]['position']); - $listOfOfficialModuleGroups = array('hr', 'technic', 'interface', 'technic', 'portal', 'financial', 'crm', 'base', 'products', 'srm', 'ecm', 'projects', 'other'); - if ($external && !in_array($familykey, $listOfOfficialModuleGroups)) { - // If module is extern and into a custom group (not into an official predefined one), it must appear at end (custom groups should not be before official groups). - if (is_numeric($familyposition)) { - $familyposition = sprintf("%03d", (int) $familyposition + 100); - } - } - - $orders[$i] = $familyposition."_".$familykey."_".$moduleposition."_".$j; // Sort by family, then by module position then number - - // Set categ[$i] - $specialstring = 'unknown'; - if ($objMod->version == 'development' || $objMod->version == 'experimental') { - $specialstring = 'expdev'; - } - if (isset($categ[$specialstring])) { - $categ[$specialstring]++; // Array of all different modules categories - } else { - $categ[$specialstring] = 1; - } - $j++; - $i++; + // Gives the possibility to the module, to provide his own family info and position of this family + if (is_array($objMod->familyinfo) && !empty($objMod->familyinfo)) { + $familyinfo = array_merge($familyinfo, $objMod->familyinfo); + $familykey = key($objMod->familyinfo); } else { - dol_syslog("Module ".get_class($objMod)." not qualified"); + $familykey = $objMod->family; } - } catch (Exception $e) { - dol_syslog("Failed to load ".$dir.$file." ".$e->getMessage(), LOG_ERR); + + $moduleposition = ($objMod->module_position ? $objMod->module_position : '50'); + if ($objMod->isCoreOrExternalModule() == 'external' && $moduleposition < 100000) { + // an external module should never return a value lower than '80'. + $moduleposition = '80'; // External modules at end by default + } + + // Add list of warnings to show into arrayofwarnings and arrayofwarningsext + if (!empty($objMod->warnings_activation)) { + $arrayofwarnings[$modName] = $objMod->warnings_activation; + } + if (!empty($objMod->warnings_activation_ext)) { + $arrayofwarningsext[$modName] = $objMod->warnings_activation_ext; + } + + $familyposition = (empty($familyinfo[$familykey]['position']) ? 0 : $familyinfo[$familykey]['position']); + $listOfOfficialModuleGroups = array('hr', 'technic', 'interface', 'technic', 'portal', 'financial', 'crm', 'base', 'products', 'srm', 'ecm', 'projects', 'other'); + if ($external && !in_array($familykey, $listOfOfficialModuleGroups)) { + // If module is extern and into a custom group (not into an official predefined one), it must appear at end (custom groups should not be before official groups). + if (is_numeric($familyposition)) { + $familyposition = sprintf("%03d", (int) $familyposition + 100); + } + } + + $orders[$i] = $familyposition."_".$familykey."_".$moduleposition."_".$j; // Sort by family, then by module position then number + + // Set categ[$i] + $specialstring = 'unknown'; + if ($objMod->version == 'development' || $objMod->version == 'experimental') { + $specialstring = 'expdev'; + } + if (isset($categ[$specialstring])) { + $categ[$specialstring]++; // Array of all different modules categories + } else { + $categ[$specialstring] = 1; + } + $j++; + $i++; + } else { + dol_syslog("Module ".get_class($objMod)." not qualified"); } } else { print "Warning bad descriptor file : ".$dir.$file." (Class ".$modName." not found into file)
"; @@ -523,12 +519,10 @@ asort($orders); $nbofactivatedmodules = count($conf->modules); -//$conf->global->MAIN_MIN_NB_ENABLED_MODULE_FOR_WARNING = 1000; -/*$moreinfo = $langs->trans("TitleNumberOfActivatedModules"); -$moreinfo2 = ''.($nbofactivatedmodules - 1).' / '.count($modules).''; -if ($nbofactivatedmodules <= (empty($conf->global->MAIN_MIN_NB_ENABLED_MODULE_FOR_WARNING) ? 1 : $conf->global->MAIN_MIN_NB_ENABLED_MODULE_FOR_WARNING)) { - $moreinfo2 .= ' '.img_warning($langs->trans("YouMustEnableOneModule")); -}*/ +$nbmodulesnotautoenabled = count($conf->modules); +if (in_array('fckeditor', $conf->modules)) $nbmodulesnotautoenabled--; +if (in_array('export', $conf->modules)) $nbmodulesnotautoenabled--; +if (in_array('import', $conf->modules)) $nbmodulesnotautoenabled--; print load_fiche_titre($langs->trans("ModulesSetup"), '', 'title_setup'); @@ -539,7 +533,7 @@ if ($mode == 'common' || $mode == 'commonkanban') { $desc .= ' '.$langs->trans("ModulesDesc2", '{picto2}'); $desc = str_replace('{picto}', img_picto('', 'switch_off', 'class="size15x"'), $desc); $desc = str_replace('{picto2}', img_picto('', 'setup', 'class="size15x"'), $desc); - if (!count($conf->modules) <= (empty($conf->global->MAIN_MIN_NB_ENABLED_MODULE_FOR_WARNING) ? 1 : $conf->global->MAIN_MIN_NB_ENABLED_MODULE_FOR_WARNING)) { // If only minimal initial modules enabled + if ($nbmodulesnotautoenabled <= getDolGlobalInt('MAIN_MIN_NB_ENABLED_MODULE_FOR_WARNING', 1)) { // If only minimal initial modules enabled $deschelp = '
'.$desc."

\n"; } } @@ -553,7 +547,7 @@ if ($mode == 'develop') { $deschelp = '
'.$langs->trans("ModulesDevelopDesc")."

\n"; } -$head = modules_prepare_head($nbofactivatedmodules, count($modules)); +$head = modules_prepare_head($nbofactivatedmodules, count($modules), $nbmodulesnotautoenabled); if ($mode == 'common' || $mode == 'commonkanban') { diff --git a/htdocs/bom/class/api_boms.class.php b/htdocs/bom/class/api_boms.class.php index e199650be30..1a42e17d875 100644 --- a/htdocs/bom/class/api_boms.class.php +++ b/htdocs/bom/class/api_boms.class.php @@ -370,7 +370,7 @@ class Boms extends DolibarrApi * * @url PUT {id}/lines/{lineid} * - * @return array|bool + * @return object|bool */ public function putLine($id, $lineid, $request_data = null) { diff --git a/htdocs/comm/action/peruser.php b/htdocs/comm/action/peruser.php index 340efbf30a8..1eba5ec7de9 100644 --- a/htdocs/comm/action/peruser.php +++ b/htdocs/comm/action/peruser.php @@ -924,6 +924,10 @@ while ($currentdaytoshow < $lastdaytoshow) { if ($usergroup > 0) { $sql .= " AND ug.fk_usergroup = ".((int) $usergroup); } + if ($user->socid > 0) { + // External users should see only contacts of their company + $sql .= " AND u.fk_soc = ".((int) $user->socid); + } //print $sql; $resql = $db->query($sql); diff --git a/htdocs/comm/index.php b/htdocs/comm/index.php index b748cac3df4..5d71683a311 100644 --- a/htdocs/comm/index.php +++ b/htdocs/comm/index.php @@ -61,25 +61,17 @@ if (isset($user->socid) && $user->socid > 0) { $socid = $user->socid; } + $max = $conf->global->MAIN_SIZE_SHORTLIST_LIMIT; +$maxofloop = (empty($conf->global->MAIN_MAXLIST_OVERLOAD) ? 500 : $conf->global->MAIN_MAXLIST_OVERLOAD); $now = dol_now(); -// Security check -//$socid = GETPOST("socid", 'int'); -if ($user->socid > 0) { - $action = ''; - $id = $user->socid; -} else { - $id = 0; -} - -//restrictedArea($user, 'societe', $id, '&societe', '', 'fk_soc', 'rowid', 0); +//restrictedArea($user, 'societe', $socid, '&societe', '', 'fk_soc', 'rowid', 0); if (!$user->hasRight('propal', 'read') && !$user->hasRight('supplier_proposal', 'read') && !$user->hasRight('commande', 'read') && !$user->hasRight('fournisseur', 'commande', 'read') && !$user->hasRight('supplier_order', 'read') && !$user->hasRight('fichinter', 'read')) { accessforbidden(); } -$maxofloop = (empty($conf->global->MAIN_MAXLIST_OVERLOAD) ? 500 : $conf->global->MAIN_MAXLIST_OVERLOAD); /* diff --git a/htdocs/commande/card.php b/htdocs/commande/card.php index 09b3c14a1da..3a34594bbd8 100644 --- a/htdocs/commande/card.php +++ b/htdocs/commande/card.php @@ -14,6 +14,7 @@ * Copyright (C) 2015 Jean-François Ferry * Copyright (C) 2018-2021 Frédéric France * Copyright (C) 2022 Gauthier VERDOL + * Copyright (C) 2023 Benjamin Falière * * 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 @@ -1841,25 +1842,25 @@ if ($action == 'create' && $usercancreate) { // Delivery delay print ''.$langs->trans('AvailabilityPeriod').''; print img_picto('', 'clock', 'class="pictofixedwidth"'); - $form->selectAvailabilityDelay($availability_id, 'availability_id', '', 1, 'maxwidth200 widthcentpercentminusx'); + $form->selectAvailabilityDelay((GETPOSTISSET('availability_id')?GETPOST('availability_id'):$availability_id), 'availability_id', '', 1, 'maxwidth200 widthcentpercentminusx'); print ''; // Terms of payment print ''.$langs->trans('PaymentConditionsShort').''; print img_picto('', 'payment', 'class="pictofixedwidth"'); - print $form->getSelectConditionsPaiements($cond_reglement_id, 'cond_reglement_id', 1, 1, 0, 'maxwidth200 widthcentpercentminusx', $deposit_percent); + print $form->getSelectConditionsPaiements((GETPOSTISSET('cond_reglement_id')?GETPOST('cond_reglement_id'):$cond_reglement_id), 'cond_reglement_id', 1, 1, 0, 'maxwidth200 widthcentpercentminusx', $deposit_percent); print ''; // Payment mode print ''.$langs->trans('PaymentMode').''; print img_picto('', 'bank', 'class="pictofixedwidth"'); - print $form->select_types_paiements($mode_reglement_id, 'mode_reglement_id', 'CRDT', 0, 1, 0, 0, 1, 'maxwidth200 widthcentpercentminusx', 1); + print $form->select_types_paiements((GETPOSTISSET('mode_reglement_id')?GETPOST('mode_reglement_id'):$mode_reglement_id), 'mode_reglement_id', 'CRDT', 0, 1, 0, 0, 1, 'maxwidth200 widthcentpercentminusx', 1); print ''; // Bank Account if (!empty($conf->global->BANK_ASK_PAYMENT_BANK_DURING_ORDER) && isModEnabled("banque")) { print ''.$langs->trans('BankAccount').''; - print img_picto('', 'bank_account', 'class="pictofixedwidth"').$form->select_comptes($fk_account, 'fk_account', 0, '', 1, '', 0, 'maxwidth200 widthcentpercentminusx', 1); + print img_picto('', 'bank_account', 'class="pictofixedwidth"').$form->select_comptes((GETPOSTISSET('fk_account')?GETPOST('fk_account'):$fk_account), 'fk_account', 0, '', 1, '', 0, 'maxwidth200 widthcentpercentminusx', 1); print ''; } @@ -1867,7 +1868,7 @@ if ($action == 'create' && $usercancreate) { if (isModEnabled('expedition')) { print ''.$langs->trans('SendingMethod').''; print img_picto('', 'object_dolly', 'class="pictofixedwidth"'); - $form->selectShippingMethod($shipping_method_id, 'shipping_method_id', '', 1, '', 0, 'maxwidth200 widthcentpercentminusx'); + $form->selectShippingMethod((GETPOSTISSET('shipping_method_id')?GETPOST('shipping_method_id'):$shipping_method_id), 'shipping_method_id', '', 1, '', 0, 'maxwidth200 widthcentpercentminusx'); print ''; } @@ -1876,14 +1877,14 @@ if ($action == 'create' && $usercancreate) { require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php'; $formproduct = new FormProduct($db); print ''.$langs->trans('Warehouse').''; - print img_picto('', 'stock', 'class="pictofixedwidth"').$formproduct->selectWarehouses($warehouse_id, 'warehouse_id', '', 1, 0, 0, '', 0, 0, array(), 'maxwidth500 widthcentpercentminusxx'); + print img_picto('', 'stock', 'class="pictofixedwidth"').$formproduct->selectWarehouses((GETPOSTISSET('warehouse_id')?GETPOST('warehouse_id'):$warehouse_id), 'warehouse_id', '', 1, 0, 0, '', 0, 0, array(), 'maxwidth500 widthcentpercentminusxx'); print ''; } // Source / Channel - What trigger creation print ''.$langs->trans('Channel').''; print img_picto('', 'question', 'class="pictofixedwidth"'); - $form->selectInputReason($demand_reason_id, 'demand_reason_id', '', 1, 'maxwidth200 widthcentpercentminusx'); + $form->selectInputReason((GETPOSTISSET('demand_reason_id')?GETPOST('demand_reason_id'):$demand_reason_id), 'demand_reason_id', '', 1, 'maxwidth200 widthcentpercentminusx'); print ''; // TODO How record was recorded OrderMode (llx_c_input_method) @@ -1893,7 +1894,7 @@ if ($action == 'create' && $usercancreate) { $langs->load("projects"); print ''; print ''.$langs->trans("Project").''; - print img_picto('', 'project', 'class="pictofixedwidth"').$formproject->select_projects(($soc->id > 0 ? $soc->id : -1), $projectid, 'projectid', 0, 0, 1, 0, 0, 0, 0, '', 1, 0, 'maxwidth500 widthcentpercentminusxx'); + print img_picto('', 'project', 'class="pictofixedwidth"').$formproject->select_projects(($soc->id > 0 ? $soc->id : -1), (GETPOSTISSET('projectid')?GETPOST('projectid'):$projectid), 'projectid', 0, 0, 1, 0, 0, 0, 0, '', 1, 0, 'maxwidth500 widthcentpercentminusxx'); print ' id).'">'; print ''; print ''; @@ -1952,7 +1953,7 @@ if ($action == 'create' && $usercancreate) { print ''; print ''.$form->editfieldkey("Currency", 'multicurrency_code', '', $object, 0).''; print ''; - print img_picto('', 'currency', 'class="pictofixedwidth"').$form->selectMultiCurrency($currency_code, 'multicurrency_code', 0, '', false, 'maxwidth200 widthcentpercentminusx'); + print img_picto('', 'currency', 'class="pictofixedwidth"').$form->selectMultiCurrency((GETPOSTISSET('multicurrency_code')?GETPOST('multicurrency_code'):$currency_code), 'multicurrency_code', 0, '', false, 'maxwidth200 widthcentpercentminusx'); print ''; } diff --git a/htdocs/commande/class/api_orders.class.php b/htdocs/commande/class/api_orders.class.php index 1a879173684..0318cbcd5bf 100644 --- a/htdocs/commande/class/api_orders.class.php +++ b/htdocs/commande/class/api_orders.class.php @@ -1053,6 +1053,7 @@ class Orders extends DolibarrApi } $shipment = new Expedition($this->db); $shipment->socid = $this->commande->socid; + $shipment->origin_id = $this->commande->id; $result = $shipment->create(DolibarrApiAccess::$user); if ($result <= 0) { throw new RestException(500, 'Error on creating expedition :'.$this->db->lasterror()); diff --git a/htdocs/compta/stats/supplier_turnover_by_thirdparty.php b/htdocs/compta/stats/supplier_turnover_by_thirdparty.php index 2b590e05fd9..515a004a3cd 100644 --- a/htdocs/compta/stats/supplier_turnover_by_thirdparty.php +++ b/htdocs/compta/stats/supplier_turnover_by_thirdparty.php @@ -249,9 +249,9 @@ if ($modecompta == 'CREANCES-DETTES') { $sql .= " sum(f.total_ht) as amount, sum(f.total_ttc) as amount_ttc"; $sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f, ".MAIN_DB_PREFIX."societe as s"; if ($selected_cat === -2) { // Without any category - $sql .= " LEFT OUTER JOIN ".MAIN_DB_PREFIX."categorie_societe as cs ON s.rowid = cs.fk_soc"; + $sql .= " LEFT OUTER JOIN ".MAIN_DB_PREFIX."categorie_fournisseur as cs ON s.rowid = cs.fk_soc"; } elseif ($selected_cat) { // Into a specific category - $sql .= ", ".MAIN_DB_PREFIX."categorie as c, ".MAIN_DB_PREFIX."categorie_societe as cs"; + $sql .= ", ".MAIN_DB_PREFIX."categorie as c, ".MAIN_DB_PREFIX."categorie_fournisseur as cs"; } $sql .= " WHERE f.fk_statut in (1,2)"; $sql .= " AND f.type IN (0,2)"; @@ -276,9 +276,9 @@ if ($modecompta == 'CREANCES-DETTES') { $sql .= ", ".MAIN_DB_PREFIX."paiementfourn as p"; $sql .= ", ".MAIN_DB_PREFIX."societe as s"; if ($selected_cat === -2) { // Without any category - $sql .= " LEFT OUTER JOIN ".MAIN_DB_PREFIX."categorie_societe as cs ON s.rowid = cs.fk_soc"; + $sql .= " LEFT OUTER JOIN ".MAIN_DB_PREFIX."categorie_fournisseur as cs ON s.rowid = cs.fk_soc"; } elseif ($selected_cat) { // Into a specific category - $sql .= ", ".MAIN_DB_PREFIX."categorie as c, ".MAIN_DB_PREFIX."categorie_societe as cs"; + $sql .= ", ".MAIN_DB_PREFIX."categorie as c, ".MAIN_DB_PREFIX."categorie_fournisseur as cs"; } $sql .= " WHERE p.rowid = pf.fk_paiementfourn"; $sql .= " AND pf.fk_facturefourn = f.rowid"; diff --git a/htdocs/conf/conf.php.example b/htdocs/conf/conf.php.example index 1cc028ff137..5325523f8e5 100644 --- a/htdocs/conf/conf.php.example +++ b/htdocs/conf/conf.php.example @@ -302,7 +302,7 @@ $dolibarr_main_restrict_ip=''; // This might be required if you access Dolibarr behind a proxy that make bad URL rewriting, to avoid false alarms. // In most cases, you should always keep this to 0. // Default value: 0 -// Possible values: 0 or 1 +// Possible values: 0 or 1 (no strict CSRF test, only test on referer) or 2 (no CSRF test at all) // Examples: // $dolibarr_nocsrfcheck='0'; // diff --git a/htdocs/core/class/cgenericdic.class.php b/htdocs/core/class/cgenericdic.class.php index ab1023b81f5..250fb3ec569 100644 --- a/htdocs/core/class/cgenericdic.class.php +++ b/htdocs/core/class/cgenericdic.class.php @@ -82,6 +82,8 @@ class CGenericDic $fieldlabel = 'label'; if ($this->table_element == 'c_stcomm') { $fieldlabel = 'libelle'; + } elseif ($this->table_element == 'c_type_fees') { + $fieldrowid = 'id'; } $error = 0; @@ -162,6 +164,8 @@ class CGenericDic if ($this->table_element == 'c_stcomm') { $fieldrowid = 'id'; $fieldlabel = 'libelle'; + } elseif ($this->table_element == 'c_type_fees') { + $fieldrowid = 'id'; } $sql = "SELECT"; @@ -233,6 +237,8 @@ class CGenericDic if ($this->table_element == 'c_stcomm') { $fieldrowid = 'id'; $fieldlabel = 'libelle'; + } elseif ($this->table_element == 'c_type_fees') { + $fieldrowid = 'id'; } $sql = "SELECT"; @@ -303,6 +309,8 @@ class CGenericDic if ($this->table_element == 'c_stcomm') { $fieldrowid = 'id'; $fieldlabel = 'libelle'; + } elseif ($this->table_element == 'c_type_fees') { + $fieldrowid = 'id'; } // Clean parameters diff --git a/htdocs/core/class/commondocgenerator.class.php b/htdocs/core/class/commondocgenerator.class.php index 33f0b369c14..33d5e5a97c6 100644 --- a/htdocs/core/class/commondocgenerator.class.php +++ b/htdocs/core/class/commondocgenerator.class.php @@ -553,6 +553,12 @@ abstract class CommonDocGenerator $resarray[$array_key.'_project_description'] = $object->project->description; $resarray[$array_key.'_project_date_start'] = dol_print_date($object->project->date_start, 'day'); $resarray[$array_key.'_project_date_end'] = dol_print_date($object->project->date_end, 'day'); + } else { // empty replacement + $resarray[$array_key.'_project_ref'] =''; + $resarray[$array_key.'_project_title'] = ''; + $resarray[$array_key.'_project_description'] = ''; + $resarray[$array_key.'_project_date_start'] = ''; + $resarray[$array_key.'_project_date_end'] = ''; } // Add vat by rates @@ -716,6 +722,14 @@ abstract class CommonDocGenerator foreach ($tmpproduct->array_options as $key => $label) { $resarray["line_product_".$key] = $label; } + } else { + // Set unused placeholders as blank + $extrafields->fetch_name_optionals_label("product"); + $extralabels = $extrafields->attributes["product"]['label']; + + foreach ($extralabels as $key => $label) { + $resarray['line_product_options_'.$key] = ''; + } } return $resarray; diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index f1b83861ef5..98836dff8cc 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -4320,7 +4320,7 @@ abstract class CommonObject * @param string $field_select name of field we need to get a list * @param string $field_where name of field of object we need to get linked items * @param string $table_element name of association table - * @return array Array of record + * @return array|int Array of record, -1 if empty */ public static function getAllItemsLinkedByObjectID($fk_object_where, $field_select, $field_where, $table_element) { @@ -6114,6 +6114,8 @@ abstract class CommonObject if (!empty($extrafields->attributes[$this->table_element]) && !empty($extrafields->attributes[$this->table_element]['computed'][$key])) { //var_dump($conf->disable_compute); if (empty($conf->disable_compute)) { + global $objectoffield; // We set a global variable to $objectoffield so + $objectoffield = $this; // we can use it inside computed formula $this->array_options["options_".$key] = dol_eval($extrafields->attributes[$this->table_element]['computed'][$key], 1, 0, ''); } } diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index c6cf71fbe44..7de2938e299 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -202,9 +202,10 @@ class Form * @param string $paramid Key of parameter for id ('id', 'socid') * @param string $gm 'auto' or 'tzuser' or 'tzuserrel' or 'tzserver' (when $typeofdata is a date) * @param array $moreoptions Array with more options. For example array('addnowlink'=>1), array('valuealreadyhtmlescaped'=>1) + * @param string $editaction [=''] use GETPOST default action or set action to edit mode * @return string HTML edit field */ - public function editfieldval($text, $htmlname, $value, $object, $perm, $typeofdata = 'string', $editvalue = '', $extObject = null, $custommsg = null, $moreparam = '', $notabletag = 1, $formatfunc = '', $paramid = 'id', $gm = 'auto', $moreoptions = array()) + public function editfieldval($text, $htmlname, $value, $object, $perm, $typeofdata = 'string', $editvalue = '', $extObject = null, $custommsg = null, $moreparam = '', $notabletag = 1, $formatfunc = '', $paramid = 'id', $gm = 'auto', $moreoptions = array(), $editaction = '') { global $conf, $langs; @@ -233,7 +234,10 @@ class Form if (!empty($conf->global->MAIN_USE_JQUERY_JEDITABLE) && !preg_match('/^select;|day|datepicker|dayhour|datehourpicker/', $typeofdata)) { // TODO add jquery timepicker and support select $ret .= $this->editInPlace($object, $value, $htmlname, $perm, $typeofdata, $editvalue, $extObject, $custommsg); } else { - $editmode = (GETPOST('action', 'aZ09') == 'edit'.$htmlname); + if ($editaction == '') { + $editaction = GETPOST('action', 'aZ09'); + } + $editmode = ($editaction == 'edit'.$htmlname); if ($editmode) { $ret .= "\n"; $ret .= '
'; diff --git a/htdocs/core/db/sqlite3.class.php b/htdocs/core/db/sqlite3.class.php index 8c10c26d464..40d0f10baa8 100644 --- a/htdocs/core/db/sqlite3.class.php +++ b/htdocs/core/db/sqlite3.class.php @@ -316,7 +316,7 @@ class DoliDBSqlite3 extends DoliDB * @param string $passwd password * @param string $name name of database (not used for mysql, used for pgsql) * @param integer $port Port of database server - * @return SQLite3 Database access handler + * @return SQLite3|string Database access handler * @see close() */ public function connect($host, $login, $passwd, $name, $port = 0) diff --git a/htdocs/core/lib/admin.lib.php b/htdocs/core/lib/admin.lib.php index 92895793082..29d9a9710c8 100644 --- a/htdocs/core/lib/admin.lib.php +++ b/htdocs/core/lib/admin.lib.php @@ -696,11 +696,12 @@ function dolibarr_set_const($db, $name, $value, $type = 'chaine', $visible = 0, /** * Prepare array with list of tabs * - * @param int $nbofactivatedmodules Number if activated modules - * @param int $nboftotalmodules Nb of total modules - * @return array Array of tabs to show + * @param int $nbofactivatedmodules Number if activated modules + * @param int $nboftotalmodules Nb of total modules + * @param int $nbmodulesnotautoenabled Nb of modules not auto enabled that are activated + * @return array Array of tabs to show */ -function modules_prepare_head($nbofactivatedmodules, $nboftotalmodules) +function modules_prepare_head($nbofactivatedmodules, $nboftotalmodules, $nbmodulesnotautoenabled) { global $langs, $conf, $user, $form; @@ -711,7 +712,7 @@ function modules_prepare_head($nbofactivatedmodules, $nboftotalmodules) $head = array(); $mode = empty($conf->global->MAIN_MODULE_SETUP_ON_LIST_BY_DEFAULT) ? 'commonkanban' : $conf->global->MAIN_MODULE_SETUP_ON_LIST_BY_DEFAULT; $head[$h][0] = DOL_URL_ROOT."/admin/modules.php?mode=".$mode; - if ($nbofactivatedmodules <= (empty($conf->global->MAIN_MIN_NB_ENABLED_MODULE_FOR_WARNING) ? 1 : $conf->global->MAIN_MIN_NB_ENABLED_MODULE_FOR_WARNING)) { // If only minimal initial modules enabled) + if ($nbmodulesnotautoenabled <= getDolGlobalInt('MAIN_MIN_NB_ENABLED_MODULE_FOR_WARNING', 1)) { // If only minimal initial modules enabled) //$head[$h][1] = $form->textwithpicto($langs->trans("AvailableModules"), $desc); $head[$h][1] = $langs->trans("AvailableModules"); $head[$h][1] .= $form->textwithpicto('', $langs->trans("YouMustEnableOneModule").'.

'.$desc.'', 1, 'warning'); diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 55c315807ca..f1d702a3a32 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -8959,10 +8959,12 @@ 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; global $action, $mainmenu, $leftmenu; + global $mysoc; + global $objectoffield; + + // Old variables used global $rights; global $object; - global $mysoc; - 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 diff --git a/htdocs/core/lib/hrm.lib.php b/htdocs/core/lib/hrm.lib.php index 5335dc1c75e..706af6bd110 100644 --- a/htdocs/core/lib/hrm.lib.php +++ b/htdocs/core/lib/hrm.lib.php @@ -52,15 +52,15 @@ function establishment_prepare_head($object) $head[$h][2] = 'info'; $h++; - $head[$h][0] = dol_buildpath("/hrm/admin/setup.php", 1); - $head[$h][1] = $langs->trans("Settings"); - $head[$h][2] = 'settings'; - $h++; + // $head[$h][0] = dol_buildpath("/hrm/admin/setup.php", 1); + // $head[$h][1] = $langs->trans("Settings"); + // $head[$h][2] = 'settings'; + // $h++; - $head[$h][0] = dol_buildpath("/hrm/admin/about.php", 1); - $head[$h][1] = $langs->trans("About"); - $head[$h][2] = 'about'; - $h++; + // $head[$h][0] = dol_buildpath("/hrm/admin/about.php", 1); + // $head[$h][1] = $langs->trans("About"); + // $head[$h][2] = 'about'; + // $h++; complete_head_from_modules($conf, $langs, null, $head, $h, 'hrm'); diff --git a/htdocs/core/lib/resource.lib.php b/htdocs/core/lib/resource.lib.php index ebfbaf224f6..1fa2aa2f2e1 100644 --- a/htdocs/core/lib/resource.lib.php +++ b/htdocs/core/lib/resource.lib.php @@ -1,7 +1,8 @@ - * Copyright (C) 2016 Gilles Poirier + * Copyright (C) 2013 Jean-François Ferry + * Copyright (C) 2016 Gilles Poirier + * Copyright (C) 2023 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 @@ -26,7 +27,7 @@ /** * Prepare head for tabs * - * @param Object $object Object + * @param Dolresource $object Object * @return array Array of head entries */ function resource_prepare_head($object) @@ -114,7 +115,10 @@ function resource_prepare_head($object) function resource_admin_prepare_head() { - global $langs, $conf, $user; + global $conf, $db, $langs, $user; + + $extrafields = new ExtraFields($db); + $extrafields->fetch_name_optionals_label('resource'); $h = 0; $head = array(); @@ -132,6 +136,10 @@ function resource_admin_prepare_head() $head[$h][0] = DOL_URL_ROOT.'/admin/resource_extrafields.php'; $head[$h][1] = $langs->trans("ExtraFields"); + $nbExtrafields = $extrafields->attributes['resource']['count']; + if ($nbExtrafields > 0) { + $head[$h][1] .= ''.$nbExtrafields.''; + } $head[$h][2] = 'attributes'; $h++; diff --git a/htdocs/core/menus/standard/eldy.lib.php b/htdocs/core/menus/standard/eldy.lib.php index a4ca1d290a1..76ee88fda2d 100644 --- a/htdocs/core/menus/standard/eldy.lib.php +++ b/htdocs/core/menus/standard/eldy.lib.php @@ -1087,18 +1087,21 @@ function get_left_menu_home($mainmenu, &$newmenu, $usemenuhider = 1, $leftmenu = $newmenu->add("/admin/index.php?mainmenu=home&leftmenu=setup", $langs->trans("Setup"), 0, $user->admin, '', $mainmenu, 'setup', 0, '', '', '', ''); if ($usemenuhider || empty($leftmenu) || $leftmenu == "setup") { + $nbmodulesnotautoenabled = count($conf->modules); + if (in_array('fckeditor', $conf->modules)) $nbmodulesnotautoenabled--; + if (in_array('export', $conf->modules)) $nbmodulesnotautoenabled--; + if (in_array('import', $conf->modules)) $nbmodulesnotautoenabled--; + // Load translation files required by the page $langs->loadLangs(array("admin", "help")); - $warnpicto = ''; if (empty($conf->global->MAIN_INFO_SOCIETE_NOM) || empty($conf->global->MAIN_INFO_SOCIETE_COUNTRY)) { $langs->load("errors"); $warnpicto = img_warning($langs->trans("WarningMandatorySetupNotComplete")); } $newmenu->add("/admin/company.php?mainmenu=home", $langs->trans("MenuCompanySetup").$warnpicto, 1); - $warnpicto = ''; - if (count($conf->modules) <= (empty($conf->global->MAIN_MIN_NB_ENABLED_MODULE_FOR_WARNING) ? 1 : $conf->global->MAIN_MIN_NB_ENABLED_MODULE_FOR_WARNING)) { // If only user module enabled + if ($nbmodulesnotautoenabled <= getDolGlobalInt('MAIN_MIN_NB_ENABLED_MODULE_FOR_WARNING', 1)) { // If only user module enabled $langs->load("errors"); $warnpicto = img_warning($langs->trans("WarningMandatorySetupNotComplete")); } diff --git a/htdocs/core/modules/DolibarrModules.class.php b/htdocs/core/modules/DolibarrModules.class.php index 8e6bd78632d..e0d7a8741a5 100644 --- a/htdocs/core/modules/DolibarrModules.class.php +++ b/htdocs/core/modules/DolibarrModules.class.php @@ -365,12 +365,16 @@ class DolibarrModules // Can not be abstract, because we need to instantiate it */ public $phpmin; + public $phpmax; + /** * @var array Minimum version of Dolibarr required by module. * e.g.: Dolibarr ≥ 3.6 = array(3, 6) */ public $need_dolibarr_version; + public $enabled_bydefault; + /** * @var bool Whether to hide the module. */ 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 f5dcfb86936..e8fc6325001 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 @@ -336,15 +336,19 @@ class doc_generic_invoice_odt extends ModelePDFFactures $object->fetchObjectLinked('', '', '', ''); //print_r($object->linkedObjects['propal']); exit; - $propal_object = $object->linkedObjects['propal'][0]; + if (isset($object->linkedObjects['propal'][0])) { + $propal_object = $object->linkedObjects['propal'][0]; + } else { + $propal_object = null; + } // 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 + '__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 @@ -435,8 +439,8 @@ class doc_generic_invoice_odt extends ModelePDFFactures } else { $odfHandler->setVars($key, 'ErrorFileNotFound', true, 'UTF-8'); } - } else // Text - { + } else { + // Text $odfHandler->setVars($key, $value, true, 'UTF-8'); } } catch (OdfException $e) { diff --git a/htdocs/core/modules/modFckeditor.class.php b/htdocs/core/modules/modFckeditor.class.php index 9dd3fce7fcd..76d8ba4eb23 100644 --- a/htdocs/core/modules/modFckeditor.class.php +++ b/htdocs/core/modules/modFckeditor.class.php @@ -63,7 +63,7 @@ class modFckeditor extends DolibarrModules $this->config_page_url = array("fckeditor.php"); // Dependencies - $this->disabled = in_array(constant('JS_CKEDITOR'), array('disabled', 'disabled/')); + $this->disabled = (defined('JS_CKEDITOR') && in_array(constant('JS_CKEDITOR'), array('disabled', 'disabled/'))); $this->depends = array(); $this->requiredby = array('modWebsites'); $this->enabled_bydefault = true; // Will be enabled during install diff --git a/htdocs/don/class/api_donations.class.php b/htdocs/don/class/api_donations.class.php index f9af0568bf0..eee681cea7b 100644 --- a/htdocs/don/class/api_donations.class.php +++ b/htdocs/don/class/api_donations.class.php @@ -295,7 +295,7 @@ class Donations extends DolibarrApi * @throws RestException 404 * @throws RestException 500 System error * - * @return array + * @return object */ public function validate($id, $idwarehouse = 0, $notrigger = 0) { diff --git a/htdocs/ecm/class/ecmdirectory.class.php b/htdocs/ecm/class/ecmdirectory.class.php index fb9b2a35dd0..21a43565a25 100644 --- a/htdocs/ecm/class/ecmdirectory.class.php +++ b/htdocs/ecm/class/ecmdirectory.class.php @@ -633,7 +633,7 @@ class EcmDirectory extends CommonObject * level Level of line (Added by buildPathFromId call) * * @param int $force Force reload of full arbo even if already loaded in cache $this->cats - * @return array Tableau de array + * @return array|int Tableau de array if OK, -1 if KO */ public function get_full_arbo($force = 0) { diff --git a/htdocs/expedition/class/api_shipments.class.php b/htdocs/expedition/class/api_shipments.class.php index 450fe943d7e..6a753a24cdb 100644 --- a/htdocs/expedition/class/api_shipments.class.php +++ b/htdocs/expedition/class/api_shipments.class.php @@ -502,7 +502,7 @@ class Shipments extends DolibarrApi * * @url POST {id}/validate * - * @return array + * @return object * \todo An error 403 is returned if the request has an empty body. * Error message: "Forbidden: Content type `text/plain` is not supported." * Workaround: send this in the body @@ -630,7 +630,7 @@ class Shipments extends DolibarrApi * * @url POST {id}/close * - * @return int + * @return object */ public function close($id, $notrigger = 0) { diff --git a/htdocs/expensereport/class/expensereport.class.php b/htdocs/expensereport/class/expensereport.class.php index 685626ef6ff..a9f4a43bdd9 100644 --- a/htdocs/expensereport/class/expensereport.class.php +++ b/htdocs/expensereport/class/expensereport.class.php @@ -2763,6 +2763,11 @@ class ExpenseReportLine extends CommonObjectLine */ public $db; + /** + * @var string Name of table without prefix where object is stored + */ + public $table_element = 'expensereport_det'; + /** * @var string Error code (or message) */ diff --git a/htdocs/fichinter/class/api_interventions.class.php b/htdocs/fichinter/class/api_interventions.class.php index 14fc9f16fcf..78b324c288d 100644 --- a/htdocs/fichinter/class/api_interventions.class.php +++ b/htdocs/fichinter/class/api_interventions.class.php @@ -336,9 +336,10 @@ class Interventions extends DolibarrApi * * @param int $id Intervention ID * @param int $notrigger 1=Does not execute triggers, 0= execute triggers - * @return Object Object with cleaned properties * * @url POST {id}/validate + * + * @return Object */ public function validate($id, $notrigger = 0) { @@ -371,9 +372,10 @@ class Interventions extends DolibarrApi * Close an intervention * * @param int $id Intervention ID - * @return Object Object with cleaned properties * * @url POST {id}/close + * + * @return Object */ public function closeFichinter($id) { diff --git a/htdocs/filefunc.inc.php b/htdocs/filefunc.inc.php index a5b5264052d..196e0be75f2 100644 --- a/htdocs/filefunc.inc.php +++ b/htdocs/filefunc.inc.php @@ -206,7 +206,7 @@ include_once DOL_DOCUMENT_ROOT.'/core/lib/security.lib.php'; // when we post forms (we allow GET and HEAD to accept direct link from a particular page). // Note about $_SERVER[HTTP_HOST/SERVER_NAME]: http://shiflett.org/blog/2006/mar/server-name-versus-http-host // See also CSRF protections done into main.inc.php -if (!defined('NOCSRFCHECK') && empty($dolibarr_nocsrfcheck)) { +if (!defined('NOCSRFCHECK') && isset($dolibarr_nocsrfcheck) && $dolibarr_nocsrfcheck == 1) { // If $dolibarr_nocsrfcheck is 0, there is a strict CSRF test with token in main if (!empty($_SERVER['REQUEST_METHOD']) && !in_array($_SERVER['REQUEST_METHOD'], array('GET', 'HEAD')) && !empty($_SERVER['HTTP_HOST'])) { $csrfattack = false; if (empty($_SERVER['HTTP_REFERER'])) { diff --git a/htdocs/fourn/class/fournisseur.product.class.php b/htdocs/fourn/class/fournisseur.product.class.php index a01c8ec00d3..4245afe62b5 100644 --- a/htdocs/fourn/class/fournisseur.product.class.php +++ b/htdocs/fourn/class/fournisseur.product.class.php @@ -673,7 +673,7 @@ class ProductFournisseur extends Product * @param int $limit Limit * @param int $offset Offset * @param int $socid Filter on a third party id - * @return array Array of ProductFournisseur with new properties to define supplier price + * @return array|int Array of ProductFournisseur with new properties to define supplier price */ public function list_product_fournisseur_price($prodid, $sortfield = '', $sortorder = '', $limit = 0, $offset = 0, $socid = 0) { @@ -1042,7 +1042,7 @@ class ProductFournisseur extends Product * @param string $sortorder Sort order * @param int $limit Limit * @param int $offset Offset - * @return array Array of Log prices + * @return array|int Array of Log prices */ public function listProductFournisseurPriceLog($product_fourn_price_id, $sortfield = '', $sortorder = '', $limit = 0, $offset = 0) { diff --git a/htdocs/hrm/establishment/info.php b/htdocs/hrm/establishment/info.php index 3bfbe912279..1a9ba129f10 100644 --- a/htdocs/hrm/establishment/info.php +++ b/htdocs/hrm/establishment/info.php @@ -138,7 +138,7 @@ if ($object->id > 0) { // Object card // ------------------------------------------------------------ - $linkback = ''.$langs->trans("BackToList").''; + $linkback = ''.$langs->trans("BackToList").''; $morehtmlref = '
'; /* diff --git a/htdocs/index.php b/htdocs/index.php index f1ce8248921..dd1e36d04f8 100644 --- a/htdocs/index.php +++ b/htdocs/index.php @@ -42,12 +42,17 @@ $hookmanager->initHooks(array('index')); * Actions */ +$nbmodulesnotautoenabled = count($conf->modules); +if (in_array('fckeditor', $conf->modules)) $nbmodulesnotautoenabled--; +if (in_array('export', $conf->modules)) $nbmodulesnotautoenabled--; +if (in_array('import', $conf->modules)) $nbmodulesnotautoenabled--; + // Check if company name is defined (first install) if (!isset($conf->global->MAIN_INFO_SOCIETE_NOM) || empty($conf->global->MAIN_INFO_SOCIETE_NOM)) { header("Location: ".DOL_URL_ROOT."/admin/index.php?mainmenu=home&leftmenu=setup&mesg=setupnotcomplete"); exit; } -if (count($conf->modules) <= (empty($conf->global->MAIN_MIN_NB_ENABLED_MODULE_FOR_WARNING) ? 1 : $conf->global->MAIN_MIN_NB_ENABLED_MODULE_FOR_WARNING)) { // If only user module enabled +if ($nbmodulesnotautoenabled <= getDolGlobalString('MAIN_MIN_NB_ENABLED_MODULE_FOR_WARNING', 1)) { // If only user module enabled header("Location: ".DOL_URL_ROOT."/admin/index.php?mainmenu=home&leftmenu=setup&mesg=setupnotcomplete"); exit; } diff --git a/htdocs/install/mysql/data/llx_c_availability.sql b/htdocs/install/mysql/data/llx_c_availability.sql index b98db76b48e..7768477c5d1 100644 --- a/htdocs/install/mysql/data/llx_c_availability.sql +++ b/htdocs/install/mysql/data/llx_c_availability.sql @@ -33,6 +33,11 @@ -- INSERT INTO llx_c_availability (code, label, type_duration, qty, active, position) VALUES ('AV_NOW', 'Immediate', null, 0, 1, 10); +INSERT INTO llx_c_availability (code, label, type_duration, qty, active, position) VALUES ('AV_1D', '1 day', 'd', 1, 1, 11); +INSERT INTO llx_c_availability (code, label, type_duration, qty, active, position) VALUES ('AV_2D', '2 days', 'd', 2, 1, 12); +INSERT INTO llx_c_availability (code, label, type_duration, qty, active, position) VALUES ('AV_3D', '3 days', 'd', 3, 1, 13); +INSERT INTO llx_c_availability (code, label, type_duration, qty, active, position) VALUES ('AV_4D', '4 days', 'd', 4, 1, 14); +INSERT INTO llx_c_availability (code, label, type_duration, qty, active, position) VALUES ('AV_5D', '5 days', 'd', 5, 1, 15); INSERT INTO llx_c_availability (code, label, type_duration, qty, active, position) VALUES ('AV_1W', '1 week', 'w', 1, 1, 20); INSERT INTO llx_c_availability (code, label, type_duration, qty, active, position) VALUES ('AV_2W', '2 weeks', 'w', 2, 1, 30); INSERT INTO llx_c_availability (code, label, type_duration, qty, active, position) VALUES ('AV_3W', '3 weeks', 'w', 3, 1, 40); diff --git a/htdocs/install/step5.php b/htdocs/install/step5.php index fc0dcf37799..6598843b882 100644 --- a/htdocs/install/step5.php +++ b/htdocs/install/step5.php @@ -29,6 +29,7 @@ * For installation: * It creates the login admin and set the MAIN_SECURITY_SALT to a random value. * It set the value for MAIN_VERSION_LAST_INSTALL + * It activates some modules * It creates the install.lock and shows the final message. * For upgrade: * It updates the value for MAIN_VERSION_LAST_UPGRADE. @@ -42,6 +43,7 @@ if (file_exists($conffile)) { } require_once $dolibarr_main_document_root.'/core/lib/admin.lib.php'; require_once $dolibarr_main_document_root.'/core/lib/security.lib.php'; // for dol_hash +require_once $dolibarr_main_document_root.'/core/lib/functions2.lib.php'; global $langs; @@ -287,6 +289,9 @@ if ($action == "set" || empty($action) || preg_match('/upgrade/i', $action)) { */ } + // List of modules to enable + $tmparray = array(); + // If we ask to force some modules to be enabled if (!empty($force_install_module)) { if (!defined('DOL_DOCUMENT_ROOT') && !empty($dolibarr_main_document_root)) { @@ -294,9 +299,53 @@ if ($action == "set" || empty($action) || preg_match('/upgrade/i', $action)) { } $tmparray = explode(',', $force_install_module); + } + + $modNameLoaded = array(); + + // Search modules dirs + $modulesdir[] = $dolibarr_main_document_root.'/core/modules/'; + + foreach ($modulesdir as $dir) { + // Load modules attributes in arrays (name, numero, orders) from dir directory + //print $dir."\n
"; + dol_syslog("Scan directory ".$dir." for module descriptor files (modXXX.class.php)"); + $handle = @opendir($dir); + if (is_resource($handle)) { + while (($file = readdir($handle)) !== false) { + if (is_readable($dir.$file) && substr($file, 0, 3) == 'mod' && substr($file, dol_strlen($file) - 10) == '.class.php') { + $modName = substr($file, 0, dol_strlen($file) - 10); + if ($modName) { + if (!empty($modNameLoaded[$modName])) { // In cache of already loaded modules ? + $mesg = "Error: Module ".$modName." was found twice: Into ".$modNameLoaded[$modName]." and ".$dir.". You probably have an old file on your disk.
"; + setEventMessages($mesg, null, 'warnings'); + dol_syslog($mesg, LOG_ERR); + continue; + } + + try { + $res = include_once $dir.$file; // A class already exists in a different file will send a non catchable fatal error. + if (class_exists($modName)) { + $objMod = new $modName($db); + $modNameLoaded[$modName] = $dir; + if (!empty($objMod->enabled_bydefault) && !in_array($file, $tmparray)) { + $tmparray[] = $file; + } + } + } catch (Exception $e) { + dol_syslog("Failed to load ".$dir.$file." ".$e->getMessage(), LOG_ERR); + } + } + } + } + } + } + + // Loop on each modules to activate it + if (!empty($tmparray)) { foreach ($tmparray as $modtoactivate) { $modtoactivatenew = preg_replace('/\.class\.php$/i', '', $modtoactivate); - print $langs->trans("ActivateModule", $modtoactivatenew).'
'; + //print $langs->trans("ActivateModule", $modtoactivatenew).'
'; $file = $modtoactivatenew.'.class.php'; dolibarr_install_syslog('step5: activate module file='.$file); @@ -307,8 +356,10 @@ if ($action == "set" || empty($action) || preg_match('/upgrade/i', $action)) { print 'ERROR: failed to activateModule() file='.$file; } } + //print '
'; } + // Now delete the flag to say install is complete dolibarr_install_syslog('step5: remove MAIN_NOT_INSTALLED const'); $resql = $db->query("DELETE FROM ".MAIN_DB_PREFIX."const WHERE ".$db->decrypt('name')." = 'MAIN_NOT_INSTALLED'"); if (!$resql) { diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang index 9706ffedb76..90e520cea25 100644 --- a/htdocs/langs/en_US/admin.lang +++ b/htdocs/langs/en_US/admin.lang @@ -1234,7 +1234,7 @@ SetupDescription4=%s -> %s

This software is a suite of m SetupDescription5=Other Setup menu entries manage optional parameters. SetupDescriptionLink=%s - %s SetupDescription3b=Basic parameters used to customize the default behavior of your application (e.g for country-related features). -SetupDescription4b=This software is a suite of many modules/applications. The modules related to your needs must be enabled and configured. Menu entries will appears with the activation of these modules. +SetupDescription4b=This software is a suite of many modules/applications. The modules related to your needs must be activated. Menu entries will appears with the activation of these modules. AuditedSecurityEvents=Security events that are audited NoSecurityEventsAreAduited=No security events are audited. You can enable them from menu %s Audit=Security events diff --git a/htdocs/langs/en_US/main.lang b/htdocs/langs/en_US/main.lang index 4c4d79398b2..a4457363d70 100644 --- a/htdocs/langs/en_US/main.lang +++ b/htdocs/langs/en_US/main.lang @@ -1223,5 +1223,5 @@ AddToContacts=Add address to my contacts LastAccess=Last access UploadAnImageToSeeAPhotoHere=Upload an image from the tab %s to see a photo here LastPasswordChangeDate=Last password change date -PublicVirtualCardUrl=Public virtual user card +PublicVirtualCardUrl=Virtual business card page TreeView=Tree view diff --git a/htdocs/langs/en_US/modulebuilder.lang b/htdocs/langs/en_US/modulebuilder.lang index 600dfba7227..3c442fcc84a 100644 --- a/htdocs/langs/en_US/modulebuilder.lang +++ b/htdocs/langs/en_US/modulebuilder.lang @@ -169,4 +169,7 @@ GeneratePermissions=I want to add the rights for this object GeneratePermissionsHelp=generate default rights for this object PermissionDeletedSuccesfuly=Permission has been successfully removed PermissionUpdatedSuccesfuly=Permission has been successfully updated -PermissionAddedSuccesfuly=Permission has been successfully added \ No newline at end of file +PermissionAddedSuccesfuly=Permission has been successfully added +MenuDeletedSuccessfuly=Menu has been successfully deleted +MenuAddedSuccessfuly=Menu has been successfully added +MenuUpdatedSuccessfuly=Menu has been successfully updated \ No newline at end of file diff --git a/htdocs/langs/fr_FR/modulebuilder.lang b/htdocs/langs/fr_FR/modulebuilder.lang index 3c4161941e8..c9c0b9ef1bc 100644 --- a/htdocs/langs/fr_FR/modulebuilder.lang +++ b/htdocs/langs/fr_FR/modulebuilder.lang @@ -169,4 +169,7 @@ GeneratePermissions=Je souhaite ajouter les droits pour cet objet GeneratePermissionsHelp=générer les droits par défault pour cet objet PermissionDeletedSuccesfuly=La permission a été supprimée avec succès PermissionUpdatedSuccesfuly=La permission a été mise à jour avec succès -PermissionAddedSuccesfuly= La permission a été ajoutée avec succès \ No newline at end of file +PermissionAddedSuccesfuly= La permission a été ajoutée avec succès +MenuDeletedSuccessfuly=Menu a été supprimé avec succès +MenuAddedSuccessfuly=Menu a été ajouté avec succès +MenuUpdatedSuccessfuly=Menu a été mise à jour avec succès \ No newline at end of file diff --git a/htdocs/modulebuilder/index.php b/htdocs/modulebuilder/index.php index 93f3e34bf2b..e52985e8c50 100644 --- a/htdocs/modulebuilder/index.php +++ b/htdocs/modulebuilder/index.php @@ -896,6 +896,17 @@ if ($dirins && $action == 'confirm_removefile' && !empty($module)) { // Init an object if ($dirins && $action == 'initobject' && $module && $objectname) { + // check if module is enabled + if (isModEnabled(strtolower($module))) { + $result = unActivateModule(strtolower($module)); + dolibarr_set_const($db, "MAIN_IHM_PARAMS_REV", (int) $conf->global->MAIN_IHM_PARAMS_REV + 1, 'chaine', 0, '', $conf->entity); + if ($result) { + setEventMessages($result, null, 'errors'); + } + header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=permissions&module='.$module); + setEventMessages($langs->trans('WarningModuleNeedRefrech', $langs->transnoentities($module)), null, 'warnings'); + } + $objectname = ucfirst($objectname); $dirins = $dirread = $listofmodules[strtolower($module)]['moduledescriptorrootpath']; @@ -1341,43 +1352,31 @@ if ($dirins && $action == 'initobject' && $module && $objectname) { // Regenerate left menu entry in descriptor for $objectname $stringtoadd = " \$this->menu[\$r++]=array( - // '' if this is a top menu. For left menu, use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode 'fk_menu'=>'fk_mainmenu=mymodule', - // This is a Left menu entry 'type'=>'left', 'titre'=>'List MyObject', 'mainmenu'=>'mymodule', 'leftmenu'=>'mymodule_myobject', 'url'=>'/mymodule/myobject_list.php', - // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. 'langs'=>'mymodule@mymodule', 'position'=>1100+\$r, - // Define condition to show or hide menu entry. Use '\$conf->mymodule->enabled' if entry must be visible if module is enabled. Use '\$leftmenu==\'system\'' to show if leftmenu system is selected. 'enabled'=>'\$conf->mymodule->enabled', - // Use 'perms'=>'\$user->rights->mymodule->level1->level2' if you want your menu with a permission rules 'perms'=>'1', 'target'=>'', - // 0=Menu for internal users, 1=external users, 2=both 'user'=>2, ); \$this->menu[\$r++]=array( - // '' if this is a top menu. For left menu, use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode 'fk_menu'=>'fk_mainmenu=mymodule,fk_leftmenu=mymodule_myobject', - // This is a Left menu entry 'type'=>'left', 'titre'=>'New MyObject', 'mainmenu'=>'mymodule', 'leftmenu'=>'mymodule_myobject', 'url'=>'/mymodule/myobject_card.php?action=create', - // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. 'langs'=>'mymodule@mymodule', 'position'=>1100+\$r, - // Define condition to show or hide menu entry. Use '\$conf->mymodule->enabled' if entry must be visible if module is enabled. Use '\$leftmenu==\'system\'' to show if leftmenu system is selected. 'enabled'=>'\$conf->mymodule->enabled', - // Use 'perms'=>'\$user->rights->mymodule->level1->level2' if you want your menu with a permission rules 'perms'=>'1', 'target'=>'', - // 0=Menu for internal users, 1=external users, 2=both 'user'=>2 );\n"; $stringtoadd = preg_replace('/MyObject/', $objectname, $stringtoadd); @@ -1389,8 +1388,28 @@ if ($dirins && $action == 'initobject' && $module && $objectname) { // TODO Allow a replace with regex using dolReplaceInFile with param arryreplacementisregex to 1 // TODO Avoid duplicate addition - dolReplaceInFile($moduledescriptorfile, array('END MODULEBUILDER LEFTMENU MYOBJECT */' => '*/'."\n".$stringtoadd."\n\t\t/* END MODULEBUILDER LEFTMENU MYOBJECT */")); - + // load class and check if menu exist with same object name + $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath']; + dol_include_once($pathtofile); + $class = 'mod'.$module; + if (class_exists($class)) { + try { + $moduleobj = new $class($db); + } catch (Exception $e) { + $error++; + dol_print_error($db, $e->getMessage()); + } + } + $menus = $moduleobj->menu; + $counter = 0 ; + foreach ($menus as $menu) { + if ($menu['leftmenu'] == strtolower($module).'_'.strtolower($objectname)) { + $counter++; + } + } + if (!$counter) { + dolReplaceInFile($moduledescriptorfile, array('/* END MODULEBUILDER LEFTMENU MYOBJECT */' => '/*LEFTMENU '.strtoupper($objectname).'*/'.$stringtoadd."\n\t\t".'/*END LEFTMENU '.strtoupper($objectname).'*/'."\n\t\t".'/* END MODULEBUILDER LEFTMENU MYOBJECT */')); + } // Add module descriptor to list of files to replace "MyObject' string with real name of object. $filetogenerate[] = 'core/modules/mod'.$module.'.class.php'; } @@ -1728,6 +1747,16 @@ if ($dirins && $action == 'confirm_deletemodule') { } if ($dirins && $action == 'confirm_deleteobject' && $objectname) { + // check if module is enabled (if it's disabled and send msg event) + if (isModEnabled(strtolower($module))) { + $result = unActivateModule(strtolower($module)); + dolibarr_set_const($db, "MAIN_IHM_PARAMS_REV", (int) $conf->global->MAIN_IHM_PARAMS_REV + 1, 'chaine', 0, '', $conf->entity); + if ($result) { + setEventMessages($result, null, 'errors'); + } + header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=permissions&module='.$module); + setEventMessages($langs->trans('WarningModuleNeedRefrech', $langs->transnoentities($module)), null, 'warnings'); + } if (preg_match('/[^a-z0-9_]/i', $objectname)) { $error++; setEventMessages($langs->trans("SpaceOrSpecialCharAreNotAllowed"), null, 'errors'); @@ -1766,53 +1795,43 @@ if ($dirins && $action == 'confirm_deleteobject' && $objectname) { ); //menu for the object selected - $stringtoedit = "\$this->menu[\$r++]=array( - // '' if this is a top menu. For left menu, use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode - 'fk_menu'=>'fk_mainmenu=".strtolower($module)."', - // This is a Left menu entry - 'type'=>'left', - 'titre'=>'List ".ucfirst($objectname)."', - 'mainmenu'=>'".strtolower($module)."', - 'leftmenu'=>'".strtolower($module)."_".strtolower($objectname)."', - 'url'=>'/".strtolower($module)."/".strtolower($objectname)."_list.php', - // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. - 'langs'=>'".strtolower($module)."@".strtolower($module)."', - 'position'=>1100+\$r, - // Define condition to show or hide menu entry. Use '\$conf->".strtolower($module)."->enabled' if entry must be visible if module is enabled. Use '\$leftmenu==\'system\'' to show if leftmenu system is selected. - 'enabled'=>'\$conf->".strtolower($module)."->enabled', - // Use 'perms'=>'\$user->rights->".strtolower($module)."->level1->level2' if you want your menu with a permission rules - 'perms'=>'1', - 'target'=>'', - // 0=Menu for internal users, 1=external users, 2=both - 'user'=>2, - ); - \$this->menu[\$r++]=array( - // '' if this is a top menu. For left menu, use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode - 'fk_menu'=>'fk_mainmenu=".strtolower($module).",fk_leftmenu=".strtolower($module)."_".strtolower($objectname)."', - // This is a Left menu entry - 'type'=>'left', - 'titre'=>'New ".ucfirst($objectname)."', - 'mainmenu'=>'".strtolower($module)."', - 'leftmenu'=>'".strtolower($module)."_".strtolower($objectname)."', - 'url'=>'/".strtolower($module)."/".strtolower($objectname)."_card.php?action=create', - // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. - 'langs'=>'".strtolower($module)."@".strtolower($module)."', - 'position'=>1100+\$r, - // Define condition to show or hide menu entry. Use '\$conf->".strtolower($module)."->enabled' if entry must be visible if module is enabled. Use '\$leftmenu==\'system\'' to show if leftmenu system is selected. - 'enabled'=>'\$conf->".strtolower($module)."->enabled', - // Use 'perms'=>'\$user->rights->".strtolower($module)."->level1->level2' if you want your menu with a permission rules - 'perms'=>'1', - 'target'=>'', - // 0=Menu for internal users, 1=external users, 2=both - 'user'=>2 - );"; + // load class and check if menu exist for this object + $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath']; + dol_include_once($pathtofile); + $class = 'mod'.$module; + if (class_exists($class)) { + try { + $moduleobj = new $class($db); + } catch (Exception $e) { + $error++; + dol_print_error($db, $e->getMessage()); + } + } + $menus = $moduleobj->menu; $moduledescriptorfile = $dirins.'/'.strtolower($module).'/core/modules/mod'.$module.'.class.php'; - $check = dolReplaceInFile($moduledescriptorfile, array($stringtoedit => '')); - if ($check > 0) { - dolReplaceInFile($moduledescriptorfile, array('/*'.strtoupper($objectname).'*/' => '')); + foreach ($menus as $menu) { + if ($menu['type'] == 'left' && $menu['leftmenu'] == strtolower($module).'_'.strtolower($objectname)) { + $left="\$this->menu[\$r++]=array( + 'fk_menu'=>'".$menu['fk_menu']."', + 'type'=>'".$menu['type']."', + 'titre'=>'".$menu['titre']."', + 'mainmenu'=>'".$menu['mainmenu']."', + 'leftmenu'=>'".$menu['leftmenu']."', + 'url'=>'".$menu['url']."', + 'langs'=>'".$menu['langs']."', + 'position'=>1100+\$r, + 'enabled'=>'".$menu['enabled']."', + 'perms'=>'".$menu['perms']."', + 'target'=>'".$menu['target']."', + 'user'=>".$menu['user'].", + );"; + dolReplaceInFile($moduledescriptorfile, array($left => '')); + } } + // Remarque : "\n" not handling yet + $check = dolReplaceInFile($moduledescriptorfile, array('/*LEFTMENU '.strtoupper($objectname).'*/'."\n" => '',"\t\t".'/*END LEFTMENU '.strtoupper($objectname).'*/'."\n" => '')); // regenerate permissions and delete them $rights = " @@ -1994,8 +2013,9 @@ if ($dirins && $action == 'addright' && !empty($module) && empty($cancel)) { $existRight = 0; $allObject = array(); - $nbOfPermissions = count($permissions); - for ($i =0; $i<$nbOfPermissions; $i++) { + $countPerms = count($permissions); + + for ($i =0; $i<$countPerms; $i++) { if ($permissions[$i][4] == $objectForPerms) { $counter++; if (count($permsForObject) < 3) { @@ -2004,9 +2024,10 @@ if ($dirins && $action == 'addright' && !empty($module) && empty($cancel)) { } $allObject[] = $permissions[$i][4]; } - $nbOfpermsInObj = count($permsForObject); + // check if label of object already exists - for ($j = 0; $j<$nbOfpermsInObj; $j++) { + $countPermsObj = count($permsForObject); + for ($j = 0; $j<$countPermsObj; $j++) { if (in_array($label, $permsForObject[$j])) { $existRight++; setEventMessages($langs->trans("ErrorExistingPermission", $langs->transnoentities($label), $langs->transnoentities($objectForPerms)), null, 'errors'); @@ -2037,6 +2058,7 @@ if ($dirins && $action == 'addright' && !empty($module) && empty($cancel)) { "; $moduledescriptorfile = $dirins.'/'.strtolower($module).'/core/modules/mod'.$module.'.class.php'; if (!$existRight) { + //var_dump(1);exit; dolReplaceInFile($moduledescriptorfile, array('/*END '.strtoupper($objectForPerms).'*/' => $rightToAdd.'/*END '.strtoupper($objectForPerms).'*/')); setEventMessages($langs->trans('PermissionAddedSuccesfuly'), null); } @@ -2099,13 +2121,18 @@ if ($dirins && GETPOST('action') == 'update_right' && GETPOST('modifyright')&& e $x1 = $permissions[$r-1][1]; $x2 = $permissions[$r-1][4]; $x3 = $permissions[$r-1][5]; - //check existing object permission - $permsForObject =array(); + //check existing object permission + $counter = 0; + $permsForObject =array(); + $permissions = $moduleobj->rights; + $firstRight = 0; + $existRight = 0; + $allObject = array(); - $allObject = array(); - $nbOfPermissions = count($permissions); - for ($i =0; $i<$nbOfPermissions; $i++) { + $countPerms = count($permissions); + for ($i =0; $i<$countPerms; $i++) { if ($permissions[$i][4] == $objectForPerms) { + $counter++; if (count($permsForObject) < 3) { $permsForObject[] = $permissions[$i]; } @@ -2114,8 +2141,8 @@ if ($dirins && GETPOST('action') == 'update_right' && GETPOST('modifyright')&& e } if ($label != $x1 && $crud != $x3) { - $x = count($permsForObject); - for ($j = 0; $j<$x; $j++) { + $countPermsObj = count($permsForObject); + for ($j = 0; $j<$countPermsObj; $j++) { if (in_array($label, $permsForObject[$j])) { $error++; setEventMessages($langs->trans("ErrorExistingPermission", $langs->transnoentities($label), $langs->transnoentities($objectForPerms)), null, 'errors'); @@ -2158,6 +2185,70 @@ if ($dirins && GETPOST('action') == 'update_right' && GETPOST('modifyright')&& e exit; } } +// Delete permission +if ($dirins && $action == 'confirm_deleteright' && !empty($module) && GETPOST('permskey', 'int')) { + $error = 0; + // load class and check if right exist + $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath']; + dol_include_once($pathtofile); + $class = 'mod'.$module; + if (class_exists($class)) { + try { + $moduleobj = new $class($db); + } catch (Exception $e) { + $error++; + dol_print_error($db, $e->getMessage()); + } + } + + $permissions = $moduleobj->rights; + $key = (int) GETPOST('permskey', 'int')-1; + //get permission want to delete from permissions array + $x1 = $permissions[$key][1]; + $x2 = $permissions[$key][4]; + $x3 = $permissions[$key][5]; + //prepare right want to delete + $rightTodelete = " + \$this->rights[\$r][0] = \$this->numero . sprintf('%02d', \$r + 1); + \$this->rights[\$r][1] = '$x1'; + \$this->rights[\$r][4] = '$x2'; + \$this->rights[\$r][5] = '$x3'; + \$r++; + "; + + + $moduledescriptorfile = $dirins.'/'.strtolower($module).'/core/modules/mod'.$module.'.class.php'; + $check = dolReplaceInFile($moduledescriptorfile, array($rightTodelete => ''."\n\t\t")); + if ($check > 0) { + //check if all permissions of object was deleted + $permsForObj = array(); + foreach ($permissions as $perms) { + $permsForObj[] = $perms[4]; + } + $permsForObj = array_count_values($permsForObj); + if ($permsForObj[$permissions[$key][4]] == 1) { + $delObjStart = dolReplaceInFile($moduledescriptorfile, array('/*'.strtoupper($permissions[$key][4].'*/') => '','/*END '.strtoupper($permissions[$key][4].'*/') => '')); + } + } + if (!$error) { + // check if module is enabled + if (isModEnabled(strtolower($module))) { + $result = unActivateModule(strtolower($module)); + dolibarr_set_const($db, "MAIN_IHM_PARAMS_REV", (int) $conf->global->MAIN_IHM_PARAMS_REV + 1, 'chaine', 0, '', $conf->entity); + if ($result) { + setEventMessages($result, null, 'errors'); + } + header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=permissions&module='.$module); + setEventMessages($langs->trans('PermissionDeletedSuccesfuly'), null); + setEventMessages($langs->trans('WarningModuleNeedRefrech', $langs->transnoentities($module)), null, 'warnings'); + exit; + } else { + header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=permissions&module='.$module); + setEventMessages($langs->trans('PermissionDeletedSuccesfuly'), null); + exit; + } + } +} // Save file if ($action == 'savefile' && empty($cancel)) { $relofcustom = basename($dirins); @@ -2269,6 +2360,91 @@ if ($action == 'reset' && $user->admin) { exit; } +// delete menu +if ($dirins && $action == 'confirm_deletemenu' && GETPOST('menukey', 'int')) { + // check if module is enabled + if (isModEnabled(strtolower($module))) { + $result = unActivateModule(strtolower($module)); + dolibarr_set_const($db, "MAIN_IHM_PARAMS_REV", (int) $conf->global->MAIN_IHM_PARAMS_REV + 1, 'chaine', 0, '', $conf->entity); + if ($result) { + setEventMessages($result, null, 'errors'); + } + header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=permissions&module='.$module); + setEventMessages($langs->trans('WarningModuleNeedRefrech', $langs->transnoentities($module)), null, 'warnings'); + } + // load class and check if menu exist + $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath']; + dol_include_once($pathtofile); + $class = 'mod'.$module; + if (class_exists($class)) { + try { + $moduleobj = new $class($db); + } catch (Exception $e) { + $error++; + dol_print_error($db, $e->getMessage()); + } + } + + $menus = $moduleobj->menu; + + $key = (int) GETPOST('menukey', 'int'); + $moduledescriptorfile = $dirins.'/'.strtolower($module).'/core/modules/mod'.$module.'.class.php'; + + + if ($menus[$key]['type'] == 'top') { + $menuTop = " + \$this->menu[\$r++] = array( + 'fk_menu'=>'".$menus[$key]['fk_menu']."', + 'type'=>'".$menus[$key]['type']."', + 'titre'=>'".$menus[$key]['titre']."', + 'prefix' => img_picto('', \$this->picto, 'class=\"paddingright pictofixedwidth valignmiddle\"'), + 'mainmenu'=>'".$menus[$key]['mainmenu']."', + 'leftmenu'=> '', + 'url'=>'".$menus[$key]['url']."', + 'langs'=>'".$menus[$key]['langs']."', + 'position'=>1000 + \$r, + 'enabled'=>'isModEnabled(\"".strtolower($module)."\")', + 'perms' =>'".$menus[$key]['perms']."', + 'target'=>'".$menus[$key]['target']."', + 'user'=>".$menus[$key]['user'].", + );"; + $check = dolReplaceInFile($moduledescriptorfile, array($menuTop => '',"\t\t".'/*TOPMENU '.strtolower($menus[$key]['titre']).'*/'."\n" => '', '/*END TOPMENU '.strtolower($menus[$key]['titre']).'*/'."\n\t\t" => '')); + } + if ($menus[$key]['type'] == 'left') { + $left="\$this->menu[\$r++]=array( + 'fk_menu'=>'".$menus[$key]['fk_menu']."', + 'type'=>'".$menus[$key]['type']."', + 'titre'=>'".$menus[$key]['titre']."', + 'mainmenu'=>'".$menus[$key]['mainmenu']."', + 'leftmenu'=>'".$menus[$key]['leftmenu']."', + 'url'=>'".$menus[$key]['url']."', + 'langs'=>'".$menus[$key]['langs']."', + 'position'=>1100+\$r, + 'enabled'=>'".$menus[$key]['enabled']."', + 'perms'=>'".$menus[$key]['perms']."', + 'target'=>'".$menus[$key]['target']."', + 'user'=>".$menus[$key]['user'].", + );"; + $check = dolReplaceInFile($moduledescriptorfile, array($left => '')); + + // check if still had menu created when initial object + // if not we delete the comments from file + $menuForObj = 0; + foreach ($menus as $menu) { + if ($menu['leftmenu'] == $menus[$key]['leftmenu']) { + $menuForObj++; + } + } + if ($menuForObj == 1) { + $extractObjName = explode("_", $menus[$key]['leftmenu']); + dolReplaceInFile($moduledescriptorfile, array('/*LEFTMENU '.strtoupper($extractObjName[1]).'*/'."\n" => '','/*END LEFTMENU '.strtoupper($extractObjName[1]).'*/' => '')); + } + } + + setEventMessages($langs->trans('MenuDeletedSuccessfuly'), null); + header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=menus&module='.$module); + exit; +} /* diff --git a/htdocs/product/card.php b/htdocs/product/card.php index ba1bc47046f..5f58678985a 100644 --- a/htdocs/product/card.php +++ b/htdocs/product/card.php @@ -1854,7 +1854,7 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) { if ($object->isService()) { $type = $langs->trans('Service'); } - //print load_fiche_titre($langs->trans('Modify').' '.$type.' : '.(is_object($object->oldcopy)?$object->oldcopy->ref:$object->ref), ""); + // print load_fiche_titre($langs->trans('Modify').' '.$type.' : '.(is_object($object->oldcopy)?$object->oldcopy->ref:$object->ref), ""); // Main official, simple, and not duplicated code print ''."\n"; @@ -1873,19 +1873,18 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) { // Ref if (empty($conf->global->MAIN_PRODUCT_REF_NOT_EDITABLE)) { - print ''.$langs->trans("Ref").''; + print ''.$langs->trans("Ref").''; } else { print ''.$langs->trans("Ref").''; } - // Label - print ''.$langs->trans("Label").''; + print ''.$langs->trans("Label").''; // Status To sell print ''.$langs->trans("Status").' ('.$langs->trans("Sell").')'; print ''; - if ($object->status_buy) { + if ((GETPOSTISSET('statut_buy') && GETPOST('statut_buy')) || (!GETPOSTISSET('statut_buy') && $object->status_buy)) { print ''; print ''; } else { @@ -1913,7 +1912,7 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) { if ($object->isProduct() || !empty($conf->global->STOCK_SUPPORTS_SERVICES)) { print ''.$langs->trans("ManageLotSerial").''; $statutarray = array('0' => $langs->trans("ProductStatusNotOnBatch"), '1' => $langs->trans("ProductStatusOnBatch"), '2' => $langs->trans("ProductStatusOnSerial")); - print $form->selectarray('status_batch', $statutarray, $object->status_batch); + print $form->selectarray('status_batch', $statutarray, (GETPOSTISSET('status_batch') ? GETPOST('status_batch') : $object->status_batch)); print ''; if (!empty($object->status_batch) || !empty($conf->use_javascript_ajax)) { $langs->load("admin"); @@ -2032,7 +2031,7 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) { // Default warehouse print ''.$langs->trans("DefaultWarehouse").''; print img_picto($langs->trans("DefaultWarehouse"), 'stock', 'class="pictofixedwidth"'); - print $formproduct->selectWarehouses($object->fk_default_warehouse, 'fk_default_warehouse', 'warehouseopen', 1); + print $formproduct->selectWarehouses((GETPOSTISSET('fk_default_warehouse') ? GETPOST('fk_default_warehouse') : $object->fk_default_warehouse), 'fk_default_warehouse', 'warehouseopen', 1); print ' '; print ''; /* @@ -2080,7 +2079,7 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) { if (empty($conf->global->PRODUCT_DISABLE_NATURE)) { // Nature print ''.$form->textwithpicto($langs->trans("NatureOfProductShort"), $langs->trans("NatureOfProductDesc")).''; - print $formproduct->selectProductNature('finished', $object->finished); + print $formproduct->selectProductNature('finished', (GETPOSTISSET('finished') ? GETPOST('finished') : $object->finished)); print ''; } } @@ -2088,7 +2087,7 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) { if (!$object->isService() && isModEnabled('bom')) { print ''.$form->textwithpicto($langs->trans("DefaultBOM"), $langs->trans("DefaultBOMDesc", $langs->transnoentitiesnoconv("Finished"))).''; $bomkey = "Bom:bom/class/bom.class.php:0:t.status=1 AND t.fk_product=".((int) $object->id); - print $form->selectForForms($bomkey, 'fk_default_bom', $object->fk_default_bom, 1); + print $form->selectForForms($bomkey, 'fk_default_bom', (GETPOSTISSET('fk_default_bom') ? GETPOST('fk_default_bom') : $object->fk_default_bom), 1); print ''; } @@ -2143,7 +2142,7 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) { // Custom code if (!$object->isService() && empty($conf->global->PRODUCT_DISABLE_CUSTOM_INFO)) { - print ''.$langs->trans("CustomCode").''; + print ''.$langs->trans("CustomCode").''; // Origin country print ''.$langs->trans("CountryOrigin").''; print ''; @@ -2196,6 +2195,11 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) { $arrayselected[] = $cat->id; } } + if (GETPOSTISSET('categories', 'array')) { + foreach (GETPOST('categories', 'array') as $cat) { + $arrayselected[] = $cat; + } + } print img_picto('', 'category').$form->multiselectarray('categories', $cate_arbo, $arrayselected, '', 0, 'quatrevingtpercent widthcentpercentminusx', 0, 0); print ""; } @@ -2221,76 +2225,76 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) { // Accountancy_code_sell print ''.$langs->trans("ProductAccountancySellCode").''; print ''; - print $formaccounting->select_account($object->accountancy_code_sell, 'accountancy_code_sell', 1, '', 1, 1, 'minwidth150 maxwidth300'); + print $formaccounting->select_account((GETPOSTISSET('accountancy_code_sell') ? GETPOST('accountancy_code_sell') : $object->accountancy_code_sell), 'accountancy_code_sell', 1, '', 1, 1, 'minwidth150 maxwidth300'); print ''; // Accountancy_code_sell_intra if ($mysoc->isInEEC()) { print ''.$langs->trans("ProductAccountancySellIntraCode").''; print ''; - print $formaccounting->select_account($object->accountancy_code_sell_intra, 'accountancy_code_sell_intra', 1, '', 1, 1, 'minwidth150 maxwidth300'); + print $formaccounting->select_account((GETPOSTISSET('accountancy_code_sell_intra') ? GETPOST('accountancy_code_sell_intra') : $object->accountancy_code_sell_intra), 'accountancy_code_sell_intra', 1, '', 1, 1, 'minwidth150 maxwidth300'); print ''; } // Accountancy_code_sell_export print ''.$langs->trans("ProductAccountancySellExportCode").''; print ''; - print $formaccounting->select_account($object->accountancy_code_sell_export, 'accountancy_code_sell_export', 1, '', 1, 1, 'minwidth150 maxwidth300'); + print $formaccounting->select_account((GETPOSTISSET('accountancy_code_sell_export') ? GETPOST('accountancy_code_sell_export') : $object->accountancy_code_sell_export), 'accountancy_code_sell_export', 1, '', 1, 1, 'minwidth150 maxwidth300'); print ''; // Accountancy_code_buy print ''.$langs->trans("ProductAccountancyBuyCode").''; print ''; - print $formaccounting->select_account($object->accountancy_code_buy, 'accountancy_code_buy', 1, '', 1, 1, 'minwidth150 maxwidth300'); + print $formaccounting->select_account((GETPOSTISSET('accountancy_code_buy') ? GETPOST('accountancy_code_buy') : $object->accountancy_code_buy), 'accountancy_code_buy', 1, '', 1, 1, 'minwidth150 maxwidth300'); print ''; // Accountancy_code_buy_intra if ($mysoc->isInEEC()) { print ''.$langs->trans("ProductAccountancyBuyIntraCode").''; print ''; - print $formaccounting->select_account($object->accountancy_code_buy_intra, 'accountancy_code_buy_intra', 1, '', 1, 1, 'minwidth150 maxwidth300'); + print $formaccounting->select_account((GETPOSTISSET('accountancy_code_buy_intra') ? GETPOST('accountancy_code_buy_intra') : $object->accountancy_code_buy_intra), 'accountancy_code_buy_intra', 1, '', 1, 1, 'minwidth150 maxwidth300'); print ''; } // Accountancy_code_buy_export print ''.$langs->trans("ProductAccountancyBuyExportCode").''; print ''; - print $formaccounting->select_account($object->accountancy_code_buy_export, 'accountancy_code_buy_export', 1, '', 1, 1, 'minwidth150 maxwidth300'); + print $formaccounting->select_account((GETPOSTISSET('accountancy_code_buy_export') ? GETPOST('accountancy_code_buy_export') : $object->accountancy_code_buy_export), 'accountancy_code_buy_export', 1, '', 1, 1, 'minwidth150 maxwidth300'); print ''; } else { // For external software // Accountancy_code_sell print ''.$langs->trans("ProductAccountancySellCode").''; - print ''; + print ''; print ''; // Accountancy_code_sell_intra if ($mysoc->isInEEC()) { print ''.$langs->trans("ProductAccountancySellIntraCode").''; - print ''; + print ''; print ''; } // Accountancy_code_sell_export print ''.$langs->trans("ProductAccountancySellExportCode").''; - print ''; + print ''; print ''; // Accountancy_code_buy print ''.$langs->trans("ProductAccountancyBuyCode").''; - print ''; + print ''; print ''; // Accountancy_code_buy_intra if ($mysoc->isInEEC()) { print ''.$langs->trans("ProductAccountancyBuyIntraCode").''; - print ''; + print ''; print ''; } // Accountancy_code_buy_export print ''.$langs->trans("ProductAccountancyBuyExportCode").''; - print ''; + print ''; print ''; } } diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index 6686b4fce8d..9db4565ca49 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -14,7 +14,7 @@ * Copyright (C) 2014 Ion agorria * Copyright (C) 2016-2018 Ferran Marcet * Copyright (C) 2017 Gustavo Novaro - * Copyright (C) 2019-2022 Frédéric France + * Copyright (C) 2019-2023 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 @@ -1566,7 +1566,7 @@ class Product extends CommonObject } } elseif (isset($this->multilangs[$key])) { if (empty($this->multilangs["$key"]["label"])) { - $this->error = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Label")); + $this->errors[] = $key . ' : ' . $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Label")); return -1; } @@ -4869,7 +4869,7 @@ class Product extends CommonObject /** * Return all parent products for current product (first level only) * - * @return array Array of product + * @return array|int Array of product * @see hasFatherOrChild() */ public function getFather() @@ -4911,7 +4911,7 @@ class Product extends CommonObject * @param int $firstlevelonly Return only direct child * @param int $level Level of recursing call (start to 1) * @param array $parents Array of all parents of $id - * @return array Return array(prodid=>array(0=prodid, 1=>qty, 2=>product type, 3=>label, 4=>incdec, 5=>product ref) + * @return array|int Return array(prodid=>array(0=prodid, 1=>qty, 2=>product type, 3=>label, 4=>incdec, 5=>product ref) */ public function getChildsArbo($id, $firstlevelonly = 0, $level = 1, $parents = array()) { diff --git a/htdocs/product/dynamic_price/class/price_global_variable_updater.class.php b/htdocs/product/dynamic_price/class/price_global_variable_updater.class.php index 317bc7fb5fd..d43a2e3bf56 100644 --- a/htdocs/product/dynamic_price/class/price_global_variable_updater.class.php +++ b/htdocs/product/dynamic_price/class/price_global_variable_updater.class.php @@ -367,7 +367,7 @@ class PriceGlobalVariableUpdater /** * List all price global variables * - * @return array Array of price global variable updaters + * @return array|int Array of price global variable updaters */ public function listUpdaters() { @@ -404,7 +404,7 @@ class PriceGlobalVariableUpdater /** * List all updaters which need to be processed * - * @return array Array of price global variable updaters + * @return array|int Array of price global variable updaters */ public function listPendingUpdaters() { diff --git a/htdocs/product/stock/class/entrepot.class.php b/htdocs/product/stock/class/entrepot.class.php index e6d3ecbd236..d201463b169 100644 --- a/htdocs/product/stock/class/entrepot.class.php +++ b/htdocs/product/stock/class/entrepot.class.php @@ -577,7 +577,7 @@ class Entrepot extends CommonObject /** * Return number of unique different product into a warehouse * - * @return Array Array('nb'=>Nb, 'value'=>Value) + * @return array|int Array('nb'=>Nb, 'value'=>Value) */ public function nb_different_products() { @@ -608,7 +608,7 @@ class Entrepot extends CommonObject /** * Return stock and value of warehosue * - * @return Array Array('nb'=>Nb, 'value'=>Value) + * @return array|int Array('nb'=>Nb, 'value'=>Value) */ public function nb_products() { diff --git a/htdocs/product/stock/productlot_card.php b/htdocs/product/stock/productlot_card.php index acf2f526773..a39d92f93aa 100644 --- a/htdocs/product/stock/productlot_card.php +++ b/htdocs/product/stock/productlot_card.php @@ -469,7 +469,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea print ''; print $form->editfieldkey($langs->trans('SellByDate'), 'sellby', $object->sellby, $object, $user->rights->stock->creer, 'datepicker'); print ''; - print $form->editfieldval($langs->trans('SellByDate'), 'sellby', $object->sellby, $object, $user->rights->stock->creer, 'datepicker'); + print $form->editfieldval($langs->trans('SellByDate'), 'sellby', $object->sellby, $object, $user->rights->stock->creer, 'datepicker', '', null, null, '', 1, '', 'id', 'auto', array(), $action); print ''; print ''; } @@ -479,7 +479,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea print ''; print $form->editfieldkey($langs->trans('EatByDate'), 'eatby', $object->eatby, $object, $user->rights->stock->creer, 'datepicker'); print ''; - print $form->editfieldval($langs->trans('EatByDate'), 'eatby', $object->eatby, $object, $user->rights->stock->creer, 'datepicker'); + print $form->editfieldval($langs->trans('EatByDate'), 'eatby', $object->eatby, $object, $user->rights->stock->creer, 'datepicker', '', null, null, '', 1, '', 'id', 'auto', array(), $action); print ''; print ''; } diff --git a/htdocs/projet/class/project.class.php b/htdocs/projet/class/project.class.php index adc617e55c2..20b0fb26e32 100644 --- a/htdocs/projet/class/project.class.php +++ b/htdocs/projet/class/project.class.php @@ -2345,4 +2345,29 @@ class Project extends CommonObject $this->lines = $taskstatic->getTasksArray(0, $user, $this->id, 0, 0, '', '-1', '', 0, 0, array(), 0, array(), 0, $loadRoleMode); } + + /** + * Function sending an email to the current member with the text supplied in parameter. + * + * @param string $text Content of message (not html entities encoded) + * @param string $subject Subject of message + * @param array $filename_list Array of attached files + * @param array $mimetype_list Array of mime types of attached files + * @param array $mimefilename_list Array of public names of attached files + * @param string $addr_cc Email cc + * @param string $addr_bcc Email bcc + * @param int $deliveryreceipt Ask a delivery receipt + * @param int $msgishtml 1=String IS already html, 0=String IS NOT html, -1=Unknown need autodetection + * @param string $errors_to erros to + * @param string $moreinheader Add more html headers + * @since V18 + * @return int <0 if KO, >0 if OK + */ + public function sendEmail($text, $subject, $filename_list = array(), $mimetype_list = array(), $mimefilename_list = array(), $addr_cc = "", $addr_bcc = "", $deliveryreceipt = 0, $msgishtml = -1, $errors_to = '', $moreinheader = '') + { + global $conf, $langs; + // TODO EMAIL + + return 1; + } } diff --git a/htdocs/public/members/new.php b/htdocs/public/members/new.php index 943280d6e2d..9ac60d8f823 100644 --- a/htdocs/public/members/new.php +++ b/htdocs/public/members/new.php @@ -372,7 +372,7 @@ if (empty($reshook) && $action == 'add') { if ($subjecttosend && $texttosend) { $moreinheader = 'X-Dolibarr-Info: send_an_email by public/members/new.php'."\r\n"; - $result = $object->send_an_email($texttosend, $subjecttosend, array(), array(), array(), "", "", 0, -1, '', $moreinheader); + $result = $object->sendEmail($texttosend, $subjecttosend, array(), array(), array(), "", "", 0, -1, '', $moreinheader); } /*if ($result < 0) { $error++; diff --git a/htdocs/public/partnership/new.php b/htdocs/public/partnership/new.php index af2583abece..d5d1dad1d81 100644 --- a/htdocs/public/partnership/new.php +++ b/htdocs/public/partnership/new.php @@ -360,7 +360,7 @@ if (empty($reshook) && $action == 'add') { if ($subjecttosend && $texttosend) { $moreinheader = 'X-Dolibarr-Info: send_an_email by public/members/new.php'."\r\n"; - $result = $object->send_an_email($texttosend, $subjecttosend, array(), array(), array(), "", "", 0, -1, '', $moreinheader); + $result = $object->sendEmail($texttosend, $subjecttosend, array(), array(), array(), "", "", 0, -1, '', $moreinheader); } } diff --git a/htdocs/public/payment/paymentok.php b/htdocs/public/payment/paymentok.php index 4a13de1ef7f..40898f1ff6e 100644 --- a/htdocs/public/payment/paymentok.php +++ b/htdocs/public/payment/paymentok.php @@ -775,7 +775,7 @@ if ($ispaymentok) { $moreinheader = 'X-Dolibarr-Info: send_an_email by public/payment/paymentok.php'."\r\n"; - $result = $object->send_an_email($texttosend, $subjecttosend, $listofpaths, $listofmimes, $listofnames, "", "", 0, -1, "", $moreinheader); + $result = $object->sendEmail($texttosend, $subjecttosend, $listofpaths, $listofmimes, $listofnames, "", "", 0, -1, "", $moreinheader); if ($result < 0) { $errmsg = $object->error; diff --git a/htdocs/public/project/new.php b/htdocs/public/project/new.php index c44002340d6..ec891fc3741 100644 --- a/htdocs/public/project/new.php +++ b/htdocs/public/project/new.php @@ -368,11 +368,10 @@ if (empty($reshook) && $action == 'add') { complete_substitutions_array($substitutionarray, $outputlangs, $object); $subjecttosend = make_substitutions($subject, $substitutionarray, $outputlangs); $texttosend = make_substitutions($msg, $substitutionarray, $outputlangs); - if ($subjecttosend && $texttosend) { $moreinheader = 'X-Dolibarr-Info: send_an_email by public/lead/new.php'."\r\n"; - $result = $object->send_an_email($texttosend, $subjecttosend, array(), array(), array(), "", "", 0, -1, '', $moreinheader); + $result = $object->sendEmail($texttosend, $subjecttosend, array(), array(), array(), "", "", 0, -1, '', $moreinheader); } /*if ($result < 0) { $error++; diff --git a/htdocs/reception/class/api_receptions.class.php b/htdocs/reception/class/api_receptions.class.php index ca46cb8909c..5e4c68fe468 100644 --- a/htdocs/reception/class/api_receptions.class.php +++ b/htdocs/reception/class/api_receptions.class.php @@ -499,10 +499,10 @@ class Receptions extends DolibarrApi * * @param int $id Reception ID * @param int $notrigger 1=Does not execute triggers, 0= execute triggers - * @return Object Object with cleaned properties * * @url POST {id}/validate * + * @return Object * \todo An error 403 is returned if the request has an empty body. * Error message: "Forbidden: Content type `text/plain` is not supported." * Workaround: send this in the body @@ -627,9 +627,10 @@ class Receptions extends DolibarrApi * * @param int $id Reception ID * @param int $notrigger Disabled triggers - * @return Object Object with cleaned properties * * @url POST {id}/close + * + * @return Object */ public function close($id, $notrigger = 0) { diff --git a/htdocs/reception/class/reception.class.php b/htdocs/reception/class/reception.class.php index e9a89691c88..018d532a363 100644 --- a/htdocs/reception/class/reception.class.php +++ b/htdocs/reception/class/reception.class.php @@ -11,7 +11,7 @@ * Copyright (C) 2015 Claudio Aschieri * Copyright (C) 2016-2022 Ferran Marcet * Copyright (C) 2018 Quentin Vial-Gouteyron - * Copyright (C) 2022 Frédéric France + * Copyright (C) 2022-2023 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 @@ -97,6 +97,12 @@ class Reception extends CommonObject public $date_delivery; // Date delivery planed + /** + * @var integer|string Effective delivery date + * @deprecated + * @see $date_reception + */ + public $date; /** * @var integer|string Effective delivery date @@ -396,8 +402,7 @@ class Reception extends CommonObject $this->statut = $obj->fk_statut; $this->user_author_id = $obj->fk_user_author; $this->date_creation = $this->db->jdate($obj->date_creation); - $this->date = $this->db->jdate($obj->date_reception); // TODO deprecated - $this->date_reception = $this->db->jdate($obj->date_reception); // TODO deprecated + $this->date = $this->db->jdate($obj->date_reception); // TODO deprecated $this->date_reception = $this->db->jdate($obj->date_reception); // Date real $this->date_delivery = $this->db->jdate($obj->date_delivery); // Date planed $this->model_pdf = $obj->model_pdf; diff --git a/htdocs/societe/class/api_thirdparties.class.php b/htdocs/societe/class/api_thirdparties.class.php index 9921167d00c..1a1b3818848 100644 --- a/htdocs/societe/class/api_thirdparties.class.php +++ b/htdocs/societe/class/api_thirdparties.class.php @@ -523,8 +523,8 @@ class Thirdparties extends DolibarrApi /** * Delete thirdparty * - * @param int $id Thirdparty ID - * @return array + * @param int $id Thirdparty ID + * @return array */ public function delete($id) { @@ -1351,10 +1351,10 @@ class Thirdparties extends DolibarrApi /** * Generate a Document from a bank account record (like SEPA mandate) * - * @param int $id Thirdparty id - * @param int $companybankid Companybank id - * @param string $model Model of document to generate - * @return array + * @param int $id Thirdparty id + * @param int $companybankid Companybank id + * @param string $model Model of document to generate + * @return array * * @url GET {id}/generateBankAccountDocument/{companybankid}/{model} */ diff --git a/htdocs/societe/paymentmodes.php b/htdocs/societe/paymentmodes.php index 87b1a4939df..b26db22261f 100644 --- a/htdocs/societe/paymentmodes.php +++ b/htdocs/societe/paymentmodes.php @@ -1459,7 +1459,7 @@ if ($socid && $action != 'edit' && $action != 'create' && $action != 'editcard' print ''; // Label - print ''.dol_escape_htmltag($rib->label).''; + print ''.dol_escape_htmltag($rib->label).''; // Stripe ID print ''; if ($rib->stripe_card_ref) { diff --git a/htdocs/supplier_proposal/class/supplier_proposal.class.php b/htdocs/supplier_proposal/class/supplier_proposal.class.php index fbd95b25738..6d7d7bc3720 100644 --- a/htdocs/supplier_proposal/class/supplier_proposal.class.php +++ b/htdocs/supplier_proposal/class/supplier_proposal.class.php @@ -1944,7 +1944,7 @@ class SupplierProposal extends CommonObject * @param int $offset For pagination * @param string $sortfield Sort criteria * @param string $sortorder Sort order - * @return int -1 if KO, array with result if OK + * @return array|int -1 if KO, array with result if OK */ public function liste_array($shortlist = 0, $draft = 0, $notcurrentuser = 0, $socid = 0, $limit = 0, $offset = 0, $sortfield = 'p.datec', $sortorder = 'DESC') { @@ -2225,7 +2225,7 @@ class SupplierProposal extends CommonObject * * @param User $user Object user * @param int $mode "opened" for askprice to close, "signed" for proposal to invoice - * @return int <0 if KO, >0 if OK + * @return WorkboardResponse|int <0 if KO, WorkboardResponse if OK */ public function load_board($user, $mode) {