diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 47ffeb5e28f8f..3296110422cca 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,7 +6,7 @@ repos: rev: v4.5.0 hooks: - id: no-commit-to-branch - args: [--branch, develop, --pattern, \d+.0] + args: [--branch, develop, --pattern, \d+.0$] - id: check-yaml args: [--unsafe] - id: check-json diff --git a/htdocs/accountancy/bookkeeping/list.php b/htdocs/accountancy/bookkeeping/list.php index 819d1fe21e8ac..6337b50f85fd3 100644 --- a/htdocs/accountancy/bookkeeping/list.php +++ b/htdocs/accountancy/bookkeeping/list.php @@ -1137,7 +1137,7 @@ print $form->selectDate($search_date_modification_start, 'search_date_modification_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("From")); print ''; print '
'; - print $form->selectDate($search_date_modification_end, 'search_date_modification_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("From")); + print $form->selectDate($search_date_modification_end, 'search_date_modification_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to")); print '
'; print ''; } diff --git a/htdocs/accountancy/journal/bankjournal.php b/htdocs/accountancy/journal/bankjournal.php index 2b154d3639ad6..95f62289d5394 100644 --- a/htdocs/accountancy/journal/bankjournal.php +++ b/htdocs/accountancy/journal/bankjournal.php @@ -216,6 +216,7 @@ // one line tabpay = line into bank // one line for bank record = tabbq // one line for thirdparty record = tabtp + // Note: tabcompany is used to store the subledger account $i = 0; while ($i < $num) { $obj = $db->fetch_object($result); @@ -263,7 +264,8 @@ ); // Set accountancy code for user - // $obj->accountancy_code is the accountancy_code of table u=user but it is defined only if a link with type 'user' exists) + // $obj->accountancy_code is the accountancy_code of table u=user (but it is defined only if + // a link with type 'user' exists and user as a subledger account) $compta_user = (!empty($obj->accountancy_code) ? $obj->accountancy_code : ''); $tabuser[$obj->rowid] = array( @@ -364,13 +366,25 @@ $userstatic->lastname = $tabuser[$obj->rowid]['lastname']; $userstatic->statut = $tabuser[$obj->rowid]['status']; $userstatic->accountancy_code = $tabuser[$obj->rowid]['accountancy_code']; + // For a payment of social contribution, we have a link sc + user. + // but we already fill the $tabpay[$obj->rowid]["soclib"] in the line 'sc'. + // If we fill it here to, we must concat if ($userstatic->id > 0) { - $tabpay[$obj->rowid]["soclib"] = $userstatic->getNomUrl(1, 'accountancy', 0); + if ($is_sc) { + $tabpay[$obj->rowid]["soclib"] .= ' '.$userstatic->getNomUrl(1, 'accountancy', 0); + } else { + $tabpay[$obj->rowid]["soclib"] = $userstatic->getNomUrl(1, 'accountancy', 0); + } } else { $tabpay[$obj->rowid]["soclib"] = '???'; // Should not happen, but happens with old data when id of user was not saved on expense report payment. } + if ($compta_user) { - $tabtp[$obj->rowid][$compta_user] += $amounttouse; + if ($is_sc) { + //$tabcompany[$obj->rowid][$compta_user] += $amounttouse; + } else { + $tabtp[$obj->rowid][$compta_user] += $amounttouse; + } } } elseif ($links[$key]['type'] == 'sc') { $chargestatic->id = $links[$key]['url_id']; diff --git a/htdocs/admin/mails.php b/htdocs/admin/mails.php index 73096056f9892..cf0a1451c4287 100644 --- a/htdocs/admin/mails.php +++ b/htdocs/admin/mails.php @@ -42,7 +42,7 @@ $usersignature = $user->signature; // For action = test or send, we ensure that content is not html, even for signature, because for this we want a test with NO html. -if ($action == 'test' || ($action == 'send' && $trackid = 'test')) { +if ($action == 'test' || ($action == 'send' && $trackid == 'test')) { $usersignature = dol_string_nohtmltag($usersignature, 2); } diff --git a/htdocs/api/class/api_documents.class.php b/htdocs/api/class/api_documents.class.php index cab81b801246c..0c79e261f3853 100644 --- a/htdocs/api/class/api_documents.class.php +++ b/htdocs/api/class/api_documents.class.php @@ -762,9 +762,52 @@ public function post($filename, $modulepart, $ref = '', $subdir = '', $fileconte throw new RestException(500, "Failed to open file '".$destfiletmp."' for write"); } - $result = dol_move($destfiletmp, $destfile, 0, $overwriteifexists, 1, 1); + $disablevirusscan = 0; + $src_file = $destfiletmp; + $dest_file = $destfile; + + // Security: + // If we need to make a virus scan + if (empty($disablevirusscan) && file_exists($src_file)) { + $checkvirusarray = dolCheckVirus($src_file); + if (count($checkvirusarray)) { + dol_syslog('Files.lib::dol_move_uploaded_file File "'.$src_file.'" (target name "'.$dest_file.'") KO with antivirus: errors='.join(',', $checkvirusarray), LOG_WARNING); + throw new RestException(500, 'ErrorFileIsInfectedWithAVirus: '.join(',', $checkvirusarray)); + } + } + + // Security: + // Disallow file with some extensions. We rename them. + // Because if we put the documents directory into a directory inside web root (very bad), this allows to execute on demand arbitrary code. + if (isAFileWithExecutableContent($dest_file) && empty($conf->global->MAIN_DOCUMENT_IS_OUTSIDE_WEBROOT_SO_NOEXE_NOT_REQUIRED)) { + // $upload_dir ends with a slash, so be must be sure the medias dir to compare to ends with slash too. + $publicmediasdirwithslash = $conf->medias->multidir_output[$conf->entity]; + if (!preg_match('/\/$/', $publicmediasdirwithslash)) { + $publicmediasdirwithslash .= '/'; + } + + if (strpos($upload_dir, $publicmediasdirwithslash) !== 0 || !getDolGlobalInt("MAIN_DOCUMENT_DISABLE_NOEXE_IN_MEDIAS_DIR")) { // We never add .noexe on files into media directory + $dest_file .= '.noexe'; + } + } + + // Security: + // We refuse cache files/dirs, upload using .. and pipes into filenames. + if (preg_match('/^\./', basename($src_file)) || preg_match('/\.\./', $src_file) || preg_match('/[<>|]/', $src_file)) { + dol_syslog("Refused to deliver file ".$src_file, LOG_WARNING); + throw new RestException(500, "Refused to deliver file ".$src_file); + } + + // Security: + // We refuse cache files/dirs, upload using .. and pipes into filenames. + if (preg_match('/^\./', basename($dest_file)) || preg_match('/\.\./', $dest_file) || preg_match('/[<>|]/', $dest_file)) { + dol_syslog("Refused to deliver file ".$dest_file, LOG_WARNING); + throw new RestException(500, "Refused to deliver file ".$dest_file); + } + + $result = dol_move($destfiletmp, $dest_file, 0, $overwriteifexists, 1, 1); if (!$result) { - throw new RestException(500, "Failed to move file into '".$destfile."'"); + throw new RestException(500, "Failed to move file into '".$dest_file."'"); } return dol_basename($destfile); diff --git a/htdocs/categories/class/api_categories.class.php b/htdocs/categories/class/api_categories.class.php index e7e86cf70fea6..30f4b23264d0a 100644 --- a/htdocs/categories/class/api_categories.class.php +++ b/htdocs/categories/class/api_categories.class.php @@ -268,7 +268,7 @@ public function delete($id) } if ($this->category->delete(DolibarrApiAccess::$user) <= 0) { - throw new RestException(500, 'Error when delete category ' . $this->category->error); + throw new RestException(500, 'Error when delete category : ' . $this->category->error); } return array( diff --git a/htdocs/comm/action/class/actioncomm.class.php b/htdocs/comm/action/class/actioncomm.class.php index 1922fdb7691c8..7ffe0e0f3b8b2 100644 --- a/htdocs/comm/action/class/actioncomm.class.php +++ b/htdocs/comm/action/class/actioncomm.class.php @@ -2432,6 +2432,7 @@ public function sendEmailsReminder() // Load event $res = $this->fetch($actionCommReminder->fk_actioncomm); + if ($res > 0) $res = $this->fetch_thirdparty(); if ($res > 0) { // PREPARE EMAIL $errormesg = ''; diff --git a/htdocs/comm/propal/class/propal.class.php b/htdocs/comm/propal/class/propal.class.php index 2dbaeaf056e09..408fa9899a6d8 100644 --- a/htdocs/comm/propal/class/propal.class.php +++ b/htdocs/comm/propal/class/propal.class.php @@ -2651,7 +2651,10 @@ public function closeProposal($user, $status, $note = '', $notrigger = 0) } $sql = "UPDATE ".MAIN_DB_PREFIX."propal"; - $sql .= " SET fk_statut = ".((int) $status).", note_private = '".$this->db->escape($newprivatenote)."', date_signature='".$this->db->idate($date_signature)."', fk_user_signature=".$fk_user_signature; + $sql .= " SET fk_statut = ".((int) $status).", note_private = '".$this->db->escape($newprivatenote)."'"; + if ($status == self::STATUS_SIGNED) { + $sql .= ", date_signature='".$this->db->idate($now)."', fk_user_signature = ".($fk_user_signature); + } $sql .= " WHERE rowid = ".((int) $this->id); $resql = $this->db->query($sql); diff --git a/htdocs/commande/list.php b/htdocs/commande/list.php index bf39beba029f8..ef7f802c61bf4 100644 --- a/htdocs/commande/list.php +++ b/htdocs/commande/list.php @@ -2508,7 +2508,7 @@ $productstat_cachevirtual[$generic_commande->lines[$lig]->fk_product]['stock_reel'] = $generic_product->stock_theorique; } else { $generic_product->stock_reel = $productstat_cache[$generic_commande->lines[$lig]->fk_product]['stock_reel']; - $generic_product->stock_theorique = $productstat_cachevirtual[$generic_commande->lines[$lig]->fk_product]['stock_reel'] = $generic_product->stock_theorique; + $generic_product->stock_theorique = $productstat_cachevirtual[$generic_commande->lines[$lig]->fk_product]['stock_reel']; } if ($reliquat > $generic_product->stock_reel) { diff --git a/htdocs/compta/bank/card.php b/htdocs/compta/bank/card.php index a923f3a082913..102e6c5f69770 100644 --- a/htdocs/compta/bank/card.php +++ b/htdocs/compta/bank/card.php @@ -80,7 +80,6 @@ $result = restrictedArea($user, 'banque', $id, 'bank_account&bank_account', '', '', $fieldid); - /* * Actions */ @@ -222,6 +221,7 @@ $object = new Account($db); $object->fetch(GETPOST("id", 'int')); + $object->oldref = $object->ref; $object->ref = dol_string_nospecial(trim(GETPOST('ref', 'alpha'))); $object->label = trim(GETPOST("label", 'alphanohtml')); $object->courant = GETPOST("type"); diff --git a/htdocs/compta/bank/class/account.class.php b/htdocs/compta/bank/class/account.class.php index 8e5366d7301be..c7a8aab1144e4 100644 --- a/htdocs/compta/bank/class/account.class.php +++ b/htdocs/compta/bank/class/account.class.php @@ -266,6 +266,11 @@ class Account extends CommonObject */ public $ics_transfer; + /** + * @var string The previous ref in case of rename on update to rename attachment folders + */ + public $oldref; + /** @@ -897,6 +902,28 @@ public function update(User $user, $notrigger = 0) } } + if (!$error && !empty($this->oldref) && $this->oldref !== $this->ref) { + $sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filepath = 'bank/".$this->db->escape($this->ref)."'"; + $sql .= " WHERE filepath = 'bank/".$this->db->escape($this->oldref)."' and src_object_type='bank_account' and entity = ".((int) $conf->entity); + $resql = $this->db->query($sql); + if (!$resql) { + $error++; + $this->error = $this->db->lasterror(); + } + + // We rename directory in order not to lose the attachments + $oldref = dol_sanitizeFileName($this->oldref); + $newref = dol_sanitizeFileName($this->ref); + $dirsource = $conf->bank->dir_output.'/'.$oldref; + $dirdest = $conf->bank->dir_output.'/'.$newref; + if (file_exists($dirsource)) { + dol_syslog(get_class($this)."::update rename dir ".$dirsource." into ".$dirdest, LOG_DEBUG); + if (@rename($dirsource, $dirdest)) { + dol_syslog("Rename ok", LOG_DEBUG); + } + } + } + if (!$error && !$notrigger) { // Call trigger $result = $this->call_trigger('BANKACCOUNT_MODIFY', $user); diff --git a/htdocs/compta/facture/card-rec.php b/htdocs/compta/facture/card-rec.php index 853bd4d3bd68a..bc0b608173e77 100644 --- a/htdocs/compta/facture/card-rec.php +++ b/htdocs/compta/facture/card-rec.php @@ -91,7 +91,10 @@ $object = new FactureRec($db); if (($id > 0 || $ref) && $action != 'create' && $action != 'add') { $ret = $object->fetch($id, $ref); - if (!$ret) { + if ($ret < 0) { + dol_print_error($db, $object->error, $object->errors); + exit; + } elseif (! $ret) { setEventMessages($langs->trans("ErrorRecordNotFound"), null, 'errors'); } } @@ -1248,6 +1251,7 @@ function showselectfksocieterib(){ if ($object->id > 0) { $object->fetch_thirdparty(); + $formconfirm = ''; // Confirmation de la suppression d'une ligne produit if ($action == 'ask_deleteline') { $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id.'&lineid='.$lineid, $langs->trans('DeleteProductLine'), $langs->trans('ConfirmDeleteProductLine'), 'confirm_deleteline', '', 'no', 1); @@ -1372,14 +1376,10 @@ function showselectfksocieterib(){ } print ''; print ''; - if ($object->type != Facture::TYPE_CREDIT_NOTE) { - if ($action == 'editconditions') { - $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id, $object->cond_reglement_id, 'cond_reglement_id'); - } else { - $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id, $object->cond_reglement_id, 'none'); - } + if ($action == 'editconditions') { + $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id, $object->cond_reglement_id, 'cond_reglement_id'); } else { - print ' '; + $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id, $object->cond_reglement_id, 'none'); } print ''; @@ -1846,6 +1846,7 @@ function showselectfksocieterib(){ // List of actions on element include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php'; $formactions = new FormActions($db); + $morehtmlcenter = ''; $somethingshown = $formactions->showactions($object, $object->element, (is_object($object->thirdparty) ? $object->thirdparty->id : 0), 1, '', $MAXEVENT, '', $morehtmlcenter); print ''; diff --git a/htdocs/compta/facture/class/facture-rec.class.php b/htdocs/compta/facture/class/facture-rec.class.php index ee61789b49a9e..b1c8dab0260bf 100644 --- a/htdocs/compta/facture/class/facture-rec.class.php +++ b/htdocs/compta/facture/class/facture-rec.class.php @@ -362,6 +362,7 @@ public function create($user, $facid, $notrigger = 0) $sql .= ", ".(!empty($this->rule_for_lines_dates) ? ("'".$this->db->escape($this->rule_for_lines_dates)."'") : "NULL"); /** BACKPORT PR 32129 */ $sql .= ")"; + if ($this->db->query($sql)) { $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."facture_rec"); diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index c3ccaf15d193c..3ed0571fe84f3 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -5615,9 +5615,9 @@ public function sendEmailsRemindersOnInvoiceDueDate($nbdays = 0, $paymentmode = $joinFileName = []; $joinFileMime = []; if ($arraymessage->joinfiles == 1 && !empty($tmpinvoice->last_main_doc)) { - $joinFile[] = DOL_DATA_ROOT.$tmpinvoice->last_main_doc; + $joinFile[] = DOL_DATA_ROOT.'/'.$tmpinvoice->last_main_doc; $joinFileName[] = basename($tmpinvoice->last_main_doc); - $joinFileMime[] = dol_mimetype(DOL_DATA_ROOT.$tmpinvoice->last_main_doc); + $joinFileMime[] = dol_mimetype(DOL_DATA_ROOT.'/'.$tmpinvoice->last_main_doc); } // Mail Creation diff --git a/htdocs/compta/stats/cabyprodserv.php b/htdocs/compta/stats/cabyprodserv.php index e747c4380a4eb..ba8a652930428 100644 --- a/htdocs/compta/stats/cabyprodserv.php +++ b/htdocs/compta/stats/cabyprodserv.php @@ -506,7 +506,7 @@ // Quantity print ''; - print $qty[$key]; + print price($qty[$key], 1, $langs, 0, 0); print ''; // Percent; diff --git a/htdocs/core/actions_massactions.inc.php b/htdocs/core/actions_massactions.inc.php index 65ae29d376a71..7d480ac493cb8 100644 --- a/htdocs/core/actions_massactions.inc.php +++ b/htdocs/core/actions_massactions.inc.php @@ -476,6 +476,11 @@ $substitutionarray['__EMAIL__'] = $thirdparty->email; $substitutionarray['__CHECK_READ__'] = ''; + if ($oneemailperrecipient) { + $substitutionarray['__ONLINE_PAYMENT_URL__'] = ''; + $substitutionarray['__ONLINE_PAYMENT_TEXT_AND_URL__'] = ''; + } + $parameters = array('mode'=>'formemail'); if (!empty($listofobjectthirdparties)) { diff --git a/htdocs/core/ajax/selectobject.php b/htdocs/core/ajax/selectobject.php index 079224c62a23e..f12b9b56b78d6 100644 --- a/htdocs/core/ajax/selectobject.php +++ b/htdocs/core/ajax/selectobject.php @@ -83,7 +83,11 @@ $searchkey = (($id && GETPOST($id, 'alpha')) ? GETPOST($id, 'alpha') : (($htmlname && GETPOST($htmlname, 'alpha')) ? GETPOST($htmlname, 'alpha') : '')); // Add a security test to avoid to get content of all tables -restrictedArea($user, $objecttmp->element, $id); +if (!empty($objecttmp->module)) { + restrictedArea($user, $objecttmp->module, $id, $objecttmp->table_element, $objecttmp->element); +} else { + restrictedArea($user, $objecttmp->element, $id); +} $arrayresult = $form->selectForFormsList($objecttmp, $htmlname, '', 0, $searchkey, '', '', '', 0, 1, 0, '', $filter); diff --git a/htdocs/core/boxes/box_actions.php b/htdocs/core/boxes/box_actions.php index fb0f93086d283..21f226b9806e1 100644 --- a/htdocs/core/boxes/box_actions.php +++ b/htdocs/core/boxes/box_actions.php @@ -106,7 +106,7 @@ public function loadBox($max = 5) $sql .= " AND s.rowid = ".((int) $user->socid); } if (empty($user->rights->agenda->allactions->read)) { - $sql .= " AND (a.fk_user_author = ".((int) $user->id)." OR a.fk_user_action = ".((int) $user->id)." OR a.fk_user_done = ".((int) $user->id).")"; + $sql .= " AND (a.fk_user_author = ".((int) $user->id)." OR a.fk_user_action = ".((int) $user->id).")"; } $sql .= " ORDER BY a.datep ASC"; $sql .= $this->db->plimit($max, 0); diff --git a/htdocs/core/class/CMailFile.class.php b/htdocs/core/class/CMailFile.class.php index da861fbfb0d2e..4110c7ee731b5 100644 --- a/htdocs/core/class/CMailFile.class.php +++ b/htdocs/core/class/CMailFile.class.php @@ -875,7 +875,7 @@ public function sendfile() } } elseif ($this->sendmode == 'smtps') { if (!is_object($this->smtps)) { - $this->error = "Failed to send mail with smtps lib to HOST=".$server.", PORT=".$conf->global->$keyforsmtpport."
Constructor of object CMailFile was not initialized without errors."; + $this->error = "Failed to send mail with smtps lib to HOST=".ini_get('SMTP').", PORT=".$conf->global->$keyforsmtpport."
Constructor of object CMailFile was not initialized without errors."; dol_syslog("CMailFile::sendfile: mail end error=".$this->error, LOG_ERR); return false; } @@ -1165,9 +1165,10 @@ public function sendfile() $res = true; if (!empty($this->error) || !empty($this->errors) || !$result) { if (!empty($failedRecipients)) { - $this->errors[] = 'Transport failed for the following addresses: "' . join('", "', $failedRecipients) . '".'; + $this->error = 'Transport failed for the following addresses: "' . join('", "', $failedRecipients) . '".'; + $this->errors[] = $this->error; } - dol_syslog("CMailFile::sendfile: mail end error=".$this->error, LOG_ERR); + dol_syslog("CMailFile::sendfile: mail end error=". join(' ', $this->errors), LOG_ERR); $res = false; if (!empty($conf->global->MAIN_MAIL_DEBUG)) { diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index e366f24af9577..f2b173f60585c 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -2192,7 +2192,9 @@ public function load_previous_next_ref($filter, $fieldid, $nodbprefix = 0) $sql = "SELECT MAX(te.".$fieldid.")"; $sql .= " FROM ".(empty($nodbprefix) ?$this->db->prefix():'').$this->table_element." as te"; if ($this->element == 'user' && !empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) { - $sql .= ",".$this->db->prefix()."usergroup_user as ug"; + if (empty($user->admin) || !empty($user->entity) || $conf->entity != 1) { + $sql .= " INNER JOIN ".MAIN_DB_PREFIX."usergroup_user as ug ON ug.fk_user = te.rowid"; + } } if (isset($this->ismultientitymanaged) && !is_numeric($this->ismultientitymanaged)) { $tmparray = explode('@', $this->ismultientitymanaged); @@ -2229,7 +2231,6 @@ public function load_previous_next_ref($filter, $fieldid, $nodbprefix = 0) if (!empty($user->admin) && empty($user->entity) && $conf->entity == 1) { $sql .= " AND te.entity IS NOT NULL"; // Show all users } else { - $sql .= " AND ug.fk_user = te.rowid"; $sql .= " AND ug.entity IN (".getEntity('usergroup').")"; } } else { @@ -2262,7 +2263,9 @@ public function load_previous_next_ref($filter, $fieldid, $nodbprefix = 0) $sql = "SELECT MIN(te.".$fieldid.")"; $sql .= " FROM ".(empty($nodbprefix) ?$this->db->prefix():'').$this->table_element." as te"; if ($this->element == 'user' && !empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) { - $sql .= ",".$this->db->prefix()."usergroup_user as ug"; + if (empty($user->admin) || !empty($user->entity) || $conf->entity != 1) { + $sql .= " INNER JOIN ".MAIN_DB_PREFIX."usergroup_user as ug ON ug.fk_user = te.rowid"; + } } if (isset($this->ismultientitymanaged) && !is_numeric($this->ismultientitymanaged)) { $tmparray = explode('@', $this->ismultientitymanaged); @@ -2299,7 +2302,6 @@ public function load_previous_next_ref($filter, $fieldid, $nodbprefix = 0) if (!empty($user->admin) && empty($user->entity) && $conf->entity == 1) { $sql .= " AND te.entity IS NOT NULL"; // Show all users } else { - $sql .= " AND ug.fk_user = te.rowid"; $sql .= " AND ug.entity IN (".getEntity('usergroup').")"; } } else { @@ -3196,7 +3198,7 @@ public function getChildrenOfLine($id, $includealltree = 0) while ($row = $this->db->fetch_row($resql)) { $rows[] = $row[0]; if (!empty($includealltree)) { - $rows = array_merge($rows, $this->getChildrenOfLine($row[0]), $includealltree); + $rows = array_merge($rows, $this->getChildrenOfLine($row[0], $includealltree)); } } } @@ -4085,8 +4087,12 @@ public function fetchObjectLinked($sourceid = null, $sourcetype = '', $targetid $classpath = 'adherents/class'; $module = 'adherent'; } elseif ($objecttype == 'contact') { - $module = 'societe'; + $module = 'societe'; + } elseif ($objecttype == 'action') { + $module = 'agenda'; + $subelement = 'actionComm'; } + // Set classfile $classfile = strtolower($subelement); $classname = ucfirst($subelement); @@ -4917,8 +4923,8 @@ public function formAddObjectLine($dateSelector, $seller, $buyer, $defaulttpldir * But for the moment we don't know if it's possible as we keep a method available on overloaded objects. * * @param string $action Action code - * @param string $seller Object of seller third party - * @param string $buyer Object of buyer third party + * @param Societe $seller Object of seller third party + * @param Societe $buyer Object of buyer third party * @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 @@ -9460,6 +9466,7 @@ public function fetchLinesCommon($morewhere = '') if ($resql) { $num_rows = $this->db->num_rows($resql); $i = 0; + $this->lines = array(); while ($i < $num_rows) { $obj = $this->db->fetch_object($resql); if ($obj) { diff --git a/htdocs/core/class/conf.class.php b/htdocs/core/class/conf.class.php index 2d6cc4f571587..79e01f2f6868b 100644 --- a/htdocs/core/class/conf.class.php +++ b/htdocs/core/class/conf.class.php @@ -161,6 +161,7 @@ public function __construct() $this->mailing = new stdClass(); $this->expensereport = new stdClass(); $this->productbatch = new stdClass(); + $this->api = new stdClass(); } /** diff --git a/htdocs/core/class/html.formmail.class.php b/htdocs/core/class/html.formmail.class.php index a56fec193b335..31e0d9ea0ee4e 100644 --- a/htdocs/core/class/html.formmail.class.php +++ b/htdocs/core/class/html.formmail.class.php @@ -865,12 +865,12 @@ public function get_form($addfileaction = 'addfile', $removefileaction = 'remove // Complete substitution array with the url to make online payment $paymenturl = ''; - $validpaymentmethod = array(); + // Set the online payment url link into __ONLINE_PAYMENT_URL__ key + require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php'; + $validpaymentmethod = getValidOnlinePaymentMethods(''); if (empty($this->substit['__REF__'])) { $paymenturl = ''; } else { - // Set the online payment url link into __ONLINE_PAYMENT_URL__ key - require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php'; $langs->loadLangs(array('paypal', 'other')); $typeforonlinepayment = 'free'; if ($this->param["models"] == 'order' || $this->param["models"] == 'order_send') { @@ -884,14 +884,15 @@ public function get_form($addfileaction = 'addfile', $removefileaction = 'remove } $url = getOnlinePaymentUrl(0, $typeforonlinepayment, $this->substit['__REF__']); $paymenturl = $url; - - $validpaymentmethod = getValidOnlinePaymentMethods(''); } if (count($validpaymentmethod) > 0 && $paymenturl) { $langs->load('other'); $this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'] = str_replace('\n', "\n", $langs->transnoentities("PredefinedMailContentLink", $paymenturl)); $this->substit['__ONLINE_PAYMENT_URL__'] = $paymenturl; + } elseif (count($validpaymentmethod) > 0) { + $this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'] = '__ONLINE_PAYMENT_TEXT_AND_URL__'; + $this->substit['__ONLINE_PAYMENT_URL__'] = '__ONLINE_PAYMENT_URL__'; } else { $this->substit['__ONLINE_PAYMENT_TEXT_AND_URL__'] = ''; $this->substit['__ONLINE_PAYMENT_URL__'] = ''; diff --git a/htdocs/core/class/utils.class.php b/htdocs/core/class/utils.class.php index 55486efd81329..4077704b45514 100644 --- a/htdocs/core/class/utils.class.php +++ b/htdocs/core/class/utils.class.php @@ -146,7 +146,13 @@ public function purgeFiles($choices = 'tempfilesold+logfiles', $nbsecondsold = 8 $result = dol_delete_dir_recursive($filesarray[$key]['fullname'], $startcount, 1, 0, $tmpcountdeleted); - if (!in_array($filesarray[$key]['fullname'], array($conf->api->dir_temp, $conf->user->dir_temp))) { // The 2 directories $conf->api->dir_temp and $conf->user->dir_temp are recreated at end, so we do not count them + $recreatedDirs = array($conf->user->dir_temp); + + if (isModEnabled('api')) { + $recreatedDirs[] = $conf->api->dir_temp; + } + + if (!in_array($filesarray[$key]['fullname'], $recreatedDirs)) { // The 2 directories $conf->api->dir_temp and $conf->user->dir_temp are recreated at end, so we do not count them $count += $result; $countdeleted += $tmpcountdeleted; } @@ -528,7 +534,7 @@ public function dumpDatabase($compression = 'none', $type = 'auto', $usedefault } elseif ($compression == 'zstd') { fclose($handle); } - if ($ok && preg_match('/^-- (MySql|MariaDB)/i', $errormsg)) { // No error + if ($ok && preg_match('/^-- (MySql|MariaDB)/i', $errormsg) || preg_match('/^\/\*M?!999999/', $errormsg)) { // Start of file is ok, NOT an error $errormsg = ''; } else { // Renommer fichier sortie en fichier erreur diff --git a/htdocs/core/lib/files.lib.php b/htdocs/core/lib/files.lib.php index 5ae46633aad3e..dc0c7b63fbc4e 100644 --- a/htdocs/core/lib/files.lib.php +++ b/htdocs/core/lib/files.lib.php @@ -1165,7 +1165,7 @@ function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disable $publicmediasdirwithslash .= '/'; } - if (strpos($upload_dir, $publicmediasdirwithslash) !== 0) { // We never add .noexe on files into media directory + if (strpos($upload_dir, $publicmediasdirwithslash) !== 0 || !getDolGlobalInt("MAIN_DOCUMENT_DISABLE_NOEXE_IN_MEDIAS_DIR")) { // We never add .noexe on files into media directory $file_name .= '.noexe'; $successcode = 2; } diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index dd1536e1245d3..7fe94ff83c444 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -1658,8 +1658,10 @@ function dol_syslog($message, $level = LOG_INFO, $ident = 0, $suffixinfilename = if (!empty($message)) { // Test log level $logLevels = array(LOG_EMERG=>'EMERG', LOG_ALERT=>'ALERT', LOG_CRIT=>'CRITICAL', LOG_ERR=>'ERR', LOG_WARNING=>'WARN', LOG_NOTICE=>'NOTICE', LOG_INFO=>'INFO', LOG_DEBUG=>'DEBUG'); + if (!array_key_exists($level, $logLevels)) { - throw new Exception('Incorrect log level'); + dol_syslog('Error Bad Log Level '.$level, LOG_ERR); + $level = $logLevels[LOG_ERR]; } if ($level > $conf->global->SYSLOG_LEVEL) { return; diff --git a/htdocs/core/lib/product.lib.php b/htdocs/core/lib/product.lib.php index e919bf2c8b6a7..fe9c18d4b2f07 100644 --- a/htdocs/core/lib/product.lib.php +++ b/htdocs/core/lib/product.lib.php @@ -446,7 +446,7 @@ function show_stats_for_company($product, $socid) print ''; print $product->stats_propale['nb']; print ''; - print $product->stats_propale['qty']; + print price($product->stats_propale['qty'], 1, $langs, 0, 0); print ''; print ''; } @@ -465,7 +465,7 @@ function show_stats_for_company($product, $socid) print ''; print $product->stats_proposal_supplier['nb']; print ''; - print $product->stats_proposal_supplier['qty']; + print price($product->stats_proposal_supplier['qty'], 1, $langs, 0, 0); print ''; print ''; } @@ -484,7 +484,7 @@ function show_stats_for_company($product, $socid) print ''; print $product->stats_commande['nb']; print ''; - print $product->stats_commande['qty']; + print price($product->stats_commande['qty'], 1, $langs, 0, 0); print ''; print ''; } @@ -503,7 +503,7 @@ function show_stats_for_company($product, $socid) print ''; print $product->stats_commande_fournisseur['nb']; print ''; - print $product->stats_commande_fournisseur['qty']; + print price($product->stats_commande_fournisseur['qty'], 1, $langs, 0, 0); print ''; print ''; } @@ -522,7 +522,7 @@ function show_stats_for_company($product, $socid) print ''; print $product->stats_facture['nb']; print ''; - print $product->stats_facture['qty']; + print price($product->stats_facture['qty'], 1, $langs, 0, 0); print ''; print ''; } @@ -560,7 +560,7 @@ function show_stats_for_company($product, $socid) print ''; print $product->stats_facture_fournisseur['nb']; print ''; - print $product->stats_facture_fournisseur['qty']; + print price($product->stats_facture_fournisseur['qty'], 1, $langs, 0, 0); print ''; print ''; } @@ -580,7 +580,7 @@ function show_stats_for_company($product, $socid) print ''; print $product->stats_contrat['nb']; print ''; - print $product->stats_contrat['qty']; + print price($product->stats_contrat['qty'], 1, $langs, 0, 0); print ''; print ''; } diff --git a/htdocs/core/modules/supplier_invoice/mod_facture_fournisseur_tulip.php b/htdocs/core/modules/supplier_invoice/mod_facture_fournisseur_tulip.php index 0aacecc69daa0..e27941537152c 100644 --- a/htdocs/core/modules/supplier_invoice/mod_facture_fournisseur_tulip.php +++ b/htdocs/core/modules/supplier_invoice/mod_facture_fournisseur_tulip.php @@ -176,7 +176,7 @@ public function getNextValue($objsoc, $object, $mode = 'next') } // Supplier invoices take invoice date instead of creation date for the mask - $numFinal = get_next_value($db, $mask, 'facture_fourn', 'ref', '', $objsoc, $object->date); + $numFinal = get_next_value($db, $mask, 'facture_fourn', 'ref', '', $objsoc, is_object($object) ?$object->date :''); return $numFinal; } diff --git a/htdocs/core/tpl/extrafields_list_search_input.tpl.php b/htdocs/core/tpl/extrafields_list_search_input.tpl.php index f57101b81e6ef..3f90715cbea9e 100644 --- a/htdocs/core/tpl/extrafields_list_search_input.tpl.php +++ b/htdocs/core/tpl/extrafields_list_search_input.tpl.php @@ -47,7 +47,7 @@ if (in_array($typeofextrafield, array('link', 'sellist', 'text', 'html'))) { $morecss = 'maxwidth200'; } - echo $extrafields->showInputField($key, (empty($search_array_options[$search_options_pattern.$tmpkey]) ? '' : $search_array_options[$search_options_pattern.$tmpkey]), '', '', $search_options_pattern, $morecss, 0, $extrafieldsobjectkey, 1); + echo $extrafields->showInputField($key, (!isset($search_array_options[$search_options_pattern.$tmpkey]) ? '' : $search_array_options[$search_options_pattern.$tmpkey]), '', '', $search_options_pattern, $morecss, 0, $extrafieldsobjectkey, 1); } print ''; } diff --git a/htdocs/core/tpl/extrafields_list_search_param.tpl.php b/htdocs/core/tpl/extrafields_list_search_param.tpl.php index 7e58e10688292..da123939c6808 100644 --- a/htdocs/core/tpl/extrafields_list_search_param.tpl.php +++ b/htdocs/core/tpl/extrafields_list_search_param.tpl.php @@ -31,8 +31,24 @@ $param .= '&'.$search_options_pattern.$tmpkey.'_endmin='.dol_print_date($val['end'], '%M'); $val = ''; } - if ($val != '') { - $param .= '&'.$search_options_pattern.$tmpkey.'='.urlencode($val); + if ($val !== '') { + if (is_array($val)) { + foreach ($val as $val2) { + $param .= '&'.$search_options_pattern.$tmpkey.'[]='.urlencode($val2); + } + } else { + // test if we have checkbox type, we add the _multiselect needed into param + $tmpkey = preg_replace('/'.$search_options_pattern.'/', '', $key); + if (in_array($extrafields->attributes[$extrafieldsobjectkey]['type'][$tmpkey], array('checkbox', 'chkbxlst'))) { + $param .= '&'.$search_options_pattern.$tmpkey.'_multiselect='.urlencode($val); + } + // test if we have boolean type, we add the _booleand needed into param + if (in_array($extrafields->attributes[$extrafieldsobjectkey]['type'][$tmpkey], array('boolean'))) { + $param .= '&'.$search_options_pattern.$tmpkey.'_boolean='.urlencode($val); + } + + $param .= '&'.$search_options_pattern.$tmpkey.'='.urlencode($val); + } } } } diff --git a/htdocs/cron/class/cronjob.class.php b/htdocs/cron/class/cronjob.class.php index b89d7ea3cb7e3..569364a4dfd6e 100644 --- a/htdocs/cron/class/cronjob.class.php +++ b/htdocs/cron/class/cronjob.class.php @@ -1275,7 +1275,7 @@ public function run_jobs($userlogin) $error++; } else { dol_syslog(get_class($this)."::run_jobs END"); - $this->lastoutput = dol_substr((empty($object->output) ? "" : $object->output."\n").$errmsg, 0, $this::MAXIMUM_LENGTH_FOR_LASTOUTPUT_FIELD, 'UTF-8', 1); + $this->lastoutput = dol_substr((empty($object->output) ? "" : $object->output."\n"), 0, $this::MAXIMUM_LENGTH_FOR_LASTOUTPUT_FIELD, 'UTF-8', 1); $this->lastresult = var_export($result, true); $retval = $this->lastresult; } diff --git a/htdocs/expensereport/card.php b/htdocs/expensereport/card.php index 77e79c8d3a6bd..16a138e213872 100644 --- a/htdocs/expensereport/card.php +++ b/htdocs/expensereport/card.php @@ -541,8 +541,7 @@ // CONTENT $link = $urlwithroot.'/expensereport/card.php?id='.$object->id; $link = ''.$link.''; - $dateRefusEx = explode(" ", $object->date_refuse); - $message = $langs->transnoentities("ExpenseReportWaitingForReApprovalMessage", $dateRefusEx[0], $object->detail_refuse, $expediteur->getFullName($langs), $link); + $message = $langs->transnoentities("ExpenseReportWaitingForReApprovalMessage", dol_print_date($object->date_refuse, 'day'), $object->detail_refuse, $expediteur->getFullName($langs), get_date_range($object->date_debut, $object->date_fin, '', $langs), $link); // Rebuild pdf /* @@ -2211,7 +2210,11 @@ } } - if (!$thumbshown) { + if (!$thumbshown && $fileinfo['extension'] == 'pdf' && !empty($filepdf) && !empty($relativepath) && !empty($fileinfo['filename'])) { + $formFile = new FormFile($db); + $imgpreview = $formFile->showPreview([], $modulepart, $relativepath.'/'.$fileinfo['filename'].'.'.strtolower($fileinfo['extension']), 0); + print $imgpreview; + } elseif (!$thumbshown) { print img_mime($ecmfilesstatic->filename); } } @@ -2859,7 +2862,7 @@ } // Presend form -$modelmail = 'expensereport'; +$modelmail = 'expensereport_send'; $defaulttopic = 'SendExpenseReportRef'; $diroutput = $conf->expensereport->dir_output; $trackid = 'exp'.$object->id; diff --git a/htdocs/fourn/class/fournisseur.commande.class.php b/htdocs/fourn/class/fournisseur.commande.class.php index ecd8bb390f2b3..f535ac013a182 100644 --- a/htdocs/fourn/class/fournisseur.commande.class.php +++ b/htdocs/fourn/class/fournisseur.commande.class.php @@ -1372,6 +1372,8 @@ public function create($user, $notrigger = 0) // We set order into draft status $this->brouillon = 1; + $this->statut = self::STATUS_DRAFT; // deprecated + $this->status = self::STATUS_DRAFT; $sql = "INSERT INTO ".MAIN_DB_PREFIX."commande_fournisseur ("; $sql .= "ref"; @@ -2945,7 +2947,7 @@ public function initAsSpecimen() $sql .= $this->db->order("rowid", "ASC"); $sql .= $this->db->plimit(1); $resql = $this->db->query($sql); - if ($resql) { + if ($resql && $this->db->num_rows($resql)) { $obj = $this->db->fetch_object($resql); $prodid = $obj->rowid; } diff --git a/htdocs/fourn/commande/list.php b/htdocs/fourn/commande/list.php index 9144a61a982cf..7bff6c12eb819 100644 --- a/htdocs/fourn/commande/list.php +++ b/htdocs/fourn/commande/list.php @@ -856,10 +856,10 @@ $sql .= " AND cf.date_livraison <= '".$db->idate($search_date_delivery_end)."'"; } if ($search_date_valid_start) { - $sql .= " AND cf.date_commande >= '".$db->idate($search_date_valid_start)."'"; + $sql .= " AND cf.date_valid >= '".$db->idate($search_date_valid_start)."'"; } if ($search_date_valid_end) { - $sql .= " AND cf.date_commande <= '".$db->idate($search_date_valid_end)."'"; + $sql .= " AND cf.date_valid <= '".$db->idate($search_date_valid_end)."'"; } if ($search_date_approve_start) { $sql .= " AND cf.date_livraison >= '".$db->idate($search_date_approve_start)."'"; diff --git a/htdocs/fourn/facture/card-rec.php b/htdocs/fourn/facture/card-rec.php index 38f0ca15f7f70..7d6e4c1b7727d 100644 --- a/htdocs/fourn/facture/card-rec.php +++ b/htdocs/fourn/facture/card-rec.php @@ -535,8 +535,8 @@ $label = ((GETPOST('product_label') && GETPOST('product_label') != $prod->label) ? GETPOST('product_label') : ''); // Update if prices fields are defined - $tva_tx = get_default_tva($mysoc, $object->thirdparty, $prod->id); - $tva_npr = get_default_npr($mysoc, $object->thirdparty, $prod->id); + $tva_tx = get_default_tva($object->thirdparty, $mysoc, $prod->id); + $tva_npr = get_default_npr($object->thirdparty, $mysoc, $prod->id); if (empty($tva_tx)) { $tva_npr = 0; } @@ -544,7 +544,7 @@ // Search the correct price into loaded array product_price_by_qty using id of array retrieved into POST['pqp']. $pqp = (GETPOST('pbq', 'int') ? GETPOST('pbq', 'int') : 0); - $datapriceofproduct = $prod->getSellPrice($mysoc, $object->thirdparty, $pqp); + $datapriceofproduct = $prod->getSellPrice($object->thirdparty, $mysoc, $pqp); $pu_ht = $datapriceofproduct['pu_ht']; $pu_ttc = $datapriceofproduct['pu_ttc']; @@ -659,8 +659,8 @@ $buyingprice = price2num(GETPOST('buying_price' . $predef) != '' ? GETPOST('buying_price' . $predef) : ''); // If buying_price is '0', we must keep this value // Local Taxes - $localtax1_tx = get_localtax($tva_tx, 1, $object->thirdparty, $mysoc, $tva_npr); - $localtax2_tx = get_localtax($tva_tx, 2, $object->thirdparty, $mysoc, $tva_npr); + $localtax1_tx = get_localtax($tva_tx, 1, $mysoc, $object->thirdparty, $tva_npr); + $localtax2_tx = get_localtax($tva_tx, 2, $mysoc, $object->thirdparty, $tva_npr); $info_bits = 0; if ($tva_npr) { $info_bits |= 0x01; @@ -1080,7 +1080,7 @@ $disableedit = 1; $disablemove = 1; $disableremove = 1; - $object->printObjectLines('', $mysoc, $object->thirdparty, $lineid, 0); // No date selector for template invoice + $object->printObjectLines('', $object->thirdparty, $mysoc, $lineid, 0); // No date selector for template invoice } print "\n"; @@ -1569,7 +1569,7 @@ $canchangeproduct = 0; $object->statut = $object->suspended; - $object->printObjectLines($action, $mysoc, $object->thirdparty, $lineid, 0); // No date selector for template invoice + $object->printObjectLines($action, $object->thirdparty, $mysoc, $lineid, 0); // No date selector for template invoice } // Form to add new line diff --git a/htdocs/holiday/class/holiday.class.php b/htdocs/holiday/class/holiday.class.php index 28dc2e2253dd0..a729dde5b753e 100644 --- a/htdocs/holiday/class/holiday.class.php +++ b/htdocs/holiday/class/holiday.class.php @@ -1061,6 +1061,13 @@ public function update($user = null, $notrigger = 0) $error++; $this->errors[] = "Error ".$this->db->lasterror(); } + if (!$error) { + $result = $this->insertExtraFields(); + if ($result < 0) { + $error++; + } + } + if (!$error) { if (!$notrigger) { // Call trigger diff --git a/htdocs/includes/odtphp/Segment.php b/htdocs/includes/odtphp/Segment.php index b57983321a39d..36e3879e8857e 100644 --- a/htdocs/includes/odtphp/Segment.php +++ b/htdocs/includes/odtphp/Segment.php @@ -114,13 +114,13 @@ public function merge() // Remove the IF tag $this->xml = str_replace('[!-- IF '.$key.' --]', '', $this->xml); // Remove everything between the ELSE tag (if it exists) and the ENDIF tag - $reg = '@(\[!--\sELSE\s' . $key . '\s--\](.*))?\[!--\sENDIF\s' . $key . '\s--\]@smU'; // U modifier = all quantifiers are non-greedy + $reg = '@(\[!--\sELSE\s' . preg_quote($key, '@') . '\s--\](.*))?\[!--\sENDIF\s' . preg_quote($key, '@') . '\s--\]@smU'; // U modifier = all quantifiers are non-greedy $this->xml = preg_replace($reg, '', $this->xml); } // Else the value is false, then two cases: no ELSE and we're done, or there is at least one place where there is an ELSE clause, then we replace it else { // Find all conditional blocks for this variable: from IF to ELSE and to ENDIF - $reg = '@\[!--\sIF\s' . $key . '\s--\](.*)(\[!--\sELSE\s' . $key . '\s--\](.*))?\[!--\sENDIF\s' . $key . '\s--\]@smU'; // U modifier = all quantifiers are non-greedy + $reg = '@\[!--\sIF\s' . preg_quote($key, '@') . '\s--\](.*)(\[!--\sELSE\s' . preg_quote($key, '@') . '\s--\](.*))?\[!--\sENDIF\s' . preg_quote($key, '@') . '\s--\]@smU'; // U modifier = all quantifiers are non-greedy preg_match_all($reg, $this->xml, $matches, PREG_SET_ORDER); foreach ($matches as $match) { // For each match, if there is an ELSE clause, we replace the whole block by the value in the ELSE clause if (!empty($match[3])) $this->xml = str_replace($match[0], $match[3], $this->xml); diff --git a/htdocs/includes/odtphp/odf.php b/htdocs/includes/odtphp/odf.php index 445bdf46a5ac5..f4d162c513a54 100644 --- a/htdocs/includes/odtphp/odf.php +++ b/htdocs/includes/odtphp/odf.php @@ -550,8 +550,8 @@ private function _moveRowSegments() private function _parse($type = 'content') { // Search all tags found into condition to complete $this->vars, so we will proceed all tests even if not defined - $reg='@\[!--\sIF\s([{}a-zA-Z0-9\.\,_]+)\s--\]@smU'; - $matches = array(); + $reg='@\[!--\sIF\s([\[\]{}a-zA-Z0-9\.\,_]+)\s--\]@smU'; + $matches = array(); preg_match_all($reg, $this->contentXml, $matches, PREG_SET_ORDER); //var_dump($this->vars);exit; @@ -572,7 +572,7 @@ private function _parse($type = 'content') // Remove the IF tag $this->contentXml = str_replace('[!-- IF '.$key.' --]', '', $this->contentXml); // Remove everything between the ELSE tag (if it exists) and the ENDIF tag - $reg = '@(\[!--\sELSE\s' . $key . '\s--\](.*))?\[!--\sENDIF\s' . $key . '\s--\]@smU'; // U modifier = all quantifiers are non-greedy + $reg = '@(\[!--\sELSE\s' . preg_quote($key, '@') . '\s--\](.*))?\[!--\sENDIF\s' . preg_quote($key, '@') . '\s--\]@smU'; // U modifier = all quantifiers are non-greedy $this->contentXml = preg_replace($reg, '', $this->contentXml); /*if ($sav != $this->contentXml) { @@ -585,7 +585,7 @@ private function _parse($type = 'content') //dol_syslog("Var ".$key." is not defined, we remove the IF, ELSE and ENDIF "); //$sav=$this->contentXml; // Find all conditional blocks for this variable: from IF to ELSE and to ENDIF - $reg = '@\[!--\sIF\s' . $key . '\s--\](.*)(\[!--\sELSE\s' . $key . '\s--\](.*))?\[!--\sENDIF\s' . $key . '\s--\]@smU'; // U modifier = all quantifiers are non-greedy + $reg = '@\[!--\sIF\s' . preg_quote($key, '@') . '\s--\](.*)(\[!--\sELSE\s' . preg_quote($key, '@') . '\s--\](.*))?\[!--\sENDIF\s' . preg_quote($key, '@') . '\s--\]@smU'; // U modifier = all quantifiers are non-greedy preg_match_all($reg, $this->contentXml, $matches, PREG_SET_ORDER); foreach ($matches as $match) { // For each match, if there is an ELSE clause, we replace the whole block by the value in the ELSE clause if (!empty($match[3])) $this->contentXml = str_replace($match[0], $match[3], $this->contentXml); diff --git a/htdocs/main.inc.php b/htdocs/main.inc.php index b57ee0a59c64d..e6ba240135bbe 100644 --- a/htdocs/main.inc.php +++ b/htdocs/main.inc.php @@ -1673,6 +1673,7 @@ function top_htmlhead($head, $title = '', $disablejs = 0, $disablehead = 0, $arr } // Refresh value of MAIN_IHM_PARAMS_REV before forging the parameter line. if (GETPOST('dol_resetcache')) { + include_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php'; dolibarr_set_const($db, "MAIN_IHM_PARAMS_REV", getDolGlobalInt('MAIN_IHM_PARAMS_REV') + 1, 'chaine', 0, '', $conf->entity); } diff --git a/htdocs/product/inventory/inventory.php b/htdocs/product/inventory/inventory.php index 4b2ea3e93c0f3..e9ddf7ad87747 100644 --- a/htdocs/product/inventory/inventory.php +++ b/htdocs/product/inventory/inventory.php @@ -97,11 +97,10 @@ //$result = restrictedArea($user, 'mymodule', $id); //Parameters Page -$param = '&id='.$object->id; +$paramwithsearch = ''; if ($limit > 0 && $limit != $conf->liste_limit) { - $param .= '&limit='.urlencode($limit); + $paramwithsearch .= '&limit='.((int) $limit); } -$paramwithsearch = $param; if (empty($conf->global->MAIN_USE_ADVANCED_PERMS)) { @@ -265,6 +264,7 @@ $sql .= ' id.fk_product, id.batch, id.qty_stock, id.qty_view, id.qty_regulated'; $sql .= ' FROM '.MAIN_DB_PREFIX.'inventorydet as id'; $sql .= ' WHERE id.fk_inventory = '.((int) $object->id); + $sql .= $db->order('id.rowid', 'ASC'); $sql .= $db->plimit($limit, $offset); $db->begin(); @@ -297,7 +297,7 @@ $inventoryline->pmp_expected = price2num(GETPOST('expectedpmp_'.$lineid, 'alpha'), 'MS'); $resultupdate = $inventoryline->update($user); } - } else { + } elseif (GETPOSTISSET('id_' . $lineid)) { // Delete record $result = $inventoryline->fetch($lineid); if ($result > 0) { @@ -415,7 +415,6 @@ - /* * View */ @@ -459,7 +458,7 @@ // Confirmation to close if ($action == 'record') { - $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('Close'), $langs->trans('ConfirmFinish'), 'update', '', 0, 1); + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id.'&page='.$page.$paramwithsearch, $langs->trans('Close'), $langs->trans('ConfirmFinish'), 'update', '', 0, 1); $action = 'view'; } @@ -494,7 +493,7 @@ // Thirdparty $morehtmlref.='
'.$langs->trans('ThirdParty') . ' : ' . $soc->getNomUrl(1); // Project -if (!empty($conf->project->enabled)) +if (isModEnabled('project')) { $langs->load("projects"); $morehtmlref.='
'.$langs->trans('Project') . ' '; @@ -583,13 +582,13 @@ // Save if ($object->status == $object::STATUS_VALIDATED) { if ($permissiontoadd) { - print ''.$langs->trans("MakeMovementsAndClose").''."\n"; + print ''.$langs->trans("MakeMovementsAndClose").''."\n"; } else { print ''.$langs->trans('MakeMovementsAndClose').''."\n"; } if ($permissiontoadd) { - print ''.$langs->trans("Cancel").''."\n"; + print ''.$langs->trans("Cancel").''."\n"; } } } @@ -990,7 +989,7 @@ function barcodeserialforproduct(tabproduct,index,element,barcodeproductqty,sele $num = $db->num_rows($resql); if (!empty($limit != 0) || $num > $limit || $page) { - print_fleche_navigation($page, $_SERVER["PHP_SELF"], $paramwithsearch, ($num >= $limit), '', '', $limit); + print_fleche_navigation($page, $_SERVER["PHP_SELF"], '&id='.$object->id.$paramwithsearch, ($num >= $limit), '', '', $limit); } $i = 0; @@ -1046,8 +1045,9 @@ function barcodeserialforproduct(tabproduct,index,element,barcodeproductqty,sele // Expected quantity = Quantity in stock when we start inventory print ''; $valuetoshow = $obj->qty_stock; + // For inventory not yet close, we overwrite with the real value in stock now - if ($object->status == $object::STATUS_DRAFT || $object->status == $object::STATUS_VALIDATED) { + if (($object->status == $object::STATUS_DRAFT || $object->status == $object::STATUS_VALIDATED) && !getDolGlobalString('DISABLE_QTY_OVERWRITE')) { if (isModEnabled('productbatch') && $product_static->hasbatch()) { $valuetoshow = $product_static->stock_warehouse[$obj->fk_warehouse]->detail_batch[$obj->batch]->qty; } else { @@ -1089,10 +1089,11 @@ function barcodeserialforproduct(tabproduct,index,element,barcodeproductqty,sele //PMP Real print ''; - - - if (!empty($obj->pmp_real)) $pmp_real = $obj->pmp_real; - else $pmp_real = $product_static->pmp; + if (!empty($obj->pmp_real) || (string) $obj->pmp_real === '0') { + $pmp_real = $obj->pmp_real; + } else { + $pmp_real = $product_static->pmp; + } $pmp_valuation_real = $pmp_real * $qty_view; print ''; print ''; @@ -1206,38 +1207,38 @@ function barcodeserialforproduct(tabproduct,index,element,barcodeproductqty,sele $(".paginationnext:last").click(function(e){ var form = $("#formrecord"); - var actionURL = "'.$_SERVER['PHP_SELF']."?page=".($page).$paramwithsearch.'"; + var actionURL = "'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&page='.($page).$paramwithsearch.'"; $.ajax({ url: actionURL, data: form.serialize(), cache: false, success: function(result){ - window.location.href = "'.$_SERVER['PHP_SELF']."?page=".($page + 1).$paramwithsearch.'"; + window.location.href = "'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&page='.($page + 1).$paramwithsearch.'"; }}); }); $(".paginationprevious:last").click(function(e){ var form = $("#formrecord"); - var actionURL = "'.$_SERVER['PHP_SELF']."?page=".($page).$paramwithsearch.'"; + var actionURL = "'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&page='.($page).$paramwithsearch.'"; $.ajax({ url: actionURL, data: form.serialize(), cache: false, success: function(result){ - window.location.href = "'.$_SERVER['PHP_SELF']."?page=".($page - 1).$paramwithsearch.'"; + window.location.href = "'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&page='.($page - 1).$paramwithsearch.'"; }}); }); $("#idbuttonmakemovementandclose").click(function(e){ var form = $("#formrecord"); - var actionURL = "'.$_SERVER['PHP_SELF']."?page=".($page).$paramwithsearch.'"; + var actionURL = "'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&page='.($page).$paramwithsearch.'"; $.ajax({ url: actionURL, data: form.serialize(), cache: false, success: function(result){ - window.location.href = "'.$_SERVER['PHP_SELF']."?page=".($page - 1).$paramwithsearch.'&action=record"; + window.location.href = "'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&page='.($page - 1).$paramwithsearch.'&action=record"; }}); }); }); @@ -1307,6 +1308,7 @@ function updateTotalValuation() { })); } + updatePrice(0, $object->price_base_type, $user, $object->tva_tx, 0, $level, $object->tva_npr, 1); + $basePrice = ($object->price_base_type == 'HT') ? $object->price : $object->price_ttc; + $basePriceMin = ($object->price_base_type == 'HT') ? $object->price_min : $object->price_min_ttc; + $ret = $object->updatePrice($basePrice, $object->price_base_type, $user, $object->tva_tx, $basePriceMin, $level, $object->tva_npr, 1); if ($ret < 0) { setEventMessages($object->error, $object->errors, 'errors'); @@ -517,7 +519,9 @@ if ($action == 'disable_price_by_qty') { // Disabling product price by quantity add a new price line with price_by_qty set to 0 $level = GETPOST('level', 'int'); - $ret = $object->updatePrice(0, $object->price_base_type, $user, $object->tva_tx, 0, $level, $object->tva_npr, 0); + $basePrice = ($object->price_base_type == 'HT') ? $object->price : $object->price_ttc; + $basePriceMin = ($object->price_base_type == 'HT') ? $object->price_min : $object->price_min_ttc; + $ret = $object->updatePrice($basePrice, $object->price_base_type, $user, $object->tva_tx, $basePriceMin, $level, $object->tva_npr, 0); if ($ret < 0) { setEventMessages($object->error, $object->errors, 'errors'); diff --git a/htdocs/product/stock/replenish.php b/htdocs/product/stock/replenish.php index 4135c31e80a67..1ddf5f92f7615 100644 --- a/htdocs/product/stock/replenish.php +++ b/htdocs/product/stock/replenish.php @@ -196,9 +196,19 @@ } $line->tva_tx = $productsupplier->vatrate_supplier; + $tva = $line->tva_tx / 100; + + // If we use multicurrency + if (isModEnabled('multicurrency') && !empty($productsupplier->fourn_multicurrency_code) && $productsupplier->fourn_multicurrency_code != $conf->currency) { + $line->multicurrency_code = $productsupplier->fourn_multicurrency_code; + $line->fk_multicurrency = $productsupplier->fourn_multicurrency_id; + $line->multicurrency_subprice = $productsupplier->fourn_multicurrency_unitprice; + $line->multicurrency_total_ht = $line->multicurrency_subprice * $qty; + $line->multicurrency_total_tva = $line->multicurrency_total_ht * $tva; + $line->multicurrency_total_ttc = $line->multicurrency_total_ht + $line->multicurrency_total_tva; + } $line->subprice = $productsupplier->fourn_pu; $line->total_ht = $productsupplier->fourn_pu * $qty; - $tva = $line->tva_tx / 100; $line->total_tva = $line->total_ht * $tva; $line->total_ttc = $line->total_ht + $line->total_tva; $line->remise_percent = $productsupplier->remise_percent; @@ -263,7 +273,8 @@ null, null, 0, - $line->fk_unit + $line->fk_unit, + $line->multicurrency_subprice ?? 0 ); } if ($result < 0) { @@ -274,9 +285,11 @@ } else { $id = $result; } + $i++; } else { $order->socid = $suppliersid[$i]; $order->fetch_thirdparty(); + $order->multicurrency_code = $order->thirdparty->multicurrency_code; // Trick to know which orders have been generated using the replenishment feature $order->source = $order::SOURCE_ID_REPLENISHMENT; diff --git a/htdocs/projet/element.php b/htdocs/projet/element.php index 01eb346cadbeb..06cfbfb1a3858 100644 --- a/htdocs/projet/element.php +++ b/htdocs/projet/element.php @@ -1245,8 +1245,8 @@ $filedir = $conf->fournisseur->commande->multidir_output[$element->entity].'/'.dol_sanitizeFileName($element->ref); } elseif ($element_doc === 'invoice_supplier') { $element_doc = 'facture_fournisseur'; - $filename = get_exdir($element->id, 2, 0, 0, $element, 'product').dol_sanitizeFileName($element->ref); - $filedir = $conf->fournisseur->facture->multidir_output[$element->entity].'/'.get_exdir($element->id, 2, 0, 0, $element, 'invoice_supplier').dol_sanitizeFileName($element->ref); + $filename = get_exdir($element->id, 2, 0, 0, $element, 'invoice_supplier').dol_sanitizeFileName($element->ref); + $filedir = $conf->fournisseur->facture->multidir_output[$element->entity].'/'.$filename; } print '
'.$formfile->getDocumentsLink($element_doc, $filename, $filedir).'
'; diff --git a/htdocs/projet/tasks/time.php b/htdocs/projet/tasks/time.php index c35cd9e83cb24..87764277b6586 100644 --- a/htdocs/projet/tasks/time.php +++ b/htdocs/projet/tasks/time.php @@ -658,7 +658,7 @@ // Update lineid into line of timespent $sql = 'UPDATE '.MAIN_DB_PREFIX.'projet_task_time SET invoice_line_id = '.((int) $lineid).', invoice_id = '.((int) $tmpinvoice->id); - $sql .= ' WHERE rowid IN ('.$db->sanitize(join(',', $toselect)).') AND fk_user = '.((int) $userid); + $sql .= ' WHERE rowid = '.((int) $timespent_id).' AND fk_user = '.((int) $userid); $result = $db->query($sql); if (!$result) { $error++; diff --git a/htdocs/takepos/invoice.php b/htdocs/takepos/invoice.php index 64688ef537a89..5257e2ab7a2d8 100644 --- a/htdocs/takepos/invoice.php +++ b/htdocs/takepos/invoice.php @@ -473,7 +473,10 @@ function fail($message) // If we add a line and no invoice yet, we create the invoice if (($action == "addline" || $action == "freezone") && $placeid == 0) { $invoice->socid = getDolGlobalString($constforcompanyid); - $invoice->date = dol_now('tzuserrel'); // We use the local date, only the day will be saved. + + include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; + $invoice->date = dol_get_first_hour(dol_now('tzuserrel')); // Invoice::create() needs a date with no hours + $invoice->module_source = 'takepos'; $invoice->pos_source = isset($_SESSION["takeposterminal"]) ? $_SESSION["takeposterminal"] : '' ; $invoice->entity = !empty($_SESSION["takeposinvoiceentity"]) ? $_SESSION["takeposinvoiceentity"] : $conf->entity;