Merge branch '17.0' of git@github.com:Dolibarr/dolibarr.git into develop

This commit is contained in:
Laurent Destailleur 2023-05-21 17:34:34 +02:00
commit fe9521b6b2
21 changed files with 154 additions and 78 deletions

View File

@ -692,6 +692,9 @@ class Lettering extends BookKeeping
// Clean parameters
$document_ids = is_array($document_ids) ? $document_ids : array();
//remove empty entries
$document_ids = array_filter($document_ids);
$doc_type = trim($doc_type);
if (empty($document_ids)) {
@ -742,10 +745,13 @@ class Lettering extends BookKeeping
// Clean parameters
$document_ids = is_array($document_ids) ? $document_ids : array();
$doc_type = trim($doc_type);
//remove empty entries
$document_ids = array_filter($document_ids);
if (empty($document_ids)) {
return array();
}
if (!is_array(self::$doc_type_infos[$doc_type])) {
$langs->load('errors');
$this->errors[] = $langs->trans('ErrorBadParameters');

View File

@ -5,6 +5,7 @@
* Copyright (C) 2012 Regis Houssin <regis.houssin@inodbox.com>
* Copyright (C) 2013 Christophe Battarel <christophe.battarel@altairis.fr>
* Copyright (C) 2013-2022 Open-DSI <support@open-dsi.fr>
* Copyright (C) 2013-2023 Alexandre Spangaro <aspangaro@open-dsi.fr>
* Copyright (C) 2013-2014 Florian Henry <florian.henry@open-concept.pro>
* Copyright (C) 2013-2014 Olivier Geffroy <jeff@jeffinfo.com>
* Copyright (C) 2017-2023 Frédéric France <frederic.france@netlogic.fr>
@ -805,12 +806,6 @@ if (!$error && $action == 'writebookkeeping') {
require_once DOL_DOCUMENT_ROOT . '/accountancy/class/lettering.class.php';
$lettering_static = new Lettering($db);
$nb_lettering = $lettering_static->bookkeepingLetteringAll(array($bookkeeping->id));
if ($nb_lettering < 0) {
$error++;
$errorforline++;
setEventMessages($lettering_static->error, $lettering_static->errors, 'errors');
}
}
}
}

View File

@ -437,13 +437,8 @@ if ($action == 'writebookkeeping') {
if (getDolGlobalInt('ACCOUNTING_ENABLE_LETTERING') && getDolGlobalInt('ACCOUNTING_ENABLE_AUTOLETTERING')) {
require_once DOL_DOCUMENT_ROOT . '/accountancy/class/lettering.class.php';
$lettering_static = new Lettering($db);
$nb_lettering = $lettering_static->bookkeepingLettering(array($bookkeeping->id));
if ($nb_lettering < 0) {
$error++;
$errorforline++;
setEventMessages($lettering_static->error, $lettering_static->errors, 'errors');
}
$nb_lettering = $lettering_static->bookkeepingLettering(array($bookkeeping->id));
}
}
}

View File

@ -4,7 +4,7 @@
* Copyright (C) 2011 Juanjo Menent <jmenent@2byte.es>
* Copyright (C) 2012 Regis Houssin <regis.houssin@inodbox.com>
* Copyright (C) 2013 Christophe Battarel <christophe.battarel@altairis.fr>
* Copyright (C) 2013-2022 Alexandre Spangaro <aspangaro@open-dsi.fr>
* Copyright (C) 2013-2023 Alexandre Spangaro <aspangaro@open-dsi.fr>
* Copyright (C) 2013-2016 Florian Henry <florian.henry@open-concept.pro>
* Copyright (C) 2013-2016 Olivier Geffroy <jeff@jeffinfo.com>
* Copyright (C) 2014 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
@ -465,13 +465,6 @@ if ($action == 'writebookkeeping') {
$lettering_static = new Lettering($db);
$nb_lettering = $lettering_static->bookkeepingLettering(array($bookkeeping->id));
if ($nb_lettering < 0) {
$error++;
$errorforline++;
$errorforinvoice[$key] = 'other';
setEventMessages($lettering_static->error, $lettering_static->errors, 'errors');
}
}
}
}

