diff --git a/ChangeLog b/ChangeLog index badefa033a3..ef931857be0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -9,27 +9,24 @@ For users: --------------- NEW: Minimal PHP version is now PHP 7.0 instead of PHP 5.6 -NEW: #21750 Added "Get lines and Post lines from BOM" at the REST Service NEW: #21780 Add pid field to Cronjob class and store PID on job execution -NEW: #19680 Add option PRODUCT_ALLOW_EXTERNAL_DOWNLOAD +NEW: #19680 Add option PRODUCT_ALLOW_EXTERNAL_DOWNLOAD to automatically have uploaded files shared publicly by a link NEW: #20650 can move the checkbox column on left (experimental option) -NEW: #21000 Added columns 'alias_name' on poject, supplier invoice, supplier order, supplier proposals and taks list +NEW: #21000 Added columns 'alias_name' on project, supplier invoice, supplier order, supplier proposals and task list 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: #21442 Enhancement of module builder init NEW: #21654 add bank account number used on invoices for debit -NEW: #21775 Template 03 manages send mails NEW: #22048 Added notes to productlot module -NEW: #22298 Bank - Add salaries & vat in tab planned entries +NEW: #22298 Bank - Add salaries & vat in the tab of planned entries of a bank account NEW: #22328 -NEW: #22370 Modulebuilder supports 'alwayseditable' (like extrafields) NEW: #22424 -NEW: #22500 member module set up made easier +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 partneships displayed on tab partnership of a thirdparty and member +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: #25594 can chose if VAT ID is unique or not for third parties @@ -57,7 +54,6 @@ NEW: Add hidden option MAIN_EMAIL_SUPPORT_ACK to restore Email ack checkbox (fea NEW: Add IMAP port setting on email collector module NEW: Adding JAPAN Chart-of-Account and regions/departments NEW: Adding NIF verification for Algeria -NEW: Add 4 other templates in website module NEW: Add link to create an element from the category page NEW: add margin infos to takepos invoice lines NEW: Add max size send for "backup and link to mail" option @@ -70,7 +66,7 @@ NEW: Add option FICHINTER_ALLOW_EXTERNAL_DOWNLOAD NEW: Add option --force on CLI cron_run_jobs.php NEW: Add option "Show price on the generated documents for receptions" NEW: Add performance index (name for company and contact) and llx_bank_url(url_id) -NEW: Add picto property on sub-module for paswword generation +NEW: Add picto property on sub-module for password generation NEW: Add price to product box in TakePOS NEW: add redirect on action confirm addconsumedline and addproduceline NEW: Add a new advanced permission "read price" @@ -89,7 +85,7 @@ NEW: Can enter the unit price including the vat NEW: Can invoice task time per different services NEW: Can join several files by default on email form NEW: Can send an email on scheduled job error -NEW: Can set a commercial discount by entereing amount including VAT +NEW: Can set a commercial discount by entering amount including VAT NEW: Can set a monthly frequency (or multiple) in cron tasks. NEW: Can set start and end dates and comment on button "Activate all services" NEW: can sort and preselected best supplier price @@ -98,6 +94,7 @@ NEW: Website Can remove a website template NEW: Website can set header "Strict-Transport-Security" in web sites. NEW: Website Can switch status of website and page from the website toolbar NEW: Website Templates of websites are now directories and not zip into core repo +NEW: Website Add 4 other templates in website module NEW: Can use products categories to make inventory NEW: Change filter type on tickets list into a multiselect combo NEW: conf TIMESPENT_ALWAYS_UPDATE_THM, when it's on we always check current thm of user to update it in task time line @@ -129,7 +126,6 @@ NEW: manage no email with thirdparties (better for GDPR) NEW: Manage Position (Rank) on Contract Lines NEW: Manage VAT on all lines on purchases cycle NEW: manage virtual stock at a future date -NEW: ModuleBuilder can generate code of class from an existing SQL table NEW: On a bank reconciled line, we can modify the bank receipt NEW: On a form to send an email, we show all emails of all contacts of object NEW: Option PRODUCTBATCH_SHOW_WAREHOUSE_ON_SHIPMENT showing wh on PDF @@ -137,7 +133,7 @@ NEW: Option PRODUIT_DESC_IN_FORM accept (desktop only or +smartphone) NEW: Page for mass stock transfer can be used with no source stock NEW: parent company column and filter in invoice and order list NEW: Add show "Sales rep" option for PDF -NEW: Picto for shared link is clicable +NEW: Picto for shared link is clickable NEW: possibility to select scopes with checkbox for Oauth tokens NEW: private and public note on user, thirdparty and contact list NEW: product categories filter on inventory list @@ -151,7 +147,7 @@ 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: set thirdparty type with company modify trigger -NEW: Show also shceduled task never finished in scheduled task widget +NEW: Show also scheduled task never finished in scheduled task widget NEW: show badge with number of extrafields in setup NEW: show category tree in sellist and chkbxlst for common object NEW: Show picto and color into combo for selection of tags @@ -163,17 +159,25 @@ NEW: SMTP using oauth2 authentication NEW: can substitue project title in mail template NEW: Supplier order list - Add column private and public note NEW: Support IP type in extrafields -NEW: support multilang in Civilities API NEW: Table of membership types 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: VAT - Admin - Add information on deadline day for submission of VAT declaration +NEW: expand/collapse permissions on user permission page +NEW: Show delivery mode on PDF for proposals +NEW: Add the target to select attendees of event for emailings + + Modules +NEW: Experimental module Asset For developers or integrators: ------------------------------ +NEW: ModuleBuilder can generate code of class from an existing SQL table +NEW: #22370 Modulebuilder supports 'alwayseditable' (like extrafields) NEW: #20912 Add trigger to record the event of sending an email from a project -NEW: Removed completely the need for library adodbtime +NEW: #21750 Added "Get lines and Post lines from BOM" at the REST Service +NEW: Removed completely the need for the library adodbtime NEW: hook on agenda pages NEW: hook to complete payment in TakePOS NEW: hook "changeHelpURL" to modify target of the help button @@ -184,6 +188,7 @@ NEW: Add new hooks for actioncomm NEW: conf->global->SYSLOG_FILE_ONEPERSESSION accept a string NEW: translate for contact type API, setup/ticket API, shipping method API NEW: All ajax pages have now a top_httphead() +NEW: support multilang in Civilities API NEW: Add API for the partnership module NEW: Add "Get lines and Post lines from BOM" in the API NEW: Replace fk_categories_product with categories_product in inventory @@ -204,6 +209,32 @@ 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.3 compared to 16.0.2 ***** + +FIX: $sign is useless +FIX: #18304 Member subscription confirmation email sent even if mandatory fields are missing +FIX: #19828 +FIX: #19877 +FIX: #22509 default value on integer fields don't retrieve by setSaveQuery +FIX: #22786 +FIX: #22813 +FIX: #22824 Accountancy - Journal - Search on subledger when list of subledger is disabled +FIX: Backup using the low memory mode +FIX: Bankaccounts API fetch with 'id' and 'socid' +FIX: base64_decode should be forbiden in dol_eval +FIX: Broken Permissions check, $object is null. +FIX: compute next value when year is on one digit for reset counter +FIX: copy same behaviour in other accountancy files +FIX: Fix the position of the verification condition of the test field in case of multi entities +FIX: for #22882 +FIX: for #22952 +FIX: merge errors on mailing card +FIX: PaymentBankTransfer Type page management with Select and Input on create.php +FIX: remove not initialized variable +FIX: SQL request parenthesis +FIX: Use the Hook addMoreActionsButtons resPrint +FIX: Wrong Extrafields Element For Assets + ***** ChangeLog for 16.0.2 compared to 16.0.1 ***** FIX: 16.0 - computed extrafields are not displayed if the object has no other extrafields diff --git a/build/debian/source/include-binaries b/build/debian/source/include-binaries deleted file mode 100644 index 021641d5c04..00000000000 --- a/build/debian/source/include-binaries +++ /dev/null @@ -1,2 +0,0 @@ -htdocs/install/doctemplates/websites/website_template-corporate.zip -htdocs/install/doctemplates/websites/website_template-stellar.zip \ No newline at end of file diff --git a/build/debian/source/options b/build/debian/source/options new file mode 100644 index 00000000000..8d8fd181896 --- /dev/null +++ b/build/debian/source/options @@ -0,0 +1,3 @@ +# Force use of gzip compression by dpkg-buildpackage +compression = "gzip" +#compression-level = 9 diff --git a/build/generate_filelist_xml.php b/build/generate_filelist_xml.php index 3d72ebe6739..b122f9b0305 100755 --- a/build/generate_filelist_xml.php +++ b/build/generate_filelist_xml.php @@ -55,14 +55,24 @@ if (empty($argv[1])) { $i=0; +$result=array(); while ($i < $argc) { if (!empty($argv[$i])) { - parse_str($argv[$i]); // set all params $release, $includecustom, $includeconstant, $buildzip ... + parse_str($argv[$i], $result); // set all params $release, $includecustom, $includeconstant, $buildzip ... } - if (preg_match('/includeconstant=/', $argv[$i])) { - $tmp=explode(':', $includeconstant, 3); // $includeconstant has been set with previous parse_str() + if (!empty($result["release"])) { + $release = $result["release"]; + } + if (!empty($result["includecustom"])) { + $includecustom = $result["includecustom"]; + } + if (!empty($result["includeconstant"])) { + $includeconstants[$i] = $result["includeconstant"]; + } + if (preg_match('/includeconstant=/', strval($argv[$i]))) { + $tmp=explode(':', $result['includeconstant'], 3); // $includeconstant has been set with previous parse_str() if (count($tmp) != 3) { - print "Error: Bad parameter includeconstant=".$includeconstant."\n"; + print "Error: Bad parameter includeconstant=".$result['includeconstant'] ."\n"; exit -1; } $includeconstants[$tmp[0]][$tmp[1]] = $tmp[2]; @@ -71,7 +81,7 @@ while ($i < $argc) { } if (empty($release)) { - print "Error: Missing release paramater\n"; + print "Error: Missing release parameter\n"; print "Usage: ".$script_file." release=autostable|auto[-mybuild]|x.y.z[-mybuild] [includecustom=1] [includeconstant=CC:MY_CONF_NAME:value]\n"; exit -1; } diff --git a/build/makepack-dolibarr.pl b/build/makepack-dolibarr.pl index abf16cee764..5d958787243 100755 --- a/build/makepack-dolibarr.pl +++ b/build/makepack-dolibarr.pl @@ -621,7 +621,6 @@ if ($nboftargetok) { $ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/includes/nnnick/chartjs/scripts`; $ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/includes/nnnick/chartjs/src`; $ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/includes/nnnick/chartjs/test`; - $ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/includes/nusoap/lib/Mail`; $ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/includes/nusoap/samples`; $ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/includes/php-iban/docs`; $ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/includes/sabre/sabre/*/tests`; @@ -679,7 +678,7 @@ if ($nboftargetok) { mkdir($DESTI.'/standard'); if (-d $DESTI.'/standard') { $NEWDESTI=$DESTI.'/standard'; } } - + print "Remove target $FILENAMETGZ.tgz...\n"; unlink("$NEWDESTI/$FILENAMETGZ.tgz"); @@ -1065,7 +1064,8 @@ if ($nboftargetok) { $ret=`mv $BUILDROOT/*_all.deb "$NEWDESTI/"`; $ret=`mv $BUILDROOT/*.dsc "$NEWDESTI/"`; $ret=`mv $BUILDROOT/*.orig.tar.gz "$NEWDESTI/"`; - $ret=`mv $BUILDROOT/*.debian.tar.xz "$NEWDESTI/"`; + #$ret=`mv $BUILDROOT/*.debian.tar.xz "$NEWDESTI/"`; # xz file is generated when build/debian/sources/option + $ret=`mv $BUILDROOT/*.debian.tar.gz "$NEWDESTI/"`; $ret=`mv $BUILDROOT/*.changes "$NEWDESTI/"`; next; } @@ -1147,7 +1147,8 @@ if ($nboftargetok) { "$DESTI/package_debian-ubuntu/${FILENAMEDEB}_all.deb"=>'Dolibarr installer for Debian-Ubuntu (DoliDeb)', "$DESTI/package_debian-ubuntu/${FILENAMEDEB}_amd64.changes"=>'none', # none means it won't be published on SF "$DESTI/package_debian-ubuntu/${FILENAMEDEB}.dsc"=>'none', # none means it won't be published on SF - "$DESTI/package_debian-ubuntu/${FILENAMEDEB}.debian.tar.xz"=>'none', # none means it won't be published on SF + #"$DESTI/package_debian-ubuntu/${FILENAMEDEB}.debian.tar.xz"=>'none', # none means it won't be published on SF + "$DESTI/package_debian-ubuntu/${FILENAMEDEB}.debian.tar.gz"=>'none', # none means it won't be published on SF "$DESTI/package_debian-ubuntu/${FILENAMEDEBSHORT}.orig.tar.gz"=>'none', # none means it won't be published on SF "$DESTI/package_windows/$FILENAMEEXEDOLIWAMP.exe"=>'Dolibarr installer for Windows (DoliWamp)', "$DESTI/standard/$FILENAMETGZ.tgz"=>'Dolibarr ERP-CRM', diff --git a/dev/dolibarr_changes.txt b/dev/dolibarr_changes.txt index cbfecbbc19f..461db52f959 100644 --- a/dev/dolibarr_changes.txt +++ b/dev/dolibarr_changes.txt @@ -283,6 +283,9 @@ RESTLER: elseif (count($value) && isset($value[0]) && is_numeric($value[0])) +* Add CommentParser.php line 406 & 407 to remove a warning on api request in php 8.1 + empty($value[0]) ? null : + empty($value[1]) ? null : +With swagger 2 provided into /explorer: ---------------------------------------- diff --git a/dev/setup/apache/virtualhost b/dev/setup/apache/virtualhost index 8c7682fe3d9..7508bbca171 100644 --- a/dev/setup/apache/virtualhost +++ b/dev/setup/apache/virtualhost @@ -3,7 +3,14 @@ #php_admin_value mail.force_extra_parameters "-f postmaster@mydomain.com" php_admin_value sendmail_path "/usr/sbin/sendmail -t -i -f postmaster@mydomain.com" php_admin_value open_basedir /tmp/:/home/.../htdocs:/home/.../dolibarr_documents: + + # Add this to use a custom apparmor profile when using apache php handler + + AADefaultHatName sellyoursaas-instances + + + ServerName myvirtualalias ServerAlias myvirtualalias @@ -82,9 +89,9 @@ # /usr/share/doc/apache2.2-common/README.Debian.gz for more info. # If both key and certificate are stored in the same file, only the # SSLCertificateFile directive is needed. - SSLCertificateFile /etc/letsencrypt/live/www.mydomain.com/cert.pem - SSLCertificateKeyFile /etc/letsencrypt/live/www.mydomain.com/privkey.pem - SSLCertificateChainFile /etc/letsencrypt/live/www.mydomain.com/chain.pem + #SSLCertificateFile /etc/letsencrypt/live/www.mydomain.com/cert.pem + #SSLCertificateKeyFile /etc/letsencrypt/live/www.mydomain.com/privkey.pem + #SSLCertificateChainFile /etc/letsencrypt/live/www.mydomain.com/chain.pem #RewriteEngine on #RewriteCond %{SERVER_PORT} ^80$ diff --git a/htdocs/accountancy/bookkeeping/balance.php b/htdocs/accountancy/bookkeeping/balance.php index d2b1aaa3348..01d89f1168d 100644 --- a/htdocs/accountancy/bookkeeping/balance.php +++ b/htdocs/accountancy/bookkeeping/balance.php @@ -239,10 +239,17 @@ if ($action != 'export_csv') { print ''; print ''; + $parameters = array(); $reshook = $hookmanager->executeHooks('addMoreActionsButtonsList', $parameters, $object, $action); // Note that $action and $object may have been modified by hook + if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + } + + $button = empty($hookmanager->resPrint) ? '' : $hookmanager->resPrint; + if (empty($reshook)) { - $button = 'global->ACCOUNTING_EXPORT_FORMAT.')" />'; + $button .= 'global->ACCOUNTING_EXPORT_FORMAT.')" />'; print ''; if (!empty($hidemargininfos)) { - print ''; + print ''; } } print '
'; print '' . "\n"; - print ''; + print '
'; print ''; print ''; print ''; diff --git a/htdocs/core/class/html.formprojet.class.php b/htdocs/core/class/html.formprojet.class.php index 9c8928de718..a0e74c5cdd5 100644 --- a/htdocs/core/class/html.formprojet.class.php +++ b/htdocs/core/class/html.formprojet.class.php @@ -66,14 +66,15 @@ class FormProjets * @param int $forcefocus Force focus on field (works with javascript only) * @param int $disabled Disabled * @param int $mode 0 for HTML mode and 1 for JSON mode - * @param string $filterkey Key to filter + * @param string $filterkey Key to filter on ref or title * @param int $nooutput No print output. Return it only. * @param int $forceaddid Force to add project id in list, event if not qualified * @param string $morecss More css * @param int $htmlid Html id to use instead of htmlname + * @param string $morefilter More filters (Must be a sql sanitized string) * @return string Return html content */ - public function select_projects($socid = -1, $selected = '', $htmlname = 'projectid', $maxlength = 16, $option_only = 0, $show_empty = 1, $discard_closed = 0, $forcefocus = 0, $disabled = 0, $mode = 0, $filterkey = '', $nooutput = 0, $forceaddid = 0, $morecss = '', $htmlid = '') + public function select_projects($socid = -1, $selected = '', $htmlname = 'projectid', $maxlength = 16, $option_only = 0, $show_empty = 1, $discard_closed = 0, $forcefocus = 0, $disabled = 0, $mode = 0, $filterkey = '', $nooutput = 0, $forceaddid = 0, $morecss = '', $htmlid = '', $morefilter = '') { // phpcs:enable global $langs, $conf, $form; @@ -96,16 +97,14 @@ class FormProjets $selected_input_value = $project->ref; } $urloption = 'socid='.((int) $socid).'&htmlname='.urlencode($htmlname).'&discardclosed='.((int) $discard_closed); - + if ($morefilter == 'usage_organize_event=1') { + $urloption .= '&usage_organize_event=1'; + } $out .= ''; - $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/projet/ajax/projects.php', $urloption, $conf->global->PROJECT_USE_SEARCH_TO_SELECT, 0, array( - // 'update' => array( - // 'projectid' => 'id' - // ) - )); + $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/projet/ajax/projects.php', $urloption, $conf->global->PROJECT_USE_SEARCH_TO_SELECT, 0, array()); } else { - $out .= $this->select_projects_list($socid, $selected, $htmlname, $maxlength, $option_only, $show_empty, abs($discard_closed), $forcefocus, $disabled, 0, $filterkey, 1, $forceaddid, $htmlid, $morecss); + $out .= $this->select_projects_list($socid, $selected, $htmlname, $maxlength, $option_only, $show_empty, abs($discard_closed), $forcefocus, $disabled, 0, $filterkey, 1, $forceaddid, $htmlid, $morecss, $morefilter); } if ($discard_closed > 0) { if (!empty($form)) { @@ -135,14 +134,15 @@ class FormProjets * @param int $forcefocus Force focus on field (works with javascript only) * @param int $disabled Disabled * @param int $mode 0 for HTML mode and 1 for array return (to be used by json_encode for example) - * @param string $filterkey Key to filter + * @param string $filterkey Key to filter on title or ref * @param int $nooutput No print output. Return it only. * @param int $forceaddid Force to add project id in list, event if not qualified * @param int $htmlid Html id to use instead of htmlname * @param string $morecss More CSS + * @param string $morefilter More filters (Must be a sql sanitized string) * @return int Nb of project if OK, <0 if KO */ - public function select_projects_list($socid = -1, $selected = '', $htmlname = 'projectid', $maxlength = 24, $option_only = 0, $show_empty = 1, $discard_closed = 0, $forcefocus = 0, $disabled = 0, $mode = 0, $filterkey = '', $nooutput = 0, $forceaddid = 0, $htmlid = '', $morecss = 'maxwidth500') + public function select_projects_list($socid = -1, $selected = '', $htmlname = 'projectid', $maxlength = 24, $option_only = 0, $show_empty = 1, $discard_closed = 0, $forcefocus = 0, $disabled = 0, $mode = 0, $filterkey = '', $nooutput = 0, $forceaddid = 0, $htmlid = '', $morecss = 'maxwidth500', $morefilter = '') { // phpcs:enable global $user, $conf, $langs; @@ -187,6 +187,9 @@ class FormProjets if (!empty($filterkey)) { $sql .= natural_search(array('p.title', 'p.ref'), $filterkey); } + if ($morefilter) { + $sql .= ' AND ('.$this->db->sanitize($morefilter, 0, 1).')'; + } $sql .= " ORDER BY p.ref ASC"; $resql = $this->db->query($sql); @@ -372,7 +375,7 @@ class FormProjets include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php'; $comboenhancement = ajax_combobox($htmlname, '', 0, $forcefocus); $out .= $comboenhancement; - $morecss = 'minwidth200 maxwidth500'; + $morecss .= ' minwidth200 maxwidth500'; } if (empty($option_only)) { diff --git a/htdocs/core/class/html.formpropal.class.php b/htdocs/core/class/html.formpropal.class.php index 87919141727..e23e71a8124 100644 --- a/htdocs/core/class/html.formpropal.class.php +++ b/htdocs/core/class/html.formpropal.class.php @@ -134,6 +134,6 @@ class FormPropal } print ''; - print ajax_combobox($htmlname); + print ajax_combobox($htmlname, array(), 0, 0, 'resolve', ($showempty < 0 ? (string) $showempty : '-1'), $morecss); } } diff --git a/htdocs/core/class/html.formsms.class.php b/htdocs/core/class/html.formsms.class.php index 68b8410e647..f08640c6e55 100644 --- a/htdocs/core/class/html.formsms.class.php +++ b/htdocs/core/class/html.formsms.class.php @@ -285,7 +285,7 @@ function limitChars(textarea, limit, infodiv) print ''; } else { print ''; - print '
'.$langs->trans("SmsInfoCharRemain").': '.(160 - dol_strlen($defaultmessage)).'
'; + print '
'.$langs->trans("SmsInfoCharRemain").': '.(160 - dol_strlen($defaultmessage)).'
'; } print "\n"; } diff --git a/htdocs/core/class/html.formticket.class.php b/htdocs/core/class/html.formticket.class.php index 1d7af10ef14..3dc618c36ab 100644 --- a/htdocs/core/class/html.formticket.class.php +++ b/htdocs/core/class/html.formticket.class.php @@ -81,6 +81,7 @@ class FormTicket public $withtitletopic; public $withtopicreadonly; public $withreadid; + public $withcompany; // to show company drop-down list public $withfromsocid; public $withfromcontactid; @@ -108,6 +109,7 @@ class FormTicket * @var string Error code (or message) */ public $error; + public $errors = array(); /** @@ -126,7 +128,7 @@ class FormTicket $this->withcompany = isModEnabled("societe"); $this->withfromsocid = 0; $this->withfromcontactid = 0; - //$this->withreadid=0; + $this->withreadid=0; //$this->withtitletopic=''; $this->withnotifytiersatcreate = 0; $this->withusercreate = 1; @@ -173,7 +175,7 @@ class FormTicket print dol_get_fiche_head(null, 'card', '', 0, ''); } - print 'param["returnurl"] : "").'">'; + print 'param["returnurl"] : $_SERVER['PHP_SELF']).'">'; print ''; print ''; foreach ($this->param as $key => $value) { @@ -332,27 +334,25 @@ class FormTicket print ''; // Severity => Priority - print ''; // Subject if ($this->withtitletopic) { print ''; } else { - if (isset($this->withreadid) && $this->withreadid > 0) { + if (isset($this->withreadid) && $this->withreadid > 0) { $subject = $langs->trans('SubjectAnswerToTicket').' '.$this->withreadid.' : '.$this->topic_title.''; } else { $subject = GETPOST('subject', 'alpha'); } print ''; - print ''; } + print ''; } if (!empty($conf->knowledgemanagement->enabled)) { diff --git a/htdocs/core/class/ldap.class.php b/htdocs/core/class/ldap.class.php index 426dec37962..011d8a380ef 100644 --- a/htdocs/core/class/ldap.class.php +++ b/htdocs/core/class/ldap.class.php @@ -1058,12 +1058,12 @@ class Ldap if (is_array($attributeArray)) { // Return list with required fields $attributeArray = array_values($attributeArray); // This is to force to have index reordered from 0 (not make ldap_search fails) - dol_syslog(get_class($this)."::getRecords connection=".$this->connection." userDn=".$userDn." filter=".$filter." attributeArray=(".join(',', $attributeArray).")"); + dol_syslog(get_class($this)."::getRecords connection=".$this->connectedServer.":".$this->serverPort." userDn=".$userDn." filter=".$filter." attributeArray=(".join(',', $attributeArray).")"); //var_dump($attributeArray); $this->result = @ldap_search($this->connection, $userDn, $filter, $attributeArray); } else { // Return list with fields selected by default - dol_syslog(get_class($this)."::getRecords connection=".$this->connection." userDn=".$userDn." filter=".$filter); + dol_syslog(get_class($this)."::getRecords connection=".$this->connectedServer.":".$this->serverPort." userDn=".$userDn." filter=".$filter); $this->result = @ldap_search($this->connection, $userDn, $filter); } if (!$this->result) { diff --git a/htdocs/core/class/utils.class.php b/htdocs/core/class/utils.class.php index ab64d0c052a..521d5ee2092 100644 --- a/htdocs/core/class/utils.class.php +++ b/htdocs/core/class/utils.class.php @@ -203,9 +203,10 @@ class Utils * @param string $file 'auto' or filename to build * @param int $keeplastnfiles Keep only last n files (not used yet) * @param int $execmethod 0=Use default method (that is 1 by default), 1=Use the PHP 'exec' - need size of dump in memory, but low memory method is used if GETPOST('lowmemorydump') is set, 2=Use the 'popen' method (low memory method) + * @param int $lowmemorydump 1=Use the low memory method. If $lowmemorydump is set, it means we want to make the compression using an external pipe instead retreiving the content of the dump in PHP memory array $output_arr and then print it into the PHP pipe open with xopen(). * @return int 0 if OK, < 0 if KO (this function is used also by cron so only 0 is OK) */ - public function dumpDatabase($compression = 'none', $type = 'auto', $usedefault = 1, $file = 'auto', $keeplastnfiles = 0, $execmethod = 0) + public function dumpDatabase($compression = 'none', $type = 'auto', $usedefault = 1, $file = 'auto', $keeplastnfiles = 0, $execmethod = 0, $lowmemorydump = 0) { global $db, $conf, $langs, $dolibarr_main_data_root; global $dolibarr_main_db_name, $dolibarr_main_db_host, $dolibarr_main_db_user, $dolibarr_main_db_port, $dolibarr_main_db_pass; @@ -358,10 +359,6 @@ class Utils $handle = ''; - // If $lowmemorydump is set, it means we want to make the compression using an external pipe instead retreiving the - // content of the dump in PHP memory array $output_arr and then print it into the PHP pipe open with xopen(). - $lowmemorydump = GETPOSTISSET("lowmemorydump") ? GETPOST("lowmemorydump") : getDolGlobalString('MAIN_LOW_MEMORY_DUMP'); - // Start call method to execute dump $fullcommandcrypted = $command." ".$paramcrypted." 2>&1"; $fullcommandclear = $command." ".$paramclear." 2>&1"; @@ -377,23 +374,23 @@ class Utils } } else { if ($compression == 'none') { - $fullcommandclear .= ' > "'.dol_sanitizePathName($outputfile).'"'; - $fullcommandcrypted .= ' > "'.dol_sanitizePathName($outputfile).'"'; + $fullcommandclear .= ' | grep -v "Warning: Using a password on the command line interface can be insecure." > "'.dol_sanitizePathName($outputfile).'"'; + $fullcommandcrypted .= ' | grep -v "Warning: Using a password on the command line interface can be insecure." > "'.dol_sanitizePathName($outputfile).'"'; $handle = 1; } elseif ($compression == 'gz') { - $fullcommandclear .= ' | gzip > "'.dol_sanitizePathName($outputfile).'"'; - $fullcommandcrypted .= ' | gzip > "'.dol_sanitizePathName($outputfile).'"'; - $paramcrypted .= ' | gzip'; + $fullcommandclear .= ' | grep -v "Warning: Using a password on the command line interface can be insecure." | gzip > "'.dol_sanitizePathName($outputfile).'"'; + $fullcommandcrypted .= ' | grep -v "Warning: Using a password on the command line interface can be insecure." | gzip > "'.dol_sanitizePathName($outputfile).'"'; + $paramcrypted .= ' | grep -v "Warning: Using a password on the command line interface can be insecure." | gzip'; $handle = 1; } elseif ($compression == 'bz') { - $fullcommandclear .= ' | bzip2 > "'.dol_sanitizePathName($outputfile).'"'; - $fullcommandcrypted .= ' | bzip2 > "'.dol_sanitizePathName($outputfile).'"'; - $paramcrypted .= ' | bzip2'; + $fullcommandclear .= ' | grep -v "Warning: Using a password on the command line interface can be insecure." | bzip2 > "'.dol_sanitizePathName($outputfile).'"'; + $fullcommandcrypted .= ' | grep -v "Warning: Using a password on the command line interface can be insecure." | bzip2 > "'.dol_sanitizePathName($outputfile).'"'; + $paramcrypted .= ' | grep -v "Warning: Using a password on the command line interface can be insecure." | bzip2'; $handle = 1; } elseif ($compression == 'zstd') { - $fullcommandclear .= ' | zstd > "'.dol_sanitizePathName($outputfile).'"'; - $fullcommandcrypted .= ' | zstd > "'.dol_sanitizePathName($outputfile).'"'; - $paramcrypted .= ' | zstd'; + $fullcommandclear .= ' | grep -v "Warning: Using a password on the command line interface can be insecure." | zstd > "'.dol_sanitizePathName($outputfile).'"'; + $fullcommandcrypted .= ' | grep -v "Warning: Using a password on the command line interface can be insecure." | zstd > "'.dol_sanitizePathName($outputfile).'"'; + $paramcrypted .= ' | grep -v "Warning: Using a password on the command line interface can be insecure." | zstd'; $handle = 1; } } diff --git a/htdocs/core/db/DoliDB.class.php b/htdocs/core/db/DoliDB.class.php index 2d2ea33a6c5..e2659e224a4 100644 --- a/htdocs/core/db/DoliDB.class.php +++ b/htdocs/core/db/DoliDB.class.php @@ -107,6 +107,25 @@ abstract class DoliDB implements Database return ''; } + + /** + * Format a SQL REGEXP + * + * @param string $subject string tested + * @param string $pattern SQL pattern to match + * @param string $sqlstring whether or not the string being tested is an SQL expression + * @return string SQL string + */ + public function regexpsql($subject, $pattern, $sqlstring = false) + { + if ($sqlstring) { + return "(". $subject ." REGEXP '" . $pattern . "')"; + } + + return "('". $subject ."' REGEXP '" . $pattern . "')"; + } + + /** * Convert (by PHP) a GM Timestamp date into a string date with PHP server TZ to insert into a date field. * Function to use to build INSERT, UPDATE or WHERE predica @@ -136,15 +155,12 @@ abstract class DoliDB implements Database * * @param string $stringtosanitize String to escape * @param int $allowsimplequote 1=Allow simple quotes in string. When string is used as a list of SQL string ('aa', 'bb', ...) + * @param string $allowsequals 1=Allow equals sign * @return string String escaped */ - public function sanitize($stringtosanitize, $allowsimplequote = 0) + public function sanitize($stringtosanitize, $allowsimplequote = 0, $allowsequals = 0) { - if ($allowsimplequote) { - return preg_replace('/[^a-z0-9_\-\.,\']/i', '', $stringtosanitize); - } else { - return preg_replace('/[^a-z0-9_\-\.,]/i', '', $stringtosanitize); - } + return preg_replace('/[^a-z0-9_\-\.,'.($allowsequals ? '=' : '').($allowsimplequote ? "\'" : '').']/i', '', $stringtosanitize); } /** diff --git a/htdocs/core/db/pgsql.class.php b/htdocs/core/db/pgsql.class.php index 0515a043fd1..28ac15a43ff 100644 --- a/htdocs/core/db/pgsql.class.php +++ b/htdocs/core/db/pgsql.class.php @@ -757,6 +757,24 @@ class DoliDBPgsql extends DoliDB return '(CASE WHEN '.$test.' THEN '.$resok.' ELSE '.$resko.' END)'; } + /** + * Format a SQL REGEXP + * + * @param string $subject string tested + * @param string $pattern SQL pattern to match + * @param string $sqlstring whether or not the string being tested is an SQL expression + * @return string SQL string + */ + public function regexpsql($subject, $pattern, $sqlstring = false) + { + if ($sqlstring) { + return "(". $subject ." ~ '" . $pattern . "')"; + } + + return "('". $subject ."' ~ '" . $pattern . "')"; + } + + /** * Renvoie le code erreur generique de l'operation precedente. * @@ -1220,7 +1238,7 @@ class DoliDBPgsql extends DoliDB // phpcs:enable $sql = "ALTER TABLE ".$table; $sql .= " MODIFY COLUMN ".$field_name." ".$field_desc['type']; - if (in_array($field_desc['type'], array('double', 'tinyint', 'int', 'varchar')) && $field_desc['value']) { + if (in_array($field_desc['type'], array('double', 'varchar')) && $field_desc['value']) { $sql .= "(".$field_desc['value'].")"; } diff --git a/htdocs/core/lib/ajax.lib.php b/htdocs/core/lib/ajax.lib.php index 6cd7a0f0381..cc871de9709 100644 --- a/htdocs/core/lib/ajax.lib.php +++ b/htdocs/core/lib/ajax.lib.php @@ -130,7 +130,10 @@ function ajax_autocompleter($selected, $htmlname, $url, $urloption = '', $minLen $("#search_'.$htmlnamejquery.'").val(item.value); $("#'.$htmlnamejquery.'").val(item.key).trigger("change"); } - var label = item.label.toString(); + var label = ""; + if (item.label != null) { + label = item.label.toString(); + } var update = {}; if (options.update) { $.each(options.update, function(key, value) { @@ -162,7 +165,9 @@ function ajax_autocompleter($selected, $htmlname, $url, $urloption = '', $minLen price_unit_ht_locale: item.price_unit_ht_locale, description : item.description, ref_customer: item.ref_customer, - tva_tx: item.tva_tx } + tva_tx: item.tva_tx, + default_vat_code: item.default_vat_code + } })); } else { console.error("Error: Ajax url '.$url.($urloption ? '?'.$urloption : '').' has returned an empty page. Should be an empty json array."); @@ -175,7 +180,8 @@ function ajax_autocompleter($selected, $htmlname, $url, $urloption = '', $minLen console.log("We will trigger change on input '.$htmlname.' because of the select definition of autocomplete code for input#search_'.$htmlname.'"); console.log("Selected id = "+ui.item.id+" - If this value is null, it means you select a record with key that is null so selection is not effective"); - console.log("Propagate before some properties retrieved by ajax into data-xxx properties"); + console.log("Propagate before some properties retrieved by ajax into data-xxx properties of #'.$htmlnamejquery.' component"); + //console.log(ui.item); // For supplier price and customer when price by quantity is off $("#'.$htmlnamejquery.'").attr("data-up", ui.item.price_ht); @@ -186,6 +192,7 @@ function ajax_autocompleter($selected, $htmlname, $url, $urloption = '', $minLen $("#'.$htmlnamejquery.'").attr("data-description", ui.item.description); $("#'.$htmlnamejquery.'").attr("data-ref-customer", ui.item.ref_customer); $("#'.$htmlnamejquery.'").attr("data-tvatx", ui.item.tva_tx); + $("#'.$htmlnamejquery.'").attr("data-default-vat-code", ui.item.default_vat_code); '; if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY)) { $script .= ' diff --git a/htdocs/core/lib/company.lib.php b/htdocs/core/lib/company.lib.php index 3d0cb72e7c9..ed9b6560618 100644 --- a/htdocs/core/lib/company.lib.php +++ b/htdocs/core/lib/company.lib.php @@ -1117,12 +1117,13 @@ function show_contacts($conf, $langs, $db, $object, $backtopage = '', $showuserl $extrafieldsobjectkey = $contactstatic->table_element; include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php'; - $sql = "SELECT t.rowid, t.lastname, t.firstname, t.fk_pays as country_id, t.civility, t.poste, t.phone as phone_pro, t.phone_mobile, t.phone_perso, t.fax, t.email, t.socialnetworks, t.statut, t.photo,"; + $sql = "SELECT t.rowid, t.entity, t.lastname, t.firstname, t.fk_pays as country_id, t.civility, t.poste, t.phone as phone_pro, t.phone_mobile, t.phone_perso, t.fax, t.email, t.socialnetworks, t.statut, t.photo,"; $sql .= " t.civility as civility_id, t.address, t.zip, t.town"; $sql .= ", t.note_private"; $sql .= " FROM ".MAIN_DB_PREFIX."socpeople as t"; $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."socpeople_extrafields as ef on (t.rowid = ef.fk_object)"; $sql .= " WHERE t.fk_soc = ".((int) $object->id); + $sql .= " AND ((t.fk_user_creat = ".((int) $user->id)." AND t.priv = 1) OR t.priv = 0)"; if ($search_rowid) { $sql .= natural_search('t.rowid', $search_rowid); } @@ -1182,7 +1183,7 @@ function show_contacts($conf, $langs, $db, $object, $backtopage = '', $showuserl if (!empty($arrayfields['t.'.$key]['checked']) || !empty($arrayfields['sc.'.$key]['checked'])) { print '
' . $langs->trans('Margins') . '' . $langs->trans('SellingPrice') . '
'; + print '
'; $this->selectSeveritiesTickets((GETPOST('severity_code') ? GETPOST('severity_code') : $this->severity_code), 'severity_code', '', 2, 1); print '
'; - // Answer to a ticket : display of the thread title in readonly if ($this->withtopicreadonly) { print $langs->trans('SubjectAnswerToTicket').' '.$this->topic_title; - print '
'; if (in_array($key, array('statut'))) { - print $form->selectarray('search_status', array('-1'=>'', '0'=>$contactstatic->LibStatut(0, 1), '1'=>$contactstatic->LibStatut(1, 1)), $search_status); + print $form->selectarray('search_status', array('-1'=>'', '0'=>$contactstatic->LibStatut(0, 1), '1'=>$contactstatic->LibStatut(1, 1)), $search_status, 0, 0, 0, '', 0, 0, 0, '', 'onrightofpage'); } elseif (in_array($key, array('role'))) { print $formcompany->showRoles("search_roles", $contactstatic, 'edit', $search_roles, 'minwidth200 maxwidth300'); } else { @@ -1271,6 +1272,7 @@ function show_contacts($conf, $langs, $db, $object, $backtopage = '', $showuserl $contactstatic->email = $obj->email; $contactstatic->socialnetworks = $obj->socialnetworks; $contactstatic->photo = $obj->photo; + $contactstatic->entity = $obj->entity; $country_code = getCountry($obj->country_id, 2); $contactstatic->country_code = $country_code; @@ -1575,7 +1577,7 @@ function show_actions_done($conf, $langs, $db, $filterobj, $objcon = '', $noprin $sql .= ", ".MAIN_DB_PREFIX."bom_bom as o"; } elseif (is_object($filterobj) && get_class($filterobj) == 'Contrat') { $sql .= ", ".MAIN_DB_PREFIX."contrat as o"; - } elseif (is_object($filterobj) && is_array($filterobj->fields) && is_array($filterobj->fields['rowid']) && (is_array($filterobj->fields['ref']) || is_array($filterobj->fields['label'])) && $filterobj->table_element && $filterobj->element) { + } elseif (is_object($filterobj) && is_array($filterobj->fields) && is_array($filterobj->fields['rowid']) && (!empty($filterobj->fields['ref']) && is_array($filterobj->fields['ref']) || $filterobj->fields['label'] && is_array($filterobj->fields['label'])) && $filterobj->table_element && $filterobj->element) { $sql .= ", ".MAIN_DB_PREFIX.$filterobj->table_element." as o"; } @@ -1617,7 +1619,7 @@ function show_actions_done($conf, $langs, $db, $filterobj, $objcon = '', $noprin if ($filterobj->id) { $sql .= " AND a.fk_element = ".((int) $filterobj->id); } - } elseif (is_object($filterobj) && is_array($filterobj->fields) && is_array($filterobj->fields['rowid']) && (is_array($filterobj->fields['ref']) || is_array($filterobj->fields['label'])) && $filterobj->table_element && $filterobj->element) { + } elseif (is_object($filterobj) && is_array($filterobj->fields) && is_array($filterobj->fields['rowid']) && (!empty($filterobj->fields['ref']) && is_array($filterobj->fields['ref']) || $filterobj->fields['label'] && is_array($filterobj->fields['label'])) && $filterobj->table_element && $filterobj->element) { // Generic case $sql .= " AND a.fk_element = o.rowid AND a.elementtype = '".$db->escape($filterobj->element).($module ? "@".$module : "")."'"; if ($filterobj->id) { @@ -1896,7 +1898,7 @@ function show_actions_done($conf, $langs, $db, $filterobj, $objcon = '', $noprin if (empty($conf->global->AGENDA_USE_EVENT_TYPE) && empty($arraylist[$labeltype])) { $labeltype = 'AC_OTH'; } - if ($actionstatic->type_code == 'AC_OTH' && $actionstatic->code == 'TICKET_MSG') { + if (preg_match('/^TICKET_MSG/', $actionstatic->code)) { $labeltype = $langs->trans("Message"); } else { if (!empty($arraylist[$labeltype])) { diff --git a/htdocs/core/lib/contact.lib.php b/htdocs/core/lib/contact.lib.php index 948af4e2868..2dbf97d4785 100644 --- a/htdocs/core/lib/contact.lib.php +++ b/htdocs/core/lib/contact.lib.php @@ -70,9 +70,10 @@ function contact_prepare_head(Contact $object) $sql = 'SELECT COUNT(n.rowid) as nb'; $sql .= ' FROM '.MAIN_DB_PREFIX.'projet as n'; $sql .= ' INNER JOIN '.MAIN_DB_PREFIX.'element_contact as cc ON (n.rowid = cc.element_id)'; - $sql .= ' WHERE cc.fk_socpeople = '.((int) $object->id); - $sql .= ' AND cc.fk_c_type_contact IN (SELECT rowid FROM '.MAIN_DB_PREFIX.'c_type_contact WHERE element="project" AND source="external")'; - $sql .= ' AND n.entity IN ('.getEntity('project').')'; + $sql .= " WHERE cc.fk_socpeople = ".((int) $object->id); + $sql .= " AND cc.fk_c_type_contact IN (SELECT rowid FROM ".MAIN_DB_PREFIX."c_type_contact WHERE element='project' AND source='external')"; + $sql .= " AND n.entity IN (".getEntity('project').")"; + $resql = $db->query($sql); if ($resql) { $obj = $db->fetch_object($resql); @@ -191,10 +192,10 @@ function show_contacts_projects($conf, $langs, $db, $object, $backtopage = '', $ $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_lead_status as cls on p.fk_opp_status = cls.rowid'; $sql .= ' INNER JOIN '.MAIN_DB_PREFIX.'element_contact as cc ON (p.rowid = cc.element_id)'; $sql .= ' INNER JOIN '.MAIN_DB_PREFIX.'c_type_contact as ctc ON (ctc.rowid = cc.fk_c_type_contact)'; - $sql .= ' WHERE cc.fk_socpeople = '.((int) $object->id); - $sql .= ' AND ctc.element="project" AND ctc.source="external"'; - $sql .= ' AND p.entity IN ('.getEntity('project').')'; - $sql .= ' ORDER BY p.dateo DESC'; + $sql .= " WHERE cc.fk_socpeople = ".((int) $object->id); + $sql .= " AND ctc.element='project' AND ctc.source='external'"; + $sql .= " AND p.entity IN (".getEntity('project').")"; + $sql .= " ORDER BY p.dateo DESC"; $result = $db->query($sql); if ($result) { diff --git a/htdocs/core/lib/expensereport.lib.php b/htdocs/core/lib/expensereport.lib.php index 19e2e0ca00d..ae9ca936c47 100644 --- a/htdocs/core/lib/expensereport.lib.php +++ b/htdocs/core/lib/expensereport.lib.php @@ -1,5 +1,6 @@ + * Copyright (C) 2022 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 @@ -130,11 +131,14 @@ function payment_expensereport_prepare_head(PaymentExpenseReport $object) */ function expensereport_admin_prepare_head() { - global $langs, $conf, $user; + global $langs, $conf, $user, $db; $h = 0; $head = array(); + $extrafields = new ExtraFields($db); + $extrafields->fetch_name_optionals_label('expensereport'); + $h = 0; $head[$h][0] = DOL_URL_ROOT."/admin/expensereport.php"; @@ -162,6 +166,10 @@ function expensereport_admin_prepare_head() $head[$h][0] = DOL_URL_ROOT.'/admin/expensereport_extrafields.php'; $head[$h][1] = $langs->trans("ExtraFields"); + $nbExtrafields = $extrafields->attributes['expensereport']['count']; + if ($nbExtrafields > 0) { + $head[$h][1] .= ''.$nbExtrafields.''; + } $head[$h][2] = 'attributes'; $h++; diff --git a/htdocs/core/lib/files.lib.php b/htdocs/core/lib/files.lib.php index cb7e1a8883e..ae4afc695e6 100644 --- a/htdocs/core/lib/files.lib.php +++ b/htdocs/core/lib/files.lib.php @@ -401,8 +401,8 @@ function completeFileArrayWithDatabaseInfo(&$filearray, $relativedir) /** * Fast compare of 2 files identified by their properties ->name, ->date and ->size * - * @param string $a File 1 - * @param string $b File 2 + * @param object $a File 1 + * @param object $b File 2 * @return int 1, 0, 1 */ function dol_compare_file($a, $b) @@ -1657,7 +1657,12 @@ function dol_add_file_process($upload_dir, $allowoverwrite = 0, $donotupdatesess if (!empty($_FILES[$varfiles])) { // For view $_FILES[$varfiles]['error'] dol_syslog('dol_add_file_process upload_dir='.$upload_dir.' allowoverwrite='.$allowoverwrite.' donotupdatesession='.$donotupdatesession.' savingdocmask='.$savingdocmask, LOG_DEBUG); - + $maxfilesinform = getDolGlobalInt("MAIN_SECURITY_MAX_ATTACHMENT_ON_FORMS", 10); + if (is_array($_FILES[$varfiles]["name"]) && count($_FILES[$varfiles]["name"]) > $maxfilesinform) { + $langs->load("errors"); // key must be loaded because we can't rely on loading during output, we need var substitution to be done now. + setEventMessages($langs->trans("ErrorTooMuchFileInForm", $maxfilesinform), null, "errors"); + return -1; + } $result = dol_mkdir($upload_dir); // var_dump($result);exit; if ($result >= 0) { @@ -2473,7 +2478,7 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, if (empty($refname)) { $refname = basename(dirname($original_file)."/"); if ($refname == 'thumbs') { - // If we get the thumbns directory, we must go one step higher. For example original_file='10/thumbs/myfile_small.jpg' -> refname='10' + // If we get the thumbs directory, we must go one step higher. For example original_file='10/thumbs/myfile_small.jpg' -> refname='10' $refname = basename(dirname(dirname($original_file))."/"); } } diff --git a/htdocs/core/lib/fourn.lib.php b/htdocs/core/lib/fourn.lib.php index 8ba05557220..c658916e359 100644 --- a/htdocs/core/lib/fourn.lib.php +++ b/htdocs/core/lib/fourn.lib.php @@ -3,6 +3,7 @@ * Copyright (C) 2005-2012 Regis Houssin * Copyright (C) 2006 Marc Barilley * Copyright (C) 2011-2013 Philippe Grand + * Copyright (C) 2022 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 @@ -178,7 +179,10 @@ function ordersupplier_prepare_head(CommandeFournisseur $object) $sumQtyAllreadyDispatched = $sumQtyAllreadyDispatched + $dispachedLines[$line]['qty']; } for ($line = 0 ; $line < $nbLinesOrdered; $line++) { - $sumQtyOrdered = $sumQtyOrdered + $object->lines[$line]->qty; + //If line is a product of conf to manage stocks for services + if ($object->lines[$line]->product_type == 0 || !empty($conf->global->STOCK_SUPPORTS_SERVICES)) { + $sumQtyOrdered = $sumQtyOrdered + $object->lines[$line]->qty; + } } $head[$h][1] .= ''.price2num($sumQtyAllreadyDispatched, 'MS').' / '.price2num($sumQtyOrdered, 'MS').''; } @@ -246,7 +250,13 @@ function ordersupplier_prepare_head(CommandeFournisseur $object) */ function supplierorder_admin_prepare_head() { - global $langs, $conf, $user; + global $langs, $conf, $user, $db; + + $extrafields = new ExtraFields($db); + $extrafields->fetch_name_optionals_label('commande_fournisseur'); + $extrafields->fetch_name_optionals_label('commande_fournisseurdet'); + $extrafields->fetch_name_optionals_label('facture_fourn'); + $extrafields->fetch_name_optionals_label('facture_fourn_det'); $h = 0; $head = array(); @@ -270,21 +280,37 @@ function supplierorder_admin_prepare_head() $head[$h][0] = DOL_URL_ROOT.'/admin/supplierorder_extrafields.php'; $head[$h][1] = $langs->trans("ExtraFieldsSupplierOrders"); + $nbExtrafields = $extrafields->attributes['commande_fournisseur']['count']; + if ($nbExtrafields > 0) { + $head[$h][1] .= ''.$nbExtrafields.''; + } $head[$h][2] = 'supplierorder'; $h++; $head[$h][0] = DOL_URL_ROOT.'/admin/supplierorderdet_extrafields.php'; $head[$h][1] = $langs->trans("ExtraFieldsSupplierOrdersLines"); + $nbExtrafields = $extrafields->attributes['commande_fournisseurdet']['count']; + if ($nbExtrafields > 0) { + $head[$h][1] .= ''.$nbExtrafields.''; + } $head[$h][2] = 'supplierorderdet'; $h++; $head[$h][0] = DOL_URL_ROOT.'/admin/supplierinvoice_extrafields.php'; $head[$h][1] = $langs->trans("ExtraFieldsSupplierInvoices"); + $nbExtrafields = $extrafields->attributes['facture_fourn']['count']; + if ($nbExtrafields > 0) { + $head[$h][1] .= ''.$nbExtrafields.''; + } $head[$h][2] = 'supplierinvoice'; $h++; $head[$h][0] = DOL_URL_ROOT.'/admin/supplierinvoicedet_extrafields.php'; $head[$h][1] = $langs->trans("ExtraFieldsSupplierInvoicesLines"); + $nbExtrafields = $extrafields->attributes['facture_fourn_det']['count']; + if ($nbExtrafields > 0) { + $head[$h][1] .= ''.$nbExtrafields.''; + } $head[$h][2] = 'supplierinvoicedet'; $h++; diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 61977623d27..33b749d220f 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -908,63 +908,7 @@ function sanitizeVal($out = '', $check = 'alphanohtml', $filter = null, $options break; case 'restricthtml': // Recommended for most html textarea case 'restricthtmlallowunvalid': - do { - $oldstringtoclean = $out; - - if (!empty($out) && !empty($conf->global->MAIN_RESTRICTHTML_ONLY_VALID_HTML) && $check != 'restricthtmlallowunvalid') { - try { - $dom = new DOMDocument; - // Add a trick to solve pb with text without parent tag - // like '

Foo

bar

' that ends up with '

Foo

bar

' - // like 'abc' that ends up with '

abc

' - $out = '
'.$out.'
'; - - $dom->loadHTML($out, LIBXML_ERR_NONE|LIBXML_HTML_NOIMPLIED|LIBXML_HTML_NODEFDTD|LIBXML_NONET|LIBXML_NOWARNING|LIBXML_NOXMLDECL); - $out = trim($dom->saveHTML()); - - // Remove the trick added to solve pb with text without parent tag - $out = preg_replace('/^
/', '', $out); - $out = preg_replace('/<\/div>$/', '', $out); - } catch (Exception $e) { - //print $e->getMessage(); - return 'InvalidHTMLString'; - } - } - - // Ckeditor use the numeric entitic for apostrophe so we force it to text entity (all other special chars are - // encoded using text entities) so we can then exclude all numeric entities. - $out = preg_replace('/'/i', ''', $out); - - // We replace chars from a/A to z/Z encoded with numeric HTML entities with the real char so we won't loose the chars at the next step (preg_replace). - // No need to use a loop here, this step is not to sanitize (this is done at next step, this is to try to save chars, even if they are - // using a non coventionnel way to be encoded, to not have them sanitized just after) - //$out = preg_replace_callback('/&#(x?[0-9][0-9a-f]+;?)/i', 'realCharForNumericEntities', $out); - $out = preg_replace_callback('/&#(x?[0-9][0-9a-f]+;?)/i', function ($m) { - return realCharForNumericEntities($m); }, $out); - - - // Now we remove all remaining HTML entities starting with a number. We don't want such entities. - $out = preg_replace('/&#x?[0-9]+/i', '', $out); // For example if we have javascript with an entities without the ; to hide the 'a' of 'javascript'. - - $out = dol_string_onlythesehtmltags($out, 0, 1, 1); - - // We should also exclude non expected HTML attributes and clean content of some attributes. - if (!empty($conf->global->MAIN_RESTRICTHTML_REMOVE_ALSO_BAD_ATTRIBUTES)) { - // Warning, the function may add a LF so we are forced to trim to compare with old $out without having always a difference and an infinit loop. - $out = dol_string_onlythesehtmlattributes($out); - } - - // Restore entity ' into ' (restricthtml is for html content so we can use html entity) - $out = preg_replace('/'/i', "'", $out); - } while ($oldstringtoclean != $out); - - // Check the limit of external links in a Rich text content. We count ' getDolGlobalInt("MAIN_SECURITY_MAX_IMG_IN_HTML_CONTENT", 1000)) { - return 'TooManyLinksIntoHTMLString'; - } - + $out = dol_htmlwithnojs($out, 1, $check); break; case 'custom': if (!empty($out)) { @@ -1314,6 +1258,22 @@ function dol_sanitizeUrl($stringtoclean, $type = 1) return $stringtoclean; } +/** + * Clean a string to use it as an Email. + * + * @param string $stringtoclean String to clean. Example 'abc@mycompany.com ' + * @return string Escaped string. + */ +function dol_sanitizeEmail($stringtoclean) +{ + do { + $oldstringtoclean = $stringtoclean; + $stringtoclean = str_ireplace(array('"', ':', '[', ']',"\n", "\r", '\\', '\/'), '', $stringtoclean); + } while ($oldstringtoclean != $stringtoclean); + + return $stringtoclean; +} + /** * Clean a string from all accent characters to be used as ref, login or by dol_sanitizeFileName * @@ -1813,7 +1773,7 @@ function dolButtonToOpenUrlInDialogPopup($name, $label, $buttonstring, $url, $di * @param array $links Array of tabs (0=>url, 1=>label, 2=>code, 3=>not used, 4=>text after link, 5=>morecssonlink). Currently initialized by calling a function xxx_admin_prepare_head. Note that label into $links[$i][1] must be already HTML escaped. * @param string $active Active tab name (document', 'info', 'ldap', ....) * @param string $title Title - * @param int $notab -1 or 0=Add tab header, 1=no tab header (if you set this to 1, using print dol_get_fiche_end() to close tab is not required), -2=Add tab header with no seaparation under tab (to start a tab just after) + * @param int $notab -1 or 0=Add tab header, 1=no tab header (if you set this to 1, using print dol_get_fiche_end() to close tab is not required), -2=Add tab header with no sepaaration under tab (to start a tab just after), -3=Add tab header but no footer separation * @param string $picto Add a picto on tab title * @param int $pictoisfullpath If 1, image path is a full path. If you set this to 1, you can use url returned by dol_buildpath('/mymodyle/img/myimg.png',1) for $picto. * @param string $morehtmlright Add more html content on right of tabs title @@ -1934,7 +1894,7 @@ function dol_get_fiche_head($links = array(), $active = '', $title = '', $notab $out .= '
'; if (!empty($links[$i][0])) { $titletoshow = preg_replace('/<.*$/', '', $links[$i][1]); - $out .= ''; + $out .= ''; } $out .= $links[$i][1]; if (!empty($links[$i][0])) { @@ -2297,11 +2257,13 @@ function dol_banner_tab($object, $paramid, $morehtml = '', $shownav = 1, $fieldi $tmptxt = $object->getLibStatut(5); $morehtmlstatus .= $tmptxt; // No status on task } else { // Generic case - $tmptxt = $object->getLibStatut(6); - if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) { - $tmptxt = $object->getLibStatut(5); + if (isset($object->status)) { + $tmptxt = $object->getLibStatut(6); + if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) { + $tmptxt = $object->getLibStatut(5); + } + $morehtmlstatus .= $tmptxt; } - $morehtmlstatus .= $tmptxt; } // Add if object was dispatched "into accountancy" @@ -4108,7 +4070,8 @@ function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $ 'shapes', 'square', 'stop-circle', 'supplier', 'supplier_proposal', 'supplier_order', 'supplier_invoice', 'timespent', 'title_setup', 'title_accountancy', 'title_bank', 'title_hrm', 'title_agenda', 'uncheck', 'url', 'user-cog', 'user-injured', 'user-md', 'vat', 'website', 'workstation', 'webhook', 'world', 'private', - 'conferenceorbooth', 'eventorganization' + 'conferenceorbooth', 'eventorganization', + 'stamp', 'signature' ))) { $fakey = $pictowithouttext; $facolor = ''; @@ -6302,10 +6265,10 @@ function getLocalTaxesFromRate($vatrate, $local, $buyer, $seller, $firstparamisi * Return vat rate of a product in a particular country, or default country vat if product is unknown. * Function called by get_default_tva(). * - * @param int $idprod Id of product or 0 if not a predefined product - * @param Societe $thirdpartytouse Thirdparty with a ->country_code defined (FR, US, IT, ...) - * @param int $idprodfournprice Id product_fournisseur_price (for "supplier" proposal/order/invoice) - * @return float|string Vat rate to use with format 5.0 or '5.0 (XXX)' + * @param int $idprod Id of product or 0 if not a predefined product + * @param Societe $thirdpartytouse Thirdparty with a ->country_code defined (FR, US, IT, ...) + * @param int $idprodfournprice Id product_fournisseur_price (for "supplier" proposal/order/invoice) + * @return float|string Vat rate to use with format 5.0 or '5.0 (XXX)' * @see get_product_localtax_for_country() */ function get_product_vat_for_country($idprod, $thirdpartytouse, $idprodfournprice = 0) @@ -6320,7 +6283,7 @@ function get_product_vat_for_country($idprod, $thirdpartytouse, $idprodfournpric if ($idprod > 0) { // Load product $product = new Product($db); - $result = $product->fetch($idprod); + $product->fetch($idprod); if ($mysoc->country_code == $thirdpartytouse->country_code) { // If country to consider is ours if ($idprodfournprice > 0) { // We want vat for product for a "supplier" object @@ -6344,11 +6307,11 @@ function get_product_vat_for_country($idprod, $thirdpartytouse, $idprodfournpric if (!$found) { if (empty($conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS)) { - // If vat of product for the country not found or not defined, we return the first higher vat of country. + // If vat of product for the country not found or not defined, we return the first rate found (sorting on use_default, then on higher vat of country). $sql = "SELECT t.taux as vat_rate, t.code as default_vat_code"; $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c"; - $sql .= " WHERE t.active=1 AND t.fk_pays = c.rowid AND c.code='".$db->escape($thirdpartytouse->country_code)."'"; - $sql .= " ORDER BY t.taux DESC, t.code ASC, t.recuperableonly ASC"; + $sql .= " WHERE t.active=1 AND t.fk_pays = c.rowid AND c.code = '".$db->escape($thirdpartytouse->country_code)."'"; + $sql .= " ORDER BY t.use_default DESC, t.taux DESC, t.code ASC, t.recuperableonly ASC"; $sql .= $db->plimit(1); $resql = $db->query($sql); @@ -6365,7 +6328,17 @@ function get_product_vat_for_country($idprod, $thirdpartytouse, $idprodfournpric dol_print_error($db); } } else { - $ret = $conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS; // Forced value if autodetect fails + // Forced value if autodetect fails. MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS can be '1.23' or '1.23 (CODE)' + $defaulttx = ''; + if ($conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS != 'none') { + $defaulttx = $conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS; + } + /*if (preg_match('/\((.*)\)/', $defaulttx, $reg)) { + $defaultcode = $reg[1]; + $defaulttx = preg_replace('/\s*\(.*\)/', '', $defaulttx); + }*/ + + $ret = $defaulttx; } } @@ -6936,7 +6909,6 @@ function dol_string_onlythesehtmltags($stringtoclean, $cleanalsosomestyles = 1, $stringtoclean = preg_replace('/:/i', ':', $stringtoclean); $stringtoclean = preg_replace('/:|�+58|:/i', '', $stringtoclean); // refused string ':' encoded (no reason to have a : encoded like this) to disable 'javascript:...' - $stringtoclean = preg_replace('/javascript\s*:/i', '', $stringtoclean); $temp = strip_tags($stringtoclean, $allowed_tags_string); // Warning: This remove also undesired changing string obfuscated with that pass injection detection into harmfull string @@ -6950,7 +6922,7 @@ function dol_string_onlythesehtmltags($stringtoclean, $cleanalsosomestyles = 1, // Remove 'javascript:' that we should not find into a text with // Warning: This is not reliable to fight against obfuscated javascript, there is a lot of other solution to include js into a common html tag (only filtered by a GETPOST(.., powerfullfilter)). if ($cleanalsojavascript) { - $temp = preg_replace('/javascript\s*:/i', '', $temp); + $temp = preg_replace('/j\s*a\s*v\s*a\s*s\s*c\s*r\s*i\s*p\s*t\s*:/i', '', $temp); } $temp = str_replace('__!DOCTYPE_HTML__', '', $temp); // Restore the DOCTYPE @@ -7131,6 +7103,91 @@ function dol_nl2br($stringtoencode, $nl2brmode = 0, $forxml = false) } } +/** + * Sanitize a HTML to remove js and dangerous content + * + * @param string $stringtoencode String to encode + * @param int $nouseofiframesandbox Allow use of option MAIN_SECURITY_USE_SANDBOX_FOR_HTMLWITHNOJS for html sanitizing + * @param string $check 'restricthtml' or 'restricthtmlallowunvalid' + * @return string HTML sanitized + */ +function dol_htmlwithnojs($stringtoencode, $nouseofiframesandbox = 0, $check = 'restricthtml') +{ + global $conf; + + if (empty($nouseofiframesandbox) && !empty($conf->global->MAIN_SECURITY_USE_SANDBOX_FOR_HTMLWITHNOJS)) { + // TODO using sandbox on inline html content is not possible yet with current browsers + //$s = ''; + return $stringtoencode; + } else { + $out = $stringtoencode; + + do { + $oldstringtoclean = $out; + + if (!empty($out) && !empty($conf->global->MAIN_RESTRICTHTML_ONLY_VALID_HTML) && $check != 'restricthtmlallowunvalid') { + try { + $dom = new DOMDocument; + // Add a trick to solve pb with text without parent tag + // like '

Foo

bar

' that wrongly ends up without the trick into '

Foo

bar

' + // like 'abc' that wrongly ends up without the tric into with '

abc

' + $out = '
'.$out.'
'; + + $dom->loadHTML($out, LIBXML_ERR_NONE|LIBXML_HTML_NOIMPLIED|LIBXML_HTML_NODEFDTD|LIBXML_NONET|LIBXML_NOWARNING|LIBXML_NOXMLDECL); + $out = trim($dom->saveHTML()); + + // Remove the trick added to solve pb with text without parent tag + $out = preg_replace('/^
/', '', $out); + $out = preg_replace('/<\/div>$/', '', $out); + } catch (Exception $e) { + // If error, invalid HTML string with no way to clean it + //print $e->getMessage(); + $out = 'InvalidHTMLString'; + } + } + + // Clean some html entities that are useless so text is cleaner + $out = preg_replace('/&(tab|newline);/i', ' ', $out); + + // Ckeditor use the numeric entitic for apostrophe so we force it to text entity (all other special chars are + // encoded using text entities) so we can then exclude all numeric entities. + $out = preg_replace('/'/i', ''', $out); + + // We replace chars from a/A to z/Z encoded with numeric HTML entities with the real char so we won't loose the chars at the next step (preg_replace). + // No need to use a loop here, this step is not to sanitize (this is done at next step, this is to try to save chars, even if they are + // using a non coventionnel way to be encoded, to not have them sanitized just after) + $out = preg_replace_callback('/&#(x?[0-9][0-9a-f]+;?)/i', function ($m) { + return realCharForNumericEntities($m); }, $out); + + + // Now we remove all remaining HTML entities starting with a number. We don't want such entities. + $out = preg_replace('/&#x?[0-9]+/i', '', $out); // For example if we have javascript with an entities without the ; to hide the 'a' of 'javascript'. + + // Keep only some html tags and remove also some 'javascript:' strings + $out = dol_string_onlythesehtmltags($out, 0, 1, 1); + + // We should also exclude non expected HTML attributes and clean content of some attributes (keep only alt=, title=...). + if (!empty($conf->global->MAIN_RESTRICTHTML_REMOVE_ALSO_BAD_ATTRIBUTES)) { + // Warning, the function may add a LF so we are forced to trim to compare with old $out without having always a difference and an infinit loop. + $out = dol_string_onlythesehtmlattributes($out); + } + + // Restore entity ' into ' (restricthtml is for html content so we can use html entity) + $out = preg_replace('/'/i', "'", $out); + } while ($oldstringtoclean != $out); + + // Check the limit of external links in a Rich text content. We count ' getDolGlobalInt("MAIN_SECURITY_MAX_IMG_IN_HTML_CONTENT", 1000)) { + $out = 'TooManyLinksIntoHTMLString'; + } + + return $out; + } +} /** * This function is called to encode a string into a HTML string but differs from htmlentities because @@ -7608,7 +7665,11 @@ function getCommonSubstitutionArray($outputlangs, $onlykey = 0, $exclude = null, $substitutionarray['__REF_SUPPLIER__'] = (isset($object->ref_supplier) ? $object->ref_supplier : null); $substitutionarray['__NOTE_PUBLIC__'] = (isset($object->note_public) ? $object->note_public : null); $substitutionarray['__NOTE_PRIVATE__'] = (isset($object->note_private) ? $object->note_private : null); - $substitutionarray['__DATE_DELIVERY__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, 'day', 0, $outputlangs) : ''); + if ($object->element == "shipping") { + $substitutionarray['__DATE_DELIVERY__'] = (isset($object->date_delivery) ? dol_print_date($object->date_delivery, 'day', 0, $outputlangs) : ''); + } else { + $substitutionarray['__DATE_DELIVERY__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, 'day', 0, $outputlangs) : ''); + } $substitutionarray['__DATE_DELIVERY_DAY__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, "%d") : ''); $substitutionarray['__DATE_DELIVERY_DAY_TEXT__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, "%A") : ''); $substitutionarray['__DATE_DELIVERY_MON__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, "%m") : ''); @@ -7963,7 +8024,9 @@ function getCommonSubstitutionArray($outputlangs, $onlykey = 0, $exclude = null, if (empty($exclude) || !in_array('date', $exclude)) { include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; - $tmp = dol_getdate(dol_now(), true); + $now = dol_now(); + + $tmp = dol_getdate($now, true); $tmp2 = dol_get_prev_day($tmp['mday'], $tmp['mon'], $tmp['year']); $tmp3 = dol_get_prev_month($tmp['mon'], $tmp['year']); $tmp4 = dol_get_next_day($tmp['mday'], $tmp['mon'], $tmp['year']); @@ -7972,6 +8035,8 @@ function getCommonSubstitutionArray($outputlangs, $onlykey = 0, $exclude = null, $daytext = $outputlangs->trans('Day'.$tmp['wday']); $substitutionarray = array_merge($substitutionarray, array( + '__NOW_TMS__' => (int) $now, + '__NOW_TMS_YMD__' => dol_print_date($now, 'day', 0, $outputlangs), '__DAY__' => (string) $tmp['mday'], '__DAY_TEXT__' => $daytext, // Monday '__DAY_TEXT_SHORT__' => dol_trunc($daytext, 3, 'right', 'UTF-8', 1), // Mon @@ -8858,7 +8923,7 @@ function dol_eval($s, $returnvalue = 0, $hideerrors = 1, $onlysimplestring = '1' $forbiddenphpstrings = array('$$'); $forbiddenphpstrings = array_merge($forbiddenphpstrings, array('_ENV', '_SESSION', '_COOKIE', '_GET', '_POST', '_REQUEST')); - $forbiddenphpfunctions = array("exec", "passthru", "shell_exec", "system", "proc_open", "popen", "eval", "dol_eval", "executeCLI", 'verifCond'); + $forbiddenphpfunctions = array("exec", "passthru", "shell_exec", "system", "proc_open", "popen", "eval", "dol_eval", "executeCLI", "verifCond", "base64_decode"); $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("fopen", "file_put_contents", "fputs", "fputscsv", "fwrite", "fpassthru", "require", "include", "mkdir", "rmdir", "symlink", "touch", "unlink", "umask")); $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("function", "call_user_func")); @@ -9316,7 +9381,7 @@ function complete_head_from_modules($conf, $langs, $object, &$head, &$h, $type, // No need to make a return $head. Var is modified as a reference if (!empty($hookmanager)) { - $parameters = array('object' => $object, 'mode' => $mode, 'head' => &$head); + $parameters = array('object' => $object, 'mode' => $mode, 'head' => &$head, 'filterorigmodule' => $filterorigmodule); $reshook = $hookmanager->executeHooks('completeTabsHead', $parameters); if ($reshook > 0) { // Hook ask to replace completely the array $head = $hookmanager->resArray; @@ -11450,9 +11515,9 @@ function getTimelineIcon($actionstatic, &$histo, $key) $iconClass = 'fa fa-ticket'; } elseif ($actionstatic->code == 'AC_TICKET_MODIFY') { $iconClass = 'fa fa-pencilxxx'; - } elseif ($actionstatic->code == 'TICKET_MSG') { + } elseif (preg_match('/^TICKET_MSG/', $actionstatic->code)) { $iconClass = 'fa fa-comments'; - } elseif ($actionstatic->code == 'TICKET_MSG_PRIVATE') { + } elseif (preg_match('/^TICKET_MSG_PRIVATE/', $actionstatic->code)) { $iconClass = 'fa fa-mask'; } elseif (!empty($conf->global->AGENDA_USE_EVENT_TYPE)) { if ($actionstatic->type_picto) { @@ -11997,9 +12062,9 @@ function show_actions_messaging($conf, $langs, $db, $filterobj, $objcon = '', $n // Title $out .= ' '; - if ($actionstatic->code == 'TICKET_MSG') { + if (preg_match('/^TICKET_MSG/', $actionstatic->code)) { $out .= $langs->trans('TicketNewMessage'); - } elseif ($actionstatic->code == 'TICKET_MSG_PRIVATE') { + } elseif (preg_match('/^TICKET_MSG_PRIVATE/', $actionstatic->code)) { $out .= $langs->trans('TicketNewMessage').' ('.$langs->trans('Private').')'; } else { if (isset($histo[$key]['type']) && $histo[$key]['type'] == 'action') { diff --git a/htdocs/core/lib/functions2.lib.php b/htdocs/core/lib/functions2.lib.php index 1461ee96c58..bd5a4b16691 100644 --- a/htdocs/core/lib/functions2.lib.php +++ b/htdocs/core/lib/functions2.lib.php @@ -1215,7 +1215,7 @@ function get_next_value($db, $mask, $table, $field, $where = '', $objsoc = '', $ } elseif ($yearlen == 2) { $yearcomp = sprintf("%02d", date("y", $date) + $yearoffset); } elseif ($yearlen == 1) { - $yearcomp = substr(date("y", $date), 2, 1) + $yearoffset; + $yearcomp = substr(date('y', $date), 1, 1) + $yearoffset; } if ($monthcomp > 1 && empty($resetEveryMonth)) { // Test with month is useless if monthcomp = 0 or 1 (0 is same as 1) (regis: $monthcomp can't equal 0) if ($yearlen == 4) { @@ -1282,6 +1282,12 @@ function get_next_value($db, $mask, $table, $field, $where = '', $objsoc = '', $ $sql .= " FROM ".MAIN_DB_PREFIX.$table; $sql .= " WHERE ".$field." LIKE '".$db->escape($maskLike)."'"; $sql .= " AND ".$field." NOT LIKE '(PROV%)'"; + + // To ensure that all variables within the MAX() brackets are integers + if (getDolGlobalInt('MAIN_NUMBERING_FILTER_ON_INT_ONLY')) { + $sql .= " AND ". $db->regexpsql($sqlstring, '^[0-9]+$', true); + } + if ($bentityon) { // only if entity enable $sql .= " AND entity IN (".getEntity($sharetable).")"; } elseif (!empty($forceentity)) { @@ -1755,6 +1761,7 @@ function weight_convert($weight, &$from_unit, $to_unit) * weigh_convert(320, $f, 0) retournera 0.32 * */ + $weight = is_numeric($weight) ? $weight : 0; while ($from_unit <> $to_unit) { if ($from_unit > $to_unit) { $weight = $weight * 10; @@ -2233,7 +2240,11 @@ function dolGetElementUrl($objectid, $objecttype, $withpicto = 0, $option = '') $classpath = 'compta/facture/class'; $classfile = 'facture-rec'; $classname = 'FactureRec'; - $module='facture'; + $module = 'facture'; + } elseif ($objecttype == 'mailing') { + $classpath = 'comm/mailing/class'; + $classfile = 'mailing'; + $classname = 'Mailing'; } if (isModEnabled($module)) { diff --git a/htdocs/core/lib/functionsnumtoword.lib.php b/htdocs/core/lib/functionsnumtoword.lib.php index 1dfe42d63b2..f451f7370eb 100644 --- a/htdocs/core/lib/functionsnumtoword.lib.php +++ b/htdocs/core/lib/functionsnumtoword.lib.php @@ -187,7 +187,7 @@ function dolNumberToWord($numero, $langs, $numorcurrency = 'number') /*In dolibarr 3.6.2 (my current version) doesn't have $langs->default and in case exist why ask $lang like a parameter?*/ - if (((is_object($langs) && $langs->default == 'es_MX') || (!is_object($langs) && $langs == 'es_MX')) && $numorcurrency == 'currency') { + if (((is_object($langs) && $langs->getDefaultLang(0) == 'es_MX') || (!is_object($langs) && $langs == 'es_MX')) && $numorcurrency == 'currency') { if ($numero >= 1 && $numero < 2) { return ("UN PESO ".$parte_decimal." / 100 M.N."); } elseif ($numero >= 0 && $numero < 1) { diff --git a/htdocs/core/lib/holiday.lib.php b/htdocs/core/lib/holiday.lib.php index 4f6da9f6d51..eb0ca243c90 100644 --- a/htdocs/core/lib/holiday.lib.php +++ b/htdocs/core/lib/holiday.lib.php @@ -1,5 +1,6 @@ +/* Copyright (C) 2006-2011 Laurent Destailleur + * Copyright (C) 2022 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 @@ -18,7 +19,7 @@ /** * \file htdocs/core/lib/holiday.lib.php - * \brief Ensemble de fonctions de base pour les adherents + * \brief base functions for holiday */ /** @@ -53,6 +54,8 @@ function holiday_prepare_head($object) $head[$h][2] = 'documents'; $h++; + complete_head_from_modules($conf, $langs, $object, $head, $h, 'holiday', 'add', 'core'); + $head[$h][0] = DOL_URL_ROOT.'/holiday/info.php?id='.$object->id; $head[$h][1] = $langs->trans("Info"); $head[$h][2] = 'info'; @@ -62,7 +65,7 @@ function holiday_prepare_head($object) // Entries must be declared in modules descriptor with line // $this->tabs = array('entity:+tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__'); to add new tab // $this->tabs = array('entity:-tabname); to remove a tab - complete_head_from_modules($conf, $langs, $object, $head, $h, 'holiday'); + complete_head_from_modules($conf, $langs, $object, $head, $h, 'holiday', 'add', 'external'); complete_head_from_modules($conf, $langs, $object, $head, $h, 'holiday', 'remove'); @@ -79,6 +82,9 @@ function holiday_admin_prepare_head() { global $db, $langs, $conf, $user; + $extrafields = new ExtraFields($db); + $extrafields->fetch_name_optionals_label('holiday'); + $h = 0; $head = array(); @@ -95,6 +101,10 @@ function holiday_admin_prepare_head() $head[$h][0] = DOL_URL_ROOT.'/admin/holiday_extrafields.php'; $head[$h][1] = $langs->trans("ExtraFields"); + $nbExtrafields = $extrafields->attributes['holiday']['count']; + if ($nbExtrafields > 0) { + $head[$h][1] .= ''.$nbExtrafields.''; + } $head[$h][2] = 'attributes'; $h++; diff --git a/htdocs/core/lib/modulebuilder.lib.php b/htdocs/core/lib/modulebuilder.lib.php index 498e587a328..163c90aa8a9 100644 --- a/htdocs/core/lib/modulebuilder.lib.php +++ b/htdocs/core/lib/modulebuilder.lib.php @@ -356,7 +356,7 @@ function rebuildObjectSql($destdir, $module, $objectname, $newmask, $readdir = ' } } } - $texttoinsert .= (($val['notnull'] > 0) ? ' NOT NULL' : ''); + $texttoinsert .= ((!empty($val['notnull']) && $val['notnull'] > 0) ? ' NOT NULL' : ''); if ($i < count($object->fields)) { $texttoinsert .= ", "; } diff --git a/htdocs/core/lib/pdf.lib.php b/htdocs/core/lib/pdf.lib.php index f71a6ed6d3c..789a65b93e4 100644 --- a/htdocs/core/lib/pdf.lib.php +++ b/htdocs/core/lib/pdf.lib.php @@ -12,7 +12,7 @@ * Copyright (C) 2015-2016 Marcos García * Copyright (C) 2019 Lenin Rivas * Copyright (C) 2020 Nicolas ZABOURI - * Copyright (C) 2021-2022 Anthony Berton + * Copyright (C) 2021-2022 Anthony Berton * * 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 @@ -400,9 +400,16 @@ function pdfBuildThirdpartyName($thirdparty, Translate $outputlangs, $includeali } } } elseif ($thirdparty instanceof Contact) { - $socname = $thirdparty->socname; - if (($includealias || getDolGlobalInt('PDF_INCLUDE_ALIAS_IN_THIRDPARTY_NAME')) && !empty($thirdparty->name_alias)) { - // TODO PDF_INCLUDE_ALIAS_IN_THIRDPARTY_NAME not completely implemented + if ($thirdparty->socid > 0) { + $thirdparty->fetch_thirdparty(); + $socname = $thirdparty->thirdparty->name; + if (($includealias || getDolGlobalInt('PDF_INCLUDE_ALIAS_IN_THIRDPARTY_NAME')) && !empty($thirdparty->thirdparty->name_alias)) { + if (getDolGlobalInt('PDF_INCLUDE_ALIAS_IN_THIRDPARTY_NAME') == 2) { + $socname = $thirdparty->thirdparty->name_alias." - ".$thirdparty->thirdparty->name; + } else { + $socname = $thirdparty->thirdparty->name." - ".$thirdparty->thirdparty->name_alias; + } + } } } else { throw new InvalidArgumentException('Parameter 1 $thirdparty is not a Societe nor Contact'); diff --git a/htdocs/core/lib/price.lib.php b/htdocs/core/lib/price.lib.php index f85e78865ed..0376b70ecd8 100644 --- a/htdocs/core/lib/price.lib.php +++ b/htdocs/core/lib/price.lib.php @@ -192,8 +192,8 @@ function calcul_price_total($qty, $pu, $remise_percent_ligne, $txtva, $uselocalt // initialize total (may be HT or TTC depending on price_base_type) $tot_sans_remise = $pu * $qty * $progress / 100; - $tot_avec_remise_ligne = $tot_sans_remise * (1 - ($remise_percent_ligne / 100)); - $tot_avec_remise = $tot_avec_remise_ligne * (1 - ($remise_percent_global / 100)); + $tot_avec_remise_ligne = $tot_sans_remise * (1 - ((float) $remise_percent_ligne / 100)); + $tot_avec_remise = $tot_avec_remise_ligne * (1 - ((float) $remise_percent_global / 100)); // initialize result array for ($i = 0; $i <= 15; $i++) { diff --git a/htdocs/core/lib/product.lib.php b/htdocs/core/lib/product.lib.php index 79d8ac57834..e919bf2c8b6 100644 --- a/htdocs/core/lib/product.lib.php +++ b/htdocs/core/lib/product.lib.php @@ -374,7 +374,10 @@ function product_admin_prepare_head() */ function product_lot_admin_prepare_head() { - global $langs, $conf, $user; + global $langs, $conf, $user, $db; + + $extrafields = new ExtraFields($db); + $extrafields->fetch_name_optionals_label('product_lot'); $h = 0; $head = array(); @@ -392,6 +395,10 @@ function product_lot_admin_prepare_head() $head[$h][0] = DOL_URL_ROOT.'/product/admin/product_lot_extrafields.php'; $head[$h][1] = $langs->trans("ExtraFields"); + $nbExtrafields = $extrafields->attributes['product_lot']['count']; + if ($nbExtrafields > 0) { + $head[$h][1] .= ''.$nbExtrafields.''; + } $head[$h][2] = 'attributes'; $h++; diff --git a/htdocs/core/lib/project.lib.php b/htdocs/core/lib/project.lib.php index 56079824f7c..beac7180297 100644 --- a/htdocs/core/lib/project.lib.php +++ b/htdocs/core/lib/project.lib.php @@ -209,6 +209,19 @@ function project_prepare_head(Project $project, $moreparam = '') $h++; } + if (isModEnabled('ticket') && $user->hasRight('ticket', 'read')) { + require_once DOL_DOCUMENT_ROOT.'/ticket/class/ticket.class.php'; + $Tickettatic = new Ticket($db); + $nbTicket = count($Tickettatic->getAllItemsLinkedByObjectID($project->id, '*', 'fk_project', 'ticket')); + $head[$h][0] = DOL_URL_ROOT.'/ticket/list.php?projectid='.((int) $project->id); + $head[$h][1] = $langs->trans("Ticket"); + if ($nbTicket > 0) { + $head[$h][1] .= ''.($nbTicket).''; + } + $head[$h][2] = 'ticket'; + $h++; + } + if (isModEnabled('eventorganization') && !empty($project->usage_organize_event)) { $langs->load('eventorganization'); $head[$h][0] = DOL_URL_ROOT . '/eventorganization/conferenceorbooth_list.php?projectid=' . $project->id; @@ -1062,6 +1075,7 @@ function projectLinesa(&$inc, $parent, &$lines, &$level, $var, $showproject, &$t * @param string $projectsrole Array of roles user has on project * @param string $tasksrole Array of roles user has on task * @param string $mine Show only task lines I am assigned to +<<<<<<<<< Temporary merge branch 1 * @param int $restricteditformytask 0=No restriction, 1=Enable add time only if task is a task i am affected to * @param int $preselectedday Preselected day * @param array $isavailable Array with data that say if user is available for several days for morning and afternoon @@ -1544,7 +1558,7 @@ function projectLinesPerDay(&$inc, $parent, $fuser, $lines, &$level, &$projectsr if (!empty($arrayfields['timeconsumed']['checked'])) { // Time spent by everybody print '
'; - // $lines[$i]->duration is a denormalised field = summ of time spent by everybody for task. What we need is time consummed by user + // $lines[$i]->duration is a denormalised field = summ of time spent by everybody for task. What we need is time consumed by user if ($lines[$i]->duration) { print ''; print convertSecondToTime($lines[$i]->duration, 'allhourmin'); @@ -1950,7 +1964,7 @@ function projectLinesPerWeek(&$inc, $firstdaytoshow, $fuser, $parent, $lines, &$ if (!empty($arrayfields['timeconsumed']['checked'])) { // Time spent by everybody print ''; - // $lines[$i]->duration is a denormalised field = summ of time spent by everybody for task. What we need is time consummed by user + // $lines[$i]->duration is a denormalised field = summ of time spent by everybody for task. What we need is time consumed by user if ($lines[$i]->duration) { print ''; print convertSecondToTime($lines[$i]->duration, 'allhourmin'); @@ -2244,7 +2258,7 @@ function projectLinesPerMonth(&$inc, $firstdaytoshow, $fuser, $parent, $lines, & // Time spent by everybody print ''; - // $lines[$i]->duration is a denormalised field = summ of time spent by everybody for task. What we need is time consummed by user + // $lines[$i]->duration is a denormalised field = summ of time spent by everybody for task. What we need is time consumed by user if ($lines[$i]->duration) { print ''; print convertSecondToTime($lines[$i]->duration, 'allhourmin'); diff --git a/htdocs/core/lib/reception.lib.php b/htdocs/core/lib/reception.lib.php index 7f5c6e865de..e697908e8cb 100644 --- a/htdocs/core/lib/reception.lib.php +++ b/htdocs/core/lib/reception.lib.php @@ -110,9 +110,13 @@ function reception_prepare_head(Reception $object) */ function reception_admin_prepare_head() { - global $langs, $conf, $user; + global $langs, $conf, $user, $db; $langs->load("receptions"); + $extrafields = new ExtraFields($db); + $extrafields->fetch_name_optionals_label('reception'); + $extrafields->fetch_name_optionals_label('commande_fournisseur_dispatch'); + $h = 0; $head = array(); @@ -126,6 +130,10 @@ function reception_admin_prepare_head() if (!empty($conf->global->MAIN_SUBMODULE_RECEPTION)) { $head[$h][0] = DOL_URL_ROOT.'/admin/reception_extrafields.php'; $head[$h][1] = $langs->trans("ExtraFields"); + $nbExtrafields = $extrafields->attributes['reception']['count']; + if ($nbExtrafields > 0) { + $head[$h][1] .= ''.$nbExtrafields.''; + } $head[$h][2] = 'attributes_reception'; $h++; } @@ -133,6 +141,10 @@ function reception_admin_prepare_head() if (!empty($conf->global->MAIN_SUBMODULE_RECEPTION)) { $head[$h][0] = DOL_URL_ROOT.'/admin/commande_fournisseur_dispatch_extrafields.php'; $head[$h][1] = $langs->trans("ExtraFieldsLines"); + $nbExtrafields = $extrafields->attributes['commande_fournisseur_dispatch']['count']; + if ($nbExtrafields > 0) { + $head[$h][1] .= ''.$nbExtrafields.''; + } $head[$h][2] = 'attributeslines_reception'; $h++; } diff --git a/htdocs/core/lib/security.lib.php b/htdocs/core/lib/security.lib.php index 8e1ed6cebd1..3ec94953284 100644 --- a/htdocs/core/lib/security.lib.php +++ b/htdocs/core/lib/security.lib.php @@ -318,27 +318,32 @@ function dolGetLdapPasswordHash($password, $type = 'md5') * If GETPOST('action','aZ09') defined, we also check write and delete permission. * This method check permission on module then call checkUserAccessToObject() for permission on object (according to entity and socid of user). * - * @param User $user User to check - * @param string $features Features to check (it must be module $object->element. Can be a 'or' check with 'levela|levelb'. - * Examples: 'societe', 'contact', 'produit&service', 'produit|service', ...) - * This is used to check permission $user->rights->features->... - * @param int $objectid Object ID if we want to check a particular record (optional) is linked to a owned thirdparty (optional). - * @param string $tableandshare 'TableName&SharedElement' with Tablename is table where object is stored. SharedElement is an optional key to define where to check entity for multicompany module. Param not used if objectid is null (optional). - * @param string $feature2 Feature to check, second level of permission (optional). Can be a 'or' check with 'sublevela|sublevelb'. - * This is used to check permission $user->rights->features->feature2... - * @param string $dbt_keyfield Field name for socid foreign key if not fk_soc. Not used if objectid is null (optional) - * @param string $dbt_select Field name for select if not rowid. Not used if objectid is null (optional) - * @param int $isdraft 1=The object with id=$objectid is a draft - * @param int $mode Mode (0=default, 1=return without dieing) - * @return int If mode = 0 (default): Always 1, die process if not allowed. If mode = 1: Return 0 if access not allowed. + * @param User $user User to check + * @param string $features Features to check (it must be module $object->element. Can be a 'or' check with 'levela|levelb'. + * Examples: 'societe', 'contact', 'produit&service', 'produit|service', ...) + * This is used to check permission $user->rights->features->... + * @param int|string|object $object Object or Object ID or list of Object ID if we want to check a particular record (optional) is linked to a owned thirdparty (optional). + * @param string $tableandshare 'TableName&SharedElement' with Tablename is table where object is stored. SharedElement is an optional key to define where to check entity for multicompany module. Param not used if objectid is null (optional). + * @param string $feature2 Feature to check, second level of permission (optional). Can be a 'or' check with 'sublevela|sublevelb'. + * This is used to check permission $user->rights->features->feature2... + * @param string $dbt_keyfield Field name for socid foreign key if not fk_soc. Not used if objectid is null (optional). Can use '' if NA. + * @param string $dbt_select Field name for select if not "rowid". Not used if objectid is null (optional) + * @param int $isdraft 1=The object with id=$objectid is a draft + * @param int $mode Mode (0=default, 1=return without dieing) + * @return int If mode = 0 (default): Always 1, die process if not allowed. If mode = 1: Return 0 if access not allowed. * @see dol_check_secure_access_document(), checkUserAccessToObject() */ -function restrictedArea(User $user, $features, $objectid = 0, $tableandshare = '', $feature2 = '', $dbt_keyfield = 'fk_soc', $dbt_select = 'rowid', $isdraft = 0, $mode = 0) +function restrictedArea(User $user, $features, $object = 0, $tableandshare = '', $feature2 = '', $dbt_keyfield = 'fk_soc', $dbt_select = 'rowid', $isdraft = 0, $mode = 0) { global $db, $conf; global $hookmanager; - $objectid = ((int) $objectid); // For the case value is coming from a non sanitized user input + if (is_object($object)) { + $objectid = $object->id; + } else { + $objectid = $object; // $objectid can be X or 'X,Y,Z' + } + $objectid = preg_replace('/[^0-9\.\,]/', '', $objectid); // For the case value is coming from a non sanitized user input //dol_syslog("functions.lib:restrictedArea $feature, $objectid, $dbtablename, $feature2, $dbt_socfield, $dbt_select, $isdraft"); //print "user_id=".$user->id.", features=".$features.", feature2=".$feature2.", objectid=".$objectid; @@ -391,11 +396,6 @@ function restrictedArea(User $user, $features, $objectid = 0, $tableandshare = ' return 1; } - // To avoid access forbidden with numeric ref - if ($dbt_select != 'rowid' && $dbt_select != 'id') { - $objectid = "'".$objectid."'"; - } - // Features/modules to check $featuresarray = array($features); if (preg_match('/&/', $features)) { @@ -426,7 +426,7 @@ function restrictedArea(User $user, $features, $objectid = 0, $tableandshare = ' } if ($feature == 'societe') { - if (!$user->hasRight('societe', 'lire') && empty($user->rights->fournisseur->lire)) { + if (!$user->hasRight('societe', 'lire') && !$user->hasRight('fournisseur', 'lire')) { $readok = 0; $nbko++; } @@ -436,12 +436,12 @@ function restrictedArea(User $user, $features, $objectid = 0, $tableandshare = ' $nbko++; } } elseif ($feature == 'produit|service') { - if (!$user->rights->produit->lire && !$user->rights->service->lire) { + if (empty($user->rights->produit->lire) && empty($user->rights->service->lire)) { $readok = 0; $nbko++; } } elseif ($feature == 'prelevement') { - if (!$user->rights->prelevement->bons->lire) { + if (empty($user->rights->prelevement->bons->lire)) { $readok = 0; $nbko++; } @@ -451,12 +451,12 @@ function restrictedArea(User $user, $features, $objectid = 0, $tableandshare = ' $nbko++; } } elseif ($feature == 'projet') { - if (!$user->rights->projet->lire && empty($user->rights->projet->all->lire)) { + if (empty($user->rights->projet->lire) && empty($user->rights->projet->all->lire)) { $readok = 0; $nbko++; } } elseif ($feature == 'payment') { - if (!$user->rights->facture->lire) { + if (empty($user->rights->facture->lire)) { $readok = 0; $nbko++; } @@ -716,7 +716,7 @@ function restrictedArea(User $user, $features, $objectid = 0, $tableandshare = ' // If we have a particular object to check permissions on, we check if $user has permission // for this given object (link to company, is contact for project, ...) if (!empty($objectid) && $objectid > 0) { - $ok = checkUserAccessToObject($user, $featuresarray, $objectid, $tableandshare, $feature2, $dbt_keyfield, $dbt_select, $parentfortableentity); + $ok = checkUserAccessToObject($user, $featuresarray, $object, $tableandshare, $feature2, $dbt_keyfield, $dbt_select, $parentfortableentity); $params = array('objectid' => $objectid, 'features' => join(',', $featuresarray), 'features2' => $feature2); //print 'checkUserAccessToObject ok='.$ok; if ($mode) { @@ -737,9 +737,9 @@ function restrictedArea(User $user, $features, $objectid = 0, $tableandshare = ' * @param array $featuresarray Features/modules to check. Example: ('user','service','member','project','task',...) * @param int|string|Object $object Full object or object ID or list of object id. For example if we want to check a particular record (optional) is linked to a owned thirdparty (optional). * @param string $tableandshare 'TableName&SharedElement' with Tablename is table where object is stored. SharedElement is an optional key to define where to check entity for multicompany modume. Param not used if objectid is null (optional). - * @param string $feature2 Feature to check, second level of permission (optional). Can be or check with 'level1|level2'. - * @param string $dbt_keyfield Field name for socid foreign key if not fk_soc. Not used if objectid is null (optional) - * @param string $dbt_select Field name for select if not rowid. Not used if objectid is null (optional) + * @param array|string $feature2 Feature to check, second level of permission (optional). Can be or check with 'level1|level2'. + * @param string $dbt_keyfield Field name for socid foreign key if not fk_soc. Not used if objectid is null (optional). Can use '' if NA. + * @param string $dbt_select Field name for select if not rowid. Not used if objectid is null (optional). * @param string $parenttableforentity Parent table for entity. Example 'fk_website@website' * @return bool True if user has access, False otherwise * @see restrictedArea() @@ -753,9 +753,10 @@ function checkUserAccessToObject($user, array $featuresarray, $object = 0, $tabl } else { $objectid = $object; // $objectid can be X or 'X,Y,Z' } + $objectid = preg_replace('/[^0-9\.\,]/', '', $objectid); // For the case value is coming from a non sanitized user input //dol_syslog("functions.lib:restrictedArea $feature, $objectid, $dbtablename, $feature2, $dbt_socfield, $dbt_select, $isdraft"); - //print "user_id=".$user->id.", features=".join(',', $featuresarray).", feature2=".$feature2.", objectid=".$objectid; + //print "user_id=".$user->id.", features=".join(',', $featuresarray).", objectid=".$objectid; //print ", tableandshare=".$tableandshare.", dbt_socfield=".$dbt_keyfield.", dbt_select=".$dbt_select."
"; // More parameters @@ -783,12 +784,13 @@ function checkUserAccessToObject($user, array $featuresarray, $object = 0, $tabl // Array to define rules of checks to do $check = array('adherent', 'banque', 'bom', 'don', 'mrp', 'user', 'usergroup', 'payment', 'payment_supplier', 'product', 'produit', 'service', 'produit|service', 'categorie', 'resource', 'expensereport', 'holiday', 'salaries', 'website', 'recruitment'); // Test on entity only (Objects with no link to company) - $checksoc = array('societe'); // Test for societe object + $checksoc = array('societe'); // Test for object Societe $checkother = array('contact', 'agenda'); // Test on entity + link to third party on field $dbt_keyfield. Allowed if link is empty (Ex: contacts...). $checkproject = array('projet', 'project'); // Test for project object $checktask = array('projet_task'); // Test for task object - $checkhierarchy = array('expensereport', 'holiday'); + $checkhierarchy = array('expensereport', 'holiday'); // check permission among the hierarchy of user $nocheck = array('barcode', 'stock'); // No test + //$checkdefault = 'all other not already defined'; // Test on entity + link to third party on field $dbt_keyfield. Not allowed if link is empty (Ex: invoice, orders...). // If dbtablename not defined, we use same name for table than module name @@ -797,6 +799,11 @@ function checkUserAccessToObject($user, array $featuresarray, $object = 0, $tabl $sharedelement = (!empty($params[1]) ? $params[1] : $dbtablename); // We change dbtablename, so we set sharedelement too. } + // To avoid an access forbidden with a numeric ref + if ($dbt_select != 'rowid' && $dbt_select != 'id') { + $objectid = "'".$objectid."'"; // Note: $objectid was already cast into int at begin of this method. + } + // Check permission for objectid on entity only if (in_array($feature, $check) && $objectid > 0) { // For $objectid = 0, no check $sql = "SELECT COUNT(dbt.".$dbt_select.") as nb"; diff --git a/htdocs/core/lib/security2.lib.php b/htdocs/core/lib/security2.lib.php index 287a151f41c..b33ad1333ef 100644 --- a/htdocs/core/lib/security2.lib.php +++ b/htdocs/core/lib/security2.lib.php @@ -191,8 +191,26 @@ if (!function_exists('dol_loginfunction')) { // and the conf file is loaded. $prefix = dol_getprefix(''); $sessiontimeout = 'DOLSESSTIMEOUT_'.$prefix; + if (!empty($conf->global->MAIN_SESSION_TIMEOUT)) { - setcookie($sessiontimeout, $conf->global->MAIN_SESSION_TIMEOUT, 0, "/", null, (empty($dolibarr_main_force_https) ? false : true), true); + if (session_status() != PHP_SESSION_ACTIVE) { + if (PHP_VERSION_ID < 70300) { + session_set_cookie_params(0, '/', null, ((empty($dolibarr_main_force_https) && isHTTPS() === false) ? false : true), true); // Add tag secure and httponly on session cookie (same as setting session.cookie_httponly into php.ini). Must be called before the session_start. + } else { + // Only available for php >= 7.3 + $sessioncookieparams = array( + 'lifetime' => 0, + 'path' => '/', + //'domain' => '.mywebsite.com', // the dot at the beginning allows compatibility with subdomains + 'secure' => ((empty($dolibarr_main_force_https) && isHTTPS() === false) ? false : true), + 'httponly' => true, + 'samesite' => 'Lax' // None || Lax || Strict + ); + session_set_cookie_params($sessioncookieparams); + } + + setcookie($sessiontimeout, $conf->global->MAIN_SESSION_TIMEOUT, 0, "/", null, (empty($dolibarr_main_force_https) ? false : true), true); + } } if (GETPOST('urlfrom', 'alpha')) { diff --git a/htdocs/core/lib/supplier_proposal.lib.php b/htdocs/core/lib/supplier_proposal.lib.php index 3c9915bc951..11c0786802f 100644 --- a/htdocs/core/lib/supplier_proposal.lib.php +++ b/htdocs/core/lib/supplier_proposal.lib.php @@ -1,6 +1,7 @@ * Copyright (C) 2005-2012 Regis Houssin + * Copyright (C) 2022 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 @@ -110,7 +111,11 @@ function supplier_proposal_prepare_head($object) */ function supplier_proposal_admin_prepare_head() { - global $langs, $conf, $user; + global $langs, $conf, $user, $db; + + $extrafields = new ExtraFields($db); + $extrafields->fetch_name_optionals_label('supplier_proposal'); + $extrafields->fetch_name_optionals_label('supplier_proposaldet'); $h = 0; $head = array(); @@ -128,11 +133,19 @@ function supplier_proposal_admin_prepare_head() $head[$h][0] = DOL_URL_ROOT.'/supplier_proposal/admin/supplier_proposal_extrafields.php'; $head[$h][1] = $langs->trans("ExtraFields"); + $nbExtrafields = $extrafields->attributes['supplier_proposal']['count']; + if ($nbExtrafields > 0) { + $head[$h][1] .= ''.$nbExtrafields.''; + } $head[$h][2] = 'attributes'; $h++; $head[$h][0] = DOL_URL_ROOT.'/supplier_proposal/admin/supplier_proposaldet_extrafields.php'; $head[$h][1] = $langs->trans("ExtraFieldsLines"); + $nbExtrafields = $extrafields->attributes['supplier_proposaldet']['count']; + if ($nbExtrafields > 0) { + $head[$h][1] .= ''.$nbExtrafields.''; + } $head[$h][2] = 'attributeslines'; $h++; diff --git a/htdocs/core/lib/website.lib.php b/htdocs/core/lib/website.lib.php index 4b43230adda..c258e3198ce 100644 --- a/htdocs/core/lib/website.lib.php +++ b/htdocs/core/lib/website.lib.php @@ -936,7 +936,7 @@ function getSocialNetworkSharingLinks() * @param string $langcode Language code ('' or 'en', 'fr', 'es', ...) * @param array $otherfilters Other filters * @param int $status 0 or 1, or -1 for both - * @return string HTML content + * @return array Array with results of search */ function getPagesFromSearchCriterias($type, $algo, $searchstring, $max = 25, $sortfield = 'date_creation', $sortorder = 'DESC', $langcode = '', $otherfilters = 'null', $status = 1) { @@ -974,6 +974,8 @@ function getPagesFromSearchCriterias($type, $algo, $searchstring, $max = 25, $so $found = 0; if (!$error && (empty($max) || ($found < $max)) && (preg_match('/meta/', $algo) || preg_match('/content/', $algo))) { + include_once DOL_DOCUMENT_ROOT.'/website/class/websitepage.class.php'; + $sql = 'SELECT wp.rowid FROM '.MAIN_DB_PREFIX.'website_page as wp'; if (is_array($otherfilters) && !empty($otherfilters['category'])) { $sql .= ', '.MAIN_DB_PREFIX.'categorie_website_page as cwp'; @@ -983,7 +985,7 @@ function getPagesFromSearchCriterias($type, $algo, $searchstring, $max = 25, $so $sql .= " AND wp.status = ".((int) $status); } if ($langcode) { - $sql .= " AND wp.lang ='".$db->escape($langcode)."'"; + $sql .= " AND wp.lang = '".$db->escape($langcode)."'"; } if ($type) { $tmparrayoftype = explode(',', $type); @@ -996,11 +998,11 @@ function getPagesFromSearchCriterias($type, $algo, $searchstring, $max = 25, $so $sql .= " AND ("; $searchalgo = ''; if (preg_match('/meta/', $algo)) { - $searchalgo .= ($searchalgo ? ' OR ' : '')."wp.title LIKE '%".$db->escapeforlike($db->escape($searchstring))."%' OR wp.description LIKE '%".$db->escapeforlike($db->escape($searchstring))."%'"; - $searchalgo .= ($searchalgo ? ' OR ' : '')."wp.keywords LIKE '".$db->escapeforlike($db->escape($searchstring)).",%' OR wp.keywords LIKE '% ".$db->escapeforlike($db->escape($searchstring))."%'"; // TODO Use a better way to scan keywords + $searchalgo .= ($searchalgo ? ' OR ' : '')."wp.title LIKE '%".$db->escape($db->escapeforlike($searchstring))."%' OR wp.description LIKE '%".$db->escape($db->escapeforlike($searchstring))."%'"; + $searchalgo .= ($searchalgo ? ' OR ' : '')."wp.keywords LIKE '".$db->escape($db->escapeforlike($searchstring)).",%' OR wp.keywords LIKE '% ".$db->escape($db->escapeforlike($searchstring))."%'"; // TODO Use a better way to scan keywords } if (preg_match('/content/', $algo)) { - $searchalgo .= ($searchalgo ? ' OR ' : '')."wp.content LIKE '%".$db->escapeforlike($db->escape($searchstring))."%'"; + $searchalgo .= ($searchalgo ? ' OR ' : '')."wp.content LIKE '%".$db->escape($db->escapeforlike($searchstring))."%'"; } $sql .= $searchalgo; if (is_array($otherfilters) && !empty($otherfilters['category'])) { @@ -1012,6 +1014,7 @@ function getPagesFromSearchCriterias($type, $algo, $searchstring, $max = 25, $so //print $sql; $resql = $db->query($sql); + if ($resql) { $i = 0; while (($obj = $db->fetch_object($resql)) && ($i < $max || $max == 0)) { diff --git a/htdocs/core/lib/website2.lib.php b/htdocs/core/lib/website2.lib.php index 0b836399f43..05727a1e539 100644 --- a/htdocs/core/lib/website2.lib.php +++ b/htdocs/core/lib/website2.lib.php @@ -722,11 +722,31 @@ function checkPHPCode($phpfullcodestringold, $phpfullcodestring) setEventMessages($langs->trans("DynamicPHPCodeContainsAForbiddenInstruction", '$...('), null, 'errors'); } - if (!$error && empty($user->rights->website->writephp)) { - if ($phpfullcodestringold != $phpfullcodestring) { + if ($phpfullcodestringold != $phpfullcodestring) { + if (!$error && empty($user->rights->website->writephp)) { $error++; setEventMessages($langs->trans("NotAllowedToAddDynamicContent"), null, 'errors'); } + if (!$error) { + $dolibarrdataroot = preg_replace('/([\\/]+)$/i', '', DOL_DATA_ROOT); + $allowimportsite = true; + if (dol_is_file($dolibarrdataroot.'/installmodules.lock')) { + $allowimportsite = false; + } + + if (!$allowimportsite) { + $error++; + // Blocked by installmodules.lock + if (getDolGlobalString('MAIN_MESSAGE_INSTALL_MODULES_DISABLED_CONTACT_US')) { + // Show clean corporate message + $message = $langs->trans('InstallModuleFromWebHasBeenDisabledContactUs'); + } else { + // Show technical generic message + $message = $langs->trans("InstallModuleFromWebHasBeenDisabledByFile", $dolibarrdataroot.'/installmodules.lock'); + } + setEventMessages($message, null, 'errors'); + } + } } return $error; diff --git a/htdocs/core/menus/standard/eldy.lib.php b/htdocs/core/menus/standard/eldy.lib.php index a09f85e1f4e..398aa6421a7 100644 --- a/htdocs/core/menus/standard/eldy.lib.php +++ b/htdocs/core/menus/standard/eldy.lib.php @@ -1726,10 +1726,10 @@ function get_left_menu_accountancy($mainmenu, &$newmenu, $usemenuhider = 1, $lef if ($nature) { $langs->load('accountancy'); - $journallabel = $langs->transnoentities($objp->label); // Labels in this table are set by loading llx_accounting_abc.sql. Label can be 'ACCOUNTING_SELL_JOURNAL', 'InventoryJournal', ... + $journallabel = $langs->transnoentities($objp->label); // Label of bank account in llx_accounting_journal $key = $langs->trans("AccountingJournalType".strtoupper($objp->nature)); - $transferlabel = ($objp->nature && $key != "AccountingJournalType".strtoupper($langs->trans($objp->nature)) ? $key : $objp->label); + $transferlabel = ($objp->nature && $key != "AccountingJournalType".strtoupper($langs->trans($objp->nature)) ? $key.($journallabel != $key ? ' '.$journallabel : ''): $journallabel); $newmenu->add('/accountancy/journal/'.$nature.'journal.php?mainmenu=accountancy&leftmenu=accountancy_journal&id_journal='.$objp->rowid, $transferlabel, 2, $user->hasRight('accounting', 'comptarapport', 'lire')); } diff --git a/htdocs/core/modules/asset/doc/doc_generic_asset_odt.modules.php b/htdocs/core/modules/asset/doc/doc_generic_asset_odt.modules.php index b11e2a7e563..8be86dda944 100644 --- a/htdocs/core/modules/asset/doc/doc_generic_asset_odt.modules.php +++ b/htdocs/core/modules/asset/doc/doc_generic_asset_odt.modules.php @@ -173,7 +173,9 @@ class doc_generic_asset_odt extends ModelePDFAsset if ($nbofiles) { $texte .= '
'; } diff --git a/htdocs/core/modules/barcode/modules_barcode.class.php b/htdocs/core/modules/barcode/modules_barcode.class.php index 01a00405452..dac575cbb17 100644 --- a/htdocs/core/modules/barcode/modules_barcode.class.php +++ b/htdocs/core/modules/barcode/modules_barcode.class.php @@ -75,7 +75,7 @@ abstract class ModeleNumRefBarCode */ public function getNom($langs) { - return empty($this->name) ? $this->nom : $this->name; + return empty($this->name) ? get_class($this) : $this->name; } /** Return a numbering example diff --git a/htdocs/core/modules/bom/doc/doc_generic_bom_odt.modules.php b/htdocs/core/modules/bom/doc/doc_generic_bom_odt.modules.php index 2dcf5512dc1..bec28b941aa 100644 --- a/htdocs/core/modules/bom/doc/doc_generic_bom_odt.modules.php +++ b/htdocs/core/modules/bom/doc/doc_generic_bom_odt.modules.php @@ -169,7 +169,9 @@ class doc_generic_bom_odt extends ModelePDFBom $texte .= '
'; // Show list of found files foreach ($listoffiles as $file) { - $texte .= '- '.$file['name'].' '.img_picto('', 'listlight').'
'; + $texte .= '- '.$file['name'].' '.img_picto('', 'listlight').''; + $texte .= '   '.img_picto('', 'delete').''; + $texte .= '
'; } $texte .= '
'; } diff --git a/htdocs/core/modules/commande/doc/doc_generic_order_odt.modules.php b/htdocs/core/modules/commande/doc/doc_generic_order_odt.modules.php index 9239ec0ed4b..5e94397bc91 100644 --- a/htdocs/core/modules/commande/doc/doc_generic_order_odt.modules.php +++ b/htdocs/core/modules/commande/doc/doc_generic_order_odt.modules.php @@ -159,7 +159,7 @@ class doc_generic_order_odt extends ModelePDFCommandes $texte .= $conf->global->COMMANDE_ADDON_PDF_ODT_PATH; $texte .= ''; $texte .= '
'; - $texte .= ''; + $texte .= ''; $texte .= '
'; // Scan directories @@ -176,7 +176,9 @@ class doc_generic_order_odt extends ModelePDFCommandes $texte .= '
'; // Show list of found files foreach ($listoffiles as $file) { - $texte .= '- '.$file['name'].' '.img_picto('', 'listlight').'
'; + $texte .= '- '.$file['name'].' '.img_picto('', 'listlight').''; + $texte .= '   '.img_picto('', 'delete').''; + $texte .= '
'; } $texte .= '
'; } diff --git a/htdocs/core/modules/contract/doc/doc_generic_contract_odt.modules.php b/htdocs/core/modules/contract/doc/doc_generic_contract_odt.modules.php index 222286d5592..dad1ebc9122 100644 --- a/htdocs/core/modules/contract/doc/doc_generic_contract_odt.modules.php +++ b/htdocs/core/modules/contract/doc/doc_generic_contract_odt.modules.php @@ -51,8 +51,7 @@ class doc_generic_contract_odt extends ModelePDFContract public $phpmin = array(7, 0); /** - * Dolibarr version of the loaded document - * @var string + * @var string Dolibarr version of the loaded document */ public $version = 'dolibarr'; @@ -94,7 +93,7 @@ class doc_generic_contract_odt extends ModelePDFContract $this->option_freetext = 1; // Support add of a personalised text $this->option_draft_watermark = 0; // Support add of a watermark on drafts - // Recupere emetteur + // Get source company $this->emetteur = $mysoc; if (!$this->emetteur->country_code) { $this->emetteur->country_code = substr($langs->defaultlang, -2); // By default if not defined @@ -123,7 +122,7 @@ class doc_generic_contract_odt extends ModelePDFContract $texte .= ''; $texte .= ''; $texte .= ''; - $texte .= ''; + $texte .= '
'; // List of directories area $texte .= ''; - } elseif ($don->modepaymentcode == 'LIQ') { + } elseif ($modepaymentcode == 'LIQ') { $ModePaiement = ''; - } elseif ($don->modepaymentcode == 'VIR' || $don->modepaymentcode == 'PRE' || $don->modepaymentcode == 'CB') { + } elseif ($modepaymentcode == 'VIR' || $modepaymentcode == 'PRE' || $modepaymentcode == 'CB') { $ModePaiement = ''; } else { $ModePaiement = ''; diff --git a/htdocs/core/modules/expedition/doc/doc_generic_shipment_odt.modules.php b/htdocs/core/modules/expedition/doc/doc_generic_shipment_odt.modules.php index cfb23269ca9..73793c5a757 100644 --- a/htdocs/core/modules/expedition/doc/doc_generic_shipment_odt.modules.php +++ b/htdocs/core/modules/expedition/doc/doc_generic_shipment_odt.modules.php @@ -175,7 +175,9 @@ class doc_generic_shipment_odt extends ModelePdfExpedition $texte .= '
'; // Show list of found files foreach ($listoffiles as $file) { - $texte .= '- '.$file['name'].' '.img_picto('', 'listlight').'
'; + $texte .= '- '.$file['name'].' '.img_picto('', 'listlight').''; + $texte .= '   '.img_picto('', 'delete').''; + $texte .= '
'; } $texte .= '
'; } 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 061f18e5442..0b8fa2d4621 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 @@ -174,7 +174,9 @@ class doc_generic_invoice_odt extends ModelePDFFactures $texte .= '
'; // Show list of found files foreach ($listoffiles as $file) { - $texte .= '- '.$file['name'].' '.img_picto('', 'listlight').'
'; + $texte .= '- '.$file['name'].' '.img_picto('', 'listlight').''; + $texte .= '   '.img_picto('', 'delete').''; + $texte .= '
'; } $texte .= '
'; } diff --git a/htdocs/core/modules/facture/doc/pdf_crabe.modules.php b/htdocs/core/modules/facture/doc/pdf_crabe.modules.php index 39d833de6cc..ee4cc9b5d0d 100644 --- a/htdocs/core/modules/facture/doc/pdf_crabe.modules.php +++ b/htdocs/core/modules/facture/doc/pdf_crabe.modules.php @@ -9,6 +9,7 @@ * Copyright (C) 2015 Marcos García * Copyright (C) 2017-2018 Ferran Marcet * Copyright (C) 2018-2020 Frédéric France + * Copyright (C) 2022 Anthony Berton * * 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 @@ -579,7 +580,8 @@ class pdf_crabe extends ModelePDFFactures $pdf->useTemplate($tplidx); } if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) { - $this->_pagehead($pdf, $object, 0, $outputlangs); + $top_shift = $this->_pagehead($pdf, $object, 0, $outputlangs); + $tab_top_newpage = (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD') ? 42 + $top_shift : 10); } $pdf->setPage($pageposbefore + 1); @@ -622,7 +624,8 @@ class pdf_crabe extends ModelePDFFactures $pdf->useTemplate($tplidx); } if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) { - $this->_pagehead($pdf, $object, 0, $outputlangs); + $top_shift = $this->_pagehead($pdf, $object, 0, $outputlangs); + $tab_top_newpage = (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD') ? 42 + $top_shift : 10); } $pdf->setPage($pageposafter + 1); } @@ -749,10 +752,18 @@ class pdf_crabe extends ModelePDFFactures // retrieve global local tax if ($localtax1_type && $localtax1ligne != 0) { - $this->localtax1[$localtax1_type][$localtax1_rate] += $localtax1ligne; + if (empty($this->localtax1[$localtax1_type][$localtax1_rate])) { + $this->localtax1[$localtax1_type][$localtax1_rate] = $localtax1ligne; + } else { + $this->localtax1[$localtax1_type][$localtax1_rate] += $localtax1ligne; + } } if ($localtax2_type && $localtax2ligne != 0) { - $this->localtax2[$localtax2_type][$localtax2_rate] += $localtax2ligne; + if (empty($this->localtax2[$localtax2_type][$localtax2_rate])) { + $this->localtax2[$localtax2_type][$localtax2_rate] = $localtax2ligne; + } else { + $this->localtax2[$localtax2_type][$localtax2_rate] += $localtax2ligne; + } } if (($object->lines[$i]->info_bits & 0x01) == 0x01) { @@ -798,7 +809,8 @@ class pdf_crabe extends ModelePDFFactures $pdf->setPage($pagenb); $pdf->setPageOrientation('', 1, 0); // The only function to edit the bottom margin of current page to set it. if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) { - $this->_pagehead($pdf, $object, 0, $outputlangs); + $top_shift = $this->_pagehead($pdf, $object, 0, $outputlangs); + $tab_top_newpage = (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD') ? 42 + $top_shift : 10); } if (!empty($tplidx)) { $pdf->useTemplate($tplidx); @@ -818,7 +830,8 @@ class pdf_crabe extends ModelePDFFactures } $pagenb++; if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) { - $this->_pagehead($pdf, $object, 0, $outputlangs); + $top_shift = $this->_pagehead($pdf, $object, 0, $outputlangs); + $tab_top_newpage = (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD') ? 42 + $top_shift : 10); } } } @@ -943,7 +956,8 @@ class pdf_crabe extends ModelePDFFactures $pdf->useTemplate($tplidx); } if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) { - $this->_pagehead($pdf, $object, 0, $outputlangs); + $top_shift = $this->_pagehead($pdf, $object, 0, $outputlangs); + $tab_top_newpage = (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD') ? 42 + $top_shift : 10); } $pdf->setPage($current_page); $this->_tableau_versements_header($pdf, $object, $outputlangs, $default_font_size, $tab3_posx, $tab3_top + $y - 3, $tab3_width, $tab3_height); @@ -1005,7 +1019,8 @@ class pdf_crabe extends ModelePDFFactures $pdf->useTemplate($tplidx); } if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) { - $this->_pagehead($pdf, $object, 0, $outputlangs); + $top_shift = $this->_pagehead($pdf, $object, 0, $outputlangs); + $tab_top_newpage = (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD') ? 42 + $top_shift : 10); } $pdf->setPage($current_page); $this->_tableau_versements_header($pdf, $object, $outputlangs, $default_font_size, $tab3_posx, $tab3_top + $y - 3, $tab3_width, $tab3_height); @@ -1180,7 +1195,7 @@ class pdf_crabe extends ModelePDFFactures // Decret n°2099-1299 2022-10-07 // French mention : "Option pour le paiement de la taxe d'après les débits" if ($this->emetteur->country_code == 'FR') { - if ($conf->global->TAX_MODE == 1) { + if (isset($conf->global->TAX_MODE) && $conf->global->TAX_MODE == 1) { $pdf->SetXY($this->marge_gauche, $posy); $pdf->writeHTMLCell(80, 5, '', '', $outputlangs->transnoentities("MentionVATDebitOptionIsOn"), 0, 1); @@ -2056,6 +2071,43 @@ class pdf_crabe extends ModelePDFFactures $pdf->SetFont('', '', $default_font_size - 1); $pdf->SetXY($posx + 2, $posy); $pdf->MultiCell($widthrecbox - 2, 4, $carac_client, 0, $ltrdirection); + + // Show shipping address + if (getDolGlobalInt('INVOICE_SHOW_SHIPPING_ADDRESS')) { + $idaddressshipping = $object->getIdContact('external', 'SHIPPING'); + + if (!empty($idaddressshipping)) { + $contactshipping = $object->fetch_Contact($idaddressshipping[0]); + $object->fetch_thirdparty($object->contact->fk_soc); + $carac_client_name_shipping=pdfBuildThirdpartyName($object->contact, $outputlangs); + $carac_client_shipping = pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, $object->contact, $usecontact, 'target', $object); + } else { + $carac_client_name_shipping=pdfBuildThirdpartyName($object->thirdparty, $outputlangs); + $carac_client_shipping=pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, '', 0, 'target', $object);; + } + if (!empty($carac_client_shipping) && (isset($object->contact->socid) && $object->contact->socid != $object->socid)) { + $posy += $hautcadre; + + // Show shipping frame + $pdf->SetXY($posx + 2, $posy - 5); + $pdf->SetFont('', '', $default_font_size - 2); + $pdf->MultiCell($widthrecbox, '', $langs->trans('ShippingTo'), 0, 'L', 0); + $pdf->Rect($posx, $posy, $widthrecbox, $hautcadre); + + // Show shipping name + $pdf->SetXY($posx + 2, $posy + 3); + $pdf->SetFont('', 'B', $default_font_size); + $pdf->MultiCell($widthrecbox - 2, 2, $carac_client_name_shipping, '', 'L'); + + $posy = $pdf->getY(); + + // Show shipping information + $pdf->SetXY($posx+2, $posy); + $pdf->SetFont('', '', $default_font_size - 1); + $pdf->MultiCell($widthrecbox - 2, 2, $carac_client_shipping, '', 'L'); + $top_shift += $hautcadre; + } + } } $pdf->SetTextColor(0, 0, 0); diff --git a/htdocs/core/modules/facture/doc/pdf_sponge.modules.php b/htdocs/core/modules/facture/doc/pdf_sponge.modules.php index e11cd90bc43..c3a4318a218 100644 --- a/htdocs/core/modules/facture/doc/pdf_sponge.modules.php +++ b/htdocs/core/modules/facture/doc/pdf_sponge.modules.php @@ -9,6 +9,7 @@ * Copyright (C) 2015 Marcos García * Copyright (C) 2017 Ferran Marcet * Copyright (C) 2018 Frédéric France + * Copyright (C) 2022 Anthony Berton * * 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 @@ -448,7 +449,9 @@ class pdf_sponge extends ModelePDFFactures $pagenb++; // Output header (logo, ref and address blocks). This is first call for first page. - $top_shift = $this->_pagehead($pdf, $object, 1, $outputlangs, $outputlangsbis); + $pagehead = $this->_pagehead($pdf, $object, 1, $outputlangs, $outputlangsbis); + $top_shift = $pagehead['top_shift']; + $shipp_shift = $pagehead['shipp_shift']; $pdf->SetFont('', '', $default_font_size - 1); $pdf->MultiCell(0, 3, ''); // Set interline to 3 $pdf->SetTextColor(0, 0, 0); @@ -456,7 +459,7 @@ class pdf_sponge extends ModelePDFFactures // $pdf->GetY() here can't be used. It is bottom of the second addresse box but first one may be higher // $this->tab_top is y where we must continue content (90 = 42 + 48: 42 is height of logo and ref, 48 is address blocks) - $this->tab_top = 90 + $top_shift; // top_shift is an addition for linked objects or addons (0 in most cases) + $this->tab_top = 90 + $top_shift + $shipp_shift; // top_shift is an addition for linked objects or addons (0 in most cases) $this->tab_top_newpage = (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD') ? 42 + $top_shift : 10); // You can add more thing under header here, if you increase $extra_under_address_shift too. @@ -1290,7 +1293,7 @@ class pdf_sponge extends ModelePDFFactures // Decret n°2099-1299 2022-10-07 // French mention : "Option pour le paiement de la taxe d'après les débits" if ($this->emetteur->country_code == 'FR') { - if ($conf->global->TAX_MODE == 1) { + if (isset($conf->global->TAX_MODE) && $conf->global->TAX_MODE == 1) { $pdf->SetXY($this->marge_gauche, $posy); $pdf->writeHTMLCell(80, 5, '', '', $outputlangs->transnoentities("MentionVATDebitOptionIsOn"), 0, 1); @@ -2222,6 +2225,7 @@ class pdf_sponge extends ModelePDFFactures $posy += 1; $top_shift = 0; + $shipp_shift = 0; // Show list of linked objects $current_y = $pdf->getY(); $posy = pdf_writeLinkedObjects($pdf, $object, $outputlangs, $posx, $posy, $w, 3, 'R', $default_font_size); @@ -2244,7 +2248,6 @@ class pdf_sponge extends ModelePDFFactures $hautcadre = !empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 38 : 40; $widthrecbox = !empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 92 : 82; - // Show sender frame if (empty($conf->global->MAIN_PDF_NO_SENDER_FRAME)) { $pdf->SetTextColor(0, 0, 0); @@ -2322,10 +2325,49 @@ class pdf_sponge extends ModelePDFFactures $pdf->SetFont('', '', $default_font_size - 1); $pdf->SetXY($posx + 2, $posy); $pdf->MultiCell($widthrecbox - 2, 4, $carac_client, 0, $ltrdirection); + + // Show shipping address + if (getDolGlobalInt('INVOICE_SHOW_SHIPPING_ADDRESS')) { + $idaddressshipping = $object->getIdContact('external', 'SHIPPING'); + + if (!empty($idaddressshipping)) { + $contactshipping = $object->fetch_Contact($idaddressshipping[0]); + $object->fetch_thirdparty($object->contact->fk_soc); + $carac_client_name_shipping=pdfBuildThirdpartyName($object->contact, $outputlangs); + $carac_client_shipping = pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, $object->contact, $usecontact, 'target', $object); + } else { + $carac_client_name_shipping=pdfBuildThirdpartyName($object->thirdparty, $outputlangs); + $carac_client_shipping=pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, '', 0, 'target', $object);; + } + if (!empty($carac_client_shipping) && (isset($object->contact->socid) && $object->contact->socid != $object->socid)) { + $posy += $hautcadre; + + // Show shipping frame + $pdf->SetXY($posx + 2, $posy - 5); + $pdf->SetFont('', '', $default_font_size - 2); + $pdf->MultiCell($widthrecbox, '', $langs->trans('ShippingTo'), 0, 'L', 0); + $pdf->Rect($posx, $posy, $widthrecbox, $hautcadre); + + // Show shipping name + $pdf->SetXY($posx + 2, $posy + 3); + $pdf->SetFont('', 'B', $default_font_size); + $pdf->MultiCell($widthrecbox - 2, 2, $carac_client_name_shipping, '', 'L'); + + $posy = $pdf->getY(); + + // Show shipping information + $pdf->SetXY($posx+2, $posy); + $pdf->SetFont('', '', $default_font_size - 1); + $pdf->MultiCell($widthrecbox - 2, 2, $carac_client_shipping, '', 'L'); + $shipp_shift += $hautcadre; + } + } } $pdf->SetTextColor(0, 0, 0); - return $top_shift; + + $pagehead = array('top_shift' => $top_shift, 'shipp_shift' => $shipp_shift); + return $pagehead; } // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore diff --git a/htdocs/core/modules/facture/mod_facture_mercure.php b/htdocs/core/modules/facture/mod_facture_mercure.php index 7a572615a21..321741ea8a0 100644 --- a/htdocs/core/modules/facture/mod_facture_mercure.php +++ b/htdocs/core/modules/facture/mod_facture_mercure.php @@ -1,9 +1,10 @@ - * Copyright (C) 2004-2011 Laurent Destailleur - * Copyright (C) 2005-2007 Regis Houssin - * Copyright (C) 2008 Raphael Bertrand (Resultic) - * Copyright (C) 2013 Juanjo Menent +/* Copyright (C) 2003-2007 Rodolphe Quiedeville + * Copyright (C) 2004-2011 Laurent Destailleur + * Copyright (C) 2005-2007 Regis Houssin + * Copyright (C) 2008 Raphael Bertrand (Resultic) + * Copyright (C) 2013 uanjo Menent + * Copyright (C) 2022 Anthony Berton * * 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 @@ -143,16 +144,28 @@ class mod_facture_mercure extends ModeleNumRefFactures // Get Mask value $mask = ''; if (is_object($invoice) && $invoice->type == 1) { - $mask = $conf->global->FACTURE_MERCURE_MASK_REPLACEMENT; + if (isset($conf->global->FACTURE_MERCURE_MASK_REPLACEMENT)) { + $mask = $conf->global->FACTURE_MERCURE_MASK_REPLACEMENT; + } if (!$mask) { - $mask = $conf->global->FACTURE_MERCURE_MASK_INVOICE; + if (isset($conf->global->FACTURE_MERCURE_MASK_INVOICE)) { + $mask = $conf->global->FACTURE_MERCURE_MASK_INVOICE; + } } } elseif (is_object($invoice) && $invoice->type == 2) { - $mask = $conf->global->FACTURE_MERCURE_MASK_CREDIT; + if (isset($conf->global->FACTURE_MERCURE_MASK_CREDIT)) { + $mask = $conf->global->FACTURE_MERCURE_MASK_CREDIT; + } } elseif (is_object($invoice) && $invoice->type == 3) { - $mask = $conf->global->FACTURE_MERCURE_MASK_DEPOSIT; + if (isset($conf->global->FACTURE_MERCURE_MASK_DEPOSIT)) { + $mask = $conf->global->FACTURE_MERCURE_MASK_DEPOSIT; + } } else { - $mask = $conf->global->FACTURE_MERCURE_MASK_INVOICE; + if (isset($conf->global->FACTURE_MERCURE_MASK_INVOICE)) { + $mask = $conf->global->FACTURE_MERCURE_MASK_INVOICE; + } else { + $mask = ''; + } } if (!$mask) { $this->error = 'NotConfigured'; diff --git a/htdocs/core/modules/import/import_csv.modules.php b/htdocs/core/modules/import/import_csv.modules.php index 09f93a436ea..22c12024c2b 100644 --- a/htdocs/core/modules/import/import_csv.modules.php +++ b/htdocs/core/modules/import/import_csv.modules.php @@ -862,8 +862,8 @@ class ImportCsv extends ModeleImports $stringtosearch = json_encode($socialnetwork).':'.json_encode($json->$socialnetwork); //var_dump($stringtosearch); //var_dump($this->db->escape($stringtosearch)); // This provide a value for sql string (but not for a like) - $where[] = $key." LIKE '%".$this->db->escapeforlike($this->db->escape($stringtosearch))."%'"; - $filters[] = $col." LIKE '%".$this->db->escapeforlike($this->db->escape($stringtosearch))."%'"; + $where[] = $key." LIKE '%".$this->db->escape($this->db->escapeforlike($stringtosearch))."%'"; + $filters[] = $col." LIKE '%".$this->db->escape($this->db->escapeforlike($stringtosearch))."%'"; //var_dump($where[1]); // This provide a value for sql string inside a like } else { $where[] = $key.' = '.$data[$key]; diff --git a/htdocs/core/modules/import/import_xlsx.modules.php b/htdocs/core/modules/import/import_xlsx.modules.php index ecf7d8b4a77..35adc4476a0 100644 --- a/htdocs/core/modules/import/import_xlsx.modules.php +++ b/htdocs/core/modules/import/import_xlsx.modules.php @@ -908,8 +908,8 @@ class ImportXlsx extends ModeleImports $stringtosearch = json_encode($socialnetwork).':'.json_encode($json->$socialnetwork); //var_dump($stringtosearch); //var_dump($this->db->escape($stringtosearch)); // This provide a value for sql string (but not for a like) - $where[] = $key." LIKE '%".$this->db->escapeforlike($this->db->escape($stringtosearch))."%'"; - $filters[] = $col." LIKE '%".$this->db->escapeforlike($this->db->escape($stringtosearch))."%'"; + $where[] = $key." LIKE '%".$this->db->escape($this->db->escapeforlike($stringtosearch))."%'"; + $filters[] = $col." LIKE '%".$this->db->escape($this->db->escapeforlike($stringtosearch))."%'"; //var_dump($where[1]); // This provide a value for sql string inside a like } else { $where[] = $key.' = '.$data[$key]; diff --git a/htdocs/core/modules/mailings/advthirdparties.modules.php b/htdocs/core/modules/mailings/advthirdparties.modules.php index 688db8b8e7f..7649c255d04 100644 --- a/htdocs/core/modules/mailings/advthirdparties.modules.php +++ b/htdocs/core/modules/mailings/advthirdparties.modules.php @@ -42,7 +42,7 @@ class mailing_advthirdparties extends MailingTargets */ public $db; - public $enabled = '$conf->societe->enabled'; + public $enabled = 'isModEnabled("societe")'; /** diff --git a/htdocs/core/modules/mailings/contacts1.modules.php b/htdocs/core/modules/mailings/contacts1.modules.php index decbc81716b..64097078147 100644 --- a/htdocs/core/modules/mailings/contacts1.modules.php +++ b/htdocs/core/modules/mailings/contacts1.modules.php @@ -38,7 +38,7 @@ class mailing_contacts1 extends MailingTargets public $require_module = array("societe"); // Module mailing actif si modules require_module actifs public $require_admin = 0; // Module mailing actif pour user admin ou non - public $enabled = '$conf->societe->enabled'; + public $enabled = 'isModEnabled("societe")'; /** * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png @@ -388,6 +388,7 @@ class mailing_contacts1 extends MailingTargets } $sql .= " WHERE sp.entity IN (".getEntity('contact').")"; $sql .= " AND sp.email <> ''"; + $sql .= " AND (SELECT count(*) FROM ".MAIN_DB_PREFIX."mailing_unsubscribe WHERE email = sp.email) = 0"; // Exclude unsubscribed email adresses $sql .= " AND sp.statut = 1"; @@ -409,7 +410,7 @@ class mailing_contacts1 extends MailingTargets // Filter on language if ($filter_lang != '') { - $sql .= " AND sp.default_lang = '".$this->db->escape($filter_lang)."'"; + $sql .= " AND sp.default_lang LIKE '".$this->db->escape($filter_lang)."%'"; } // Filter on nature diff --git a/htdocs/core/modules/mailings/eventorganization.modules.php b/htdocs/core/modules/mailings/eventorganization.modules.php new file mode 100644 index 00000000000..84c27c5f673 --- /dev/null +++ b/htdocs/core/modules/mailings/eventorganization.modules.php @@ -0,0 +1,212 @@ + + * Copyright (C) 2005-2010 Laurent Destailleur + * Copyright (C) 2005-2009 Regis Houssin + * + * This file is an example to follow to add your own email selector inside + * the Dolibarr email tool. + * Follow instructions given in README file to know what to change to build + * your own emailing list selector. + * Code that need to be changed in this file are marked by "CHANGE THIS" tag. + */ + +/** + * \file htdocs/core/modules/mailings/eventorganization.modules.php + * \ingroup mailing + * \brief Example file to provide a list of recipients for mailing module + */ + + +// Load Dolibarr Environment +include_once DOL_DOCUMENT_ROOT.'/core/modules/mailings/modules_mailings.php'; + + +/** + * Class to manage a list of personalised recipients for mailing feature + */ +class mailing_eventorganization extends MailingTargets +{ + // This label is used if no translation is found for key XXX neither MailingModuleDescXXX where XXX=name is found + public $name = 'AttendeesOfOrganizedEvent'; + public $desc = "Attendees of an organized event"; + + public $require_admin = 0; + + public $require_module = array(); // This module allows to select by categories must be also enabled if category module is not activated + + /** + * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png + */ + public $picto = 'conferenceorbooth'; + + /** + * @var DoliDB Database handler. + */ + public $db; + + public $enabled = 'isModEnabled("eventorganization")'; + + + /** + * Constructor + * + * @param DoliDB $db Database handler + */ + public function __construct($db) + { + global $conf, $langs; + $langs->load('companies'); + + $this->db = $db; + } + + + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * This is the main function that returns the array of emails + * + * @param int $mailing_id Id of mailing. No need to use it. + * @return int <0 if error, number of emails added if ok + */ + public function add_to_target($mailing_id) + { + // phpcs:enable + global $conf, $langs; + + $cibles = array(); + $addDescription = ''; + + $sql = "SELECT p.ref, p.entity, e.rowid as id, e.fk_project, e.email as email, e.email_company as company_name, e.firstname as firstname, e.lastname as lastname,"; + $sql .= " 'eventorganizationattendee' as source"; + $sql .= " FROM ".MAIN_DB_PREFIX."eventorganization_conferenceorboothattendee as e,"; + $sql .= " ".MAIN_DB_PREFIX."projet as p"; + $sql .= " WHERE e.email <> ''"; + $sql .= " AND e.fk_project = p.rowid"; + $sql .= " AND p.entity IN (".getEntity('project').")"; + $sql .= " AND e.email NOT IN (SELECT email FROM ".MAIN_DB_PREFIX."mailing_cibles WHERE fk_mailing=".((int) $mailing_id).")"; + $sql .= " AND e.fk_project = ".((int) GETPOST('filter_eventorganization', 'int')); + $sql .= " ORDER BY e.email"; + + // Stock recipients emails into targets table + $result = $this->db->query($sql); + if ($result) { + $num = $this->db->num_rows($result); + $i = 0; + $j = 0; + + dol_syslog(get_class($this)."::add_to_target mailing ".$num." targets found"); + + $old = ''; + while ($i < $num) { + $obj = $this->db->fetch_object($result); + if ($old <> $obj->email) { + $otherTxt = ($obj->ref ? $langs->transnoentities("Project").'='.$obj->ref : ''); + if (strlen($addDescription) > 0 && strlen($otherTxt) > 0) { + $otherTxt .= ";"; + } + $otherTxt .= $addDescription; + $cibles[$j] = array( + 'email' => $obj->email, + 'fk_project' => $obj->fk_project, + 'lastname' => $obj->lastname, + 'firstname' => $obj->firstname, + 'other' => $otherTxt, + 'source_url' => $this->url($obj->id, $obj->source), + 'source_id' => $obj->id, + 'source_type' => $obj->source + ); + $old = $obj->email; + $j++; + } + + $i++; + } + } else { + dol_syslog($this->db->error()); + $this->error = $this->db->error(); + return -1; + } + + return parent::addTargetsToDatabase($mailing_id, $cibles); + } + + + /** + * On the main mailing area, there is a box with statistics. + * If you want to add a line in this report you must provide an + * array of SQL request that returns two field: + * One called "label", One called "nb". + * + * @return array Array with SQL requests + */ + public function getSqlArrayForStats() + { + // CHANGE THIS: Optionnal + + //var $statssql=array(); + //$this->statssql[0]="SELECT field1 as label, count(distinct(email)) as nb FROM mytable WHERE email IS NOT NULL"; + return array(); + } + + + /** + * Return here number of distinct emails returned by your selector. + * For example if this selector is used to extract 500 different + * emails from a text file, this function must return 500. + * + * @param string $sql Requete sql de comptage + * @return int|string Nb of recipient, or <0 if error, or '' if NA + */ + public function getNbOfRecipients($sql = '') + { + global $conf; + + $sql = "SELECT COUNT(DISTINCT(e.email)) as nb"; + $sql .= " FROM ".MAIN_DB_PREFIX."eventorganization_conferenceorboothattendee as e, "; + $sql .= " ".MAIN_DB_PREFIX."projet as p"; + $sql .= " WHERE e.email <> ''"; + $sql .= " AND e.fk_project = p.rowid"; + $sql .= " AND p.entity IN (".getEntity('project').")"; + + //print $sql; + + // La requete doit retourner un champ "nb" pour etre comprise par parent::getNbOfRecipients + return parent::getNbOfRecipients($sql); + } + + /** + * This is to add a form filter to provide variant of selector + * If used, the HTML select must be called "filter" + * + * @return string A html select zone + */ + public function formFilter() + { + global $conf, $langs; + + $langs->load("companies"); + + include_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php'; + $formproject = new FormProjets($this->db); + $s .= $formproject->select_projects(-1, 0, "filter_eventorganization", 0, 0, 1, 1, 0, 0, 0, '', 1, 0, '', '', 'usage_organize_event=1'); + + return $s; + } + + + /** + * Can include an URL link on each record provided by selector shown on target page. + * + * @param int $id ID + * @param string $sourcetype Source type + * @return string Url link + */ + public function url($id, $sourcetype = 'thirdparty') + { + if ($sourcetype == 'project') { + return ''.img_object('', "eventorganization").''; + } + + return ''; + } +} diff --git a/htdocs/core/modules/mailings/example.modules.php b/htdocs/core/modules/mailings/example.modules.php deleted file mode 100644 index 739ab773196..00000000000 --- a/htdocs/core/modules/mailings/example.modules.php +++ /dev/null @@ -1,154 +0,0 @@ - - * - * This file is an example to follow to add your own email selector inside - * the Dolibarr email tool. - * Follow instructions given in README file to know what to change to build - * your own emailing list selector. - * Code that need to be changed in this file are marked by "CHANGE THIS" tag. - */ - -/** - * \file htdocs/core/modules/mailings/example.modules.php - * \ingroup mailing - * \brief Example file to provide a list of recipients for mailing module - */ - -include_once DOL_DOCUMENT_ROOT.'/core/modules/mailings/modules_mailings.php'; - - -// CHANGE THIS: Class name must be called mailing_xxx with xxx=name of your selector - -/** - \class mailing_example - \brief Class to manage a list of personalised recipients for mailing feature -*/ -class mailing_example extends MailingTargets -{ - // CHANGE THIS: Put here a name not already used - public $name = 'example'; - // CHANGE THIS: Put here a description of your selector module. - // This label is used if no translation is found for key MailingModuleDescXXX where XXX=name is found - public $desc = 'Put here a description'; - // CHANGE THIS: Set to 1 if selector is available for admin users only - public $require_admin = 0; - // CHANGE THIS: Add a tooltip language key to add a tooltip help icon after the email target selector - public $tooltip = 'MyTooltipLangKey'; - - public $require_module = array(); - - /** - * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png - */ - public $picto = ''; - - /** - * @var DoliDB Database handler. - */ - public $db; - - - // CHANGE THIS: Constructor name must be called mailing_xxx with xxx=name of your selector - /** - * Constructor - * - * @param DoliDB $db Database handler - */ - public function __construct($db) - { - $this->db = $db; - } - - - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps - /** - * This is the main function that returns the array of emails - * - * @param int $mailing_id Id of mailing. No need to use it. - * @return int <0 if error, number of emails added if ok - */ - public function add_to_target($mailing_id) - { - // phpcs:enable - $target = array(); - - // CHANGE THIS - // ----- Your code start here ----- - - // You must fill the $target array with record like this - // $target[0]=array('email'=>'email_0','name'=>'name_0','firstname'=>'firstname_0', 'other'=>'other_0'); - // ... - // $target[n]=array('email'=>'email_n','name'=>'name_n','firstname'=>'firstname_n', 'other'=>'other_n'); - - // Example: $target[0]=array('email'=>'myemail@example.com', 'name'=>'Doe', 'firstname'=>'John', 'other'=>'Other information'); - - // ----- Your code end here ----- - - return parent::addTargetsToDatabase($mailing_id, $target); - } - - - /** - * On the main mailing area, there is a box with statistics. - * If you want to add a line in this report you must provide an - * array of SQL request that returns two field: - * One called "label", One called "nb". - * - * @return array Array with SQL requests - */ - public function getSqlArrayForStats() - { - // CHANGE THIS: Optionnal - - //var $statssql=array(); - //$this->statssql[0]="SELECT field1 as label, count(distinct(email)) as nb FROM mytable WHERE email IS NOT NULL"; - return array(); - } - - - /** - * Return here number of distinct emails returned by your selector. - * For example if this selector is used to extract 500 different - * emails from a text file, this function must return 500. - * - * @param string $sql Requete sql de comptage - * @return int|string Nb of recipient, or <0 if error, or '' if NA - */ - public function getNbOfRecipients($sql = '') - { - // CHANGE THIS: Optionnal - - // Example: return parent::getNbOfRecipients("SELECT count(*) as nb from dolibarr_table"); - // Example: return 500; - return '?'; - } - - /** - * This is to add a form filter to provide variant of selector - * If used, the HTML select must be called "filter" - * - * @return string A html select zone - */ - public function formFilter() - { - // CHANGE THIS: Optionnal - - $s = ''; - return $s; - } - - - /** - * Can include an URL link on each record provided by selector - * shown on target page. - * - * @param int $id ID - * @return string Url link - */ - public function url($id) - { - // CHANGE THIS: Optionnal - - return ''; - } -} diff --git a/htdocs/core/modules/mailings/fraise.modules.php b/htdocs/core/modules/mailings/fraise.modules.php index 992539cc303..9fe6a615f5d 100644 --- a/htdocs/core/modules/mailings/fraise.modules.php +++ b/htdocs/core/modules/mailings/fraise.modules.php @@ -41,7 +41,7 @@ class mailing_fraise extends MailingTargets public $require_module = array('adherent'); - public $enabled = '$conf->adherent->enabled'; + public $enabled = 'isModEnabled("adherent")'; /** * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png diff --git a/htdocs/core/modules/mailings/partnership.modules.php b/htdocs/core/modules/mailings/partnership.modules.php index 8a1fe0f2c16..b4a8e9d8fd9 100644 --- a/htdocs/core/modules/mailings/partnership.modules.php +++ b/htdocs/core/modules/mailings/partnership.modules.php @@ -44,7 +44,7 @@ class mailing_partnership extends MailingTargets */ public $db; - public $enabled = '$conf->partnership->enabled'; + public $enabled = 'isModEnabled("partnership")'; /** diff --git a/htdocs/core/modules/mailings/thirdparties.modules.php b/htdocs/core/modules/mailings/thirdparties.modules.php index 71be0733fb2..2f8040d4b75 100644 --- a/htdocs/core/modules/mailings/thirdparties.modules.php +++ b/htdocs/core/modules/mailings/thirdparties.modules.php @@ -31,7 +31,7 @@ class mailing_thirdparties extends MailingTargets public $require_module = array("societe"); // This module allows to select by categories must be also enabled if category module is not activated - public $enabled = '$conf->societe->enabled'; + public $enabled = 'isModEnabled("societe")'; /** * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png diff --git a/htdocs/core/modules/mailings/thirdparties_services_expired.modules.php b/htdocs/core/modules/mailings/thirdparties_services_expired.modules.php index 9083b643900..9fc43e37388 100644 --- a/htdocs/core/modules/mailings/thirdparties_services_expired.modules.php +++ b/htdocs/core/modules/mailings/thirdparties_services_expired.modules.php @@ -29,7 +29,7 @@ class mailing_thirdparties_services_expired extends MailingTargets public $require_module = array('contrat'); - public $enabled = '$conf->societe->enabled'; + public $enabled = 'isModEnabled("societe")'; /** * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png @@ -219,6 +219,7 @@ class mailing_thirdparties_services_expired extends MailingTargets $s = ' + '; $coldisplay++; @@ -718,7 +718,8 @@ if (!empty($usemargins) && $user->rights->margins->creer) { { console.log("objectline_create.tpl Call method change() after change on #idprod or #idprodfournprice (senderissupplier=). this.val = "+$(this).val()); - setforpredef(); // TODO Keep vat combo visible and set it to first entry into list that match result of get_default_tva + setforpredef(); // TODO Keep vat combo visible and set it to first entry into list that match result of get_default_tva(product) + jQuery('#trlinefordates').show(); rights->margins->creer) { global->PRODUIT_CUSTOMER_PRICES_BY_QTY) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) { ?> if (isNaN(pbq)) { console.log("We use experimental option PRODUIT_CUSTOMER_PRICES_BY_QTY or PRODUIT_CUSTOMER_PRICES_BY_QTY but we could not get the id of pbq from product combo list, so load of price may be 0 if product has differet prices"); } - // Get the HT price for the product and display it + // Get the price for the product and display it console.log("Load unit price without tax and set it into #price_ht for product id="+$(this).val()+" socid=socid; ?>"); $.post('/product/ajax/products.php?action=fetch', { 'id': $(this).val(), 'socid': socid; ?>, 'token': '' }, @@ -755,7 +756,7 @@ if (!empty($usemargins) && $user->rights->margins->creer) { if (data.mandatory_period == 1 && data.type == 1) { jQuery('#date_start').addClass('inputmandatory'); jQuery('#date_end').addClass('inputmandatory'); - }else{ + } else { jQuery('#date_start').removeClass('inputmandatory'); jQuery('#date_end').removeClass('inputmandatory'); } @@ -767,6 +768,23 @@ if (!empty($usemargins) && $user->rights->margins->creer) { console.log("objectline_create.tpl set content of price_ht"); jQuery("#price_ht").val(data.price_ht); } + + var tva_tx = data.tva_tx; + var default_vat_code = data.default_vat_code; + + // Now set the VAT + var stringforvatrateselection = tva_tx; + if (typeof default_vat_code != 'undefined' && default_vat_code != null) { + stringforvatrateselection = stringforvatrateselection+' ('+default_vat_code+')'; + } + // Set vat rate if field is an input box + $('#tva_tx').val(tva_tx); + // Set vat rate by selecting the combo + //$('#tva_tx option').val(tva_tx); // This is bugged, it replaces the vat key of all options + $('#tva_tx option').removeAttr('selected'); + console.log("stringforvatrateselection="+stringforvatrateselection+" -> value of option label for this key="+$('#tva_tx option[value="'+stringforvatrateselection+'"]').val()); + $('#tva_tx option[value="'+stringforvatrateselection+'"]').prop('selected', true); + global->PRODUIT_AUTOFILL_DESC) && $conf->global->PRODUIT_AUTOFILL_DESC == 1) { if (getDolGlobalInt('MAIN_MULTILANGS') && !empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE)) { ?> @@ -919,39 +937,41 @@ if (!empty($usemargins) && $user->rights->margins->creer) { ?> global->PRODUIT_CUSTOMER_PRICES_BY_QTY)) {?> - /* To process customer price per quantity (PRODUIT_CUSTOMER_PRICES_BY_QTY works only if combo product is not an ajax after x key pressed) */ - var pbq = parseInt($('option:selected', this).attr('data-pbq')); // When select is done from HTML select - if (isNaN(pbq)) { pbq = jQuery('#idprod').attr('data-pbq'); } // When select is done from HTML input with autocomplete - var pbqup = parseFloat($('option:selected', this).attr('data-pbqup')); - if (isNaN(pbqup)) { pbqup = jQuery('#idprod').attr('data-pbqup'); } - var pbqbase = $('option:selected', this).attr('data-pbqbase'); - if (isNaN(pbqbase)) { pbqbase = jQuery('#idprod').attr('data-pbqbase'); } - var pbqqty = parseFloat($('option:selected', this).attr('data-pbqqty')); - if (isNaN(pbqqty)) { pbqqty = jQuery('#idprod').attr('data-pbqqty'); } - var pbqpercent = parseFloat($('option:selected', this).attr('data-pbqpercent')); - if (isNaN(pbqpercent)) { pbqpercent = jQuery('#idprod').attr('data-pbqpercent'); } + if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY)) { + ?> + /* To process customer price per quantity (PRODUIT_CUSTOMER_PRICES_BY_QTY works only if combo product is not an ajax after x key pressed) */ + var pbq = parseInt($('option:selected', this).attr('data-pbq')); // When select is done from HTML select + if (isNaN(pbq)) { pbq = jQuery('#idprod').attr('data-pbq'); } // When select is done from HTML input with autocomplete + var pbqup = parseFloat($('option:selected', this).attr('data-pbqup')); + if (isNaN(pbqup)) { pbqup = jQuery('#idprod').attr('data-pbqup'); } + var pbqbase = $('option:selected', this).attr('data-pbqbase'); + if (isNaN(pbqbase)) { pbqbase = jQuery('#idprod').attr('data-pbqbase'); } + var pbqqty = parseFloat($('option:selected', this).attr('data-pbqqty')); + if (isNaN(pbqqty)) { pbqqty = jQuery('#idprod').attr('data-pbqqty'); } + var pbqpercent = parseFloat($('option:selected', this).attr('data-pbqpercent')); + if (isNaN(pbqpercent)) { pbqpercent = jQuery('#idprod').attr('data-pbqpercent'); } - if ((jQuery('#idprod').val() > 0) && ! isNaN(pbq) && pbq > 0) - { - var pbqupht = pbqup; /* TODO support of price per qty TTC not yet available */ + if ((jQuery('#idprod').val() > 0) && ! isNaN(pbq) && pbq > 0) + { + var pbqupht = pbqup; /* TODO support of price per qty TTC not yet available */ - console.log("We choose a price by quanty price_by_qty id = "+pbq+" price_by_qty upht = "+pbqupht+" price_by_qty qty = "+pbqqty+" price_by_qty percent = "+pbqpercent); - jQuery("#pbq").val(pbq); - jQuery("#price_ht").val(pbqupht); - if (jQuery("#qty").val() < pbqqty) - { - jQuery("#qty").val(pbqqty); - } - if (jQuery("#remise_percent").val() < pbqpercent) - { - jQuery("#remise_percent").val(pbqpercent); - } - } else { jQuery("#pbq").val(''); } + console.log("We choose a price by quanty price_by_qty id = "+pbq+" price_by_qty upht = "+pbqupht+" price_by_qty qty = "+pbqqty+" price_by_qty percent = "+pbqpercent); + jQuery("#pbq").val(pbq); + jQuery("#price_ht").val(pbqupht); + if (jQuery("#qty").val() < pbqqty) + { + jQuery("#qty").val(pbqqty); + } + if (jQuery("#remise_percent").val() < pbqpercent) + { + jQuery("#remise_percent").val(pbqpercent); + } + } else { jQuery("#pbq").val(''); } - // Deal with supplier + + // Deal with supplier ref price if (jQuery('#idprodfournprice').val() > 0) { console.log("objectline_create.tpl #idprodfournprice is > 0, so we set some properties into page"); @@ -971,7 +991,15 @@ if (!empty($usemargins) && $user->rights->margins->creer) { var tva_tx = parseFloat($('option:selected', this).attr('data-tvatx')); // When select is done from HTML select if (isNaN(tva_tx)) { tva_tx = parseFloat(jQuery('#idprodfournprice').attr('data-tvatx'));} // When select is done from HTML input with ajax autocomplete - console.log("objectline_create.tpl We find supplier price : up = "+up+", up_locale = "+up_locale+", qty = "+qty+", tva_tx = "+tva_tx+", discount = "+discount+" for product "+jQuery('#idprodfournprice').val()); + var default_vat_code = $('option:selected', this).attr('data-default-vat-code'); // When select is done from HTML select + if (typeof default_vat_code === 'undefined') { default_vat_code = jQuery('#idprodfournprice').attr('data-default-vat-code');} // When select is done from HTML input with ajax autocomplete + + var stringforvatrateselection = tva_tx; + if (typeof default_vat_code != 'undefined' && default_vat_code != null) { + stringforvatrateselection = stringforvatrateselection+' ('+default_vat_code+')'; + } + + console.log("objectline_create.tpl We find supplier price : up = "+up+", up_locale = "+up_locale+", qty = "+qty+", tva_tx = "+tva_tx+", default_vat_code = "+default_vat_code+", stringforvatrateselection="+stringforvatrateselection+", discount = "+discount+" for product supplier ref id = "+jQuery('#idprodfournprice').val()); if (typeof up_locale === 'undefined') { jQuery("#price_ht").val(up); @@ -979,8 +1007,13 @@ if (!empty($usemargins) && $user->rights->margins->creer) { jQuery("#price_ht").val(up_locale); } - /* $('#tva_tx option').removeAttr('selected').filter('[value='+tva_tx+']').prop('selected', true); */ - $('#tva_tx option').val(tva_tx); + // Set vat rate if field is an input box + $('#tva_tx').val(tva_tx); + // Set vat rate by selecting the combo + //$('#tva_tx option').val(tva_tx); // This is bugged, it replaces the vat key of all options + $('#tva_tx option').removeAttr('selected'); + console.log("stringforvatrateselection="+stringforvatrateselection+" -> value of option label for this key="+$('#tva_tx option[value="'+stringforvatrateselection+'"]').val()); + $('#tva_tx option[value="'+stringforvatrateselection+'"]').prop('selected', true); if (jQuery("#qty").val() < qty) { jQuery("#qty").val(qty); diff --git a/htdocs/core/tpl/objectline_edit.tpl.php b/htdocs/core/tpl/objectline_edit.tpl.php index 8c786e7a041..5520215d89a 100644 --- a/htdocs/core/tpl/objectline_edit.tpl.php +++ b/htdocs/core/tpl/objectline_edit.tpl.php @@ -196,7 +196,7 @@ $coldisplay++; if ($object->element == 'supplier_proposal' || $object->element == 'order_supplier' || $object->element == 'invoice_supplier' || $object->element == 'invoice_supplier_rec') { // We must have same test in printObjectLines $coldisplay++; ?> - + fk_fournprice.'">'; } diff --git a/htdocs/core/tpl/objectline_view.tpl.php b/htdocs/core/tpl/objectline_view.tpl.php index 03e98e1147d..14197b6d052 100644 --- a/htdocs/core/tpl/objectline_view.tpl.php +++ b/htdocs/core/tpl/objectline_view.tpl.php @@ -234,14 +234,14 @@ if (($line->info_bits & 2) == 2) { } } -if ($user->rights->fournisseur->lire && $line->fk_fournprice > 0 && empty($conf->global->SUPPLIER_HIDE_SUPPLIER_OBJECTLINES)) { +if ($user->hasRight('fournisseur', 'lire') && isset($line->fk_fournprice) && $line->fk_fournprice > 0 && empty($conf->global->SUPPLIER_HIDE_SUPPLIER_OBJECTLINES)) { require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php'; $productfourn = new ProductFournisseur($this->db); $productfourn->fetch_product_fournisseur_price($line->fk_fournprice); print '
'; print ''.$langs->trans('Supplier').' : '.$productfourn->getSocNomUrl(1, 'supplier').' - '.$langs->trans('Ref').' : '; // Supplier ref - if ($user->rights->produit->creer || $user->rights->service->creer) { // change required right here + if ($user->hasRight('produit', 'creer') || $user->hasRight('service', 'creer')) { // change required right here print $productfourn->getNomUrl(); } else { print $productfourn->ref_supplier; @@ -353,19 +353,27 @@ if ($line->special_code == 3) { ?> if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) { $tooltiponprice = $langs->transcountry("TotalHT", $mysoc->country_code).'='.price($line->total_ht); $tooltiponprice .= '
'.$langs->transcountry("TotalVAT", ($senderissupplier ? $object->thirdparty->country_code : $mysoc->country_code)).'='.price($line->total_tva); - if (!$senderissupplier && is_object($object->thirdparty)) { + if (is_object($object->thirdparty)) { + if ($senderissupplier) { + $seller = $object->thirdparty; + $buyer = $mysoc; + } else { + $seller = $mysoc; + $buyer = $object->thirdparty; + } + if ($mysoc->useLocalTax(1)) { - if (($mysoc->country_code == $object->thirdparty->country_code) || $object->thirdparty->useLocalTax(1)) { - $tooltiponprice .= '
'.$langs->transcountry("TotalLT1", ($senderissupplier ? $object->thirdparty->country_code : $mysoc->country_code)).'='.price($line->total_localtax1); + if (($seller->country_code == $buyer->country_code) || $line->total_localtax1 || $seller->useLocalTax(1)) { + $tooltiponprice .= '
'.$langs->transcountry("TotalLT1", $seller->country_code).'='.price($line->total_localtax1); } else { - $tooltiponprice .= '
'.$langs->transcountry("TotalLT1", ($senderissupplier ? $object->thirdparty->country_code : $mysoc->country_code)).'='.$langs->trans("NotUsedForThisCustomer").''; + $tooltiponprice .= '
'.$langs->transcountry("TotalLT1", $seller->country_code).'='.$langs->trans($senderissupplier ? "NotUsedForThisSupplier" : "NotUsedForThisCustomer").''; } } if ($mysoc->useLocalTax(2)) { - if (($mysoc->country_code == $object->thirdparty->country_code) || $object->thirdparty->useLocalTax(2)) { - $tooltiponprice .= '
'.$langs->transcountry("TotalLT2", ($senderissupplier ? $object->thirdparty->country_code : $mysoc->country_code)).'='.price($line->total_localtax2); + if (($seller->country_code == $buyer->thirdparty->country_code) || $line->total_localtax2 || $seller->useLocalTax(2)) { + $tooltiponprice .= '
'.$langs->transcountry("TotalLT2", $seller->country_code).'='.price($line->total_localtax2); } else { - $tooltiponprice .= '
'.$langs->transcountry("TotalLT2", ($senderissupplier ? $object->thirdparty->country_code : $mysoc->country_code)).'='.$langs->trans("NotUsedForThisCustomer").''; + $tooltiponprice .= '
'.$langs->transcountry("TotalLT2", $seller->country_code).'='.$langs->trans($senderissupplier ? "NotUsedForThisSupplier" : "NotUsedForThisCustomer").''; } } } @@ -418,7 +426,7 @@ if ($this->statut == 0 && !empty($object_rights->creer) && $action != 'selectlin print 'Error SQL: ' . $this->db->lasterror(); } elseif ($obj = $this->db->fetch_object($resql_asset)) { if (!empty($obj->found)) { - print ''; + print ''; print img_edit_add() . ''; } } @@ -430,7 +438,7 @@ if ($this->statut == 0 && !empty($object_rights->creer) && $action != 'selectlin $coldisplay++; if (($line->info_bits & 2) == 2 || !empty($disableedit)) { } else { ?> - id.'#line_'.$line->id; ?>"> + id; ?>"> '; } print ''; diff --git a/htdocs/core/triggers/interface_50_modAgenda_ActionsAuto.class.php b/htdocs/core/triggers/interface_50_modAgenda_ActionsAuto.class.php index f31a4c2c93e..e3f798dec62 100644 --- a/htdocs/core/triggers/interface_50_modAgenda_ActionsAuto.class.php +++ b/htdocs/core/triggers/interface_50_modAgenda_ActionsAuto.class.php @@ -742,7 +742,7 @@ class InterfaceActionsAuto extends DolibarrTriggers if (!is_object($member)) { // This should not happen include_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php'; $member = new Adherent($this->db); - $member->fetch($this->fk_adherent); + $member->fetch($object->fk_adherent); } if (empty($object->actionmsg2)) { diff --git a/htdocs/cron/class/cronjob.class.php b/htdocs/cron/class/cronjob.class.php index 8f4b32ae502..d26c83f4772 100644 --- a/htdocs/cron/class/cronjob.class.php +++ b/htdocs/cron/class/cronjob.class.php @@ -1262,13 +1262,13 @@ class Cronjob extends CommonObject dol_syslog(get_class($this)."::run_jobs END result=".$result." error=".$errmsg, LOG_ERR); $this->error = $errmsg; - $this->lastoutput = ($object->output ? $object->output."\n" : "").$errmsg; + $this->lastoutput = (!empty($object->output) ? $object->output."\n" : "").$errmsg; $this->lastresult = is_numeric($result) ? $result : -1; $retval = $this->lastresult; $error++; } else { dol_syslog(get_class($this)."::run_jobs END"); - $this->lastoutput = $object->output; + $this->lastoutput = (!empty($object->output) ? $object->output : ""); $this->lastresult = var_export($result, true); $retval = $this->lastresult; } diff --git a/htdocs/cron/list.php b/htdocs/cron/list.php index ae53242d836..30f195b550b 100644 --- a/htdocs/cron/list.php +++ b/htdocs/cron/list.php @@ -448,7 +448,7 @@ print ''; print ''; print '\n"; // Public note @@ -516,7 +524,8 @@ if ($action == 'create') { if (isModEnabled('project')) { print "\n"; } diff --git a/htdocs/don/class/paymentdonation.class.php b/htdocs/don/class/paymentdonation.class.php index e4928ac9363..b42f5fb4e4d 100644 --- a/htdocs/don/class/paymentdonation.class.php +++ b/htdocs/don/class/paymentdonation.class.php @@ -65,7 +65,7 @@ class PaymentDonation extends CommonObject public $amounts = array(); // Array of amounts public $fk_typepayment; // Payment mode ID - public $paymenttype; // Payment mode ID + public $paymenttype; // Payment mode ID or Code. TODO Use only the code in this field. public $num_payment; @@ -188,12 +188,12 @@ class PaymentDonation extends CommonObject $sql = "INSERT INTO ".MAIN_DB_PREFIX."payment_donation (fk_donation, datec, datep, amount,"; $sql .= " fk_typepayment, num_payment, note, ext_payment_id, ext_payment_site,"; $sql .= " fk_user_creat, fk_bank)"; - $sql .= " VALUES ($this->chid, '".$this->db->idate($now)."',"; + $sql .= " VALUES (".((int) $this->chid).", '".$this->db->idate($now)."',"; $sql .= " '".$this->db->idate($this->datepaid)."',"; - $sql .= " ".price2num($totalamount).","; + $sql .= " ".((float) price2num($totalamount)).","; $sql .= " ".((int) $this->paymenttype).", '".$this->db->escape($this->num_payment)."', '".$this->db->escape($this->note_public)."', "; $sql .= " ".($this->ext_payment_id ? "'".$this->db->escape($this->ext_payment_id)."'" : "null").", ".($this->ext_payment_site ? "'".$this->db->escape($this->ext_payment_site)."'" : "null").","; - $sql .= " ".$user->id.", 0)"; + $sql .= " ".((int) $user->id).", 0)"; dol_syslog(get_class($this)."::create", LOG_DEBUG); $resql = $this->db->query($sql); @@ -269,8 +269,8 @@ class PaymentDonation extends CommonObject $this->tms = $this->db->jdate($obj->tms); $this->datep = $this->db->jdate($obj->datep); $this->amount = $obj->amount; - $this->fk_typepayment = $obj->fk_typepayment; // For backward compatibility - $this->paymenttype = $obj->fk_typepayment; + $this->fk_typepayment = $obj->fk_typepayment; // Id on type of payent + $this->paymenttype = $obj->fk_typepayment; // Id on type of payment. We should store the code into paymenttype. $this->num_payment = $obj->num_payment; $this->note_public = $obj->note_public; $this->fk_bank = $obj->fk_bank; diff --git a/htdocs/don/document.php b/htdocs/don/document.php index b6b7e6a24d3..a5aa3984202 100644 --- a/htdocs/don/document.php +++ b/htdocs/don/document.php @@ -49,13 +49,6 @@ $action = GETPOST('action', 'aZ09'); $confirm = GETPOST('confirm', 'alpha'); $projectid = (GETPOST('projectid') ? GETPOST('projectid', 'int') : 0); -// Security check -if ($user->socid) { - $socid = $user->socid; -} -$result = restrictedArea($user, 'don', $id, ''); - - // Get parameters $limit = GETPOST('limit', 'int') ? GETPOST('limit', 'int') : $conf->liste_limit; $sortfield = GETPOST('sortfield', 'aZ09comma'); @@ -74,13 +67,20 @@ if (!$sortfield) { $sortfield = "name"; } - $object = new Don($db); -$object->fetch($id, $ref); +if ($id > 0 || $ref) { + $object->fetch($id, $ref); +} $upload_dir = $conf->don->dir_output.'/'.get_exdir($id, 0, 0, 0, $object, 'donation').'/'.dol_sanitizeFileName($object->ref); $modulepart = 'don'; +// Security check +if ($user->socid) { + $socid = $user->socid; +} +$result = restrictedArea($user, 'don', $object->id); + $permissiontoadd = $user->rights->don->creer; // Used by the include of actions_dellink.inc.php diff --git a/htdocs/don/index.php b/htdocs/don/index.php index 721cfb8d67a..c402ecd6f0e 100644 --- a/htdocs/don/index.php +++ b/htdocs/don/index.php @@ -35,11 +35,11 @@ $hookmanager->initHooks(array('donationindex')); $langs->load("donations"); +$donation_static = new Don($db); + // Security check $result = restrictedArea($user, 'don'); -$donation_static = new Don($db); - /* * Actions diff --git a/htdocs/don/info.php b/htdocs/don/info.php index 82dd9842210..ad67cceb30c 100644 --- a/htdocs/don/info.php +++ b/htdocs/don/info.php @@ -38,14 +38,17 @@ $ref = GETPOST('ref', 'alpha'); $action = GETPOST('action', 'aZ09'); $projectid = (GETPOST('projectid') ? GETPOST('projectid', 'int') : 0); +$object = new Don($db); +if ($id > 0 || $ref) { + $object->fetch($id, $ref); +} + // Security check if ($user->socid) { $socid = $user->socid; } -$result = restrictedArea($user, 'don', $id, ''); +$result = restrictedArea($user, 'don', $object->id); -$object = new Don($db); -$object->fetch($id); /* diff --git a/htdocs/don/list.php b/htdocs/don/list.php index c3cb4d9ce58..ac704571daa 100644 --- a/htdocs/don/list.php +++ b/htdocs/don/list.php @@ -88,6 +88,11 @@ $fieldstosearchall = array( 'd.firstname'=>'Firstname', ); +// Security check +$result = restrictedArea($user, 'don'); + + + /* * View @@ -234,7 +239,7 @@ if ($resql) { Don::STATUS_PAID=>$langs->trans("DonationStatusPaid"), Don::STATUS_CANCELED=>$langs->trans("Canceled") ); - print $form->selectarray('search_status', $liststatus, $search_status, -4, 0, 0, '', 0, 0, 0, '', 'maxwidth100'); + print $form->selectarray('search_status', $liststatus, $search_status, -4, 0, 0, '', 0, 0, 0, '', 'maxwidth100 onrightofpage'); print ''; print ''; print '\n"; print ''; print ''; print ''; print ''; // Number diff --git a/htdocs/emailcollector/class/emailcollectoraction.class.php b/htdocs/emailcollector/class/emailcollectoraction.class.php index 46b787fc6fd..e43a86da515 100644 --- a/htdocs/emailcollector/class/emailcollectoraction.class.php +++ b/htdocs/emailcollector/class/emailcollectoraction.class.php @@ -85,7 +85,7 @@ class EmailCollectorAction extends CommonObject 'rowid' => array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>1, 'visible'=>-1, 'position'=>1, 'notnull'=>1, 'index'=>1, 'comment'=>"Id",), 'fk_emailcollector' => array('type'=>'integer', 'label'=>'Id of emailcollector', 'foreignkey'=>'emailcollector.rowid'), 'type' => array('type'=>'varchar(128)', 'label'=>'Type', 'enabled'=>1, 'visible'=>1, 'position'=>10, 'notnull'=>1, 'index'=>1), - 'actionparam' => array('type'=>'varchar(255)', 'label'=>'ParamForAction', 'enabled'=>1, 'visible'=>1, 'position'=>40, 'notnull'=>-1), + 'actionparam' => array('type'=>'text', 'label'=>'ParamForAction', 'enabled'=>1, 'visible'=>1, 'position'=>40, 'notnull'=>-1), 'date_creation' => array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>1, 'visible'=>-2, 'position'=>500, 'notnull'=>1,), 'tms' => array('type'=>'timestamp', 'label'=>'DateModification', 'enabled'=>1, 'visible'=>-2, 'position'=>501, 'notnull'=>1,), 'fk_user_creat' => array('type'=>'integer', 'label'=>'UserAuthor', 'enabled'=>1, 'visible'=>-2, 'position'=>510, 'notnull'=>1, 'foreignkey'=>'llx_user.rowid',), diff --git a/htdocs/eventorganization/class/conferenceorboothattendee.class.php b/htdocs/eventorganization/class/conferenceorboothattendee.class.php index 909758ca3f2..595eaf67eeb 100644 --- a/htdocs/eventorganization/class/conferenceorboothattendee.class.php +++ b/htdocs/eventorganization/class/conferenceorboothattendee.class.php @@ -123,6 +123,7 @@ class ConferenceOrBoothAttendee extends CommonObject 'import_key' => array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>'1', 'position'=>1000, 'notnull'=>-1, 'visible'=>-2,), 'model_pdf' => array('type'=>'varchar(255)', 'label'=>'Model pdf', 'enabled'=>'1', 'position'=>1010, 'notnull'=>-1, 'visible'=>0,), 'status' => array('type'=>'smallint', 'label'=>'Status', 'enabled'=>'1', 'position'=>1000, 'default'=>0, 'notnull'=>1, 'visible'=>1, 'index'=>1, 'arrayofkeyval'=>array('0'=>'Draft', '1'=>'Validated', '9'=>'Canceled'),), + 'ip' => array('type'=>'varchar(250)', 'label'=>'Ip', 'enabled'=>'1', 'position'=>1000, 'notnull'=>-1, 'visible'=>-2,), ); public $rowid; public $ref; diff --git a/htdocs/expedition/class/expedition.class.php b/htdocs/expedition/class/expedition.class.php index d3981dcf264..0b8668a6c1a 100644 --- a/htdocs/expedition/class/expedition.class.php +++ b/htdocs/expedition/class/expedition.class.php @@ -84,6 +84,13 @@ class Expedition extends CommonObject */ public $picto = 'dolly'; + + /** + * @var array Array with all fields and their property. Do not use it as a static var. It may be modified by constructor. + */ + public $fields = array(); + + public $socid; /** @@ -733,7 +740,8 @@ class Expedition extends CommonObject } else { $qty = $obj->edbqty; } - if ($qty <= 0) { + + if ($qty == 0 || ($qty < 0 && !getDolGlobalInt('SHIPMENT_ALLOW_NEGATIVE_QTY'))) { continue; } dol_syslog(get_class($this)."::valid movement index ".$i." ed.rowid=".$obj->rowid." edb.rowid=".$obj->edbrowid); diff --git a/htdocs/expedition/class/expeditionstats.class.php b/htdocs/expedition/class/expeditionstats.class.php index 8eb31896f38..aa4e40fcb8f 100644 --- a/htdocs/expedition/class/expeditionstats.class.php +++ b/htdocs/expedition/class/expeditionstats.class.php @@ -131,6 +131,54 @@ class ExpeditionStats extends Stats return $this->_getNbByYear($sql); } + /** + * Return the orders amount by month for a year + * + * @param int $year Year to scan + * @param int $format 0=Label of abscissa is a translated text, 1=Label of abscissa is month number, 2=Label of abscissa is first letter of month + * @return array Array with amount by month + */ + public function getAmountByMonth($year, $format = 0) + { + global $user; + + $sql = "SELECT date_format(c.date_valid,'%m') as dm, SUM(c.".$this->field.")"; + $sql .= " FROM ".$this->from; + if (empty($user->rights->societe->client->voir) && !$this->socid) { + $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + } + $sql .= $this->join; + $sql .= " WHERE ".$this->where; + $sql .= " GROUP BY dm"; + $sql .= $this->db->order('dm', 'DESC'); + + $res = $this->_getAmountByMonth($year, $sql, $format); + return $res; + } + + /** + * Return the orders amount average by month for a year + * + * @param int $year year for stats + * @return array array with number by month + */ + public function getAverageByMonth($year) + { + global $user; + + $sql = "SELECT date_format(c.date_valid,'%m') as dm, AVG(c.".$this->field.")"; + $sql .= " FROM ".$this->from; + if (empty($user->rights->societe->client->voir) && !$this->socid) { + $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + } + $sql .= $this->join; + $sql .= " WHERE ".$this->where; + $sql .= " GROUP BY dm"; + $sql .= $this->db->order('dm', 'DESC'); + + return $this->_getAverageByMonth($year, $sql); + } + /** * Return nb, total and average * diff --git a/htdocs/expedition/list.php b/htdocs/expedition/list.php index 3b06f005787..14544087647 100644 --- a/htdocs/expedition/list.php +++ b/htdocs/expedition/list.php @@ -284,6 +284,9 @@ if (!empty($extrafields->attributes[$object->table_element]['label'])) { $parameters = array(); $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters); // Note that $action and $object may have been modified by hook $sql .= $hookmanager->resPrint; + +$sqlfields = $sql; // $sql fields to remove for count total + $sql .= " FROM ".MAIN_DB_PREFIX."expedition as e"; if (!empty($extrafields->attributes[$object->table_element]['label']) && is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label'])) { $sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$object->table_element."_extrafields as ef on (e.rowid = ef.fk_object)"; @@ -446,19 +449,31 @@ $parameters = array(); $reshook = $hookmanager->executeHooks('printFieldListHaving', $parameters, $object); // Note that $action and $object may have been modified by hook $sql .= empty($hookmanager->resPrint) ? "" : " HAVING 1=1 ".$hookmanager->resPrint; -$sql .= $db->order($sortfield, $sortorder); - $nbtotalofrecords = ''; if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { - $result = $db->query($sql); - $nbtotalofrecords = $db->num_rows($result); + /* The fast and low memory method to get and count full list converts the sql into a sql count */ + $sqlforcount = preg_replace('/^'.preg_quote($sqlfields, '/').'/', 'SELECT COUNT(*) as nbtotalofrecords', $sql); + $sqlforcount = preg_replace('/GROUP BY .*$/', '', $sqlforcount); + $resql = $db->query($sqlforcount); + if ($resql) { + $objforcount = $db->fetch_object($resql); + $nbtotalofrecords = $objforcount->nbtotalofrecords; + } else { + dol_print_error($db); + } + if (($page * $limit) > $nbtotalofrecords) { // if total resultset is smaller then paging size (filtering), goto and load page 0 $page = 0; $offset = 0; } + $db->free($resql); } -$sql .= $db->plimit($limit + 1, $offset); +// Complete request and execute it with limit +$sql .= $db->order($sortfield, $sortorder); +if ($limit) { + $sql .= $db->plimit($limit + 1, $offset); +} //print $sql; $resql = $db->query($sql); @@ -772,7 +787,7 @@ if (!empty($arrayfields['e.tms']['checked'])) { // Status if (!empty($arrayfields['e.fk_statut']['checked'])) { print ''; } // Status billed diff --git a/htdocs/expedition/stats/month.php b/htdocs/expedition/stats/month.php index 34842efaaf3..398bc381715 100644 --- a/htdocs/expedition/stats/month.php +++ b/htdocs/expedition/stats/month.php @@ -47,11 +47,12 @@ $WIDTH = DolGraph::getDefaultGraphSizeForStats('width'); $HEIGHT = DolGraph::getDefaultGraphSizeForStats('height'); $mesg = ''; +$mode = ''; print load_fiche_titre($langs->trans("StatisticsOfSendings").' '.$year, $mesg); -$stats = new ExpeditionStats($db); -$data = $stats->getNbExpeditionByMonth($year); +$stats = new ExpeditionStats($db, $socid, $mode); +$data = $stats->getNbByMonth($year); dol_mkdir($conf->expedition->dir_temp); diff --git a/htdocs/expensereport/card.php b/htdocs/expensereport/card.php index 33ec1fede7b..f6aa14865ec 100644 --- a/htdocs/expensereport/card.php +++ b/htdocs/expensereport/card.php @@ -2297,7 +2297,7 @@ if ($action == 'create') { } } - $tredited = 'tredited'; + $tredited = 'tredited'; // Case the addfile and linkto file is used for edit (used by following tpl) include DOL_DOCUMENT_ROOT.'/expensereport/tpl/expensereport_addfile.tpl.php'; include DOL_DOCUMENT_ROOT.'/expensereport/tpl/expensereport_linktofile.tpl.php'; @@ -2455,6 +2455,7 @@ if ($action == 'create') { print ''."\n"; print ''; + $tredited = ''; // Case the addfile and linkto file is used for edit (used by following tpl) include DOL_DOCUMENT_ROOT.'/expensereport/tpl/expensereport_linktofile.tpl.php'; include DOL_DOCUMENT_ROOT.'/expensereport/tpl/expensereport_addfile.tpl.php'; @@ -2517,6 +2518,7 @@ if ($action == 'create') { print ''; + // Action column + if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print ''; + } if (!empty($arrayfields['d.ref']['checked'])) { print ''; } // Action column - print ''; + if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print ''; + } print "\n"; print ''; + if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', 'align="center"', $sortfield, $sortorder, 'maxwidthsearch '); + } if (!empty($arrayfields['d.ref']['checked'])) { print_liste_field_titre($arrayfields['d.ref']['label'], $_SERVER["PHP_SELF"], "d.ref", "", $param, '', $sortfield, $sortorder); } @@ -676,7 +703,9 @@ if ($resql) { if (!empty($arrayfields['d.fk_statut']['checked'])) { print_liste_field_titre($arrayfields['d.fk_statut']['label'], $_SERVER["PHP_SELF"], "d.fk_statut", "", $param, 'align="right"', $sortfield, $sortorder); } - print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', 'align="center"', $sortfield, $sortorder, 'maxwidthsearch '); + if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', 'align="center"', $sortfield, $sortorder, 'maxwidthsearch '); + } print "\n"; $total_total_ht = 0; @@ -712,6 +741,18 @@ if ($resql) { print ''; + // Action column + if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print ''; + } // Ref if (!empty($arrayfields['d.ref']['checked'])) { print ''; } - print ''; if (!$i) { $totalarray['nbfield']++; } diff --git a/htdocs/expensereport/tpl/expensereport_linktofile.tpl.php b/htdocs/expensereport/tpl/expensereport_linktofile.tpl.php index 3835740dd40..fd25a1fff4b 100644 --- a/htdocs/expensereport/tpl/expensereport_linktofile.tpl.php +++ b/htdocs/expensereport/tpl/expensereport_linktofile.tpl.php @@ -136,8 +136,18 @@ if (empty($conf->global->EXPENSEREPORT_DISABLE_ATTACHMENT_ON_LINES)) { print ''; } else { - print 'global->MAIN_OPTIMIZEFORTEXTBROWSER) ? ' style="display: none"' : '').'>'; - print 'global->MAIN_OPTIMIZEFORTEXTBROWSER) ? ' style="display: none"' : '').'>'; + if (!empty($tredited)) { + print ''; + } + print ''; } diff --git a/htdocs/fichinter/list.php b/htdocs/fichinter/list.php index 174196a23a5..a3b69d6e26c 100644 --- a/htdocs/fichinter/list.php +++ b/htdocs/fichinter/list.php @@ -251,6 +251,9 @@ if (!empty($extrafields->attributes[$object->table_element]['label'])) { $parameters = array(); $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters); // Note that $action and $object may have been modified by hook $sql .= $hookmanager->resPrint; + +$sqlfields = $sql; // $sql fields to remove for count total + $sql .= " FROM ".MAIN_DB_PREFIX."fichinter as f"; if (isModEnabled('project')) { $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."projet as pr on f.fk_projet = pr.rowid"; @@ -324,20 +327,18 @@ $sql .= $hookmanager->resPrint; // Count total nb of records $nbtotalofrecords = ''; if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { - /* This old and fast method to get and count full list returns all record so use a high amount of memory. */ - $resql = $db->query($sql); - $nbtotalofrecords = $db->num_rows($resql); /* The fast and low memory method to get and count full list converts the sql into a sql count */ - /*$sqlforcount = preg_replace('/^SELECT[a-zA-Z0-9\._\s\(\),=<>\:\-\']+\sFROM/Ui', 'SELECT COUNT(*) as nbtotalofrecords FROM', $sql); + $sqlforcount = preg_replace('/^'.preg_quote($sqlfields, '/').'/', 'SELECT COUNT(*) as nbtotalofrecords', $sql); + $sqlforcount = preg_replace('/GROUP BY .*$/', '', $sqlforcount); $resql = $db->query($sqlforcount); if ($resql) { $objforcount = $db->fetch_object($resql); $nbtotalofrecords = $objforcount->nbtotalofrecords; } else { dol_print_error($db); - }*/ + } - if (($page * $limit) > $nbtotalofrecords) { // if total of record found is smaller than page * limit, goto and load page 0 + if (($page * $limit) > $nbtotalofrecords) { // if total resultset is smaller then paging size (filtering), goto and load page 0 $page = 0; $offset = 0; } @@ -493,7 +494,7 @@ if (!empty($moreforfilter)) { } $varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage; -$selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage, getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN', '')); // This also change content of $arrayfields +$selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage, getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')); // This also change content of $arrayfields $selectedfields .= (count($arrayofmassactions) ? $form->showCheckAddButtons('checkforselect', 1) : ''); print '
'; @@ -503,7 +504,7 @@ print '
'; @@ -161,10 +160,25 @@ class doc_generic_contract_odt extends ModelePDFContract $texte .= '
'; // Scan directories - if (count($listofdir)) { - $texte .= $langs->trans("NumberOfModelFilesFound").': '.count($listoffiles).''; + $nbofiles = count($listoffiles); + if (!empty($conf->global->CONTRACT_ADDON_PDF_ODT_PATH)) { + $texte .= $langs->trans("NumberOfModelFilesFound").': '; + //$texte.=$nbofiles?'':''; + $texte .= count($listoffiles); + //$texte.=$nbofiles?'':''; + $texte .= ''; } + if ($nbofiles) { + $texte .= '
'; + // Show list of found files + foreach ($listoffiles as $file) { + $texte .= '- '.$file['name'].' '.img_picto('', 'listlight').''; + $texte .= '   '.img_picto('', 'delete').''; + $texte .= '
'; + } + $texte .= '
'; + } // Add input to upload a new template file. $texte .= '
'.$langs->trans("UploadNewTemplate"); $maxfilesizearray = getMaxFileSizeArray(); @@ -228,7 +242,7 @@ class doc_generic_contract_odt extends ModelePDFContract $sav_charset_output = $outputlangs->charset_output; $outputlangs->charset_output = 'UTF-8'; - // Load traductions files required by page + // Load translation files required by page $outputlangs->loadLangs(array("main", "dict", "companies", "bills")); if ($conf->contrat->multidir_output[$object->entity]) { @@ -382,16 +396,21 @@ class doc_generic_contract_odt extends ModelePDFContract dol_syslog($e->getMessage(), LOG_INFO); } + // Call the ODTSubstitution hook + $parameters = array('odfHandler'=>&$odfHandler, 'file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs, 'substitutionarray'=>&$tmparray); + $reshook = $hookmanager->executeHooks('ODTSubstitution', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks + foreach ($tmparray as $key => $value) { try { - if (preg_match('/logo$/', $key)) { // Image + if (preg_match('/logo$/', $key)) { + // Image if (file_exists($value)) { $odfHandler->setImage($key, $value); } else { $odfHandler->setVars($key, 'ErrorFileNotFound', true, 'UTF-8'); } - } else // Text - { + } else { + // Text $odfHandler->setVars($key, $value, true, 'UTF-8'); } } catch (OdfException $e) { @@ -448,7 +467,7 @@ class doc_generic_contract_odt extends ModelePDFContract } // Call the beforeODTSave hook - $parameters = array('odfHandler'=>&$odfHandler, 'file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs); + $parameters = array('odfHandler'=>&$odfHandler, 'file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs, 'substitutionarray'=>&$tmparray); $reshook = $hookmanager->executeHooks('beforeODTSave', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks // Write new file @@ -457,6 +476,7 @@ class doc_generic_contract_odt extends ModelePDFContract $odfHandler->exportAsAttachedPDF($file); } catch (Exception $e) { $this->error = $e->getMessage(); + dol_syslog($e->getMessage(), LOG_INFO); return -1; } } else { @@ -464,10 +484,12 @@ class doc_generic_contract_odt extends ModelePDFContract $odfHandler->saveToDisk($file); } catch (Exception $e) { $this->error = $e->getMessage(); + dol_syslog($e->getMessage(), LOG_INFO); return -1; } } + $parameters = array('odfHandler'=>&$odfHandler, 'file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs, 'substitutionarray'=>&$tmparray); $reshook = $hookmanager->executeHooks('afterODTCreation', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks if (!empty($conf->global->MAIN_UMASK)) { diff --git a/htdocs/core/modules/dons/html_cerfafr.modules.php b/htdocs/core/modules/dons/html_cerfafr.modules.php index 792c8434ba4..d859ae0ca56 100644 --- a/htdocs/core/modules/dons/html_cerfafr.modules.php +++ b/htdocs/core/modules/dons/html_cerfafr.modules.php @@ -120,18 +120,18 @@ class html_cerfafr extends ModeleDon // This is not the proper way to do it but $formclass->form_modes_reglement // prints the translation instead of returning it - if ($don->modepaiementid) { - $formclass->load_cache_types_paiements(); - $paymentmode = $formclass->cache_types_paiements[$don->modepaiementid]['label']; + $formclass->load_cache_types_paiements(); + if ($don->modepaymentid) { + $paymentmode = $formclass->cache_types_paiements[$don->modepaymentid]['label']; } else { $paymentmode = ''; } - - if ($don->modepaymentcode == 'CHQ') { + $modepaymentcode = !empty($formclass->cache_types_paiements[$don->modepaymentid]['code']) ? $formclass->cache_types_paiements[$don->modepaymentid]['code'] : ""; + if ($modepaymentcode == 'CHQ') { $ModePaiement = '
Remise d\'espèces Chèque Virement, prélèvement, carte bancaire Remise d\'espèces Chèque Virement, prélèvement, carte bancaire Remise d\'espèces Chèque Virement, prélèvement, carte bancaire Remise d\'espèces Chèque Virement, prélèvement, carte bancaire">">   '; -print $form->selectarray('search_status', array('0'=>$langs->trans("Disabled"), '1'=>$langs->trans("Scheduled")), $search_status, 1); +print $form->selectarray('search_status', array('0'=>$langs->trans("Disabled"), '1'=>$langs->trans("Scheduled")), $search_status, 1, 0, 0, '', 0, 0, 0, '', 'onrightofpage'); print ''; $searchpicto = $form->showFilterButtons(); print $searchpicto; diff --git a/htdocs/delivery/class/delivery.class.php b/htdocs/delivery/class/delivery.class.php index ad1a3b9934a..73fc15e6911 100644 --- a/htdocs/delivery/class/delivery.class.php +++ b/htdocs/delivery/class/delivery.class.php @@ -638,7 +638,7 @@ class Delivery extends CommonObject $sql .= " WHERE rowid = ".((int) $lineid); if ($this->db->query($sql)) { - $this->update_price(); + $this->update_price(1); return 1; } else { diff --git a/htdocs/don/card.php b/htdocs/don/card.php index a0a795e9c8b..459c892a1d9 100644 --- a/htdocs/don/card.php +++ b/htdocs/don/card.php @@ -48,6 +48,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php'; $langs->loadLangs(array('bills', 'companies', 'donations', 'users')); $id = GETPOST('rowid') ?GETPOST('rowid', 'int') : GETPOST('id', 'int'); +$ref = GETPOST('ref', 'alpha'); $action = GETPOST('action', 'aZ09'); $cancel = GETPOST('cancel', 'alpha'); $confirm = GETPOST('confirm', 'alpha'); @@ -58,10 +59,11 @@ $projectid = (GETPOST('projectid') ? GETPOST('projectid', 'int') : 0); $public_donation = (int) GETPOST("public", 'int'); $object = new Don($db); -$extrafields = new ExtraFields($db); +if ($id > 0 || $ref) { + $object->fetch($id, $ref); +} -// Security check -$result = restrictedArea($user, 'don', $id); +$extrafields = new ExtraFields($db); // fetch optionals attributes and labels $extrafields->fetch_name_optionals_label($object->table_element); @@ -71,6 +73,11 @@ $search_array_options = $extrafields->getOptionalsFromPost($object->table_elemen $hookmanager->initHooks(array('doncard', 'globalcard')); $upload_dir = $conf->don->dir_output; + + +// Security check +$result = restrictedArea($user, 'don', $object->id); + $permissiontoadd = $user->rights->don->creer; @@ -487,7 +494,8 @@ if ($action == 'create') { // Payment mode print "
".$langs->trans("PaymentMode")."\n"; $selected = GETPOST('modepayment', 'int'); - $form->select_types_paiements($selected, 'modepayment', 'CRDT', 0, 1); + print img_picto('', 'payment', 'class="pictofixedwidth"'); + print $form->select_types_paiements($selected, 'modepayment', 'CRDT', 0, 1, 0, 0, 1, 'maxwidth200 widthcentpercentminusx', 1); print "
".$langs->trans("Project").""; - $formproject->select_projects(-1, $projectid, 'fk_project', 0, 0, 1, 1, 0, 0, 0, '', 0, 0, 'maxwidth500'); + print img_picto('', 'project', 'class="pictofixedwidth"'); + print $formproject->select_projects(-1, $projectid, 'fk_project', 0, 0, 1, 1, 0, 0, 0, '', 1, 0, 'maxwidth500'); print "
'; $searchpicto = $form->showFilterAndCheckAddButtons(0); diff --git a/htdocs/don/note.php b/htdocs/don/note.php index 4d84c4b1417..dd3f4e176ce 100644 --- a/htdocs/don/note.php +++ b/htdocs/don/note.php @@ -43,17 +43,19 @@ $ref = GETPOST('ref', 'alpha'); $action = GETPOST('action', 'aZ09'); $projectid = (GETPOST('projectid') ? GETPOST('projectid', 'int') : 0); +$hookmanager->initHooks(array('donnote')); + +$object = new Don($db); +if ($id > 0 || $ref) { + $object->fetch($id, $ref); +} + // Security check $socid = 0; if ($user->socid) { $socid = $user->socid; } -$hookmanager->initHooks(array('donnote')); - -$result = restrictedArea($user, 'don', $id, ''); - -$object = new Don($db); -$object->fetch($id); +$result = restrictedArea($user, 'don', $object->id, ''); $permissionnote = $user->rights->don->creer; // Used by the include of actions_setnotes.inc.php diff --git a/htdocs/don/payment/payment.php b/htdocs/don/payment/payment.php index 6a2cc78f128..358c0b208e9 100644 --- a/htdocs/don/payment/payment.php +++ b/htdocs/don/payment/payment.php @@ -95,7 +95,7 @@ if ($action == 'add_payment') { // Create a line of payments $payment = new PaymentDonation($db); $payment->chid = $chid; - $payment->datepaid = $datepaid; + $payment->datep = $datepaid; $payment->amounts = $amounts; // Tableau de montant $payment->paymenttype = GETPOST("paymenttype", 'int'); $payment->num_payment = GETPOST("num_payment", 'alphanohtml'); @@ -192,14 +192,14 @@ if ($action == 'create') { print '
'.$langs->trans("PaymentMode").''; - $form->select_types_paiements(GETPOSTISSET("paymenttype") ? GETPOST("paymenttype") : $object->paymenttype, "paymenttype"); + $form->select_types_paiements(GETPOSTISSET("paymenttype") ? GETPOST("paymenttype") : $object->fk_typepayment, "paymenttype"); print "
'.$langs->trans('AccountToCredit').''; - $form->select_comptes(GETPOSTISSET("accountid") ? GETPOST("accountid") : $object->accountid, "accountid", 0, '', 2); // Show open bank account list + $form->select_comptes(GETPOSTISSET("accountid") ? GETPOST("accountid") : "0", "accountid", 0, '', 2); // Show open bank account list print '
'; - print $form->selectarray('search_status', array('0'=>$langs->trans('StatusSendingDraftShort'), '1'=>$langs->trans('StatusSendingValidatedShort'), '2'=>$langs->trans('StatusSendingProcessedShort')), $search_status, 1); + print $form->selectarray('search_status', array('0'=>$langs->trans('StatusSendingDraftShort'), '1'=>$langs->trans('StatusSendingValidatedShort'), '2'=>$langs->trans('StatusSendingProcessedShort')), $search_status, 1, 0, 0, '', 0, 0, 0, '', 'onrightofpage'); print '
'; $defaultvat = -1; if (!empty($conf->global->EXPENSEREPORT_NO_DEFAULT_VAT)) { + // If option to have no default VAT on expense report is on, we force MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS $conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS = 'none'; } print $form->load_tva('vatrate', (!empty($vatrate) ? $vatrate : $defaultvat), $mysoc, '', 0, 0, '', false, 1); diff --git a/htdocs/expensereport/class/expensereport.class.php b/htdocs/expensereport/class/expensereport.class.php index a1afcef74a2..ecb1cf3d65b 100644 --- a/htdocs/expensereport/class/expensereport.class.php +++ b/htdocs/expensereport/class/expensereport.class.php @@ -367,7 +367,7 @@ class ExpenseReport extends CommonObject } if (!$error) { - $result = $this->update_price(); + $result = $this->update_price(1); if ($result > 0) { if (!$notrigger) { // Call trigger @@ -1858,7 +1858,7 @@ class ExpenseReport extends CommonObject $result = $this->line->insert(0, true); if ($result > 0) { - $result = $this->update_price(); // This method is designed to add line from user input so total calculation must be done using 'auto' mode. + $result = $this->update_price(1); // This method is designed to add line from user input so total calculation must be done using 'auto' mode. if ($result > 0) { $this->db->commit(); return $this->line->id; @@ -2217,7 +2217,7 @@ class ExpenseReport extends CommonObject return -1; } - $this->update_price(); + $this->update_price(1); $this->db->commit(); @@ -2896,7 +2896,7 @@ class ExpenseReportLine extends CommonObjectLine if (!$fromaddline) { $tmpparent = new ExpenseReport($this->db); $tmpparent->fetch($this->fk_expensereport); - $result = $tmpparent->update_price(); + $result = $tmpparent->update_price(1); if ($result < 0) { $error++; $this->error = $tmpparent->error; @@ -3023,7 +3023,7 @@ class ExpenseReportLine extends CommonObjectLine $tmpparent = new ExpenseReport($this->db); $result = $tmpparent->fetch($this->fk_expensereport); if ($result > 0) { - $result = $tmpparent->update_price(); + $result = $tmpparent->update_price(1); if ($result < 0) { $error++; $this->error = $tmpparent->error; diff --git a/htdocs/expensereport/list.php b/htdocs/expensereport/list.php index 896bb29cf43..bded18fa597 100644 --- a/htdocs/expensereport/list.php +++ b/htdocs/expensereport/list.php @@ -285,6 +285,9 @@ if (!empty($extrafields->attributes[$object->table_element]['label'])) { $parameters = array(); $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters); // Note that $action and $object may have been modified by hook $sql .= $hookmanager->resPrint; + +$sqlfields = $sql; // $sql fields to remove for count total + $sql .= " FROM ".MAIN_DB_PREFIX."expensereport as d"; if (isset($extrafields->attributes[$object->table_element]['label']) && is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label'])) { $sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$object->table_element."_extrafields as ef on (d.rowid = ef.fk_object)"; @@ -340,20 +343,32 @@ $parameters = array(); $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters); // Note that $action and $object may have been modified by hook $sql .= $hookmanager->resPrint; -$sql .= $db->order($sortfield, $sortorder); - // Count total nb of records $nbtotalofrecords = ''; if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { - $result = $db->query($sql); - $nbtotalofrecords = $db->num_rows($result); + /* The fast and low memory method to get and count full list converts the sql into a sql count */ + $sqlforcount = preg_replace('/^'.preg_quote($sqlfields, '/').'/', 'SELECT COUNT(*) as nbtotalofrecords', $sql); + $sqlforcount = preg_replace('/GROUP BY .*$/', '', $sqlforcount); + $resql = $db->query($sqlforcount); + if ($resql) { + $objforcount = $db->fetch_object($resql); + $nbtotalofrecords = $objforcount->nbtotalofrecords; + } else { + dol_print_error($db); + } + if (($page * $limit) > $nbtotalofrecords) { // if total resultset is smaller then paging size (filtering), goto and load page 0 $page = 0; $offset = 0; } + $db->free($resql); } -$sql .= $db->plimit($limit + 1, $offset); +// Complete request and execute it with limit +$sql .= $db->order($sortfield, $sortorder); +if ($limit) { + $sql .= $db->plimit($limit + 1, $offset); +} //print $sql; $resql = $db->query($sql); @@ -532,7 +547,7 @@ if ($resql) { } $varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage; - $selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields + $selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage, getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')); // This also change content of $arrayfields $selectedfields .= (count($arrayofmassactions) ? $form->showCheckAddButtons('checkforselect', 1) : ''); print '
'; @@ -540,6 +555,13 @@ if ($resql) { // Filters print '
'; + $searchpicto = $form->showFilterButtons('left'); + print $searchpicto; + print ''; print ''; @@ -626,14 +648,19 @@ if ($resql) { print ''; - $searchpicto = $form->showFilterButtons(); - print $searchpicto; - print ''; + $searchpicto = $form->showFilterButtons(); + print $searchpicto; + print '
'; + if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined + $selected = 0; + if (in_array($obj->rowid, $arrayofselected)) { + $selected = 1; + } + print ''; + } + print ''; @@ -856,15 +897,17 @@ if ($resql) { } } // Action column - print ''; - if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined - $selected = 0; - if (in_array($obj->rowid, $arrayofselected)) { - $selected = 1; + if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print ''; + if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined + $selected = 0; + if (in_array($obj->rowid, $arrayofselected)) { + $selected = 1; + } + print ''; } - print ''; + print '
'; + if (empty($tredited)) { + $css = 'oddeven nohover trattachnewfilenow'; + $newcolspan = $colspan; + } else { + $css = 'trattachnewfilenow tredited'; + $newcolspan = $colspan - 1; + } + print '
'; print ''.$langs->trans("NoFilesUploadedYet").''; print '
'; // Action column -if (!empty($conf->global->MAIN_CHECKBOX_LEFT_COLUMN)) { +if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { print ''; } // Fields of detail line @@ -588,7 +589,7 @@ if (!empty($arrayfields['fd.duree']['checked'])) { print ''; } // Action column -if (empty($conf->global->MAIN_CHECKBOX_LEFT_COLUMN)) { +if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { print ''; +// Action column +if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'center maxwidthsearch '); +} if (!empty($arrayfields['f.ref']['checked'])) { print_liste_field_titre($arrayfields['f.ref']['label'], $_SERVER["PHP_SELF"], "f.ref", "", $param, '', $sortfield, $sortorder); } @@ -650,7 +655,11 @@ if (!empty($arrayfields['fd.date']['checked'])) { if (!empty($arrayfields['fd.duree']['checked'])) { print_liste_field_titre($arrayfields['fd.duree']['label'], $_SERVER["PHP_SELF"], "fd.duree", "", $param, '', $sortfield, $sortorder, 'right '); } -print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'center maxwidthsearch '); + +// Action column +if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'center maxwidthsearch '); +} print "\n"; @@ -687,7 +696,18 @@ while ($i < $imaxinloop) { $companystatic->status = $obj->thirdpartystatus; print ''; - + // Action column + if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print ''; + } if (!empty($arrayfields['f.ref']['checked'])) { print ""; print ''; - // Mode de reglement par defaut + // Default payment mode print '
'; $searchpicto = $form->showFilterButtons('left'); print $searchpicto; @@ -574,7 +575,7 @@ if (!empty($arrayfields['f.fk_statut']['checked'])) { if (empty($conf->global->FICHINTER_CLASSIFY_BILLED)) { unset($liststatus[2]); // Option deprecated. In a future, billed must be managed with a dedicated field to 0 or 1 } - print $form->selectarray('search_status', $liststatus, $search_status, 1, 0, 0, '', 1); + print $form->selectarray('search_status', $liststatus, $search_status, 1, 0, 0, '', 1, 0, 0, '', 'onrightofpage'); print ' '; $searchpicto = $form->showFilterButtons(); print $searchpicto; @@ -602,6 +603,10 @@ $totalarray['nbfield'] = 0; // Fields title label // -------------------------------------------------------------------- print '
'; + if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined + $selected = 0; + if (in_array($obj->rowid, $arrayofselected)) { + $selected = 1; + } + print ''; + } + print '"; @@ -848,7 +868,7 @@ while ($i < $imaxinloop) { $totalarray['val']['fd.duree'] += $obj->duree; } // Action column - if (empty($conf->global->MAIN_CHECKBOX_LEFT_COLUMN)) { + if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { print ''; if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined $selected = 0; diff --git a/htdocs/fourn/card.php b/htdocs/fourn/card.php index 2c929aa40ba..f3260d8ea48 100644 --- a/htdocs/fourn/card.php +++ b/htdocs/fourn/card.php @@ -106,7 +106,7 @@ if (empty($reshook)) { setEventMessages($object->error, $object->errors, 'errors'); } } - // terms of the settlement + // Set payment terms of the settlement if ($action == 'setconditions' && $user->rights->societe->creer) { $object->fetch($id); $result = $object->setPaymentTerms(GETPOST('cond_reglement_supplier_id', 'int')); @@ -114,7 +114,7 @@ if (empty($reshook)) { dol_print_error($db, $object->error); } } - // mode de reglement + // Payment mode if ($action == 'setmode' && $user->rights->societe->creer) { $object->fetch($id); $result = $object->setPaymentMethods(GETPOST('mode_reglement_supplier_id', 'int')); @@ -123,6 +123,15 @@ if (empty($reshook)) { } } + // Bank account + if ($action == 'setbankaccount' && $user->rights->societe->creer) { + $object->fetch($id); + $result = $object->setBankAccount(GETPOST('fk_account', 'int')); + if ($result < 0) { + setEventMessages($object->error, $object->errors, 'errors'); + } + } + // update supplier order min amount if ($action == 'setsupplier_order_min_amount') { $object->fetch($id); @@ -276,7 +285,7 @@ if ($object->id > 0) { print "
'; print '"; print ''; + if (isModEnabled("banque")) { + // Default bank account for payments + print '"; + print ''; + } + // Relative discounts (Discounts-Drawbacks-Rebates) print '
'; print $langs->trans('PaymentMode'); @@ -294,6 +303,26 @@ if ($object->id > 0) { print "
'; + print ''; + } + print '
'; + print $langs->trans('PaymentBankAccount'); + print ''; + if (($action != 'editbankaccount') && $user->rights->societe->creer) { + print 'id.'">'.img_edit($langs->trans('SetBankAccount'), 1).'
'; + print '
'; + if ($action == 'editbankaccount') { + $form->formSelectAccount($_SERVER['PHP_SELF'].'?socid='.$object->id, $object->fk_account, 'fk_account', 1); + } else { + $form->formSelectAccount($_SERVER['PHP_SELF'].'?socid='.$object->id, $object->fk_account, 'none'); + } + print "
'; print ''; - // Add input to upload a new template file. $texte .= '
'.$langs->trans("UploadNewTemplate"); $maxfilesizearray = getMaxFileSizeArray(); @@ -195,6 +193,7 @@ class doc_generic_myobject_odt extends ModelePDFMyObject $texte .= ''; $texte .= ''; $texte .= '
'; + $texte .= ''; $texte .= '
'; diff --git a/htdocs/fourn/class/fournisseur.commande.class.php b/htdocs/fourn/class/fournisseur.commande.class.php index 3e58ceddfce..aed73da97ba 100644 --- a/htdocs/fourn/class/fournisseur.commande.class.php +++ b/htdocs/fourn/class/fournisseur.commande.class.php @@ -2138,7 +2138,7 @@ class CommandeFournisseur extends CommonOrder } if ($line->delete($notrigger) > 0) { - $this->update_price(); + $this->update_price(1); return 1; } else { $this->error = $line->error; @@ -2641,7 +2641,7 @@ class CommandeFournisseur extends CommonOrder $sql .= ", ".price2num($comclient->lines[$i]->qty, 'MS').", ".price2num($comclient->lines[$i]->tva_tx, 5).", ".price2num($comclient->lines[$i]->localtax1_tx, 5).", ".price2num($comclient->lines[$i]->localtax2_tx, 5).", ".price2num($comclient->lines[$i]->remise_percent, 3); $sql .= ", '".price2num($comclient->lines[$i]->subprice, 'MT')."','0', '".$this->db->escape($ref)."');"; if ($this->db->query($sql)) { - $this->update_price(); + $this->update_price(1); } } @@ -2894,7 +2894,7 @@ class CommandeFournisseur extends CommonOrder // Mise a jour info denormalisees au niveau facture if ($result >= 0) { - $this->update_price('', 'auto'); + $this->update_price('1', 'auto'); $this->db->commit(); return $result; } else { diff --git a/htdocs/fourn/class/fournisseur.facture.class.php b/htdocs/fourn/class/fournisseur.facture.class.php index 3f7013fec34..2f607ad75cf 100644 --- a/htdocs/fourn/class/fournisseur.facture.class.php +++ b/htdocs/fourn/class/fournisseur.facture.class.php @@ -809,7 +809,7 @@ class FactureFournisseur extends CommonInvoice // Update total price - $result = $this->update_price(); + $result = $this->update_price(1); if ($result > 0) { // Actions on extra fields if (!$error) { @@ -2425,7 +2425,7 @@ class FactureFournisseur extends CommonInvoice $this->errors[] = $line->error; } else { // Update total price into invoice record - $res = $this->update_price('', 'auto', 0, $this->thirdparty); + $res = $this->update_price('1', 'auto', 0, $this->thirdparty); } return $res; @@ -2472,7 +2472,7 @@ class FactureFournisseur extends CommonInvoice $this->db->rollback(); return -3; } else { - $res = $this->update_price(); + $res = $this->update_price(1); if ($res > 0) { $this->db->commit(); diff --git a/htdocs/fourn/commande/card.php b/htdocs/fourn/commande/card.php index 5dbe81ca4a4..f559c31a89f 100644 --- a/htdocs/fourn/commande/card.php +++ b/htdocs/fourn/commande/card.php @@ -413,13 +413,13 @@ if (empty($reshook)) { // Add a product line if ($action == 'addline' && GETPOST('submitforalllines', 'aZ09') && GETPOST('vatforalllines', 'alpha') && $usercancreate) { - // Define vat_rate + // Define new vat_rate for all lines $vat_rate = (GETPOST('vatforalllines') ? GETPOST('vatforalllines') : 0); $vat_rate = str_replace('*', '', $vat_rate); $localtax1_rate = get_localtax($vat_rate, 1, $object->thirdparty, $mysoc); $localtax2_rate = get_localtax($vat_rate, 2, $object->thirdparty, $mysoc); foreach ($object->lines as $line) { - $result = $object->updateline($line->id, $line->desc, $line->subprice, $line->qty, $line->remise_percent, $vat_rate, $localtax1_rate, $localtax2_rate, 'HT', $line->info_bits, $line->product_type, 0, $line->date_start, $line->date_end, $line->array_options, $line->fk_unit, $line->multicurrency_subprice); + $result = $object->updateline($line->id, $line->desc, $line->subprice, $line->qty, $line->remise_percent, $vat_rate, $localtax1_rate, $localtax2_rate, 'HT', $line->info_bits, $line->product_type, 0, $line->date_start, $line->date_end, $line->array_options, $line->fk_unit, $line->multicurrency_subprice, $line->ref_supplier); } } elseif ($action == 'addline' && $usercancreate) { $db->begin(); @@ -1698,7 +1698,7 @@ if ($action == 'create') { print $societe->getNomUrl(1, 'supplier'); print ''; } else { - print img_picto('', 'company').$form->select_company((empty($socid) ? '' : $socid), 'socid', 's.fournisseur=1', 'SelectThirdParty', 1, 0, null, 0, 'minwidth175 maxwidth500 widthcentpercentminusxx'); + print img_picto('', 'company').$form->select_company((empty($socid) ? '' : $socid), 'socid', '(s.fournisseur=1 AND s.status=1)', 'SelectThirdParty', 1, 0, null, 0, 'minwidth175 maxwidth500 widthcentpercentminusxx'); // reload page to retrieve customer informations if (!empty($conf->global->RELOAD_PAGE_ON_SUPPLIER_CHANGE)) { print ' diff --git a/htdocs/install/doctemplates/websites/website_template-restaurant/containers/index.php b/htdocs/install/doctemplates/websites/website_template-restaurant/containers/index.php index dc10e0099f4..08ce45517af 100644 --- a/htdocs/install/doctemplates/websites/website_template-restaurant/containers/index.php +++ b/htdocs/install/doctemplates/websites/website_template-restaurant/containers/index.php @@ -1,11 +1,5 @@ ref.'/page250.tpl.php'; +?> diff --git a/htdocs/install/doctemplates/websites/website_template-restaurant/containers/javascript.js.php b/htdocs/install/doctemplates/websites/website_template-restaurant/containers/javascript.js.php index f58102cf00b..fe1f15266af 100644 --- a/htdocs/install/doctemplates/websites/website_template-restaurant/containers/javascript.js.php +++ b/htdocs/install/doctemplates/websites/website_template-restaurant/containers/javascript.js.php @@ -8,6 +8,7 @@ header('Cache-Control: max-age=3600, public, must-revalidate'); header('Content-type: application/javascript'); // END PHP ?> /* JS content (all pages) */ +// test diff --git a/htdocs/install/doctemplates/websites/website_template-restaurant/containers/menu.php b/htdocs/install/doctemplates/websites/website_template-restaurant/containers/menu.php index 7e4cd71a69d..57315e4da18 100644 --- a/htdocs/install/doctemplates/websites/website_template-restaurant/containers/menu.php +++ b/htdocs/install/doctemplates/websites/website_template-restaurant/containers/menu.php @@ -1,5 +1,5 @@ ref.'/page172.tpl.php'; +if (empty($dolibarr_main_data_root)) require './page251.tpl.php'; else require $dolibarr_main_data_root.'/website/'.$website->ref.'/page251.tpl.php'; ?> diff --git a/htdocs/install/doctemplates/websites/website_template-restaurant/containers/page169.tpl.php b/htdocs/install/doctemplates/websites/website_template-restaurant/containers/page169.tpl.php deleted file mode 100644 index a592c302c73..00000000000 --- a/htdocs/install/doctemplates/websites/website_template-restaurant/containers/page169.tpl.php +++ /dev/null @@ -1,198 +0,0 @@ - - - -About us - - - - - - - - - -use_manifest) { print ''."\n"; } ?> - - - - - - - - - - - - -
- - -
- - - -
-
-
- -
-

Team Members

-
- -
-
- - -
-

Sophia

- -

CEO & Founder

-
-
-
- -
-
- - -

Benjamin W.

- -

Restaurant Manager

-
-
- -
-
- - -

Muchen Jack

- -

Senior Chef

-
-
- -
-
-
- - - - -
- -
- - - - diff --git a/htdocs/install/doctemplates/websites/website_template-restaurant/containers/page172.tpl.php b/htdocs/install/doctemplates/websites/website_template-restaurant/containers/page172.tpl.php deleted file mode 100644 index cf759e644a8..00000000000 --- a/htdocs/install/doctemplates/websites/website_template-restaurant/containers/page172.tpl.php +++ /dev/null @@ -1,597 +0,0 @@ - - - -Our menus - - - - - - - - - -use_manifest) { print ''."\n"; } ?> - - - - - - - - - - - - -
- - -
- - - - - - - -
- -
-
-
-
-

name; ?>

-
- -
-
Location
- -

getFullAddress(); ?>

- - Directions -
- -
-
Opening Hours
- - - $day : " .getDolGlobalString("MAIN_INFO_OPENINGHOURS_$day") ."

"; - } - ?> - -

- Tel: - phone ?> -

-
- -
-
Social
- - - - -
-
- -
- -
- -
- - - - diff --git a/htdocs/install/doctemplates/websites/website_template-restaurant/containers/page248.tpl.php b/htdocs/install/doctemplates/websites/website_template-restaurant/containers/page248.tpl.php new file mode 100644 index 00000000000..9acf79aaec9 --- /dev/null +++ b/htdocs/install/doctemplates/websites/website_template-restaurant/containers/page248.tpl.php @@ -0,0 +1,113 @@ + + + +About us + + + + + + + + + +use_manifest) { print ''."\n"; } ?> + + + + + + + + + + + + + + +
+
+ + + +
+
+
+ +
+

Team Members

+
+ +
+
+ + +
+

Sophia

+ +

CEO & Founder

+
+
+
+ +
+
+ + +

Benjamin W.

+ +

Restaurant Manager

+
+
+ +
+
+ + +

Muchen Jack

+ +

Senior Chef

+
+
+ +
+
+
+ +
+ +
+ + + + + + + + diff --git a/htdocs/install/doctemplates/websites/website_template-restaurant/containers/page170.tpl.php b/htdocs/install/doctemplates/websites/website_template-restaurant/containers/page249.tpl.php similarity index 70% rename from htdocs/install/doctemplates/websites/website_template-restaurant/containers/page170.tpl.php rename to htdocs/install/doctemplates/websites/website_template-restaurant/containers/page249.tpl.php index c444ce1292d..8742e231c27 100644 --- a/htdocs/install/doctemplates/websites/website_template-restaurant/containers/page170.tpl.php +++ b/htdocs/install/doctemplates/websites/website_template-restaurant/containers/page249.tpl.php @@ -18,8 +18,8 @@ ob_start(); - - + + use_manifest) { print ''."\n"; } ?> @@ -34,7 +34,7 @@ ob_start(); email; @@ -51,67 +51,12 @@ ob_start(); } } ?> + + + +
- - -
+
- +
@@ -144,6 +89,9 @@ ob_start(); method="post" role="form" > + + +
Phone Numbertrans("Phone"); ?> Emailtrans("Email"); ?> Messagetrans("Message"); ?> __N__
__N____N__
__N__ __N__
__N__ __N__
__N____N__
__N__
Weekdays
__N____N__
__N__ $day : \" .getDolGlobalString(\"MAIN_INFO_OPENINGHOURS_$day\") .\"

\"; __N__ }__N__ ?>__N__
__N____N__
Weekends
__N____N__
__N__

Saturday and Sunday

__N____N__

to be determined !

__N__
__N__
__N____N__
__N__

__N__ getFullAddress() ?>__N__

__N____N__
__N__ __N__
__N__
__N__ __N__ __N__
__N__
__N____N__ __N__ __N__ __N__ __N__ __N__ __N__ __N__ __N__
__N__
__N__
__N__

Reserve a table

__N____N__ __N__
__N____N__ __N__
__N__ __N__ \" />__N__ __N__
__N__
__N____N__
__N__
__N____N__
__N__
__N____N__
__N__
__N____N__
__N__
__N____N__
__N__
__N____N__
__N__
__N____N__
__N__ __N__
__N__ __N__
__N__
__N____N__
__N__
__N__ __N__ __N____N__
__N__', '', 0); --- File generated by Dolibarr 17.0.0-alpha -- 2022-10-08 18:18:50 UTC --; --- Page ID 171 -> 3__+MAX_llx_website_page__ - Aliases index --; -INSERT INTO llx_website_page(rowid, fk_page, fk_website, pageurl, aliasalt, title, description, lang, image, keywords, status, date_creation, tms, import_key, grabbed_from, type_container, htmlheader, content, author_alias, allowed_in_frames) VALUES(3__+MAX_llx_website_page__, null, __WEBSITE_ID__, 'index', '', 'index', '', '', '', '', '1', '2022-08-09 16:34:54', '2022-10-08 19:28:42', null, '', 'page', '', '__N____N__
__N____N____N__
__N__
__N__
__N__
__N__
__N__
__N__

__N__ Delicious Steaks__N__

__N____N__ __N__ __N__

__N__ 4.7/5__N__

__N____N__
__N__ __N__ __N__ __N__ __N__ __N__
__N__
__N____N__

__N__ From 1,206+ Customer__N__ Reviews__N__

__N__
__N__
__N__
__N____N__
__N__ __N__
__N__
__N__
__N__ __N__
__N____N__
__N__

__N__ Fine Dining Restaurant__N__

__N__
__N__
__N____N__
__N__
__N__ __N__
__N____N__
__N__ __N__

Steak

__N____N__ 26.50__N__
__N____N__ __N__ __N__ 3.8/5__N__ __N____N__
__N__ __N__ __N__ __N__ __N__ __N__
__N__
__N__
__N__
__N____N__
__N__
__N__ __N__
__N____N__
__N__ __N__

__N__ Sausage Pasta__N__

__N____N__ 18.25__N__
__N____N__ __N__ __N__ 4.2/5__N__ __N____N__
__N__ __N__ __N__ __N__ __N__ __N__
__N__
__N__ __N__ __N__ __N____N__ __N__ __N__ Previous__N__ __N____N__ __N__ __N__ Next__N__ __N__ __N__ __N__ __N__ __N____N__
__N__ __N__ __N__ Your browser does not support the video tag.__N__ __N__
__N____N__
__N__
__N____N__
__N__
__N__
__N__
__N__

__N__ Special Menus__N__

__N__
__N____N__
__N__
__N__
__N__ __N____N__ Breakfast__N__
__N____N__ __N__

Morning Fresh

__N____N__ 12.50__N____N__ __N__
__N__ 4.3/5__N__
__N____N__
__N__ __N__ __N__ __N__ __N__ __N__
__N____N__

__N__ 102 Reviews__N__

__N__
__N__
__N__
__N__
__N____N__
__N__
__N__
__N__ __N____N__ Lunch__N__
__N____N__ __N__

DoliCloud Soup

__N____N__ 24.50__N____N__ __N__
__N__ 3/5__N__
__N____N__
__N__ __N__ __N__ __N__ __N__ __N__
__N____N__

__N__ 50 Reviews__N__

__N__
__N__
__N__ __N__ __N____N__
__N__
__N__
__N__ __N____N__ Dinner__N__
__N____N__ __N__

Premium Steak

__N____N__ 45__N____N__ __N__
__N__ 3/5__N__
__N____N__
__N__ __N__ __N__ __N__ __N__ __N__
__N____N__

__N__ 86 Reviews__N__

__N__
__N__
__N__ __N__ __N____N__
__N__
__N__
__N__ __N____N__ Dinner__N__
__N____N__ __N__

Seafood Set

__N____N__ 86__N____N__ __N__
__N__ 3/5__N__
__N____N__
__N__ __N__ __N__ __N__ __N__ __N__
__N____N__

__N__ 44 Reviews__N__

__N__
__N__
__N__ __N__ __N____N__
__N__
__N__
__N__ __N____N__ Breakfast__N__
__N____N__ __N__

Burger Set

__N____N__ 20.50__N____N__ __N__
__N__ 4.3/5__N__
__N____N__
__N__ __N__ __N__ __N__ __N__ __N__
__N____N__

__N__ 102 Reviews__N__

__N__
__N__
__N__ __N__ __N____N__
__N__
__N__
__N__ __N____N__ Lunch__N__
__N____N__ __N__

Healthy Soup

__N____N__ 34.20__N____N__ __N__
__N__ 3/5__N__
__N____N__
__N__ __N__ __N__ __N__ __N__ __N__
__N____N__

__N__ 64 Reviews__N__

__N__
__N__
__N__ __N__ __N__ __N__ __N__
__N__
__N____N__ __N____N__
__N__', '', 0); -UPDATE llx_website SET fk_default_home = 3__+MAX_llx_website_page__ WHERE rowid = __WEBSITE_ID__; --- File generated by Dolibarr 17.0.0-alpha -- 2022-10-08 18:18:50 UTC --; --- Page ID 172 -> 4__+MAX_llx_website_page__ - Aliases menu --; -INSERT INTO llx_website_page(rowid, fk_page, fk_website, pageurl, aliasalt, title, description, lang, image, keywords, status, date_creation, tms, import_key, grabbed_from, type_container, htmlheader, content, author_alias, allowed_in_frames) VALUES(4__+MAX_llx_website_page__, null, __WEBSITE_ID__, 'menu', '', 'Our menus', '', '', '', '', '1', '2022-08-16 14:37:03', '2022-10-08 19:23:06', null, '', 'page', '', '__N__
__N__ __N____N__
__N__
__N__
__N__
__N__
__N__

Our Menus

__N____N__ Perfect for all Breakfast, Lunch and__N__ Dinner__N__
__N__
__N__
__N____N__
__N__
__N____N__
__N__
__N__
__N__
__N__

Breakfast Menu

__N__
__N____N__
__N__
__N__ __N____N__ __N__

Fresh Start

__N____N__ $24.50__N____N__ __N__
__N__ 4.4/5__N__
__N____N__
__N__ __N__ __N__ __N__ __N__ __N__
__N____N__

__N__ 128 Reviews__N__

__N__
__N__
__N__
__N__
__N____N__
__N__
__N__ __N____N__ __N__

Baked Creamy

__N____N__ $16.50__N____N__ __N__
__N__ 3/5__N__
__N____N__
__N__ __N__ __N__ __N__ __N__ __N__
__N____N__

__N__ 64 Reviews__N__

__N__
__N__
__N__ __N__ __N____N__
__N__
__N__ __N____N__ __N__

Burger Set

__N____N__ $24.50__N____N__ $36.50__N____N__ __N__
__N__ 3/5__N__
__N____N__
__N__ __N__ __N__ __N__ __N__ __N__
__N____N__

__N__ 32 Reviews__N__

__N__
__N__
__N__ __N__ __N__ __N__ __N__
__N____N__
__N__
__N__
__N__
__N__

Lunch Menu

__N__
__N____N__
__N__
__N__ __N____N__ __N__

Super Steak Set

__N____N__ $32.75__N____N__ $55__N____N__ __N__
__N__ 4.2/5__N__
__N____N__
__N__ __N__ __N__ __N__ __N__ __N__
__N____N__

__N__ 66 Reviews__N__

__N__
__N__
__N__
__N__
__N____N__
__N__
__N__ __N____N__ __N__

Bread & Steak Set

__N____N__ $42.50__N____N__ __N__
__N__ 3/5__N__
__N____N__
__N__ __N__ __N__ __N__ __N__ __N__
__N____N__

__N__ 84 Reviews__N__

__N__
__N__
__N__ __N__ __N__ __N__ __N__
__N____N__
__N__
__N__
__N__
__N__

Dinner Menu

__N__
__N____N__
__N__
__N__ __N____N__ __N__

Seafood Set

__N____N__ $65.50__N____N__ __N__
__N__ 4.4/5__N__
__N____N__
__N__ __N__ __N__ __N__ __N__ __N__
__N____N__

__N__ 102 Reviews__N__

__N__
__N__
__N__
__N__
__N____N__
__N__
__N__ __N____N__ __N__

Premium Steak

__N____N__ $74.25__N____N__ __N__
__N__ 3/5__N__
__N____N__
__N__ __N__ __N__ __N__ __N__ __N__
__N____N__

__N__ 56 Reviews__N__

__N__
__N__
__N__ __N__ __N____N__
__N__
__N__ __N____N__ __N__

Salmon Set

__N____N__ $60__N____N__ __N__
__N__ 3/5__N__
__N____N__
__N__ __N__ __N__ __N__ __N__ __N__
__N____N__

__N__ 76 Reviews__N__

__N__
__N__
__N__ __N__ __N__ __N__ __N__
__N__
__N____N__ __N____N__
__N__', '', 0); +-- File generated by Dolibarr 17.0.0-beta -- 2022-11-20 14:10:56 UTC --; +-- Page ID 248 -> 1__+MAX_llx_website_page__ - Aliases about --; +INSERT INTO llx_website_page(rowid, fk_page, fk_website, pageurl, aliasalt, title, description, lang, image, keywords, status, date_creation, tms, import_key, grabbed_from, type_container, htmlheader, content, author_alias, allowed_in_frames) VALUES(1__+MAX_llx_website_page__, null, __WEBSITE_ID__, 'about', '', 'About us', '', '', '', '', '1', '2022-08-09 16:40:13', '2022-11-20 14:15:19', null, '', 'page', '', '__N____N____N__
__N__
__N____N__
__N__
__N__
__N____N__
__N__

About Us

__N____N__ Get to know us more__N__
__N____N__
__N__
__N____N__
__N__
__N____N__
__N__
__N__
__N____N__
__N__

Team Members

__N__
__N____N__
__N__
__N__ \"\"__N__ __N__
__N__

Sophia

__N____N__

CEO & Founder

__N__
__N__
__N__
__N____N__
__N__
__N__ \"\"__N____N__

Benjamin W.

__N____N__

Restaurant Manager

__N__
__N__
__N____N__
__N__
__N__ \"\"__N__ __N__

Muchen Jack

__N____N__

Senior Chef

__N__
__N__
__N____N__
__N__
__N__
__N__ __N__
__N____N__
__N____N____N____N____N__', '', 0); +-- File generated by Dolibarr 17.0.0-beta -- 2022-11-20 14:10:56 UTC --; +-- Page ID 249 -> 2__+MAX_llx_website_page__ - Aliases contact --; +INSERT INTO llx_website_page(rowid, fk_page, fk_website, pageurl, aliasalt, title, description, lang, image, keywords, status, date_creation, tms, import_key, grabbed_from, type_container, htmlheader, content, author_alias, allowed_in_frames) VALUES(2__+MAX_llx_website_page__, null, __WEBSITE_ID__, 'contact', '', 'Contact us', '', '', '', '', '1', '2022-08-16 14:40:51', '2022-11-20 14:50:10', null, '', 'page', '', '__N__email;__N__ $message = GETPOST(\'message\', \'alpha\');__N__ $cmail = new CMailFile(\'Contact from website\', $to, $from, $message);__N__ if ($cmail->sendfile()) {__N__ ?>__N__ __N__ trans(\"ErrorFailedToSendMail\", $from, $to).\'. \'.$cmail->error;__N__ }__N__}__N__?>__N____N____N____N____N__
__N__
__N__
__N__
__N__
__N__
__N__

Say Hi

__N____N__ We are happy to get in touch with you__N__
__N__
__N__
__N____N__
__N__
__N____N__
__N__ __N__
__N__
__N__
__N__
__N__

Leave a message

__N__
__N____N__
__N__ __N__ __N__ \">__N__ __N__
__N__
__N____N__
__N__ trans(\"Phone\"); ?>__N____N__ __N__
__N____N__
__N__ trans(\"Email\"); ?>__N____N__ __N____N__ trans(\"Message\"); ?>__N____N__ __N__
__N____N__
__N__ __N__
__N__ __N__
__N____N__
__N__
Weekdays
__N____N__
__N__ $day : \" .getDolGlobalString(\"MAIN_INFO_OPENINGHOURS_$day\") .\"

\"; __N__ }__N__ ?>__N__
__N____N__
Weekends
__N____N__
__N__

Saturday and Sunday

__N____N__

to be determined !

__N__
__N__
__N____N__
__N__

__N__ __N__

__N__ getFullAddress() ?>__N__

__N____N__ __N__
__N__
__N__ __N__
__N__
__N__
__N__
__N__
__N__
__N____N____N__ __N__ __N__ __N__
__N__
__N__
__N__

Reserve a table

__N____N__ __N__
__N____N__ __N__
__N__ __N__ \" />__N__ __N__
__N__
__N____N__
__N__
__N____N__
__N__
__N____N__
__N__
__N____N__
__N__
__N____N__
__N__
__N____N__
__N__
__N____N__
__N__ __N__
__N__ __N__
__N__
__N____N__
__N__
__N__ __N__ __N____N__
__N____N____N____N____N__', '', 0); +-- File generated by Dolibarr 17.0.0-beta -- 2022-11-20 14:10:56 UTC --; +-- Page ID 252 -> 3__+MAX_llx_website_page__ - Aliases footer --; +INSERT INTO llx_website_page(rowid, fk_page, fk_website, pageurl, aliasalt, title, description, lang, image, keywords, status, date_creation, tms, import_key, grabbed_from, type_container, htmlheader, content, author_alias, allowed_in_frames) VALUES(3__+MAX_llx_website_page__, null, __WEBSITE_ID__, 'footer', '', 'Footer', '', '', '', '', '1', '2022-11-20 12:51:50', '2022-11-20 14:07:39', null, '', 'other', '', '__N__
__N__ __N__ __N__
__N__', '', 0); +-- File generated by Dolibarr 17.0.0-beta -- 2022-11-20 14:10:56 UTC --; +-- Page ID 253 -> 4__+MAX_llx_website_page__ - Aliases header --; +INSERT INTO llx_website_page(rowid, fk_page, fk_website, pageurl, aliasalt, title, description, lang, image, keywords, status, date_creation, tms, import_key, grabbed_from, type_container, htmlheader, content, author_alias, allowed_in_frames) VALUES(4__+MAX_llx_website_page__, null, __WEBSITE_ID__, 'header', '', 'Header', '', '', '', '', '1', '2022-11-20 13:12:33', '2022-11-20 14:21:25', null, '', 'menu', '', '
__N__ __N__
__N____N__', '', 0); +-- File generated by Dolibarr 17.0.0-beta -- 2022-11-20 14:10:56 UTC --; +-- Page ID 250 -> 5__+MAX_llx_website_page__ - Aliases index --; +INSERT INTO llx_website_page(rowid, fk_page, fk_website, pageurl, aliasalt, title, description, lang, image, keywords, status, date_creation, tms, import_key, grabbed_from, type_container, htmlheader, content, author_alias, allowed_in_frames) VALUES(5__+MAX_llx_website_page__, null, __WEBSITE_ID__, 'index', '', 'index', '', '', '', '', '1', '2022-08-09 16:34:54', '2022-11-20 15:10:45', null, '', 'page', '', '__N____N____N____N____N__
__N__
__N__
__N__
__N__
__N__
__N__
__N__

__N__ Delicious Steaks__N__

__N____N__
__N__ __N__
__N__ __N__ __N__ __N__ __N__ __N__
__N__
__N__
__N__
__N__
__N____N__
__N__ __N__
__N__
__N__
__N__ __N__
__N____N__
__N__

__N__ Fine Dining Restaurant__N__

__N__
__N__
__N____N__
__N__
__N__ __N__
__N____N__
__N__ __N__

Steak

__N____N__ 26.50__N__
__N__
__N__
__N____N__
__N__
__N__ __N__
__N____N__
__N__ __N__

__N__ Sausage Pasta__N__

__N____N__ 18.25__N__
__N__
__N__
__N__
__N____N__ __N__ __N__ Previous__N__ __N____N__ __N__ __N__ Next__N__ __N__ __N__ __N__ __N__ __N____N__
__N__
__N____N__
__N__
__N__
__N__
__N__

__N__ Special Menus__N__

__N__
__N____N__
__N__
__N__
__N__ __N____N__ Breakfast__N__
__N____N__ __N__

Morning Fresh

__N____N__ 12.50__N____N__ __N__
__N__ __N__ __N__ __N__ __N__ __N__
__N__
__N__
__N__
__N__
__N____N__
__N__
__N__
__N__ __N____N__ Lunch__N__
__N____N__ __N__

DoliCloud Soup

__N____N__ 24.50__N____N__ __N__
__N__ __N__ __N__ __N__ __N__ __N__
__N__
__N__
__N__ __N__ __N____N__
__N__
__N__
__N__ __N____N__ Dinner__N__
__N____N__ __N__

Premium Steak

__N____N__ 45__N____N__ __N__
__N__ __N__ __N__ __N__ __N__ __N__
__N__
__N__
__N__ __N__ __N____N__
__N__
__N__
__N__ __N____N__ Dinner__N__
__N____N__ __N__

Seafood Set

__N____N__ 86__N____N__ __N__
__N__ __N__ __N__ __N__ __N__ __N__
__N__
__N__
__N__ __N__ __N____N__
__N__
__N__
__N__ __N____N__ Breakfast__N__
__N____N__ __N__

Burger Set

__N____N__ 20.50__N____N__ __N__
__N__ __N__ __N__ __N__ __N__ __N__
__N__
__N__
__N__ __N__ __N____N__
__N__
__N__
__N__ __N____N__ Lunch__N__
__N____N__ __N__

Healthy Soup

__N____N__ 34.20__N____N__ __N__
__N__ __N__ __N__ __N__ __N__ __N__
__N__
__N__
__N__ __N__ __N__ __N__ __N__
__N__
__N____N__
__N____N____N____N__', '', 0); +UPDATE llx_website SET fk_default_home = 5__+MAX_llx_website_page__ WHERE rowid = __WEBSITE_ID__; +-- File generated by Dolibarr 17.0.0-beta -- 2022-11-20 14:10:56 UTC --; +-- Page ID 251 -> 6__+MAX_llx_website_page__ - Aliases menu --; +INSERT INTO llx_website_page(rowid, fk_page, fk_website, pageurl, aliasalt, title, description, lang, image, keywords, status, date_creation, tms, import_key, grabbed_from, type_container, htmlheader, content, author_alias, allowed_in_frames) VALUES(6__+MAX_llx_website_page__, null, __WEBSITE_ID__, 'menu', '', 'Our menus', '', '', '', '', '1', '2022-08-16 14:37:03', '2022-11-20 14:30:03', null, '', 'page', '', '__N____N____N____N____N__
__N__
__N__
__N__
__N__
__N__
__N__

Our Menus

__N____N__ Perfect for all Breakfast, Lunch and__N__ Dinner__N__
__N__
__N__
__N____N__
__N__
__N____N__
__N__
__N__
__N__
__N__

Breakfast Menu

__N__
__N____N__
__N__
__N__ __N____N__ __N__

Fresh Start

__N____N__ $24.50__N__
__N__
__N__
__N____N__
__N__
__N__ __N____N__ __N__

Baked Creamy

__N____N__ $16.50__N__
__N__
__N__
__N____N__
__N__
__N__ __N____N__ __N__

Burger Set

__N____N__ $24.50__N____N__ $36.50__N__
__N__
__N__ __N__ __N__ __N__
__N____N__
__N__
__N__
__N__
__N__

Lunch Menu

__N__
__N____N__
__N__
__N__ __N____N__ __N__

Super Steak Set

__N____N__ $32.75__N____N__ $55__N__
__N__
__N__
__N____N__
__N__
__N__ __N____N__ __N__

Bread & Steak Set

__N____N__ $42.50__N__
__N__
__N__
__N__ __N__ __N__
__N____N__
__N__
__N__
__N__
__N__

Dinner Menu

__N__
__N____N__
__N__
__N__ __N____N__ __N__

Seafood Set

__N____N__ $65.50__N__
__N__
__N__
__N____N__
__N__
__N__ __N____N__ __N__

Premium Steak

__N____N__ $74.25__N__
__N__
__N__
__N____N__
__N__
__N__ __N____N__ __N__

Salmon Set

__N____N__ $60__N__
__N__
__N__ __N__ __N__ __N__
__N__
__N____N__
__N____N____N____N__', '', 0); -- For Dolibarr v14+ --; UPDATE llx_website SET lang = 'en' WHERE rowid = __WEBSITE_ID__; diff --git a/htdocs/install/mysql/data/llx_c_action_trigger.sql b/htdocs/install/mysql/data/llx_c_action_trigger.sql index 83d4bb6e775..9aa28c116c8 100644 --- a/htdocs/install/mysql/data/llx_c_action_trigger.sql +++ b/htdocs/install/mysql/data/llx_c_action_trigger.sql @@ -119,9 +119,6 @@ insert into llx_c_action_trigger (code,label,description,elementtype,rang) value insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('EXPENSE_REPORT_APPROVE','Expense report approved','Executed when an expense report is approved','expensereport',203); insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('EXPENSE_REPORT_PAID','Expense report billed','Executed when an expense report is set as billed','expensereport',204); insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('EXPENSE_REPORT_DELETE','Expense report deleted','Executed when an expense report is deleted','expensereport',205); -insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('HOLIDAY_VALIDATE','Expense report validated','Executed when an expense report is validated','expensereport',211); -insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('HOLIDAY_MODIFY','Expense report modified','Executed when an expense report is modified','expensereport',212); -insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('HOLIDAY_APPROVE','Expense report approved','Executed when an expense report is approved','expensereport',212); insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('PROJECT_CREATE','Project creation','Executed when a project is created','project',140); insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('PROJECT_VALIDATE','Project validation','Executed when a project is validated','project',141); insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('PROJECT_MODIFY','Project modified','Executed when a project is modified','project',142); @@ -172,7 +169,7 @@ insert into llx_c_action_trigger (code,label,description,elementtype,rang) value insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('HOLIDAY_CREATE','Holiday created','Executed when a holiday is created','holiday',800); insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('HOLIDAY_MODIFY','Holiday modified','Executed when a holiday is modified','holiday',801); insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('HOLIDAY_VALIDATE','Holiday validated','Executed when a holiday is validated','holiday',802); -insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('HOLIDAY_APPROVE','Holiday aprouved','Executed when a holiday is aprouved','holiday',803); +insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('HOLIDAY_APPROVE','Holiday approved','Executed when a holiday is aprouved','holiday',803); insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('HOLIDAY_CANCEL','Holiday canceled','Executed when a holiday is canceled','holiday',802); insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('HOLIDAY_DELETE','Holiday deleted','Executed when a holiday is deleted','holiday',804); diff --git a/htdocs/install/mysql/data/llx_c_actioncomm.sql b/htdocs/install/mysql/data/llx_c_actioncomm.sql index 38f09ba23d0..c244bcae2bd 100644 --- a/htdocs/install/mysql/data/llx_c_actioncomm.sql +++ b/htdocs/install/mysql/data/llx_c_actioncomm.sql @@ -21,7 +21,6 @@ -- You should have received a copy of the GNU General Public License -- along with this program. If not, see . -- --- -- -- Do not put a comment at the end of the line, this file is parsed during the @@ -37,14 +36,6 @@ delete from llx_c_actioncomm where id in (1,2,3,4,5,6,8,9,10,11,30,31,40,50); --- Code used from 3.3+ when type of event is used -insert into llx_c_actioncomm (id, code, libelle, type, module, active, position) values ( 1, 'AC_TEL', 'Phone call', 'system', NULL, 1, 2); -insert into llx_c_actioncomm (id, code, libelle, type, module, active, position) values ( 2, 'AC_FAX', 'Send Fax', 'system', NULL, 1, 3); -insert into llx_c_actioncomm (id, code, libelle, type, module, active, position) values ( 4, 'AC_EMAIL', 'Send Email', 'system', NULL, 1, 4); -insert into llx_c_actioncomm (id, code, libelle, type, module, active, position) values ( 5, 'AC_RDV', 'Rendez-vous', 'system', NULL, 1, 1); -insert into llx_c_actioncomm (id, code, libelle, type, module, active, position) values ( 6, 'AC_EMAIL_IN', 'reception Email', 'system', NULL, 1, 4); -insert into llx_c_actioncomm (id, code, libelle, type, module, active, position) values ( 11, 'AC_INT', 'Intervention on site', 'system', NULL, 1, 4); - -- Code kept for backward compatibility < 3.3 --insert into llx_c_actioncomm (id, code, libelle, type, module, active, position) values ( 3, 'AC_PROP', 'Send commercial proposal by email', 'systemauto', 'propal', 0, 10); --insert into llx_c_actioncomm (id, code, libelle, type, module, active, position) values ( 8, 'AC_COM', 'Send customer order by email', 'systemauto', 'order', 0, 8); @@ -53,10 +44,18 @@ insert into llx_c_actioncomm (id, code, libelle, type, module, active, position) --insert into llx_c_actioncomm (id, code, libelle, type, module, active, position) values ( 30, 'AC_SUP_ORD', 'Send supplier order by email', 'systemauto', 'order_supplier', 0, 9); --insert into llx_c_actioncomm (id, code, libelle, type, module, active, position) values ( 31, 'AC_SUP_INV', 'Send supplier invoice by email', 'systemauto', 'invoice_supplier', 0, 7); +-- Code used from 3.3+ when type of event is used +insert into llx_c_actioncomm (id, code, libelle, type, module, active, position) values ( 1, 'AC_TEL', 'Phone call', 'system', NULL, 1, 2); +insert into llx_c_actioncomm (id, code, libelle, type, module, active, position) values ( 2, 'AC_FAX', 'Send Fax', 'system', NULL, 0, 3); +insert into llx_c_actioncomm (id, code, libelle, type, module, active, position) values ( 4, 'AC_EMAIL', 'Send Email', 'system', NULL, 0, 4); +insert into llx_c_actioncomm (id, code, libelle, type, module, active, position) values ( 5, 'AC_RDV', 'Rendez-vous', 'system', NULL, 1, 1); +insert into llx_c_actioncomm (id, code, libelle, type, module, active, position) values ( 6, 'AC_EMAIL_IN', 'Reception Email', 'system', NULL, 0, 4); +insert into llx_c_actioncomm (id, code, libelle, type, module, active, position) values ( 11, 'AC_INT', 'Intervention on site', 'system', NULL, 1, 4); + -- Code used from 3.3+ when type of event is not used insert into llx_c_actioncomm (id, code, libelle, type, module, active, position) values ( 40, 'AC_OTH_AUTO', 'Other (automatically inserted events)', 'systemauto', NULL, 1, 20); -insert into llx_c_actioncomm (id, code, libelle, type, module, active, position) values ( 50, 'AC_OTH', 'Other (manually inserted events)', 'systemauto', NULL, 1, 5); +insert into llx_c_actioncomm (id, code, libelle, type, module, active, position) values ( 50, 'AC_OTH', 'Other (manually inserted events)', 'system', NULL, 1, 5); INSERT INTO llx_c_actioncomm (id, code, libelle, type, module, active, position) VALUES ( 60, 'AC_EO_ONLINECONF', 'Online/Virtual conference', 'module', 'conference@eventorganization', 1, 60); INSERT INTO llx_c_actioncomm (id, code, libelle, type, module, active, position) VALUES ( 61, 'AC_EO_INDOORCONF', 'Indoor conference', 'module', 'conference@eventorganization', 1, 61); diff --git a/htdocs/install/mysql/data/llx_c_tva.sql b/htdocs/install/mysql/data/llx_c_tva.sql index d78fea4ad4d..6c96cb46605 100644 --- a/htdocs/install/mysql/data/llx_c_tva.sql +++ b/htdocs/install/mysql/data/llx_c_tva.sql @@ -137,7 +137,6 @@ insert into llx_c_tva(rowid,fk_pays,taux,code,recuperableonly,localtax1,localtax -- GERMANY (id country=5) insert into llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) values ( 51, 5, '0','0','No VAT', 1); insert into llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) values ( 52, 5, '7.0','0','ermäßigte USt.', 1); -insert into llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) values ( 53, 5, '0.0','0','keine USt.', 1); insert into llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) values ( 54, 5, '5.5','0','USt. Forst', 0); insert into llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) values ( 55, 5, '10.7','0','USt. Landwirtschaft', 0); insert into llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) values ( 56, 5, '19.0','0','allgemeine Ust.',1); diff --git a/htdocs/install/mysql/data/llx_const.sql b/htdocs/install/mysql/data/llx_const.sql index 61c7336f48b..06463207069 100644 --- a/htdocs/install/mysql/data/llx_const.sql +++ b/htdocs/install/mysql/data/llx_const.sql @@ -35,7 +35,7 @@ insert into llx_const (name, value, type, note, visible, entity) values ('MAIN_NOT_INSTALLED','1','chaine','Setup is running',1,0); insert into llx_const (name, value, type, note, visible, entity) values ('MAIN_FEATURES_LEVEL','0','chaine','Level of features to show: -1=stable+deprecated, 0=stable only (default), 1=stable+experimental, 2=stable+experimental+development',1,0); insert into llx_const (name, value, type, note, visible, entity) values ('MAILING_LIMIT_SENDBYWEB','25','chaine','Number of targets to defined packet size when sending mass email',1,0); -insert into llx_const (name, value, type, note, visible, entity) values ('MAIN_ENABLE_LOG_TO_HTML','0','chaine','If this option is set to 1, it is possible to see log output at end of HTML sources by adding paramater logtohtml=1 on URL. Module log must also be enabled.',1,0); +--insert into llx_const (name, value, type, note, visible, entity) values ('MAIN_ENABLE_LOG_TO_HTML','0','chaine','If this option is set to 1, it is possible to see log output at end of HTML sources by adding paramater logtohtml=1 on URL. Module log must also be enabled.',1,0); -- Hidden and common to all entities insert into llx_const (name, value, type, note, visible, entity) values ('SYSLOG_HANDLERS','["mod_syslog_file"]','chaine','Which logger to use',0,0); diff --git a/htdocs/install/mysql/migration/16.0.0-17.0.0.sql b/htdocs/install/mysql/migration/16.0.0-17.0.0.sql index bef3e07e910..228fde598bb 100644 --- a/htdocs/install/mysql/migration/16.0.0-17.0.0.sql +++ b/htdocs/install/mysql/migration/16.0.0-17.0.0.sql @@ -52,9 +52,16 @@ ALTER TABLE llx_user DROP COLUMN idpers1; ALTER TABLE llx_user DROP COLUMN idpers2; ALTER TABLE llx_user DROP COLUMN idpers3; +UPDATE llx_c_actioncomm SET type = 'system' WHERE code = 'AC_OTH'; + +ALTER TABLE llx_opensurvey_user_studs MODIFY reponses VARCHAR(200) NOT NULL; -- v17 +ALTER TABLE llx_mailing_cibles MODIFY COLUMN source_type varchar(32); + +ALTER TABLE llx_actioncomm ADD INDEX idx_actioncomm_percent (percent); + UPDATE llx_c_paiement SET code = 'BANCON' WHERE code = 'BAN' AND libelle = 'Bancontact'; -- VMYSQL4.3 ALTER TABLE llx_partnership MODIFY COLUMN fk_user_creat integer NULL; @@ -62,6 +69,11 @@ UPDATE llx_c_paiement SET code = 'BANCON' WHERE code = 'BAN' AND libelle = 'Banc ALTER TABLE llx_partnership ADD COLUMN ip varchar(250); ALTER TABLE llx_adherent ADD COLUMN ip varchar(250); +ALTER TABLE llx_projet ADD COLUMN ip varchar(250); +ALTER TABLE llx_actioncomm ADD COLUMN ip varchar(250); +ALTER TABLE llx_eventorganization_conferenceorboothattendee ADD COLUMN ip varchar(250); +ALTER TABLE llx_opensurvey_user_studs ADD COLUMN ip varchar(250); +ALTER TABLE llx_opensurvey_comments ADD COLUMN ip varchar(250); ALTER TABLE llx_fichinterdet_rec DROP COLUMN remise; ALTER TABLE llx_fichinterdet_rec DROP COLUMN fk_export_commpta; @@ -81,8 +93,6 @@ UPDATE llx_holiday SET fk_user_approve = fk_user_valid WHERE statut = 3 AND fk_u ALTER TABLE llx_inventory ADD COLUMN categories_product VARCHAR(255) DEFAULT NULL AFTER fk_product; -ALTER TABLE llx_ticket ADD COLUMN ip varchar(250); - ALTER TABLE llx_societe ADD last_main_doc VARCHAR(255) NULL AFTER model_pdf; ALTER TABLE llx_emailcollector_emailcollector MODIFY COLUMN lastresult text; @@ -110,12 +120,12 @@ ALTER TABLE llx_product ADD COLUMN sell_or_eat_by_mandatory tinyint DEFAULT 0 NO ALTER TABLE llx_recruitment_recruitmentcandidature ADD email_date datetime after email_msgid; -ALTER TABLE llx_societe ADD last_main_doc VARCHAR(255) NULL AFTER model_pdf; - ALTER TABLE llx_ticket ADD COLUMN ip varchar(250); ALTER TABLE llx_ticket ADD email_date datetime after email_msgid; +ALTER TABLE llx_ticket MODIFY COLUMN message mediumtext; + ALTER TABLE llx_cronjob ADD COLUMN pid integer; INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('BE-VICTORYDAY', 0, 2, '', 0, 5, 8, 1); @@ -372,5 +382,10 @@ ALTER TABLE llx_prelevement_facture_demande RENAME TO llx_prelevement_demande; ALTER TABLE llx_prelevement ADD COLUMN fk_salary INTEGER NULL AFTER fk_facture_fourn; ALTER TABLE llx_prelevement_demande ADD COLUMN fk_salary INTEGER NULL AFTER fk_facture_fourn; - ALTER TABLE llx_user ADD COLUMN birth_place varchar(64); + +ALTER TABLE llx_opensurvey_user_studs ADD COLUMN date_creation datetime NULL; +ALTER TABLE llx_opensurvey_comments ADD COLUMN date_creation datetime NULL; + +ALTER TABLE llx_c_tva ADD COLUMN use_default tinyint DEFAULT 0; + diff --git a/htdocs/install/mysql/tables/llx_actioncomm.key.sql b/htdocs/install/mysql/tables/llx_actioncomm.key.sql index ee16386c7c4..944471620ae 100644 --- a/htdocs/install/mysql/tables/llx_actioncomm.key.sql +++ b/htdocs/install/mysql/tables/llx_actioncomm.key.sql @@ -27,5 +27,6 @@ ALTER TABLE llx_actioncomm ADD INDEX idx_actioncomm_datep (datep); ALTER TABLE llx_actioncomm ADD INDEX idx_actioncomm_datep2 (datep2); ALTER TABLE llx_actioncomm ADD INDEX idx_actioncomm_recurid (recurid); ALTER TABLE llx_actioncomm ADD INDEX idx_actioncomm_ref_ext (ref_ext); +ALTER TABLE llx_actioncomm ADD INDEX idx_actioncomm_percent (percent); ALTER TABLE llx_actioncomm ADD UNIQUE INDEX uk_actioncomm_ref (ref, entity); diff --git a/htdocs/install/mysql/tables/llx_c_tva.sql b/htdocs/install/mysql/tables/llx_c_tva.sql index b9a6cc4e12c..9bc77bb69ea 100644 --- a/htdocs/install/mysql/tables/llx_c_tva.sql +++ b/htdocs/install/mysql/tables/llx_c_tva.sql @@ -28,6 +28,7 @@ create table llx_c_tva localtax1_type varchar(10) NOT NULL DEFAULT '0', localtax2 varchar(20) NOT NULL DEFAULT '0', localtax2_type varchar(10) NOT NULL DEFAULT '0', + use_default tinyint DEFAULT 0, -- set to 1 to be the default vat when no vat defined on product recuperableonly integer NOT NULL DEFAULT 0, note varchar(128), active tinyint DEFAULT 1 NOT NULL, diff --git a/htdocs/install/mysql/tables/llx_mailing_cibles-mailing.sql b/htdocs/install/mysql/tables/llx_mailing_cibles-mailing.sql index da0b6c1683a..3c38eedaaaf 100644 --- a/htdocs/install/mysql/tables/llx_mailing_cibles-mailing.sql +++ b/htdocs/install/mysql/tables/llx_mailing_cibles-mailing.sql @@ -32,7 +32,7 @@ create table llx_mailing_cibles statut smallint NOT NULL DEFAULT 0, -- -1 = error, 0 = not sent, ... source_url varchar(255), source_id integer, - source_type varchar(16), + source_type varchar(32), date_envoi datetime, tms timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, error_text varchar(255) -- text with error if statut is -1 diff --git a/htdocs/install/mysql/tables/llx_opensurvey_comments-opensurvey.sql b/htdocs/install/mysql/tables/llx_opensurvey_comments-opensurvey.sql index 52d938b7c47..a615e0f9cb7 100644 --- a/htdocs/install/mysql/tables/llx_opensurvey_comments-opensurvey.sql +++ b/htdocs/install/mysql/tables/llx_opensurvey_comments-opensurvey.sql @@ -21,5 +21,6 @@ CREATE TABLE llx_opensurvey_comments ( comment text NOT NULL, tms timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, usercomment text + date_creation datetime NOT NULL, ) ENGINE=innodb; diff --git a/htdocs/install/mysql/tables/llx_opensurvey_user_studs-opensurvey.sql b/htdocs/install/mysql/tables/llx_opensurvey_user_studs-opensurvey.sql index 03ad9b35ec5..e139816c3fa 100644 --- a/htdocs/install/mysql/tables/llx_opensurvey_user_studs-opensurvey.sql +++ b/htdocs/install/mysql/tables/llx_opensurvey_user_studs-opensurvey.sql @@ -19,6 +19,7 @@ CREATE TABLE llx_opensurvey_user_studs ( id_users INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, nom VARCHAR(64) NOT NULL, id_sondage VARCHAR(16) NOT NULL, - reponses VARCHAR(100) NOT NULL, -- Not used for 'F' surveys + reponses VARCHAR(200) NOT NULL, -- Not used for 'F' surveys tms timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP + date_creation datetime NOT NULL, ) ENGINE=innodb; diff --git a/htdocs/install/mysql/tables/llx_product.sql b/htdocs/install/mysql/tables/llx_product.sql index 0c2fdce5152..2267113e987 100644 --- a/htdocs/install/mysql/tables/llx_product.sql +++ b/htdocs/install/mysql/tables/llx_product.sql @@ -57,7 +57,7 @@ create table llx_product fk_user_modif integer, -- user making last change tosell tinyint DEFAULT 1, -- Product you sell tobuy tinyint DEFAULT 1, -- Product you buy - onportal tinyint DEFAULT 0, -- If it is a product you sell and you want to sell it on portal (module website must be on) + onportal tinyint DEFAULT 0, -- If it is a product you sell and you want to sell it from internal portal (module 'portal') tobatch tinyint DEFAULT 0 NOT NULL, -- Is it a product that need a batch management (eat-by or lot management) sell_or_eat_by_mandatory tinyint DEFAULT 0 NOT NULL, -- Make sell-by or eat-by date mandatory batch_mask varchar(32) DEFAULT NULL, -- If the product has batch feature, you may want to use a batch mask per product diff --git a/htdocs/install/mysql/tables/llx_projet.key.sql b/htdocs/install/mysql/tables/llx_projet.key.sql index 4b9dd008943..26869454c41 100644 --- a/htdocs/install/mysql/tables/llx_projet.key.sql +++ b/htdocs/install/mysql/tables/llx_projet.key.sql @@ -22,4 +22,8 @@ ALTER TABLE llx_projet ADD UNIQUE INDEX uk_projet_ref (ref, entity); ALTER TABLE llx_projet ADD INDEX idx_projet_fk_soc (fk_soc); +ALTER TABLE llx_projet ADD INDEX idx_projet_ref (ref); +ALTER TABLE llx_projet ADD INDEX idx_projet_fk_statut (fk_statut); +ALTER TABLE llx_projet ADD INDEX idx_projet_fk_opp_status (fk_opp_status); + ALTER TABLE llx_projet ADD CONSTRAINT fk_projet_fk_soc FOREIGN KEY (fk_soc) REFERENCES llx_societe (rowid); diff --git a/htdocs/install/mysql/tables/llx_societe.sql b/htdocs/install/mysql/tables/llx_societe.sql index 7f198db6042..47671f4e7c3 100644 --- a/htdocs/install/mysql/tables/llx_societe.sql +++ b/htdocs/install/mysql/tables/llx_societe.sql @@ -44,7 +44,7 @@ create table llx_societe town varchar(50), -- town fk_departement integer DEFAULT 0, -- fk_pays integer DEFAULT 0, -- - fk_account integer DEFAULT 0, -- + fk_account integer DEFAULT 0, -- default bank account phone varchar(20), -- phone number fax varchar(20), -- fax number url varchar(255), -- diff --git a/htdocs/install/mysql/tables/llx_ticket-ticket.sql b/htdocs/install/mysql/tables/llx_ticket-ticket.sql index 278d62894bc..c651eaccca2 100644 --- a/htdocs/install/mysql/tables/llx_ticket-ticket.sql +++ b/htdocs/install/mysql/tables/llx_ticket-ticket.sql @@ -26,7 +26,7 @@ CREATE TABLE llx_ticket fk_user_create integer, fk_user_assign integer, subject varchar(255), - message text, + message mediumtext, fk_statut integer, resolution integer, progress integer DEFAULT 0, -- progression 0 - 100 or null diff --git a/htdocs/install/step5.php b/htdocs/install/step5.php index 958a8b28d95..4fc30772f78 100644 --- a/htdocs/install/step5.php +++ b/htdocs/install/step5.php @@ -297,7 +297,7 @@ if ($action == "set" || empty($action) || preg_match('/upgrade/i', $action)) { } 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'"); + $resql = $db->query("DELETE FROM ".MAIN_DB_PREFIX."const WHERE ".$db->decrypt('name')." = 'MAIN_NOT_INSTALLED'"); if (!$resql) { dol_print_error($db, 'Error in setup program'); } diff --git a/htdocs/knowledgemanagement/knowledgerecord_agenda.php b/htdocs/knowledgemanagement/knowledgerecord_agenda.php index 026e2fad51d..b293a2dbdd7 100644 --- a/htdocs/knowledgemanagement/knowledgerecord_agenda.php +++ b/htdocs/knowledgemanagement/knowledgerecord_agenda.php @@ -87,7 +87,8 @@ if ($id > 0 || !empty($ref)) { // Security check - Protection if external user //if ($user->socid > 0) accessforbidden(); //if ($user->socid > 0) $socid = $user->socid; -//$result = restrictedArea($user, 'knowledgemanagement', $object->id); +$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +restrictedArea($user, $object->module, $object->id, $object->table_element, $object->element, '', 'rowid', $isdraft); $permissiontoadd = $user->rights->knowledgemanagement->knowledgerecord->write; // Used by the include of actions_addupdatedelete.inc.php diff --git a/htdocs/knowledgemanagement/knowledgerecord_card.php b/htdocs/knowledgemanagement/knowledgerecord_card.php index c28bc9e1c9c..0c182d71f9e 100644 --- a/htdocs/knowledgemanagement/knowledgerecord_card.php +++ b/htdocs/knowledgemanagement/knowledgerecord_card.php @@ -85,8 +85,8 @@ $upload_dir = $conf->knowledgemanagement->multidir_output[isset($object->entity) // Security check - Protection if external user //if ($user->socid > 0) accessforbidden(); //if ($user->socid > 0) $socid = $user->socid; -//$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); -//restrictedArea($user, $object->element, $object->id, '', '', 'fk_soc', 'rowid', $isdraft); +$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +restrictedArea($user, $object->module, $object->id, $object->table_element, $object->element, '', 'rowid', $isdraft); //if (empty($conf->knowledgemanagement->enabled)) accessforbidden(); //if (empty($permissiontoread)) accessforbidden(); @@ -478,7 +478,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea // Back to draft if ($object->status == $object::STATUS_VALIDATED) { - print dolGetButtonAction('', $langs->trans('SetToDraft'), 'default', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=confirm_setdraft&confirm=yes', '', $permissiontoadd); + print dolGetButtonAction('', $langs->trans('SetToDraft'), 'default', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=confirm_setdraft&confirm=yes&token='.newToken(), '', $permissiontoadd); } if (($object->status == $object::STATUS_DRAFT || $object->status == $object::STATUS_VALIDATED) && $permissiontovalidate) { print dolGetButtonAction('', $langs->trans('Modify'), 'default', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=edit&token='.newToken(), '', $permissiontoadd); diff --git a/htdocs/knowledgemanagement/knowledgerecord_contact.php b/htdocs/knowledgemanagement/knowledgerecord_contact.php index e1c77ab0d7b..4e557a3e1ae 100644 --- a/htdocs/knowledgemanagement/knowledgerecord_contact.php +++ b/htdocs/knowledgemanagement/knowledgerecord_contact.php @@ -53,12 +53,14 @@ include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be includ // Security check - Protection if external user //if ($user->socid > 0) accessforbidden(); //if ($user->socid > 0) $socid = $user->socid; -//$result = restrictedArea($user, 'knowledgemanagement', $object->id); +$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +restrictedArea($user, $object->module, $object->id, $object->table_element, $object->element, '', 'rowid', $isdraft); $permission = $user->rights->knowledgemanagement->knowledgerecord->write; + /* - * Add a new contact + * Actions */ if ($action == 'addcontact' && $permission) { @@ -108,16 +110,10 @@ $contactstatic = new Contact($db); $userstatic = new User($db); -/* *************************************************************************** */ -/* */ -/* View and edit mode */ -/* */ -/* *************************************************************************** */ +// View and edit mode if ($object->id) { - /* - * Show tabs - */ + // Show tabs $head = knowledgerecordPrepareHead($object); print dol_get_fiche_head($head, 'contact', $langs->trans("KnowledgeRecord"), -1, $object->picto); diff --git a/htdocs/knowledgemanagement/knowledgerecord_document.php b/htdocs/knowledgemanagement/knowledgerecord_document.php index fff7ad68601..7430de8a495 100644 --- a/htdocs/knowledgemanagement/knowledgerecord_document.php +++ b/htdocs/knowledgemanagement/knowledgerecord_document.php @@ -78,7 +78,8 @@ if ($id > 0 || !empty($ref)) { // Security check - Protection if external user //if ($user->socid > 0) accessforbidden(); //if ($user->socid > 0) $socid = $user->socid; -//$result = restrictedArea($user, 'knowledgemanagement', $object->id); +$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +restrictedArea($user, $object->module, $object->id, $object->table_element, $object->element, '', 'rowid', $isdraft); $permissiontoadd = $user->rights->knowledgemanagement->knowledgerecord->write; // Used by the include of actions_addupdatedelete.inc.php and actions_linkedfiles.inc.php diff --git a/htdocs/knowledgemanagement/knowledgerecord_list.php b/htdocs/knowledgemanagement/knowledgerecord_list.php index c8df2018ae7..dffd3d63d7b 100644 --- a/htdocs/knowledgemanagement/knowledgerecord_list.php +++ b/htdocs/knowledgemanagement/knowledgerecord_list.php @@ -153,7 +153,7 @@ if ($user->socid > 0) { // Protection if external user //$socid = $user->socid; accessforbidden(); } -//$result = restrictedArea($user, 'knowledgemanagement'); +$result = restrictedArea($user, 'knowledgemanagement', 0, '', 'knowledgerecord'); //if (!$permissiontoread) accessforbidden(); diff --git a/htdocs/knowledgemanagement/knowledgerecord_note.php b/htdocs/knowledgemanagement/knowledgerecord_note.php index 3abc9e71866..28a2bcaa9d0 100644 --- a/htdocs/knowledgemanagement/knowledgerecord_note.php +++ b/htdocs/knowledgemanagement/knowledgerecord_note.php @@ -46,11 +46,6 @@ $hookmanager->initHooks(array('knowledgerecordnote', 'globalcard')); // Note tha // Fetch optionals attributes and labels $extrafields->fetch_name_optionals_label($object->table_element); -// Security check - Protection if external user -//if ($user->socid > 0) accessforbidden(); -//if ($user->socid > 0) $socid = $user->socid; -//$result = restrictedArea($user, 'knowledgemanagement', $id); - // Load object include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be include, not include_once // Must be include, not include_once. Include fetch and fetch_thirdparty but not fetch_optionals if ($id > 0 || !empty($ref)) { @@ -60,6 +55,11 @@ if ($id > 0 || !empty($ref)) { $permissionnote = $user->rights->knowledgemanagement->knowledgerecord->write; // Used by the include of actions_setnotes.inc.php $permissiontoadd = $user->rights->knowledgemanagement->knowledgerecord->write; // Used by the include of actions_addupdatedelete.inc.php +// Security check - Protection if external user +//if ($user->socid > 0) accessforbidden(); +//if ($user->socid > 0) $socid = $user->socid; +$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); +restrictedArea($user, $object->module, $object->id, $object->table_element, $object->element, '', 'rowid', $isdraft); /* diff --git a/htdocs/knowledgemanagement/lib/knowledgemanagement.lib.php b/htdocs/knowledgemanagement/lib/knowledgemanagement.lib.php index 2f189b05f5c..d1de9e5e401 100644 --- a/htdocs/knowledgemanagement/lib/knowledgemanagement.lib.php +++ b/htdocs/knowledgemanagement/lib/knowledgemanagement.lib.php @@ -28,10 +28,13 @@ */ function knowledgemanagementAdminPrepareHead() { - global $langs, $conf; + global $langs, $conf, $db; $langs->load("knowledgemanagement"); + $extrafields = new ExtraFields($db); + $extrafields->fetch_name_optionals_label('knowledgemanagement_knowledgerecord'); + $h = 0; $head = array(); @@ -43,14 +46,13 @@ function knowledgemanagementAdminPrepareHead() $head[$h][0] = DOL_URL_ROOT.'/admin/knowledgerecord_extrafields.php'; $head[$h][1] = $langs->trans("ExtraFields"); + $nbExtrafields = $extrafields->attributes['knowledgemanagement_knowledgerecord']['count']; + if ($nbExtrafields > 0) { + $head[$h][1] .= ''.$nbExtrafields.''; + } $head[$h][2] = 'extra'; $h++; - /*$head[$h][0] = DOL_URL_ROOT.'/knowledgemanagement/admin/about.php'; - $head[$h][1] = $langs->trans("About"); - $head[$h][2] = 'about'; - $h++;*/ - // Show more tabs from modules // Entries must be declared in modules descriptor with line //$this->tabs = array( diff --git a/htdocs/langs/de_AT/ecm.lang b/htdocs/langs/de_AT/ecm.lang index bfb47abf032..29ad990c4ca 100644 --- a/htdocs/langs/de_AT/ecm.lang +++ b/htdocs/langs/de_AT/ecm.lang @@ -2,4 +2,3 @@ ECMSectionsManual=Manuelle Verzeichnisse ECMSectionsAuto=Automatische Verzeichnisse ECMNbOfFilesInSubDir=Anzahl der Dateien im Unterverzeichnis -ECMAreaDesc2=* Automatische Verzeichnisse werden automatisch befüllt, wenn Sie Dokumente von der Karte eines Elements erstellen.
* Manuelle Verzeichnisse können Sie dazu nutzen, nicht mit anderen Elementen verbundene Dokumente zu speichern. diff --git a/htdocs/langs/de_CH/ecm.lang b/htdocs/langs/de_CH/ecm.lang index 57cb0298e43..814cee2c845 100644 --- a/htdocs/langs/de_CH/ecm.lang +++ b/htdocs/langs/de_CH/ecm.lang @@ -6,7 +6,6 @@ ECMAddSection=Ordner hinzufügen ECMNbOfFilesInDir=Anzahl der Dateien in Ordner ECMNbOfSubDir=Anzahl der Unterordner ECMNbOfFilesInSubDir=Anzahl Dateien in Unterordnern -ECMAreaDesc2=* In den automatischen Verzeichnissen werden die vom System erzeugeten Dokumente abgelegt.
* Die manuellen Verzeichnisse können Sie selbst verwalten und zusätzliche nicht direkt zuordenbare Dokument hinterlegen. ECMSectionWasRemoved=Der Ordner %s wurde gelöscht. ECMSearchByKeywords=Suche nach Stichwörter ECMSearchByEntity=Suche nach Objekt diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang index 911bb6b0b93..538309a6342 100644 --- a/htdocs/langs/en_US/admin.lang +++ b/htdocs/langs/en_US/admin.lang @@ -1250,6 +1250,7 @@ AreaForAdminOnly=Setup parameters can be set by administrator users only. SystemInfoDesc=System information is miscellaneous technical information you get in read only mode and visible for administrators only. SystemAreaForAdminOnly=This area is available to administrator users only. Dolibarr user permissions cannot change this restriction. CompanyFundationDesc=Edit the information of your company/organization. Click on "%s" button at the bottom of the page when done. +MoreNetworksAvailableWithModule=More social networks may be available by enabling the module "Social networks". AccountantDesc=If you have an external accountant/bookkeeper, you can edit here its information. AccountantFileNumber=Accountant code DisplayDesc=Parameters affecting the look and presentation of the application can be modified here. @@ -1881,7 +1882,7 @@ SuppliersInvoiceNumberingModel=Vendor invoices numbering models IfSetToYesDontForgetPermission=If set to a non null value, don't forget to provide permissions to groups or users allowed for the second approval ##### GeoIPMaxmind ##### GeoIPMaxmindSetup=GeoIP Maxmind module setup -PathToGeoIPMaxmindCountryDataFile=Path to file containing Maxmind ip to country translation.
Examples:
/usr/local/share/GeoIP/GeoIP.dat
/usr/share/GeoIP/GeoIP.dat
/usr/share/GeoIP/GeoLite2-Country.mmdb +PathToGeoIPMaxmindCountryDataFile=Path to file containing Maxmind ip to country translation NoteOnPathLocation=Note that your ip to country data file must be inside a directory your PHP can read (Check your PHP open_basedir setup and filesystem permissions). YouCanDownloadFreeDatFileTo=You can download a free demo version of the Maxmind GeoIP country file at %s. YouCanDownloadAdvancedDatFileTo=You can also download a more complete version, with updates, of the Maxmind GeoIP country file at %s. @@ -1932,6 +1933,7 @@ BackupDumpWizard=Wizard to build the database dump file BackupZipWizard=Wizard to build the archive of documents directory SomethingMakeInstallFromWebNotPossible=Installation of external module is not possible from the web interface for the following reason: SomethingMakeInstallFromWebNotPossible2=For this reason, process to upgrade described here is a manual process only a privileged user may perform. +InstallModuleFromWebHasBeenDisabledContactUs=Install or development of external modules or dynamic websites, from the application, is currently locked for security purpose. Please contact us if you need to enable this feature. InstallModuleFromWebHasBeenDisabledByFile=Install of external module from application has been disabled by your administrator. You must ask him to remove the file %s to allow this feature. ConfFileMustContainCustom=Installing or building an external module from application need to save the module files into directory %s. To have this directory processed by Dolibarr, you must setup your conf/conf.php to add the 2 directive lines:
$dolibarr_main_url_root_alt='/custom';
$dolibarr_main_document_root_alt='%s/custom'; HighlightLinesOnMouseHover=Highlight table lines when mouse move passes over @@ -2298,6 +2300,8 @@ IconOnly=Icon only - Text on tooltip only INVOICE_ADD_ZATCA_QR_CODE=Show the ZATCA QR code on invoices INVOICE_ADD_ZATCA_QR_CODEMore=Some Arabic countries need this QR Code on their invoices INVOICE_ADD_SWISS_QR_CODE=Show the swiss QR-Bill code on invoices +INVOICE_SHOW_SHIPPING_ADDRESS=Show shipping address +INVOICE_SHOW_SHIPPING_ADDRESSMore=Compulsory mention for France UrlSocialNetworksDesc=Url link of social network. Use {socialid} for the variable part that contains the social network ID. IfThisCategoryIsChildOfAnother=If this category is a child of another one DarkThemeMode=Dark theme mode @@ -2317,7 +2321,7 @@ UsePassword=Use a password UseOauth=Use a OAUTH token Images=Images MaxNumberOfImagesInGetPost=Max number of images allowed in a HTML field submitted in a form -MaxNumberOfPostOnPublicPagesByIP=Max number of posts on public pages with the same IP address +MaxNumberOfPostOnPublicPagesByIP=Max number of posts on public pages with the same IP address in a month CIDLookupURL=The module brings an URL that can be used by an external tool to get the name of a thirdparty or contact from its phone number. URL to use is: ScriptIsEmpty=The script is empty ShowHideTheNRequests=Show/hide the %s SQL request(s) @@ -2340,3 +2344,4 @@ DesktopsAndSmartphones=Desktops et smartphones AllowOnlineSign=Allow online signing AllowExternalDownload=Allow external download (without login, using a shared link) DeadlineDayVATSubmission=Deadline day for vat submission on the next month +MaxNumberOfAttachementOnForms=Max number of joinded files in form diff --git a/htdocs/langs/en_US/bills.lang b/htdocs/langs/en_US/bills.lang index 2551f92af53..d7c29a82399 100644 --- a/htdocs/langs/en_US/bills.lang +++ b/htdocs/langs/en_US/bills.lang @@ -162,6 +162,7 @@ ErrorThisPartOrAnotherIsAlreadyUsedSoDiscountSerieCantBeRemoved=This part or ano ErrorInvoiceIsNotLastOfSameType=Error: The date of invoice %s is %s. It must be posterior or equal to last date for same type invoices (%s). Please change the invoice date. BillFrom=From BillTo=To +ShippingTo=Shipping to ActionsOnBill=Actions on invoice RecurringInvoiceTemplate=Template / Recurring invoice NoQualifiedRecurringInvoiceTemplateFound=No recurring template invoice qualified for generation. diff --git a/htdocs/langs/en_US/compta.lang b/htdocs/langs/en_US/compta.lang index 82ef7f0be9a..4b623231511 100644 --- a/htdocs/langs/en_US/compta.lang +++ b/htdocs/langs/en_US/compta.lang @@ -29,6 +29,8 @@ BalanceBefore=Balance (before) Balance=Balance Debit=Debit Credit=Credit +AccountingDebit=Debit +AccountingCredit=Credit Piece=Accounting Doc. AmountHTVATRealReceived=Net collected AmountHTVATRealPaid=Net paid diff --git a/htdocs/langs/en_US/errors.lang b/htdocs/langs/en_US/errors.lang index 860ae75e604..b3eeae4606b 100644 --- a/htdocs/langs/en_US/errors.lang +++ b/htdocs/langs/en_US/errors.lang @@ -97,7 +97,7 @@ ErrorWrongValueForField=Field %s: '%s' does not match regex rule < ErrorHtmlInjectionForField=Field %s: The value '%s' contains a malicious data not allowed ErrorFieldValueNotIn=Field %s: '%s' is not a value found in field %s of %s ErrorFieldRefNotIn=Field %s: '%s' is not a %s existing ref -ErrorMultipleRecordFoundFromRef=Several record found when searching from ref %s. No way to know which ID to use. +ErrorMultipleRecordFoundFromRef=Several record found when searching from ref %s. No way to know which ID to use. ErrorsOnXLines=%s errors found ErrorFileIsInfectedWithAVirus=The antivirus program was not able to validate the file (file might be infected by a virus) ErrorNumRefModel=A reference exists into database (%s) and is not compatible with this numbering rule. Remove record or renamed reference to activate this module. @@ -244,11 +244,12 @@ ErrorObjectMustHaveStatusActiveToBeDisabled=Objects must have status 'Active' to ErrorObjectMustHaveStatusDraftOrDisabledToBeActivated=Objects must have status 'Draft' or 'Disabled' to be enabled ErrorNoFieldWithAttributeShowoncombobox=No fields has property 'showoncombobox' into definition of object '%s'. No way to show the combolist. ErrorFieldRequiredForProduct=Field '%s' is required for product %s +AlreadyTooMuchPostOnThisIPAdress=You have already posted too much on this IP address. ProblemIsInSetupOfTerminal=Problem is in setup of terminal %s. ErrorAddAtLeastOneLineFirst=Add at least one line first ErrorRecordAlreadyInAccountingDeletionNotPossible=Error, record is already transferred in accounting, deletion is not possible. ErrorLanguageMandatoryIfPageSetAsTranslationOfAnother=Error, language is mandatory if you set the page as a translation of another one. -ErrorLanguageOfTranslatedPageIsSameThanThisPage=Error, language of translated page is same than this one. +ErrorLanguageOfTranslatedPageIsSameThanThisPage=Error, language of translated page is same than this one. ErrorBatchNoFoundForProductInWarehouse=No lot/serial found for product "%s" in warehouse "%s". ErrorBatchNoFoundEnoughQuantityForProductInWarehouse=No enough quantity for this lot/serial for product "%s" in warehouse "%s". ErrorOnlyOneFieldForGroupByIsPossible=Only 1 field for the 'Group by' is possible (others are discarded) @@ -279,13 +280,13 @@ ErrorWrongFileName=Name of the file cannot have __SOMETHING__ in it ErrorNotInDictionaryPaymentConditions=Not in Payment Terms Dictionary, please modify. ErrorIsNotADraft=%s is not a draft ErrorExecIdFailed=Can't execute command "id" -ErrorBadCharIntoLoginName=Unauthorized character in the login name -ErrorRequestTooLarge=Error, request too large -ErrorNotApproverForHoliday=You are not the approver for leave %s +ErrorBadCharIntoLoginName=Unauthorized character in the field %s +ErrorRequestTooLarge=Error, request too large or session expired +ErrorNotApproverForHoliday=You are not the approver for leave %s ErrorAttributeIsUsedIntoProduct=This attribute is used in one or more product variants ErrorAttributeValueIsUsedIntoProduct=This attribute value is used in one or more product variants ErrorPaymentInBothCurrency=Error, all amounts must be entered in the same column -ErrorYouTryToPayInvoicesInACurrencyFromBankWithAnotherCurrency=You try to pay invoices in the currency %s from an account with the currency %s +ErrorYouTryToPayInvoicesInACurrencyFromBankWithAnotherCurrency=You try to pay invoices in the currency %s from an account with the currency %s ErrorInvoiceLoadThirdParty=Can't load third-party object for invoice "%s" ErrorInvoiceLoadThirdPartyKey=Third-party key "%s" no set for invoice "%s" ErrorDeleteLineNotAllowedByObjectStatus=Delete line is not allowed by current object status @@ -294,13 +295,14 @@ ErrorThirpdartyOrMemberidIsMandatory=Third party or Member of partnership is man ErrorFailedToWriteInTempDirectory=Failed to write in temp directory ErrorQuantityIsLimitedTo=Quantity is limited to %s ErrorFailedToLoadThirdParty=Failed to find/load thirdparty from id=%s, email=%s, name=%s -ErrorThisPaymentModeIsNotSepa=This payment mode is not a bank account +ErrorThisPaymentModeIsNotSepa=This payment mode is not a bank account ErrorStripeCustomerNotFoundCreateFirst=Stripe customer is not set for this thirdparty (or set to a value deleted on Stripe side). Create (or re-attach) it first. -ErrorCharPlusNotSupportedByImapForSearch=IMAP search is not able to search into sender or recipient for a string containing the character + +ErrorCharPlusNotSupportedByImapForSearch=IMAP search is not able to search into sender or recipient for a string containing the character + ErrorTableNotFound=Table %s not found ErrorValueForTooLow=Value for %s is too low ErrorValueCantBeNull=Value for %s can't be null ErrorDateOfMovementLowerThanDateOfFileTransmission=The date of the bank transaction can't be lower than the date of the file transmission +ErrorTooMuchFileInForm=Too much files in form, the maximum number is %s file(s) # Warnings WarningParamUploadMaxFileSizeHigherThanPostMaxSize=Your PHP parameter upload_max_filesize (%s) is higher than PHP parameter post_max_size (%s). This is not a consistent setup. @@ -314,7 +316,7 @@ WarningConfFileMustBeReadOnly=Warning, your config file (htdocs/conf/conf.php WarningsOnXLines=Warnings on %s source record(s) WarningNoDocumentModelActivated=No model, for document generation, has been activated. A model will be chosen by default until you check your module setup. WarningLockFileDoesNotExists=Warning, once setup is finished, you must disable the installation/migration tools by adding a file install.lock into directory %s. Omitting the creation of this file is a grave security risk. -WarningUntilDirRemoved=All security warnings (visible by admin users only) will remain active as long as the vulnerability is present (or that constant MAIN_REMOVE_INSTALL_WARNING is added in Setup->Other Setup). +WarningUntilDirRemoved=This security warning will remain active as long as the vulnerability is present. WarningCloseAlways=Warning, closing is done even if amount differs between source and target elements. Enable this feature with caution. WarningUsingThisBoxSlowDown=Warning, using this box slow down seriously all pages showing the box. WarningClickToDialUserSetupNotComplete=Setup of ClickToDial information for your user are not complete (see tab ClickToDial onto your user card). diff --git a/htdocs/langs/en_US/main.lang b/htdocs/langs/en_US/main.lang index 2b86c2d3e65..87b4f8f3036 100644 --- a/htdocs/langs/en_US/main.lang +++ b/htdocs/langs/en_US/main.lang @@ -206,6 +206,7 @@ Valid=Valid Approve=Approve Disapprove=Disapprove ReOpen=Re-Open +OpenVerb=Open Upload=Upload ToLink=Link Select=Select @@ -488,6 +489,7 @@ ActionsOnContact=Events for this contact/address ActionsOnContract=Events for this contract ActionsOnMember=Events about this member ActionsOnProduct=Events about this product +ActionsOnAsset=Events for this fixed asset NActionsLate=%s late ToDo=To do Completed=Completed diff --git a/htdocs/langs/en_US/mrp.lang b/htdocs/langs/en_US/mrp.lang index 82196b584bd..442c5c92b1c 100644 --- a/htdocs/langs/en_US/mrp.lang +++ b/htdocs/langs/en_US/mrp.lang @@ -27,6 +27,7 @@ ConfirmCloneBillOfMaterials=Are you sure you want to clone the bill of materials ConfirmCloneMo=Are you sure you want to clone the Manufacturing Order %s ? ManufacturingEfficiency=Manufacturing efficiency ConsumptionEfficiency=Consumption efficiency +Consumption=Consumption ValueOfMeansLoss=Value of 0.95 means an average of 5%% of loss during the manufacturing or the disassembly ValueOfMeansLossForProductProduced=Value of 0.95 means an average of 5%% of loss of produced product DeleteBillOfMaterials=Delete Bill Of Materials diff --git a/htdocs/langs/en_US/projects.lang b/htdocs/langs/en_US/projects.lang index b6001b2b27b..2407d4b2d86 100644 --- a/htdocs/langs/en_US/projects.lang +++ b/htdocs/langs/en_US/projects.lang @@ -23,6 +23,7 @@ TasksPublicDesc=This view presents all projects and tasks you are allowed to rea TasksDesc=This view presents all projects and tasks (your user permissions grant you permission to view everything). AllTaskVisibleButEditIfYouAreAssigned=All tasks for qualified projects are visible, but you can enter time only for task assigned to selected user. Assign task if you need to enter time on it. OnlyYourTaskAreVisible=Only tasks assigned to you are visible. If you need to enter time on a task and if the task is not visible here, then you need to assign the task to yourself. +ImportDatasetProjects=Projects or opportunities ImportDatasetTasks=Tasks of projects ProjectCategories=Project tags/categories NewProject=New project @@ -240,7 +241,7 @@ OppStatusPENDING=Pending OppStatusWON=Won OppStatusLOST=Lost Budget=Budget -AllowToLinkFromOtherCompany=Allow to link project from other company

Supported values:
- Keep empty: Can link any project of the company (default)
- "all": Can link any projects, even projects of other companies
- A list of third-party ids separated by commas: can link all projects of these third partys (Example: 123,4795,53)
+AllowToLinkFromOtherCompany=Allow to link an element with a project of other company

Supported values:
- Keep empty: Can link elements with any projects in the same company (default)
- "all": Can link elements with any projects, even projects of other companies
- A list of third-party ids separated by commas: can link elements with any projects of these third partys (Example: 123,4795,53)
LatestProjects=Latest %s projects LatestModifiedProjects=Latest %s modified projects OtherFilteredTasks=Other filtered tasks @@ -284,7 +285,7 @@ ProfitIsCalculatedWith=Profit is calculated using AddPersonToTask=Add also to tasks UsageOrganizeEvent=Usage: Event Organization PROJECT_CLASSIFY_CLOSED_WHEN_ALL_TASKS_DONE=Classify project as closed when all its tasks are completed (100%% progress) -PROJECT_CLASSIFY_CLOSED_WHEN_ALL_TASKS_DONE_help=Note: existing projects with all tasks at 100 %% progress won't be affected: you will have to close them manually. This option only affects open projects. +PROJECT_CLASSIFY_CLOSED_WHEN_ALL_TASKS_DONE_help=Note: existing projects with all tasks already set to a progress of 100 %% won't be affected: you will have to close them manually. This option only affects open projects. SelectLinesOfTimeSpentToInvoice=Select lines of time spent that are unbilled, then bulk action "Generate Invoice" to bill them ProjectTasksWithoutTimeSpent=Project tasks without time spent FormForNewLeadDesc=Thanks to fill the following form to contact us. You can also send us an email directly to %s. diff --git a/htdocs/langs/en_US/receptions.lang b/htdocs/langs/en_US/receptions.lang index 5b51f5ba071..7324f14f2e0 100644 --- a/htdocs/langs/en_US/receptions.lang +++ b/htdocs/langs/en_US/receptions.lang @@ -32,6 +32,7 @@ StatusReceptionDraftShort=Draft StatusReceptionValidatedShort=Validated StatusReceptionProcessedShort=Processed ReceptionSheet=Reception sheet +ValidateReception=Validate reception ConfirmDeleteReception=Are you sure you want to delete this reception? ConfirmValidateReception=Are you sure you want to validate this reception with reference %s? ConfirmCancelReception=Are you sure you want to cancel this reception? diff --git a/htdocs/langs/en_US/users.lang b/htdocs/langs/en_US/users.lang index 3f2c7f5f53a..757e9f1dedf 100644 --- a/htdocs/langs/en_US/users.lang +++ b/htdocs/langs/en_US/users.lang @@ -127,3 +127,5 @@ DateLastLogin=Date last login DatePreviousLogin=Date previous login IPLastLogin=IP last login IPPreviousLogin=IP previous login +ShowAllPerms=Show all permission rows +HideAllPerms=Hide all permission rows diff --git a/htdocs/langs/en_US/website.lang b/htdocs/langs/en_US/website.lang index 874cdc76f28..742e3afff67 100644 --- a/htdocs/langs/en_US/website.lang +++ b/htdocs/langs/en_US/website.lang @@ -153,3 +153,5 @@ PreviousContainer=Previous page/container WebsiteMustBeDisabled=The website must have the status "%s" WebpageMustBeDisabled=The web page must have the status "%s" SetWebsiteOnlineBefore=When website is offline, all pages are offline. Change status of website first. +Booking=Booking +Reservation=Reservation diff --git a/htdocs/langs/es_AR/ecm.lang b/htdocs/langs/es_AR/ecm.lang index a668d35a6b8..099dbdbaf6f 100644 --- a/htdocs/langs/es_AR/ecm.lang +++ b/htdocs/langs/es_AR/ecm.lang @@ -15,7 +15,6 @@ ECMNbOfSubDir=Cantidad de sub-carpetas ECMNbOfFilesInSubDir=Cantidad de archivos en sub-carpetas ECMArea=Area SAD/ACE ECMAreaDesc=El área de SAD/ACE (Sistema de Administración de Documentos / Administración de Contenido Electrónico) te permite guardar, compartir y rápidamente buscar todo tipo de documentos en Dolibarr. -ECMAreaDesc2=* Las carpetas automáticas son llenadas automáticamente al agregar documentos desde la ficha de un elemento.
* Las carpetas manuales pueden ser usadas para guardar documentos no enlazados a un elemento en particular. ECMSectionWasRemoved=Carpeta %s ha sido eliminada. ECMSectionWasCreated=Carpeta %s ha sido creada. ECMSearchByKeywords=Búsqueda por palabras clave diff --git a/htdocs/langs/es_CL/ecm.lang b/htdocs/langs/es_CL/ecm.lang index c8bda73008d..462663342bc 100644 --- a/htdocs/langs/es_CL/ecm.lang +++ b/htdocs/langs/es_CL/ecm.lang @@ -6,7 +6,6 @@ ECMNbOfSubDir=Cantidad de subdirectorios ECMNbOfFilesInSubDir=Número de archivos en subdirectorios ECMArea=Área de DMS / ECM ECMAreaDesc=El área DMS / ECM (Sistema de gestión de documentos / gestión de contenido electrónico) le permite guardar, compartir y buscar rápidamente todo tipo de documentos en Dolibarr. -ECMAreaDesc2=* Los directorios automáticos se rellenan automáticamente al agregar documentos desde la tarjeta de un elemento.
* Los directorios manuales se pueden usar para guardar documentos no vinculados a un elemento en particular. ECMSectionWasRemoved=El directorio %s ha sido borrado. ECMSectionWasCreated=El directorio %s ha sido creado. ECMNoDirectoryYet=Sin directorio creado diff --git a/htdocs/langs/es_CL/ticket.lang b/htdocs/langs/es_CL/ticket.lang index 5a4f2f39b72..3cec391874a 100644 --- a/htdocs/langs/es_CL/ticket.lang +++ b/htdocs/langs/es_CL/ticket.lang @@ -60,7 +60,6 @@ TicketAssigned=Ticket ahora está asignado TicketChangeCategory=Cambiar código analítico TicketChangeSeverity=Cambiar severidad TicketAddMessage=Añade un mensaje -AddMessage=Añade un mensaje MessageSuccessfullyAdded=Ticket agregado TicketMessageSuccessfullyAdded=Mensaje agregado con éxito TicketMessagesList=Lista de mensajes diff --git a/htdocs/langs/es_CO/admin.lang b/htdocs/langs/es_CO/admin.lang index af4d57d1984..4ca8b5f0aa3 100644 --- a/htdocs/langs/es_CO/admin.lang +++ b/htdocs/langs/es_CO/admin.lang @@ -1307,7 +1307,6 @@ ActivateFCKeditor=Activar editor avanzado para: FCKeditorForNotePublic=Creación / edición WYSIWIG del campo "notas públicas" de elementos FCKeditorForNotePrivate=Creación / edición WYSIWIG del campo "notas privadas" de elementos FCKeditorForCompany=Creación / edición WYSIWIG de la descripción de campo de elementos (excepto productos / servicios) -FCKeditorForProduct=Creación / edición WYSIWIG de la descripción de campo de productos / servicios FCKeditorForProductDetails=WYSIWIG creación / edición de líneas de detalle de productos para todas las entidades (propuestas, pedidos, facturas, etc ...). Advertencia: El uso de esta opción para este caso no se recomienda seriamente, ya que puede crear problemas con caracteres especiales y formato de página al crear archivos PDF. FCKeditorForMailing=Creación / edición WYSIWIG para eMailings masivos (Herramientas-> eMailing) FCKeditorForUserSignature=Creación / edición WYSIWIG de la firma del usuario. diff --git a/htdocs/langs/es_CO/ecm.lang b/htdocs/langs/es_CO/ecm.lang index 8e5fb615fc0..27f9ce5dd7b 100644 --- a/htdocs/langs/es_CO/ecm.lang +++ b/htdocs/langs/es_CO/ecm.lang @@ -6,7 +6,6 @@ ECMCreationDate=Fecha de creación ECMNbOfFilesInSubDir=Número de archivos en subdirectorios ECMArea=Área DMS / ECM ECMAreaDesc=El área DMS / ECM (Document Management System / Electronic Content Management) permite guardar, compartir y buscar rápidamente todo tipo de documentos en Dolibarr. -ECMAreaDesc2=* Los directorios automáticos se llenan automáticamente al agregar documentos desde la tarjeta de un elemento.
* Los directorios manuales se pueden usar para guardar documentos que no están vinculados a un elemento en particular. ECMSectionWasRemoved=El directorio %s ha sido eliminado. ECMSectionWasCreated=Se ha creado el directorio %s . ECMNoDirectoryYet=No se creó ningún directorio diff --git a/htdocs/langs/es_CO/ticket.lang b/htdocs/langs/es_CO/ticket.lang index 3f6313f135e..ea3d8b55ff9 100644 --- a/htdocs/langs/es_CO/ticket.lang +++ b/htdocs/langs/es_CO/ticket.lang @@ -77,7 +77,6 @@ TicketChangeType=Tipo de cambio TicketChangeCategory=Cambiar el código analítico TicketChangeSeverity=Cambiar la gravedad TicketAddMessage=Añade un mensaje -AddMessage=Añade un mensaje MessageSuccessfullyAdded=Ticket agregado TicketMessageSuccessfullyAdded=Mensaje agregado exitosamente TicketMessagesList=Lista de mensajes diff --git a/htdocs/langs/es_CO/workflow.lang b/htdocs/langs/es_CO/workflow.lang index 326b17aadd9..aee62bbc20c 100644 --- a/htdocs/langs/es_CO/workflow.lang +++ b/htdocs/langs/es_CO/workflow.lang @@ -14,5 +14,4 @@ descWORKFLOW_ORDER_CLASSIFY_SHIPPED_SHIPPING=Clasifique el pedido de ventas de o descWORKFLOW_ORDER_CLASSIFY_SHIPPED_SHIPPING_CLOSED=Clasifique el pedido de venta de origen vinculado como enviado cuando se cierra un envío (y si la cantidad enviada por todos los envíos es la misma que en el pedido para actualizar) descWORKFLOW_ORDER_CLASSIFY_BILLED_SUPPLIER_PROPOSAL=Clasifique la propuesta del proveedor de origen vinculado como facturada cuando se valida la factura del proveedor (y si el monto de la factura es el mismo que el monto total de la propuesta vinculada) descWORKFLOW_INVOICE_AMOUNT_CLASSIFY_BILLED_SUPPLIER_ORDER=Clasifique el pedido de compra de origen vinculado como facturado cuando se valida la factura del proveedor (y si el monto de la factura es el mismo que el monto total del pedido vinculado) -descWORKFLOW_BILL_ON_RECEPTION=Clasifique las recepciones como "facturadas" cuando un pedido de proveedor vinculado is validado descWORKFLOW_SHIPPING_CLASSIFY_CLOSED_INVOICE=Clasifique el envío de origen vinculado como cerrado cuando se valida la factura del cliente diff --git a/htdocs/langs/es_EC/ecm.lang b/htdocs/langs/es_EC/ecm.lang index 7f8d9157910..0fea60981c8 100644 --- a/htdocs/langs/es_EC/ecm.lang +++ b/htdocs/langs/es_EC/ecm.lang @@ -5,7 +5,6 @@ ECMCreationDate=Fecha de creación ECMNbOfFilesInSubDir=Número de archivos en subdirectorios ECMArea=Área de DMS/ECM ECMAreaDesc=El área SGD/GCE (Sistema de Gestión de Documentos / Gestión de Contenido Electrónico) le permite guardar, compartir y buscar rápidamente todo tipo de documentos en Dolibarr. -ECMAreaDesc2=* Los directorios automáticos se rellenan automáticamente al agregar documentos desde la tarjeta de un elemento.
* Los directorios manuales se pueden utilizar para guardar documentos no vinculados a un elemento en particular. ECMSectionWasRemoved=Se ha eliminado el directorio %s. ECMSectionWasCreated=Directorio %s ha sido creado. ECMSearchByKeywords=Búsqueda por palabras clave diff --git a/htdocs/langs/es_EC/ticket.lang b/htdocs/langs/es_EC/ticket.lang index 29b388752e1..1580632c9ad 100644 --- a/htdocs/langs/es_EC/ticket.lang +++ b/htdocs/langs/es_EC/ticket.lang @@ -53,7 +53,6 @@ TicketAssigned=Ticket ahora está asignado TicketChangeCategory=Cambiar código analítico TicketChangeSeverity=Cambiar severidad TicketAddMessage=Añade un mensaje -AddMessage=Añade un mensaje MessageSuccessfullyAdded=Ticket agregado TicketMessageSuccessfullyAdded=Mensaje agregado con éxito TicketMessagesList=Lista de mensajes diff --git a/htdocs/langs/es_US/admin.lang b/htdocs/langs/es_US/admin.lang index f59ee2569c5..c5ab56cb8d8 100644 --- a/htdocs/langs/es_US/admin.lang +++ b/htdocs/langs/es_US/admin.lang @@ -3,4 +3,3 @@ OperationParamDesc=Define the rules to use to extract or set values.
Example EmailCollectorLoadThirdPartyHelp=You can use this action to use the email content to find and load an existing thirdparty in your database. The found (or created) thirdparty will be used for following actions that need it.
For example, if you want to create a thirdparty with a name extracted from a string 'Name: name to find' present into the body, use the sender email as email, you can set the parameter field like this:
'email=HEADER:^From:(.*);name=EXTRACT:BODY:Name:\\s([^\\s]*);client=SET:2;'
IfYouUseASecondTaxYouMustSetYouUseTheMainTax=If you want to use a second tax, you must enable also the first sale tax IfYouUseAThirdTaxYouMustSetYouUseTheMainTax=If you want to use a third tax, you must enable also the first sale tax -AllowExternalDownload=Allow external download diff --git a/htdocs/langs/fr_CA/ecm.lang b/htdocs/langs/fr_CA/ecm.lang index d660995b9f5..c6a678b714f 100644 --- a/htdocs/langs/fr_CA/ecm.lang +++ b/htdocs/langs/fr_CA/ecm.lang @@ -5,7 +5,6 @@ ECMSectionsManual=Arbre manuel ECMSectionsAuto=Arbre automatique ECMAddSection=Ajouter un répertoire ECMCreationDate=Date création -ECMAreaDesc2=* Les répertoires automatiques sont remplis automatiquement lors de l'ajout de documents à partir d'une carte d'un élément.
* Les répertoires manuels peuvent être utilisés pour enregistrer des documents non liés à un élément particulier. ECMSectionWasRemoved=Le répertoire %s a été supprimé. ECMSectionOfDocuments=Répertoires de documents ShowECMSection=Afficher le répertoire diff --git a/htdocs/langs/fr_FR/admin.lang b/htdocs/langs/fr_FR/admin.lang index 69f077d628f..79a266df816 100644 --- a/htdocs/langs/fr_FR/admin.lang +++ b/htdocs/langs/fr_FR/admin.lang @@ -2189,6 +2189,7 @@ ShowProjectLabel=Libellé du projet PDF_INCLUDE_ALIAS_IN_THIRDPARTY_NAME=Inclure un alias dans le nom du tiers THIRDPARTY_ALIAS=Nom du tiers - Alias du tiers ALIAS_THIRDPARTY=Alias du tiers - Nom du tiers +MAIN_USE_COMPANY_NAME_OF_CONTACT=Use company name of contact PDF_USE_ALSO_LANGUAGE_CODE=Si vous souhaitez que certains textes de votre PDF soient dupliqués dans 2 langues différentes dans le même PDF généré, vous devez définir ici cette deuxième langue pour que le PDF généré contienne 2 langues différentes dans la même page, celle choisie lors de la génération du PDF et celle-ci (seuls quelques modèles PDF prennent en charge cette fonction). Gardez vide pour 1 langue par PDF. PDF_USE_A=Générer document PDF avec le format PDF/A à la place du format PDF standard FafaIconSocialNetworksDesc=Entrez ici le code d'une icône FontAwesome. Si vous ne savez pas ce qu'est FontAwesome, vous pouvez utiliser la valeur générique fa-address-book. @@ -2314,7 +2315,7 @@ UseOauth=Utiliser un token OAUTH Images=Images Posts=publications MaxNumberOfImagesInGetPost=Nombre maximum d'images autorisées dans un champ HTML soumis dans un formulaire -MaxNumberOfPostOnPublicPagesByIP=Nombre maximum de publications sur des pages publiques avec une adresse IP +MaxNumberOfPostOnPublicPagesByIP=Nombre maximum de publications par mois sur des pages publiques avec une adresse IP CIDLookupURL=Le module apporte une URL qui peut être utilisée par un outil externe pour obtenir le nom d'un tiers ou d'un contact à partir de son numéro de téléphone. L'URL à utiliser est : ScriptIsEmpty=Le script est manquant ShowHideTheNRequests=Afficher/Cacher les %s requête(s) SQL. diff --git a/htdocs/langs/fr_FR/main.lang b/htdocs/langs/fr_FR/main.lang index eb787cb279d..211c841ee4e 100644 --- a/htdocs/langs/fr_FR/main.lang +++ b/htdocs/langs/fr_FR/main.lang @@ -45,6 +45,7 @@ NoError=Aucune erreur Error=Erreur Errors=Erreurs ErrorFieldRequired=Le champ '%s' est obligatoire +AlreadyTooMuchPostOnThisIPAdress=Vous avez déjà posté trop de messages depuis cette adresse IP. ErrorFieldFormat=Le champ '%s' a une valeur incorrecte ErrorFileDoesNotExists=Le fichier %s n'existe pas ErrorFailedToOpenFile=Impossible d'ouvrir le fichier %s @@ -1206,3 +1207,4 @@ CreatedByPublicPortal=Créé à partir du portail public UserAgent=User Agent InternalUser=Utilisateur interne ExternalUser=Utilisateur externe +WarningUserDifferentContactSocid=Contact non relié à un tiers. Le tiers ne sera pas enregistré. diff --git a/htdocs/langs/nl_BE/ticket.lang b/htdocs/langs/nl_BE/ticket.lang index 30a0241a7d4..3d1419278be 100644 --- a/htdocs/langs/nl_BE/ticket.lang +++ b/htdocs/langs/nl_BE/ticket.lang @@ -57,7 +57,6 @@ MarkAsRead=Markeer ticket als gelezen TicketHistory=Ticket geschiedenis TicketChangeType=Van type veranderen TicketAddMessage=Voeg een bericht toe -AddMessage=Voeg een bericht toe TicketMessageSuccessfullyAdded=Bericht is succesvol toegevoegd NoMsgForThisTicket=Geen bericht voor dit ticket TicketSeverity=Strengheid diff --git a/htdocs/langs/pt_BR/admin.lang b/htdocs/langs/pt_BR/admin.lang index 80684c463d4..837113cb418 100644 --- a/htdocs/langs/pt_BR/admin.lang +++ b/htdocs/langs/pt_BR/admin.lang @@ -1333,7 +1333,6 @@ ActivateFCKeditor=Editor avançado ativo por: FCKeditorForNotePublic=Usar editor WYSIWIG nos campos de "notas públicas" dos elementos FCKeditorForNotePrivate=Usar editor WYSIWIG nos campos de "notas privadas" dos elementos FCKeditorForCompany=Usar editor WYSIWIG nos campos de descrição dos elementos (exceto produtos/serviços) -FCKeditorForProduct=Usar editor WYSIWIG nos campos de descrição de produtos/serviços FCKeditorForProductDetails=Criação / edição WYSIWIG de linhas de detalhes de produtos para todas as entidades (propostas, encomendas, facturas, etc ...). Aviso: O uso desta opção neste caso não é recomendado, pois pode criar problemas com caracteres especiais e formatação de página ao construir arquivos PDF. FCKeditorForMailing=Criação/edição do WYSIWIG nos E-Mails massivos (ferramentas->emailing) FCKeditorForUserSignature=criação/edição do WYSIWIG nas assinaturas de usuários diff --git a/htdocs/langs/pt_BR/ecm.lang b/htdocs/langs/pt_BR/ecm.lang index 3c7bb7eddf3..1b5ed3fa5cb 100644 --- a/htdocs/langs/pt_BR/ecm.lang +++ b/htdocs/langs/pt_BR/ecm.lang @@ -12,7 +12,6 @@ ECMNbOfFilesInSubDir=Numero de arquivos nos subpastas ECMCreationUser=Criado por ECMArea=Área DMS / ECM ECMAreaDesc=A área DMS / ECM (Gerenciamento de documentos / Gerenciamento de conteúdo eletrônico) permite salvar, compartilhar e pesquisar rapidamente todos os tipos de documentos no Dolibarr. -ECMAreaDesc2=* As pastas automáticas são geradas automaticamente quando algum arquivo é adicionado a algum ficheiro do sistema.
* As pastas manuais podem ser usados ​​para guardar documentos sem ligação a um cadastro do sistema. ECMSectionWasRemoved=A pasta %s foi eliminada ECMSearchByKeywords=Busca usando palavras chave ECMSearchByEntity=Busca por objeto diff --git a/htdocs/langs/pt_BR/ticket.lang b/htdocs/langs/pt_BR/ticket.lang index df070b1eced..09f8001f5b1 100644 --- a/htdocs/langs/pt_BR/ticket.lang +++ b/htdocs/langs/pt_BR/ticket.lang @@ -76,7 +76,6 @@ TicketHistory=Histórico de bilhetes TicketChangeCategory=Modifica o código analítico TicketChangeSeverity=Alterar gravidade TicketAddMessage=Adiciona uma mensagem -AddMessage=Adiciona uma mensagem MessageSuccessfullyAdded=Bilhete adicionado NoMsgForThisTicket=Nenhuma mensagem para este bilhete TicketProperties=Classificação diff --git a/htdocs/langs/pt_MZ/admin.lang b/htdocs/langs/pt_MZ/admin.lang index f499ad97ebf..961304d0627 100644 --- a/htdocs/langs/pt_MZ/admin.lang +++ b/htdocs/langs/pt_MZ/admin.lang @@ -1329,7 +1329,6 @@ ActivateFCKeditor=Editor avançado ativo por: FCKeditorForNotePublic=Usar editor WYSIWIG nos campos de "notas públicas" dos elementos FCKeditorForNotePrivate=Usar editor WYSIWIG nos campos de "notas privadas" dos elementos FCKeditorForCompany=Usar editor WYSIWIG nos campos de descrição dos elementos (exceto produtos/serviços) -FCKeditorForProduct=Usar editor WYSIWIG nos campos de descrição de produtos/serviços FCKeditorForProductDetails=Criação / edição WYSIWIG de linhas de detalhes de produtos para todas as entidades (propostas, encomendas, facturas, etc ...). Aviso: O uso desta opção neste caso não é recomendado, pois pode criar problemas com caracteres especiais e formatação de página ao construir arquivos PDF. FCKeditorForMailing=Criação/edição do WYSIWIG nos E-Mails massivos (ferramentas->emailing) FCKeditorForUserSignature=criação/edição do WYSIWIG nas assinaturas de usuários diff --git a/htdocs/langs/pt_MZ/ecm.lang b/htdocs/langs/pt_MZ/ecm.lang index 3c7bb7eddf3..1b5ed3fa5cb 100644 --- a/htdocs/langs/pt_MZ/ecm.lang +++ b/htdocs/langs/pt_MZ/ecm.lang @@ -12,7 +12,6 @@ ECMNbOfFilesInSubDir=Numero de arquivos nos subpastas ECMCreationUser=Criado por ECMArea=Área DMS / ECM ECMAreaDesc=A área DMS / ECM (Gerenciamento de documentos / Gerenciamento de conteúdo eletrônico) permite salvar, compartilhar e pesquisar rapidamente todos os tipos de documentos no Dolibarr. -ECMAreaDesc2=* As pastas automáticas são geradas automaticamente quando algum arquivo é adicionado a algum ficheiro do sistema.
* As pastas manuais podem ser usados ​​para guardar documentos sem ligação a um cadastro do sistema. ECMSectionWasRemoved=A pasta %s foi eliminada ECMSearchByKeywords=Busca usando palavras chave ECMSearchByEntity=Busca por objeto diff --git a/htdocs/loan/class/loan.class.php b/htdocs/loan/class/loan.class.php index 81a00904794..1c6913035e8 100644 --- a/htdocs/loan/class/loan.class.php +++ b/htdocs/loan/class/loan.class.php @@ -104,6 +104,10 @@ class Loan extends CommonObject */ public $fk_project; + /** + * @var int totalpaid + */ + public $totalpaid; const STATUS_UNPAID = 0; const STATUS_PAID = 1; diff --git a/htdocs/loan/info.php b/htdocs/loan/info.php index 49618d0f46c..188a61c61e6 100644 --- a/htdocs/loan/info.php +++ b/htdocs/loan/info.php @@ -102,8 +102,6 @@ $morehtmlref .= ''; $linkback = ''.$langs->trans("BackToList").''; -$object->totalpaid = $totalpaid; // To give a chance to dol_banner_tab to use already paid amount to show correct status - dol_banner_tab($object, 'id', $linkback, 1, 'rowid', 'ref', $morehtmlref, '', 0, '', $morehtmlright); print '
'; diff --git a/htdocs/loan/list.php b/htdocs/loan/list.php index 146c0521a61..1324876a98c 100644 --- a/htdocs/loan/list.php +++ b/htdocs/loan/list.php @@ -107,8 +107,13 @@ $title = $langs->trans('Loans'); $sql = "SELECT l.rowid, l.label, l.capital, l.datestart, l.dateend, l.paid,"; $sql .= " SUM(pl.amount_capital) as alreadypaid"; -$sql .= " FROM ".MAIN_DB_PREFIX."loan as l LEFT JOIN ".MAIN_DB_PREFIX."payment_loan AS pl"; -$sql .= " ON l.rowid = pl.fk_loan"; + +$sqlfields = $sql; // $sql fields to remove for count total + +$sql .= " FROM ".MAIN_DB_PREFIX."loan as l"; +$linktopl = " LEFT JOIN ".MAIN_DB_PREFIX."payment_loan AS pl ON l.rowid = pl.fk_loan"; +$sql .= $linktopl; + $sql .= " WHERE l.entity = ".$conf->entity; if ($search_amount) { $sql .= natural_search("l.capital", $search_amount, 1); @@ -120,36 +125,43 @@ if ($search_label) { $sql .= natural_search("l.label", $search_label); } $sql .= " GROUP BY l.rowid, l.label, l.capital, l.paid, l.datestart, l.dateend"; -$sql .= $db->order($sortfield, $sortorder); // Count total nb of records $nbtotalofrecords = ''; if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { - $resql = $db->query($sql); - $nbtotalofrecords = $db->num_rows($resql); - if (($page * $limit) > $nbtotalofrecords) { // if total of record found is smaller than page * limit, goto and load page 0 + /* The fast and low memory method to get and count full list converts the sql into a sql count */ + $sqlforcount = preg_replace('/^'.preg_quote($sqlfields, '/').'/', 'SELECT COUNT(*) as nbtotalofrecords', $sql); + $sqlforcount = preg_replace('/'.preg_quote($linktopl, '/').'/', '', $sqlforcount); + $sqlforcount = preg_replace('/GROUP BY .*$/', '', $sqlforcount); + $resql = $db->query($sqlforcount); + if ($resql) { + $objforcount = $db->fetch_object($resql); + $nbtotalofrecords = $objforcount->nbtotalofrecords; + } else { + dol_print_error($db); + } + + if (($page * $limit) > $nbtotalofrecords) { // if total resultset is smaller then paging size (filtering), goto and load page 0 $page = 0; $offset = 0; } + $db->free($resql); } -// if total of record found is smaller than limit, no need to do paging and to restart another select with limits set. -if (is_numeric($nbtotalofrecords) && ($limit > $nbtotalofrecords || empty($limit))) { - $num = $nbtotalofrecords; -} else { - if ($limit) { - $sql .= $db->plimit($limit + 1, $offset); - } - - $resql = $db->query($sql); - if (!$resql) { - dol_print_error($db); - exit; - } - - $num = $db->num_rows($resql); +// Complete request and execute it with limit +$sql .= $db->order($sortfield, $sortorder); +if ($limit) { + $sql .= $db->plimit($limit + 1, $offset); } +$resql = $db->query($sql); +if (!$resql) { + dol_print_error($db); + exit; +} + +$num = $db->num_rows($resql); + // Output page // -------------------------------------------------------------------- diff --git a/htdocs/main.inc.php b/htdocs/main.inc.php index 32d442008eb..eed0450e49f 100644 --- a/htdocs/main.inc.php +++ b/htdocs/main.inc.php @@ -80,7 +80,7 @@ function realCharForNumericEntities($matches) * Warning: Such a protection can't be enough. It is not reliable as it will always be possible to bypass this. Good protection can * only be guaranted by escaping data during output. * - * @param string $val Brut value found into $_GET, $_POST or PHP_SELF + * @param string $val Brute value found into $_GET, $_POST or PHP_SELF * @param string $type 0=POST, 1=GET, 2=PHP_SELF, 3=GET without sql reserved keywords (the less tolerant test) * @return int >0 if there is an injection, 0 if none */ @@ -89,18 +89,22 @@ function testSqlAndScriptInject($val, $type) // Decode string first because a lot of things are obfuscated by encoding or multiple encoding. // So error=alert(1) $val = preg_replace('//', '', $val); - $val = preg_replace('/[\r\n]/', '', $val); + $val = preg_replace('/[\r\n\t]/', '', $val); } while ($oldval != $val); //print "type = ".$type." after decoding: ".$val."\n"; @@ -123,11 +127,12 @@ function testSqlAndScriptInject($val, $type) // For SQL Injection (only GET are used to scan for such injection strings) if ($type == 1 || $type == 3) { - $inj += preg_match('/delete\s+from/i', $val); - $inj += preg_match('/create\s+table/i', $val); - $inj += preg_match('/insert\s+into/i', $val); - $inj += preg_match('/select\s+from/i', $val); - $inj += preg_match('/into\s+(outfile|dumpfile)/i', $val); + // Note the \s+ is replaced into \s* because some spaces may have been modified in previous loop + $inj += preg_match('/delete\s*from/i', $val); + $inj += preg_match('/create\s*table/i', $val); + $inj += preg_match('/insert\s*into/i', $val); + $inj += preg_match('/select\s*from/i', $val); + $inj += preg_match('/into\s*(outfile|dumpfile)/i', $val); $inj += preg_match('/user\s*\(/i', $val); // avoid to use function user() or mysql_user() that return current database login $inj += preg_match('/information_schema/i', $val); // avoid to use request that read information_schema database $inj += preg_match('/ (isModEnabled("fournisseur") && empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->hasRight("fournisseur", "facture", "write")) || (isModEnabled("supplier_invoice") && $user->hasRight("supplier_invoice", "write")), // vs hooking "position" => 90, ), + array( + "url" => "/ticket/card.php?action=create&mainmenu=ticket", + "title" => "NewTicket@ticket", + "name" => "Ticket@ticket", + "picto" => "ticket", + "activation" => isModEnabled('ticket') && $user->hasRight("ticket", "write"), // vs hooking + "position" => 100, + ), + array( + "url" => "/fichinter/card.php?action=create&mainmenu=commercial", + "title" => "NewIntervention@interventions", + "name" => "Intervention@interventions", + "picto" => "intervention", + "activation" => isModEnabled('ficheinter') && $user->hasRight("ficheinter", "creer"), // vs hooking + "position" => 110, + ), array( "url" => "/product/card.php?action=create&type=0&mainmenu=products", "title" => "NewProduct@products", "name" => "Product@products", "picto" => "object_product", "activation" => isModEnabled("product") && $user->hasRight("produit", "write"), // vs hooking - "position" => 100, + "position" => 400, ), array( "url" => "/product/card.php?action=create&type=1&mainmenu=products", @@ -2543,7 +2569,7 @@ function printDropdownQuickadd() "name" => "Service@products", "picto" => "object_service", "activation" => isModEnabled("service") && $user->hasRight("service", "write"), // vs hooking - "position" => 110, + "position" => 410, ), array( "url" => "/user/card.php?action=create&type=1&mainmenu=home", diff --git a/htdocs/master.inc.php b/htdocs/master.inc.php index 79f6f578e5f..03515c9a2e2 100644 --- a/htdocs/master.inc.php +++ b/htdocs/master.inc.php @@ -58,10 +58,10 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/conf.class.php'; $conf = new Conf(); // Set properties specific to database -$conf->db->host = $dolibarr_main_db_host; -$conf->db->port = $dolibarr_main_db_port; -$conf->db->name = $dolibarr_main_db_name; -$conf->db->user = $dolibarr_main_db_user; +$conf->db->host = empty($dolibarr_main_db_host) ? '' : $dolibarr_main_db_host; +$conf->db->port = empty($dolibarr_main_db_port) ? '' : $dolibarr_main_db_port; +$conf->db->name = empty($dolibarr_main_db_name) ? '' : $dolibarr_main_db_name; +$conf->db->user = empty($dolibarr_main_db_user) ? '' : $dolibarr_main_db_user; $conf->db->pass = empty($dolibarr_main_db_pass) ? '' : $dolibarr_main_db_pass; $conf->db->type = $dolibarr_main_db_type; $conf->db->prefix = $dolibarr_main_db_prefix; diff --git a/htdocs/modulebuilder/index.php b/htdocs/modulebuilder/index.php index 29959822af1..8b87d84c10e 100644 --- a/htdocs/modulebuilder/index.php +++ b/htdocs/modulebuilder/index.php @@ -1643,6 +1643,34 @@ if ($dirins && $action == 'confirm_deletemodule') { // Dir for module $dir = $dirins.'/'.$modulelowercase; + $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath']; + + // Dir for module + $dir = dol_buildpath($modulelowercase, 0); + + // Zip file to build + $FILENAMEZIP = ''; + + // Load module + 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()); + } + } else { + $error++; + $langs->load("errors"); + dol_print_error($db, $langs->trans("ErrorFailedToLoadModuleDescriptorForXXX", $module)); + exit; + } + + $moduleobj->remove(); + $result = dol_delete_dir_recursive($dir); if ($result > 0) { @@ -1974,6 +2002,28 @@ if ($message) { $infomodulesfound = '
'.$form->textwithpicto('', $langs->trans("ModuleBuilderDesc3", count($listofmodules)).'

'.$langs->trans("ModuleBuilderDesc4", $FILEFLAG).'
'.$textforlistofdirs).'
'; + +$dolibarrdataroot = preg_replace('/([\\/]+)$/i', '', DOL_DATA_ROOT); +$allowonlineinstall = true; +if (dol_is_file($dolibarrdataroot.'/installmodules.lock')) { + $allowonlineinstall = false; +} +if (empty($allowonlineinstall)) { + if (getDolGlobalString('MAIN_MESSAGE_INSTALL_MODULES_DISABLED_CONTACT_US')) { + // Show clean message + $message = info_admin($langs->trans('InstallModuleFromWebHasBeenDisabledContactUs')); + } else { + // Show technical message + $message = info_admin($langs->trans("InstallModuleFromWebHasBeenDisabledByFile", $dolibarrdataroot.'/installmodules.lock'), 0, 0, 1, 'warning'); + } + + print $message; + + llxFooter(); + exit(0); +} + + // Load module descriptor $error = 0; $moduleobj = null; @@ -3062,7 +3112,7 @@ if ($module == 'initmodule') { $proplabel = $propval['label']; $proptype = $propval['type']; $proparrayofkeyval = !empty($propval['arrayofkeyval'])?$propval['arrayofkeyval']:''; - $propnotnull = $propval['notnull']; + $propnotnull = !empty($propval['notnull']) ? $propval['notnull'] : '0'; $propdefault = !empty($propval['default'])?$propval['default']:''; $propindex = !empty($propval['index'])?$propval['index']:''; $propforeignkey = !empty($propval['foreignkey'])?$propval['foreignkey']:''; diff --git a/htdocs/modulebuilder/template/class/api_mymodule.class.php b/htdocs/modulebuilder/template/class/api_mymodule.class.php index 736fd9ddc38..ce92ef5ea8e 100644 --- a/htdocs/modulebuilder/template/class/api_mymodule.class.php +++ b/htdocs/modulebuilder/template/class/api_mymodule.class.php @@ -293,7 +293,9 @@ class MyModuleApi extends DolibarrApi throw new RestException(401, 'Access to instance id='.$this->myobject->id.' of object not allowed for login '.DolibarrApiAccess::$user->login); } - if (!$this->myobject->delete(DolibarrApiAccess::$user)) { + if ($this->myobject->delete(DolibarrApiAccess::$user) == 0) { + throw new RestException(409, 'Error when deleting MyObject : '.$this->myobject->error); + } elseif ($this->myobject->delete(DolibarrApiAccess::$user) < 0) { throw new RestException(500, 'Error when deleting MyObject : '.$this->myobject->error); } diff --git a/htdocs/modulebuilder/template/class/myobject.class.php b/htdocs/modulebuilder/template/class/myobject.class.php index 97c4e9ba646..2fe7d983513 100644 --- a/htdocs/modulebuilder/template/class/myobject.class.php +++ b/htdocs/modulebuilder/template/class/myobject.class.php @@ -110,7 +110,7 @@ class MyObject extends CommonObject // BEGIN MODULEBUILDER PROPERTIES /** - * @var array Array with all fields and their property. Do not use it as a static var. It may be modified by constructor. + * @var array Array with all fields into database and their property. Do not use it as a static var. It may be modified by constructor. */ public $fields = array( 'rowid' => array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>1, 'visible'=>-2, 'noteditable'=>1, 'notnull'=> 1, 'index'=>1, 'position'=>1, 'comment'=>'Id', 'css'=>'left'), @@ -736,7 +736,7 @@ class MyObject extends CommonObject public function reopen($user, $notrigger = 0) { // Protection - if ($this->status != self::STATUS_CANCELED) { + if ($this->status == self::STATUS_VALIDATED) { return 0; } @@ -865,6 +865,36 @@ class MyObject extends CommonObject return $result; } + /** + * Return a thumb for kanban views + * + * @param string $option Where point the link (0=> main card, 1,2 => shipment, 'nolink'=>No link) + * @return string HTML Code for Kanban thumb. + */ + /* + public function getKanbanView($option = '') + { + $return = '
'; + $return .= '
'; + $return .= ''; + $return .= img_picto('', $this->picto); + $return .= ''; + $return .= '
'; + $return .= ''.(method_exists($this, 'getNomUrl') ? $this->getNomUrl() : $this->ref).''; + if (property_exists($this, 'label')) { + $return .= '
'.$this->label.''; + } + if (method_exists($this, 'getLibStatut')) { + $return .= '
'.$this->getLibStatut(5).'
'; + } + $return .= '
'; + $return .= '
'; + $return .= '
'; + + return $return; + } + */ + /** * Return the label of the status * diff --git a/htdocs/modulebuilder/template/core/modules/mailings/mailinglist_mymodule_myobject.modules.php b/htdocs/modulebuilder/template/core/modules/mailings/mailinglist_mymodule_myobject.modules.php index 280f62dc2c1..7b2c4e2ab5a 100644 --- a/htdocs/modulebuilder/template/core/modules/mailings/mailinglist_mymodule_myobject.modules.php +++ b/htdocs/modulebuilder/template/core/modules/mailings/mailinglist_mymodule_myobject.modules.php @@ -24,7 +24,7 @@ class mailing_mailinglist_mymodule_myobject extends MailingTargets // CHANGE THIS: Set to 1 if selector is available for admin users only public $require_admin = 0; - public $enabled = '$conf->mymodule->enabled'; + public $enabled = 'isModEnabled("mymodule")'; public $require_module = array(); diff --git a/htdocs/modulebuilder/template/core/modules/mymodule/doc/doc_generic_myobject_odt.modules.php b/htdocs/modulebuilder/template/core/modules/mymodule/doc/doc_generic_myobject_odt.modules.php index 46967d6e4fa..b7dfc374a52 100644 --- a/htdocs/modulebuilder/template/core/modules/mymodule/doc/doc_generic_myobject_odt.modules.php +++ b/htdocs/modulebuilder/template/core/modules/mymodule/doc/doc_generic_myobject_odt.modules.php @@ -119,7 +119,7 @@ class doc_generic_myobject_odt extends ModelePDFMyObject $form = new Form($this->db); $texte = $this->description.".
\n"; - $texte .= '
'; + $texte .= ''; $texte .= ''; $texte .= ''; $texte .= ''; @@ -158,7 +158,7 @@ class doc_generic_myobject_odt extends ModelePDFMyObject $texte .= $conf->global->MYMODULE_MYOBJECT_ADDON_PDF_ODT_PATH; $texte .= ''; $texte .= '
'; - $texte .= ''; + $texte .= ''; $texte .= '
'; // Scan directories @@ -172,18 +172,16 @@ class doc_generic_myobject_odt extends ModelePDFMyObject } if ($nbofiles) { - $texte .= '
'; @@ -282,8 +281,10 @@ class doc_generic_myobject_odt extends ModelePDFMyObject $newfiletmp = preg_replace('/\.od(t|s)/i', '', $newfile); $newfiletmp = preg_replace('/template_/i', '', $newfiletmp); $newfiletmp = preg_replace('/modele_/i', '', $newfiletmp); + $newfiletmp = $objectref . '_' . $newfiletmp; //$file=$dir.'/'.$newfiletmp.'.'.dol_print_date(dol_now(),'%Y%m%d%H%M%S').'.odt'; + // Get extension (ods or odt) $newfileformat = substr($newfile, strrpos($newfile, '.') + 1); if (!empty($conf->global->MAIN_DOC_USE_TIMING)) { @@ -308,7 +309,7 @@ class doc_generic_myobject_odt extends ModelePDFMyObject return -1; } - // If CUSTOMER contact defined on order, we use it + // If CUSTOMER contact defined on object, we use it $usecontact = false; $arrayidcontact = $object->getIdContact('external', 'CUSTOMER'); if (count($arrayidcontact) > 0) { @@ -348,7 +349,7 @@ class doc_generic_myobject_odt extends ModelePDFMyObject // Line of free text $newfreetext = ''; - $paramfreetext = 'ORDER_FREE_TEXT'; + $paramfreetext = 'MYMODULE_MYOBJECT_FREE_TEXT'; if (!empty($conf->global->$paramfreetext)) { $newfreetext = make_substitutions($conf->global->$paramfreetext, $substitutionarray); } diff --git a/htdocs/modulebuilder/template/myobject_agenda.php b/htdocs/modulebuilder/template/myobject_agenda.php index 5b5860f6475..d7b84707b95 100644 --- a/htdocs/modulebuilder/template/myobject_agenda.php +++ b/htdocs/modulebuilder/template/myobject_agenda.php @@ -145,7 +145,7 @@ if ($enablepermissioncheck) { //if ($user->socid > 0) accessforbidden(); //if ($user->socid > 0) $socid = $user->socid; //$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); -//restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +//restrictedArea($user, $object->module, $object->id, $object->table_element, $object->element, 'fk_soc', 'rowid', $isdraft); if (!isModEnabled("mymodule")) { accessforbidden(); } diff --git a/htdocs/modulebuilder/template/myobject_card.php b/htdocs/modulebuilder/template/myobject_card.php index 95f10b5b90c..4e80c81a4df 100644 --- a/htdocs/modulebuilder/template/myobject_card.php +++ b/htdocs/modulebuilder/template/myobject_card.php @@ -145,7 +145,7 @@ $upload_dir = $conf->mymodule->multidir_output[isset($object->entity) ? $object- //if ($user->socid > 0) accessforbidden(); //if ($user->socid > 0) $socid = $user->socid; //$isdraft = (isset($object->status) && ($object->status == $object::STATUS_DRAFT) ? 1 : 0); -//restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +//restrictedArea($user, $object->module, $object->id, $object->table_element, $object->element, 'fk_soc', 'rowid', $isdraft); if (!isModEnabled("mymodule")) { accessforbidden(); } diff --git a/htdocs/modulebuilder/template/myobject_contact.php b/htdocs/modulebuilder/template/myobject_contact.php index b0f7b5cfb30..9568201238c 100644 --- a/htdocs/modulebuilder/template/myobject_contact.php +++ b/htdocs/modulebuilder/template/myobject_contact.php @@ -93,7 +93,7 @@ if ($enablepermissioncheck) { //if ($user->socid > 0) accessforbidden(); //if ($user->socid > 0) $socid = $user->socid; //$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); -//restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +//restrictedArea($user, $object->module, $object->id, $object->table_element, $object->element, 'fk_soc', 'rowid', $isdraft); if (!isModEnabled("mymodule")) { accessforbidden(); } diff --git a/htdocs/modulebuilder/template/myobject_document.php b/htdocs/modulebuilder/template/myobject_document.php index 6aed7382b7d..ff1756e2b15 100644 --- a/htdocs/modulebuilder/template/myobject_document.php +++ b/htdocs/modulebuilder/template/myobject_document.php @@ -137,7 +137,7 @@ if ($enablepermissioncheck) { //if ($user->socid > 0) accessforbidden(); //if ($user->socid > 0) $socid = $user->socid; //$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); -//restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +//restrictedArea($user, $object->module, $object->id, $object->table_element, $object->element, 'fk_soc', 'rowid', $isdraft); if (!isModEnabled("mymodule")) { accessforbidden(); } diff --git a/htdocs/modulebuilder/template/myobject_list.php b/htdocs/modulebuilder/template/myobject_list.php index f26afd1a503..06ad9a298ec 100644 --- a/htdocs/modulebuilder/template/myobject_list.php +++ b/htdocs/modulebuilder/template/myobject_list.php @@ -196,7 +196,7 @@ if ($user->socid > 0) accessforbidden(); //if ($user->socid > 0) accessforbidden(); //$socid = 0; if ($user->socid > 0) $socid = $user->socid; //$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); -//restrictedArea($user, $object->element, 0, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +//restrictedArea($user, $object->module, 0, $object->table_element, $object->element, 'fk_soc', 'rowid', $isdraft); if (!isModEnabled("mymodule")) { accessforbidden('Module mymodule not enabled'); } @@ -282,6 +282,9 @@ $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters, $obje $sql .= preg_replace('/^,/', '', $hookmanager->resPrint); $sql = preg_replace('/,\s*$/', '', $sql); //$sql .= ", COUNT(rc.rowid) as anotherfield"; + +$sqlfields = $sql; // $sql fields to remove for count total + $sql .= " FROM ".MAIN_DB_PREFIX.$object->table_element." as t"; //$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."anothertable as rc ON rc.parent = t.rowid"; if (isset($extrafields->attributes[$object->table_element]['label']) && is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label'])) { @@ -364,21 +367,9 @@ $sql .= empty($hookmanager->resPrint) ? "" : " HAVING 1=1 ".$hookmanager->resPri // Count total nb of records $nbtotalofrecords = ''; if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { - /* This old and fast method to get and count full list returns all record so use a high amount of memory. - $resql = $db->query($sql); - $nbtotalofrecords = $db->num_rows($resql); - */ - /* The slow method does not consume memory on mysql (not tested on pgsql) */ - /*$resql = $db->query($sql, 0, 'auto', 1); - while ($db->fetch_object($resql)) { - if (empty($nbtotalofrecords)) { - $nbtotalofrecords = 1; // We can't make +1 because init value is '' - } else { - $nbtotalofrecords++; - } - }*/ /* The fast and low memory method to get and count full list converts the sql into a sql count */ - $sqlforcount = preg_replace('/^SELECT[a-zA-Z0-9\._\s\(\),=<>\:\-\']+\sFROM/Ui', 'SELECT COUNT(*) as nbtotalofrecords FROM', $sql); + $sqlforcount = preg_replace('/^'.preg_quote($sqlfields, '/').'/', 'SELECT COUNT(*) as nbtotalofrecords', $sql); + $sqlforcount = preg_replace('/GROUP BY .*$/', '', $sqlforcount); $resql = $db->query($sqlforcount); if ($resql) { $objforcount = $db->fetch_object($resql); @@ -387,7 +378,7 @@ if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { dol_print_error($db); } - if (($page * $limit) > $nbtotalofrecords) { // if total of record found is smaller than page * limit, goto and load page 0 + if (($page * $limit) > $nbtotalofrecords) { // if total resultset is smaller then paging size (filtering), goto and load page 0 $page = 0; $offset = 0; } diff --git a/htdocs/modulebuilder/template/myobject_note.php b/htdocs/modulebuilder/template/myobject_note.php index f7859cfb217..89e5e0ba76e 100644 --- a/htdocs/modulebuilder/template/myobject_note.php +++ b/htdocs/modulebuilder/template/myobject_note.php @@ -117,7 +117,7 @@ if ($enablepermissioncheck) { //if ($user->socid > 0) accessforbidden(); //if ($user->socid > 0) $socid = $user->socid; //$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); -//restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); +//restrictedArea($user, $object->module, $object->id, $object->table_element, $object->element, 'fk_soc', 'rowid', $isdraft); if (!isModEnabled("mymodule")) { accessforbidden(); } diff --git a/htdocs/mrp/mo_card.php b/htdocs/mrp/mo_card.php index 32571252ebf..aa3381c1242 100644 --- a/htdocs/mrp/mo_card.php +++ b/htdocs/mrp/mo_card.php @@ -731,7 +731,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea // Show links to link elements $linktoelem = $form->showLinkToObjectBlock($object, null, array('mo')); - $somethingshown = $form->showLinkedObjectBlock($object, $linktoelem, false, 'MOChild'); + $somethingshown = $form->showLinkedObjectBlock($object, $linktoelem, false); print '
'; diff --git a/htdocs/mrp/mo_list.php b/htdocs/mrp/mo_list.php index f7a6ed88571..723e4a76853 100644 --- a/htdocs/mrp/mo_list.php +++ b/htdocs/mrp/mo_list.php @@ -174,6 +174,9 @@ if (empty($reshook)) { if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // All tests are required to be compatible with all browsers foreach ($object->fields as $key => $val) { $search[$key] = ''; + if ($key == 'status') { + $search[$key] = -1; + } if (preg_match('/^(date|timestamp|datetime)/', $val['type'])) { $search[$key.'_dtstart'] = ''; $search[$key.'_dtend'] = ''; @@ -226,6 +229,9 @@ $parameters = array(); $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters, $object); // Note that $action and $object may have been modified by hook $sql .= preg_replace('/^,/', '', $hookmanager->resPrint); $sql = preg_replace('/,\s*$/', '', $sql); + +$sqlfields = $sql; // $sql fields to remove for count total + $sql .= " FROM ".MAIN_DB_PREFIX.$object->table_element." as t"; if (isset($extrafields->attributes[$object->table_element]['label']) && is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label'])) { $sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$object->table_element."_extrafields as ef on (t.rowid = ef.fk_object)"; @@ -247,7 +253,7 @@ foreach ($search as $key => $val) { if ($key == 'status' && $search[$key] == -1) { continue; } - if ($key == 'fk_parent_line') { + if ($key == 'fk_parent_line' && $search[$key] != '') { $sql .= natural_search('moparent.ref', $search[$key], 0); continue; } @@ -311,35 +317,41 @@ $sql.=$hookmanager->resPrint; $sql=preg_replace('/,\s*$/','', $sql); */ -$sql .= $db->order($sortfield, $sortorder); - // Count total nb of records $nbtotalofrecords = ''; if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { - $resql = $db->query($sql); - $nbtotalofrecords = $db->num_rows($resql); - if (($page * $limit) > $nbtotalofrecords) { // if total of record found is smaller than page * limit, goto and load page 0 + /* The fast and low memory method to get and count full list converts the sql into a sql count */ + $sqlforcount = preg_replace('/^'.preg_quote($sqlfields, '/').'/', 'SELECT COUNT(*) as nbtotalofrecords', $sql); + $sqlforcount = preg_replace('/GROUP BY .*$/', '', $sqlforcount); + $resql = $db->query($sqlforcount); + if ($resql) { + $objforcount = $db->fetch_object($resql); + $nbtotalofrecords = $objforcount->nbtotalofrecords; + } else { + dol_print_error($db); + } + + if (($page * $limit) > $nbtotalofrecords) { // if total resultset is smaller then paging size (filtering), goto and load page 0 $page = 0; $offset = 0; } + $db->free($resql); } -// if total of record found is smaller than limit, no need to do paging and to restart another select with limits set. -if (is_numeric($nbtotalofrecords) && ($limit > $nbtotalofrecords || empty($limit))) { - $num = $nbtotalofrecords; -} else { - if ($limit) { - $sql .= $db->plimit($limit + 1, $offset); - } - $resql = $db->query($sql); - if (!$resql) { - dol_print_error($db); - exit; - } - - $num = $db->num_rows($resql); +// Complete request and execute it with limit +$sql .= $db->order($sortfield, $sortorder); +if ($limit) { + $sql .= $db->plimit($limit + 1, $offset); } +$resql = $db->query($sql); +if (!$resql) { + dol_print_error($db); + exit; +} + +$num = $db->num_rows($resql); + // Direct jump if only one record found if ($num == 1 && !empty($conf->global->MAIN_SEARCH_DIRECT_OPEN_IF_ONLY_ONE) && $search_all && !$page) { $obj = $db->fetch_object($resql); @@ -450,7 +462,7 @@ if (!empty($moreforfilter)) { } $varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage; -$selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields +$selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage, getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN', '')); // This also change content of $arrayfields $selectedfields .= (count($arrayofmassactions) ? $form->showCheckAddButtons('checkforselect', 1) : ''); print '
'; // You can use div-table-responsive-no-min if you dont need reserved height for your table @@ -460,6 +472,13 @@ print ''; +// Action column +if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print ''; +} foreach ($object->fields as $key => $val) { $cssforfield = (empty($val['csslist']) ? (empty($val['css']) ? '' : $val['css']) : $val['csslist']); if ($key == 'status') { @@ -505,16 +524,22 @@ $parameters = array('arrayfields'=>$arrayfields); $reshook = $hookmanager->executeHooks('printFieldListOption', $parameters, $object); // Note that $action and $object may have been modified by hook print $hookmanager->resPrint; // Action column -print ''; +if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print ''; +} print ''."\n"; // Fields title label // -------------------------------------------------------------------- print ''; +// Action column +if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print getTitleFieldOfList($selectedfields, 0, $_SERVER["PHP_SELF"], '', '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ')."\n"; +} foreach ($object->fields as $key => $val) { $cssforfield = (empty($val['csslist']) ? (empty($val['css']) ? '' : $val['css']) : $val['csslist']); if ($key == 'status') { @@ -539,7 +564,9 @@ $parameters = array('arrayfields'=>$arrayfields, 'param'=>$param, 'sortfield'=>$ $reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters, $object); // Note that $action and $object may have been modified by hook print $hookmanager->resPrint; // Action column -print getTitleFieldOfList($selectedfields, 0, $_SERVER["PHP_SELF"], '', '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ')."\n"; +if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print getTitleFieldOfList($selectedfields, 0, $_SERVER["PHP_SELF"], '', '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ')."\n"; +} print ''."\n"; @@ -570,6 +597,18 @@ while ($i < ($limit ? min($num, $limit) : $num)) { // Show here line of result print ''; + // Action column + if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print ''; + } foreach ($object->fields as $key => $val) { $cssforfield = (empty($val['csslist']) ? (empty($val['css']) ? '' : $val['css']) : $val['csslist']); if (in_array($val['type'], array('date', 'datetime', 'timestamp'))) { @@ -627,15 +666,17 @@ while ($i < ($limit ? min($num, $limit) : $num)) { $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters, $object); // Note that $action and $object may have been modified by hook print $hookmanager->resPrint; // Action column - print ''; } - print ''; if (!$i) { $totalarray['nbfield']++; } diff --git a/htdocs/mrp/mo_production.php b/htdocs/mrp/mo_production.php index 64ae11909ef..7bff43bfc7b 100644 --- a/htdocs/mrp/mo_production.php +++ b/htdocs/mrp/mo_production.php @@ -220,7 +220,7 @@ if (empty($reshook)) { if ($qtytoprocess >= 0) { $idstockmove = $stockmove->livraison($user, $line->fk_product, GETPOST('idwarehouse-'.$line->id.'-'.$i), $qtytoprocess, 0, $labelmovement, dol_now(), '', '', GETPOST('batch-'.$line->id.'-'.$i), $id_product_batch, $codemovement); } else { - $idstockmove = $stockmove->reception($user, $line->fk_product, GETPOST('idwarehouse-'.$line->id.'-'.$i), $qtytoprocess, 0, $labelmovement, dol_now(), '', '', GETPOST('batch-'.$line->id.'-'.$i), $id_product_batch, $codemovement); + $idstockmove = $stockmove->reception($user, $line->fk_product, GETPOST('idwarehouse-'.$line->id.'-'.$i), $qtytoprocess * -1, 0, $labelmovement, dol_now(), '', '', GETPOST('batch-'.$line->id.'-'.$i), $id_product_batch, $codemovement); } if ($idstockmove < 0) { $error++; diff --git a/htdocs/mrp/tpl/linkedobjectblock.tpl.php b/htdocs/mrp/tpl/linkedobjectblock.tpl.php index 3b8c3f2ecaa..84ca487b771 100644 --- a/htdocs/mrp/tpl/linkedobjectblock.tpl.php +++ b/htdocs/mrp/tpl/linkedobjectblock.tpl.php @@ -39,48 +39,79 @@ $langs->load("bom"); $total = 0; $ilink = 0; -$mo_static = new Mo($db); -$res = $mo_static->fetch($object->id); -$TMoChilds = $mo_static->getMoChilds(); -$hookmanager->initHooks('LinesLinkedObjectBlock'); -$parameters = array('TMoChilds' => $TMoChilds); -$reshook = $hookmanager->executeHooks('LinesLinkedObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook -if (empty($reshook)) { - foreach ($TMoChilds as $key => $objectlink) { +if ($object->element == 'mo') { + $mo_static = new Mo($db); + $res = $mo_static->fetch($object->id); + $TMoChilds = $mo_static->getMoChilds(); + + $hookmanager->initHooks('LinesLinkedObjectBlock'); + $parameters = array('TMoChilds' => $TMoChilds); + $reshook = $hookmanager->executeHooks('LinesLinkedObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook + if (empty($reshook)) { + foreach ($TMoChilds as $key => $objectlink) { + $ilink++; + + $trclass = 'oddeven'; + + echo ''; + echo ''; + + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo "\n"; + } + } +} else { + $linkedObjectBlock = dol_sort_array($linkedObjectBlock, 'date', 'desc', 0, 0, 1); + + $total = 0; + $ilink = 0; + foreach ($linkedObjectBlock as $key => $objectlink) { $ilink++; $trclass = 'oddeven'; - - echo ''; - echo ''; + print ''; - echo ''; - - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo "\n"; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print "\n"; } } + echo "\n"; diff --git a/htdocs/opensurvey/card.php b/htdocs/opensurvey/card.php index b243b8c8342..36c5b2ea07d 100644 --- a/htdocs/opensurvey/card.php +++ b/htdocs/opensurvey/card.php @@ -209,7 +209,7 @@ $toutsujet = explode(",", $object->sujet); $listofanswers = array(); foreach ($toutsujet as $value) { $tmp = explode('@', $value); - $listofanswers[] = array('label'=>$tmp[0], 'format'=>($tmp[1] ? $tmp[1] : 'checkbox')); + $listofanswers[] = array('label'=>$tmp[0], 'format'=>(!empty($tmp[1]) ? $tmp[1] : 'checkbox')); } $toutsujet = str_replace("@", "
", $toutsujet); $toutsujet = str_replace("°", "'", $toutsujet); diff --git a/htdocs/opensurvey/class/opensurveysondage.class.php b/htdocs/opensurvey/class/opensurveysondage.class.php index cae73d0c2b2..2014e57f629 100644 --- a/htdocs/opensurvey/class/opensurveysondage.class.php +++ b/htdocs/opensurvey/class/opensurveysondage.class.php @@ -274,7 +274,7 @@ class Opensurveysondage extends CommonObject $this->sujet = $obj->sujet; $this->fk_user_creat = $obj->fk_user_creat; - $this->date_m = $this->db->jdate($obj->tls); + $this->date_m = $this->db->jdate(!empty($obj->tls) ? $obj->tls : ""); $ret = 1; } else { $sondage = ($id ? 'id='.$id : 'sondageid='.$numsurvey); @@ -571,12 +571,14 @@ class Opensurveysondage extends CommonObject * * @param string $comment Comment content * @param string $comment_user Comment author + * @param string $user_ip Comment author IP * @return boolean False in case of the query fails, true if it was successful */ - public function addComment($comment, $comment_user) + public function addComment($comment, $comment_user, $user_ip = '') { - $sql = "INSERT INTO ".MAIN_DB_PREFIX."opensurvey_comments (id_sondage, comment, usercomment)"; - $sql .= " VALUES ('".$this->db->escape($this->id_sondage)."','".$this->db->escape($comment)."','".$this->db->escape($comment_user)."')"; + $now = dol_now(); + $sql = "INSERT INTO ".MAIN_DB_PREFIX."opensurvey_comments (id_sondage, comment, usercomment, date_creation, ip)"; + $sql .= " VALUES ('".$this->db->escape($this->id_sondage)."','".$this->db->escape($comment)."','".$this->db->escape($comment_user)."','".$this->db->idate($now)."'".($user_ip ? ",'".$this->db->escape($user_ip)."'" : '').")"; $resql = $this->db->query($sql); if (!$resql) { @@ -685,7 +687,7 @@ class Opensurveysondage extends CommonObject { $result = 0; - $sql .= " SELECT COUNT(id_users) as nb FROM ".MAIN_DB_PREFIX."opensurvey_user_studs"; + $sql = " SELECT COUNT(id_users) as nb FROM ".MAIN_DB_PREFIX."opensurvey_user_studs"; $sql .= " WHERE id_sondage = '".$this->db->escape($this->ref)."'"; $resql = $this->db->query($sql); diff --git a/htdocs/opensurvey/exportcsv.php b/htdocs/opensurvey/exportcsv.php index a7e8b709793..a8a231787c3 100644 --- a/htdocs/opensurvey/exportcsv.php +++ b/htdocs/opensurvey/exportcsv.php @@ -63,9 +63,9 @@ $now = dol_now(); $nbcolonnes = substr_count($object->sujet, ',') + 1; $toutsujet = explode(",", $object->sujet); - +$somme = array(); // affichage des sujets du sondage -$input .= $langs->trans("Name").";"; +$input = $langs->trans("Name").";"; for ($i = 0; $toutsujet[$i]; $i++) { if ($object->format == "D") { $input .= ''.dol_print_date($toutsujet[$i], 'dayhour').';'; @@ -105,15 +105,18 @@ if ($resql) { //affichage des resultats $ensemblereponses = $obj->reponses; for ($k = 0; $k < $nbcolonnes; $k++) { + if (empty($somme[$k])) { + $somme[$k] = 0; + } $car = substr($ensemblereponses, $k, 1); if ($car == "1") { $input .= 'OK;'; $somme[$k]++; } elseif ($car == "2") { - $input .= 'KO;'; + $input .= ';'; $somme[$k]++; } else { - $input .= ';'; + $input .= 'KO;'; } } diff --git a/htdocs/opensurvey/list.php b/htdocs/opensurvey/list.php index 44241007dfb..5700909cd91 100644 --- a/htdocs/opensurvey/list.php +++ b/htdocs/opensurvey/list.php @@ -40,6 +40,7 @@ $toselect = GETPOST('toselect', 'array'); // Array of ids of elements selected $contextpage = GETPOST('contextpage', 'aZ') ?GETPOST('contextpage', 'aZ') : 'opensurveylist'; // To manage different context of search $backtopage = GETPOST('backtopage', 'alpha'); // Go back to a dedicated page $optioncss = GETPOST('optioncss', 'aZ'); // Option for the css output (always '' except when 'print') +$sall = trim((GETPOST('search_all', 'alphanohtml') != '') ? GETPOST('search_all', 'alphanohtml') : GETPOST('sall', 'alphanohtml')); $id = GETPOST('id', 'alpha'); $search_ref = GETPOST('search_ref', 'alpha'); @@ -175,16 +176,16 @@ $sql .= " WHERE p.entity IN (".getEntity('survey').")"; if ($search_status != '-1' && $search_status != '') { $sql .= natural_search("p.status", $search_status, 2); } -if ($search_expired == 'expired') { +if (!empty($search_expired) && $search_expired == 'expired') { $sql .= " AND p.date_fin < '".$db->idate($now)."'"; } -if ($search_expired == 'opened') { +if (!empty($search_expired) && $search_expired == 'opened') { $sql .= " AND p.date_fin >= '".$db->idate($now)."'"; } -if ($search_ref) { +if (!empty($search_ref)) { $sql .= natural_search("p.id_sondage", $search_ref); } -if ($search_title) { +if (!empty($search_title)) { $sql .= natural_search("p.titre", $search_title); } // Add where from extra fields @@ -327,6 +328,13 @@ print '
'; + $searchpicto = $form->showFilterButtons('left'); + print $searchpicto; + print ''; -$searchpicto = $form->showFilterButtons(); -print $searchpicto; -print ''; + $searchpicto = $form->showFilterButtons(); + print $searchpicto; + print '
'; + if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined + $selected = 0; + if (in_array($object->id, $arrayofselected)) { + $selected = 1; + } + print ''; + } + print ''; - if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined - $selected = 0; - if (in_array($object->id, $arrayofselected)) { - $selected = 1; + if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print ''; + if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined + $selected = 0; + if (in_array($object->id, $arrayofselected)) { + $selected = 1; + } + print ''; } - print ''; + print '
' . $langs->trans("ManufacturingOrder"); + if (!empty($showImportButton) && $conf->global->MAIN_ENABLE_IMPORT_LINKED_OBJECT_LINES) { + print ' '; + echo '' . $objectlink->getNomUrl(1) . ''; + // $result = $product_static->fetch($objectlink->fk_product); + print '' . dol_print_date($objectlink->date_creation, 'day') . '-' . $objectlink->getLibStatut(3) . ''; + + // we want to make the link via element_element for delete action + $sql = " Select rowid from " . MAIN_DB_PREFIX . "element_element"; + $sql .= " WHERE fk_source = " . (int) $object->id . " and fk_target = '" . dol_escape_htmltag($key) . "'"; + + $resql = $db->query($sql); + $k = 0; + if ($resql) { + $obj = $db->fetch_object($resql); + if ($obj->rowid && $obj->rowid > 0) $k = $obj->rowid; + } + echo '' . img_picto($langs->transnoentitiesnoconv("RemoveLink"), 'unlink') . ''; + echo '
' . $langs->trans("ManufacturingOrder"); + if ($ilink == count($linkedObjectBlock) && empty($noMoreLinkedObjectBlockAfter) && count($linkedObjectBlock) <= 1) { + $trclass .= ' liste_sub_total'; + } + print '
'.$langs->trans("ManufacturingOrder"); if (!empty($showImportButton) && $conf->global->MAIN_ENABLE_IMPORT_LINKED_OBJECT_LINES) { - print ' id; + print ' '; } - echo ''.$objectlink->getNomUrl(1).''; - // $result = $product_static->fetch($objectlink->fk_product); print '' . dol_print_date($objectlink->date_creation, 'day') . '-' . $objectlink->getLibStatut(3) . ''; - // we want to make the link via element_element for delete action - $sql = " Select rowid from " . MAIN_DB_PREFIX . "element_element"; - $sql .= " WHERE fk_source = ". (int) $object->id . " and fk_target = '" . dol_escape_htmltag($key) ."'"; - - $resql = $db->query($sql); - $k = 0; - if ($resql) { - $obj = $db->fetch_object($resql); - if ($obj->rowid && $obj->rowid > 0 ) $k = $obj->rowid; - } - echo '' . img_picto($langs->transnoentitiesnoconv("RemoveLink"), 'unlink') . ''; - - echo '
'.$objectlink->getNomUrl(1).''.$objectlink->ref_client.''.dol_print_date($objectlink->date_start_planned, 'day').'-'.$objectlink->getLibStatut(3).''.img_picto($langs->transnoentitiesnoconv("RemoveLink"), 'unlink').'
'; +// Action column +if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print ''; +} print ''; print ''; print ''; @@ -335,7 +343,7 @@ print ''; print ''; print ''; $arraystatus = array('-1'=>' ', '0'=>$langs->trans("Draft"), '1'=>$langs->trans("Opened"), '2'=>$langs->trans("Closed")); -print ''; +print ''; // Extra fields include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_input.tpl.php'; @@ -344,16 +352,22 @@ $parameters = array('arrayfields'=>$arrayfields); $reshook = $hookmanager->executeHooks('printFieldListOption', $parameters, $object); // Note that $action and $object may have been modified by hook print $hookmanager->resPrint; // Action column -print ''; +if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print ''; +} print ''."\n"; // Fields title label // -------------------------------------------------------------------- print ''; +// Action column +if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print getTitleFieldOfList($selectedfields, 0, $_SERVER["PHP_SELF"], '', '', '', 'align="center"', $sortfield, $sortorder, 'maxwidthsearch ')."\n"; +} print_liste_field_titre("Ref", $_SERVER["PHP_SELF"], "p.id_sondage", $param, "", "", $sortfield, $sortorder); print_liste_field_titre("Title", $_SERVER["PHP_SELF"], "p.titre", $param, "", "", $sortfield, $sortorder); print_liste_field_titre("Type", $_SERVER["PHP_SELF"], "p.format", $param, "", "", $sortfield, $sortorder); @@ -369,7 +383,9 @@ $parameters = array('arrayfields'=>$arrayfields, 'param'=>$param, 'sortfield'=>$ $reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters, $object); // Note that $action and $object may have been modified by hook print $hookmanager->resPrint; // Action column -print getTitleFieldOfList($selectedfields, 0, $_SERVER["PHP_SELF"], '', '', '', 'align="center"', $sortfield, $sortorder, 'maxwidthsearch ')."\n"; +if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print getTitleFieldOfList($selectedfields, 0, $_SERVER["PHP_SELF"], '', '', '', 'align="center"', $sortfield, $sortorder, 'maxwidthsearch ')."\n"; +} print ''."\n"; @@ -402,7 +418,18 @@ while ($i < min($num, $limit)) { // Show here line of result print ''; - + // Action column + if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print ''; + } // Ref print ''; } - print ''; if (!$i) { $totalarray['nbfield']++; } diff --git a/htdocs/opensurvey/results.php b/htdocs/opensurvey/results.php index f8a2648a809..d8405c31027 100644 --- a/htdocs/opensurvey/results.php +++ b/htdocs/opensurvey/results.php @@ -435,7 +435,7 @@ $toutsujet = explode(",", $object->sujet); $listofanswers = array(); foreach ($toutsujet as $value) { $tmp = explode('@', $value); - $listofanswers[] = array('label'=>$tmp[0], 'format'=>($tmp[1] ? $tmp[1] : 'checkbox')); + $listofanswers[] = array('label'=>$tmp[0], 'format'=>(!empty($tmp[1]) ? $tmp[1] : 'checkbox')); } $toutsujet = str_replace("@", "
", $toutsujet); $toutsujet = str_replace("°", "'", $toutsujet); @@ -701,34 +701,10 @@ if ($object->format == "D") { $colspan = 1; $nbofsujet = count($toutsujet); for ($i = 0; $i < $nbofsujet; $i++) { - $current = $toutsujet[$i]; - - if (strpos($toutsujet[$i], '@') !== false) { - $current = substr($toutsujet[$i], 0, strpos($toutsujet[$i], '@')); - } - - if (isset($toutsujet[$i + 1]) && strpos($toutsujet[$i + 1], '@') !== false) { - $next = substr($toutsujet[$i + 1], 0, strpos($toutsujet[$i + 1], '@')); - } elseif (isset($toutsujet[$i + 1])) { - $next = $toutsujet[$i + 1]; - } - - $currenty = 0; - if ($current) { - $currenty = strftime("%Y", $current); - } - $next = 0; - if ($next) { - $nexty = strftime("%Y", $next); - } - if (isset($toutsujet[$i + 1]) && ($currenty == $nexty)) { + if (isset($toutsujet[$i + 1]) && date('Y', intval($toutsujet[$i])) == date('Y', intval($toutsujet[$i + 1]))) { $colspan++; } else { - print ''."\n"; + print ''."\n"; $colspan = 1; } } diff --git a/htdocs/opensurvey/wizard/choix_date.php b/htdocs/opensurvey/wizard/choix_date.php index 46983829c3b..d8f89b18e16 100644 --- a/htdocs/opensurvey/wizard/choix_date.php +++ b/htdocs/opensurvey/wizard/choix_date.php @@ -37,6 +37,7 @@ if (!$user->rights->opensurvey->write) { $_SESSION["formatsondage"] = "D"; $erreur = false; +$erreurNbchoice = 0; /* * Actions @@ -49,114 +50,120 @@ if (GETPOST('confirmation')) { $nbofchoice = count($_SESSION["totalchoixjour"]); $errheure = array(); - for ($i = 0; $i < $nbofchoice; $i++) { - // Show hours choices - for ($j = 0; $j < $_SESSION["nbrecaseshoraires"]; $j++) { - $horairesi = GETPOST("horaires".$i); - $_SESSION["horaires$i"][$j] = $horairesi[$j]; - - $tmphorairesi = GETPOST('horaires'.$i, 'array'); - - if (!is_array($tmphorairesi)) { - $errheure[$i][$j] = true; - $erreur = true; - continue; - } - - // A range like 8:00-11:00 - $creneaux = array(); - $heures = array(); - if (preg_match("/(\d{1,2}:\d{2})-(\d{1,2}:\d{2})/", $tmphorairesi[$j], $creneaux)) { - //on recupere les deux parties du preg_match qu'on redécoupe autour des ":" - $debutcreneau = explode(":", $creneaux[1]); - $fincreneau = explode(":", $creneaux[2]); - - //comparaison des heures de fin et de debut - //si correctes, on entre les données dans la variables de session - if ($debutcreneau[0] < 24 && $fincreneau[0] < 24 && $debutcreneau[1] < 60 && $fincreneau[1] < 60 && ($debutcreneau[0] < $fincreneau[0] || ($debutcreneau[0] == $fincreneau[0] && $debutcreneau[1] < $fincreneau[1]))) { - $_SESSION["horaires$i"][$j] = $creneaux[1].'-'.$creneaux[2]; - } else { //sinon message d'erreur et nettoyage de la case - $errheure[$i][$j] = true; - $erreur = true; - } - } elseif (preg_match(";^(\d{1,2}h\d{0,2})-(\d{1,2}h\d{0,2})$;i", $tmphorairesi[$j], $creneaux)) { //si c'est un creneau type 8h00-11h00 - //on recupere les deux parties du preg_match qu'on redécoupe autour des "H" - $debutcreneau = preg_split("/h/i", $creneaux[1]); - $fincreneau = preg_split("/h/i", $creneaux[2]); - - //comparaison des heures de fin et de debut - //si correctes, on entre les données dans la variables de session - if ($debutcreneau[0] < 24 && $fincreneau[0] < 24 && $debutcreneau[1] < 60 && $fincreneau[1] < 60 && ($debutcreneau[0] < $fincreneau[0] || ($debutcreneau[0] == $fincreneau[0] && $debutcreneau[1] < $fincreneau[1]))) { - $_SESSION["horaires$i"][$j] = $creneaux[1].'-'.$creneaux[2]; - } else { //sinon message d'erreur et nettoyage de la case - $errheure[$i][$j] = true; - $erreur = true; - } - } elseif (preg_match(";^(\d{1,2}):(\d{2})$;", $tmphorairesi[$j], $heures)) { //si c'est une heure simple type 8:00 - //si valeures correctes, on entre les données dans la variables de session - if ($heures[1] < 24 && $heures[2] < 60) { - $_SESSION["horaires$i"][$j] = $heures[0]; - } else { //sinon message d'erreur et nettoyage de la case - $errheure[$i][$j] = true; - $erreur = true; - } - } elseif (preg_match(";^(\d{1,2})h(\d{0,2})$;i", $tmphorairesi[$j], $heures)) { //si c'est une heure encore plus simple type 8h - //si valeures correctes, on entre les données dans la variables de session - if ($heures[1] < 24 && $heures[2] < 60) { - $_SESSION["horaires$i"][$j] = $heures[0]; - } else { //sinon message d'erreur et nettoyage de la case - $errheure[$i][$j] = true; - $erreur = true; - } - } elseif (preg_match(";^(\d{1,2})-(\d{1,2})$;", $tmphorairesi[$j], $heures)) { //si c'est un creneau simple type 8-11 - //si valeures correctes, on entre les données dans la variables de session - if ($heures[1] < $heures[2] && $heures[1] < 24 && $heures[2] < 24) { - $_SESSION["horaires$i"][$j] = $heures[0]; - } else { //sinon message d'erreur et nettoyage de la case - $errheure[$i][$j] = true; - $erreur = true; - } - } elseif (preg_match(";^(\d{1,2})h-(\d{1,2})h$;", $tmphorairesi[$j], $heures)) { //si c'est un creneau H type 8h-11h - //si valeures correctes, on entre les données dans la variables de session - if ($heures[1] < $heures[2] && $heures[1] < 24 && $heures[2] < 24) { - $_SESSION["horaires$i"][$j] = $heures[0]; - } else { //sinon message d'erreur et nettoyage de la case - $errheure[$i][$j] = true; - $erreur = true; - } - } elseif ($tmphorairesi[$j] == "") { //Si la case est vide - unset($_SESSION["horaires$i"][$j]); - } else { //pour tout autre format, message d'erreur - $errheure[$i][$j] = true; - $erreur = true; - } - - if (issetAndNoEmpty('horaires'.$i, $_SESSION) === false || issetAndNoEmpty($j, $_SESSION['horaires'.$i]) === false) { - if (issetAndNoEmpty('horaires'.$i, $_SESSION) === true) { - $_SESSION["horaires$i"][$j] = ''; - } else { - $_SESSION["horaires$i"] = array(); - $_SESSION["horaires$i"][$j] = ''; - } - } - } - - if ($_SESSION["horaires$i"][0] == "" && $_SESSION["horaires$i"][1] == "" && $_SESSION["horaires$i"][2] == "" && $_SESSION["horaires$i"][3] == "" && $_SESSION["horaires$i"][4] == "") { - $choixdate .= ","; - $choixdate .= $_SESSION["totalchoixjour"][$i]; - } else { + if ($nbofchoice * $_SESSION["nbrecaseshoraires"] > 200) { + setEventMessages($langs->trans("ErrorFieldTooLong"), null, 'errors'); + $erreurNb++; + } else { + for ($i = 0; $i < $nbofchoice; $i++) { + // Show hours choices for ($j = 0; $j < $_SESSION["nbrecaseshoraires"]; $j++) { - if ($_SESSION["horaires$i"][$j] != "") { - $choixdate .= ","; - $choixdate .= $_SESSION["totalchoixjour"][$i]; - $choixdate .= "@"; - // On remplace la virgule et l'arobase pour ne pas avoir de problème par la suite - $choixdate .= str_replace(array(',', '@'), array(',', '@'), $_SESSION["horaires$i"][$j]); + $horairesi = GETPOST("horaires".$i); + $_SESSION["horaires$i"][$j] = $horairesi[$j]; + + $tmphorairesi = GETPOST('horaires'.$i, 'array'); + + if (!is_array($tmphorairesi)) { + $errheure[$i][$j] = true; + $erreur = true; + continue; + } + + // A range like 8:00-11:00 + $creneaux = array(); + $heures = array(); + if (preg_match("/(\d{1,2}:\d{2})-(\d{1,2}:\d{2})/", $tmphorairesi[$j], $creneaux)) { + //on recupere les deux parties du preg_match qu'on redécoupe autour des ":" + $debutcreneau = explode(":", $creneaux[1]); + $fincreneau = explode(":", $creneaux[2]); + + //comparaison des heures de fin et de debut + //si correctes, on entre les données dans la variables de session + if ($debutcreneau[0] < 24 && $fincreneau[0] < 24 && $debutcreneau[1] < 60 && $fincreneau[1] < 60 && ($debutcreneau[0] < $fincreneau[0] || ($debutcreneau[0] == $fincreneau[0] && $debutcreneau[1] < $fincreneau[1]))) { + $_SESSION["horaires$i"][$j] = $creneaux[1].'-'.$creneaux[2]; + } else { //sinon message d'erreur et nettoyage de la case + $errheure[$i][$j] = true; + $erreur = true; + } + } elseif (preg_match(";^(\d{1,2}h\d{0,2})-(\d{1,2}h\d{0,2})$;i", $tmphorairesi[$j], $creneaux)) { //si c'est un creneau type 8h00-11h00 + //on recupere les deux parties du preg_match qu'on redécoupe autour des "H" + $debutcreneau = preg_split("/h/i", $creneaux[1]); + $fincreneau = preg_split("/h/i", $creneaux[2]); + + //comparaison des heures de fin et de debut + //si correctes, on entre les données dans la variables de session + if ($debutcreneau[0] < 24 && $fincreneau[0] < 24 && $debutcreneau[1] < 60 && $fincreneau[1] < 60 && ($debutcreneau[0] < $fincreneau[0] || ($debutcreneau[0] == $fincreneau[0] && $debutcreneau[1] < $fincreneau[1]))) { + $_SESSION["horaires$i"][$j] = $creneaux[1].'-'.$creneaux[2]; + } else { //sinon message d'erreur et nettoyage de la case + $errheure[$i][$j] = true; + $erreur = true; + } + } elseif (preg_match(";^(\d{1,2}):(\d{2})$;", $tmphorairesi[$j], $heures)) { //si c'est une heure simple type 8:00 + //si valeures correctes, on entre les données dans la variables de session + if ($heures[1] < 24 && $heures[2] < 60) { + $_SESSION["horaires$i"][$j] = $heures[0]; + } else { //sinon message d'erreur et nettoyage de la case + $errheure[$i][$j] = true; + $erreur = true; + } + } elseif (preg_match(";^(\d{1,2})h(\d{0,2})$;i", $tmphorairesi[$j], $heures)) { //si c'est une heure encore plus simple type 8h + //si valeures correctes, on entre les données dans la variables de session + if ($heures[1] < 24 && $heures[2] < 60) { + $_SESSION["horaires$i"][$j] = $heures[0]; + } else { //sinon message d'erreur et nettoyage de la case + $errheure[$i][$j] = true; + $erreur = true; + } + } elseif (preg_match(";^(\d{1,2})-(\d{1,2})$;", $tmphorairesi[$j], $heures)) { //si c'est un creneau simple type 8-11 + //si valeures correctes, on entre les données dans la variables de session + if ($heures[1] < $heures[2] && $heures[1] < 24 && $heures[2] < 24) { + $_SESSION["horaires$i"][$j] = $heures[0]; + } else { //sinon message d'erreur et nettoyage de la case + $errheure[$i][$j] = true; + $erreur = true; + } + } elseif (preg_match(";^(\d{1,2})h-(\d{1,2})h$;", $tmphorairesi[$j], $heures)) { //si c'est un creneau H type 8h-11h + //si valeures correctes, on entre les données dans la variables de session + if ($heures[1] < $heures[2] && $heures[1] < 24 && $heures[2] < 24) { + $_SESSION["horaires$i"][$j] = $heures[0]; + } else { //sinon message d'erreur et nettoyage de la case + $errheure[$i][$j] = true; + $erreur = true; + } + } elseif ($tmphorairesi[$j] == "") { //Si la case est vide + unset($_SESSION["horaires$i"][$j]); + } else { //pour tout autre format, message d'erreur + $errheure[$i][$j] = true; + $erreur = true; + } + + if (issetAndNoEmpty('horaires'.$i, $_SESSION) === false || issetAndNoEmpty($j, $_SESSION['horaires'.$i]) === false) { + if (issetAndNoEmpty('horaires'.$i, $_SESSION) === true) { + $_SESSION["horaires$i"][$j] = ''; + } else { + $_SESSION["horaires$i"] = array(); + $_SESSION["horaires$i"][$j] = ''; + } + } + } + + if ($_SESSION["horaires$i"][0] == "" && $_SESSION["horaires$i"][1] == "" && $_SESSION["horaires$i"][2] == "" && $_SESSION["horaires$i"][3] == "" && $_SESSION["horaires$i"][4] == "") { + $choixdate .= ","; + $choixdate .= $_SESSION["totalchoixjour"][$i]; + } else { + for ($j = 0; $j < $_SESSION["nbrecaseshoraires"]; $j++) { + if ($_SESSION["horaires$i"][$j] != "") { + $choixdate .= ","; + $choixdate .= $_SESSION["totalchoixjour"][$i]; + $choixdate .= "@"; + // On remplace la virgule et l'arobase pour ne pas avoir de problème par la suite + $choixdate .= str_replace(array(',', '@'), array(',', '@'), $_SESSION["horaires$i"][$j]); + } } } } } + if (!empty($errheure)) { setEventMessages($langs->trans("ErrorBadFormat"), null, 'errors'); } @@ -170,7 +177,7 @@ if (GETPOST('confirmation')) { } // Add survey into database - if (!$erreur) { + if (!$erreur && $erreurNb == 0) { $_SESSION["toutchoix"] = substr("$choixdate", 1); ajouter_sondage(); diff --git a/htdocs/partnership/class/partnership.class.php b/htdocs/partnership/class/partnership.class.php index 4838c80f92d..5908b964f2c 100644 --- a/htdocs/partnership/class/partnership.class.php +++ b/htdocs/partnership/class/partnership.class.php @@ -17,16 +17,14 @@ */ /** - * \file class/partnership.class.php + * \file htdocs/partnership/class/partnership.class.php * \ingroup partnership * \brief This file is a CRUD class file for Partnership (Create/Read/Update/Delete) */ + // Put here all includes required by your class file require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php'; -//require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php'; -//require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php'; - /** * Class for Partnership @@ -124,6 +122,7 @@ class Partnership extends CommonObject 'last_check_backlink' => array('type'=>'datetime', 'label'=>'LastCheckBacklink', 'enabled'=>'1', 'position'=>72, 'notnull'=>0, 'visible'=>-2,), 'reason_decline_or_cancel' => array('type'=>'text', 'label'=>'ReasonDeclineOrCancel', 'enabled'=>'1', 'position'=>73, 'notnull'=>0, 'visible'=>-2,), 'fk_soc' => array('type'=>'integer:Societe:societe/class/societe.class.php:1:status=1 AND entity IN (__SHARED_ENTITIES__)', 'label'=>'ThirdParty', 'picto'=>'company', 'enabled'=>'1', 'position'=>50, 'notnull'=>-1, 'visible'=>1, 'index'=>1, 'css'=>'maxwidth500', 'csslist'=>'tdoverflowmax150',), + 'ip' => array('type'=>'varchar(250)', 'label'=>'Ip', 'enabled'=>'1', 'position'=>74, 'notnull'=>0, 'visible'=>-2,), ); public $rowid; public $ref; @@ -195,7 +194,7 @@ class Partnership extends CommonObject $this->db = $db; - if (!empty($conf->global->PARTNERSHIP_IS_MANAGED_FOR) && getDolGlobalString('PARTNERSHIP_IS_MANAGED_FOR') == 'member') { + if (getDolGlobalString('PARTNERSHIP_IS_MANAGED_FOR') == 'member') { $this->fields['fk_member'] = array('type'=>'integer:Adherent:adherents/class/adherent.class.php:1', 'label'=>'Member', 'enabled'=>'1', 'position'=>50, 'notnull'=>-1, 'visible'=>1, 'index'=>1, 'picto'=>'member', 'csslist'=>'tdoverflowmax150'); } else { $this->fields['fk_soc'] = array('type'=>'integer:Societe:societe/class/societe.class.php:1:status=1 AND entity IN (__SHARED_ENTITIES__)', 'label'=>'ThirdParty', 'enabled'=>'1', 'position'=>50, 'notnull'=>-1, 'visible'=>1, 'index'=>1, 'picto'=>'company', 'css'=>'maxwidth500', 'csslist'=>'tdoverflowmax150'); diff --git a/htdocs/partnership/lib/partnership.lib.php b/htdocs/partnership/lib/partnership.lib.php index abf8dcca63b..5c30be6ffd1 100644 --- a/htdocs/partnership/lib/partnership.lib.php +++ b/htdocs/partnership/lib/partnership.lib.php @@ -28,10 +28,13 @@ */ function partnershipAdminPrepareHead() { - global $langs, $conf; + global $langs, $conf, $db; $langs->loadLangs(array("members", "partnership")); + $extrafields = new ExtraFields($db); + $extrafields->fetch_name_optionals_label('partnership'); + $h = 0; $head = array(); @@ -43,6 +46,10 @@ function partnershipAdminPrepareHead() $head[$h][0] = dol_buildpath("/partnership/admin/partnership_extrafields.php", 1); $head[$h][1] = $langs->trans("ExtraFields"); + $nbExtrafields = $extrafields->attributes['partnership']['count']; + if ($nbExtrafields > 0) { + $head[$h][1] .= ''.$nbExtrafields.''; + } $head[$h][2] = 'partnership_extrafields'; $h++; @@ -51,13 +58,6 @@ function partnershipAdminPrepareHead() $head[$h][2] = 'website'; $h++; - /* - $head[$h][0] = dol_buildpath("/partnership/admin/about.php", 1); - $head[$h][1] = $langs->trans("About"); - $head[$h][2] = 'about'; - $h++; - */ - // Show more tabs from modules // Entries must be declared in modules descriptor with line //$this->tabs = array( diff --git a/htdocs/partnership/partnership_card.php b/htdocs/partnership/partnership_card.php index 551794b5d4a..de5449b7e80 100644 --- a/htdocs/partnership/partnership_card.php +++ b/htdocs/partnership/partnership_card.php @@ -374,7 +374,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea // require_once DOL_DOCUMENT_ROOT.'/core/class/notify.class.php'; // $notify = new Notify($db); // $formquestion = array_merge($formquestion, array( - // array('type' => 'onecolumn', 'value' => $notify->confirmMessage('PROPAL_CLOSE_SIGNED', $object->socid, $object)), + // array('type' => 'onecolumn', 'value' => $notify->confirmMessage('PARTNERSHIP_CLOSE_DENY', $object->socid, $object)), // )); // } diff --git a/htdocs/product/admin/product.php b/htdocs/product/admin/product.php index a8106a9ae88..069029d074b 100644 --- a/htdocs/product/admin/product.php +++ b/htdocs/product/admin/product.php @@ -148,11 +148,15 @@ if ($action == 'other') { $value = GETPOST('activate_FillProductDescAuto', 'alpha'); $res = dolibarr_set_const($db, "PRODUIT_AUTOFILL_DESC", $value, 'chaine', 0, '', $conf->entity); - $value = GETPOST('PRODUIT_FOURN_TEXTS', 'alpha'); - $res = dolibarr_set_const($db, "PRODUIT_FOURN_TEXTS", $value, 'chaine', 0, '', $conf->entity); + if (GETPOSTISSET('PRODUIT_FOURN_TEXTS')) { + $value = GETPOST('PRODUIT_FOURN_TEXTS', 'alpha'); + $res = dolibarr_set_const($db, "PRODUIT_FOURN_TEXTS", $value, 'chaine', 0, '', $conf->entity); + } - $value = GETPOST('PRODUCT_USE_SUPPLIER_PACKAGING', 'alpha'); - $res = dolibarr_set_const($db, "PRODUCT_USE_SUPPLIER_PACKAGING", $value, 'chaine', 0, '', $conf->entity); + if (GETPOSTISSET('PRODUCT_USE_SUPPLIER_PACKAGING')) { + $value = GETPOST('PRODUCT_USE_SUPPLIER_PACKAGING', 'alpha'); + $res = dolibarr_set_const($db, "PRODUCT_USE_SUPPLIER_PACKAGING", $value, 'chaine', 0, '', $conf->entity); + } } diff --git a/htdocs/product/ajax/products.php b/htdocs/product/ajax/products.php index 24da89b7619..f61e92c56f3 100644 --- a/htdocs/product/ajax/products.php +++ b/htdocs/product/ajax/products.php @@ -93,6 +93,7 @@ if ($action == 'fetch' && !empty($id)) { $outprice_ht = null; $outprice_ttc = null; $outpricebasetype = null; + $outtva_tx_formated = 0; $outtva_tx = 0; $outdefault_vat_code = ''; $outqty = 1; @@ -140,7 +141,8 @@ if ($action == 'fetch' && !empty($id)) { $outprice_ttc = price($objp->unitprice * (1 + ($object->tva_tx / 100))); $outpricebasetype = $object->price_base_type; - $outtva_tx = $object->tva_tx; + $outtva_tx_formated = price($object->tva_tx); + $outtva_tx = price2num($object->tva_tx); $outdefault_vat_code = $object->default_vat_code; $outqty = $objp->quantity; @@ -165,15 +167,17 @@ if ($action == 'fetch' && !empty($id)) { $objp = $db->fetch_object($result); if ($objp) { $found = true; - $outprice_ht = price($objp->price); - $outprice_ttc = price($objp->price_ttc); + $outprice_ht = price($objp->price); // formated for langage user because is inserted into input field + $outprice_ttc = price($objp->price_ttc); // formated for langage user because is inserted into input field $outpricebasetype = $objp->price_base_type; if (!empty($conf->global->PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL)) { - $outtva_tx = $objp->tva_tx; + $outtva_tx_formated = price($objp->tva_tx); // formated for langage user because is inserted into input field + $outtva_tx = price2num($objp->tva_tx); // international numeric $outdefault_vat_code = $objp->default_vat_code; } else { // The common and default behaviour. - $outtva_tx = $object->tva_tx; + $outtva_tx_formated = price($object->tva_tx); + $outtva_tx = price2num($object->tva_tx); $outdefault_vat_code = $object->default_vat_code; } } @@ -195,7 +199,8 @@ if ($action == 'fetch' && !empty($id)) { $outprice_ht = price($prodcustprice->lines[0]->price); $outprice_ttc = price($prodcustprice->lines[0]->price_ttc); $outpricebasetype = $prodcustprice->lines[0]->price_base_type; - $outtva_tx = $prodcustprice->lines[0]->tva_tx; + $outtva_tx_formated = price($prodcustprice->lines[0]->tva_tx); + $outtva_tx = price2num($prodcustprice->lines[0]->tva_tx); $outdefault_vat_code = $prodcustprice->lines[0]->default_vat_code; } } @@ -205,7 +210,8 @@ if ($action == 'fetch' && !empty($id)) { $outprice_ht = price($object->price); $outprice_ttc = price($object->price_ttc); $outpricebasetype = $object->price_base_type; - $outtva_tx = $object->tva_tx; + $outtva_tx_formated = price($object->tva_tx); + $outtva_tx = price2num($object->tva_tx); $outdefault_vat_code = $object->default_vat_code; } @@ -219,6 +225,7 @@ if ($action == 'fetch' && !empty($id)) { 'price_ht' => $outprice_ht, 'price_ttc' => $outprice_ttc, 'pricebasetype' => $outpricebasetype, + 'tva_tx_formated' => $outtva_tx_formated, 'tva_tx' => $outtva_tx, 'default_vat_code' => $outdefault_vat_code, 'qty' => $outqty, diff --git a/htdocs/product/card.php b/htdocs/product/card.php index c1be61741bb..8f1f6061861 100644 --- a/htdocs/product/card.php +++ b/htdocs/product/card.php @@ -2528,7 +2528,7 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) { print ''; } - if ($object->isService() && $conf->workstation->enabled) { + if ($object->isService() && isModEnabled('workstation')) { $workstation = new Workstation($db); $res = $workstation->fetch($object->fk_default_workstation); diff --git a/htdocs/product/class/api_products.class.php b/htdocs/product/class/api_products.class.php index e234f4dba8e..76ee11f727e 100644 --- a/htdocs/product/class/api_products.class.php +++ b/htdocs/product/class/api_products.class.php @@ -454,7 +454,19 @@ class Products extends DolibarrApi global $user; $user = DolibarrApiAccess::$user; - return $this->product->delete(DolibarrApiAccess::$user); + $res = $this->product->delete(DolibarrApiAccess::$user); + if ($res < 0) { + throw new RestException(500, "Can't delete, error occurs"); + } elseif ($res == 0) { + throw new RestException(409, "Can't delete, that product is probably used"); + } + + return array( + 'success' => array( + 'code' => 200, + 'message' => 'Object deleted' + ) + ); } /** diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index ffb72bfca78..bebe5d5a98d 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -2159,7 +2159,7 @@ class Product extends CommonObject } } else { $price = price2num($newprice, 'MU'); - $price_ttc = ($newnpr != 1) ? price2num($newprice) * (1 + ($newvat / 100)) : $price; + $price_ttc = ($newnpr != 1) ? (float) price2num($newprice) * (1 + ($newvat / 100)) : $price; $price_ttc = price2num($price_ttc, 'MU'); if ($newminprice !== '' || $newminprice === 0) { @@ -2179,12 +2179,34 @@ class Product extends CommonObject $localtax1 = $localtaxes_array['1']; $localtaxtype2 = $localtaxes_array['2']; $localtax2 = $localtaxes_array['3']; - } else // old method. deprecated because ot can't retrieve type - { - $localtaxtype1 = '0'; - $localtax1 = get_localtax($newvat, 1); - $localtaxtype2 = '0'; - $localtax2 = get_localtax($newvat, 2); + } else { + // if array empty, we try to use the vat code + if (!empty($newdefaultvatcode)) { + global $mysoc; + // Get record from code + $sql = "SELECT t.rowid, t.code, t.recuperableonly, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type"; + $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c"; + $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$this->db->escape($mysoc->country_code)."'"; + $sql .= " AND t.taux = ".((float) $newdefaultvatcode)." AND t.active = 1"; + $sql .= " AND t.code = '".$this->db->escape($newdefaultvatcode)."'"; + $resql = $this->db->query($sql); + if ($resql) { + $obj = $this->db->fetch_object($resql); + if ($obj) { + $npr = $obj->recuperableonly; + $localtax1 = $obj->localtax1; + $localtax2 = $obj->localtax2; + $localtaxtype1 = $obj->localtax1_type; + $localtaxtype2 = $obj->localtax2_type; + } + } + } else { + // old method. deprecated because we can't retrieve type + $localtaxtype1 = '0'; + $localtax1 = get_localtax($newvat, 1); + $localtaxtype2 = '0'; + $localtax2 = get_localtax($newvat, 2); + } } if (empty($localtax1)) { $localtax1 = 0; // If = '' then = 0 diff --git a/htdocs/product/fournisseurs.php b/htdocs/product/fournisseurs.php index 5eae5c45dc9..95de1f53da8 100644 --- a/htdocs/product/fournisseurs.php +++ b/htdocs/product/fournisseurs.php @@ -270,10 +270,13 @@ if (empty($reshook)) { if ($ret == -3) { $error++; - $object->fetch($object->product_id_already_linked); - $productLink = $object->getNomUrl(1, 'supplier'); + $tmpobject = new Product($db); + $tmpobject->fetch($object->product_id_already_linked); + $productLink = $tmpobject->getNomUrl(1, 'supplier'); - setEventMessages($langs->trans("ReferenceSupplierIsAlreadyAssociatedWithAProduct", $productLink), null, 'errors'); + $texttoshow = $langs->trans("ReferenceSupplierIsAlreadyAssociatedWithAProduct", '{s1}'); + $texttoshow = str_replace('{s1}', $productLink, $texttoshow); + setEventMessages($texttoshow, null, 'errors'); } elseif ($ret < 0) { $error++; setEventMessages($object->error, $object->errors, 'errors'); @@ -788,16 +791,11 @@ END; // Barcode type print ''; - print ''; + print ''; print ''; - print ''; - - // Barcode value - print ''; - print ''; - print ''; + print img_picto('', 'barcode', 'class="pictofixedwidth"'); + print $formbarcode->selectBarcodeType((GETPOSTISSET('fk_barcode_type') ? GETPOST('fk_barcode_type', 'int') : ($rowid ? $object->supplier_fk_barcode_type : getDolGlobalint("PRODUIT_DEFAULT_BARCODE_TYPE"))), 'fk_barcode_type', 1); + print ' '; print ''; } @@ -995,52 +993,72 @@ END; $param = "&id=".$object->id; + $nbfields = 0; + print ''; if (!empty($arrayfields['pfp.datec']['checked'])) { print_liste_field_titre("AppliedPricesFrom", $_SERVER["PHP_SELF"], "pfp.datec", "", $param, "", $sortfield, $sortorder, '', '', 1); + $nbfields++; } if (!empty($arrayfields['s.nom']['checked'])) { print_liste_field_titre("Suppliers", $_SERVER["PHP_SELF"], "s.nom", "", $param, "", $sortfield, $sortorder, '', '', 1); + $nbfields++; } print_liste_field_titre("SupplierRef", $_SERVER["PHP_SELF"], "", "", $param, "", $sortfield, $sortorder, '', '', 1); + $nbfields++; if (!empty($arrayfields['pfp.fk_availability']['checked'])) { print_liste_field_titre("Availability", $_SERVER["PHP_SELF"], "pfp.fk_availability", "", $param, "", $sortfield, $sortorder); + $nbfields++; } if (!empty($arrayfields['pfp.quantity']['checked'])) { print_liste_field_titre("QtyMin", $_SERVER["PHP_SELF"], "pfp.quantity", "", $param, '', $sortfield, $sortorder, 'right '); + $nbfields++; } print_liste_field_titre("VATRate", $_SERVER["PHP_SELF"], '', '', $param, '', $sortfield, $sortorder, 'right '); + $nbfields++; print_liste_field_titre("PriceQtyMinHT", $_SERVER["PHP_SELF"], '', '', $param, '', $sortfield, $sortorder, 'right '); + $nbfields++; if (isModEnabled("multicurrency")) { print_liste_field_titre("PriceQtyMinHTCurrency", $_SERVER["PHP_SELF"], '', '', $param, '', $sortfield, $sortorder, 'right '); + $nbfields++; } if (!empty($arrayfields['pfp.unitprice']['checked'])) { print_liste_field_titre("UnitPriceHT", $_SERVER["PHP_SELF"], "pfp.unitprice", "", $param, '', $sortfield, $sortorder, 'right '); + $nbfields++; } if (!empty($arrayfields['pfp.multicurrency_unitprice']['checked'])) { print_liste_field_titre("UnitPriceHTCurrency", $_SERVER["PHP_SELF"], "pfp.multicurrency_unitprice", "", $param, '', $sortfield, $sortorder, 'right '); + $nbfields++; } if (isModEnabled("multicurrency")) { print_liste_field_titre("Currency", $_SERVER["PHP_SELF"], "", "", $param, '', $sortfield, $sortorder, 'right '); + $nbfields++; } print_liste_field_titre("DiscountQtyMin", $_SERVER["PHP_SELF"], '', '', $param, '', $sortfield, $sortorder, 'right '); + $nbfields++; if (!empty($arrayfields['pfp.delivery_time_days']['checked'])) { print_liste_field_titre("NbDaysToDelivery", $_SERVER["PHP_SELF"], "pfp.delivery_time_days", "", $param, '', $sortfield, $sortorder, 'right '); + $nbfields++; } if (!empty($arrayfields['pfp.supplier_reputation']['checked'])) { print_liste_field_titre("ReputationForThisProduct", $_SERVER["PHP_SELF"], "pfp.supplier_reputation", "", $param, '', $sortfield, $sortorder, 'center '); + $nbfields++; } if (!empty($arrayfields['pfp.fk_barcode_type']['checked'])) { print_liste_field_titre("BarcodeType", $_SERVER["PHP_SELF"], "pfp.fk_barcode_type", "", $param, '', $sortfield, $sortorder, 'center '); + $nbfields++; } if (!empty($arrayfields['pfp.barcode']['checked'])) { print_liste_field_titre("BarcodeValue", $_SERVER["PHP_SELF"], "pfp.barcode", "", $param, '', $sortfield, $sortorder, 'center '); + $nbfields++; } if (!empty($arrayfields['pfp.packaging']['checked'])) { print_liste_field_titre("PackagingForThisProduct", $_SERVER["PHP_SELF"], "pfp.packaging", "", $param, 'align="center"', $sortfield, $sortorder); + $nbfields++; } if (!empty($arrayfields['pfp.tms']['checked'])) { print_liste_field_titre("DateModification", $_SERVER["PHP_SELF"], "pfp.tms", "", $param, '', $sortfield, $sortorder, 'right ', '', 1); + $nbfields++; } // fetch optionals attributes and labels @@ -1062,6 +1080,7 @@ END; } if (!empty($arrayfields['ef.' . $key]['checked'])) { print_liste_field_titre($extratitle, $_SERVER["PHP_SELF"], 'ef.' . $key, '', $param, '', $sortfield, $sortorder, 'right '); + $nbfields++; } } } @@ -1069,10 +1088,11 @@ END; } if (is_object($hookmanager)) { - $parameters = array('id_fourn'=>(!empty($id_fourn)?$id_fourn:''), 'prod_id'=>$object->id); + $parameters = array('id_fourn'=>(!empty($id_fourn)?$id_fourn:''), 'prod_id'=>$object->id, 'nbfields'=>$nbfields); $reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters, $object, $action); } print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'center maxwidthsearch '); + $nbfields++; print "\n"; if (is_array($product_fourn_list)) { @@ -1254,6 +1274,10 @@ END; print ''; } + + if (empty($product_fourn_list)) { + print ''; + } } else { dol_print_error($db); } diff --git a/htdocs/product/inventory/list.php b/htdocs/product/inventory/list.php index 18104118068..88e590c478b 100644 --- a/htdocs/product/inventory/list.php +++ b/htdocs/product/inventory/list.php @@ -224,6 +224,9 @@ $parameters = array(); $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters, $object); // Note that $action and $object may have been modified by hook $sql .= preg_replace('/^,/', '', $hookmanager->resPrint); $sql = preg_replace('/,\s*$/', '', $sql); + +$sqlfields = $sql; // $sql fields to remove for count total + $sql .= " FROM ".MAIN_DB_PREFIX.$object->table_element." as t"; if (isset($extrafields->attributes[$object->table_element]['label']) && is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label'])) { $sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$object->table_element."_extrafields as ef on (t.rowid = ef.fk_object)"; @@ -322,35 +325,41 @@ $sql.=$hookmanager->resPrint; $sql=preg_replace('/,\s*$/','', $sql); */ -$sql .= $db->order($sortfield, $sortorder); - -// Count total nb of records +/// Count total nb of records $nbtotalofrecords = ''; if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { - $resql = $db->query($sql); - $nbtotalofrecords = $db->num_rows($resql); - if (($page * $limit) > $nbtotalofrecords) { // if total of record found is smaller than page * limit, goto and load page 0 + /* The fast and low memory method to get and count full list converts the sql into a sql count */ + $sqlforcount = preg_replace('/^'.preg_quote($sqlfields, '/').'/', 'SELECT COUNT(*) as nbtotalofrecords', $sql); + $sqlforcount = preg_replace('/GROUP BY .*$/', '', $sqlforcount); + $resql = $db->query($sqlforcount); + if ($resql) { + $objforcount = $db->fetch_object($resql); + $nbtotalofrecords = $objforcount->nbtotalofrecords; + } else { + dol_print_error($db); + } + + if (($page * $limit) > $nbtotalofrecords) { // if total resultset is smaller then paging size (filtering), goto and load page 0 $page = 0; $offset = 0; } + $db->free($resql); } -// if total of record found is smaller than limit, no need to do paging and to restart another select with limits set. -if (is_numeric($nbtotalofrecords) && ($limit > $nbtotalofrecords || empty($limit))) { - $num = $nbtotalofrecords; -} else { - if ($limit) { - $sql .= $db->plimit($limit + 1, $offset); - } - $resql = $db->query($sql); - if (!$resql) { - dol_print_error($db); - exit; - } - - $num = $db->num_rows($resql); +// Complete request and execute it with limit +$sql .= $db->order($sortfield, $sortorder); +if ($limit) { + $sql .= $db->plimit($limit + 1, $offset); } +$resql = $db->query($sql); +if (!$resql) { + dol_print_error($db); + exit; +} + +$num = $db->num_rows($resql); + // Direct jump if only one record found if ($num == 1 && !empty($conf->global->MAIN_SEARCH_DIRECT_OPEN_IF_ONLY_ONE) && $search_all && !$page) { $obj = $db->fetch_object($resql); @@ -474,7 +483,7 @@ if (!empty($moreforfilter)) { } $varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage; -$selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields +$selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage, getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN', '')); // This also change content of $arrayfields $selectedfields .= (count($arrayofmassactions) ? $form->showCheckAddButtons('checkforselect', 1) : ''); print '
'; // You can use div-table-responsive-no-min if you dont need reserved height for your table @@ -484,6 +493,13 @@ print '
'; + $searchpicto = $form->showFilterButtons('left'); + print $searchpicto; + print ''.$form->selectarray('search_status', $arraystatus, $search_status).''.$form->selectarray('search_status', $arraystatus, $search_status, 0, 0, 0, '', 0, 0, 0, '', 'onroghtofpage').''; -$searchpicto = $form->showFilterButtons(); -print $searchpicto; -print ''; + $searchpicto = $form->showFilterButtons(); + print $searchpicto; + print '
'; + if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined + $selected = 0; + if (in_array($obj->rowid, $arrayofselected)) { + $selected = 1; + } + print ''; + } + print ''; print $opensurvey_static->getNomUrl(1); @@ -478,15 +505,17 @@ while ($i < min($num, $limit)) { $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters, $object); // Note that $action and $object may have been modified by hook print $hookmanager->resPrint; // Action column - print ''; - if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined - $selected = 0; - if (in_array($obj->rowid, $arrayofselected)) { - $selected = 1; + if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print ''; + if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined + $selected = 0; + if (in_array($obj->rowid, $arrayofselected)) { + $selected = 1; + } + print ''; } - print ''; + print ''; - if ($current) { - print strftime("%Y", $current); - } - print ''.date('Y', intval($toutsujet[$i])).'
'.$langs->trans('BarcodeType').''.$langs->trans('GencodBuyPrice').''; - print $formbarcode->selectBarcodeType(($rowid ? $object->supplier_fk_barcode_type : getDolGlobalint("PRODUIT_DEFAULT_BARCODE_TYPE")), 'fk_barcode_type', 1); - print '
'.$langs->trans('BarcodeValue').''.img_picto('', 'barcode', 'class="pictofixedwidth"').'
'.$langs->trans("None").'
'; +// Action column +if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print ''; +} foreach ($object->fields as $key => $val) { $cssforfield = (empty($val['csslist']) ? (empty($val['css']) ? '' : $val['css']) : $val['csslist']); if ($key == 'status') { @@ -522,16 +538,22 @@ $parameters = array('arrayfields'=>$arrayfields); $reshook = $hookmanager->executeHooks('printFieldListOption', $parameters, $object); // Note that $action and $object may have been modified by hook print $hookmanager->resPrint; // Action column -print ''; +if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print ''; +} print ''."\n"; // Fields title label // -------------------------------------------------------------------- print ''; +// Action column +if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print getTitleFieldOfList($selectedfields, 0, $_SERVER["PHP_SELF"], '', '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ')."\n"; +} foreach ($object->fields as $key => $val) { $cssforfield = (empty($val['csslist']) ? (empty($val['css']) ? '' : $val['css']) : $val['csslist']); if ($key == 'status') { @@ -554,7 +576,9 @@ $parameters = array('arrayfields'=>$arrayfields, 'param'=>$param, 'sortfield'=>$ $reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters, $object); // Note that $action and $object may have been modified by hook print $hookmanager->resPrint; // Action column -print getTitleFieldOfList($selectedfields, 0, $_SERVER["PHP_SELF"], '', '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ')."\n"; +if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print getTitleFieldOfList($selectedfields, 0, $_SERVER["PHP_SELF"], '', '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ')."\n"; +} print ''."\n"; @@ -584,6 +608,18 @@ while ($i < ($limit ? min($num, $limit) : $num)) { // Show here line of result print ''; + // Action column + if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print ''; + } foreach ($object->fields as $key => $val) { $cssforfield = (empty($val['csslist']) ? (empty($val['css']) ? '' : $val['css']) : $val['csslist']); if (in_array($val['type'], array('date', 'datetime', 'timestamp'))) { @@ -636,15 +672,17 @@ while ($i < ($limit ? min($num, $limit) : $num)) { $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters, $object); // Note that $action and $object may have been modified by hook print $hookmanager->resPrint; // Action column - print ''; } - print ''; if (!$i) { $totalarray['nbfield']++; } diff --git a/htdocs/product/list.php b/htdocs/product/list.php index e637e478df4..da17d702820 100644 --- a/htdocs/product/list.php +++ b/htdocs/product/list.php @@ -176,7 +176,6 @@ if (!empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT) // List of fields to search into when doing a "search in all" $fieldstosearchall = array( 'p.ref'=>"Ref", - 'pfp.ref_fourn'=>"RefSupplier", 'p.label'=>"ProductLabel", 'p.description'=>"Description", "p.note"=>"Note", @@ -190,7 +189,6 @@ if (getDolGlobalInt('MAIN_MULTILANGS')) { } if (isModEnabled('barcode')) { $fieldstosearchall['p.barcode'] = 'Gencod'; - $fieldstosearchall['pfp.barcode'] = 'GencodBuyPrice'; } // Personalized search criterias. Example: $conf->global->PRODUCT_QUICKSEARCH_ON_FIELDS = 'p.ref=ProductRef;p.label=ProductLabel;p.description=Description;p.note=Note;' if (!empty($conf->global->PRODUCT_QUICKSEARCH_ON_FIELDS)) { @@ -436,6 +434,9 @@ if (!empty($extrafields->attributes[$object->table_element]['label'])) { $parameters = array(); $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters, $object, $action); // Note that $action and $object may have been modified by hook $sql .= $hookmanager->resPrint; + +$sqlfields = $sql; // $sql fields to remove for count total + $sql .= ' FROM '.MAIN_DB_PREFIX.'product as p'; if (!empty($conf->global->MAIN_PRODUCT_PERENTITY_SHARED)) { $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "product_perentity as ppe ON ppe.fk_product = p.rowid AND ppe.entity = " . ((int) $conf->entity); @@ -459,7 +460,16 @@ if (!empty($conf->global->PRODUCT_USE_UNITS)) { $sql .= ' WHERE p.entity IN ('.getEntity('product').')'; if ($sall) { - $sql .= natural_search(array_keys($fieldstosearchall), $sall); + $sql .= ' AND ('; + $sql .= natural_search(array_keys($fieldstosearchall), $sall, 0, 1); + // Search also into a supplier reference 'pfp.ref_fourn'="RefSupplier" + $sql .= ' OR EXISTS (SELECT rowid FROM '.MAIN_DB_PREFIX.'product_fournisseur_price as pfp WHERE pfp.fk_product = p.rowid'; + $sql .= ' AND ('.natural_search('pfp.ref_fourn', $sall, 0, 1); + if (isModEnabled('barcode')) { + // Search also into a supplier barcode 'pfp.barcode'='GencodBuyPrice'; + $sql .= ' OR '.natural_search('pfp.barcode', $sall, 0, 1); + } + $sql .= ')))'; } // if the type is not 1, we show all products (type = 0,2,3) if (dol_strlen($search_type) && $search_type != '-1') { @@ -595,11 +605,8 @@ $sql .= $hookmanager->resPrint; $nbtotalofrecords = ''; if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { - /* $result = $db->query($sql); - $nbtotalofrecords = $db->num_rows($result); - */ /* The fast and low memory method to get and count full list converts the sql into a sql count */ - $sqlforcount = preg_replace('/^SELECT[a-zA-Z0-9\._\s\(\),=<>\:\-\']+\sFROM/Ui', 'SELECT COUNT(*) as nbtotalofrecords FROM', $sql); + $sqlforcount = preg_replace('/^'.preg_quote($sqlfields, '/').'/', 'SELECT COUNT(*) as nbtotalofrecords', $sql); $sqlforcount = preg_replace('/'.preg_quote($linktopfp, '/').'/', '', $sqlforcount); $sqlforcount = preg_replace('/GROUP BY .*$/', '', $sqlforcount); $resql = $db->query($sqlforcount); @@ -614,6 +621,7 @@ if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { $page = 0; $offset = 0; } + $db->free($resql); } // Complete request and execute it with limit @@ -1338,49 +1346,54 @@ while ($i < min($num, $limit)) { } } } + $parameters = array('staticdata' => $obj); + // Note that $action and $object may have been modified by hook + // do product_static fetch in hook if wanted or anything else + $reshook = $hookmanager->executeHooks('loadStaticObject', $parameters, $product_static, $action); + if (empty($reshook)) { + $product_static->id = $obj->rowid; + $product_static->ref = $obj->ref; + $product_static->ref_fourn = empty($obj->ref_supplier) ? '' : $obj->ref_supplier; // deprecated + $product_static->ref_supplier = empty($obj->ref_supplier) ? '' : $obj->ref_supplier; + $product_static->label = $obj->label; + $product_static->finished = $obj->finished; + $product_static->type = $obj->fk_product_type; + $product_static->status_buy = $obj->tobuy; + $product_static->status = $obj->tosell; + $product_static->status_batch = $obj->tobatch; + $product_static->entity = $obj->entity; + $product_static->pmp = $obj->pmp; + $product_static->accountancy_code_sell = $obj->accountancy_code_sell; + $product_static->accountancy_code_sell_export = $obj->accountancy_code_sell_export; + $product_static->accountancy_code_sell_intra = $obj->accountancy_code_sell_intra; + $product_static->accountancy_code_buy = $obj->accountancy_code_buy; + $product_static->accountancy_code_buy_intra = $obj->accountancy_code_buy_intra; + $product_static->accountancy_code_buy_export = $obj->accountancy_code_buy_export; + $product_static->length = $obj->length; + $product_static->length_units = $obj->length_units; + $product_static->width = $obj->width; + $product_static->width_units = $obj->width_units; + $product_static->height = $obj->height; + $product_static->height_units = $obj->height_units; + $product_static->weight = $obj->weight; + $product_static->weight_units = $obj->weight_units; + $product_static->volume = $obj->volume; + $product_static->volume_units = $obj->volume_units; + $product_static->surface = $obj->surface; + $product_static->surface_units = $obj->surface_units; + if (!empty($conf->global->PRODUCT_USE_UNITS)) { + $product_static->fk_unit = $obj->fk_unit; + } - $product_static->id = $obj->rowid; - $product_static->ref = $obj->ref; - $product_static->ref_fourn = empty($obj->ref_supplier) ? '' : $obj->ref_supplier; // deprecated - $product_static->ref_supplier = empty($obj->ref_supplier) ? '' : $obj->ref_supplier; - $product_static->label = $obj->label; - $product_static->finished = $obj->finished; - $product_static->type = $obj->fk_product_type; - $product_static->status_buy = $obj->tobuy; - $product_static->status = $obj->tosell; - $product_static->status_batch = $obj->tobatch; - $product_static->entity = $obj->entity; - $product_static->pmp = $obj->pmp; - $product_static->accountancy_code_sell = $obj->accountancy_code_sell; - $product_static->accountancy_code_sell_export = $obj->accountancy_code_sell_export; - $product_static->accountancy_code_sell_intra = $obj->accountancy_code_sell_intra; - $product_static->accountancy_code_buy = $obj->accountancy_code_buy; - $product_static->accountancy_code_buy_intra = $obj->accountancy_code_buy_intra; - $product_static->accountancy_code_buy_export = $obj->accountancy_code_buy_export; - $product_static->length = $obj->length; - $product_static->length_units = $obj->length_units; - $product_static->width = $obj->width; - $product_static->width_units = $obj->width_units; - $product_static->height = $obj->height; - $product_static->height_units = $obj->height_units; - $product_static->weight = $obj->weight; - $product_static->weight_units = $obj->weight_units; - $product_static->volume = $obj->volume; - $product_static->volume_units = $obj->volume_units; - $product_static->surface = $obj->surface; - $product_static->surface_units = $obj->surface_units; - if (!empty($conf->global->PRODUCT_USE_UNITS)) { - $product_static->fk_unit = $obj->fk_unit; - } - - // STOCK_DISABLE_OPTIM_LOAD can be set to force load_stock whatever is permissions on stock. - if ((isModEnabled('stock') && $user->rights->stock->lire && $search_type != 1) || !empty($conf->global->STOCK_DISABLE_OPTIM_LOAD)) { // To optimize call of load_stock - if ($obj->fk_product_type != 1 || !empty($conf->global->STOCK_SUPPORTS_SERVICES)) { // Not a service - $option = 'nobatch'; - if (empty($arrayfields['stock_virtual']['checked'])) { - $option .= ',novirtual'; + // STOCK_DISABLE_OPTIM_LOAD can be set to force load_stock whatever is permissions on stock. + if ((isModEnabled('stock') && $user->rights->stock->lire && $search_type != 1) || !empty($conf->global->STOCK_DISABLE_OPTIM_LOAD)) { // To optimize call of load_stock + if ($product_static->type != 1 || !empty($conf->global->STOCK_SUPPORTS_SERVICES)) { // Not a service + $option = 'nobatch'; + if (empty($arrayfields['stock_virtual']['checked'])) { + $option .= ',novirtual'; + } + $product_static->load_stock($option); // Load stock_reel + stock_warehouse. This can also call load_virtual_stock() } - $product_static->load_stock($option); // Load stock_reel + stock_warehouse. This can also call load_virtual_stock() } } @@ -1454,7 +1467,7 @@ while ($i < min($num, $limit)) { // Label if (!empty($arrayfields['p.label']['checked'])) { - print ''; + print ''; if (!$i) { $totalarray['nbfield']++; } @@ -1464,7 +1477,7 @@ while ($i < min($num, $limit)) { if (!empty($arrayfields['p.fk_product_type']['checked'])) { print ''; + print ''; if (!$i) { $totalarray['nbfield']++; } @@ -1522,7 +1535,7 @@ while ($i < min($num, $limit)) { // Weight if (!empty($arrayfields['p.weight']['checked'])) { print ''; if (!$i) { $totalarray['nbfield']++; @@ -1542,7 +1555,7 @@ while ($i < min($num, $limit)) { // Length if (!empty($arrayfields['p.length']['checked'])) { print ''; if (!$i) { $totalarray['nbfield']++; @@ -1562,7 +1575,7 @@ while ($i < min($num, $limit)) { // Width if (!empty($arrayfields['p.width']['checked'])) { print ''; if (!$i) { $totalarray['nbfield']++; @@ -1582,7 +1595,7 @@ while ($i < min($num, $limit)) { // Height if (!empty($arrayfields['p.height']['checked'])) { print ''; if (!$i) { $totalarray['nbfield']++; @@ -1602,7 +1615,7 @@ while ($i < min($num, $limit)) { // Surface if (!empty($arrayfields['p.surface']['checked'])) { print ''; if (!$i) { $totalarray['nbfield']++; @@ -1622,7 +1635,7 @@ while ($i < min($num, $limit)) { // Volume if (!empty($arrayfields['p.volume']['checked'])) { print ''; if (!$i) { $totalarray['nbfield']++; @@ -1654,7 +1667,7 @@ while ($i < min($num, $limit)) { // Sell price if (!empty($arrayfields['p.sellprice']['checked'])) { print ''; @@ -1799,7 +1812,7 @@ while ($i < min($num, $limit)) { // Desired stock if (!empty($arrayfields['p.desiredstock']['checked'])) { print ''; @@ -1810,7 +1823,7 @@ while ($i < min($num, $limit)) { // Stock real if (!empty($arrayfields['p.stock']['checked'])) { print ''; + print ''; if (!$i) { $totalarray['nbfield']++; } } if (!empty($arrayfields[$alias_product_perentity . '.accountancy_code_sell_intra']['checked'])) { - print ''; + print ''; if (!$i) { $totalarray['nbfield']++; } } if (!empty($arrayfields[$alias_product_perentity . '.accountancy_code_sell_export']['checked'])) { - print ''; + print ''; if (!$i) { $totalarray['nbfield']++; } } // Accountancy code buy if (!empty($arrayfields[$alias_product_perentity . '.accountancy_code_buy']['checked'])) { - print ''; + print ''; if (!$i) { $totalarray['nbfield']++; } } if (!empty($arrayfields[$alias_product_perentity . '.accountancy_code_buy_intra']['checked'])) { - print ''; + print ''; if (!$i) { $totalarray['nbfield']++; } } if (!empty($arrayfields[$alias_product_perentity . '.accountancy_code_buy_export']['checked'])) { - print ''; + print ''; if (!$i) { $totalarray['nbfield']++; } @@ -1935,7 +1948,7 @@ while ($i < min($num, $limit)) { if (!empty($conf->use_javascript_ajax) && $user->hasRight("produit", "creer") && !empty($conf->global->MAIN_DIRECT_STATUS_UPDATE)) { print ajax_object_onoff($product_static, 'status', 'tosell', 'ProductStatusOnSell', 'ProductStatusNotOnSell'); } else { - print $product_static->LibStatut($obj->tosell, 5, 0); + print $product_static->LibStatut($product_static->status, 5, 0); } print ''; if (!$i) { @@ -1948,7 +1961,7 @@ while ($i < min($num, $limit)) { if (!empty($conf->use_javascript_ajax) && $user->hasRight("produit", "creer") && !empty($conf->global->MAIN_DIRECT_STATUS_UPDATE)) { print ajax_object_onoff($product_static, 'status_buy', 'tobuy', 'ProductStatusOnBuy', 'ProductStatusNotOnBuy'); } else { - print $product_static->LibStatut($obj->tobuy, 5, 1); + print $product_static->LibStatut($product_static->status_buy, 5, 1); } print ''; if (!$i) { diff --git a/htdocs/product/note.php b/htdocs/product/note.php index 0d7ad91af5f..ba83e64c401 100644 --- a/htdocs/product/note.php +++ b/htdocs/product/note.php @@ -54,13 +54,13 @@ $permissionnote = $user->rights->produit->creer; // Used by the include of actio if ($object->id > 0) { if ($object->type == $object::TYPE_PRODUCT) { - restrictedArea($user, 'produit', $object->id, 'product&product', '', ''); + restrictedArea($user, 'product', $object->id, 'product&product', '', ''); } if ($object->type == $object::TYPE_SERVICE) { restrictedArea($user, 'service', $object->id, 'product&product', '', ''); } } else { - restrictedArea($user, 'produit|service', $fieldvalue, 'product&product', '', '', $fieldtype); + restrictedArea($user, 'product|service', $fieldvalue, 'product&product', '', '', $fieldtype); } diff --git a/htdocs/product/price.php b/htdocs/product/price.php index d7005fa439a..cde676c9732 100644 --- a/htdocs/product/price.php +++ b/htdocs/product/price.php @@ -136,6 +136,7 @@ if (empty($reshook)) { $npr = preg_match('/\*/', $tva_tx_txt) ? 1 : 0; $localtax1 = 0; $localtax2 = 0; $localtax1_type = '0'; $localtax2_type = '0'; // If value contains the unique code of vat line (new recommanded method), we use it to find npr and local taxes + if (preg_match('/\((.*)\)/', $tva_tx_txt, $reg)) { // We look into database using code (we can't use get_localtax() because it depends on buyer that is not known). Same in create product. $vatratecode = $reg[1]; @@ -229,7 +230,7 @@ if (empty($reshook)) { $oldnpr = $object->tva_npr; //$localtaxarray=array('0'=>$localtax1_type,'1'=>$localtax1,'2'=>$localtax2_type,'3'=>$localtax2); - $localtaxarray = array(); // We do not store localtaxes into product, we will use instead the "vat code" to retrieve them. + $localtaxarray = array(); // We do not store localtaxes into product, we will use instead the "vat code" to retrieve them when required. $level = 0; $ret = $object->updatePrice($oldprice, $oldpricebasetype, $user, $tva_tx, $oldminprice, $level, $oldnpr, 0, 0, $localtaxarray, $vatratecode); @@ -877,7 +878,7 @@ dol_banner_tab($object, 'ref', $linkback, $shownav, 'ref'); print '
'; print '
'; -print '
'; + $searchpicto = $form->showFilterButtons('left'); + print $searchpicto; + print ''; -$searchpicto = $form->showFilterButtons(); -print $searchpicto; -print ''; + $searchpicto = $form->showFilterButtons(); + print $searchpicto; + print '
'; + if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined + $selected = 0; + if (in_array($object->id, $arrayofselected)) { + $selected = 1; + } + print ''; + } + print ''; - if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined - $selected = 0; - if (in_array($object->id, $arrayofselected)) { - $selected = 1; + if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print ''; + if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined + $selected = 0; + if (in_array($object->id, $arrayofselected)) { + $selected = 1; + } + print ''; } - print ''; + print ''.$obj->label.''.$product_static->label.''; $s = ''; - if ($obj->fk_product_type == 0) { + if ($product_static->type == 0) { $s .= img_picto($langs->trans("Product"), 'product', 'class="paddingleftonly paddingrightonly colorgrey"'); } else { $s .= img_picto($langs->trans("Service"), 'service', 'class="paddingleftonly paddingrightonly colorgrey"'); @@ -1478,7 +1491,7 @@ while ($i < min($num, $limit)) { // Barcode if (!empty($arrayfields['p.barcode']['checked'])) { - print ''.$obj->barcode.''.$product_static->barcode.''; - print $obj->weight; + print $product_static->weight; print ''; - print $obj->length; + print $product_static->length; print ''; - print $obj->width; + print $product_static->width; print ''; - print $obj->height; + print $product_static->height; print ''; - print $obj->surface; + print $product_static->surface; print ''; - print $obj->volume; + print $product_static->volume; print ''; - if ($obj->tosell && $usercancreadprice) { + if ($product_static->status && $usercancreadprice) { if ($obj->price_base_type == 'TTC') { print ''.price($obj->price_ttc).' '.$langs->trans("TTC").''; } else { @@ -1677,7 +1690,7 @@ while ($i < min($num, $limit)) { $productpricescache[$obj->rowid] = array(); } - if ($obj->tosell && $usercancreadprice) { + if ($product_static->status && $usercancreadprice) { // Make 1 request for all price levels (without filter on price_level) and saved result into an cache array // then reuse the cache array if we need prices for other price levels $sqlp = "SELECT p.rowid, p.fk_product, p.price, p.price_ttc, p.price_level, p.date_price, p.price_base_type"; @@ -1727,7 +1740,7 @@ while ($i < min($num, $limit)) { // Better buy price if (!empty($arrayfields['p.minbuyprice']['checked'])) { print ''; - if ($obj->tobuy && $obj->bestpurchaseprice != '' && $usercancreadprice) { + if ($product_static->status_buy && $obj->bestpurchaseprice != '' && $usercancreadprice) { if ($product_fourn->find_min_price_product_fournisseur($obj->rowid) > 0) { if ($product_fourn->product_fourn_price_id > 0) { if ((isModEnabled("fournisseur") && !empty($user->rights->fournisseur->lire) && empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)) || (isModEnabled("supplier_order") && !empty($user->rights->supplier_order->lire)) || (isModEnabled("supplier_invoice") && !empty($user->rights->supplier_invoice->lire))) { @@ -1748,7 +1761,7 @@ while ($i < min($num, $limit)) { // Number of buy prices if (!empty($arrayfields['p.numbuyprice']['checked'])) { print ''; - if ($obj->tobuy && $usercancreadprice) { + if ($product_static->status_buy && $usercancreadprice) { if (count($productFournList = $product_fourn->list_product_fournisseur_price($obj->rowid)) > 0) { $htmltext = $product_fourn->display_price_product_fournisseur(1, 1, 0, 1, $productFournList); print $form->textwithpicto(count($productFournList), $htmltext); @@ -1788,7 +1801,7 @@ while ($i < min($num, $limit)) { // Limit alert if (!empty($arrayfields['p.seuil_stock_alerte']['checked'])) { print ''; - if ($obj->fk_product_type != 1) { + if ($product_static->type != 1) { print $obj->seuil_stock_alerte; } print ''; - if ($obj->fk_product_type != 1) { + if ($product_static->type != 1) { print $obj->desiredstock; } print ''; - if ($obj->fk_product_type != 1) { + if ($product_static->type != 1) { if ($obj->seuil_stock_alerte != '' && $product_static->stock_reel < (float) $obj->seuil_stock_alerte) { print img_warning($langs->trans("StockLowerThanLimit", $obj->seuil_stock_alerte)).' '; } @@ -1826,7 +1839,7 @@ while ($i < min($num, $limit)) { // Stock virtual if (!empty($arrayfields['stock_virtual']['checked'])) { print ''; - if ($obj->fk_product_type != 1) { + if ($product_static->type != 1) { if ($obj->seuil_stock_alerte != '' && $product_static->stock_theorique < (float) $obj->seuil_stock_alerte) { print img_warning($langs->trans("StockLowerThanLimit", $obj->seuil_stock_alerte)).' '; } @@ -1868,38 +1881,38 @@ while ($i < min($num, $limit)) { } // Accountancy code sell if (!empty($arrayfields[$alias_product_perentity . '.accountancy_code_sell']['checked'])) { - print ''.$obj->accountancy_code_sell.''.$product_static->accountancy_code_sell.''.$obj->accountancy_code_sell_intra.''.$product_static->accountancy_code_sell_intra.''.$obj->accountancy_code_sell_export.''.$product_static->accountancy_code_sell_export.''.$obj->accountancy_code_buy.''.$product_static->accountancy_code_buy.''.$obj->accountancy_code_buy_intra.''.$product_static->accountancy_code_buy_intra.''.$obj->accountancy_code_buy_export.''.$product_static->accountancy_code_buy_export.'
'; +print '
'; // Price per customer segment/level if (!empty($conf->global->PRODUIT_MULTIPRICES) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) { @@ -1000,6 +1001,7 @@ if (!empty($conf->global->PRODUIT_MULTIPRICES) || !empty($conf->global->PRODUIT_ print ''; print '
'.$langs->trans("DefaultTaxRate").''; + // TODO We show localtax from $object, but this properties may not be correct. Only value $object->default_vat_code is guaranted. $positiverates = ''; if (price2num($object->tva_tx)) { $positiverates .= ($positiverates ? '/' : '').price2num($object->tva_tx); @@ -1013,6 +1015,7 @@ if (!empty($conf->global->PRODUIT_MULTIPRICES) || !empty($conf->global->PRODUIT_ if (empty($positiverates)) { $positiverates = '0'; } + print vatrate($positiverates.($object->default_vat_code ? ' ('.$object->default_vat_code.')' : ''), true, $object->tva_npr, 1); /* if ($object->default_vat_code) @@ -1026,7 +1029,7 @@ if (!empty($conf->global->PRODUIT_MULTIPRICES) || !empty($conf->global->PRODUIT_ print '
'; - print ''; + print '
'; print ''; } diff --git a/htdocs/product/stock/movement_list.php b/htdocs/product/stock/movement_list.php index 56030347d12..c6a3727557b 100644 --- a/htdocs/product/stock/movement_list.php +++ b/htdocs/product/stock/movement_list.php @@ -619,6 +619,9 @@ $parameters = array(); $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters); // Note that $action and $object may have been modified by hook $sql .= preg_replace('/^,/', '', $hookmanager->resPrint); $sql = preg_replace('/,\s*$/', '', $sql); + +$sqlfields = $sql; // $sql fields to remove for count total + $sql .= " FROM ".MAIN_DB_PREFIX."entrepot as e,"; $sql .= " ".MAIN_DB_PREFIX."product as p,"; $sql .= " ".MAIN_DB_PREFIX."stock_mouvement as m"; @@ -690,24 +693,22 @@ include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php'; $parameters = array(); $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters); // Note that $action and $object may have been modified by hook $sql .= $hookmanager->resPrint; + // Count total nb of records $nbtotalofrecords = ''; if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { - /* This old and fast method to get and count full list returns all record so use a high amount of memory. - $resql = $db->query($sql); - $nbtotalofrecords = $db->num_rows($resql); - */ - /* The slow method does not consume memory on mysql (not tested on pgsql) */ - /*$resql = $db->query($sql, 0, 'auto', 1); - while ($db->fetch_object($resql)) { - $nbtotalofrecords++; - }*/ /* The fast and low memory method to get and count full list converts the sql into a sql count */ - $sqlforcount = preg_replace('/^SELECT[a-zA-Z0-9\._\s\(\),=<>\:\-\']+\sFROM/Ui', 'SELECT COUNT(*) as nbtotalofrecords FROM', $sql); + $sqlforcount = preg_replace('/^'.preg_quote($sqlfields, '/').'/', 'SELECT COUNT(*) as nbtotalofrecords', $sql); + $sqlforcount = preg_replace('/GROUP BY .*$/', '', $sqlforcount); $resql = $db->query($sqlforcount); - $objforcount = $db->fetch_object($resql); - $nbtotalofrecords = $objforcount->nbtotalofrecords; - if (($page * $limit) > $nbtotalofrecords) { // if total of record found is smaller than page * limit, goto and load page 0 + if ($resql) { + $objforcount = $db->fetch_object($resql); + $nbtotalofrecords = $objforcount->nbtotalofrecords; + } else { + dol_print_error($db); + } + + if (($page * $limit) > $nbtotalofrecords) { // if total resultset is smaller then paging size (filtering), goto and load page 0 $page = 0; $offset = 0; } diff --git a/htdocs/product/stock/replenish.php b/htdocs/product/stock/replenish.php index be7f006d5a0..d1644623ce1 100644 --- a/htdocs/product/stock/replenish.php +++ b/htdocs/product/stock/replenish.php @@ -465,7 +465,7 @@ if ($usevirtualstock) { $sqlProductionToConsume .= " ".MAIN_DB_PREFIX."mrp_production as mp5"; $sqlProductionToConsume .= " WHERE mm5.rowid = mp5.fk_mo AND mm5.entity IN (".getEntity(!empty($conf->global->STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE) ? 'stock' : 'mo').")"; $sqlProductionToConsume .= " AND mp5.fk_product = p.rowid"; - $sqlProductionToConsume .= " AND mp5.role IN ('toconsume', 'consummed')"; + $sqlProductionToConsume .= " AND mp5.role IN ('toconsume', 'consumed')"; $sqlProductionToConsume .= " AND mm5.status IN (1,2))"; $sqlProductionToProduce = "(SELECT GREATEST(0, ".$db->ifsql("SUM(".$db->ifsql("mp5.role = 'toproduce'", 'mp5.qty', '- mp5.qty').") IS NULL", "0", "SUM(".$db->ifsql("mp5.role = 'toproduce'", 'mp5.qty', '- mp5.qty').")").") as qty"; // We need the ifsql because if result is 0 for product p.rowid, we must return 0 and not NULL diff --git a/htdocs/projet/activity/permonth.php b/htdocs/projet/activity/permonth.php index 273affc3563..49849b362ba 100644 --- a/htdocs/projet/activity/permonth.php +++ b/htdocs/projet/activity/permonth.php @@ -419,7 +419,7 @@ if (!empty($conf->categorie->enabled)) // If the user can view user other than himself $moreforfilter .= '
'; $moreforfilter .= '
'; -$includeonly = 'hierachyme'; +$includeonly = 'hierarchyme'; if (empty($user->rights->user->user->lire)) { $includeonly = array($user->id); } diff --git a/htdocs/projet/class/api_tasks.class.php b/htdocs/projet/class/api_tasks.class.php index 0eaf8654421..cd232061bc4 100644 --- a/htdocs/projet/class/api_tasks.class.php +++ b/htdocs/projet/class/api_tasks.class.php @@ -544,7 +544,7 @@ class Tasks extends DolibarrApi $this->task->timespent_datehour = $newdate; $this->task->timespent_withhour = 1; $this->task->timespent_duration = $duration; - $this->task->timespent_fk_user = $user_id; + $this->task->timespent_fk_user = $uid; $this->task->timespent_note = $note; $result = $this->task->addTimeSpent(DolibarrApiAccess::$user, 0); diff --git a/htdocs/projet/class/project.class.php b/htdocs/projet/class/project.class.php index e3865663bf7..9c8b4ebee26 100644 --- a/htdocs/projet/class/project.class.php +++ b/htdocs/projet/class/project.class.php @@ -306,9 +306,9 @@ class Project extends CommonObject 'tms' =>array('type'=>'timestamp', 'label'=>'DateModificationShort', 'enabled'=>1, 'visible'=>-2, 'notnull'=>1, 'position'=>405), 'fk_user_creat' =>array('type'=>'integer', 'label'=>'UserCreation', 'enabled'=>1, 'visible'=>0, 'notnull'=>1, 'position'=>410), 'fk_user_modif' =>array('type'=>'integer', 'label'=>'UserModification', 'enabled'=>1, 'visible'=>0, 'position'=>415), - 'import_key' =>array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>0, 'position'=>420), + 'import_key' =>array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-1, 'position'=>420), 'email_msgid'=>array('type'=>'varchar(255)', 'label'=>'EmailMsgID', 'enabled'=>1, 'visible'=>-1, 'position'=>450, 'help'=>'EmailMsgIDWhenSourceisEmail'), - 'fk_statut' =>array('type'=>'smallint(6)', 'label'=>'Status', 'enabled'=>1, 'visible'=>1, 'notnull'=>1, 'position'=>500) + 'fk_statut' =>array('type'=>'smallint(6)', 'label'=>'Status', 'enabled'=>1, 'visible'=>1, 'notnull'=>1, 'position'=>500), ); // END MODULEBUILDER PROPERTIES @@ -435,6 +435,7 @@ class Project extends CommonObject $sql .= ", note_private"; $sql .= ", note_public"; $sql .= ", entity"; + $sql .= ", ip"; $sql .= ") VALUES ("; $sql .= "'".$this->db->escape($this->ref)."'"; $sql .= ", '".$this->db->escape($this->title)."'"; @@ -466,6 +467,7 @@ class Project extends CommonObject $sql .= ", ".($this->note_private ? "'".$this->db->escape($this->note_private)."'" : 'null'); $sql .= ", ".($this->note_public ? "'".$this->db->escape($this->note_public)."'" : 'null'); $sql .= ", ".((int) $conf->entity); + $sql .= ", ".(!isset($this->ip) ? 'NULL' : "'".$this->db->escape($this->ip)."'"); $sql .= ")"; dol_syslog(get_class($this)."::create", LOG_DEBUG); diff --git a/htdocs/projet/class/task.class.php b/htdocs/projet/class/task.class.php index b751d8d1e8e..ef04862eb71 100644 --- a/htdocs/projet/class/task.class.php +++ b/htdocs/projet/class/task.class.php @@ -2203,7 +2203,7 @@ class Task extends CommonObjectLine $sql .= " t.rowid as taskid, t.progress as progress, t.fk_statut as status,"; $sql .= " t.dateo as date_start, t.datee as datee"; $sql .= " FROM ".MAIN_DB_PREFIX."projet as p"; - $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s on p.fk_soc = s.rowid"; + //$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s on p.fk_soc = s.rowid"; //if (! $user->rights->societe->client->voir && ! $socid) $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON sc.fk_soc = s.rowid"; $sql .= ", ".MAIN_DB_PREFIX."projet_task as t"; $sql .= " WHERE p.entity IN (".getEntity('project', 0).')'; diff --git a/htdocs/projet/class/taskstats.class.php b/htdocs/projet/class/taskstats.class.php index a5b088f01e8..5794d585101 100644 --- a/htdocs/projet/class/taskstats.class.php +++ b/htdocs/projet/class/taskstats.class.php @@ -193,4 +193,35 @@ class TaskStats extends Stats // var_dump($res);print '
'; return $res; } + + + /** + * Return the Task amount by month for a year + * + * @param int $year Year to scan + * @param int $format 0=Label of abscissa is a translated text, 1=Label of abscissa is month number, 2=Label of abscissa is first letter of month + * @return array Array with amount by month + */ + public function getAmountByMonth($year, $format = 0) + { + // Return an empty array at the moment because task has no amount + return array(); + } + + /** + * Return average of entity by month + * @param int $year year number + * @return int value + */ + protected function getAverageByMonth($year) + { + $sql = "SELECT date_format(datef,'%m') as dm, AVG(f.".$this->field.")"; + $sql .= " FROM ".$this->from; + $sql .= " WHERE f.datef BETWEEN '".$this->db->idate(dol_get_first_day($year))."' AND '".$this->db->idate(dol_get_last_day($year))."'"; + $sql .= " AND ".$this->where; + $sql .= " GROUP BY dm"; + $sql .= $this->db->order('dm', 'DESC'); + + return $this->_getAverageByMonth($year, $sql); + } } diff --git a/htdocs/projet/list.php b/htdocs/projet/list.php index 1d1ad691505..b31666245d4 100644 --- a/htdocs/projet/list.php +++ b/htdocs/projet/list.php @@ -113,6 +113,13 @@ $search_accept_booth_suggestions = GETPOST('search_accept_booth_suggestions', 'i $search_price_registration = GETPOST("search_price_registration", 'alpha'); $search_price_booth = GETPOST("search_price_booth", 'alpha'); $search_login = GETPOST('search_login', 'alpha'); +$searchCategoryCustomerOperator = 0; +if (GETPOSTISSET('formfilteraction')) { + $searchCategoryCustomerOperator = GETPOST('search_category_customer_operator', 'int'); +} elseif (!empty($conf->global->MAIN_SEARCH_CAT_OR_BY_DEFAULT)) { + $searchCategoryCustomerOperator = $conf->global->MAIN_SEARCH_CAT_OR_BY_DEFAULT; +} +$searchCategoryCustomerList = GETPOST('search_category_customer_list', 'array'); $optioncss = GETPOST('optioncss', 'alpha'); $mine = ((GETPOST('mode') == 'mine') ? 1 : 0); @@ -407,7 +414,7 @@ $distinct = 'DISTINCT'; // We add distinct until we are added a protection to be $sql = "SELECT ".$distinct." p.rowid as id, p.ref, p.title, p.fk_statut as status, p.fk_opp_status, p.public, p.fk_user_creat,"; $sql .= " p.datec as date_creation, p.dateo as date_start, p.datee as date_end, p.opp_amount, p.opp_percent, (p.opp_amount*p.opp_percent/100) as opp_weighted_amount, p.tms as date_update, p.budget_amount,"; $sql .= " p.usage_opportunity, p.usage_task, p.usage_bill_time, p.usage_organize_event,"; -$sql .= " p.email_msgid,"; +$sql .= " p.email_msgid, p.import_key,"; $sql .= " p.accept_conference_suggestions, p.accept_booth_suggestions, p.price_registration, p.price_booth,"; $sql .= " s.rowid as socid, s.nom as name, s.name_alias as alias, s.email, s.email, s.phone, s.fax, s.address, s.town, s.zip, s.fk_pays, s.client, s.code_client,"; $sql .= " country.code as country_code,"; @@ -594,6 +601,50 @@ if (!empty($searchCategoryProjectList)) { } } } +$searchCategoryCustomerSqlList = array(); +if ($searchCategoryCustomerOperator == 1) { + $existsCategoryCustomerList = array(); + foreach ($searchCategoryCustomerList as $searchCategoryCustomer) { + if (intval($searchCategoryCustomer) == -2) { + $sqlCategoryCustomerNotExists = " NOT EXISTS ("; + $sqlCategoryCustomerNotExists .= " SELECT cat_cus.fk_soc"; + $sqlCategoryCustomerNotExists .= " FROM ".$db->prefix()."categorie_societe AS cat_cus"; + $sqlCategoryCustomerNotExists .= " WHERE cat_cus.fk_soc = p.fk_soc"; + $sqlCategoryCustomerNotExists .= " )"; + $searchCategoryCustomerSqlList[] = $sqlCategoryCustomerNotExists; + } elseif (intval($searchCategoryCustomer) > 0) { + $existsCategoryCustomerList[] = $db->escape($searchCategoryCustomer); + } + } + if (!empty($existsCategoryCustomerList)) { + $sqlCategoryCustomerExists = " EXISTS ("; + $sqlCategoryCustomerExists .= " SELECT cat_cus.fk_soc"; + $sqlCategoryCustomerExists .= " FROM ".$db->prefix()."categorie_societe AS cat_cus"; + $sqlCategoryCustomerExists .= " WHERE cat_cus.fk_soc = p.fk_soc"; + $sqlCategoryCustomerExists .= " AND cat_cus.fk_categorie IN (".$db->sanitize(implode(',', $existsCategoryCustomerList)).")"; + $sqlCategoryCustomerExists .= " )"; + $searchCategoryCustomerSqlList[] = $sqlCategoryCustomerExists; + } + if (!empty($searchCategoryCustomerSqlList)) { + $sql .= " AND (".implode(' OR ', $searchCategoryCustomerSqlList).")"; + } +} else { + foreach ($searchCategoryCustomerList as $searchCategoryCustomer) { + if (intval($searchCategoryCustomer) == -2) { + $sqlCategoryCustomerNotExists = " NOT EXISTS ("; + $sqlCategoryCustomerNotExists .= " SELECT cat_cus.fk_soc"; + $sqlCategoryCustomerNotExists .= " FROM ".$db->prefix()."categorie_societe AS cat_cus"; + $sqlCategoryCustomerNotExists .= " WHERE cat_cus.fk_soc = p.fk_soc"; + $sqlCategoryCustomerNotExists .= " )"; + $searchCategoryCustomerSqlList[] = $sqlCategoryCustomerNotExists; + } elseif (intval($searchCategoryCustomer) > 0) { + $searchCategoryCustomerSqlList[] = "p.fk_soc IN (SELECT fk_soc FROM ".$db->prefix()."categorie_societe WHERE fk_categorie = ".((int) $searchCategoryCustomer).")"; + } + } + if (!empty($searchCategoryCustomerSqlList)) { + $sql .= " AND (".implode(' AND ', $searchCategoryCustomerSqlList).")"; + } +} // Add where from extra fields include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php'; // Add where from hooks @@ -794,6 +845,9 @@ if ($search_login) { if ($optioncss != '') { $param .= '&optioncss='.urlencode($optioncss); } +foreach ($searchCategoryCustomerList as $searchCategoryCustomer) { + $param .= "&search_category_customer_list[]=".urlencode($searchCategoryCustomer); +} // Add $param from extra fields include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php'; @@ -900,6 +954,18 @@ if (isModEnabled('categorie') && $user->rights->categorie->lire) { $formcategory = new FormCategory($db); $moreforfilter .= $formcategory->getFilterBox(Categorie::TYPE_PROJECT, $search_category_array); } +// Filter on customer categories +if (!empty($conf->global->MAIN_SEARCH_CATEGORY_CUSTOMER_ON_PROJECT_LIST) && !empty($conf->categorie->enabled) && $user->rights->categorie->lire) { + $moreforfilter .= '
'; + $tmptitle = $langs->transnoentities('CustomersProspectsCategoriesShort'); + $moreforfilter .= img_picto($tmptitle, 'category', 'class="pictofixedwidth"'); + $categoriesArr = $form->select_all_categories(Categorie::TYPE_CUSTOMER, '', '', 64, 0, 1); + $categoriesArr[-2] = '- '.$langs->trans('NotCategorized').' -'; + $moreforfilter .= Form::multiselectarray('search_category_customer_list', $categoriesArr, $searchCategoryCustomerList, 0, 0, 'minwidth300', 0, 0, '', 'category', $tmptitle); + $moreforfilter .= ' '; + $moreforfilter .= $form->textwithpicto('', $langs->trans('UseOrOperatorForCategories') . ' : ' . $tmptitle, 1, 'help', '', 0, 2, 'tooltip_cat_cus'); // Tooltip on click + $moreforfilter .= '
'; +} if (!empty($moreforfilter)) { print '
'; @@ -1104,6 +1170,11 @@ if (!empty($arrayfields['p.email_msgid']['checked'])) { print '
'; } +if (!empty($arrayfields['p.import_key']['checked'])) { + // Import key + print ''; +} if (!empty($arrayfields['p.fk_statut']['checked'])) { print ''; } @@ -1212,6 +1283,9 @@ if (!empty($arrayfields['p.tms']['checked'])) { if (!empty($arrayfields['p.email_msgid']['checked'])) { print_liste_field_titre($arrayfields['p.email_msgid']['label'], $_SERVER["PHP_SELF"], "p.email_msgid", "", $param, '', $sortfield, $sortorder, 'center '); } +if (!empty($arrayfields['p.import_key']['checked'])) { + print_liste_field_titre($arrayfields['p.import_key']['label'], $_SERVER["PHP_SELF"], "p.import_key", "", $param, '', $sortfield, $sortorder, ''); +} if (!empty($arrayfields['p.fk_statut']['checked'])) { print_liste_field_titre($arrayfields['p.fk_statut']['label'], $_SERVER["PHP_SELF"], "p.fk_statut", "", $param, '', $sortfield, $sortorder, 'right '); } @@ -1665,6 +1739,13 @@ while ($i < $imaxinloop) { print ''; if (!$i) $totalarray['nbfield']++; } + // Import key + if (!empty($arrayfields['p.import_key']['checked'])) { + print ''; + if (!$i) { + $totalarray['nbfield']++; + } + } // Status if (!empty($arrayfields['p.fk_statut']['checked'])) { print ''; diff --git a/htdocs/projet/tasks/list.php b/htdocs/projet/tasks/list.php index fdec5c6a958..f7ba2cc89f4 100644 --- a/htdocs/projet/tasks/list.php +++ b/htdocs/projet/tasks/list.php @@ -70,6 +70,13 @@ $search_task_budget_amount = GETPOST('search_task_budget_amount'); $search_societe = GETPOST('search_societe'); $search_societe_alias = GETPOST('search_societe_alias'); $search_opp_status = GETPOST("search_opp_status", 'alpha'); +$searchCategoryCustomerOperator = 0; +if (GETPOSTISSET('formfilteraction')) { + $searchCategoryCustomerOperator = GETPOST('search_category_customer_operator', 'int'); +} elseif (!empty($conf->global->MAIN_SEARCH_CAT_OR_BY_DEFAULT)) { + $searchCategoryCustomerOperator = $conf->global->MAIN_SEARCH_CAT_OR_BY_DEFAULT; +} +$searchCategoryCustomerList = GETPOST('search_category_customer_list', 'array'); $mine = GETPOST('mode', 'alpha') == 'mine' ? 1 : 0; if ($mine) { @@ -235,6 +242,7 @@ if (empty($reshook)) { $search_datelimit_start = ''; $search_datelimit_end = ''; $toselect = array(); + $searchCategoryCustomerList = array(); $search_array_options = array(); } @@ -464,6 +472,50 @@ if (!empty($searchCategoryProjectList)) { } } } +$searchCategoryCustomerSqlList = array(); +if ($searchCategoryCustomerOperator == 1) { + $existsCategoryCustomerList = array(); + foreach ($searchCategoryCustomerList as $searchCategoryCustomer) { + if (intval($searchCategoryCustomer) == -2) { + $sqlCategoryCustomerNotExists = " NOT EXISTS ("; + $sqlCategoryCustomerNotExists .= " SELECT cat_cus.fk_soc"; + $sqlCategoryCustomerNotExists .= " FROM ".$db->prefix()."categorie_societe AS cat_cus"; + $sqlCategoryCustomerNotExists .= " WHERE cat_cus.fk_soc = p.fk_soc"; + $sqlCategoryCustomerNotExists .= " )"; + $searchCategoryCustomerSqlList[] = $sqlCategoryCustomerNotExists; + } elseif (intval($searchCategoryCustomer) > 0) { + $existsCategoryCustomerList[] = $db->escape($searchCategoryCustomer); + } + } + if (!empty($existsCategoryCustomerList)) { + $sqlCategoryCustomerExists = " EXISTS ("; + $sqlCategoryCustomerExists .= " SELECT cat_cus.fk_soc"; + $sqlCategoryCustomerExists .= " FROM ".$db->prefix()."categorie_societe AS cat_cus"; + $sqlCategoryCustomerExists .= " WHERE cat_cus.fk_soc = p.fk_soc"; + $sqlCategoryCustomerExists .= " AND cat_cus.fk_categorie IN (".$db->sanitize(implode(',', $existsCategoryCustomerList)).")"; + $sqlCategoryCustomerExists .= " )"; + $searchCategoryCustomerSqlList[] = $sqlCategoryCustomerExists; + } + if (!empty($searchCategoryCustomerSqlList)) { + $sql .= " AND (".implode(' OR ', $searchCategoryCustomerSqlList).")"; + } +} else { + foreach ($searchCategoryCustomerList as $searchCategoryCustomer) { + if (intval($searchCategoryCustomer) == -2) { + $sqlCategoryCustomerNotExists = " NOT EXISTS ("; + $sqlCategoryCustomerNotExists .= " SELECT cat_cus.fk_soc"; + $sqlCategoryCustomerNotExists .= " FROM ".$db->prefix()."categorie_societe AS cat_cus"; + $sqlCategoryCustomerNotExists .= " WHERE cat_cus.fk_soc = p.fk_soc"; + $sqlCategoryCustomerNotExists .= " )"; + $searchCategoryCustomerSqlList[] = $sqlCategoryCustomerNotExists; + } elseif (intval($searchCategoryCustomer) > 0) { + $searchCategoryCustomerSqlList[] = "p.fk_soc IN (SELECT fk_soc FROM ".$db->prefix()."categorie_societe WHERE fk_categorie = ".((int) $searchCategoryCustomer).")"; + } + } + if (!empty($searchCategoryCustomerSqlList)) { + $sql .= " AND (".implode(' AND ', $searchCategoryCustomerSqlList).")"; + } +} // Add where from extra fields include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php'; // Add where from hooks @@ -617,6 +669,9 @@ if ($search_task_user > 0) { if ($optioncss != '') { $param .= '&optioncss='.urlencode($optioncss); } +foreach ($searchCategoryCustomerList as $searchCategoryCustomer) { + $param .= "&search_category_customer_list[]=".urlencode($searchCategoryCustomer); +} // Add $param from extra fields include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php'; // Add $param from hooks @@ -712,6 +767,19 @@ if (empty($user->rights->user->user->lire)) { $moreforfilter .= img_picto($tmptitle, 'user', 'class="pictofixedwidth"').$form->select_dolusers($search_task_user, 'search_task_user', $tmptitle, '', 0, $includeonly, '', 0, 0, 0, '', 0, '', 'maxwidth250'); $moreforfilter .= ''; +// Filter on customer categories +if (!empty($conf->global->MAIN_SEARCH_CATEGORY_CUSTOMER_ON_TASK_LIST) && !empty($conf->categorie->enabled) && $user->rights->categorie->lire) { + $moreforfilter .= '
'; + $tmptitle = $langs->transnoentities('CustomersProspectsCategoriesShort'); + $moreforfilter .= img_picto($tmptitle, 'category', 'class="pictofixedwidth"'); + $categoriesArr = $form->select_all_categories(Categorie::TYPE_CUSTOMER, '', '', 64, 0, 1); + $categoriesArr[-2] = '- '.$langs->trans('NotCategorized').' -'; + $moreforfilter .= Form::multiselectarray('search_category_customer_list', $categoriesArr, $searchCategoryCustomerList, 0, 0, 'minwidth300', 0, 0, '', 'category', $tmptitle); + $moreforfilter .= ' '; + $moreforfilter .= $form->textwithpicto('', $langs->trans('UseOrOperatorForCategories') . ' : ' . $tmptitle, 1, 'help', '', 0, 2, 'tooltip_cat_cus'); // Tooltip on click + $moreforfilter .= '
'; +} + if (!empty($moreforfilter)) { print '
'; print $moreforfilter; diff --git a/htdocs/projet/tasks/time.php b/htdocs/projet/tasks/time.php index 8e30664232b..fce9813987c 100644 --- a/htdocs/projet/tasks/time.php +++ b/htdocs/projet/tasks/time.php @@ -54,6 +54,7 @@ $toselect = GETPOST('toselect', 'array'); // Array of ids of elements selected i $contextpage = GETPOST('contextpage', 'aZ') ?GETPOST('contextpage', 'aZ') : 'timespentlist'; // To manage different context of search $backtopage = GETPOST('backtopage', 'alpha'); // Go back to a dedicated page $optioncss = GETPOST('optioncss', 'alpha'); +$mode = GETPOST('mode', 'alpha'); $id = GETPOST('id', 'int'); $projectid = GETPOST('projectid', 'int'); @@ -67,6 +68,14 @@ $search_month = GETPOST('search_month', 'int'); $search_year = GETPOST('search_year', 'int'); $search_datehour = ''; $search_datewithhour = ''; +$search_date_startday = GETPOST('search_date_startday', 'int'); +$search_date_startmonth = GETPOST('search_date_startmonth', 'int'); +$search_date_startyear = GETPOST('search_date_startyear', 'int'); +$search_date_endday = GETPOST('search_date_endday', 'int'); +$search_date_endmonth = GETPOST('search_date_endmonth', 'int'); +$search_date_endyear = GETPOST('search_date_endyear', 'int'); +$search_date_start = dol_mktime(0, 0, 0, $search_date_startmonth, $search_date_startday, $search_date_startyear); // Use tzserver +$search_date_end = dol_mktime(23, 59, 59, $search_date_endmonth, $search_date_endday, $search_date_endyear); $search_note = GETPOST('search_note', 'alpha'); $search_duration = GETPOST('search_duration', 'int'); $search_value = GETPOST('search_value', 'int'); @@ -76,6 +85,9 @@ $search_user = GETPOST('search_user', 'int'); $search_valuebilled = GETPOST('search_valuebilled', 'int'); $search_product_ref = GETPOST('search_product_ref', 'alpha'); $search_company = GETPOST('$search_company', 'alpha'); +$search_company_alias = GETPOST('$search_company_alias', 'alpha'); +$search_project_ref = GETPOST('$search_project_ref', 'alpha'); +$search_project_label = GETPOST('$search_project_label', 'alpha'); $limit = GETPOST('limit', 'int') ?GETPOST('limit', 'int') : $conf->liste_limit; $sortfield = GETPOST('sortfield', 'aZ09comma'); @@ -165,8 +177,19 @@ if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x' $search_value = ''; $search_date_creation = ''; $search_date_update = ''; + $search_date_startday = ''; + $search_date_startmonth = ''; + $search_date_startyear = ''; + $search_date_endday = ''; + $search_date_endmonth = ''; + $search_date_endyear = ''; + $search_date_start = ''; + $search_date_end = ''; $search_task_ref = ''; $search_company = ''; + $search_company_alias = ''; + $search_project_ref = ''; + $search_project_label = ''; $search_task_label = ''; $search_user = 0; $search_valuebilled = ''; @@ -323,10 +346,10 @@ if (($action == 'updateline' || $action == 'updatesplitline') && !$cancel && $us } } -if ($action == 'confirm_deleteline' && $confirm == "yes" && $user->rights->projet->supprimer) { - $object->fetchTimeSpent(GETPOST('lineid', 'int')); // load properties like $object->timespent_id +if ($action == 'confirm_deleteline' && $confirm == "yes" && ($user->hasRight('projet', 'time') || $user->hasRight('projet', 'all', 'creer'))) { + $object->fetchTimeSpent(GETPOST('lineid', 'int')); // load properties like $object->timespent_xxx - if (in_array($object->timespent_fk_user, $childids) || $user->rights->projet->all->creer) { + if (in_array($object->timespent_fk_user, $childids) || $user->hasRight('projet', 'all', 'creer')) { $result = $object->delTimeSpent($user); // delete line with $object->timespent_id if ($result < 0) { @@ -1219,7 +1242,12 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser $arrayfields = array(); $arrayfields['t.task_date'] = array('label'=>$langs->trans("Date"), 'checked'=>1); $arrayfields['p.fk_soc'] = array('label'=>$langs->trans("ThirdParty"), 'type'=>'integer:Societe:/societe/class/societe.class.php:1','checked'=>1); + $arrayfields['s.name_alias'] = array('label'=>$langs->trans("AliasNameShort"), 'type'=>'integer:Societe:/societe/class/societe.class.php:1'); if ((empty($id) && empty($ref)) || !empty($projectidforalltimes)) { // Not a dedicated task + if (! empty($allprojectforuser)) { + $arrayfields['p.project_ref'] = ['label' => $langs->trans('RefProject'), 'checked' => 1]; + $arrayfields['p.project_label'] = ['label' => $langs->trans('ProjectLabel'), 'checked' => 1]; + } $arrayfields['t.task_ref'] = array('label'=>$langs->trans("RefTask"), 'checked'=>1); $arrayfields['t.task_label'] = array('label'=>$langs->trans("LabelTask"), 'checked'=>1); } @@ -1258,6 +1286,15 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser if ($search_company != '') { $param .= '&$search_company='.urlencode($search_company); } + if ($search_company_alias != '') { + $param .= '&$search_company_alias='.urlencode($search_company_alias); + } + if ($search_project_ref != '') { + $param .= '&$search_project_ref='.urlencode($search_project_ref); + } + if ($search_project_label != '') { + $param .= '&$search_project_label='.urlencode($search_project_label); + } if ($search_task_label != '') { $param .= '&search_task_label='.urlencode($search_task_label); } @@ -1270,6 +1307,25 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser if ($optioncss != '') { $param .= '&optioncss='.urlencode($optioncss); } + if ($search_date_startday) { + $param .= '&search_date_startday='.urlencode($search_date_startday); + } + if ($search_date_startmonth) { + $param .= '&search_date_startmonth='.urlencode($search_date_startmonth); + } + if ($search_date_startyear) { + $param .= '&search_date_startyear='.urlencode($search_date_startyear); + } + if ($search_date_endday) { + $param .= '&search_date_endday='.urlencode($search_date_endday); + } + if ($search_date_endmonth) { + $param .= '&search_date_endmonth='.urlencode($search_date_endmonth); + } + if ($search_date_endyear) { + $param .= '&search_date_endyear='.urlencode($search_date_endyear); + } + /* // Add $param from extra fields include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php'; @@ -1300,9 +1356,9 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser print ''; } elseif ($action == 'createtime' && $user->rights->projet->time) { print ''; - } elseif ($massaction == 'generateinvoice' && $user->rights->facture->lire) { + } elseif ($massaction == 'generateinvoice' && $user->rights->facture->creer) { print ''; - } elseif ($massaction == 'generateinter' && $user->rights->ficheinter->lire) { + } elseif ($massaction == 'generateinter' && $user->rights->ficheinter->creer) { print ''; } else { print ''; @@ -1459,7 +1515,7 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser $sql .= " pt.ref, pt.label, pt.fk_projet,"; $sql .= " u.lastname, u.firstname, u.login, u.photo, u.statut as user_status,"; $sql .= " il.fk_facture as invoice_id, inv.fk_statut,"; - $sql .= " p.fk_soc,"; + $sql .= " p.fk_soc,s.name_alias,"; // Add fields from hooks $parameters = array(); $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters, $object); // Note that $action and $object may have been modified by hook @@ -1502,6 +1558,15 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser if ($search_company) { $sql .= natural_search('s.nom', $search_company); } + if ($search_company_alias) { + $sql .= natural_search('s.name_alias', $search_company_alias); + } + if ($search_project_ref) { + $sql .= natural_search('p.ref', $search_project_ref); + } + if ($search_project_label) { + $sql .= natural_search('p.title', $search_project_label); + } if ($search_task_label) { $sql .= natural_search('pt.label', $search_task_label); } @@ -1518,6 +1583,13 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser $sql .= ' AND (t.invoice_id = 0 OR t.invoice_id IS NULL)'; } + if ($search_date_start) { + $sql .= " AND t.task_date >= '".$db->idate($search_date_start)."'"; + } + if ($search_date_end) { + $sql .= " AND t.task_date <= '".$db->idate($search_date_end)."'"; + } + $sql .= dolSqlDateFilter('t.task_datehour', $search_day, $search_month, $search_year); // Add where from hooks @@ -1740,12 +1812,13 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser print '
'; // Date if (!empty($arrayfields['t.task_date']['checked'])) { - print ''; } // Thirdparty @@ -1753,8 +1826,18 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser print ''; } + // Thirdparty alias + if (!empty($arrayfields['s.name_alias']['checked'])) { + print ''; + } + if (!empty($allprojectforuser)) { - print ''; + if (!empty($arrayfields['p.project_ref']['checked'])) { + print ''; + } + if (!empty($arrayfields['p.project_label']['checked'])) { + print ''; + } } // Task if ((empty($id) && empty($ref)) || !empty($projectidforalltimes)) { // Not a dedicated task @@ -1809,11 +1892,20 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser if (!empty($arrayfields['t.task_date']['checked'])) { print_liste_field_titre($arrayfields['t.task_date']['label'], $_SERVER['PHP_SELF'], 't.task_date,t.task_datehour,t.rowid', '', $param, '', $sortfield, $sortorder); } + if (!empty($arrayfields['p.fk_soc']['checked'])) { print_liste_field_titre($arrayfields['p.fk_soc']['label'], $_SERVER['PHP_SELF'], 't.task_date,t.task_datehour,t.rowid', '', $param, '', $sortfield, $sortorder); } + if (!empty($arrayfields['s.name_alias']['checked'])) { + print_liste_field_titre($arrayfields['s.name_alias']['label'], $_SERVER['PHP_SELF'], 's.name_alias', '', $param, '', $sortfield, $sortorder); + } if (!empty($allprojectforuser)) { - print_liste_field_titre("Project", $_SERVER['PHP_SELF'], '', '', $param, '', $sortfield, $sortorder); + if (!empty($arrayfields['p.project_ref']['checked'])) { + print_liste_field_titre("Project", $_SERVER['PHP_SELF'], 'p.ref', '', $param, '', $sortfield, $sortorder); + } + if (!empty($arrayfields['p.project_label']['checked'])) { + print_liste_field_titre("ProjectLabel", $_SERVER['PHP_SELF'], 'p.title', '', $param, '', $sortfield, $sortorder); + } } if ((empty($id) && empty($ref)) || !empty($projectidforalltimes)) { // Not a dedicated task if (!empty($arrayfields['t.task_ref']['checked'])) { @@ -1892,37 +1984,75 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser // Thirdparty if (!empty($arrayfields['p.fk_soc']['checked'])) { print ''; if (!$i) { $totalarray['nbfield']++; } } - // Project ref - if (!empty($allprojectforuser)) { - print ''; if (!$i) { $totalarray['nbfield']++; } } + // Project ref & label + if (!empty($allprojectforuser)) { + if (!empty($arrayfields['p.project_ref']['checked'])) { + print ''; + if (! $i) { + $totalarray['nbfield']++; + } + } + if (!empty($arrayfields['p.project_label']['checked'])) { + print ''; + if (! $i) { + $totalarray['nbfield']++; + } + } + } + // Task ref if (!empty($arrayfields['t.task_ref']['checked'])) { if ((empty($id) && empty($ref)) || !empty($projectidforalltimes)) { // Not a dedicated task @@ -2107,7 +2237,7 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser print ' '; print ''; } elseif ($user->hasRight('projet', 'time') || $user->hasRight('projet', 'all', 'creer')) { // Read project and enter time consumed on assigned tasks - if ($task_time->fk_user == $user->id || in_array($task_time->fk_user, $childids) || $user->hasRight('projet', 'all', 'creer')) { + if (in_array($task_time->fk_user, $childids) || $user->hasRight('projet', 'all', 'creer')) { if (getDolGlobalString('MAIN_FEATURES_LEVEL') >= 2) { print ' '; print 'rowid.$param.((empty($id) || $tab == 'timespent') ? '&tab=timespent' : '').'">'; diff --git a/htdocs/public/cron/cron_run_jobs_by_url.php b/htdocs/public/cron/cron_run_jobs_by_url.php index 497c68954db..2cbea50bb90 100644 --- a/htdocs/public/cron/cron_run_jobs_by_url.php +++ b/htdocs/public/cron/cron_run_jobs_by_url.php @@ -142,26 +142,18 @@ if ($result < 0) { exit; } -$qualifiedjobs = array(); -foreach ($object->lines as $val) { - if (!verifCond($val->test)) { - continue; - } - $qualifiedjobs[] = $val; -} - // TODO Duplicate code. This sequence of code must be shared with code into cron_run_jobs.php script. // current date -$nbofjobs = count($qualifiedjobs); +$nbofjobs = count($object->lines); $nbofjobslaunchedok = 0; $nbofjobslaunchedko = 0; -if (is_array($qualifiedjobs) && (count($qualifiedjobs) > 0)) { +if (is_array($object->lines) && (count($object->lines) > 0)) { $savconf = dol_clone($conf); // Loop over job - foreach ($qualifiedjobs as $line) { + foreach ($object->lines as $line) { dol_syslog("cron_run_jobs.php cronjobid: ".$line->id." priority=".$line->priority." entity=".$line->entity." label=".$line->label, LOG_DEBUG); echo "cron_run_jobs.php cronjobid: ".$line->id." priority=".$line->priority." entity=".$line->entity." label=".$line->label; @@ -191,6 +183,10 @@ if (is_array($qualifiedjobs) && (count($qualifiedjobs) > 0)) { } } + if (!verifCond($line->test)) { + continue; + } + //If date_next_jobs is less of current date, execute the program, and store the execution time of the next execution in database if (($line->datenextrun < $now) && (empty($line->datestart) || $line->datestart <= $now) && (empty($line->dateend) || $line->dateend >= $now)) { echo " - qualified"; diff --git a/htdocs/public/eventorganization/attendee_new.php b/htdocs/public/eventorganization/attendee_new.php index b4f6ee14217..cb4ba38e628 100644 --- a/htdocs/public/eventorganization/attendee_new.php +++ b/htdocs/public/eventorganization/attendee_new.php @@ -56,6 +56,7 @@ require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php'; require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/paymentterm.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; global $dolibarr_main_url_root; @@ -229,7 +230,7 @@ if ($reshook < 0) { } // Action called when page is submitted -if (empty($reshook) && $action == 'add' && (!empty($conference->id) && $conference->status!=2 || !empty($project->id) && $project->status == Project::STATUS_VALIDATED)) { +if (empty($reshook) && $action == 'add' && (!empty($conference->id) && $conference->status==2 || !empty($project->id) && $project->status == Project::STATUS_VALIDATED)) { $error = 0; $urlback = ''; @@ -259,10 +260,12 @@ if (empty($reshook) && $action == 'add' && (!empty($conference->id) && $conferen // Check if attendee already exists (by email and for this event) $confattendee = new ConferenceOrBoothAttendee($db); + $filter = array(); + if ($type == 'global') { $filter = array('t.fk_project'=>((int) $id), 'customsql'=>'t.email="'.$db->escape($email).'"'); } - if ($action == 'conf') { + if ($type == 'conf') { $filter = array('t.fk_actioncomm'=>((int) $id), 'customsql'=>'t.email="'.$db->escape($email).'"'); } @@ -281,7 +284,39 @@ if (empty($reshook) && $action == 'add' && (!empty($conference->id) && $conferen $confattendee->fk_actioncomm = $id; $confattendee->note_public = $note_public; - $resultconfattendee = $confattendee->create($user); + $confattendee->ip = getUserRemoteIP(); + $nb_post_max = getDolGlobalInt("MAIN_SECURITY_MAX_POST_ON_PUBLIC_PAGES_BY_IP_ADDRESS", 200); + $now = dol_now(); + $minmonthpost = dol_time_plus_duree($now, -1, "m"); + // Calculate nb of post for IP + $nb_post_ip = 0; + if ($nb_post_max > 0) { // Calculate only if there is a limit to check + $sql = "SELECT COUNT(ref) as nb_attendee"; + $sql .= " FROM ".MAIN_DB_PREFIX."eventorganization_conferenceorboothattendee"; + $sql .= " WHERE ip = '".$db->escape($confattendee->ip)."'"; + $sql .= " AND date_creation > '".$db->idate($minmonthpost)."'"; + $resql = $db->query($sql); + if ($resql) { + $num = $db->num_rows($resql); + $i = 0; + while ($i < $num) { + $i++; + $obj = $db->fetch_object($resql); + $nb_post_ip = $obj->nb_attendee; + } + } + } + + $resultconforbooth = -1; + + if ($nb_post_max > 0 && $nb_post_ip >= $nb_post_max) { + $error++; + $errmsg .= $langs->trans("AlreadyTooMuchPostOnThisIPAdress"); + array_push($confattendee->errors, $langs->trans("AlreadyTooMuchPostOnThisIPAdress")); + setEventMessage($errmsg, 'errors'); + } else { + $resultconfattendee = $confattendee->create($user); + } if ($resultconfattendee < 0) { $error++; $errmsg .= $confattendee->error; @@ -787,7 +822,7 @@ if ((!empty($conference->id) && $conference->status == ConferenceOrBooth::STATUS print ''; // Country - print '
'; print $langs->trans("PriceLevel"); if ($user->admin) { @@ -1217,9 +1220,9 @@ if (!empty($conf->global->PRODUIT_MULTIPRICES) || !empty($conf->global->PRODUIT_ if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) { // TODO Fix the form inside tr instead of td print '
'.$langs->trans("PriceByQuantity"); if ($object->prices_by_qty[0] == 0) { - print '  ('.$langs->trans("Activate").')'; + print '  ('.$langs->trans("Activate").')'; } else { - print '  ('.$langs->trans("DisablePriceByQty").')'; + print '  ('.$langs->trans("DisablePriceByQty").')'; } print ''; diff --git a/htdocs/product/reassort.php b/htdocs/product/reassort.php index ed7b7e3e77f..c5b27a00c20 100644 --- a/htdocs/product/reassort.php +++ b/htdocs/product/reassort.php @@ -147,7 +147,7 @@ $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters, $obje $sql .= $hookmanager->resPrint; $sql .= ' FROM '.MAIN_DB_PREFIX.'product as p'; $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product_stock as s ON p.rowid = s.fk_product'; -$sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'entrepot as e ON s.fk_entrepot = e.rowid AND e.entity IN ('.getEntity('entrepot').')'; +$sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'entrepot as e ON s.fk_entrepot = e.rowid AND e.entity IN ('.getEntity('stock').')'; if (!empty($conf->global->PRODUCT_USE_UNITS)) { $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_units as u on p.fk_unit = u.rowid'; } diff --git a/htdocs/product/reassortlot.php b/htdocs/product/reassortlot.php index f3ad55d526d..40c8fcf4292 100644 --- a/htdocs/product/reassortlot.php +++ b/htdocs/product/reassortlot.php @@ -635,7 +635,7 @@ while ($i < $imaxinloop) { $product_static->status_batch = $objp->tobatch; $product_lot_static->batch = $objp->batch; - $product_lot_static->product_id = $objp->rowid; + $product_lot_static->fk_product = $objp->rowid; $product_lot_static->id = $objp->lotid; $product_lot_static->eatby = $objp->eatby; $product_lot_static->sellby = $objp->sellby; @@ -659,6 +659,7 @@ while ($i < $imaxinloop) { if (isModEnabled("service") && $type == 1) { print ''; + $regs = array(); if (preg_match('/([0-9]+)y/i', $objp->duration, $regs)) { print $regs[1].' '.$langs->trans("DurationYear"); } elseif (preg_match('/([0-9]+)m/i', $objp->duration, $regs)) { diff --git a/htdocs/product/stock/list.php b/htdocs/product/stock/list.php index b0c33e61484..bd8b5a2932a 100644 --- a/htdocs/product/stock/list.php +++ b/htdocs/product/stock/list.php @@ -533,7 +533,7 @@ print $hookmanager->resPrint; // Status if (!empty($arrayfields['t.statut']['checked'])) { print ''; - print $form->selectarray('search_status', $warehouse->statuts, $search_status, 1, 0, 0, '', 1); + print $form->selectarray('search_status', $warehouse->statuts, $search_status, 1, 0, 0, '', 1, 0, 0, '', 'onrightofpage'); print ''; print ''; + print ''; $arrayofstatus = array(); @@ -1111,7 +1182,7 @@ if (!empty($arrayfields['p.fk_statut']['checked'])) { $arrayofstatus[$key] = $langs->trans($val); } $arrayofstatus['99'] = $langs->trans("NotClosed").' ('.$langs->trans('Draft').' + '.$langs->trans('Opened').')'; - print $form->selectarray('search_status', $arrayofstatus, $search_status, 1, 0, 0, '', 0, 0, 0, '', 'minwidth75imp maxwidth125 selectarrowonleft'); + print $form->selectarray('search_status', $arrayofstatus, $search_status, 1, 0, 0, '', 0, 0, 0, '', 'minwidth75imp maxwidth125 selectarrowonleft onrightofpage'); print ajax_combobox('search_status'); print ''.dol_escape_htmltag($obj->import_key).''.$object->getLibStatut(5).'
'; - if (!empty($conf->global->MAIN_LIST_FILTER_ON_DAY)) { - print ''; - } - print ''; - print $formother->selectyear($search_year, 'search_year', 1, 20, 5); + print ''; + print '
'; + print $form->selectDate($search_date_start ? $search_date_start : -1, 'search_date_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('From')); + print '
'; + print '
'; + print $form->selectDate($search_date_end ? $search_date_end : -1, 'search_date_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('to')); + print '
'; print '
'; - if (empty($conf->cache['thridparty'][$task_time->fk_soc])) { - $tmpsociete = new Societe($db); - $tmpsociete->fetch($task_time->fk_soc); - $conf->cache['thridparty'][$task_time->fk_soc] = $tmpsociete; - } else { - $tmpsociete = $conf->cache['thridparty'][$task_time->fk_soc]; + if ($task_time->fk_soc > 0) { + if (empty($conf->cache['thridparty'][$task_time->fk_soc])) { + $tmpsociete = new Societe($db); + $tmpsociete->fetch($task_time->fk_soc); + $conf->cache['thridparty'][$task_time->fk_soc] = $tmpsociete; + } else { + $tmpsociete = $conf->cache['thridparty'][$task_time->fk_soc]; + } + print $tmpsociete->getNomUrl(1, '', 100, 0, 1, empty($arrayfields['s.name_alias']['checked']) ? 0 : 1); } - print $tmpsociete->getNomUrl(1); print ''; - if (empty($conf->cache['project'][$task_time->fk_projet])) { - $tmpproject = new Project($db); - $tmpproject->fetch($task_time->fk_projet); - $conf->cache['project'][$task_time->fk_projet] = $tmpproject; - } else { - $tmpproject = $conf->cache['project'][$task_time->fk_projet]; + // Thirdparty alias + if (!empty($arrayfields['s.name_alias']['checked'])) { + print ''; + if ($task_time->fk_soc > 0) { + if (empty($conf->cache['thridparty'][$task_time->fk_soc])) { + $tmpsociete = new Societe($db); + $tmpsociete->fetch($task_time->fk_soc); + $conf->cache['thridparty'][$task_time->fk_soc] = $tmpsociete; + } else { + $tmpsociete = $conf->cache['thridparty'][$task_time->fk_soc]; + } + print $tmpsociete->name_alias; } - print $tmpproject->getNomUrl(1); print ''; + if (empty($conf->cache['project'][$task_time->fk_projet])) { + $tmpproject = new Project($db); + $tmpproject->fetch($task_time->fk_projet); + $conf->cache['project'][$task_time->fk_projet] = $tmpproject; + } else { + $tmpproject = $conf->cache['project'][$task_time->fk_projet]; + } + print $tmpproject->getNomUrl(1); + print ''; + if (empty($conf->cache['project'][$task_time->fk_projet])) { + $tmpproject = new Project($db); + $tmpproject->fetch($task_time->fk_projet); + $conf->cache['project'][$task_time->fk_projet] = $tmpproject; + } else { + $tmpproject = $conf->cache['project'][$task_time->fk_projet]; + } + print $tmpproject->title; + print '
trans('Country') . ''; + print '
'.$langs->trans('Country').''; print img_picto('', 'country', 'class="pictofixedwidth"'); $country_id = GETPOST('country_id'); if (!$country_id && !empty($conf->global->MEMBER_NEWFORM_FORCECOUNTRYCODE)) { diff --git a/htdocs/public/members/new.php b/htdocs/public/members/new.php index 051506d54ac..7b5acf5c99d 100644 --- a/htdocs/public/members/new.php +++ b/htdocs/public/members/new.php @@ -73,6 +73,7 @@ require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent_type.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/cunits.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; // Init vars $errmsg = ''; @@ -277,152 +278,192 @@ if (empty($reshook) && $action == 'add') { $adh->pass = GETPOST('pass1'); } $adh->photo = GETPOST('photo'); - $adh->country_id = $conf->global->MEMBER_NEWFORM_FORCECOUNTRYCODE ? $conf->global->MEMBER_NEWFORM_FORCECOUNTRYCODE : GETPOST('country_id', 'int'); + $adh->country_id = getDolGlobalString("MEMBER_NEWFORM_FORCECOUNTRYCODE", GETPOST('country_id', 'int')); $adh->state_id = GETPOST('state_id', 'int'); - $adh->typeid = $conf->global->MEMBER_NEWFORM_FORCETYPE ? $conf->global->MEMBER_NEWFORM_FORCETYPE : GETPOST('typeid', 'int'); + $adh->typeid = getDolGlobalString("MEMBER_NEWFORM_FORCETYPE", GETPOST('typeid', 'int')); $adh->note_private = GETPOST('note_private'); - $adh->morphy = $conf->global->MEMBER_NEWFORM_FORCEMORPHY ? $conf->global->MEMBER_NEWFORM_FORCEMORPHY : GETPOST('morphy'); + $adh->morphy = getDolGlobalString("MEMBER_NEWFORM_FORCEMORPHY", GETPOST('morphy')); $adh->birth = $birthday; + $adh->ip = getUserRemoteIP(); + + $nb_post_max = getDolGlobalInt("MAIN_SECURITY_MAX_POST_ON_PUBLIC_PAGES_BY_IP_ADDRESS", 200); + $now = dol_now(); + $minmonthpost = dol_time_plus_duree($now, -1, "m"); + // Calculate nb of post for IP + $nb_post_ip = 0; + if ($nb_post_max > 0) { // Calculate only if there is a limit to check + $sql = "SELECT COUNT(ref) as nb_adh"; + $sql .= " FROM ".MAIN_DB_PREFIX."adherent"; + $sql .= " WHERE ip = '".$db->escape($adh->ip)."'"; + $sql .= " AND datec > '".$db->idate($minmonthpost)."'"; + $resql = $db->query($sql); + if ($resql) { + $num = $db->num_rows($resql); + $i = 0; + while ($i < $num) { + $i++; + $obj = $db->fetch_object($resql); + $nb_post_ip = $obj->nb_adh; + } + } + } + // Fill array 'array_options' with data from add form $extrafields->fetch_name_optionals_label($adh->table_element); $ret = $extrafields->setOptionalsFromPost(null, $adh); if ($ret < 0) { $error++; + $errmsg .= $adh->error; } - $result = $adh->create($user); - if ($result > 0) { - require_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php'; - $object = $adh; + if ($nb_post_max > 0 && $nb_post_ip >= $nb_post_max) { + $error++; + $errmsg .= $langs->trans("AlreadyTooMuchPostOnThisIPAdress"); + array_push($adh->errors, $langs->trans("AlreadyTooMuchPostOnThisIPAdress")); + } - $adht = new AdherentType($db); - $adht->fetch($object->typeid); + if (!$error) { + $result = $adh->create($user); + if ($result > 0) { + require_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php'; + $object = $adh; - if ($object->email) { - $subject = ''; - $msg = ''; + $adht = new AdherentType($db); + $adht->fetch($object->typeid); - // Send subscription email - include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php'; - $formmail = new FormMail($db); - // Set output language - $outputlangs = new Translate('', $conf); - $outputlangs->setDefaultLang(empty($object->thirdparty->default_lang) ? $mysoc->default_lang : $object->thirdparty->default_lang); - // Load traductions files required by page - $outputlangs->loadLangs(array("main", "members")); - // Get email content from template - $arraydefaultmessage = null; - $labeltouse = $conf->global->ADHERENT_EMAIL_TEMPLATE_AUTOREGISTER; + if ($object->email) { + $subject = ''; + $msg = ''; - if (!empty($labeltouse)) { - $arraydefaultmessage = $formmail->getEMailTemplate($db, 'member', $user, $outputlangs, 0, 1, $labeltouse); + // Send subscription email + include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php'; + $formmail = new FormMail($db); + // Set output language + $outputlangs = new Translate('', $conf); + $outputlangs->setDefaultLang(empty($object->thirdparty->default_lang) ? $mysoc->default_lang : $object->thirdparty->default_lang); + // Load traductions files required by page + $outputlangs->loadLangs(array("main", "members")); + // Get email content from template + $arraydefaultmessage = null; + $labeltouse = $conf->global->ADHERENT_EMAIL_TEMPLATE_AUTOREGISTER; + + if (!empty($labeltouse)) { + $arraydefaultmessage = $formmail->getEMailTemplate($db, 'member', $user, $outputlangs, 0, 1, $labeltouse); + } + + if (!empty($labeltouse) && is_object($arraydefaultmessage) && $arraydefaultmessage->id > 0) { + $subject = $arraydefaultmessage->topic; + $msg = $arraydefaultmessage->content; + } + + $substitutionarray = getCommonSubstitutionArray($outputlangs, 0, null, $object); + complete_substitutions_array($substitutionarray, $outputlangs, $object); + $subjecttosend = make_substitutions($subject, $substitutionarray, $outputlangs); + $texttosend = make_substitutions(dol_concatdesc($msg, $adht->getMailOnValid()), $substitutionarray, $outputlangs); + + 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); + } + /*if ($result < 0) { + $error++; + setEventMessages($object->error, $object->errors, 'errors'); + }*/ } - if (!empty($labeltouse) && is_object($arraydefaultmessage) && $arraydefaultmessage->id > 0) { - $subject = $arraydefaultmessage->topic; - $msg = $arraydefaultmessage->content; - } - - $substitutionarray = getCommonSubstitutionArray($outputlangs, 0, null, $object); - complete_substitutions_array($substitutionarray, $outputlangs, $object); - $subjecttosend = make_substitutions($subject, $substitutionarray, $outputlangs); - $texttosend = make_substitutions(dol_concatdesc($msg, $adht->getMailOnValid()), $substitutionarray, $outputlangs); - - 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); - } - /*if ($result < 0) { - $error++; - setEventMessages($object->error, $object->errors, 'errors'); - }*/ - } - - // Send email to the foundation to say a new member subscribed with autosubscribe form - if (!empty($conf->global->MAIN_INFO_SOCIETE_MAIL) && !empty($conf->global->ADHERENT_AUTOREGISTER_NOTIF_MAIL_SUBJECT) && - !empty($conf->global->ADHERENT_AUTOREGISTER_NOTIF_MAIL)) { - // Define link to login card - $appli = constant('DOL_APPLICATION_TITLE'); - if (!empty($conf->global->MAIN_APPLICATION_TITLE)) { - $appli = $conf->global->MAIN_APPLICATION_TITLE; - if (preg_match('/\d\.\d/', $appli)) { - if (!preg_match('/'.preg_quote(DOL_VERSION).'/', $appli)) { - $appli .= " (".DOL_VERSION.")"; // If new title contains a version that is different than core + // Send email to the foundation to say a new member subscribed with autosubscribe form + if (!empty($conf->global->MAIN_INFO_SOCIETE_MAIL) && !empty($conf->global->ADHERENT_AUTOREGISTER_NOTIF_MAIL_SUBJECT) && + !empty($conf->global->ADHERENT_AUTOREGISTER_NOTIF_MAIL)) { + // Define link to login card + $appli = constant('DOL_APPLICATION_TITLE'); + if (!empty($conf->global->MAIN_APPLICATION_TITLE)) { + $appli = $conf->global->MAIN_APPLICATION_TITLE; + if (preg_match('/\d\.\d/', $appli)) { + if (!preg_match('/'.preg_quote(DOL_VERSION).'/', $appli)) { + $appli .= " (".DOL_VERSION.")"; // If new title contains a version that is different than core + } + } else { + $appli .= " ".DOL_VERSION; } } else { $appli .= " ".DOL_VERSION; } + + $to = $adh->makeSubstitution($conf->global->MAIN_INFO_SOCIETE_MAIL); + $from = $conf->global->ADHERENT_MAIL_FROM; + $mailfile = new CMailFile( + '['.$appli.'] '.$conf->global->ADHERENT_AUTOREGISTER_NOTIF_MAIL_SUBJECT, + $to, + $from, + $adh->makeSubstitution($conf->global->ADHERENT_AUTOREGISTER_NOTIF_MAIL), + array(), + array(), + array(), + "", + "", + 0, + -1 + ); + + if (!$mailfile->sendfile()) { + dol_syslog($langs->trans("ErrorFailedToSendMail", $from, $to), LOG_ERR); + } + } + + // Auto-create thirdparty on member creation + if (!empty($conf->global->ADHERENT_DEFAULT_CREATE_THIRDPARTY)) { + $company = new Societe($db); + $result = $company->create_from_member($adh); + if ($result < 0) { + $error++; + $errmsg .= join('
', $company->errors); + } + } + + if (!empty($backtopage)) { + $urlback = $backtopage; + } elseif (!empty($conf->global->MEMBER_URL_REDIRECT_SUBSCRIPTION)) { + $urlback = $conf->global->MEMBER_URL_REDIRECT_SUBSCRIPTION; + // TODO Make replacement of __AMOUNT__, etc... } else { - $appli .= " ".DOL_VERSION; + $urlback = $_SERVER["PHP_SELF"]."?action=added&token=".newToken(); } - $to = $adh->makeSubstitution($conf->global->MAIN_INFO_SOCIETE_MAIL); - $from = $conf->global->ADHERENT_MAIL_FROM; - $mailfile = new CMailFile( - '['.$appli.'] '.$conf->global->ADHERENT_AUTOREGISTER_NOTIF_MAIL_SUBJECT, - $to, - $from, - $adh->makeSubstitution($conf->global->ADHERENT_AUTOREGISTER_NOTIF_MAIL), - array(), - array(), - array(), - "", - "", - 0, - -1 - ); + if (!empty($conf->global->MEMBER_NEWFORM_PAYONLINE) && $conf->global->MEMBER_NEWFORM_PAYONLINE != '-1') { + if (empty($conf->global->MEMBER_NEWFORM_EDITAMOUNT)) { // If edition of amount not allowed + // TODO Check amount is same than the amount required for the type of member or if not defined as the defeault amount into $conf->global->MEMBER_NEWFORM_AMOUNT + // It is not so important because a test is done on return of payment validation. + } - if (!$mailfile->sendfile()) { - dol_syslog($langs->trans("ErrorFailedToSendMail", $from, $to), LOG_ERR); - } - } + $urlback = getOnlinePaymentUrl(0, 'member', $adh->ref, price2num(GETPOST('amount', 'alpha'), 'MT'), '', 0); - // Auto-create thirdparty on member creation - if (!empty($conf->global->ADHERENT_DEFAULT_CREATE_THIRDPARTY)) { - $company = new Societe($db); - $result = $company->create_from_member($adh); - if ($result < 0) { - $error++; - $errmsg .= join('
', $company->errors); + if (GETPOST('email')) { + $urlback .= '&email='.urlencode(GETPOST('email')); + } + if ($conf->global->MEMBER_NEWFORM_PAYONLINE != '-1' && $conf->global->MEMBER_NEWFORM_PAYONLINE != 'all') { + $urlback .= '&paymentmethod='.urlencode($conf->global->MEMBER_NEWFORM_PAYONLINE); + } + } else { + if (!empty($entity)) { + $urlback .= '&entity='.((int) $entity); + } } } if (!empty($backtopage)) { $urlback = $backtopage; + dol_syslog("member ".$adh->ref." was created, we redirect to ".$urlback); } elseif (!empty($conf->global->MEMBER_URL_REDIRECT_SUBSCRIPTION)) { $urlback = $conf->global->MEMBER_URL_REDIRECT_SUBSCRIPTION; // TODO Make replacement of __AMOUNT__, etc... + dol_syslog("member ".$adh->ref." was created, we redirect to ".$urlback); } else { - $urlback = $_SERVER["PHP_SELF"]."?action=added&token=".newToken(); + $error++; + $errmsg .= join('
', $adh->errors); } - - if (!empty($conf->global->MEMBER_NEWFORM_PAYONLINE) && $conf->global->MEMBER_NEWFORM_PAYONLINE != '-1') { - if (empty($conf->global->MEMBER_NEWFORM_EDITAMOUNT)) { // If edition of amount not allowed - // TODO Check amount is same than the amount required for the type of member or if not defined as the defeault amount into $conf->global->MEMBER_NEWFORM_AMOUNT - // It is not so important because a test is done on return of payment validation. - } - - $urlback = getOnlinePaymentUrl(0, 'member', $adh->ref, price2num(GETPOST('amount', 'alpha'), 'MT'), '', 0); - - if (GETPOST('email')) { - $urlback .= '&email='.urlencode(GETPOST('email')); - } - if ($conf->global->MEMBER_NEWFORM_PAYONLINE != '-1' && $conf->global->MEMBER_NEWFORM_PAYONLINE != 'all') { - $urlback .= '&paymentmethod='.urlencode($conf->global->MEMBER_NEWFORM_PAYONLINE); - } - } else { - if (!empty($entity)) { - $urlback .= '&entity='.((int) $entity); - } - } - - dol_syslog("member ".$adh->ref." was created, we redirect to ".$urlback); - } else { - $error++; - $errmsg .= join('
', $adh->errors); } } @@ -433,6 +474,7 @@ if (empty($reshook) && $action == 'add') { exit; } else { $db->rollback(); + $action = "create"; } } @@ -483,6 +525,7 @@ if (!empty($conf->global->MEMBER_NEWFORM_TEXT)) { print ''; dol_htmloutput_errors($errmsg); +dol_htmloutput_events(); // Print form print ''."\n"; @@ -770,7 +813,7 @@ if (!empty($conf->global->MEMBER_SKIP_TABLE) || !empty($conf->global->MEMBER_NEW foreach ($measuringUnits->records as $lines) $units[$lines->short_label] = $langs->trans(ucfirst($lines->label)); - $publiccounters = $conf->global->MEMBER_COUNTERS_ARE_PUBLIC; + $publiccounters = getDolGlobalString("MEMBER_COUNTERS_ARE_PUBLIC"); $sql = "SELECT d.rowid, d.libelle as label, d.subscription, d.amount, d.caneditamount, d.vote, d.note, d.duration, d.statut as status, d.morphy, COUNT(a.rowid) AS membercount"; $sql .= " FROM ".MAIN_DB_PREFIX."adherent_type as d"; diff --git a/htdocs/public/onlinesign/newonlinesign.php b/htdocs/public/onlinesign/newonlinesign.php index 10cb5e4354f..f0738f0e420 100644 --- a/htdocs/public/onlinesign/newonlinesign.php +++ b/htdocs/public/onlinesign/newonlinesign.php @@ -183,6 +183,7 @@ if ($action == 'confirm_refusepropal' && $confirm == 'yes') { // Online customer is not a user, so we use the use that validates the documents $user = new User($db); $user->fetch($object->user_valid_id); + $object->context = array('closedfromonlinesignature' => 'closedfromonlinesignature'); $result = $object->call_trigger('PROPAL_CLOSE_REFUSED', $user); if ($result < 0) { $error++; diff --git a/htdocs/public/opensurvey/studs.php b/htdocs/public/opensurvey/studs.php index f11f8aea918..34f8ecd9400 100644 --- a/htdocs/public/opensurvey/studs.php +++ b/htdocs/public/opensurvey/studs.php @@ -41,6 +41,7 @@ require_once DOL_DOCUMENT_ROOT."/core/lib/admin.lib.php"; require_once DOL_DOCUMENT_ROOT."/core/lib/files.lib.php"; require_once DOL_DOCUMENT_ROOT."/opensurvey/class/opensurveysondage.class.php"; require_once DOL_DOCUMENT_ROOT."/opensurvey/lib/opensurvey.lib.php"; +require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; // Init vars @@ -97,8 +98,36 @@ if (GETPOST('ajoutcomment', 'alpha')) { $error++; } + $user_ip = getUserRemoteIP(); + $nb_post_max = getDolGlobalInt("MAIN_SECURITY_MAX_POST_ON_PUBLIC_PAGES_BY_IP_ADDRESS", 200); + $now = dol_now(); + $minmonthpost = dol_time_plus_duree($now, -1, "m"); + // Calculate nb of post for IP + $nb_post_ip = 0; + if ($nb_post_max > 0) { // Calculate only if there is a limit to check + $sql = "SELECT COUNT(id_comment) as nb_comments"; + $sql .= " FROM ".MAIN_DB_PREFIX."opensurvey_comments"; + $sql .= " WHERE ip = '".$db->escape($user_ip)."'"; + $sql .= " AND date_creation > '".$db->idate($minmonthpost)."'"; + $resql = $db->query($sql); + if ($resql) { + $num = $db->num_rows($resql); + $i = 0; + while ($i < $num) { + $i++; + $obj = $db->fetch_object($resql); + $nb_post_ip = $obj->nb_comments; + } + } + } + + if ($nb_post_max > 0 && $nb_post_ip >= $nb_post_max) { + setEventMessages($langs->trans("AlreadyTooMuchPostOnThisIPAdress"), null, 'errors'); + $error++; + } + if (!$error) { - $resql = $object->addComment($comment, $comment_user); + $resql = $object->addComment($comment, $comment_user, $user_ip); if (!$resql) { dol_print_error($db); @@ -125,6 +154,30 @@ if (GETPOST("boutonp") || GETPOST("boutonp.x") || GETPOST("boutonp_x")) { // bo } } + $user_ip = getUserRemoteIP(); + $nb_post_max = getDolGlobalInt("MAIN_SECURITY_MAX_POST_ON_PUBLIC_PAGES_BY_IP_ADDRESS", 200); + $now = dol_now(); + $minmonthpost = dol_time_plus_duree($now, -1, "m"); + // Calculate nb of post for IP + $nb_post_ip = 0; + if ($nb_post_max > 0) { // Calculate only if there is a limit to check + $sql = "SELECT COUNT(id_users) as nb_records"; + $sql .= " FROM ".MAIN_DB_PREFIX."opensurvey_user_studs"; + $sql .= " WHERE ip = '".$db->escape($user_ip)."'"; + $sql .= " AND date_creation > '".$db->idate($minmonthpost)."'"; + $resql = $db->query($sql); + if ($resql) { + $num = $db->num_rows($resql); + $i = 0; + while ($i < $num) { + $i++; + $obj = $db->fetch_object($resql); + $nb_post_ip = $obj->nb_records; + } + } + } + + $nom = substr(GETPOST("nom", 'alphanohtml'), 0, 64); // Check if vote already exists @@ -137,12 +190,17 @@ if (GETPOST("boutonp") || GETPOST("boutonp.x") || GETPOST("boutonp_x")) { // bo } $num_rows = $db->num_rows($resql); + if ($num_rows > 0) { setEventMessages($langs->trans("VoteNameAlreadyExists"), null, 'errors'); $error++; + } elseif ($nb_post_max > 0 && $nb_post_ip >= $nb_post_max) { + setEventMessages($langs->trans("AlreadyTooMuchPostOnThisIPAdress"), null, 'errors'); + $error++; } else { - $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'opensurvey_user_studs (nom, id_sondage, reponses)'; - $sql .= " VALUES ('".$db->escape($nom)."', '".$db->escape($numsondage)."','".$db->escape($nouveauchoix)."')"; + $now = dol_now(); + $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'opensurvey_user_studs (nom, id_sondage, reponses, ip, date_creation)'; + $sql .= " VALUES ('".$db->escape($nom)."', '".$db->escape($numsondage)."','".$db->escape($nouveauchoix)."', '".$db->escape($user_ip)."', '".$db->idate($now)."')"; $resql = $db->query($sql); if ($resql) { @@ -267,7 +325,7 @@ $toutsujet = explode(",", $object->sujet); $listofanswers = array(); foreach ($toutsujet as $value) { $tmp = explode('@', $value); - $listofanswers[] = array('label'=>$tmp[0], 'format'=>($tmp[1] ? $tmp[1] : 'checkbox')); + $listofanswers[] = array('label'=>$tmp[0], 'format'=>(!empty($tmp[1]) ? $tmp[1] : 'checkbox')); } $toutsujet = str_replace("°", "'", $toutsujet); diff --git a/htdocs/public/partnership/new.php b/htdocs/public/partnership/new.php index 68e9034a761..b6444753eb7 100644 --- a/htdocs/public/partnership/new.php +++ b/htdocs/public/partnership/new.php @@ -59,6 +59,7 @@ require_once DOL_DOCUMENT_ROOT.'/partnership/class/partnership.class.php'; require_once DOL_DOCUMENT_ROOT.'/partnership/class/partnership_type.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; // Init vars $errmsg = ''; @@ -223,7 +224,29 @@ if (empty($reshook) && $action == 'add') { $partnership->fk_user_creat = 0; $partnership->fk_type = GETPOST('partnershiptype', 'int'); //$partnership->typeid = $conf->global->PARTNERSHIP_NEWFORM_FORCETYPE ? $conf->global->PARTNERSHIP_NEWFORM_FORCETYPE : GETPOST('typeid', 'int'); + $partnership->ip = getUserRemoteIP(); + $nb_post_max = getDolGlobalInt("MAIN_SECURITY_MAX_POST_ON_PUBLIC_PAGES_BY_IP_ADDRESS", 200); + $now = dol_now(); + $minmonthpost = dol_time_plus_duree($now, -1, "m"); + // Calculate nb of post for IP + $nb_post_ip = 0; + if ($nb_post_max > 0) { // Calculate only if there is a limit to check + $sql = "SELECT COUNT(ref) as nb_partnerships"; + $sql .= " FROM ".MAIN_DB_PREFIX."partnership"; + $sql .= " WHERE ip = '".$db->escape($partnership->ip)."'"; + $sql .= " AND date_creation > '".$db->idate($minmonthpost)."'"; + $resql = $db->query($sql); + if ($resql) { + $num = $db->num_rows($resql); + $i = 0; + while ($i < $num) { + $i++; + $obj = $db->fetch_object($resql); + $nb_post_ip = $obj->nb_partnerships; + } + } + } // test if societe already exist $company = new Societe($db); $result = $company->fetch(0, GETPOST('societe')); @@ -290,6 +313,11 @@ if (empty($reshook) && $action == 'add') { $error++; } + if ($nb_post_max > 0 && $nb_post_ip >= $nb_post_max) { + $error++; + $errmsg = $langs->trans("AlreadyTooMuchPostOnThisIPAdress"); + array_push($partnership->errors, $langs->trans("AlreadyTooMuchPostOnThisIPAdress")); + } if (!$error) { $result = $partnership->create($user); if ($result > 0) { @@ -464,6 +492,8 @@ if (empty($reshook) && $action == 'add') { $error++; $errmsg .= join('
', $partnership->errors); } + } else { + setEventMessage($errmsg, 'errors'); } } @@ -502,7 +532,7 @@ if (empty($reshook) && $action == 'added') { $form = new Form($db); $formcompany = new FormCompany($db); -$extrafields->fetch_name_optionals_label($partnership->table_element); // fetch optionals attributes and labels +$extrafields->fetch_name_optionals_label($object->table_element); // fetch optionals attributes and labels llxHeaderVierge($langs->trans("NewPartnershipRequest")); @@ -518,7 +548,7 @@ print '
'; if (!empty($conf->global->PARTNERSHIP_NEWFORM_TEXT)) { print $langs->trans($conf->global->PARTNERSHIP_NEWFORM_TEXT)."
\n"; } else { - print $langs->trans("NewPartnershipRequestDesc", $conf->global->MAIN_INFO_SOCIETE_MAIL)."
\n"; + print $langs->trans("NewPartnershipRequestDesc", getDolGlobalString("MAIN_INFO_SOCIETE_MAIL"))."
\n"; } print '
'; diff --git a/htdocs/public/project/new.php b/htdocs/public/project/new.php index 61bbd23ea61..7603c046006 100644 --- a/htdocs/public/project/new.php +++ b/htdocs/public/project/new.php @@ -57,6 +57,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/json.lib.php'; require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; // Init vars $errmsg = ''; @@ -296,6 +297,28 @@ if (empty($reshook) && $action == 'add') { $proj->opp_status = $defaultoppstatus; $proj->fk_opp_status = $defaultoppstatus; + $proj->ip = getUserRemoteIP(); + $nb_post_max = getDolGlobalInt("MAIN_SECURITY_MAX_POST_ON_PUBLIC_PAGES_BY_IP_ADDRESS", 200); + $now = dol_now(); + $minmonthpost = dol_time_plus_duree($now, -1, "m"); + $nb_post_ip = 0; + if ($nb_post_max > 0) { // Calculate only if there is a limit to check + $sql = "SELECT COUNT(rowid) as nb_projets"; + $sql .= " FROM ".MAIN_DB_PREFIX."projet"; + $sql .= " WHERE ip = '".$db->escape($proj->ip)."'"; + $sql .= " AND datec > '".$db->idate($minmonthpost)."'"; + $resql = $db->query($sql); + if ($resql) { + $num = $db->num_rows($resql); + $i = 0; + while ($i < $num) { + $i++; + $obj = $db->fetch_object($resql); + $nb_post_ip = $obj->nb_projets; + } + } + } + // Fill array 'array_options' with data from the form $extrafields->fetch_name_optionals_label($proj->table_element); $ret = $extrafields->setOptionalsFromPost(null, $proj); @@ -303,74 +326,83 @@ if (empty($reshook) && $action == 'add') { $error++; } - // Create the project - $result = $proj->create($user); - if ($result > 0) { - require_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php'; - $object = $proj; - - if ($object->email) { - $subject = ''; - $msg = ''; - - // Send subscription email - include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php'; - $formmail = new FormMail($db); - // Set output language - $outputlangs = new Translate('', $conf); - $outputlangs->setDefaultLang(empty($object->thirdparty->default_lang) ? $mysoc->default_lang : $object->thirdparty->default_lang); - // Load traductions files required by page - $outputlangs->loadLangs(array("main", "members", "projects")); - // Get email content from template - $arraydefaultmessage = null; - $labeltouse = $conf->global->PROJECT_EMAIL_TEMPLATE_AUTOLEAD; - - if (!empty($labeltouse)) { - $arraydefaultmessage = $formmail->getEMailTemplate($db, 'project', $user, $outputlangs, 0, 1, $labeltouse); - } - - if (!empty($labeltouse) && is_object($arraydefaultmessage) && $arraydefaultmessage->id > 0) { - $subject = $arraydefaultmessage->topic; - $msg = $arraydefaultmessage->content; - } - if (empty($labeltosue)) { - $labeltouse = '['.$mysoc->name.'] '.$langs->trans("YourMessage"); - $msg = $langs->trans("YourMessageHasBeenReceived"); - } - - $substitutionarray = getCommonSubstitutionArray($outputlangs, 0, null, $object); - 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); - } - /*if ($result < 0) { - $error++; - setEventMessages($object->error, $object->errors, 'errors'); - }*/ - } - - if (!empty($backtopage)) { - $urlback = $backtopage; - } elseif (!empty($conf->global->PROJECT_URL_REDIRECT_LEAD)) { - $urlback = $conf->global->PROJECT_URL_REDIRECT_LEAD; - // TODO Make replacement of __AMOUNT__, etc... - } else { - $urlback = $_SERVER["PHP_SELF"]."?action=added&token=".newToken(); - } - - if (!empty($entity)) { - $urlback .= '&entity='.$entity; - } - - dol_syslog("project lead ".$proj->ref." has been created, we redirect to ".$urlback); - } else { + if ($nb_post_max > 0 && $nb_post_ip >= $nb_post_max) { $error++; - $errmsg .= $proj->error.'
'.join('
', $proj->errors); + $errmsg = $langs->trans("AlreadyTooMuchPostOnThisIPAdress"); + array_push($proj->errors, $langs->trans("AlreadyTooMuchPostOnThisIPAdress")); + } + // Create the project + if (!$error) { + $result = $proj->create($user); + if ($result > 0) { + require_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php'; + $object = $proj; + + if ($object->email) { + $subject = ''; + $msg = ''; + + // Send subscription email + include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php'; + $formmail = new FormMail($db); + // Set output language + $outputlangs = new Translate('', $conf); + $outputlangs->setDefaultLang(empty($object->thirdparty->default_lang) ? $mysoc->default_lang : $object->thirdparty->default_lang); + // Load traductions files required by page + $outputlangs->loadLangs(array("main", "members", "projects")); + // Get email content from template + $arraydefaultmessage = null; + $labeltouse = $conf->global->PROJECT_EMAIL_TEMPLATE_AUTOLEAD; + + if (!empty($labeltouse)) { + $arraydefaultmessage = $formmail->getEMailTemplate($db, 'project', $user, $outputlangs, 0, 1, $labeltouse); + } + + if (!empty($labeltouse) && is_object($arraydefaultmessage) && $arraydefaultmessage->id > 0) { + $subject = $arraydefaultmessage->topic; + $msg = $arraydefaultmessage->content; + } + if (empty($labeltosue)) { + $labeltouse = '['.$mysoc->name.'] '.$langs->trans("YourMessage"); + $msg = $langs->trans("YourMessageHasBeenReceived"); + } + + $substitutionarray = getCommonSubstitutionArray($outputlangs, 0, null, $object); + 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); + } + /*if ($result < 0) { + $error++; + setEventMessages($object->error, $object->errors, 'errors'); + }*/ + } + + if (!empty($backtopage)) { + $urlback = $backtopage; + } elseif (!empty($conf->global->PROJECT_URL_REDIRECT_LEAD)) { + $urlback = $conf->global->PROJECT_URL_REDIRECT_LEAD; + // TODO Make replacement of __AMOUNT__, etc... + } else { + $urlback = $_SERVER["PHP_SELF"]."?action=added&token=".newToken(); + } + + if (!empty($entity)) { + $urlback .= '&entity='.$entity; + } + + dol_syslog("project lead ".$proj->ref." has been created, we redirect to ".$urlback); + } else { + $error++; + $errmsg .= $proj->error.'
'.join('
', $proj->errors); + } + } else { + setEventMessage($errmsg, 'errors'); } } diff --git a/htdocs/public/project/suggestbooth.php b/htdocs/public/project/suggestbooth.php index f42e75b21b1..68e469b6a00 100644 --- a/htdocs/public/project/suggestbooth.php +++ b/htdocs/public/project/suggestbooth.php @@ -56,6 +56,7 @@ require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php'; require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/paymentterm.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; global $dolibarr_main_url_root; @@ -361,7 +362,41 @@ if (empty($reshook) && $action == 'add') { $conforbooth->datep2 = $dateend; $conforbooth->datec = dol_now(); $conforbooth->tms = dol_now(); - $resultconforbooth = $conforbooth->create($user); + $conforbooth->ip = getUserRemoteIP(); + + $nb_post_max = getDolGlobalInt("MAIN_SECURITY_MAX_POST_ON_PUBLIC_PAGES_BY_IP_ADDRESS", 200); + $now = dol_now(); + $minmonthpost = dol_time_plus_duree($now, -1, "m"); + + // Calculate nb of post for IP + $nb_post_ip = 0; + if ($nb_post_max > 0) { // Calculate only if there is a limit to check + $sql = "SELECT COUNT(ref) as nb_confs"; + $sql .= " FROM ".MAIN_DB_PREFIX."actioncomm"; + $sql .= " WHERE ip = '".$db->escape($conforbooth->ip)."'"; + $sql .= " AND datec > '".$db->idate($minmonthpost)."'"; + $resql = $db->query($sql); + if ($resql) { + $num = $db->num_rows($resql); + $i = 0; + while ($i < $num) { + $i++; + $obj = $db->fetch_object($resql); + $nb_post_ip = $obj->nb_confs; + } + } + } + + $resultconforbooth = 0; + + if ($nb_post_max > 0 && $nb_post_ip >= $nb_post_max) { + $error++; + $errmsg .= $langs->trans("AlreadyTooMuchPostOnThisIPAdress"); + array_push($conforbooth->errors, $langs->trans("AlreadyTooMuchPostOnThisIPAdress")); + setEventMessage($errmsg, 'errors'); + } else { + $resultconforbooth = $conforbooth->create($user); + } if ($resultconforbooth<=0) { $error++; $errmsg .= $conforbooth->error; diff --git a/htdocs/public/project/suggestconference.php b/htdocs/public/project/suggestconference.php index f0b9299f980..5590b0bf94c 100644 --- a/htdocs/public/project/suggestconference.php +++ b/htdocs/public/project/suggestconference.php @@ -56,6 +56,7 @@ require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php'; require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/paymentterm.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; global $dolibarr_main_url_root; @@ -359,7 +360,41 @@ if (empty($reshook) && $action == 'add') { $conforbooth->tms = dol_now(); $conforbooth->firstname = $contact->firstname; $conforbooth->lastname = $contact->lastname; - $resultconforbooth = $conforbooth->create($user); + $conforbooth->ip = getUserRemoteIP(); + + $nb_post_max = getDolGlobalInt("MAIN_SECURITY_MAX_POST_ON_PUBLIC_PAGES_BY_IP_ADDRESS", 200); + $now = dol_now(); + $minmonthpost = dol_time_plus_duree($now, -1, "m"); + + // Calculate nb of post for IP + $nb_post_ip = 0; + if ($nb_post_max > 0) { // Calculate only if there is a limit to check + $sql = "SELECT COUNT(ref) as nb_confs"; + $sql .= " FROM ".MAIN_DB_PREFIX."actioncomm"; + $sql .= " WHERE ip = '".$db->escape($conforbooth->ip)."'"; + $sql .= " AND datec > '".$db->idate($minmonthpost)."'"; + $resql = $db->query($sql); + if ($resql) { + $num = $db->num_rows($resql); + $i = 0; + while ($i < $num) { + $i++; + $obj = $db->fetch_object($resql); + $nb_post_ip = $obj->nb_confs; + } + } + } + + $resultconforbooth = 0; + + if ($nb_post_max > 0 && $nb_post_ip >= $nb_post_max) { + $error++; + $errmsg .= $langs->trans("AlreadyTooMuchPostOnThisIPAdress"); + array_push($conforbooth->errors, $langs->trans("AlreadyTooMuchPostOnThisIPAdress")); + setEventMessage($errmsg, 'errors'); + } else { + $resultconforbooth = $conforbooth->create($user); + } if ($resultconforbooth<=0) { $error++; $errmsg .= $conforbooth->error; diff --git a/htdocs/public/recruitment/index.php b/htdocs/public/recruitment/index.php index bb135d54d50..23a180b9a7b 100644 --- a/htdocs/public/recruitment/index.php +++ b/htdocs/public/recruitment/index.php @@ -171,6 +171,7 @@ if (!empty($conf->global->RECRUITMENT_IMAGE_PUBLIC_INTERFACE)) { $results = $object->fetchAll($sortfield, $sortorder, 0, 0, array('status' => 1)); +$now = dol_now(); if (is_array($results)) { if (empty($results)) { diff --git a/htdocs/public/ticket/create_ticket.php b/htdocs/public/ticket/create_ticket.php index 43c2e7bbd78..75111725df0 100644 --- a/htdocs/public/ticket/create_ticket.php +++ b/htdocs/public/ticket/create_ticket.php @@ -60,6 +60,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/ticket.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/security.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php'; require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php'; @@ -246,7 +247,9 @@ if (empty($reshook)) { $object->severity_code = GETPOST("severity_code", 'aZ09'); $object->ip = getUserRemoteIP(); - $nb_post_max = getDolGlobalInt("MAIN_SECURITY_MAX_POST_ON_PUBLIC_PAGES_BY_IP_ADDRESS", 1000); + $nb_post_max = getDolGlobalInt("MAIN_SECURITY_MAX_POST_ON_PUBLIC_PAGES_BY_IP_ADDRESS", 200); + $now = dol_now(); + $minmonthpost = dol_time_plus_duree($now, -1, "m"); // Calculate nb of post for IP $nb_post_ip = 0; @@ -254,6 +257,7 @@ if (empty($reshook)) { $sql = "SELECT COUNT(ref) as nb_tickets"; $sql .= " FROM ".MAIN_DB_PREFIX."ticket"; $sql .= " WHERE ip = '".$db->escape($object->ip)."'"; + $sql .= " AND datec > '".$db->idate($minmonthpost)."'"; $resql = $db->query($sql); if ($resql) { $num = $db->num_rows($resql); diff --git a/htdocs/reception/card.php b/htdocs/reception/card.php index 9fdae4e0cc7..adbbdfefa80 100644 --- a/htdocs/reception/card.php +++ b/htdocs/reception/card.php @@ -1286,7 +1286,7 @@ if ($action == 'create') { $lines = $object->lines; $num_prod = count($lines); - + $indiceAsked = 0; if ($object->id > 0) { if (!empty($object->origin) && $object->origin_id > 0) { $object->origin = 'CommandeFournisseur'; diff --git a/htdocs/reception/class/reception.class.php b/htdocs/reception/class/reception.class.php index ebb50154eda..bda9821f993 100644 --- a/htdocs/reception/class/reception.class.php +++ b/htdocs/reception/class/reception.class.php @@ -50,6 +50,11 @@ class Reception extends CommonObject { use CommonIncoterm; + /** + * @var string code + */ + public $code = ""; + /** * @var string element name */ @@ -113,6 +118,10 @@ class Reception extends CommonObject public $lines = array(); + // detail of lot and qty = array(id in llx_commande_fournisseur_dispatch, batch, qty) + // We can use this to know warehouse planned to be used for each lot. + public $detail_batch; + const STATUS_DRAFT = 0; const STATUS_VALIDATED = 1; const STATUS_CLOSED = 2; @@ -1204,6 +1213,14 @@ class Reception extends CommonObject $this->total_ttc += $pu_ht + $tva; + if (isModEnabled('productbatch') && !empty($line->batch)) { + $detail_batch = new stdClass(); + $detail_batch->eatby = $line->eatby; + $detail_batch->sellby = $line->sellby; + $detail_batch->batch = $line->batch; + $detail_batch->qty = $line->qty; + $line->detail_batch[] = $detail_batch; + } $this->lines[] = $line; } diff --git a/htdocs/reception/list.php b/htdocs/reception/list.php index 210f068af0a..cac761023ef 100644 --- a/htdocs/reception/list.php +++ b/htdocs/reception/list.php @@ -531,6 +531,9 @@ if (!empty($extrafields->attributes[$object->table_element]['label'])) { $parameters = array(); $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters); // Note that $action and $object may have been modified by hook $sql .= $hookmanager->resPrint; + +$sqlfields = $sql; // $sql fields to remove for count total + $sql .= " FROM ".MAIN_DB_PREFIX."reception as e"; if (!empty($extrafields->attributes[$object->table_element]['label']) && is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label'])) { $sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$object->table_element."_extrafields as ef on (e.rowid = ef.fk_object)"; @@ -614,12 +617,29 @@ $sql .= $hookmanager->resPrint; $nbtotalofrecords = ''; if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { - $result = $db->query($sql); - $nbtotalofrecords = $db->num_rows($result); + /* The fast and low memory method to get and count full list converts the sql into a sql count */ + $sqlforcount = preg_replace('/^'.preg_quote($sqlfields, '/').'/', 'SELECT COUNT(*) as nbtotalofrecords', $sql); + $sqlforcount = preg_replace('/GROUP BY .*$/', '', $sqlforcount); + $resql = $db->query($sqlforcount); + if ($resql) { + $objforcount = $db->fetch_object($resql); + $nbtotalofrecords = $objforcount->nbtotalofrecords; + } else { + dol_print_error($db); + } + + if (($page * $limit) > $nbtotalofrecords) { // if total resultset is smaller then paging size (filtering), goto and load page 0 + $page = 0; + $offset = 0; + } + $db->free($resql); } +// Complete request and execute it with limit $sql .= $db->order($sortfield, $sortorder); -$sql .= $db->plimit($limit + 1, $offset); +if ($limit) { + $sql .= $db->plimit($limit + 1, $offset); +} //print $sql; $resql = $db->query($sql); diff --git a/htdocs/reception/stats/index.php b/htdocs/reception/stats/index.php index 1e26bf5871a..df11e2a9cd5 100644 --- a/htdocs/reception/stats/index.php +++ b/htdocs/reception/stats/index.php @@ -41,7 +41,7 @@ $year = GETPOST('year') > 0 ?GETPOST('year') : $nowyear; $startyear = $year - (empty($conf->global->MAIN_STATS_GRAPHS_SHOW_N_YEARS) ? 2 : max(1, min(10, $conf->global->MAIN_STATS_GRAPHS_SHOW_N_YEARS))); $endyear = $year; -$langs->loadLangs(array("reception", "other", "companies")); +$langs->loadLangs(array("receptions", "other", "companies")); // Security check if ($user->socid) { diff --git a/htdocs/recruitment/class/api_recruitment.class.php b/htdocs/recruitment/class/api_recruitment.class.php index af2c87dcdb3..cf4fa7a143e 100644 --- a/htdocs/recruitment/class/api_recruitment.class.php +++ b/htdocs/recruitment/class/api_recruitment.class.php @@ -441,7 +441,7 @@ class Recruitment extends DolibarrApi // $this->jobposition->abc = sanitizeVal($this->jobposition->abc, 'alphanohtml'); if ($this->jobposition->update(DolibarrApiAccess::$user, false) > 0) { - return $this->get($id); + return $this->getJobPosition($id); } else { throw new RestException(500, $this->jobposition->error); } @@ -484,7 +484,7 @@ class Recruitment extends DolibarrApi // $this->jobposition->abc = sanitizeVal($this->jobposition->abc, 'alphanohtml'); if ($this->candidature->update(DolibarrApiAccess::$user, false) > 0) { - return $this->get($id); + return $this->getCandidature($id); } else { throw new RestException(500, $this->candidature->error); } diff --git a/htdocs/recruitment/class/recruitmentjobposition.class.php b/htdocs/recruitment/class/recruitmentjobposition.class.php index dda796c243e..7a9d077f910 100644 --- a/htdocs/recruitment/class/recruitmentjobposition.class.php +++ b/htdocs/recruitment/class/recruitmentjobposition.class.php @@ -1,5 +1,6 @@ +/* Copyright (C) 2020 Laurent Destailleur +/* Copyright (C) 2022 Alexandre Spangaro * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -62,10 +63,24 @@ class RecruitmentJobPosition extends CommonObject */ public $picto = 'recruitmentjobposition'; - + /** + * Draft status + */ const STATUS_DRAFT = 0; + + /** + * Validated + */ const STATUS_VALIDATED = 1; + + /** + * Recruited + */ const STATUS_RECRUITED = 3; + + /** + * Canceled + */ const STATUS_CANCELED = 9; @@ -651,7 +666,7 @@ class RecruitmentJobPosition extends CommonObject } /** - * Close the commercial proposal + * Close the recruitment * * @param User $user Object user that close * @param int $status Statut @@ -683,12 +698,6 @@ class RecruitmentJobPosition extends CommonObject if ($status == self::STATUS_RECRUITED) { $triggerName = 'RECRUITMENTJOB_CLOSE_RECRUITED'; $modelpdf = $this->model_pdf; - - if ($result < 0) { - $this->error = $this->db->lasterror(); - $this->db->rollback(); - return -2; - } } if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) { diff --git a/htdocs/recruitment/core/modules/recruitment/doc/doc_generic_recruitmentjobposition_odt.modules.php b/htdocs/recruitment/core/modules/recruitment/doc/doc_generic_recruitmentjobposition_odt.modules.php index c86713ffb93..cfbf91463e8 100644 --- a/htdocs/recruitment/core/modules/recruitment/doc/doc_generic_recruitmentjobposition_odt.modules.php +++ b/htdocs/recruitment/core/modules/recruitment/doc/doc_generic_recruitmentjobposition_odt.modules.php @@ -28,6 +28,7 @@ */ require_once DOL_DOCUMENT_ROOT.'/recruitment/core/modules/recruitment/modules_recruitmentjobposition.php'; +require_once DOL_DOCUMENT_ROOT.'/recruitment/class/recruitmentjobposition.class.php'; require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; @@ -238,7 +239,7 @@ class doc_generic_recruitmentjobposition_odt extends ModelePDFRecruitmentJobPosi // If $object is id instead of object if (!is_object($object)) { $id = $object; - $object = new Commande($this->db); + $object = new RecruitmentJobPosition($this->db); $result = $object->fetch($id); if ($result < 0) { dol_print_error($this->db, $object->error); @@ -286,7 +287,11 @@ class doc_generic_recruitmentjobposition_odt extends ModelePDFRecruitmentJobPosi //print "conf->societe->dir_temp=".$conf->societe->dir_temp; dol_mkdir($conf->recruitment->dir_temp); - + if (!is_writable($conf->recruitment->dir_temp)) { + $this->error = $langs->transnoentities("ErrorFailedToWriteInTempDirectory", $conf->recruitment->dir_temp); + dol_syslog('Error in write_file: ' . $this->error, LOG_ERR); + return -1; + } // If CUSTOMER contact defined on order, we use it $usecontact = false; @@ -339,7 +344,7 @@ class doc_generic_recruitmentjobposition_odt extends ModelePDFRecruitmentJobPosi $odfHandler = new odf( $srctemplatepath, array( - 'PATH_TO_TMP' => $conf->commande->dir_temp, + 'PATH_TO_TMP' => $conf->recruitment->dir_temp, 'ZIP_PROXY' => 'PclZipProxy', // PhpZipProxy or PclZipProxy. Got "bad compression method" error when using PhpZipProxy. 'DELIMITER_LEFT' => '{', 'DELIMITER_RIGHT' => '}' diff --git a/htdocs/recruitment/recruitmentjobposition_card.php b/htdocs/recruitment/recruitmentjobposition_card.php index be1b9eec084..d1ca4ef2db1 100644 --- a/htdocs/recruitment/recruitmentjobposition_card.php +++ b/htdocs/recruitment/recruitmentjobposition_card.php @@ -291,7 +291,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea require_once DOL_DOCUMENT_ROOT.'/core/class/notify.class.php'; $notify = new Notify($db); $formquestion = array_merge($formquestion, array( - array('type' => 'onecolumn', 'value' => $notify->confirmMessage('PROPAL_CLOSE_SIGNED', $object->socid, $object)), + array('type' => 'onecolumn', 'value' => $notify->confirmMessage('RECRUITMENTJOBPOSITION_CLOSE_SIGNED', $object->socid, $object)), )); }*/ diff --git a/htdocs/recruitment/recruitmentjobposition_list.php b/htdocs/recruitment/recruitmentjobposition_list.php index b2edac8dd4d..e6b538b5167 100644 --- a/htdocs/recruitment/recruitmentjobposition_list.php +++ b/htdocs/recruitment/recruitmentjobposition_list.php @@ -446,7 +446,7 @@ if (!empty($moreforfilter)) { } $varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage; -$selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields +$selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage, getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')); // This also change content of $arrayfields $selectedfields .= (count($arrayofmassactions) ? $form->showCheckAddButtons('checkforselect', 1) : ''); print '
'; // You can use div-table-responsive-no-min if you dont need reserved height for your table @@ -456,6 +456,13 @@ print ''; +// Action column +if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print ''; +} foreach ($object->fields as $key => $val) { $cssforfield = (empty($val['csslist']) ? (empty($val['css']) ? '' : $val['css']) : $val['csslist']); if ($key == 'status') { @@ -501,10 +508,12 @@ if (!empty($arrayfields['nbapplications']['checked'])) { print ''; } // Action column -print ''; +if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print ''; +} print ''."\n"; $totalarray = array(); @@ -513,6 +522,10 @@ $totalarray['nbfield'] = 0; // Fields title label // -------------------------------------------------------------------- print ''; +// Action column +if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print getTitleFieldOfList(($mode != 'kanban' ? $selectedfields : ''), 0, $_SERVER["PHP_SELF"], '', '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ')."\n"; +} foreach ($object->fields as $key => $val) { $cssforfield = (empty($val['csslist']) ? (empty($val['css']) ? '' : $val['css']) : $val['csslist']); if ($key == 'status') { @@ -540,7 +553,9 @@ if (!empty($arrayfields['nbapplications']['checked'])) { $totalarray['nbfield']++; } // Action column -print getTitleFieldOfList(($mode != 'kanban' ? $selectedfields : ''), 0, $_SERVER["PHP_SELF"], '', '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ')."\n"; +if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print getTitleFieldOfList(($mode != 'kanban' ? $selectedfields : ''), 0, $_SERVER["PHP_SELF"], '', '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ')."\n"; +} $totalarray['nbfield']++; print ''."\n"; @@ -586,6 +601,18 @@ while ($i < $imaxinloop) { // Show here line of result $j = 0; print ''; + // Action column + if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print ''; + } foreach ($object->fields as $key => $val) { $cssforfield = (empty($val['csslist']) ? (empty($val['css']) ? '' : $val['css']) : $val['csslist']); if (in_array($val['type'], array('date', 'datetime', 'timestamp'))) { @@ -642,15 +669,17 @@ while ($i < $imaxinloop) { print ''; } // Action column - print ''; } - print ''; if (!$i) { $totalarray['nbfield']++; } diff --git a/htdocs/resource/contact.php b/htdocs/resource/contact.php index 45e4ce4b329..3b032fffb94 100644 --- a/htdocs/resource/contact.php +++ b/htdocs/resource/contact.php @@ -114,10 +114,6 @@ llxHeader('', $langs->trans("Resource")); // View and edit mode if ($id > 0 || !empty($ref)) { - $soc = new Societe($db); - $soc->fetch($object->socid); - - $head = resource_prepare_head($object); print dol_get_fiche_head($head, 'contact', $langs->trans("ResourceSingular"), -1, 'resource'); diff --git a/htdocs/salaries/card.php b/htdocs/salaries/card.php index 5ba1b818137..0b961648115 100644 --- a/htdocs/salaries/card.php +++ b/htdocs/salaries/card.php @@ -110,12 +110,13 @@ $permissiontoadd = $user->rights->salaries->write; // Used by the include of act $permissiontodelete = $user->rights->salaries->delete || ($permissiontoadd && isset($object->status) && $object->status == $object::STATUS_DRAFT); -/** +/* * Actions */ $parameters = array(); -$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks +// Note that $action and $object may be modified by some hooks +$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); if ($reshook < 0) { setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); } @@ -123,14 +124,14 @@ if ($reshook < 0) { if (empty($reshook)) { $error = 0; - $backurlforlist = dol_buildpath('/salaries/list.php', 1); + $backurlforlist = DOL_URL_ROOT.'/salaries/list.php'; if (empty($backtopage) || ($cancel && empty($id))) { if (empty($backtopage) || ($cancel && strpos($backtopage, '__ID__'))) { if (empty($id) && (($action != 'add' && $action != 'create') || $cancel)) { $backtopage = $backurlforlist; } else { - $backtopage = dol_buildpath('/salaries/card.php', 1).'?id='.($id > 0 ? $id : '__ID__'); + $backtopage = DOL_URL_ROOT.'/salaries/card.php?id='.($id > 0 ? $id : '__ID__'); } } } @@ -444,9 +445,10 @@ $form = new Form($db); $formfile = new FormFile($db); if (isModEnabled('project')) $formproject = new FormProjets($db); -$title = $langs->trans('Salary')." - ".$langs->trans('Card'); +$title = $langs->trans('Salary')." - ".$object->ref; $help_url = ""; -llxHeader("", $title, $help_url); + +llxHeader('', $title, $help_url); if ($id > 0) { @@ -458,7 +460,7 @@ if ($id > 0) { } // Create -if ($action == 'create') { +if ($action == 'create' && $permissiontoadd) { $year_current = dol_print_date(dol_now('gmt'), "%Y", 'gmt'); $pastmonth = strftime("%m", dol_now()) - 1; $pastmonthyear = $year_current; @@ -480,7 +482,7 @@ if ($action == 'create') { $datesp = dol_get_first_day($pastmonthyear, $pastmonth, false); $dateep = dol_get_last_day($pastmonthyear, $pastmonth, false); } - print ''; + print ''; print ''; print ''; if ($backtopage) { @@ -522,7 +524,7 @@ if ($action == 'create') { print ''."\n"; } - print dol_get_fiche_head('', ''); + print dol_get_fiche_head(''); print '
'; + $searchpicto = $form->showFilterButtons('left'); + print $searchpicto; + print ''; -$searchpicto = $form->showFilterButtons(); -print $searchpicto; -print ''; + $searchpicto = $form->showFilterButtons(); + print $searchpicto; + print '
'; + if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined + $selected = 0; + if (in_array($object->id, $arrayofselected)) { + $selected = 1; + } + print ''; + } + print ''.$obj->nbapplications.''; - if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined - $selected = 0; - if (in_array($object->id, $arrayofselected)) { - $selected = 1; + if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print ''; + if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined + $selected = 0; + if (in_array($object->id, $arrayofselected)) { + $selected = 1; + } + print ''; } - print ''; + print '
'; @@ -683,7 +685,7 @@ if ($action == 'create') { ); } else { - alert("'.dol_escape_js($langs->trans("FillFieldFirst")).'"); + alert("'.dol_escape_js($langs->transnoentitiesnoconv("FillFieldFirst")).'"); } }); @@ -692,13 +694,8 @@ if ($action == 'create') { } -/* ************************************************************************** */ -/* */ -/* View mode */ -/* */ -/* ************************************************************************** */ - -if ($id) { +// View mode +if ($id > 0) { $head = salaries_prepare_head($object); $formconfirm = ''; @@ -794,34 +791,26 @@ if ($id) { $morehtmlref .= ''; } + $usercancreate = $permissiontoadd; + // Project if (isModEnabled('project')) { - $morehtmlref .= '
'.$langs->trans('Project').' '; - if ($user->rights->salaries->write) { + $langs->load("projects"); + $morehtmlref .= '
'; + if ($usercancreate) { + $morehtmlref .= img_picto($langs->trans("Project"), 'project', 'class="pictofixedwidth"'); if ($action != 'classify') { - $morehtmlref .= ''.img_edit($langs->transnoentitiesnoconv('SetProject')).' : '; - } - if ($action == 'classify') { - //$morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'projectid', 0, 0, 1, 1); - $morehtmlref .= ''; - $morehtmlref .= ''; - $morehtmlref .= ''; - $morehtmlref .= $formproject->select_projects(-1, $object->fk_project, 'projectid', 0, 0, 1, 0, 1, 0, 0, '', 1, 0, 'maxwidth500'); - $morehtmlref .= ''; - $morehtmlref .= ''; - } else { - $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, $object->fk_project, 'none', 0, 0, 0, 1); + $morehtmlref .= ''.img_edit($langs->transnoentitiesnoconv('SetProject')).' '; } + $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, ($action == 'classify' ? 1 : 0), 0, 1, ''); } else { if (!empty($object->fk_project)) { $proj = new Project($db); $proj->fetch($object->fk_project); - $morehtmlref .= ' : '.$proj->getNomUrl(1); + $morehtmlref .= $proj->getNomUrl(1); if ($proj->title) { - $morehtmlref .= ' - '.$proj->title; + $morehtmlref .= ' - '.dol_escape_htmltag($proj->title).''; } - } else { - $morehtmlref .= ''; } } } diff --git a/htdocs/salaries/class/paymentsalary.class.php b/htdocs/salaries/class/paymentsalary.class.php index 1a716cba31d..860deaa69f0 100644 --- a/htdocs/salaries/class/paymentsalary.class.php +++ b/htdocs/salaries/class/paymentsalary.class.php @@ -701,8 +701,7 @@ class PaymentSalary extends CommonObject $link = ''; $linkend = ''; - if ($withpicto) $result .= ($link.img_object($label, 'payment', 'class="classfortooltip"').$linkend.' '); - if ($withpicto && $withpicto != 2) $result .= ' '; + if ($withpicto) $result .= ($link.img_object($label, 'payment', 'class="classfortooltip pictofixedwidth"').$linkend); if ($withpicto != 2) $result .= $link.($maxlen ?dol_trunc($this->ref, $maxlen) : $this->ref).$linkend; } diff --git a/htdocs/salaries/class/salary.class.php b/htdocs/salaries/class/salary.class.php index 8949313ecb0..25adb60382c 100644 --- a/htdocs/salaries/class/salary.class.php +++ b/htdocs/salaries/class/salary.class.php @@ -544,7 +544,7 @@ class Salary extends CommonObject $linkend = ''; $result .= $linkstart; - if ($withpicto) $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip ? 0 : 1); + if ($withpicto) $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright pictofixedwidth"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip pictofixedwidth"'), 0, 0, $notooltip ? 0 : 1); if ($withpicto != 2) $result .= $this->ref; $result .= $linkend; //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : ''); diff --git a/htdocs/salaries/document.php b/htdocs/salaries/document.php index 163042dbeb8..2ce7b2e2745 100644 --- a/htdocs/salaries/document.php +++ b/htdocs/salaries/document.php @@ -78,7 +78,9 @@ $childids = $user->getAllChildIds(1); // fetch optionals attributes and labels $extrafields->fetch_name_optionals_label($object->table_element); -$object = new Salary($db); +// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context +$hookmanager->initHooks(array('salarydoc', 'globalcard')); + if ($id > 0 || !empty($ref)) { $object->fetch($id, $ref); @@ -105,7 +107,9 @@ if ($user->socid) { } restrictedArea($user, 'salaries', $object->id, 'salary', ''); +$permissiontoread = $user->rights->salaries->read; $permissiontoadd = $user->rights->salaries->write; // Used by the include of actions_addupdatedelete.inc.php and actions_linkedfiles +$permissiontodelete = $user->rights->salaries->delete || ($permissiontoadd && isset($object->status) && $object->status == $object::STATUS_DRAFT); /* @@ -176,34 +180,26 @@ if ($object->id) { $morehtmlref .= '
'.$langs->trans('Employee').' : '.$userstatic->getNomUrl(-1); + $usercancreate = $permissiontoadd; + // Project if (isModEnabled('project')) { - $morehtmlref .= '
'.$langs->trans('Project').' '; - if ($user->rights->salaries->write) { + $langs->load("projects"); + $morehtmlref .= '
'; + if ($usercancreate) { + $morehtmlref .= img_picto($langs->trans("Project"), 'project', 'class="pictofixedwidth"'); if ($action != 'classify') { - $morehtmlref .= ''.img_edit($langs->transnoentitiesnoconv('SetProject')).' : '; - } - if ($action == 'classify') { - //$morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'projectid', 0, 0, 1, 1); - $morehtmlref .= ''; - $morehtmlref .= ''; - $morehtmlref .= ''; - $morehtmlref .= $formproject->select_projects(-1, $object->fk_project, 'projectid', 0, 0, 1, 0, 1, 0, 0, '', 1, 0, 'maxwidth500'); - $morehtmlref .= ''; - $morehtmlref .= ''; - } else { - $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, -1, $object->fk_project, 'none', 0, 0, 0, 1); + $morehtmlref .= ''.img_edit($langs->transnoentitiesnoconv('SetProject')).' '; } + $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, ($action == 'classify' ? 1 : 0), 0, 1, ''); } else { if (!empty($object->fk_project)) { $proj = new Project($db); $proj->fetch($object->fk_project); - $morehtmlref .= ' : '.$proj->getNomUrl(1); + $morehtmlref .= $proj->getNomUrl(1); if ($proj->title) { - $morehtmlref .= ' - '.$proj->title; + $morehtmlref .= ' - '.dol_escape_htmltag($proj->title).''; } - } else { - $morehtmlref .= ''; } } } diff --git a/htdocs/salaries/info.php b/htdocs/salaries/info.php index e16493ddc91..1085b1175cf 100644 --- a/htdocs/salaries/info.php +++ b/htdocs/salaries/info.php @@ -58,6 +58,9 @@ $childids = $user->getAllChildIds(1); // fetch optionals attributes and labels $extrafields->fetch_name_optionals_label($object->table_element); +// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context +$hookmanager->initHooks(array('salaryinfo', 'globalcard')); + $object = new Salary($db); if ($id > 0 || !empty($ref)) { $object->fetch($id, $ref); @@ -77,6 +80,10 @@ if ($id > 0 || !empty($ref)) { restrictedArea($user, 'salaries', $object->id, 'salary', ''); +$permissiontoread = $user->rights->salaries->read; +$permissiontoadd = $user->rights->salaries->write; // Used by the include of actions_addupdatedelete.inc.php and actions_linkedfiles +$permissiontodelete = $user->rights->salaries->delete || ($permissiontoadd && isset($object->status) && $object->status == $object::STATUS_DRAFT); + /* * Actions @@ -107,7 +114,6 @@ $title = $langs->trans('Salary')." - ".$langs->trans('Info'); $help_url = ""; llxHeader("", $title, $help_url); -$object = new Salary($db); $object->fetch($id); $object->info($id); @@ -139,34 +145,26 @@ if ($action != 'editlabel') { $morehtmlref .= '
'.$langs->trans('Employee').' : '.$userstatic->getNomUrl(-1); +$usercancreate = $permissiontoadd; + // Project if (isModEnabled('project')) { - $morehtmlref .= '
'.$langs->trans('Project').' '; - if ($user->rights->salaries->write) { + $langs->load("projects"); + $morehtmlref .= '
'; + if ($usercancreate) { + $morehtmlref .= img_picto($langs->trans("Project"), 'project', 'class="pictofixedwidth"'); if ($action != 'classify') { - $morehtmlref .= ''.img_edit($langs->transnoentitiesnoconv('SetProject')).' : '; - } - if ($action == 'classify') { - //$morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'projectid', 0, 0, 1, 1); - $morehtmlref .= ''; - $morehtmlref .= ''; - $morehtmlref .= ''; - $morehtmlref .= $formproject->select_projects(-1, $object->fk_project, 'projectid', 0, 0, 1, 0, 1, 0, 0, '', 1, 0, 'maxwidth500'); - $morehtmlref .= ''; - $morehtmlref .= ''; - } else { - $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, $object->fk_project, 'none', 0, 0, 0, 1); + $morehtmlref .= ''.img_edit($langs->transnoentitiesnoconv('SetProject')).' '; } + $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, ($action == 'classify' ? 1 : 0), 0, 1, ''); } else { if (!empty($object->fk_project)) { $proj = new Project($db); $proj->fetch($object->fk_project); - $morehtmlref .= ' : '.$proj->getNomUrl(1); + $morehtmlref .= $proj->getNomUrl(1); if ($proj->title) { - $morehtmlref .= ' - '.$proj->title; + $morehtmlref .= ' - '.dol_escape_htmltag($proj->title).''; } - } else { - $morehtmlref .= ''; } } } @@ -180,7 +178,7 @@ print '
'; print '
'; -print '
'; +//Status print ''; // Extra fields diff --git a/htdocs/societe/class/api_thirdparties.class.php b/htdocs/societe/class/api_thirdparties.class.php index 3901db79cc4..db7eec3096e 100644 --- a/htdocs/societe/class/api_thirdparties.class.php +++ b/htdocs/societe/class/api_thirdparties.class.php @@ -538,7 +538,20 @@ class Thirdparties extends DolibarrApi throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); } $this->company->oldcopy = clone $this->company; - return $this->company->delete($id); + + $res = $this->company->delete($id); + if ($res < 0) { + throw new RestException(500, "Can't delete, error occurs"); + } elseif ($res == 0) { + throw new RestException(409, "Can't delete, that product is probably used"); + } + + return array( + 'success' => array( + 'code' => 200, + 'message' => 'Object deleted' + ) + ); } /** @@ -1154,7 +1167,7 @@ class Thirdparties extends DolibarrApi */ public function getCompanyBankAccount($id) { - if (!DolibarrApiAccess::$user->rights->facture->lire) { + if (!DolibarrApiAccess::$user->rights->societe->lire) { throw new RestException(401); } if (empty($id)) { diff --git a/htdocs/societe/class/companybankaccount.class.php b/htdocs/societe/class/companybankaccount.class.php index c3ecbe31ccd..d81a360e7d2 100644 --- a/htdocs/societe/class/companybankaccount.class.php +++ b/htdocs/societe/class/companybankaccount.class.php @@ -242,8 +242,7 @@ class CompanyBankAccount extends Account $sql .= " FROM ".MAIN_DB_PREFIX."societe_rib"; if ($id) { $sql .= " WHERE rowid = ".((int) $id); - } - if ($socid) { + } elseif ($socid > 0) { $sql .= " WHERE fk_soc = ".((int) $socid); if ($default > -1) { $sql .= " AND default_rib = ".((int) $default); diff --git a/htdocs/societe/class/societe.class.php b/htdocs/societe/class/societe.class.php index 8da7e20e4e5..1fb149ba250 100644 --- a/htdocs/societe/class/societe.class.php +++ b/htdocs/societe/class/societe.class.php @@ -2702,23 +2702,24 @@ class Societe extends CommonObject if (!empty($this->tva_intra) || (!empty($conf->global->SOCIETE_SHOW_FIELD_IN_TOOLTIP) && strpos($conf->global->SOCIETE_SHOW_FIELD_IN_TOOLTIP, 'vatnumber') !== false)) { $label2 .= '
'.$langs->trans('VATIntra').': '.dol_escape_htmltag($this->tva_intra); } + if (!empty($conf->global->SOCIETE_SHOW_FIELD_IN_TOOLTIP)) { - if (strpos($conf->global->SOCIETE_SHOW_FIELD_IN_TOOLTIP, 'profid1') !== false) { + if (strpos($conf->global->SOCIETE_SHOW_FIELD_IN_TOOLTIP, 'profid1') !== false && $langs->trans('ProfId1'.$this->country_code) != '-') { $label2 .= '
'.$langs->trans('ProfId1'.$this->country_code).': '.$this->idprof1; } - if (strpos($conf->global->SOCIETE_SHOW_FIELD_IN_TOOLTIP, 'profid2') !== false) { + if (strpos($conf->global->SOCIETE_SHOW_FIELD_IN_TOOLTIP, 'profid2') !== false && $langs->trans('ProfId2'.$this->country_code) != '-') { $label2 .= '
'.$langs->trans('ProfId2'.$this->country_code).': '.$this->idprof2; } - if (strpos($conf->global->SOCIETE_SHOW_FIELD_IN_TOOLTIP, 'profid3') !== false) { + if (strpos($conf->global->SOCIETE_SHOW_FIELD_IN_TOOLTIP, 'profid3') !== false && $langs->trans('ProfId3'.$this->country_code) != '-') { $label2 .= '
'.$langs->trans('ProfId3'.$this->country_code).': '.$this->idprof3; } - if (strpos($conf->global->SOCIETE_SHOW_FIELD_IN_TOOLTIP, 'profid4') !== false) { + if (strpos($conf->global->SOCIETE_SHOW_FIELD_IN_TOOLTIP, 'profid4') !== false && $langs->trans('ProfId4'.$this->country_code) != '-') { $label2 .= '
'.$langs->trans('ProfId4'.$this->country_code).': '.$this->idprof4; } - if (strpos($conf->global->SOCIETE_SHOW_FIELD_IN_TOOLTIP, 'profid5') !== false) { + if (strpos($conf->global->SOCIETE_SHOW_FIELD_IN_TOOLTIP, 'profid5') !== false && $langs->trans('ProfId5'.$this->country_code) != '-') { $label2 .= '
'.$langs->trans('ProfId5'.$this->country_code).': '.$this->idprof5; } - if (strpos($conf->global->SOCIETE_SHOW_FIELD_IN_TOOLTIP, 'profid6') !== false) { + if (strpos($conf->global->SOCIETE_SHOW_FIELD_IN_TOOLTIP, 'profid6') !== false && $langs->trans('ProfId6'.$this->country_code) != '-') { $label2 .= '
'.$langs->trans('ProfId6'.$this->country_code).': '.$this->idprof6; } } diff --git a/htdocs/societe/list.php b/htdocs/societe/list.php index dfb5f5ee279..6da7fcf3779 100644 --- a/htdocs/societe/list.php +++ b/htdocs/societe/list.php @@ -488,6 +488,9 @@ if (!empty($extrafields->attributes[$object->table_element]['label'])) { $parameters = array(); $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters, $object, $action); // Note that $action and $object may have been modified by hook $sql .= $hookmanager->resPrint; + +$sqlfields = $sql; // $sql fields to remove for count total + $sql .= " FROM ".MAIN_DB_PREFIX."societe as s"; $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s2 ON s.parent = s2.rowid"; if (!empty($extrafields->attributes[$object->table_element]['label']) && is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label'])) { @@ -723,14 +726,9 @@ $sql .= $hookmanager->resPrint; // Count total nb of records with no order and no limits $nbtotalofrecords = ''; if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { - /*$resql = $db->query($sql); - if ($resql) { - $nbtotalofrecords = $db->num_rows($resql); - } else { - dol_print_error($db); - }*/ /* The fast and low memory method to get and count full list converts the sql into a sql count */ - $sqlforcount = preg_replace('/^SELECT[a-zA-Z0-9\._\s\(\),=<>\:\-\']+\sFROM/Ui', 'SELECT COUNT(*) as nbtotalofrecords FROM', $sql); + $sqlforcount = preg_replace('/^'.preg_quote($sqlfields, '/').'/', 'SELECT COUNT(*) as nbtotalofrecords', $sql); + $sqlforcount = preg_replace('/GROUP BY .*$/', '', $sqlforcount); $resql = $db->query($sqlforcount); if ($resql) { $objforcount = $db->fetch_object($resql); @@ -767,7 +765,7 @@ if ($num == 1 && !empty($conf->global->MAIN_SEARCH_DIRECT_OPEN_IF_ONLY_ONE) && ( $obj = $db->fetch_object($resql); $id = $obj->rowid; if (!empty($conf->global->SOCIETE_ON_SEARCH_AND_LIST_GO_ON_CUSTOMER_OR_SUPPLIER_CARD)) { - if ($obj->client > 0) { + if ($companystatic->client > 0) { header("Location: ".DOL_URL_ROOT.'/comm/card.php?socid='.$id); exit; } @@ -1447,27 +1445,36 @@ $totalarray = array(); $totalarray['nbfield'] = 0; while ($i < min($num, $limit)) { $obj = $db->fetch_object($resql); + $parameters = array('staticdata' => $obj); + // Note that $action and $object may have been modified by hook + // do companystatic fetch in hook if wanted or anything else + $reshook = $hookmanager->executeHooks('loadStaticObject', $parameters, $companystatic, $action); + if (empty($reshook)) { + $companystatic->id = $obj->rowid; + $companystatic->name = $obj->name; + $companystatic->name_alias = $obj->name_alias; + $companystatic->logo = $obj->logo; + $companystatic->barcode = $obj->barcode; + $companystatic->canvas = $obj->canvas; + $companystatic->client = $obj->client; + $companystatic->status = $obj->status; + $companystatic->email = $obj->email; + $companystatic->address = $obj->address; + $companystatic->zip = $obj->zip; + $companystatic->town = $obj->town; + $companystatic->fournisseur = $obj->fournisseur; + $companystatic->code_client = $obj->code_client; + $companystatic->code_fournisseur = $obj->code_fournisseur; + $companystatic->tva_intra = $obj->tva_intra; + $companystatic->country_code = $obj->country_code; - $companystatic->id = $obj->rowid; - $companystatic->name = $obj->name; - $companystatic->name_alias = $obj->name_alias; - $companystatic->logo = $obj->logo; - $companystatic->canvas = $obj->canvas; - $companystatic->client = $obj->client; - $companystatic->status = $obj->status; - $companystatic->email = $obj->email; - $companystatic->fournisseur = $obj->fournisseur; - $companystatic->code_client = $obj->code_client; - $companystatic->code_fournisseur = $obj->code_fournisseur; - $companystatic->tva_intra = $obj->tva_intra; - $companystatic->country_code = $obj->country_code; + $companystatic->code_compta_client = $obj->code_compta; + $companystatic->code_compta_fournisseur = $obj->code_compta_fournisseur; - $companystatic->code_compta_client = $obj->code_compta; - $companystatic->code_compta_fournisseur = $obj->code_compta_fournisseur; - - $companystatic->fk_prospectlevel = $obj->fk_prospectlevel; - $companystatic->fk_parent = $obj->fk_parent; - $companystatic->entity = $obj->entity; + $companystatic->fk_prospectlevel = $obj->fk_prospectlevel; + $companystatic->fk_parent = $obj->fk_parent; + $companystatic->entity = $obj->entity; + } print 'global->MAIN_SOCIETE_SHOW_COMPLETE_NAME) ? ' class="tdoverflowmax200"' : '').' data-key="ref">'; if ($contextpage == 'poslist') { - print dol_escape_htmltag($obj->name); + print dol_escape_htmltag($companystatic->name); } else { print $companystatic->getNomUrl(1, '', 100, 0, 1, empty($arrayfields['s.name_alias']['checked']) ? 0 : 1); } @@ -1520,56 +1527,56 @@ while ($i < min($num, $limit)) { } // Barcode if (!empty($arrayfields['s.barcode']['checked'])) { - print ''; + print ''; if (!$i) { $totalarray['nbfield']++; } } // Customer code if (!empty($arrayfields['s.code_client']['checked'])) { - print ''; + print ''; if (!$i) { $totalarray['nbfield']++; } } // Supplier code if (!empty($arrayfields['s.code_fournisseur']['checked'])) { - print ''; + print ''; if (!$i) { $totalarray['nbfield']++; } } // Account customer code if (!empty($arrayfields['s.code_compta']['checked'])) { - print ''; + print ''; if (!$i) { $totalarray['nbfield']++; } } // Account supplier code if (!empty($arrayfields['s.code_compta_fournisseur']['checked'])) { - print ''; + print ''; if (!$i) { $totalarray['nbfield']++; } } // Address if (!empty($arrayfields['s.address']['checked'])) { - print ''; + print ''; if (!$i) { $totalarray['nbfield']++; } } // Zip if (!empty($arrayfields['s.zip']['checked'])) { - print "\n"; + print "\n"; if (!$i) { $totalarray['nbfield']++; } } // Town if (!empty($arrayfields['s.town']['checked'])) { - print '\n"; + print '\n"; if (!$i) { $totalarray['nbfield']++; } @@ -1591,7 +1598,7 @@ while ($i < min($num, $limit)) { // Country if (!empty($arrayfields['country.code_iso']['checked'])) { print ''; if (!$i) { @@ -1638,13 +1645,13 @@ while ($i < min($num, $limit)) { } } if (!empty($arrayfields['s.phone']['checked'])) { - print '\n"; + print '\n"; if (!$i) { $totalarray['nbfield']++; } } if (!empty($arrayfields['s.fax']['checked'])) { - print '\n"; + print '\n"; if (!$i) { $totalarray['nbfield']++; } @@ -1693,11 +1700,11 @@ while ($i < min($num, $limit)) { } // VAT if (!empty($arrayfields['s.tva_intra']['checked'])) { - print '\n"; if (!$i) { $totalarray['nbfield']++; diff --git a/htdocs/stripe/charge.php b/htdocs/stripe/charge.php index f598275177e..0aee0c11e30 100644 --- a/htdocs/stripe/charge.php +++ b/htdocs/stripe/charge.php @@ -87,38 +87,18 @@ if (!$rowid) { $option = array('limit' => $limit + 1); $num = 0; + $param = ''; + $totalnboflines = ''; + $moreforfilter = ''; + $list = null; if (GETPOSTISSET('starting_after_'.$page)) { $option['starting_after'] = GETPOST('starting_after_'.$page, 'alphanohtml'); } - - try { - if ($stripeacc) { - $list = \Stripe\Charge::all($option, array("stripe_account" => $stripeacc)); - } else { - $list = \Stripe\Charge::all($option); - } - - $num = count($list->data); - - $totalnboflines = ''; - - $param = ''; - //if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param .= '&contextpage='.urlencode($contextpage); - if ($limit > 0 && $limit != $conf->liste_limit) { - $param .= '&limit='.urlencode($limit); - } - $param .= '&starting_after_'.($page + 1).'='.$list->data[($limit - 1)]->id; - //$param.='&ending_before_'.($page+1).'='.$list->data[($limit-1)]->id; - - $moreforfilter = ''; - } catch (Exception $e) { - print $e->getMessage(); - } - print ''; if ($optioncss != '') { print ''; } + print ''; print ''; print ''; @@ -145,146 +125,168 @@ if (!$rowid) { print_liste_field_titre("Status", $_SERVER["PHP_SELF"], "", "", "", '', '', '', 'right '); print "\n"; + try { + if ($stripeacc) { + $list = \Stripe\Charge::all($option, array("stripe_account" => $stripeacc)); + } else { + $list = \Stripe\Charge::all($option); + } + + $num = count($list->data); + + + //if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param .= '&contextpage='.urlencode($contextpage); + if ($limit > 0 && $limit != $conf->liste_limit) { + $param .= '&limit='.urlencode($limit); + } + $param .= '&starting_after_'.($page + 1).'='.$list->data[($limit - 1)]->id; + //$param.='&ending_before_'.($page+1).'='.$list->data[($limit-1)]->id; + } catch (Exception $e) { + print ''; + } + //print $list; $i = 0; - foreach ($list->data as $charge) { - if ($i >= $limit) { - break; - } + if (!empty($list)) { + foreach ($list->data as $charge) { + if ($i >= $limit) { + break; + } - if ($charge->refunded == '1') { - $status = img_picto($langs->trans("refunded"), 'statut6'); - } elseif ($charge->paid == '1') { - $status = img_picto($langs->trans((string) $charge->status), 'statut4'); - } else { - $label = $langs->trans("Message").": ".$charge->failure_message."
"; - $label .= $langs->trans("Network").": ".$charge->outcome->network_status."
"; - $label .= $langs->trans("Status").": ".$langs->trans((string) $charge->outcome->seller_message); - $status = $form->textwithpicto(img_picto($langs->trans((string) $charge->status), 'statut8'), $label, -1); - } + if ($charge->refunded == '1') { + $status = img_picto($langs->trans("refunded"), 'statut6'); + } elseif ($charge->paid == '1') { + $status = img_picto($langs->trans((string) $charge->status), 'statut4'); + } else { + $label = $langs->trans("Message").": ".$charge->failure_message."
"; + $label .= $langs->trans("Network").": ".$charge->outcome->network_status."
"; + $label .= $langs->trans("Status").": ".$langs->trans((string) $charge->outcome->seller_message); + $status = $form->textwithpicto(img_picto($langs->trans((string) $charge->status), 'statut8'), $label, -1); + } - if (isset($charge->payment_method_details->type) && $charge->payment_method_details->type == 'card') { - $type = $langs->trans("card"); - } elseif (isset($charge->source->type) && $charge->source->type == 'card') { - $type = $langs->trans("card"); - } elseif (isset($charge->payment_method_details->type) && $charge->payment_method_details->type == 'three_d_secure') { - $type = $langs->trans("card3DS"); - } elseif (isset($charge->payment_method_details->type) && $charge->payment_method_details->type == 'sepa_debit') { - $type = $langs->trans("sepadebit"); - } elseif (isset($charge->payment_method_details->type) && $charge->payment_method_details->type == 'ideal') { - $type = $langs->trans("iDEAL"); - } + if (isset($charge->payment_method_details->type) && $charge->payment_method_details->type == 'card') { + $type = $langs->trans("card"); + } elseif (isset($charge->source->type) && $charge->source->type == 'card') { + $type = $langs->trans("card"); + } elseif (isset($charge->payment_method_details->type) && $charge->payment_method_details->type == 'three_d_secure') { + $type = $langs->trans("card3DS"); + } elseif (isset($charge->payment_method_details->type) && $charge->payment_method_details->type == 'sepa_debit') { + $type = $langs->trans("sepadebit"); + } elseif (isset($charge->payment_method_details->type) && $charge->payment_method_details->type == 'ideal') { + $type = $langs->trans("iDEAL"); + } - // Why this ? - /*if (!empty($charge->payment_intent)) { - if (empty($stripeacc)) { // If the Stripe connect account not set, we use common API usage - $charge = \Stripe\PaymentIntent::retrieve($charge->payment_intent); - } else { - $charge = \Stripe\PaymentIntent::retrieve($charge->payment_intent, array("stripe_account" => $stripeacc)); - } - }*/ + // Why this ? + /*if (!empty($charge->payment_intent)) { + if (empty($stripeacc)) { // If the Stripe connect account not set, we use common API usage + $charge = \Stripe\PaymentIntent::retrieve($charge->payment_intent); + } else { + $charge = \Stripe\PaymentIntent::retrieve($charge->payment_intent, array("stripe_account" => $stripeacc)); + } + }*/ - // The metadata FULLTAG is defined by the online payment page - $FULLTAG = $charge->metadata->FULLTAG; + // The metadata FULLTAG is defined by the online payment page + $FULLTAG = $charge->metadata->FULLTAG; - // Save into $tmparray all metadata - $tmparray = dolExplodeIntoArray($FULLTAG, '.', '='); - // Load origin object according to metadata - if (!empty($tmparray['CUS']) && $tmparray['CUS'] > 0) { - $societestatic->fetch($tmparray['CUS']); - } elseif (!empty($charge->metadata->dol_thirdparty_id) && $charge->metadata->dol_thirdparty_id > 0) { - $societestatic->fetch($charge->metadata->dol_thirdparty_id); - } else { - $societestatic->id = 0; - } - if (!empty($tmparray['MEM']) && $tmparray['MEM'] > 0) { - $memberstatic->fetch($tmparray['MEM']); - } else { - $memberstatic->id = 0; - } + // Save into $tmparray all metadata + $tmparray = dolExplodeIntoArray($FULLTAG, '.', '='); + // Load origin object according to metadata + if (!empty($tmparray['CUS']) && $tmparray['CUS'] > 0) { + $societestatic->fetch($tmparray['CUS']); + } elseif (!empty($charge->metadata->dol_thirdparty_id) && $charge->metadata->dol_thirdparty_id > 0) { + $societestatic->fetch($charge->metadata->dol_thirdparty_id); + } else { + $societestatic->id = 0; + } + if (!empty($tmparray['MEM']) && $tmparray['MEM'] > 0) { + $memberstatic->fetch($tmparray['MEM']); + } else { + $memberstatic->id = 0; + } - print ''; + print ''; - if (!empty($stripeacc)) { - $connect = $stripeacc.'/'; - } else { - $connect = ''; - } + if (!empty($stripeacc)) { + $connect = $stripeacc.'/'; + } else { + $connect = ''; + } - // Ref - $url = 'https://dashboard.stripe.com/'.$connect.'test/payments/'.$charge->id; - if ($servicestatus) { - $url = 'https://dashboard.stripe.com/'.$connect.'payments/'.$charge->id; - } - print "\n"; + // Ref + $url = 'https://dashboard.stripe.com/'.$connect.'test/payments/'.$charge->id; + if ($servicestatus) { + $url = 'https://dashboard.stripe.com/'.$connect.'payments/'.$charge->id; + } + print "\n"; - // Stripe customer - print "\n"; + // Stripe customer + print "\n"; - // Link - print "\n"; + // Link + print "\n"; - // Origin - print "\n"; + + // Date payment + print '\n"; + // Type + print ''; + // Amount + print '"; + // Status + print '\n"; + + print "\n"; + + $i++; } - print "\n"; - - // Date payment - print '\n"; - // Type - print ''; - // Amount - print '"; - // Status - print '\n"; - - print "\n"; - - $i++; } print '
'; +print '
'; dol_print_object_info($object); print '
'; diff --git a/htdocs/salaries/list.php b/htdocs/salaries/list.php index e0efb53915b..361107005a6 100644 --- a/htdocs/salaries/list.php +++ b/htdocs/salaries/list.php @@ -448,9 +448,10 @@ if (isModEnabled("banque")) { // Amount print '
'; $liststatus = array('0' => $langs->trans("Unpaid"), '1' => $langs->trans("Paid")); -print $form->selectarray('search_status', $liststatus, $search_status, 1); +print $form->selectarray('search_status', $liststatus, $search_status, 1, 0, 0, '', 0, 0, 0, '', 'onrightofpage'); print '
'.dol_escape_htmltag($obj->barcode).''.dol_escape_htmltag($companystatic->barcode).''.dol_escape_htmltag($obj->code_client).''.dol_escape_htmltag($companystatic->code_client).''.dol_escape_htmltag($obj->code_fournisseur).''.dol_escape_htmltag($companystatic->code_fournisseur).''.dol_escape_htmltag($obj->code_compta).''.dol_escape_htmltag($companystatic->code_compta_client).''.dol_escape_htmltag($obj->code_compta_fournisseur).''.dol_escape_htmltag($companystatic->code_compta_fournisseur).''.dol_escape_htmltag($obj->address).''.dol_escape_htmltag($companystatic->address).'".dol_escape_htmltag($obj->zip)."".dol_escape_htmltag($companystatic->zip)."'.dol_escape_htmltag($obj->town)."'.dol_escape_htmltag($companystatic->town)."'; - $labelcountry = ($obj->country_code && ($langs->trans("Country".$obj->country_code) != "Country".$obj->country_code)) ? $langs->trans("Country".$obj->country_code) : $obj->country_label; + $labelcountry = ($companystatic->country_code && ($langs->trans("Country".$companystatic->country_code) != "Country".$companystatic->country_code)) ? $langs->trans("Country".$companystatic->country_code) : $obj->country_label; print $labelcountry; print ''.dol_print_phone($obj->phone, $obj->country_code, 0, $obj->rowid, 'AC_TEL', ' ', 'phone')."'.dol_print_phone($obj->phone, $companystatic->country_code, 0, $obj->rowid, 'AC_TEL', ' ', 'phone')."'.dol_print_phone($obj->fax, $obj->country_code, 0, $obj->rowid, 'AC_TEL', ' ', 'fax')."'.dol_print_phone($obj->fax, $companystatic->country_code, 0, $obj->rowid, 'AC_TEL', ' ', 'fax')."'; - if ($obj->tva_intra && !isValidVATID($companystatic)) { + print ''; + if ($companystatic->tva_intra && !isValidVATID($companystatic)) { print img_warning("BadVATNumber", '', 'pictofixedwidth'); } - print $obj->tva_intra; + print $companystatic->tva_intra; print "
'.$e->getMessage().'
"; - print "".img_picto($langs->trans('ShowInStripe'), 'globe')." ".$charge->id.""; - if ($charge->payment_intent) { - print '
'.$charge->payment_intent.''; - } - print "
"; + print "".img_picto($langs->trans('ShowInStripe'), 'globe')." ".$charge->id.""; + if ($charge->payment_intent) { + print '
'.$charge->payment_intent.''; + } + print "
"; - if (isModEnabled('stripe') && !empty($stripeacc)) { - $connect = $stripeacc.'/'; - } - $url = 'https://dashboard.stripe.com/'.$connect.'test/customers/'.$charge->customer; - if ($servicestatus) { - $url = 'https://dashboard.stripe.com/'.$connect.'customers/'.$charge->customer; - } - if (!empty($charge->customer)) { - print ''.img_picto($langs->trans('ShowInStripe'), 'globe').' '.$charge->customer.''; - } - print ""; + if (isModEnabled('stripe') && !empty($stripeacc)) { + $connect = $stripeacc.'/'; + } + $url = 'https://dashboard.stripe.com/'.$connect.'test/customers/'.$charge->customer; + if ($servicestatus) { + $url = 'https://dashboard.stripe.com/'.$connect.'customers/'.$charge->customer; + } + if (!empty($charge->customer)) { + print ''.img_picto($langs->trans('ShowInStripe'), 'globe').' '.$charge->customer.''; + } + print ""; - if ($societestatic->id > 0) { - print $societestatic->getNomUrl(1); - } elseif ($memberstatic->id > 0) { - print $memberstatic->getNomUrl(1); - } - print ""; + if ($societestatic->id > 0) { + print $societestatic->getNomUrl(1); + } elseif ($memberstatic->id > 0) { + print $memberstatic->getNomUrl(1); + } + print ""; - if ($charge->metadata->dol_type == "order" || $charge->metadata->dol_type == "commande") { - $object = new Commande($db); - $object->fetch($charge->metadata->dol_id); - if ($object->id > 0) { - print "".img_picto('', 'order')." ".$object->ref.""; + // Origin + print ""; + if ($charge->metadata->dol_type == "order" || $charge->metadata->dol_type == "commande") { + $object = new Commande($db); + $object->fetch($charge->metadata->dol_id); + if ($object->id > 0) { + print "".img_picto('', 'order')." ".$object->ref.""; + } else { + print $FULLTAG; + } + } elseif ($charge->metadata->dol_type == "invoice" || $charge->metadata->dol_type == "facture") { + $object = new Facture($db); + $object->fetch($charge->metadata->dol_id); + if ($object->id > 0) { + print "".img_picto('', 'bill')." ".$object->ref.""; + } else { + print $FULLTAG; + } } else { print $FULLTAG; } - } elseif ($charge->metadata->dol_type == "invoice" || $charge->metadata->dol_type == "facture") { - $object = new Facture($db); - $object->fetch($charge->metadata->dol_id); - if ($object->id > 0) { - print "".img_picto('', 'bill')." ".$object->ref.""; - } else { - print $FULLTAG; - } - } else { - print $FULLTAG; + print "'.dol_print_date($charge->created, 'dayhour')."'; + print $type; + print ''.price(($charge->amount - $charge->amount_refunded) / 100, 0, '', 1, - 1, - 1, strtoupper($charge->currency))."'; + print $status; + print "
'.dol_print_date($charge->created, 'dayhour')."'; - print $type; - print ''.price(($charge->amount - $charge->amount_refunded) / 100, 0, '', 1, - 1, - 1, strtoupper($charge->currency))."'; - print $status; - print "
'; diff --git a/htdocs/supplier_proposal/card.php b/htdocs/supplier_proposal/card.php index 66f69a25ff9..71d9668dc92 100644 --- a/htdocs/supplier_proposal/card.php +++ b/htdocs/supplier_proposal/card.php @@ -972,7 +972,7 @@ if (empty($reshook)) { } $ttc = price2num(GETPOST('price_ttc'), '', 2); - $ht = $ttc / (1 + ($vatratecleaned / 100)); + $ht = (float) $ttc / (1 + ((float) $vatratecleaned / 100)); $price_base_type = 'HT'; } @@ -1879,7 +1879,7 @@ if ($action == 'create') { // Show object lines $result = $object->getLinesArray(); - print ' + print ' diff --git a/htdocs/supplier_proposal/class/supplier_proposal.class.php b/htdocs/supplier_proposal/class/supplier_proposal.class.php index 7ecd6e0b3a5..221700ee369 100644 --- a/htdocs/supplier_proposal/class/supplier_proposal.class.php +++ b/htdocs/supplier_proposal/class/supplier_proposal.class.php @@ -1261,8 +1261,9 @@ class SupplierProposal extends CommonObject $this->statut_libelle = $obj->statut_label; $this->datec = $this->db->jdate($obj->datec); // TODO deprecated $this->datev = $this->db->jdate($obj->datev); // TODO deprecated - $this->date_creation = $this->db->jdate($obj->datec); //Creation date - $this->date_validation = $this->db->jdate($obj->datev); //Validation date + $this->date_creation = $this->db->jdate($obj->datec); // Creation date + $this->date = $this->date_creation; + $this->date_validation = $this->db->jdate($obj->datev); // Validation date $this->date_livraison = $this->db->jdate($obj->delivery_date); // deprecated $this->delivery_date = $this->db->jdate($obj->delivery_date); $this->shipping_method_id = ($obj->fk_shipping_method > 0) ? $obj->fk_shipping_method : null; diff --git a/htdocs/supplier_proposal/list.php b/htdocs/supplier_proposal/list.php index fd71dc26204..3439c3ee11d 100644 --- a/htdocs/supplier_proposal/list.php +++ b/htdocs/supplier_proposal/list.php @@ -177,7 +177,7 @@ $arrayfields = array( 'state.nom'=>array('label'=>$langs->trans("StateShort"), 'checked'=>0), 'country.code_iso'=>array('label'=>$langs->trans("Country"), 'checked'=>0), 'typent.code'=>array('label'=>$langs->trans("ThirdPartyType"), 'checked'=>$checkedtypetiers), - 'sp.date_valid'=>array('label'=>$langs->trans("Date"), 'checked'=>1), + 'sp.date_valid'=>array('label'=>$langs->trans("DateValidation"), 'checked'=>1), 'sp.date_livraison'=>array('label'=>$langs->trans("DateEnd"), 'checked'=>1), 'sp.total_ht'=>array('label'=>$langs->trans("AmountHT"), 'checked'=>1), 'sp.total_tva'=>array('label'=>$langs->trans("AmountVAT"), 'checked'=>0), @@ -694,7 +694,7 @@ if ($resql) { } $varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage; - $selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields + $selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage, getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')); // This also change content of $arrayfields if ($massactionbutton) { $selectedfields .= $form->showCheckAddButtons('checkforselect', 1); } @@ -703,6 +703,13 @@ if ($resql) { print ''."\n"; print ''; + // Action column + if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print ''; + } if (!empty($arrayfields['sp.ref']['checked'])) { print ''; } // Action column - print ''; + if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print ''; + } print "\n"; // Fields title print ''; + if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'center maxwidthsearch '); + } if (!empty($arrayfields['sp.ref']['checked'])) { print_liste_field_titre($arrayfields['sp.ref']['label'], $_SERVER["PHP_SELF"], 'sp.ref', '', $param, '', $sortfield, $sortorder); } @@ -923,7 +935,9 @@ if ($resql) { if (!empty($arrayfields['sp.fk_statut']['checked'])) { print_liste_field_titre($arrayfields['sp.fk_statut']['label'], $_SERVER["PHP_SELF"], "sp.fk_statut", "", $param, '', $sortfield, $sortorder, 'right '); } - print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'center maxwidthsearch '); + if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'center maxwidthsearch '); + } print ''."\n"; $now = dol_now(); @@ -953,7 +967,18 @@ if ($resql) { $companystatic->code_client = $obj->code_client; print ''; - + // Action column + if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print ''; + } if (!empty($arrayfields['sp.ref']['checked'])) { print ''; } - print ''; if (!$i) { $totalarray['nbfield']++; } diff --git a/htdocs/takepos/css/pos.css.php b/htdocs/takepos/css/pos.css.php index 6f72fa6e7f2..88482b4dcba 100644 --- a/htdocs/takepos/css/pos.css.php +++ b/htdocs/takepos/css/pos.css.php @@ -337,7 +337,8 @@ div.paymentbordline width: 100%; height: 100%; margin: 0 auto; - overflow: visible; + overflow-x: hidden; + overfloy-y: scroll; box-sizing: border-box; } @@ -364,6 +365,7 @@ div.paymentbordline margin: 0 auto; width: 100%; height: 55%; + overflow: hidden; } .div1{ @@ -714,9 +716,12 @@ div#moreinfo, div#infowarehouse { } button.actionbutton { - min-height: 60px; + display: inline-flex; + align-items: center; + justify-content: center; padding-left: 4px; padding-right: 4px; + min-height: 30px; } } @@ -940,17 +945,19 @@ div#moreinfo, div#infowarehouse { } } -.arrows { - display: none; - position: absolute; - justify-content: space-between; - width: 100%; -} - .indicator { background: #00000042; padding: 15px 5px; cursor: pointer; + position:absolute; +} + +.indicator.left { + left:0; +} + +.indicator.right { + right:0; } .indicator:hover { @@ -1041,4 +1048,4 @@ html { .topnav.overflow .arrows { display: flex; -} \ No newline at end of file +} diff --git a/htdocs/theme/eldy/global.inc.php b/htdocs/theme/eldy/global.inc.php index 95a8e47f009..193bc2c6e1e 100644 --- a/htdocs/theme/eldy/global.inc.php +++ b/htdocs/theme/eldy/global.inc.php @@ -1395,6 +1395,12 @@ select.flat.selectlimit { overflow: hidden; height: auto !important; } +.tenlinesmax { + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 10; + overflow: hidden; +} .tablelistofcalendars { margin-top: 25px !important; @@ -1709,6 +1715,7 @@ select.widthcentpercentminusxx, span.widthcentpercentminusxx:not(.select2-select select.minwidth100imp, select.minwidth100, select.minwidth200, select.minwidth200imp, select.minwidth300 { width: calc(100% - 40px) !important; + min-width: 100px; display: inline-block; } select.widthcentpercentminusxx, span.widthcentpercentminusxx:not(.select2-selection), input.widthcentpercentminusxx { @@ -2421,6 +2428,9 @@ img.photoref, div.photoref { } img.photokanban, div.photokanban { padding: 0; + border: none; + box-shadow: none; + vertical-align: middle; } div.photoref .fa, div.photoref .fas, div.photoref .far { font-size: 2.5em; diff --git a/htdocs/theme/eldy/info-box.inc.php b/htdocs/theme/eldy/info-box.inc.php index b860e69abba..29db8cf0769 100644 --- a/htdocs/theme/eldy/info-box.inc.php +++ b/htdocs/theme/eldy/info-box.inc.php @@ -96,7 +96,7 @@ if (!defined('ISLOADEDBYSTEELSHEET')) { padding-bottom: 5px; } .info-box-sm .info-box-icon { - height: 80px; + height: 96px; /* must match height of info-box-sm .info-box-content */ width: 78px; font-size: 25px; line-height: 92px; @@ -112,7 +112,7 @@ if (!defined('ISLOADEDBYSTEELSHEET')) { height: 98px; } .info-box-icon > img { - max-width: 100%; + max-width: 85%; } .info-box-module .info-box-icon > img { max-width: 60%; @@ -179,11 +179,11 @@ a.info-box-text-a i.fa.fa-exclamation-triangle { } -.info-box-sm .info-box-icon-text, .info-box-sm .info-box-icon-version{ +.info-box-sm .info-box-icon-text, .info-box-sm .info-box-icon-version { overflow: hidden; width: 80px; } -.info-box:hover .info-box-icon-text{ +.info-box:hover .info-box-icon-text { opacity: 1; } @@ -191,8 +191,9 @@ a.info-box-text-a i.fa.fa-exclamation-triangle { padding: 5px 10px; margin-left: 84px; } -.info-box-sm .info-box-content{ +.info-box-sm .info-box-content { margin-left: 80px; + height: 86px; /* 96 - margins of .info-box-sm .info-box-content */ } .info-box-sm .info-box-module-enabled { /* background: linear-gradient(0.35turn, #fff, #fff, #f6faf8, #e4efe8) */ diff --git a/htdocs/theme/md/info-box.inc.php b/htdocs/theme/md/info-box.inc.php index c48a9d537a8..ba96575239f 100644 --- a/htdocs/theme/md/info-box.inc.php +++ b/htdocs/theme/md/info-box.inc.php @@ -208,7 +208,7 @@ a.info-box-text-a i.fa.fa-exclamation-triangle { } .info-box-sm .info-box-icon { - height: 80px; + height: 96px; width: 80px; font-size: 25px; line-height: 92px; @@ -223,7 +223,7 @@ a.info-box-text-a i.fa.fa-exclamation-triangle { height: 98px; } .info-box-icon > img { - max-width: 100%; + max-width: 85%; } .info-box-module .info-box-icon > img { max-width: 55%; diff --git a/htdocs/theme/md/style.css.php b/htdocs/theme/md/style.css.php index 2324da32c43..08c6cfa8959 100644 --- a/htdocs/theme/md/style.css.php +++ b/htdocs/theme/md/style.css.php @@ -1514,6 +1514,12 @@ select.flat.selectlimit { overflow: hidden; height: auto !important; } +.tenlinesmax { + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 10; + overflow: hidden; +} .tablelistofcalendars { margin-top: 25px !important; @@ -2453,6 +2459,8 @@ img.photoref, div.photoref { img.photokanban, div.photokanban { padding: 0; border: none; + box-shadow: none; + vertical-align: middle; } div.photoref .fa, div.photoref .fas, div.photoref .far { diff --git a/htdocs/ticket/class/actions_ticket.class.php b/htdocs/ticket/class/actions_ticket.class.php index c5e267fddf6..6ad204965bc 100644 --- a/htdocs/ticket/class/actions_ticket.class.php +++ b/htdocs/ticket/class/actions_ticket.class.php @@ -206,9 +206,9 @@ class ActionsTicket print ''; print '
'; + $searchpicto = $form->showFilterButtons('left'); + print $searchpicto; + print ''; print ''; @@ -838,19 +845,24 @@ if ($resql) { // Status if (!empty($arrayfields['sp.fk_statut']['checked'])) { print ''; - $formpropal->selectProposalStatus($search_status, 1, 0, 1, 'supplier', 'search_status', 'minwidth75imp'); + $formpropal->selectProposalStatus($search_status, 1, 0, 1, 'supplier', 'search_status', 'minwidth75imp onrightofpage'); print ''; - $searchpicto = $form->showFilterButtons(); - print $searchpicto; - print ''; + $searchpicto = $form->showFilterButtons(); + print $searchpicto; + print '
'; + if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined + $selected = 0; + if (in_array($obj->rowid, $arrayofselected)) { + $selected = 1; + } + print ''; + } + print ''; @@ -1203,15 +1228,17 @@ if ($resql) { } // Action column - print ''; - if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined - $selected = 0; - if (in_array($obj->rowid, $arrayofselected)) { - $selected = 1; + if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print ''; + if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined + $selected = 0; + if (in_array($obj->rowid, $arrayofselected)) { + $selected = 1; + } + print ''; } - print ''; + print '
'; - if (!empty($user->rights->ticket->manage) && $action == 'edit_message_init') { + if ($user->hasRight('ticket', 'manage') && $action == 'edit_message_init') { // MESSAGE - $msg = GETPOST('message_initial', 'alpha') ? GETPOST('message_initial', 'alpha') : $object->message; + $msg = GETPOSTISSET('message_initial') ? GETPOST('message_initial', 'restricthtml') : $object->message; include_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php'; $uselocalbrowser = true; $ckeditorenabledforticket = $conf->global->FCKEDITOR_ENABLE_TICKET; @@ -218,7 +218,7 @@ class ActionsTicket // Deal with format differences (text / HTML) if (dol_textishtml($object->message)) { print '
'; - print $object->message; + print dol_htmlwithnojs($object->message); print '
'; /*print '
'; print $langs->trans("More").'...'; diff --git a/htdocs/ticket/class/ticket.class.php b/htdocs/ticket/class/ticket.class.php index 440950628d1..2aacffefcd1 100644 --- a/htdocs/ticket/class/ticket.class.php +++ b/htdocs/ticket/class/ticket.class.php @@ -1612,13 +1612,13 @@ class Ticket extends CommonObject // Insert entry into agenda with code 'TICKET_MSG' include_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php'; $actioncomm = new ActionComm($this->db); - $actioncomm->type_code = 'AC_OTH'; + $actioncomm->type_code = 'AC_OTH_AUTO'; // This is not an entry that must appears into manual calendar but only into CRM calendar $actioncomm->code = 'TICKET_MSG'; if ($this->private) { $actioncomm->code = 'TICKET_MSG_PRIVATE'; } if ($send_email) { - $actioncomm->type_code = 'AC_EMAIL'; + $actioncomm->code .= '_SENTBYMAIL'; } $actioncomm->socid = $this->socid; $actioncomm->label = $this->subject; @@ -1691,7 +1691,7 @@ class Ticket extends CommonObject $this->cache_msgs_ticket[$i]['datec'] = $this->db->jdate($obj->datec); $this->cache_msgs_ticket[$i]['subject'] = $obj->label; $this->cache_msgs_ticket[$i]['message'] = $obj->message; - $this->cache_msgs_ticket[$i]['private'] = ($obj->code == 'TICKET_MSG_PRIVATE' ? 1 : 0); + $this->cache_msgs_ticket[$i]['private'] = (preg_match('/^TICKET_MSG_PRIVATE/', $obj->code) ? 1 : 0); $i++; } return $num; diff --git a/htdocs/ticket/list.php b/htdocs/ticket/list.php index 66bda452ccf..4c4dce5a428 100644 --- a/htdocs/ticket/list.php +++ b/htdocs/ticket/list.php @@ -353,6 +353,9 @@ $parameters = array(); $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters, $object); // Note that $action and $object may have been modified by hook $sql .= preg_replace('/^,/', '', $hookmanager->resPrint); $sql = preg_replace('/,\s*$/', '', $sql); + +$sqlfields = $sql; // $sql fields to remove for count total + $sql .= " FROM ".MAIN_DB_PREFIX.$object->table_element." as t"; if (isset($extrafields->attributes[$object->table_element]['label']) && is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label'])) { $sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$object->table_element."_extrafields as ef on (t.rowid = ef.fk_object)"; @@ -458,11 +461,17 @@ $sql .= $hookmanager->resPrint; $nbtotalofrecords = ''; if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { /* The fast and low memory method to get and count full list converts the sql into a sql count */ - $sqlforcount = preg_replace('/^SELECT[a-zA-Z0-9\._\s\(\),=<>\:\-\']+\sFROM/Ui', 'SELECT COUNT(*) as nbtotalofrecords FROM', $sql); + $sqlforcount = preg_replace('/^'.preg_quote($sqlfields, '/').'/', 'SELECT COUNT(*) as nbtotalofrecords', $sql); + $sqlforcount = preg_replace('/GROUP BY .*$/', '', $sqlforcount); $resql = $db->query($sqlforcount); - $objforcount = $db->fetch_object($resql); - $nbtotalofrecords = $objforcount->nbtotalofrecords; - if (($page * $limit) > $nbtotalofrecords) { // if total of record found is smaller than page * limit, goto and load page 0 + if ($resql) { + $objforcount = $db->fetch_object($resql); + $nbtotalofrecords = $objforcount->nbtotalofrecords; + } else { + dol_print_error($db); + } + + if (($page * $limit) > $nbtotalofrecords) { // if total resultset is smaller then paging size (filtering), goto and load page 0 $page = 0; $offset = 0; } @@ -791,7 +800,7 @@ if (!empty($moreforfilter)) { } $varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage; -$selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields +$selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage, getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')); // This also change content of $arrayfields $selectedfields .= (count($arrayofmassactions) ? $form->showCheckAddButtons('checkforselect', 1) : ''); print '
'; // You can use div-table-responsive-no-min if you dont need reserved height for your table @@ -802,6 +811,13 @@ print ''; +// Action column +if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print ''; +} foreach ($object->fields as $key => $val) { $cssforfield = (empty($val['csslist']) ? (empty($val['css']) ? '' : $val['css']) : $val['csslist']); if ($key == 'fk_statut') { @@ -903,16 +919,21 @@ $parameters = array('arrayfields'=>$arrayfields); $reshook = $hookmanager->executeHooks('printFieldListOption', $parameters, $object); // Note that $action and $object may have been modified by hook print $hookmanager->resPrint; // Action column -print ''; +if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print ''; +} print ''."\n"; // Fields title label // -------------------------------------------------------------------- print ''; +if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print getTitleFieldOfList($selectedfields, 0, $_SERVER["PHP_SELF"], '', '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ')."\n"; +} foreach ($object->fields as $key => $val) { $cssforfield = (empty($val['csslist']) ? (empty($val['css']) ? '' : $val['css']) : $val['csslist']); if ($key == 'fk_statut' || $key == 'severity_code') { @@ -943,7 +964,9 @@ $parameters = array( ); $reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters, $object); // Note that $action and $object may have been modified by hook print $hookmanager->resPrint; -print getTitleFieldOfList($selectedfields, 0, $_SERVER["PHP_SELF"], '', '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ')."\n"; +if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print getTitleFieldOfList($selectedfields, 0, $_SERVER["PHP_SELF"], '', '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ')."\n"; +} print ''."\n"; @@ -978,6 +1001,18 @@ while ($i < ($limit ? min($num, $limit) : $num)) { // Show here line of result print ''; + // Action column + if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print ''; + } foreach ($object->fields as $key => $val) { $cssforfield = (empty($val['csslist']) ? (empty($val['css']) ? '' : $val['css']) : $val['csslist']); if (in_array($val['type'], array('date', 'datetime', 'timestamp'))) { @@ -1118,15 +1153,17 @@ while ($i < ($limit ? min($num, $limit) : $num)) { $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters, $object); // Note that $action and $object may have been modified by hook print $hookmanager->resPrint; // Action column - print ''; } - print ''; if (!$i) { $totalarray['nbfield']++; } diff --git a/htdocs/user/card.php b/htdocs/user/card.php index 5a5a5d6fc9e..2325ab7ab53 100644 --- a/htdocs/user/card.php +++ b/htdocs/user/card.php @@ -537,6 +537,9 @@ if (empty($reshook)) { $sql .= " SET fk_socpeople=".((int) $contactid); if (!empty($contact->socid)) { $sql .= ", fk_soc=".((int) $contact->socid); + } elseif ($socid > 0) { + $sql .= ", fk_soc = null"; + setEventMessages($langs->trans("WarningUserDifferentContactSocid"), '', 'warnings'); // Add message if post socid != $contact->socid } $sql .= " WHERE rowid = ".((int) $object->id); } elseif ($socid > 0) { @@ -1834,10 +1837,10 @@ if ($action == 'create' || $action == 'adduserldap') { print ''; print ''; print "\n"; diff --git a/htdocs/user/class/api_users.class.php b/htdocs/user/class/api_users.class.php index e18c78e6ced..747d4ab3286 100644 --- a/htdocs/user/class/api_users.class.php +++ b/htdocs/user/class/api_users.class.php @@ -640,7 +640,17 @@ class Users extends DolibarrApi throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); } $this->useraccount->oldcopy = clone $this->useraccount; - return $this->useraccount->delete(DolibarrApiAccess::$user); + + if (!$this->useraccount->delete(DolibarrApiAccess::$user)) { + throw new RestException(500); + } + + return array( + 'success' => array( + 'code' => 200, + 'message' => 'Ticket deleted' + ) + ); } // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore diff --git a/htdocs/user/class/user.class.php b/htdocs/user/class/user.class.php index d49f810f915..75c9f1b2bae 100644 --- a/htdocs/user/class/user.class.php +++ b/htdocs/user/class/user.class.php @@ -1522,7 +1522,7 @@ class User extends CommonObject return -1; } elseif (preg_match('/['.preg_quote($badCharUnauthorizedIntoLoginName, '/').']/', $this->login)) { $langs->load("errors"); - $this->error = $langs->trans("ErrorBadCharIntoLoginName"); + $this->error = $langs->trans("ErrorBadCharIntoLoginName", $langs->transnoentitiesnoconv("Login")); return -1; } @@ -1918,7 +1918,7 @@ class User extends CommonObject return -1; } elseif (preg_match('/['.preg_quote($badCharUnauthorizedIntoLoginName, '/').']/', $this->login)) { $langs->load("errors"); - $this->error = $langs->trans("ErrorBadCharIntoLoginName"); + $this->error = $langs->trans("ErrorBadCharIntoLoginName", $langs->transnoentitiesnoconv("Login")); return -1; } diff --git a/htdocs/user/list.php b/htdocs/user/list.php index d472ae3e9f4..8610113f0da 100644 --- a/htdocs/user/list.php +++ b/htdocs/user/list.php @@ -373,6 +373,9 @@ $parameters = array(); $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters, $object); // Note that $action and $object may have been modified by hook $sql .= preg_replace('/^,/', '', $hookmanager->resPrint); $sql = preg_replace('/,\s*$/', '', $sql); + +$sqlfields = $sql; // $sql fields to remove for count total + $sql .= " FROM ".MAIN_DB_PREFIX.$object->table_element." as u"; if (isset($extrafields->attributes[$object->table_element]['label']) && is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label'])) { $sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$object->table_element."_extrafields as ef on (u.rowid = ef.fk_object)"; @@ -481,21 +484,9 @@ $sql .= $hookmanager->resPrint; // Count total nb of records $nbtotalofrecords = ''; if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { - /* This old and fast method to get and count full list returns all record so use a high amount of memory. - $resql = $db->query($sql); - $nbtotalofrecords = $db->num_rows($resql); - */ - /* The slow method does not consume memory on mysql (not tested on pgsql) */ - /*$resql = $db->query($sql, 0, 'auto', 1); - while ($db->fetch_object($resql)) { - if (empty($nbtotalofrecords)) { - $nbtotalofrecords = 1; // We can't make +1 because init value is '' - } else { - $nbtotalofrecords++; - } - }*/ /* The fast and low memory method to get and count full list converts the sql into a sql count */ - $sqlforcount = preg_replace('/^SELECT[a-zA-Z0-9\._\s\(\),=<>\:\-\']+\sFROM/Ui', 'SELECT COUNT(*) as nbtotalofrecords FROM', $sql); + $sqlforcount = preg_replace('/^'.preg_quote($sqlfields, '/').'/', 'SELECT COUNT(*) as nbtotalofrecords', $sql); + $sqlforcount = preg_replace('/GROUP BY .*$/', '', $sqlforcount); $resql = $db->query($sqlforcount); if ($resql) { $objforcount = $db->fetch_object($resql); @@ -504,7 +495,7 @@ if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { dol_print_error($db); } - if (($page * $limit) > $nbtotalofrecords) { // if total of record found is smaller than page * limit, goto and load page 0 + if (($page * $limit) > $nbtotalofrecords) { // if total resultset is smaller then paging size (filtering), goto and load page 0 $page = 0; $offset = 0; } diff --git a/htdocs/user/perms.php b/htdocs/user/perms.php index 6dca3bdca83..cf055f8382c 100644 --- a/htdocs/user/perms.php +++ b/htdocs/user/perms.php @@ -44,6 +44,7 @@ $action = GETPOST('action', 'aZ09'); $confirm = GETPOST('confirm', 'alpha'); $module = GETPOST('module', 'alpha'); $rights = GETPOST('rights', 'int'); +$updatedmodulename = GETPOST('updatedmodulename', 'alpha'); $contextpage = GETPOST('contextpage', 'aZ') ?GETPOST('contextpage', 'aZ') : 'userperms'; // To manage different context of search if (!isset($id) || empty($id)) { @@ -267,7 +268,7 @@ print '
'; print '
'; + $searchpicto = $form->showFilterButtons('left'); + print $searchpicto; + print ''; -$searchpicto = $form->showFilterButtons(); -print $searchpicto; -print ''; + $searchpicto = $form->showFilterButtons(); + print $searchpicto; + print '
'; + if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined + $selected = 0; + if (in_array($obj->rowid, $arrayofselected)) { + $selected = 1; + } + print ''; + } + print ''; - if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined - $selected = 0; - if (in_array($obj->rowid, $arrayofselected)) { - $selected = 1; + if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print ''; + if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined + $selected = 0; + if (in_array($obj->rowid, $arrayofselected)) { + $selected = 1; + } + print ''; } - print ''; + print '
'.$langs->trans("LastConnexion").''; if ($object->datepreviouslogin) { - print dol_print_date($object->datepreviouslogin, "dayhour").' ('.$langs->trans("Previous").'), '; + print dol_print_date($object->datepreviouslogin, "dayhour", "tzuserrel").' ('.$langs->trans("Previous").'), '; } if ($object->datelastlogin) { - print dol_print_date($object->datelastlogin, "dayhour").' ('.$langs->trans("Currently").')'; + print dol_print_date($object->datelastlogin, "dayhour", "tzuserrel").' ('.$langs->trans("Currently").')'; } print '
'; // Login -print ''; +print ''; if (!empty($object->ldap_sid) && $object->statut == 0) { print ''; if (($caneditperms && empty($objMod->rights_admin_allowed)) || empty($object->admin)) { if ($caneditperms) { print ''; + } else { + print ''; } print ''; +} else { + print ''; + print ''; } -print ''; -if ($user->admin) { - print ''; -} + +print ''; +print ''; + print ''."\n"; @@ -408,9 +420,13 @@ $sql .= " ORDER BY r.family_position, r.module_position, r.module, r.id"; $result = $db->query($sql); if ($result) { $num = $db->num_rows($result); - $i = 0; + $i = 0; $j = 0; $oldmod = ''; + $cookietohidegroup = (empty($_COOKIE["DOLUSER_PERMS_HIDE_GRP"]) ? '' : preg_replace('/^,/', '', $_COOKIE["DOLUSER_PERMS_HIDE_GRP"])); + $cookietohidegrouparray = explode(',', $cookietohidegroup); + //var_dump($cookietohidegrouparray); + while ($i < $num) { $obj = $db->fetch_object($result); @@ -460,47 +476,83 @@ if ($result) { } */ + if (GETPOSTISSET('forbreakperms_'.$obj->module)) { + $ishidden = GETPOST('forbreakperms_'.$obj->module, 'int'); + } elseif (in_array($j, $cookietohidegrouparray)) { // If j is among list of hidden group + $ishidden = 1; + } else { + $ishidden = 0; + } + $isexpanded = ! $ishidden; + //var_dump("isexpanded=".$isexpanded); + // Break found, it's a new module to catch if (isset($obj->module) && ($oldmod <> $obj->module)) { $oldmod = $obj->module; + $j++; + if (GETPOSTISSET('forbreakperms_'.$obj->module)) { + $ishidden = GETPOST('forbreakperms_'.$obj->module, 'int'); + } elseif (in_array($j, $cookietohidegrouparray)) { // If j is among list of hidden group + $ishidden = 1; + } else { + $ishidden = 0; + } + $isexpanded = ! $ishidden; + //var_dump('$obj->module='.$obj->module.' isexpanded='.$isexpanded); + // Break detected, we get objMod $objMod = $modules[$obj->module]; $picto = ($objMod->picto ? $objMod->picto : 'generic'); // Show break line - print ''; - print ''; + print ''; if (($caneditperms && empty($objMod->rights_admin_allowed)) || empty($object->admin)) { if ($caneditperms) { - print ''; + print ''; + } else { + print ''; } - print ''; + print ''; } else { if ($caneditperms) { - print ''; + print ''; + print ''; + } else { + print ''; } - print ''; - } - print ''; - - // Permission id - if ($user->admin) { - print ''; + print ''; } + print ''; + print ''; //Add picto + / - when open en closed print ''."\n"; } print ''."\n"; - print ''; + print ''; // Picto and label of module print ''; + } else { + print ''; } print ''; } elseif (in_array($obj->id, $permsuser)) { // Permission granted by user if ($caneditperms) { - print ''; + } else { + print ''; } print ''; + } else { + print ''; } print ''; + } else { + print ''; } print ''; } } else { // Do not own permission if ($caneditperms) { - print ''; + } else { + print ''; } print ''; } // Description of permission $permlabel = (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ($langs->trans("PermissionAdvanced".$obj->id) != ("PermissionAdvanced".$obj->id)) ? $langs->trans("PermissionAdvanced".$obj->id) : (($langs->trans("Permission".$obj->id) != ("Permission".$obj->id)) ? $langs->trans("Permission".$obj->id) : $langs->trans($obj->label))); - print '
'.$langs->trans("Login").'
'.$langs->trans("Login").''; print $langs->trans("LoginAccountDisableInDolibarr"); @@ -306,6 +307,8 @@ if ($reshook < 0) { setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); } +$listofexpandedmodules = array(); + print "\n"; print '
'; @@ -316,17 +319,26 @@ print '
'.$langs->trans("Module").''; - print ''.$langs->trans("All").""; + print ''.$langs->trans("All").""; print ' / '; - print ''.$langs->trans("None").""; + print ''.$langs->trans("None").""; print '    '.$langs->trans("Permissions").''; +print ''.img_picto('', 'folder-open', 'class="paddingright"').''.$langs->trans("ExpandAll").''; +print ' | '; +print ''.img_picto('', 'folder', 'class="paddingright"').''.$langs->trans("UndoExpandAll").''; +print '
'; + print '
'; + print ''; print img_object('', $picto, 'class="pictoobjectwidth paddingright"').' '.$objMod->getName(); print ''; print ''; - print 'module.'&confirm=yes">'.$langs->trans("All").""; + print '        '; + print ''; + print ''; + print '
'; print '
'; +print ''; + +print ''; + $parameters = array(); $reshook = $hookmanager->executeHooks('insertExtraFooter', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks if ($reshook < 0) { diff --git a/htdocs/variants/card.php b/htdocs/variants/card.php index ca026bef4a4..634290ca187 100644 --- a/htdocs/variants/card.php +++ b/htdocs/variants/card.php @@ -327,24 +327,11 @@ if ($action == 'create') { print '
'; if (!empty($object->lines) || ($permissiontoedit && $action != 'selectlines' && $action != 'editline')) { - print ''; - } - - // Form to add new line - if ($permissiontoedit && $action != 'selectlines') { - if ($action != 'editline') { - // Add products/services form - - $parameters = array(); - $reshook = $hookmanager->executeHooks('formAddObjectLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook - if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); - if (empty($reshook)) - $object->formAddObjectLine(1, $mysoc, $soc); - } + print '
'; } if (!empty($object->lines)) { - $object->printObjectLines($action, $mysoc, null, GETPOST('lineid', 'int'), 1); + $object->printObjectLines($action, $mysoc, null, GETPOST('lineid', 'int'), 1, '/variants/tpl', ($permissiontoedit ? 1 : 0)); } if (!empty($object->lines) || ($permissiontoedit && $action != 'selectlines' && $action != 'editline')) { diff --git a/htdocs/variants/class/ProductAttribute.class.php b/htdocs/variants/class/ProductAttribute.class.php index fc96f247e63..ae82873d8bd 100644 --- a/htdocs/variants/class/ProductAttribute.class.php +++ b/htdocs/variants/class/ProductAttribute.class.php @@ -1272,11 +1272,13 @@ class ProductAttribute extends CommonObject * @param int $selected Object line selected * @param int $dateSelector 1=Show also date range input fields * @param string $defaulttpldir Directory where to find the template + * @param int $addcreateline 1=Add create line * @return void */ - public function printObjectLines($action, $seller, $buyer, $selected = 0, $dateSelector = 0, $defaulttpldir = '/variants/tpl') + public function printObjectLines($action, $seller, $buyer, $selected = 0, $dateSelector = 0, $defaulttpldir = '/variants/tpl', $addcreateline = 0) { global $conf, $hookmanager, $langs, $user, $form, $object; + global $mysoc; // TODO We should not use global var for this global $disableedit, $disablemove, $disableremove; @@ -1306,9 +1308,25 @@ class ProductAttribute extends CommonObject } } + + if ($addcreateline) { + // Form to add new line + if ($action != 'selectlines') { + if ($action != 'editline') { + // Add products/services form + + $parameters = array(); + $reshook = $hookmanager->executeHooks('formAddObjectLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook + if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + if (empty($reshook)) + $object->formAddObjectLine(1, $mysoc, $buyer); + } + } + } + $i = 0; - print "\n"; + print "\n"; foreach ($this->lines as $line) { if (is_object($hookmanager)) { // Old code is commented on preceding line. $parameters = array('line' => $line, 'num' => $num, 'i' => $i, 'selected' => $selected, 'table_element_line' => $line->table_element); @@ -1320,7 +1338,7 @@ class ProductAttribute extends CommonObject $i++; } - print "\n"; + print "\n"; } /** diff --git a/htdocs/variants/tpl/productattributevalueline_create.tpl.php b/htdocs/variants/tpl/productattributevalueline_create.tpl.php index cc16302a68d..f23e7175f58 100644 --- a/htdocs/variants/tpl/productattributevalueline_create.tpl.php +++ b/htdocs/variants/tpl/productattributevalueline_create.tpl.php @@ -84,7 +84,7 @@ if ($nolinesbefore) { diff --git a/htdocs/viewimage.php b/htdocs/viewimage.php index 3b1d60e0e90..d676f8a6ee9 100644 --- a/htdocs/viewimage.php +++ b/htdocs/viewimage.php @@ -228,6 +228,10 @@ $original_file = str_replace('..\\', '/', $original_file); // Find the subdirectory name as the reference $refname = basename(dirname($original_file)."/"); +if ($refname == 'thumbs') { + // If we get the thumbs directory, we must go one step higher. For example original_file='10/thumbs/myfile_small.jpg' -> refname='10' + $refname = basename(dirname(dirname($original_file))."/"); +} // Check that file is allowed for view with viewimage.php if (!empty($original_file) && !dolIsAllowedForPreview($original_file)) { diff --git a/htdocs/website/class/website.class.php b/htdocs/website/class/website.class.php index d532f7f475c..9cc470a5954 100644 --- a/htdocs/website/class/website.class.php +++ b/htdocs/website/class/website.class.php @@ -151,10 +151,10 @@ class Website extends CommonObject /** * Create object into database * - * @param User $user User that creates - * @param bool $notrigger false=launch triggers after, true=disable triggers + * @param User $user User that creates + * @param bool $notrigger false=launch triggers after, true=disable triggers * - * @return int <0 if KO, Id of created object if OK + * @return int <0 if KO, 0 if already exists, ID of created object if OK */ public function create(User $user, $notrigger = false) { @@ -282,8 +282,11 @@ class Website extends CommonObject // Commit or rollback if ($error) { $this->db->rollback(); - - return -1 * $error; + if ($this->db->lasterrno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') { + return 0; + } else { + return -1 * $error; + } } else { $this->db->commit(); @@ -1154,7 +1157,7 @@ class Website extends CommonObject /** * Open a zip with all data of web site and load it into database. * - * @param string $pathtofile Path of zip file + * @param string $pathtofile Full path of zip file * @return int <0 if KO, Id of new website if OK */ public function importWebSite($pathtofile) @@ -1163,6 +1166,8 @@ class Website extends CommonObject $error = 0; + $pathtofile = dol_sanitizePathName($pathtofile); + $object = $this; if (empty($object->ref)) { $this->error = 'Function importWebSite called on object not loaded (object->ref is empty)'; diff --git a/htdocs/website/index.php b/htdocs/website/index.php index a87fce31734..6e4d96880fb 100644 --- a/htdocs/website/index.php +++ b/htdocs/website/index.php @@ -572,7 +572,23 @@ if ($massaction == 'delcategory' && GETPOST('confirmmassaction', 'alpha') && $us if ($massaction == 'replace' && GETPOST('confirmmassaction', 'alpha') && $usercanedit) { $replacestring = GETPOST('replacestring', 'none'); - if (empty($user->rights->website->writephp)) { + $dolibarrdataroot = preg_replace('/([\\/]+)$/i', '', DOL_DATA_ROOT); + $allowimportsite = true; + if (dol_is_file($dolibarrdataroot.'/installmodules.lock')) { + $allowimportsite = false; + } + + if (!$allowimportsite) { + // Blocked by installmodules.lock + if (getDolGlobalString('MAIN_MESSAGE_INSTALL_MODULES_DISABLED_CONTACT_US')) { + // Show clean corporate message + $message = $langs->trans('InstallModuleFromWebHasBeenDisabledContactUs'); + } else { + // Show technical generic message + $message = $langs->trans("InstallModuleFromWebHasBeenDisabledByFile", $dolibarrdataroot.'/installmodules.lock'); + } + setEventMessages($message, null, 'errors'); + } elseif (empty($user->rights->website->writephp)) { setEventMessages("NotAllowedToAddDynamicContent", null, 'errors'); } elseif (!$replacestring) { setEventMessages("ErrorReplaceStringEmpty", null, 'errors'); @@ -694,7 +710,10 @@ if ($action == 'addsite' && $usercanedit) { $tmpobject->virtualhost = GETPOST('virtualhost', 'alpha'); $result = $tmpobject->create($user); - if ($result <= 0) { + if ($result == 0) { + $error++; + setEventMessages($langs->trans("ErrorLabelAlreadyExists"), null, 'errors'); + } elseif ($result < 0) { $error++; setEventMessages($tmpobject->error, $tmpobject->errors, 'errors'); } @@ -2374,76 +2393,101 @@ if ($action == 'regeneratesite' && $usercanedit) { // Import site if ($action == 'importsiteconfirm' && $usercanedit) { - if (empty($_FILES) && !GETPOSTISSET('templateuserfile')) { - setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("File")), null, 'errors'); - $action = 'importsite'; - } else { - if (!empty($_FILES) || GETPOSTISSET('templateuserfile')) { - // Check symlink to medias and restore it if ko. Recreate also dir of website if not found. - $pathtomedias = DOL_DATA_ROOT.'/medias'; - $pathtomediasinwebsite = $pathofwebsite.'/medias'; - if (!is_link(dol_osencode($pathtomediasinwebsite))) { - dol_syslog("Create symlink for ".$pathtomedias." into name ".$pathtomediasinwebsite); - dol_mkdir(dirname($pathtomediasinwebsite)); // To be sure dir for website exists - $result = symlink($pathtomedias, $pathtomediasinwebsite); - if (!$result) { - setEventMessages($langs->trans("ErrorFieldToCreateSymLinkToMedias", $pathtomediasinwebsite, $pathtomedias), null, 'errors'); - $action = 'importsite'; - } - } + $dolibarrdataroot = preg_replace('/([\\/]+)$/i', '', DOL_DATA_ROOT); + $allowimportsite = true; + if (dol_is_file($dolibarrdataroot.'/installmodules.lock')) { + $allowimportsite = false; + } - $fileofzip = ''; - if (GETPOSTISSET('templateuserfile')) { - $fileofzip = DOL_DATA_ROOT.'/doctemplates/websites/'.GETPOST('templateuserfile', 'alpha'); - } elseif (!empty($_FILES)) { - if (is_array($_FILES['userfile']['tmp_name'])) { - $userfiles = $_FILES['userfile']['tmp_name']; - } else { - $userfiles = array($_FILES['userfile']['tmp_name']); + if ($allowimportsite) { + if (empty($_FILES) && !GETPOSTISSET('templateuserfile')) { + setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("File")), null, 'errors'); + $action = 'importsite'; + } else { + if (!empty($_FILES) || GETPOSTISSET('templateuserfile')) { + // Check symlink to medias and restore it if ko. Recreate also dir of website if not found. + $pathtomedias = DOL_DATA_ROOT.'/medias'; + $pathtomediasinwebsite = $pathofwebsite.'/medias'; + if (!is_link(dol_osencode($pathtomediasinwebsite))) { + dol_syslog("Create symlink for ".$pathtomedias." into name ".$pathtomediasinwebsite); + dol_mkdir(dirname($pathtomediasinwebsite)); // To be sure dir for website exists + $result = symlink($pathtomedias, $pathtomediasinwebsite); + if (!$result) { + setEventMessages($langs->trans("ErrorFieldToCreateSymLinkToMedias", $pathtomediasinwebsite, $pathtomedias), null, 'errors'); + $action = 'importsite'; + } } - foreach ($userfiles as $key => $userfile) { - if (empty($_FILES['userfile']['tmp_name'][$key])) { - $error++; - if ($_FILES['userfile']['error'][$key] == 1 || $_FILES['userfile']['error'][$key] == 2) { - setEventMessages($langs->trans('ErrorFileSizeTooLarge'), null, 'errors'); - $action = 'importsite'; - } else { - setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("File")), null, 'errors'); - $action = 'importsite'; + $fileofzip = ''; + if (GETPOSTISSET('templateuserfile')) { + // Case we selected one template + $fileofzip = DOL_DATA_ROOT.'/doctemplates/websites/'.GETPOST('templateuserfile', 'alpha'); // $fileofzip will be sanitized later into the importWebSite() + } elseif (!empty($_FILES)) { + // Case we upload a new template + if (is_array($_FILES['userfile']['tmp_name'])) { + $userfiles = $_FILES['userfile']['tmp_name']; + } else { + $userfiles = array($_FILES['userfile']['tmp_name']); + } + + // Check if $_FILES is ok + foreach ($userfiles as $key => $userfile) { + if (empty($_FILES['userfile']['tmp_name'][$key])) { + $error++; + if ($_FILES['userfile']['error'][$key] == 1 || $_FILES['userfile']['error'][$key] == 2) { + setEventMessages($langs->trans('ErrorFileSizeTooLarge'), null, 'errors'); + $action = 'importsite'; + } else { + setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("File")), null, 'errors'); + $action = 'importsite'; + } } } - } - if (!$error) { - $upload_dir = $conf->website->dir_temp; - $result = dol_add_file_process($upload_dir, 1, -1, 'userfile', ''); - } - - // Get name of file (take last one if several name provided) - $fileofzip = $upload_dir.'/unknown'; - foreach ($_FILES as $key => $ifile) { - foreach ($ifile['name'] as $key2 => $ifile2) { - $fileofzip = $upload_dir.'/'.$ifile2; + if (!$error) { + //$upload_dir = $conf->website->dir_temp; + $upload_dir = DOL_DATA_ROOT.'/doctemplates/websites/'; + $result = dol_add_file_process($upload_dir, 1, -1, 'userfile', ''); } - } - } - if (!$error) { - $result = $object->importWebSite($fileofzip); + // Get name of file (take last one if several name provided) + /* + $fileofzip = $upload_dir.'/unknown'; + foreach ($_FILES as $key => $ifile) { + foreach ($ifile['name'] as $key2 => $ifile2) { + $fileofzip = $upload_dir.'/'.$ifile2; + } + } + */ - if ($result < 0) { - setEventMessages($object->error, $object->errors, 'errors'); $action = 'importsite'; - } else { - // Force mode dynamic on - dolibarr_set_const($db, 'WEBSITE_SUBCONTAINERSINLINE', 1, 'chaine', 0, '', $conf->entity); + } - header("Location: ".$_SERVER["PHP_SELF"].'?website='.$object->ref); - exit(); + if (!$error && GETPOSTISSET('templateuserfile')) { + $result = $object->importWebSite($fileofzip); + + if ($result < 0) { + setEventMessages($object->error, $object->errors, 'errors'); + $action = 'importsite'; + } else { + // Force mode dynamic on + dolibarr_set_const($db, 'WEBSITE_SUBCONTAINERSINLINE', 1, 'chaine', 0, '', $conf->entity); + + header("Location: ".$_SERVER["PHP_SELF"].'?website='.$object->ref); + exit(); + } } } } + } else { + if (getDolGlobalString('MAIN_MESSAGE_INSTALL_MODULES_DISABLED_CONTACT_US')) { + // Show clean corporate message + $message = $langs->trans('InstallModuleFromWebHasBeenDisabledContactUs'); + } else { + // Show technical generic message + $message = $langs->trans("InstallModuleFromWebHasBeenDisabledByFile", $dolibarrdataroot.'/installmodules.lock'); + } + setEventMessages($message, null, 'errors'); } } @@ -2679,7 +2723,7 @@ $moreheadjs .= ''."\n"; -llxHeader($moreheadcss.$moreheadjs, $langs->trans("WebsiteSetup"), $helpurl, '', 0, 0, $arrayofjs, $arrayofcss, '', '', ''."\n".'
'); +llxHeader($moreheadcss.$moreheadjs, $langs->trans("Website").(empty($website->ref) ? '' : ' - '.$website->ref), $helpurl, '', 0, 0, $arrayofjs, $arrayofcss, '', '', ''."\n".'
'); print "\n"; print ''."\n"; @@ -3678,7 +3722,7 @@ if ($action == 'editcss') { // Manifest.json print '
- +
'; $htmlhelp = $langs->trans("Example").' :
'; - $htmlhelp .= dol_htmlentitiesbr($manifestjsoncontentdefault); + $htmlhelp .= ''.dol_htmlentitiesbr($manifestjsoncontentdefault).''; print $form->textwithpicto($langs->trans('WEBSITE_MANIFEST_JSON'), $htmlhelp, 1, 'help', '', 0, 2, 'manifestjsontooltip'); print '
'; print $langs->trans("UseManifest").': '.$form->selectyesno('use_manifest', $website->use_manifest, 1).'
'; @@ -3844,16 +3888,33 @@ if ($action == 'importsite') { print ''.$langs->trans("ZipOfWebsitePackageToImport").'

'; - $maxfilesizearray = getMaxFileSizeArray(); - $maxmin = $maxfilesizearray['maxmin']; - if ($maxmin > 0) { - print ''; // MAX_FILE_SIZE must precede the field type=file - } - print ''; - print ''; - print ''; - print '


'; + $dolibarrdataroot = preg_replace('/([\\/]+)$/i', '', DOL_DATA_ROOT); + $allowimportsite = true; + if (dol_is_file($dolibarrdataroot.'/installmodules.lock')) { + $allowimportsite = false; + } + + if ($allowimportsite) { + $maxfilesizearray = getMaxFileSizeArray(); + $maxmin = $maxfilesizearray['maxmin']; + if ($maxmin > 0) { + print ''; // MAX_FILE_SIZE must precede the field type=file + } + print ''; + print ''; + print ''; + print '


'; + } else { + if (getDolGlobalString('MAIN_MESSAGE_INSTALL_MODULES_DISABLED_CONTACT_US')) { + // Show clean corporate message + $message = $langs->trans('InstallModuleFromWebHasBeenDisabledContactUs'); + } else { + // Show technical generic message + $message = $langs->trans("InstallModuleFromWebHasBeenDisabledByFile", $dolibarrdataroot.'/installmodules.lock'); + } + print info_admin($message).'

'; + } print ''.$langs->trans("ZipOfWebsitePackageToLoad").'

'; diff --git a/scripts/cron/cron_run_jobs.php b/scripts/cron/cron_run_jobs.php index 630ae8c9948..c7a9d19fb5c 100755 --- a/scripts/cron/cron_run_jobs.php +++ b/scripts/cron/cron_run_jobs.php @@ -189,25 +189,17 @@ if ($result < 0) { exit(-1); } -$qualifiedjobs = array(); -foreach ($object->lines as $val) { - if (!verifCond($val->test)) { - continue; - } - $qualifiedjobs[] = $val; -} - // TODO Duplicate code. This sequence of code must be shared with code into public/cron/cron_run_jobs.php php page. -$nbofjobs = count($qualifiedjobs); +$nbofjobs = count($object->lines); $nbofjobslaunchedok = 0; $nbofjobslaunchedko = 0; -if (is_array($qualifiedjobs) && (count($qualifiedjobs) > 0)) { +if (is_array($object->lines) && (count($object->lines) > 0)) { $savconf = dol_clone($conf); // Loop over job - foreach ($qualifiedjobs as $line) { + foreach ($object->lines as $line) { dol_syslog("cron_run_jobs.php cronjobid: ".$line->id." priority=".$line->priority." entity=".$line->entity." label=".$line->label, LOG_DEBUG); echo "cron_run_jobs.php cronjobid: ".$line->id." priority=".$line->priority." entity=".$line->entity." label=".$line->label; @@ -249,6 +241,10 @@ if (is_array($qualifiedjobs) && (count($qualifiedjobs) > 0)) { } } + if (!verifCond($line->test)) { + continue; + } + //If date_next_jobs is less of current date, execute the program, and store the execution time of the next execution in database if ($forcequalified || (($line->datenextrun < $now) && (empty($line->datestart) || $line->datestart <= $now) && (empty($line->dateend) || $line->dateend >= $now))) { echo " - qualified"; diff --git a/test/phpunit/KnowledgeRecordTest.php b/test/phpunit/KnowledgeRecordTest.php index 8c3ed03e9b5..ad306ed04b2 100644 --- a/test/phpunit/KnowledgeRecordTest.php +++ b/test/phpunit/KnowledgeRecordTest.php @@ -175,13 +175,63 @@ class KnowledgeRecordTest extends PHPUnit\Framework\TestCase return $result; } + /** + * testKnowledgeRecordFetch + * + * @param int $id Id order + * @return KnowledgeRecord + * + * @depends testKnowledgeRecordCreate + * The depends says test is run only if previous is ok + */ + public function testKnowledgeRecordFetch($id) + { + global $conf,$user,$langs,$db; + $conf=$this->savconf; + $user=$this->savuser; + $langs=$this->savlangs; + $db=$this->savdb; + + $localobject=new KnowledgeRecord($this->savdb); + $result=$localobject->fetch($id); + + $this->assertLessThan($result, 0); + print __METHOD__." id=".$id." result=".$result."\n"; + return $localobject; + } + + /** + * testKnowledgeRecordUpdate + * @param KnowledgeRecord $localobject KnowledgeRecord + * @return int + * + * @depends testKnowledgeRecordFetch + * The depends says test is run only if previous is ok + */ + public function testKnowledgeRecordUpdate($localobject) + { + global $conf, $user, $langs, $db; + $conf = $this->savconf; + $user = $this->savuser; + $langs = $this->savlangs; + $db = $this->savdb; + + $localobject->note_private='New note private after update'; + $result = $localobject->update($user); + + $this->assertLessThan($result, 0); + print __METHOD__." id=".$localobject->id." result=".$result."\n"; + + return $result; + } + /** * testKnowledgeRecordDelete * * @param int $id Id of object * @return int * - * @depends testKnowledgeRecordCreate + * @depends testKnowledgeRecordUpdate * The depends says test is run only if previous is ok */ public function testKnowledgeRecordDelete($id) diff --git a/test/phpunit/SecurityTest.php b/test/phpunit/SecurityTest.php index cadf8a7504f..4a0b65333ff 100644 --- a/test/phpunit/SecurityTest.php +++ b/test/phpunit/SecurityTest.php @@ -221,6 +221,10 @@ class SecurityTest extends PHPUnit\Framework\TestCase $result=testSqlAndScriptInject($test, 1); $this->assertEquals($expectedresult, $result, 'Error on testSqlAndScriptInject for SQL2a. Should find an attack on GET param and did not.'); + $test = "delete\nfrom"; + $result=testSqlAndScriptInject($test, 1); + $this->assertEquals($expectedresult, $result, 'Error on testSqlAndScriptInject for SQL2b. Should find an attack on GET param and did not.'); + $test = 'action=update& ... set ... ='; $result=testSqlAndScriptInject($test, 1); $this->assertEquals(0, $result, 'Error on testSqlAndScriptInject for SQL2b. Should not find an attack on GET param and did.'); @@ -332,7 +336,11 @@ class SecurityTest extends PHPUnit\Framework\TestCase $test="Text with ' encoded with the numeric html entity converted into text entity ' (like when submited by CKEditor)"; $result=testSqlAndScriptInject($test, 0); // result must be 0 - $this->assertEquals(0, $result, 'Error on testSqlAndScriptInject mmm'); + $this->assertEquals(0, $result, 'Error on testSqlAndScriptInject mmm, result should be 0 and is not'); + + $test ='XSS'; + $result=testSqlAndScriptInject($test, 0); + $this->assertGreaterThanOrEqual($expectedresult, $result, 'Error on testSqlAndScriptInject nnn, result should be >= 1 and is not'); $test="/dolibarr/htdocs/index.php/".chr('246')."abc"; // Add the char %F6 into the variable $result=testSqlAndScriptInject($test, 2); @@ -385,9 +393,8 @@ class SecurityTest extends PHPUnit\Framework\TestCase $_POST["param16"]='abc'; $_POST["param17"]='abc'; $_POST["param18"]='abc'; - //$_POST["param13"]='javascript%26colon%26%23x3B%3Balert(1)'; - //$_POST["param14"]='javascripT&javascript#x3a alert(1)'; - + $_POST["param19"]='XSS'; + //$_POST["param19"]='XSS'; $result=GETPOST('id', 'int'); // Must return nothing print __METHOD__." result=".$result."\n"; @@ -507,7 +514,7 @@ class SecurityTest extends PHPUnit\Framework\TestCase print __METHOD__." result=".$result."\n"; $this->assertEquals(trim($_POST["param11"]), $result, 'Test an email string with alphawithlgt'); - // Test with restricthtml we must remove html open/close tag and content but not htmlentities (we can decode html entities for ascii chars like n) + // Test with restricthtml: we must remove html open/close tag and content but not htmlentities (we can decode html entities for ascii chars like n) $result=GETPOST("param6", 'restricthtml'); print __METHOD__." result param6=".$result."\n"; @@ -537,16 +544,24 @@ class SecurityTest extends PHPUnit\Framework\TestCase print __METHOD__." result=".$result."\n"; $this->assertEquals("Text with ' encoded with the numeric html entity converted into text entity ' (like when submited by CKEditor)", $result, 'Test 14'); - $result=GETPOST("param15", 'restricthtml'); // src=>0xbeefed + $result=GETPOST("param15", 'restricthtml'); // param15 = src=>0xbeefed that is a dangerous string print __METHOD__." result=".$result."\n"; $this->assertEquals("0xbeefed", $result, 'Test 15'); // The GETPOST return a harmull string - // Test with restricthtml + MAIN_RESTRICTHTML_REMOVE_ALSO_BAD_ATTRIBUTES to test disabling of bad atrributes + $result=GETPOST("param19", 'restricthtml'); + print __METHOD__." result=".$result."\n"; + $this->assertEquals('XSS', $result, 'Test 19'); + + + // Test with restricthtml + MAIN_RESTRICTHTML_ONLY_VALID_HTML to test disabling of bad atrributes $conf->global->MAIN_RESTRICTHTML_ONLY_VALID_HTML = 1; - $result=GETPOST("param15", 'restricthtml'); + + $result=GETPOST("param15", 'restricthtml'); // param15 = src=>0xbeefed that is a dangerous string print __METHOD__." result=".$result."\n"; $this->assertEquals('InvalidHTMLString', $result, 'Test 15b'); + //$this->assertEquals(' src=>0xbeefed', $result, 'Test 15b'); + unset($conf->global->MAIN_RESTRICTHTML_ONLY_VALID_HTML); @@ -555,7 +570,7 @@ class SecurityTest extends PHPUnit\Framework\TestCase $result=GETPOST("param15", 'restricthtml'); print __METHOD__." result=".$result."\n"; - $this->assertEquals('0xbeefed', $result, 'Test 15b'); + $this->assertEquals('0xbeefed', $result, 'Test 15c'); $result=GETPOST('param16', 'restricthtml'); print __METHOD__." result=".$result."\n"; @@ -836,6 +851,36 @@ class SecurityTest extends PHPUnit\Framework\TestCase $this->assertEquals('google.com', $result, 'Test on dol_sanitizeUrl C'); } + /** + * testDolSanitizeEmail + * + * @return void + */ + public function testDolSanitizeEmail() + { + global $conf,$user,$langs,$db; + $conf=$this->savconf; + $user=$this->savuser; + $langs=$this->savlangs; + $db=$this->savdb; + + $test = 'aaa@mycompany.com , bbb@mycompany.com '; + $result=dol_sanitizeEmail($test); + $this->assertEquals($test, $result, 'Test on dol_sanitizeEmail A'); + + $test = "aaa@mycompany.com ,\nbbb@mycompany.com "; + $result=dol_sanitizeEmail($test); + $this->assertEquals('aaa@mycompany.com ,bbb@mycompany.com ', $result, 'Test on dol_sanitizeEmail B'); + + $test = 'aaa@mycompany.com ,\nbbb@mycompany.com '; + $result=dol_sanitizeEmail($test); + $this->assertEquals('aaa@mycompany.com ,nbbb@mycompany.com ', $result, 'Test on dol_sanitizeEmail C'); + + $test = 'aaa@mycompany.com , "bcc:bbb"@mycompany.com '; + $result=dol_sanitizeEmail($test); + $this->assertEquals('aaa@mycompany.com , bccbbb@mycompany.com ', $result, 'Test on dol_sanitizeEmail D'); + } + /** * testDolSanitizeFileName * diff --git a/test/phpunit/Website.class.php b/test/phpunit/Website.class.php new file mode 100644 index 00000000000..50d0c16453d --- /dev/null +++ b/test/phpunit/Website.class.php @@ -0,0 +1,178 @@ + + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * or see https://www.gnu.org/ + */ + +/** + * \file test/phpunit/WebsiteTest.php + * \ingroup test + * \brief PHPUnit test + * \remarks To run this script as CLI: phpunit filename.php + */ + +global $conf,$user,$langs,$db; +//define('TEST_DB_FORCE_TYPE','mysql'); // This is to force using mysql driver +//require_once 'PHPUnit/Autoload.php'; + +if (! defined('NOREQUIRESOC')) { + define('NOREQUIRESOC', '1'); +} +if (! defined('NOCSRFCHECK')) { + define('NOCSRFCHECK', '1'); +} +if (! defined('NOTOKENRENEWAL')) { + define('NOTOKENRENEWAL', '1'); +} +if (! defined('NOREQUIREMENU')) { + define('NOREQUIREMENU', '1'); // If there is no menu to show +} +if (! defined('NOREQUIREHTML')) { + define('NOREQUIREHTML', '1'); // If we don't need to load the html.form.class.php +} +if (! defined('NOREQUIREAJAX')) { + define('NOREQUIREAJAX', '1'); +} +if (! defined("NOLOGIN")) { + define("NOLOGIN", '1'); // If this page is public (can be called outside logged session) +} +if (! defined("NOSESSION")) { + define("NOSESSION", '1'); +} + +require_once dirname(__FILE__).'/../../htdocs/main.inc.php'; +require_once dirname(__FILE__).'/../../htdocs/core/lib/website.lib.php'; + + +if (empty($user->id)) { + print "Load permissions for admin user nb 1\n"; + $user->fetch(1); + $user->getrights(); +} +$conf->global->MAIN_DISABLE_ALL_MAILS=1; + + +/** + * Class for PHPUnit tests + * + * @backupGlobals disabled + * @backupStaticAttributes enabled + * @remarks backupGlobals must be disabled to have db,conf,user and lang not erased. + */ +class WebsiteTest extends PHPUnit\Framework\TestCase +{ + protected $savconf; + protected $savuser; + protected $savlangs; + protected $savdb; + + /** + * Constructor + * We save global variables into local variables + * + * @return SecurityTest + */ + public function __construct() + { + parent::__construct(); + + //$this->sharedFixture + global $conf,$user,$langs,$db; + $this->savconf=$conf; + $this->savuser=$user; + $this->savlangs=$langs; + $this->savdb=$db; + + print __METHOD__." db->type=".$db->type." user->id=".$user->id; + //print " - db ".$db->db; + print "\n"; + } + + /** + * setUpBeforeClass + * + * @return void + */ + public static function setUpBeforeClass() + { + global $conf,$user,$langs,$db; + $db->begin(); // This is to have all actions inside a transaction even if test launched without suite. + + print __METHOD__."\n"; + } + + /** + * tearDownAfterClass + * + * @return void + */ + public static function tearDownAfterClass() + { + global $conf,$user,$langs,$db; + $db->rollback(); + + print __METHOD__."\n"; + } + + /** + * Init phpunit tests + * + * @return void + */ + protected function setUp() + { + global $conf,$user,$langs,$db; + $conf=$this->savconf; + $user=$this->savuser; + $langs=$this->savlangs; + $db=$this->savdb; + + print __METHOD__."\n"; + } + + /** + * End phpunit tests + * + * @return void + */ + protected function tearDown() + { + print __METHOD__."\n"; + } + + + /** + * testGetPagesFromSearchCriterias + * + * @return void + */ + public function testGetPagesFromSearchCriterias() + { + global $db; + + $s = "123') OR 1=1-- \' xxx"; + /* + var_dump($s); + var_dump($db->escapeforlike($s)); + var_dump($db->escape($db->escapeforlike($s))); + */ + + $res = getPagesFromSearchCriterias('page,blogpost', 'meta,content', $s, 2, 'date_creation', 'DESC', 'en'); + //var_dump($res); + print __METHOD__." message=".$res['code']."\n"; + // We must found no line (so code should be KO). If we found somethiing, it means there is a SQL injection of the 1=1 + $this->assertEquals($res['code'], 'KO'); + } +}