View File

@ -125,7 +125,7 @@ if ($action == 'add') {
} else {
if (!$amountto[$n]) {
$errori[$n]++;
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("AmountTo")).' #'.$n, null, 'errors');
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("AmountToOthercurrency")).' #'.$n, null, 'errors');
}
}
if ($amountto[$n] < 0) {
@ -218,14 +218,22 @@ print ' <script type="text/javascript">
});
function init_page(i) {
// TODO Scan all line i and set atleast2differentcurrency if there is 2 different values among all lines
var account1 = $("#select"+i+"_account_from").val();
var account2 = $("#select"+i+"_account_to").val();
var currencycode1 = $("#select"+i+"_account_from option:selected").attr("data-currency-code");
var currencycode2 = $("#select"+i+"_account_to option:selected").attr("data-currency-code");
console.log("Set fields according to currencycode found currencycode1="+currencycode1+" currencycode2="+currencycode2);
var atleast2differentcurrency = false;
$(".selectbankaccount").each(function( index ) {
// Scan all line i and set atleast2differentcurrency if there is 2 different values among all lines
var account1 = $("#select"+index+"_account_from").val();
var account2 = $("#select"+index+"_account_to").val();
var currencycode1 = $("#select"+index+"_account_from option:selected").attr("data-currency-code");
var currencycode2 = $("#select"+index+"_account_to option:selected").attr("data-currency-code");
console.log("Set atleast2differentcurrency according to currencycode found for index="+index+" currencycode1="+currencycode1+" currencycode2="+currencycode2);
atleast2differentcurrency = (currencycode2!==currencycode1 && currencycode1 !== undefined && currencycode2 !== undefined && currencycode2!=="" && currencycode1!=="");
if (atleast2differentcurrency) {
return false;
}
});
var atleast2differentcurrency = (currencycode2!==currencycode1 && currencycode1 !== undefined && currencycode2 !== undefined && currencycode2!=="" && currencycode1!=="");
if (atleast2differentcurrency) {
console.log("We show multicurrency field");

View File

@ -1371,30 +1371,36 @@ class FormTicket
}
jQuery(".email_line").hide();
}
';
jQuery("#send_msg_email").click(function() {
if(jQuery(this).is(":checked")) {
if (jQuery("#private_message").is(":checked")) {
jQuery("#private_message").prop("checked", false).trigger("change");
// If constant set, allow to send private messages as email
if (empty($conf->global->TICKET_SEND_PRIVATE_EMAIL)) {
print 'jQuery("#send_msg_email").click(function() {
if(jQuery(this).is(":checked")) {
if (jQuery("#private_message").is(":checked")) {
jQuery("#private_message").prop("checked", false).trigger("change");
}
jQuery(".email_line").show();
}
jQuery(".email_line").show();
}
else {
jQuery(".email_line").hide();
}
});
else {
jQuery(".email_line").hide();
}
});
jQuery("#private_message").click(function() {
if (jQuery(this).is(":checked")) {
if (jQuery("#send_msg_email").is(":checked")) {
jQuery("#send_msg_email").prop("checked", false).trigger("change");
jQuery("#private_message").click(function() {
if (jQuery(this).is(":checked")) {
if (jQuery("#send_msg_email").is(":checked")) {
jQuery("#send_msg_email").prop("checked", false).trigger("change");
}
jQuery(".email_line").hide();
}
jQuery(".email_line").hide();
}
});';
});';
}
print '});
</script>';
print '<form method="post" name="ticket" id="ticket" enctype="multipart/form-data" action="'.$this->param["returnurl"].'">';
print '<input type="hidden" name="token" value="'.newToken().'">';
print '<input type="hidden" name="action" value="'.$this->action.'">';

View File

@ -3259,7 +3259,7 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity,
$partsofdirinoriginalfile = explode('/', $original_file);
if (!empty($partsofdirinoriginalfile[1])) { // If original_file is xxx/filename (xxx is a part we will use)
$partofdirinoriginalfile = $partsofdirinoriginalfile[0];
if ($partofdirinoriginalfile && !empty($fuser->rights->$modulepart->$partofdirinoriginalfile) && ($fuser->rights->$modulepart->$partofdirinoriginalfile->{$lire} || $fuser->rights->$modulepart->$partofdirinoriginalfile->{$read})) {
if ($partofdirinoriginalfile && ($fuser->hasRight($modulepart, $partofdirinoriginalfile, 'lire') || $fuser->hasRight($modulepart, $partofdirinoriginalfile, 'read'))) {
$accessallowed = 1;
}
}

View File

@ -8937,6 +8937,22 @@ function utf8_check($str)
return true;
}
/**
* Check if a string is in UTF8
*
* @param string $str String to check
* @return boolean True if string is valid UTF8 string, false if corrupted
*/
function utf8_valid($str)
{
/* 2 other methods to test if string is utf8
$validUTF8 = mb_check_encoding($messagetext, 'UTF-8');
$validUTF8b = ! (false === mb_detect_encoding($messagetext, 'UTF-8', true));
*/
return preg_match('//u', $str) ? true : false;
}
/**
* Check if a string is in ASCII
*

View File

@ -763,14 +763,22 @@ class InterfaceActionsAuto extends DolibarrTriggers
// Load translation files required by the page
$langs->loadLangs(array("agenda", "other", "members"));
if (empty($object->actionmsg2)) {
$object->actionmsg2 = $langs->transnoentities("MemberSubscriptionDeletedInDolibarr", $object->ref, $object->getFullName($langs));
$member = $this->context['member'];
if (!is_object($member)) { // This should not happen but it happen when deleting a subscription from adherents/subscription/card.php
dol_syslog("Execute a trigger MEMBER_SUBSCRIPTION_CREATE with context key 'member' not an object");
include_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
$member = new Adherent($this->db);
$member->fetch($object->fk_adherent);
}
$object->actionmsg = $langs->transnoentities("MemberSubscriptionDeletedInDolibarr", $object->ref, $object->getFullName($langs));
$object->actionmsg .= "\n".$langs->transnoentities("Member").': '.$object->getFullName($langs);
$object->actionmsg = $langs->transnoentities("MemberSubscriptionDeletedInDolibarr", $object->ref, $member->getFullName($langs));
$object->actionmsg .= "\n".$langs->transnoentities("Member").': '.$member->getFullName($langs);
$object->actionmsg .= "\n".$langs->transnoentities("Type").': '.$object->fk_type;
$object->actionmsg .= "\n".$langs->transnoentities("Amount").': '.$object->amount;
$object->actionmsg .= "\n".$langs->transnoentities("Period").': '.dol_print_date($object->dateh, 'day').' - '.dol_print_date($object->datef, 'day');
if (empty($object->actionmsg2)) {
$object->actionmsg2 = $langs->transnoentities("MemberSubscriptionDeletedInDolibarr", $object->ref, $member->getFullName($langs));
}
$object->sendtoid = 0;
if (isset($object->fk_soc) && $object->fk_soc > 0) {

View File

@ -1177,7 +1177,7 @@ class Cronjob extends CommonObject
return -1;
} else {
if (empty($user->id)) {
$this->error = " User user login:".$userlogin." do not exists";
$this->error = "User login: ".$userlogin." does not exist";
dol_syslog(get_class($this)."::run_jobs ".$this->error, LOG_ERR);
$conf->setEntityValues($this->db, $savcurrententity);
return -1;

View File

@ -1000,8 +1000,10 @@ class EmailCollector extends CommonObject
} else {
// Nothing can be done for this param
$errorforthisaction++;
$this->error = 'The extract rule to use has on an unknown source (must be HEADER, SUBJECT or BODY)';
$this->error = 'The extract rule to use to overwrite properties has on an unknown source (must be HEADER, SUBJECT or BODY)';
$this->errors[] = $this->error;
$operationslog .= '<br>'.$this->error;
}
} elseif (preg_match('/^(SET|SETIFEMPTY):(.*)$/', $valueforproperty, $regforregex)) {
$valuecurrent = '';
@ -1754,7 +1756,15 @@ class EmailCollector extends CommonObject
//$htmlmsg,$plainmsg,$charset,$attachments
$messagetext = $plainmsg ? $plainmsg : dol_string_nohtmltag($htmlmsg, 0);
// Removed emojis
$messagetext = preg_replace('/[\x{10000}-\x{10FFFF}]/u', "\xEF\xBF\xBD", $messagetext);
if (utf8_valid($messagetext)) {
//$messagetext = preg_replace('/[\x{10000}-\x{10FFFF}]/u', "\xEF\xBF\xBD", $messagetext);
$messagetext = $this->removeEmoji($messagetext);
} else {
$operationslog .= '<br>Discarded - Email body is not valid utf8';
dol_syslog(" Discarded - Email body is not valid utf8");
continue; // Exclude email
}
if ($searchfilterexcludebody) {
if (preg_match('/'.preg_quote($searchfilterexcludebody, '/').'/ms', $messagetext)) {
@ -2268,8 +2278,10 @@ class EmailCollector extends CommonObject
} else {
// Nothing can be done for this param
$errorforactions++;
$this->error = 'The extract rule to use to load thirdparty has an unknown source (must be HEADER, SUBJECT or BODY)';
$this->error = 'The extract rule to use to load thirdparty for email '.$msgid.' has an unknown source (must be HEADER, SUBJECT or BODY)';
$this->errors[] = $this->error;
$operationslog .= '<br>'.$this->error;
}
} elseif (preg_match('/^(SET|SETIFEMPTY):(.*)$/', $valueforproperty, $reg)) {
//if (preg_match('/^options_/', $tmpproperty)) $object->array_options[preg_replace('/^options_/', '', $tmpproperty)] = $reg[1];
@ -3499,4 +3511,24 @@ class EmailCollector extends CommonObject
return $subject;
}
/**
* Remove EMoji from email content
*
* @param string $text String to sanitize
* @return string Sanitized string
*/
protected function removeEmoji($text)
{
// Supprimer les caractères emoji en utilisant une expression régulière
$text = preg_replace('/[\x{1F600}-\x{1F64F}]/u', '', $text);
$text = preg_replace('/[\x{1F300}-\x{1F5FF}]/u', '', $text);
$text = preg_replace('/[\x{1F680}-\x{1F6FF}]/u', '', $text);
$text = preg_replace('/[\x{2600}-\x{26FF}]/u', '', $text);
$text = preg_replace('/[\x{2700}-\x{27BF}]/u', '', $text);
$text = preg_replace('/[\x{1F900}-\x{1F9FF}]/u', '', $text);
$text = preg_replace('/[\x{1F1E0}-\x{1F1FF}]/u', '', $text);
return $text;
}
}

View File

@ -739,6 +739,7 @@ if (empty($reshook)) {
// Actions on extra fields
$result = $object->insertExtraFields('INTERVENTION_MODIFY');
if ($result < 0) {
setEventMessages($object->error, $object->errors, 'errors');
$error++;
}
}

View File

@ -319,4 +319,5 @@ StockTransferRightCreateUpdate=Create/Update stocks transfers
StockTransferRightDelete=Delete stocks transfers
BatchNotFound=Lot / serial not found for this product
StockMovementWillBeRecorded=Stock movement will be recorded
StockMovementNotYetRecorded=Stock movement will not be affected by this step
StockMovementNotYetRecorded=Stock movement will not be affected by this step
WarningThisWIllAlsoDeleteStock=Warning, this will also destroy all quantities in stock in the warehouse

View File

@ -391,7 +391,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea
// ));
// }
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ToRefuse'), $text, 'confirm_refuse', $formquestion, '', 1, 250);
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ToRefuse'), '', 'confirm_refuse', $formquestion, '', 1, 250);
}
// Call Hook formConfirm

View File

@ -129,7 +129,7 @@ if (!empty($canvas)) {
}
// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
$hookmanager->initHooks(array('productreassortlotlist'));
$hookmanager->initHooks(array('reassortlotlist'));
// Security check
if ($user->socid) {

View File

@ -413,7 +413,10 @@ if ($action == 'create') {
// Confirm delete warehouse
if ($action == 'delete') {
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"]."?id=".$object->id, $langs->trans("DeleteAWarehouse"), $langs->trans("ConfirmDeleteWarehouse", $object->label), "confirm_delete", '', 0, 2);
$formquestion = array(
array('type' => 'other', 'name' => 'info', 'label' => img_warning('').$langs->trans("WarningThisWIllAlsoDeleteStock"), 'morecss'=>'warning')
);
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"]."?id=".$object->id, $langs->trans("DeleteAWarehouse"), $langs->trans("ConfirmDeleteWarehouse", $object->label), "confirm_delete", $formquestion, 0, 2);
}
// Call Hook formConfirm

View File

@ -382,16 +382,28 @@ class Entrepot extends CommonObject
// End call triggers
}
$elements = array('stock_mouvement', 'product_stock', 'product_warehouse_properties');
foreach ($elements as $table) {
if (!$error) {
$sql = "DELETE FROM ".$this->db->prefix().$table;
$sql .= " WHERE fk_entrepot = ".((int) $this->id);
if (!$error) {
$sql = "DELETE FROM ".$this->db->prefix()."product_batch";
$sql .= " WHERE fk_product_stock IN (SELECT rowid FROM ".$this->db->prefix()."product_stock as ps WHERE ps.fk_entrepot = ".((int) $this->id).")";
$result = $this->db->query($sql);
if (!$result) {
$error++;
$this->errors[] = $this->db->lasterror();
}
}
$result = $this->db->query($sql);
if (!$result) {
$error++;
$this->errors[] = $this->db->lasterror();
if (!$error) {
$elements = array('stock_mouvement', 'product_stock');
foreach ($elements as $table) {
if (!$error) {
$sql = "DELETE FROM ".$this->db->prefix().$table;
$sql .= " WHERE fk_entrepot = ".((int) $this->id);
$result = $this->db->query($sql);
if (!$result) {
$error++;
$this->errors[] = $this->db->lasterror();
}
}
}
}

View File

@ -707,8 +707,7 @@ if ($id > 0 || !empty($ref)) {
// List of actions on element
include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
$formactions = new FormActions($db);
$defaultthirdpartyid = $socid > 0 ? $socid : $object->project->socid;
$formactions->showactions($object, 'task', $defaultthirdpartyid, 1, '', 10, 'withproject='.$withproject);
$formactions->showactions($object, 'project_task', 0, 1, '', 10, 'withproject='.$withproject);
print '</div></div>';
}

View File

@ -633,7 +633,7 @@ if (empty($reshook)) {
$error++;
}
if ($prod_entry_mode == 'free' && (empty($idprod) || $idprod < 0) && GETPOST('price_ht') === '' && GETPOST('price_ttc') === '' && $price_ht_devise === '') { // Unit price can be 0 but not ''. Also price can be negative for proposal.
if ($prod_entry_mode == 'free' && (empty($idprod) || $idprod < 0) && GETPOST('price_ht') === '' && GETPOST('price_ttc') === '' && GETPOST('multicurrency_price_ht') === '') { // Unit price can be 0 but not ''. Also price can be negative for proposal.
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("UnitPrice")), null, 'errors');
$error++;
}

View File

@ -62,7 +62,8 @@ if (!defined('ISLOADEDBYSTEELSHEET')) {
position: relative;
}
.timeline > li.timeline-code-ticket_msg_private > .timeline-item {
.timeline > li.timeline-code-ticket_msg_private > .timeline-item,
.timeline > li.timeline-code-ticket_msg_private_sentbymail > .timeline-item {
background: #fffbe5;
border-color: #d0cfc0;
}

View File

@ -199,7 +199,7 @@ if (is_array($object->lines) && (count($object->lines) > 0)) {
// Force reload of setup for the current entity
if ((empty($line->entity) ? 1 : $line->entity) != $conf->entity) {
dol_syslog("cron_run_jobs.php we work on another entity conf than ".$conf->entity." so we reload mysoc, langs, user and conf", LOG_DEBUG);
dol_syslog("cron_run_jobs.php: we work on another entity conf than ".$conf->entity." so we reload mysoc, langs, user and conf", LOG_DEBUG);
echo " -> we change entity so we reload mysoc, langs, user and conf";
$conf->entity = (empty($line->entity) ? 1 : $line->entity);
@ -211,12 +211,12 @@ if (is_array($object->lines) && (count($object->lines) > 0)) {
$result = $user->fetch('', $userlogin, '', 1);
if ($result < 0) {
echo "\nUser Error: ".$user->error."\n";
dol_syslog("cron_run_jobs.php:: User Error:".$user->error, LOG_ERR);
dol_syslog("cron_run_jobs.php: User Error:".$user->error, LOG_ERR);
exit(-1);
} else {
if ($result == 0) {
echo "\nUser login: ".$userlogin." does not exists for entity ".$conf->entity."\n";
dol_syslog("User login:".$userlogin." does not exists", LOG_ERR);
echo "\nUser login: ".$userlogin." does not exist for entity ".$conf->entity."\n";
dol_syslog("cron_run_jobs.php: User login: ".$userlogin." does not exist", LOG_ERR);
exit(-1);
}
}
@ -248,7 +248,7 @@ if (is_array($object->lines) && (count($object->lines) > 0)) {
$cronjob = new Cronjob($db);
$result = $cronjob->fetch($line->id);
if ($result < 0) {
echo "Error cronjobid: ".$line->id." cronjob->fetch: ".$cronjob->error."\n";
echo " - Error cronjobid: ".$line->id." cronjob->fetch: ".$cronjob->error."\n";
echo "Failed to fetch job ".$line->id."\n";
dol_syslog("cron_run_jobs.php::fetch Error ".$cronjob->error, LOG_ERR);
exit(-1);
@ -256,7 +256,7 @@ if (is_array($object->lines) && (count($object->lines) > 0)) {
// Execute job
$result = $cronjob->run_jobs($userlogin);
if ($result < 0) {
echo "Error cronjobid: ".$line->id." cronjob->run_job: ".$cronjob->error."\n";
echo " - Error cronjobid: ".$line->id." cronjob->run_job: ".$cronjob->error."\n";
echo "At least one job failed. Go on menu Home-Setup-Admin tools to see result for each job.\n";
echo "You can also enable module Log if not yet enabled, run again and take a look into dolibarr.log file\n";
dol_syslog("cron_run_jobs.php::run_jobs Error ".$cronjob->error, LOG_ERR);
@ -272,7 +272,7 @@ if (is_array($object->lines) && (count($object->lines) > 0)) {
// We re-program the next execution and stores the last execution time for this job
$result = $cronjob->reprogram_jobs($userlogin, $now);
if ($result < 0) {
echo "Error cronjobid: ".$line->id." cronjob->reprogram_job: ".$cronjob->error."\n";
echo " - Error cronjobid: ".$line->id." cronjob->reprogram_job: ".$cronjob->error."\n";
echo "Enable module Log if not yet enabled, run again and take a look into dolibarr.log file\n";
dol_syslog("cron_run_jobs.php::reprogram_jobs Error ".$cronjob->error, LOG_ERR);
exit(-1);