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

This commit is contained in:
Laurent Destailleur 2026-05-04 18:21:25 +02:00
commit eeb7e8cb5d
60 changed files with 357 additions and 166 deletions

View file

@ -2,6 +2,12 @@
English Dolibarr ChangeLog
--------------------------------------------------------------
***** ChangeLog for 23.0.3 compared to 23.0.2 *****
FIX: IDOR on messaging.php - credit Aksoum Abderrahmane
FIX: Some remaining cross-customer object creation on API (proposal, orders) - credit Mitch311
SEC: Better sanitization param for GETPOST of htmlheader of website page - See commit bbbbb56c6455514dcd0acca53afc17a92ed21bb9
***** ChangeLog for 23.0.2 compared to 23.0.1 *****

View file

@ -662,6 +662,8 @@ if ($nboftargetok) {
run("rm -fr $BUILDROOT/$PROJECT/htdocs/install/mssql");
run("rm -fr $BUILDROOT/$PROJECT/htdocs/install/sqlite3");
run("rm -fr $BUILDROOT/$PROJECT/htdocs/install/install.forced.php");
run("rm -fr $BUILDROOT/$PROJECT/node_modules");
run("rm -fr $BUILDROOT/$PROJECT/dev/ansible");

View file

@ -722,6 +722,8 @@ if ($nboftargetok) {
$ret = `rm -fr $BUILDROOT/$PROJECT/htdocs/install/mssql`;
$ret = `rm -fr $BUILDROOT/$PROJECT/htdocs/install/sqlite3`;
$ret = `rm -fr $BUILDROOT/$PROJECT/htdocs/install/install.forced.php`;
$ret = `rm -fr $BUILDROOT/$PROJECT/node_modules`;
$ret = `rm -fr $BUILDROOT/$PROJECT/dev/ansible`;

View file

@ -366,7 +366,7 @@ if ($action == 'writebookkeeping' && !$error && $user->hasRight('accounting', 'b
$account_label = $accountingaccount->label;
// get compte id and label
if ($accountingaccount->fetch(0, $k, true)) {
if ($accountingaccount->id > 0) {
$bookkeeping = new BookKeeping($db);
$bookkeeping->doc_date = $val["date"];
$bookkeeping->doc_ref = $val["ref"];

View file

@ -107,6 +107,9 @@ if ($action == 'update') {
} else {
$res = dolibarr_set_const($db, "MEMBER_NEWFORM_FORCEMORPHY", $forcemorphy, 'chaine', 0, '', $conf->entity);
}
if (GETPOSTISSET('MEMBER_SEARCH_MEMBER_PUBLIC_FORM_CREATE')) {
$res = dolibarr_set_const($db, "MEMBER_SEARCH_MEMBER_PUBLIC_FORM_CREATE", GETPOST('MEMBER_SEARCH_MEMBER_PUBLIC_FORM_CREATE') == 'yes' ? 1 : 0, 'chaine', 0, '', $conf->entity);
}
if (!($res > 0)) {
$error++;
@ -318,9 +321,9 @@ if (getDolGlobalString('MEMBER_ENABLE_PUBLIC')) {
// Search a member after member creation form
print '<tr class="oddeven" id="trpayment"><td>';
print $langs->trans("MEMBER_SEARCH_MEMBER_PUBLIC_FORM_CREATE");
print $form->textwithpicto($langs->trans("MEMBER_SEARCH_MEMBER_PUBLIC_FORM_CREATE"), $langs->trans("MEMBER_SEARCH_MEMBER_PUBLIC_FORM_CREATEDesc"));
print '</td><td>';
print $form->selectyesno("MEMBER_SEARCH_MEMBER_PUBLIC_FORM_CREATE"); // Reverse the logic "hide -> show" for retrocompatibility
print $form->selectyesno("MEMBER_SEARCH_MEMBER_PUBLIC_FORM_CREATE", getDolGlobalInt("MEMBER_SEARCH_MEMBER_PUBLIC_FORM_CREATE")); // Reverse the logic "hide -> show" for retrocompatibility
print "</td></tr>\n";
print '</table>';

View file

@ -107,7 +107,8 @@ $item->fieldAttr = array(
'type' => 'number',
'step' => '0.01',
'min' => 0,
'max' => 100
'max' => 100,
'class' => 'width75 right',
);
@ -133,6 +134,8 @@ include DOL_DOCUMENT_ROOT.'/core/actions_setmoduleoptions.inc.php';
* View
*/
$action = 'edit';
$dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
$help_url = 'EN:Invoice_Configuration|FR:Configuration_module_facture|ES:ConfiguracionFactura';
@ -150,27 +153,7 @@ print dol_get_fiche_head($head, 'situation', $langs->trans("InvoiceSituation"),
print '<span class="opacitymedium">'.$langs->trans("InvoiceFirstSituationDesc").'</span><br><br>';
/*
* Numbering module
*/
if ($action == 'edit') {
print $formSetup->generateOutput(true);
} else {
print $formSetup->generateOutput();
}
if (count($formSetup->items) > 0) {
if ($action != 'edit') {
print '<div class="tabsAction">';
print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?action=edit&token='.newToken().'">'.$langs->trans("Modify").'</a>';
print '</div>';
}
} else {
print '<br>'.$langs->trans("NothingToSetup");
}
print $formSetup->generateOutput(true);
print dol_get_fiche_end();

View file

@ -280,12 +280,14 @@ print '<td width="80">&nbsp;</td>';
print "</tr>\n";
// Allow payments on different thirdparties bills but same parent company
/*
print '<tr class="oddeven"><td>';
print $langs->trans("PaymentOnDifferentThirdBills");
print '</td><td width="60" align="center">';
print $form->selectyesno("FACTURE_PAYMENTS_ON_DIFFERENT_THIRDPARTIES_BILLS", getDolGlobalInt('FACTURE_PAYMENTS_ON_DIFFERENT_THIRDPARTIES_BILLS'), 1);
print '</td><td class="right">';
print "</td></tr>\n";
*/
// Allow to group payments by mod in rapports
print '<tr class="oddeven"><td>';

View file

@ -168,6 +168,8 @@ if (preg_match('/set_([a-z0-9_\-]+)/i', $action, $reg)) {
$securitycspstring = "";
if (isset($sourcetype) && $sourcetype == "data") {
$forceCSPArr[$directivecsp][] = "data:".$sourcedatacsp;
} elseif (isset($sourcetype) && $sourcetype == "blob") {
$forceCSPArr[$directivecsp][] = "blob:".$sourcedatacsp;
} elseif (isset($sourcetype) && $sourcetype == "input") {
if (empty($forceCSPArr[$directivecsp])) {
$forceCSPArr[$directivecsp] = array();

View file

@ -252,7 +252,11 @@ class Ai
}
}
$localurl = 2; // Accept both local and external endpoints
// By default, we accept only external endpoints ($dolibarr_ai_allow_local_endpoints is not set).
// To allow local endpoints, we must set $dolibarr_ai_allow_local_endpoints to 1 or 2 in conf.php.
global $dolibarr_ai_allow_local_endpoints;
$localurl = $dolibarr_ai_allow_local_endpoints ?? 0;
$response = getURLContent($this->apiEndpoint, 'POST', $payload, 1, $headers, array('http', 'https'), $localurl);
if (empty($response['http_code'])) {

View file

@ -748,7 +748,7 @@ class Asset extends CommonObject
}
$sql = "SELECT ad.rowid, ad.depreciation_mode, ad.ref, ad.depreciation_date, ad.depreciation_ht, ad.cumulative_depreciation_ht,";
$sql .= " " . $this->db->ifsql('EXISTS (SELECT fk_docdet FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping as ab WHERE ab.doc_type = \'asset\' AND ab.fk_docdet = ad.rowid)', '1', '0') . " AS bookkeeping";
$sql .= " " . $this->db->ifsql('EXISTS (SELECT fk_docdet FROM ' . MAIN_DB_PREFIX . 'accounting_bookkeeping as ab WHERE ab.doc_type = \'asset\' AND ab.fk_docdet = ad.rowid)', '1', '0') . " AS bookkeeping";
$sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation AS ad";
$sql .= " WHERE ad.fk_asset = " . (int) $this->id;
$sql .= " ORDER BY ad.depreciation_date ASC";

View file

@ -1450,7 +1450,6 @@ if ($action == 'create') { // aaa
// Ref customer
$morehtmlref .= $form->editfieldkey("", 'title', $object->title, $object, $user->hasRight('mailing', 'creer'), 'string', '', 0, 1);
$morehtmlref .= $form->editfieldval("", 'title', $object->title, $object, $user->hasRight('mailing', 'creer'), 'string', '', null, null, '', 1);
$morehtmlref .= '</div>';
$morehtmlstatus = '';
$nbtry = $nbok = 0;
@ -1484,6 +1483,7 @@ if ($action == 'create') { // aaa
}
}
}
$morehtmlref .= '</div>';
dol_banner_tab($object, 'id', $linkback, 1, 'rowid', 'ref', $morehtmlref, '', 0, '', $morehtmlstatus);
@ -1548,19 +1548,24 @@ if ($action == 'create') { // aaa
print '<tr><td>';
print $langs->trans("MAIN_MAIL_SENDMODE");
print '</td><td>';
if (getDolGlobalString('MAIN_MAIL_SENDMODE_EMAILING') && getDolGlobalString('MAIN_MAIL_SENDMODE_EMAILING') != 'default') {
$text = $listofmethods[getDolGlobalString('MAIN_MAIL_SENDMODE_EMAILING')];
} elseif (getDolGlobalString('MAIN_MAIL_SENDMODE')) {
$text = $listofmethods[getDolGlobalString('MAIN_MAIL_SENDMODE')];
} else {
$text = $listofmethods['mail'];
}
print $text;
if (getDolGlobalString('MAIN_MAIL_SENDMODE_EMAILING') != 'default') {
if (getDolGlobalString('MAIN_MAIL_SENDMODE_EMAILING') != 'mail') {
print ' <span class="opacitymedium">('.getDolGlobalString('MAIN_MAIL_SMTP_SERVER_EMAILING').')</span>';
if ($object->messtype != 'sms') {
if (getDolGlobalString('MAIN_MAIL_SENDMODE_EMAILING') && getDolGlobalString('MAIN_MAIL_SENDMODE_EMAILING') != 'default') {
$text = $listofmethods[getDolGlobalString('MAIN_MAIL_SENDMODE_EMAILING')];
} elseif (getDolGlobalString('MAIN_MAIL_SENDMODE')) {
$text = $listofmethods[getDolGlobalString('MAIN_MAIL_SENDMODE')];
} else {
$text = $listofmethods['mail'];
}
} elseif (getDolGlobalString('MAIN_MAIL_SENDMODE') != 'mail' && getDolGlobalString('MAIN_MAIL_SMTP_SERVER')) {
print $text;
if (getDolGlobalString('MAIN_MAIL_SENDMODE_EMAILING') != 'default') {
if (getDolGlobalString('MAIN_MAIL_SENDMODE_EMAILING') != 'mail') {
print ' <span class="opacitymedium">('.getDolGlobalString('MAIN_MAIL_SMTP_SERVER_EMAILING', getDolGlobalString('MAIN_MAIL_SMTP_SERVER')).')</span>';
}
} elseif (getDolGlobalString('MAIN_MAIL_SENDMODE') != 'mail' && getDolGlobalString('MAIN_MAIL_SMTP_SERVER')) {
print ' <span class="opacitymedium">('.getDolGlobalString('MAIN_MAIL_SMTP_SERVER').')</span>';
}
} else {
print 'SMS ';
print ' <span class="opacitymedium">('.getDolGlobalString('MAIN_MAIL_SMTP_SERVER').')</span>';
}
print '</td></tr>';

View file

@ -314,8 +314,20 @@ class Proposals extends DolibarrApi
if (!DolibarrApiAccess::$user->hasRight('propal', 'creer')) {
throw new RestException(403, "Insufficiant rights");
}
// Check mandatory fields
$result = $this->_validate($request_data);
$this->_validate($request_data);
// Check thirdparty validity
$socid = (int) $request_data['socid'];
$thirdpartytmp = new Societe($this->db);
$thirdparty_result = $thirdpartytmp->fetch($socid);
if ($thirdparty_result < 1) {
throw new RestException(404, 'Thirdparty with id='.$socid.' not found or not allowed');
}
if (!DolibarrApi::_checkAccessToResource('societe', $thirdpartytmp->id)) {
throw new RestException(404, 'Thirdparty with id='.$thirdpartytmp->id.' not found or not allowed');
}
foreach ($request_data as $field => $value) {
if ($field === 'caller') {

View file

@ -319,8 +319,20 @@ class Orders extends DolibarrApi
if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
throw new RestException(403, "Insufficiant rights");
}
// Check mandatory fields
$result = $this->_validate($request_data);
$this->_validate($request_data);
// Check thirdparty validity
$socid = (int) $request_data['socid'];
$thirdpartytmp = new Societe($this->db);
$thirdparty_result = $thirdpartytmp->fetch($socid);
if ($thirdparty_result < 1) {
throw new RestException(404, 'Thirdparty with id='.$socid.' not found or not allowed');
}
if (!DolibarrApi::_checkAccessToResource('societe', $thirdpartytmp->id)) {
throw new RestException(404, 'Thirdparty with id='.$thirdpartytmp->id.' not found or not allowed');
}
foreach ($request_data as $field => $value) {
if ($field === 'caller') {

View file

@ -423,7 +423,7 @@ if ($action == "valid" && $permissiontoadd) { // validate = close
if ($contextpage == 'takepos') {
print "
<script>
parent.location.href='../../takepos/index.php?place='+parent.place;
location.href='cashcontrol_card.php?id=".$id."&contextpage=takepos';
</script>";
exit;
}

View file

@ -361,6 +361,17 @@ class Invoices extends DolibarrApi
// Check mandatory fields (not using output, only possible exception is important)
$this->_validate($request_data);
// Check thirdparty validity
$socid = (int) $request_data['socid'];
$thirdpartytmp = new Societe($this->db);
$thirdparty_result = $thirdpartytmp->fetch($socid);
if ($thirdparty_result < 1) {
throw new RestException(404, 'Thirdparty with id='.$socid.' not found or not allowed');
}
if (!DolibarrApi::_checkAccessToResource('societe', $thirdpartytmp->id)) {
throw new RestException(404, 'Thirdparty with id='.$thirdpartytmp->id.' not found or not allowed');
}
foreach ($request_data as $field => $value) {
if ($field === 'caller') {
// Add a mention of caller so on trigger called after action, we can filter to avoid a loop if we try to sync back again with the caller

View file

@ -1423,6 +1423,9 @@ class Facture extends CommonInvoice
$this->date = dol_now();
$this->source = 0;
// Avoid updating the row ranks
$this->context['createfromclone'] = 1;
$num = count($object->lines);
for ($i = 0; $i < $num; $i++) {
$line = new FactureLigne($this->db);

View file

@ -76,7 +76,7 @@ if (isModEnabled('category')) {
}
// Load translation files required by the page
$langs->loadLangs(array('bills', 'companies', 'products', 'categories'));
$langs->loadLangs(array('bills', 'companies', 'products', 'categories', 'cashdesk'));
$search_all = trim(GETPOST('search_all', 'alphanohtml'));
@ -220,6 +220,7 @@ $diroutputmassaction = $conf->invoice->dir_output.'/temp/massgeneration/'.$user-
$now = dol_now();
$error = 0;
$sql = '';
// Initialize a technical object to manage hooks of page. Note that conf->hooks_modules contains an array of hook context
$object = new Facture($db);
@ -346,6 +347,10 @@ foreach ($object->fields as $key => $val) {
}
// Extra fields
include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_array_fields.tpl.php';
// Add hook to complete $arrayfield
$parameters = array('arrayfields' => &$arrayfields);
$reshook = $hookmanager->executeHooks('completeArrayFields', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
$sql .= $hookmanager->resPrint;
// For POS context, we force some fields
if ($contextpage == 'poslist') {

View file

@ -708,7 +708,7 @@ class BonPrelevement extends CommonObject
$paiement->num_payment = $this->ref; // Set ref of direct debit note
$paiement->id_prelevement = $this->id;
$result = $paiement->create($user); // This use ->paiementid, that is ID of payment mode
$result = $paiement->create($user, 1); // This use ->paiementid, that is ID of payment mode. closepaidinvoices=1 to convert deposit invoice to available credit
if ($result < 0) {
$error++;

View file

@ -5,7 +5,7 @@
* Copyright (C) 2006 Yannick Warnier <ywarnier@beeznest.org>
* Copyright (C) 2014 Ferran Marcet <fmarcet@2byte.es>
* Copyright (C) 2018-2024 Frédéric France <frederic.france@free.fr>
* Copyright (C) 2024-2025 MDW <mdeweerd@users.noreply.github.com>
* Copyright (C) 2024-2026 MDW <mdeweerd@users.noreply.github.com>
* Copyright (C) 2026 Juan Pablo Farber <jfarber55@hotmail.com>
*
* This program is free software; you can redistribute it and/or modify
@ -423,6 +423,7 @@ if (!is_array($x_coll) || !is_array($x_paye)) {
print '</tr>';
$action = "tvadetail";
$parameters = array();
$parameters["mode"] = $modetax;
$parameters["start"] = $date_start;
$parameters["end"] = $date_end;
@ -454,6 +455,9 @@ if (!is_array($x_coll) || !is_array($x_paye)) {
print '</tr>'."\n";
foreach ($x_both[$thirdparty_id]['coll']['detail'] as $index => $fields) {
// Sort by payment date/invoice date
usort($x_both[$thirdparty_id]['coll']['detail'], 'cmp_fields_date');
// Define type
// We MUST use dtype (type in line). We can use something else, only if dtype is really unknown.
$type = (isset($fields['dtype']) ? $fields['dtype'] : $fields['ptype']);
@ -644,6 +648,9 @@ if (!is_array($x_coll) || !is_array($x_paye)) {
print '</tr>'."\n";
foreach ($x_both[$thirdparty_id]['paye']['detail'] as $index => $fields) {
// Sort by payment date/invoice date
usort($x_both[$thirdparty_id]['paye']['detail'], 'cmp_fields_date');
// Define type
// We MUST use dtype (type in line). We can use something else, only if dtype is really unknown.
$type = (isset($fields['dtype']) ? $fields['dtype'] : $fields['ptype']);
@ -810,3 +817,20 @@ print '</div>';
llxFooter();
$db->close();
/**
* Helper compare function to sort lines by payment date first
*
* @param array{datep:int,datef:int} $a Left argument to compare
* @param array{datep:int,datef:int} $b Right argument to compare
* @return int<-1,1> Indicates sort order between arguments
*/
function cmp_fields_date(&$a, &$b)
{
// Compare payment date
if ($a['datep'] != $b['datep']) {
return $a['datep'] <=> $b['datep'];
}
// In case the payment date is the same, order by invoice date
return $a['datef'] <=> $b['datef'];
}

View file

@ -36,9 +36,7 @@ class Contracts extends DolibarrApi
*/
public static $FIELDS = array(
'socid',
'date_contrat',
'commercial_signature_id',
'commercial_suivi_id'
'date_contrat'
);
/**
@ -236,6 +234,10 @@ class Contracts extends DolibarrApi
throw new RestException(403, "Missing permission: Create/modify contracts/subscriptions");
}
// Check mandatory fields
$this->_validate($request_data);
// Check thirdparty validity
$socid = (int) $request_data['socid'];
$thirdpartytmp = new Societe($this->db);
$thirdparty_result = $thirdpartytmp->fetch($socid);
@ -246,9 +248,6 @@ class Contracts extends DolibarrApi
throw new RestException(404, 'Thirdparty with id='.$thirdpartytmp->id.' not found or not allowed');
}
// Check mandatory fields
$result = $this->_validate($request_data);
foreach ($request_data as $field => $value) {
if ($field === 'caller') {
// Add a mention of caller so on trigger called after action, we can filter to avoid a loop if we try to sync back again with the caller

View file

@ -382,28 +382,28 @@ if ($filter_datecloture_start != '' && $filter_opcloture == -1) {
}
if (!empty($filter_opouvertureprevue) && $filter_opouvertureprevue != -1 && $filter_opouvertureprevue != ' BETWEEN ' && $filter_dateouvertureprevue_start != '') {
$sql .= " AND cd.date_ouverture_prevue ".$filter_opouvertureprevue." '".$db->idate($filter_dateouvertureprevue_start)."'";
$sql .= " AND cd.date_ouverture_prevue ".preg_replace('/[^<>]/', '', $filter_opouvertureprevue)." '".$db->idate($filter_dateouvertureprevue_start)."'";
}
if (!empty($filter_opouvertureprevue) && $filter_opouvertureprevue == ' BETWEEN ') {
$sql .= " AND cd.date_ouverture_prevue ".$filter_opouvertureprevue." '".$db->idate($filter_dateouvertureprevue_start)."' AND '".$db->idate($filter_dateouvertureprevue_end)."'";
$sql .= " AND cd.date_ouverture_prevue ".$db->sanitize($filter_opouvertureprevue)." '".$db->idate($filter_dateouvertureprevue_start)."' AND '".$db->idate($filter_dateouvertureprevue_end)."'";
}
if (!empty($filter_op1) && $filter_op1 != -1 && $filter_op1 != ' BETWEEN ' && $filter_date1_start != '') {
$sql .= " AND cd.date_ouverture ".$filter_op1." '".$db->idate($filter_date1_start)."'";
$sql .= " AND cd.date_ouverture ".preg_replace('/[^<>]/', '', $filter_op1)." '".$db->idate($filter_date1_start)."'";
}
if (!empty($filter_op1) && $filter_op1 == ' BETWEEN ') {
$sql .= " AND cd.date_ouverture ".$filter_op1." '".$db->idate($filter_date1_start)."' AND '".$db->idate($filter_date1_end)."'";
$sql .= " AND cd.date_ouverture ".$db->sanitize($filter_op1)." '".$db->idate($filter_date1_start)."' AND '".$db->idate($filter_date1_end)."'";
}
if (!empty($filter_op2) && $filter_op2 != -1 && $filter_op2 != ' BETWEEN ' && $filter_date2_start != '') {
$sql .= " AND cd.date_fin_validite ".$filter_op2." '".$db->idate($filter_date2_start)."'";
$sql .= " AND cd.date_fin_validite ".preg_replace('/[^<>]/', '', $filter_op2)." '".$db->idate($filter_date2_start)."'";
}
if (!empty($filter_op2) && $filter_op2 == ' BETWEEN ') {
$sql .= " AND cd.date_fin_validite ".$filter_op2." '".$db->idate($filter_date2_start)."' AND '".$db->idate($filter_date2_end)."'";
$sql .= " AND cd.date_fin_validite ".$db->sanitize($filter_op2)." '".$db->idate($filter_date2_start)."' AND '".$db->idate($filter_date2_end)."'";
}
if (!empty($filter_opcloture) && $filter_opcloture != ' BETWEEN ' && $filter_opcloture != -1 && $filter_datecloture_start != '') {
$sql .= " AND cd.date_cloture ".$filter_opcloture." '".$db->idate($filter_datecloture_start)."'";
$sql .= " AND cd.date_cloture ".preg_replace('/[^<>]/', '', $filter_opcloture)." '".$db->idate($filter_datecloture_start)."'";
}
if (!empty($filter_opcloture) && $filter_opcloture == ' BETWEEN ') {
$sql .= " AND cd.date_cloture ".$filter_opcloture." '".$db->idate($filter_datecloture_start)."' AND '".$db->idate($filter_datecloture_end)."'";
$sql .= " AND cd.date_cloture ".$db->sanitize($filter_opcloture)." '".$db->idate($filter_datecloture_start)."' AND '".$db->idate($filter_datecloture_end)."'";
}
// Add where from extra fields
include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php';

View file

@ -42,8 +42,6 @@ if (!defined('NOREQUIRESOC')) {
// Load Dolibarr environment
require '../../main.inc.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/genericobject.class.php';
/**
* @var Conf $conf
* @var DoliDB $db
@ -51,6 +49,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/genericobject.class.php';
* @var Translate $langs
* @var User $user
*/
require_once DOL_DOCUMENT_ROOT.'/core/class/genericobject.class.php';
$action = GETPOST('action', 'aZ09');
$backtopage = GETPOST('backtopage');
@ -131,12 +130,19 @@ if (($action == 'set') && !empty($id)) { // Test on permission already done in h
foreach ($object->errors as $msg) {
print $msg."\n";;
}
$db->close();
http_response_code(500);
exit;
}
if ($backtopage) {
$db->close();
header('Location: '.$backtopage);
exit;
}
}
$db->close();

View file

@ -915,6 +915,10 @@ abstract class CommonInvoice extends CommonObject
*/
public function getVentilExportCompta($mode = 0)
{
if (!isModEnabled('accounting')) {
return 0;
}
$alreadydispatched = 0;
$type = 'customer_invoice';

View file

@ -457,7 +457,7 @@ class DolEditor
$out .= 'jQuery(document).ready(function() {';
$out .= ' jQuery(".buttonforacesave").click(function() {
console.log("We click on savefile button for component '.dol_escape_js($this->htmlname).'");
console.log("We click on button (with class .buttonforacesave) that must fill ace fields for component '.dol_escape_js($this->htmlname).'");
var aceEditor = window.ace.edit("'.dol_escape_js($this->htmlname).'aceeditorid");
if (aceEditor) {
var cursorPos = aceEditor.getCursorPosition();

View file

@ -197,21 +197,18 @@ class FormAccounting extends Form
$selected = array();
$langs->load('accountancy');
while ($obj = $this->db->fetch_object($resql)) {
$label = $langs->trans($obj->label);
$select_value_in = $obj->rowid;
$select_value_out = $obj->rowid;
// Try to guess if we have found default value
if ($select_in == 1) {
$select_value_in = $obj->code;
}
if ($select_out == 1) {
$select_value_out = $obj->code;
// Build the full text directly here
$translatedLabel = $langs->trans($obj->label);
if (empty($translatedLabel) || $translatedLabel === $obj->label) {
$translatedLabel = $obj->label; // fallback to the raw label
}
$label = $obj->code . ' - ' . $translatedLabel;
$select_value_in = ($select_in == 1 ? $obj->code : $obj->rowid);
$select_value_out = ($select_out == 1 ? $obj->code : $obj->rowid);
// Remember guy's we store in database llx_accounting_bookkeeping the code of accounting_journal and not the rowid
if (!empty($selectedIds) && in_array($select_value_in, $selectedIds)) {
//var_dump("Found ".$selectid." ".$select_value_in);
$selected[] = $select_value_out;
}
$options[$select_value_out] = $label;
@ -223,7 +220,7 @@ class FormAccounting extends Form
}
}
$out .= Form::multiselectarray($htmlname, $options, $selected, $showempty, 0, $morecss, 0, 0, '', 'code_journal', '', ($disabledajaxcombo ? 0 : 1));
$out .= Form::multiselectarray($htmlname, $options, $selected, 0, 0, $morecss, 0, 0, '', 'code_journal', '', ($disabledajaxcombo ? 0 : 1));
return $out;
}

View file

@ -1503,6 +1503,7 @@ class FormMail extends Form
* @param string $htmlContent HTML name of WYSIWYG field to fill once layout has been chosen
* @param string $showlinktolayout Show link to layout
* @return string HTML for model email boxes
* @see getContentPageTemplate()
*/
public function getEmailLayoutSelector($htmlContent = 'message', $showlinktolayout = 'email')
{
@ -1837,27 +1838,25 @@ class FormMail extends Form
if ($type_template == 'body') {
// Special case to use this->withbody as content
$defaultmessage = (string) $this->withbody;
} elseif ($type_template == 'facture_send') {
} elseif ($type_template == 'facture_send' || $type_template == 'facture' || $type_template == 'facture_relance') {
$defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendInvoice");
} elseif ($type_template == 'facture_relance') {
$defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendInvoiceReminder");
} elseif ($type_template == 'propal_send') {
} elseif ($type_template == 'propal_send' || $type_template == 'propal') {
$defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendProposal");
} elseif ($type_template == 'supplier_proposal_send') {
} elseif ($type_template == 'supplier_proposal_send' || $type_template == 'supplier_proposal') {
$defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendSupplierProposal");
} elseif ($type_template == 'order_send') {
} elseif ($type_template == 'order_send' || $type_template == 'order') {
$defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendOrder");
} elseif ($type_template == 'order_supplier_send') {
} elseif ($type_template == 'order_supplier_send' || $type_template == 'order_supplier') {
$defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendSupplierOrder");
} elseif ($type_template == 'invoice_supplier_send') {
} elseif ($type_template == 'invoice_supplier_send' || $type_template == 'invoice_supplier') {
$defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendSupplierInvoice");
} elseif ($type_template == 'shipping_send') {
} elseif ($type_template == 'shipping_send' || $type_template == 'shipping') {
$defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendShipping");
} elseif ($type_template == 'reception_send') {
} elseif ($type_template == 'reception_send' || $type_template == 'reception') {
$defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendReception");
} elseif ($type_template == 'fichinter_send') {
} elseif ($type_template == 'fichinter_send' || $type_template == 'fichinter') {
$defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendFichInter");
} elseif ($type_template == 'actioncomm_send') {
} elseif ($type_template == 'actioncomm_send' || $type_template == 'actioncomm') {
$defaultmessage = $outputlangs->transnoentities("PredefinedMailContentSendActionComm");
} elseif (!empty($type_template)) {
$defaultmessage = $outputlangs->transnoentities("PredefinedMailContentGeneric");

View file

@ -242,7 +242,8 @@ class FormSetup
if ($reshook > 0) {
return $hookmanager->resPrint;
} else {
$out = '<table class="noborder centpercent">';
$out = '<div class="div-table-responsive-no-min">';
$out .= '<table class="noborder centpercent">';
if (empty($hideTitle)) {
if (empty($title)) {
$title = $this->langs->transnoentitiesnoconv("Parameter");
@ -265,6 +266,7 @@ class FormSetup
$out .= '</tbody>';
$out .= '</table>';
$out .= '</div>';
return $out;
}
}

View file

@ -349,6 +349,7 @@ class FormWebsite
*
* @param string $htmlContent HTML name of WYSIWYG field
* @return string HTML for model page boxes
* @see getEmailLayoutSelector()
*/
public function getContentPageTemplate($htmlContent = 'message')
{
@ -359,8 +360,12 @@ class FormWebsite
require_once DOL_DOCUMENT_ROOT.'/core/lib/emaillayout.lib.php';
$listofsamples = dol_dir_list(DOL_DOCUMENT_ROOT.'/website/samples', 'files', 0, '^page-sample-.*\.html$');
$arrayofsamples = array();
$arrayofsamples['empty'] = 'EmptyPage'; // Always this one first
// Define list of layouts to use
$arrayofsamples = array(
'empty' => 'EmptyPage',
);
foreach ($listofsamples as $sample) {
$reg = array();
if (preg_match('/^page-sample-(.*)\.html$/', $sample['name'], $reg)) {
@ -391,7 +396,7 @@ class FormWebsite
$contentHtml = file_exists($pathtoTemplateFile) ? make_substitutions(@file_get_contents($pathtoTemplateFile), $substitutionarray) : '';
$out .= '<div class="template-option" data-template="'.$template.'" data-content="'.htmlentities($contentHtml).'">';
$out .= '<img class="maillayout" alt="'.$template.'" src="'.DOL_URL_ROOT.'/theme/common/maillayout/'.$template.'.png" />';
$out .= '<img class="maillayout" alt="'.$template.'" src="'.DOL_URL_ROOT.'/theme/common/maillayout/'.($template === 'empty' ? 'none' : $template).'.png" />';
$out .= '<span class="template-option-text">'.($template != 'text' ? ucfirst($template) : ucfirst($templateFunction)).'</span>';
$out .= '</div>';
}

View file

@ -1290,7 +1290,7 @@ class Notify
if (!empty($mailTemplateLabel)) {
include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
$formmail = new FormMail($this->db);
$emailTemplate = $formmail->getEMailTemplate($this->db, $object_type.'_send', $user, $outputlangs, 0, 1, $mailTemplateLabel);
$emailTemplate = $formmail->getEMailTemplate($this->db, $object_type, $user, $outputlangs, 0, 1, $mailTemplateLabel);
}
if (!empty($mailTemplateLabel) && is_object($emailTemplate) && $emailTemplate->id > 0) {
if (property_exists($object, 'thirdparty')) {

View file

@ -68,13 +68,15 @@ if (!defined('USE_CUSTOM_REPORT_AS_INCLUDE')) {
$search_measures = GETPOST('search_measures', 'array:alphanohtml');
//$search_xaxis = GETPOST('search_xaxis', 'array');
if (GETPOST('search_xaxis', 'alpha') && GETPOST('search_xaxis', 'alpha') != '-1') {
$search_xaxis = array(GETPOST('search_xaxis', 'alpha'));
} else {
$search_xaxis = array();
}
//$search_groupby = GETPOST('search_groupby', 'array');
if (GETPOST('search_groupby', 'alpha') && GETPOST('search_groupby', 'alpha') != '-1') {
$search_groupby = array(GETPOST('search_groupby', 'alpha'));
} else {
$search_groupby = array();
}
'@phan-var-force string[] $search_groupby';
@ -482,7 +484,7 @@ if (count($search_groupby)) {
$fieldtocount = $gvalsanitized;
}
$sql = "SELECT DISTINCT ".$fieldtocount." as val"; // $fieldtocount has been sanitized by previous lines as we can't use db->sanitie()
$sql = "SELECT DISTINCT ".$fieldtocount." as val"; // $fieldtocount has been sanitized by previous lines as we can't use db->sanitize()
if (strpos($fieldtocount, 'te') === 0) {
$tabletouse = $object->table_element;

View file

@ -33,9 +33,9 @@ define('NOTOKENRENEWAL', 1); // Disables token renewal
// is a security hole if anybody can access without
// being an authenticated user.
require_once '../../../../main.inc.php';
/**
* @var Conf $conf
* @var User $user
*
* @var string $dolibarr_main_data_root
* @var string $dolibarr_main_url_root
@ -49,6 +49,13 @@ if ($pos == '/') {
//define('DOL_URL_ROOT', $pos);
$entity = ((!empty($_SESSION['dol_entity']) && $_SESSION['dol_entity'] > 1) ? $_SESSION['dol_entity'] : null);
if (!empty($user->admin) && !$user->hasRight('website', 'write')) {
accessforbidden('Need to be admin or having write permission on website module');
exit;
}
// SECURITY: You must explicitly enable this "connector". (Set it to "true").
// WARNING: don't just set "$Config['Enabled'] = true ;", you must be sure that only
// authenticated users can access this file or use some kind of session checking.

View file

@ -26,6 +26,9 @@
ob_start();
require 'config.inc.php'; // This include the main.inc.php
/**
* @var array<string,mixed> $Config
*/
require 'connector.lib.php';
if (!$Config['Enabled']) {

View file

@ -2229,6 +2229,7 @@ function GetContentPolicySources()
// Fetch directives
"fetch" => array(
"*" => array("label" => "*", "data-sourcetype" => "select"),
"blob" => array("label" => "blob:", "data-sourcetype" => "blob"),
"data" => array("label" => "data:", "data-sourcetype" => "data"),
"self" => array("label" => "self", "data-sourcetype" => "quoted"),
"unsafe-eval" => array("label" => "unsafe-eval", "data-sourcetype" => "quoted"),

View file

@ -843,7 +843,9 @@ function ajax_object_onoff($object, $code, $field, $text_on, $text_off, $input =
}
}).fail(
function(response) {
alert(response.responseText);
//alert(response.responseText);
console.warn(response.responseText);
Dolibarr.tools.setEventMessage(response.responseText, "errors");
}
);
});
@ -886,7 +888,9 @@ function ajax_object_onoff($object, $code, $field, $text_on, $text_off, $input =
}
}).fail(
function(response) {
alert(response.responseText);
//alert(response.responseText);
console.warn(response.responseText);
Dolibarr.tools.setEventMessage(response.responseText, "errors");
}
);
});

View file

@ -88,7 +88,7 @@ function pdf_getFormat($outputlangs = null, $mode = 'setup')
{
global $conf, $db, $langs;
dol_syslog("pdf_getFormat Get paper format with mode=".$mode." MAIN_PDF_FORMAT=".(!getDolGlobalString('MAIN_PDF_FORMAT') ? 'null' : $conf->global->MAIN_PDF_FORMAT)." outputlangs->defaultlang=".(is_object($outputlangs) ? $outputlangs->defaultlang : 'null')." and langs->defaultlang=".(is_object($langs) ? $langs->defaultlang : 'null'));
dol_syslog("pdf_getFormat Get paper format with mode=".$mode." MAIN_PDF_FORMAT=".getDolGlobalString('MAIN_PDF_FORMAT')." outputlangs->defaultlang=".(is_object($outputlangs) ? $outputlangs->defaultlang : 'null')." and langs->defaultlang=".(is_object($langs) ? $langs->defaultlang : 'null'));
// Default value if setup was not done and/or entry into c_paper_format not defined
$width = 210;
@ -242,7 +242,9 @@ function pdf_getEncryption($pathoffile)
//ob_start();
@($parser = new TCPDF_PARSER(ltrim($content)));
[$xref, $data] = $parser->getParsedData();
$tmp = $parser->getParsedData();
$xref = $tmp[0];
$data = $tmp[1] ?? null;
unset($parser);
//ob_end_clean();
@ -265,10 +267,8 @@ function pdf_getEncryption($pathoffile)
*/
function pdf_getPDFFont($outputlangs)
{
global $conf;
if (getDolGlobalString('MAIN_PDF_FORCE_FONT')) {
return $conf->global->MAIN_PDF_FORCE_FONT;
return getDolGlobalString('MAIN_PDF_FORCE_FONT');
}
$font = 'Helvetica'; // By default, for FPDI, or ISO language on TCPDF
@ -311,8 +311,7 @@ function pdf_getPDFFontSize($outputlangs)
*/
function pdf_getHeightForLogo($logo, $url = false)
{
global $conf;
$height = (!getDolGlobalString('MAIN_DOCUMENTS_LOGO_HEIGHT') ? 20 : $conf->global->MAIN_DOCUMENTS_LOGO_HEIGHT);
$height = getDolGlobalInt('MAIN_DOCUMENTS_LOGO_HEIGHT', 20);
$maxwidth = 130;
include_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php';
$tmp = dol_getImageSize($logo, $url);
@ -1296,7 +1295,10 @@ function pdf_pagefoot(&$pdf, $outputlangs, $paramfreetext, $fromcompany, $marge_
$pdf->SetDrawColor(224, 224, 224);
// Option for footer text color
if (getDolGlobalString('PDF_FOOTER_TEXT_COLOR')) {
[$r, $g, $b] = sscanf(getDolGlobalString('PDF_FOOTER_TEXT_COLOR'), '%d, %d, %d');
$tmparray = sscanf(getDolGlobalString('PDF_FOOTER_TEXT_COLOR'), '%d, %d, %d');
$r = $tmparray[0];
$g = $tmparray[1];
$b = $tmparray[2];
$pdf->SetTextColor($r, $g, $b);
}
@ -1334,7 +1336,10 @@ function pdf_pagefoot(&$pdf, $outputlangs, $paramfreetext, $fromcompany, $marge_
// Option for footer background color (without freetext zone)
if (getDolGlobalString('PDF_FOOTER_BACKGROUND_COLOR')) {
[$r, $g, $b] = sscanf($conf->global->PDF_FOOTER_BACKGROUND_COLOR, '%d, %d, %d');
$tmparray = sscanf(getDolGlobalString('PDF_FOOTER_BACKGROUND_COLOR'), '%d, %d, %d');
$r = $tmparray[0];
$g = $tmparray[1];
$b = $tmparray[2];
$pdf->setAutoPageBreak(false, 0); // Disable auto pagebreak
$pdf->Rect(0, $dims['hk'] - $posy + $freetextheight, $dims['wk'] + 1, $marginwithfooter + 1, 'F', array(), $fill_color = array($r, $g, $b));
$pdf->setAutoPageBreak(true, 0); // Restore pagebreak
@ -1386,7 +1391,10 @@ function pdf_pagefoot(&$pdf, $outputlangs, $paramfreetext, $fromcompany, $marge_
// Option for footer background color (without freetext zone)
if (getDolGlobalString('PDF_FOOTER_BACKGROUND_COLOR')) {
[$r, $g, $b] = sscanf($conf->global->PDF_FOOTER_BACKGROUND_COLOR, '%d, %d, %d');
$tmparray = sscanf(getDolGlobalString('PDF_FOOTER_BACKGROUND_COLOR'), '%d, %d, %d');
$r = $tmparray[0];
$g = $tmparray[1];
$b = $tmparray[2];
$pdf->setAutoPageBreak(false, 0); // Disable auto pagebreak
$pdf->Rect(0, $dims['hk'] - $posy + $freetextheight, $dims['wk'] + 1, $marginwithfooter + 1, 'F', array(), $fill_color = array($r, $g, $b));
$pdf->setAutoPageBreak(true, 0); // Restore pagebreak
@ -1844,7 +1852,8 @@ function pdf_getlinedesc($object, $i, $outputlangs, $hideref = 0, $hidedesc = 0,
}
if (isset($productCustomerPrice) && !empty($productCustomerPrice->ref_customer)) {
switch ($conf->global->PRODUIT_CUSTOMER_PRICES_PDF_REF_MODE) {
$idcustprice = getDolGlobalInt('PRODUIT_CUSTOMER_PRICES_PDF_REF_MODE');
switch ($idcustprice) {
case 1:
$ref_prodserv = $productCustomerPrice->ref_customer;
break;

View file

@ -2509,7 +2509,7 @@ function projectLinesPerMonth(&$inc, $firstdaytoshow, $fuser, $parent, $lines, &
if ($lines[$i]->id > 0) {
//var_dump('totalforeachday after taskid='.$lines[$i]->id.' and previous one on level '.$level);
//var_dump($totalforeachday);
$ret = projectLinesPerMonth($inc, $firstdaytoshow, $fuser, $lines[$i]->id, ($parent == 0 ? $lineswithoutlevel0 : $lines), $level, $projectsrole, $tasksrole, $mine, $restricteditformytask, $isavailable, $oldprojectforbreak, $TWeek);
$ret = projectLinesPerMonth($inc, $firstdaytoshow, $fuser, $lines[$i]->id, ($parent == 0 ? $lineswithoutlevel0 : $lines), $level, $projectsrole, $tasksrole, $mine, $restricteditformytask, $isavailable, $oldprojectforbreak, $TWeek, $arrayfields);
//var_dump('ret with parent='.$lines[$i]->id.' level='.$level);
//var_dump($ret);
foreach ($ret as $key => $val) {

View file

@ -1204,10 +1204,10 @@ function checkUserAccessToObject($user, array $featuresarray, $object = 0, $tabl
$sql .= " AND dbt.".$dbt_keyfield." = ".((int) $user->socid);
} elseif (isModEnabled("societe") && !$user->hasRight('societe', 'client', 'voir')) {
// If internal user without permission to see all thirdparties: Check permission for internal users that are restricted on their objects
if (empty($dbt_keyfield)) {
dol_print_error(null, 'Param dbt_keyfield is required but not defined');
}
if ($feature != 'ticket') {
if (empty($dbt_keyfield)) {
dol_print_error(null, 'Param dbt_keyfield is required but not defined');
}
$sql = "SELECT COUNT(sc.fk_soc) as nb";
$sql .= " FROM ".MAIN_DB_PREFIX.$dbtablename." as dbt";
$sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc";
@ -1227,7 +1227,7 @@ function checkUserAccessToObject($user, array $featuresarray, $object = 0, $tabl
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON sc.fk_soc = dbt.".$dbt_keyfield." AND sc.fk_user = ".((int) $user->id);
$sql .= " WHERE dbt.".$dbt_select." IN (".$db->sanitize($objectid, 1).")";
$sql .= " AND dbt.entity IN (".getEntity($sharedelement, 1).")";
$sql .= " AND (sc.fk_user = ".((int) $user->id)." OR sc.fk_user IS NULL)";
$sql .= " AND (sc.fk_user = ".((int) $user->id)." OR dbt.".$dbt_keyfield." IS NULL OR dbt.".$dbt_keyfield." = 0)";
}
} elseif (isModEnabled('multicompany')) {
// If multicompany, and user is an internal user with all permissions, check that object is in correct entity

View file

@ -105,7 +105,7 @@ function dolKeepOnlyPhpCode($str)
}
}
}
return $newstr;
return str_replace(array("\r\n", "\r"), array("\n", "\n"), $newstr);
}
/**

View file

@ -937,7 +937,7 @@ function showWebsiteTemplates(Website $website, int $refresh)
/**
* Check a new string containing only php code (including <php tag)
* Check that the new string $phpfullcodestring contains only php code (including <php tag)
* - Block if user has no permission to change PHP code.
* - Block also if bad code found in the new string.
*

View file

@ -218,7 +218,7 @@ if (isset($extrafields->attributes[$elementtype]['type']) && is_array($extrafiel
$colspan++;
}
print '<tr class="oddeven">';
print '<tr class="">';
print '<td colspan="'.$colspan.'"><span class="opacitymedium">';
print $langs->trans("None");
print '</span></td>';

View file

@ -974,13 +974,20 @@ if (!empty($usemargins) && $user->hasRight('margins', 'creer')) {
<?php
} ?>
}
// 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);
// Set vat rate: handle both input box and combo cases
if ($('#tva_tx option').length) {
// It is a combo: try exact match first (rate + code), fallback to numeric match
if ($('#tva_tx option[value="' + stringforvatrateselection + '"]').length) {
$('#tva_tx').val(stringforvatrateselection);
} else {
$('#tva_tx option').filter(function () {
return parseFloat($(this).val()) === parseFloat(tva_tx);
}).first().prop('selected', true);
}
} else {
// It is an input box
$('#tva_tx').val(tva_tx);
}
<?php
if (getDolGlobalInt('PRODUIT_AUTOFILL_DESC') == 1) {

View file

@ -314,7 +314,7 @@ if (!empty($dolibarr_website_allow_custom_php) && $dolibarr_website_allow_custom
if (function_exists($systemfunction)) {
print '<center><br><br>';
print 'Website features are protected to be disabled if the PHP system functions ('.implode(',', $systemfunctions).') are not disabled for the website context.<br>';
print 'Website features are DISABLED if the PHP system functions ('.implode(',', $systemfunctions).') are NOT disabled for the website context.<br>';
print 'The value "'.$systemfunction.'" has NOT been found into the <b>current disable_functions</b>=<br>';
print '<textarea cols="100" rows="5">';
print ini_get('disable_functions'); // Warning, the real value may not be this one.Only the master initial value from php.ini is effective, not the local value set at virtualhost.

View file

@ -1596,7 +1596,7 @@ if ($action == 'create' && $usercancreate) {
// Document model
include_once DOL_DOCUMENT_ROOT.'/core/modules/expedition/modules_expedition.php';
$list = ModelePdfExpedition::liste_modeles($db);
if (is_countable($list) && count($list) > 1) {
if (is_array($list) && count($list) > 1) {
print "<tr><td>".$langs->trans("DefaultModel")."</td>";
print '<td colspan="3">';
print img_picto('', 'pdf', 'class="pictofixedwidth"');
@ -1807,7 +1807,7 @@ if ($action == 'create' && $usercancreate) {
// Document model
include_once DOL_DOCUMENT_ROOT . '/core/modules/expedition/modules_expedition.php';
$list = ModelePdfExpedition::liste_modeles($db);
if (is_countable($list) && count($list) > 1) {
if (is_array($list) && count($list) > 1) {
print "<tr><td>" . $langs->trans("DefaultModel") . "</td>";
print '<td colspan="3">';
print img_picto('', 'pdf', 'class="pictofixedwidth"');

View file

@ -54,10 +54,14 @@ create table llx_categorie_project_task (
ALTER TABLE llx_categorie_project_task ADD PRIMARY KEY pk_categorie_propal (fk_categorie, fk_project_task);
--noqa:enable=PRS
ALTER TABLE llx_categorie_project_task ADD INDEX idx_categorie_project_fk_categorie (fk_categorie);
ALTER TABLE llx_categorie_project_task ADD INDEX idx_categorie_project_fk_task (fk_project_task);
ALTER TABLE llx_categorie_project_task ADD CONSTRAINT fk_categorie_project_task_categorie_rowid FOREIGN KEY (fk_categorie) REFERENCES llx_categorie (rowid);
ALTER TABLE llx_categorie_project_task ADD CONSTRAINT fk_categorie_project_task_rowid FOREIGN KEY (fk_project_task) REFERENCES llx_projet (rowid);
ALTER TABLE llx_categorie_project_task DROP FOREIGN KEY fk_categorie_project_task_rowid;
-- VMYSQL4.1 DROP INDEX idx_categorie_project_fk_task ON llx_categorie_project_task;
-- VPGSQL8.2 DROP INDEX idx_categorie_project_fk_task;
ALTER TABLE llx_categorie_project_task ADD INDEX idx_categorie_project_fk_task (fk_project_task);
ALTER TABLE llx_categorie_project_task ADD CONSTRAINT fk_categorie_project_task_rowid FOREIGN KEY (fk_project_task) REFERENCES llx_projet_task (rowid);
UPDATE llx_actioncomm SET elementtype = 'project_task' WHERE elementtype = 'task';

View file

@ -22,4 +22,4 @@ ALTER TABLE llx_categorie_project_task ADD INDEX idx_categorie_project_fk_catego
ALTER TABLE llx_categorie_project_task ADD INDEX idx_categorie_project_fk_task (fk_project_task);
ALTER TABLE llx_categorie_project_task ADD CONSTRAINT fk_categorie_project_task_categorie_rowid FOREIGN KEY (fk_categorie) REFERENCES llx_categorie (rowid);
ALTER TABLE llx_categorie_project_task ADD CONSTRAINT fk_categorie_project_task_rowid FOREIGN KEY (fk_project_task) REFERENCES llx_projet (rowid);
ALTER TABLE llx_categorie_project_task ADD CONSTRAINT fk_categorie_project_task_rowid FOREIGN KEY (fk_project_task) REFERENCES llx_projet_task (rowid);

View file

@ -114,6 +114,7 @@ Language_ru_UA=Russian (Ukraine)
Language_ta_IN=Tamil
Language_tg_TJ=Tajik
Language_tr_TR=Turkish
Language_si_LK=Sinhala
Language_sl_SI=Slovenian
Language_sv_SV=Swedish
Language_sv_SE=Swedish

View file

@ -259,5 +259,6 @@ ConfirmMergeMembers=Are you sure you want to merge the chosen member with the cu
ErrorMembersMerge=There was an error when merging the members. Please check the log. Changes have been reverted.
ConfirmCreateMember=Confirm create member
CorrespondingMemberFound=Corresponding member found
CorrespondingMemberFoundQuestion=A member has been found with the given information.<br>Do you want to renew your membership?
MEMBER_SEARCH_MEMBER_PUBLIC_FORM_CREATE=Searches for a member matching the information entered in the public member creation form. If a member is found, redirects the user to the membership payment form
CorrespondingMemberFoundQuestion=A member has been found with the given information.<br>Do you want to renew your membership? (if not nothing will be recorded)
MEMBER_SEARCH_MEMBER_PUBLIC_FORM_CREATE=Suggest to just record the subscription (without creating a new member) if an existing member is found
MEMBER_SEARCH_MEMBER_PUBLIC_FORM_CREATEDesc=A search is done on login, company name + email (for legal entity), or full name + email (for individual). If a member is already found, the form suggest to record a renewal of subscription.

View file

@ -98,5 +98,5 @@ ErrorInBatch=Erreur lors de l'exécution du travail %s
# Cron Boxes
LastExecutedScheduledJob=Dernier travail planifié exécuté
NextScheduledJobExecute=Prochain travail planifié à exécuter
NumberScheduledJobError=Nombre de travaux planifiées en erreur
NumberScheduledJobError=Nombre de travaux planifiés en erreur
NumberScheduledJobNeverFinished=Nombre de tâches planifiées jamais terminées

View file

@ -195,6 +195,10 @@ foreach ($object->fields as $key => $val) {
// Extra fields
include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_array_fields.tpl.php';
// Add hook to complete $arrayfield
$parameters = array('arrayfields' => &$arrayfields);
$reshook = $hookmanager->executeHooks('completeArrayFields', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
$sql .= $hookmanager->resPrint;
// Complete arrayfields with special fields
/*$arrayfields = array_merge($arrayfields, array(

View file

@ -1323,10 +1323,11 @@ print '<script type="text/javascript">
var actionURL = "'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&page='.($page).$paramwithsearch.'";
$.ajax({
url: actionURL,
type: "POST",
data: form.serialize(),
cache: false,
success: function(result){
window.location.href = "'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&page='.($page - 1).$paramwithsearch.'&action=record";
window.location.href = "'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&page='.($page).$paramwithsearch.'&action=record";
}});
return false;
});

View file

@ -2766,9 +2766,9 @@ if ((!getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || $action == 'showlog_defau
// We add it to fix this if not (trouble with old versions)
// We emulate the change of the price from interface with the same value than the one into table llx_product
if (getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) {
$ret = $object->updatePrice(($object->multiprices_base_type[1] == 'TTC' ? $object->multiprices_ttc[1] : $object->multiprices[1]), $object->multiprices_base_type[1], $user, (empty($object->multiprices_tva_tx[1]) ? 0 : $object->multiprices_tva_tx[1]), ($object->multiprices_base_type[1] == 'TTC' ? $object->multiprices_min_ttc[1] : $object->multiprices_min[1]), 1);
$ret = $object->updatePrice(($object->multiprices_base_type[1] == 'TTC' ? $object->multiprices_ttc[1] : $object->multiprices[1]), $object->multiprices_base_type[1], $user, (empty($object->multiprices_tva_tx[1]) ? 0 : $object->multiprices_tva_tx[1]), ($object->multiprices_base_type[1] == 'TTC' ? $object->multiprices_min_ttc[1] : $object->multiprices_min[1]), 1, 0, 0, 0, array(), $object->default_vat_code);
} else {
$ret = $object->updatePrice(($object->price_base_type == 'TTC' ? $object->price_ttc : $object->price), $object->price_base_type, $user, $object->tva_tx, ($object->price_base_type == 'TTC' ? $object->price_min_ttc : $object->price_min));
$ret = $object->updatePrice(($object->price_base_type == 'TTC' ? $object->price_ttc : $object->price), $object->price_base_type, $user, $object->tva_tx, ($object->price_base_type == 'TTC' ? $object->price_min_ttc : $object->price_min), 0, $object->tva_npr, 0, 0, array(), $object->default_vat_code);
}
if ($ret < 0) {

View file

@ -226,9 +226,13 @@ if ($reshook < 0) {
}
// Verify if we can find member
if (empty($reshook) && getDolGlobalInt("MEMBER_SEARCH_MEMBER_PUBLIC_FORM_CREATE") && $action == 'add' && !GETPOSTISSET("nofetchmember")) { // Test on permission not required here
$memberfound = false;
if (!getDolGlobalString('ADHERENT_LOGIN_NOT_REQUIRED') && GETPOSTISSET('login')) {
// Note that this allow to guess anonymous ID already used. But this is not a problem as it is an anonymous pseudonym.
// If we try to new account and option MEMBER_SEARCH_MEMBER_PUBLIC_FORM_CREATE was off, we also get the same error.
$sql = "SELECT rowid as id";
$sql .= " FROM ".MAIN_DB_PREFIX."adherent as a";
$sql .= " WHERE a.login = '".$db->escape(GETPOST('login'))."'";
@ -806,6 +810,7 @@ if (getDolGlobalString('MEMBER_SKIP_TABLE') || getDolGlobalString('MEMBER_NEWFOR
$morInput.prop({disabled: true, checked: false}); */
$span1.addClass("member-individual-back").removeClass("nonature-back");
$span2.removeClass("member-company-back").addClass("nonature-back");
$("#phisicalinput").prop("checked", true);
$tdLast.addClass("fieldrequired");
$tdFirst.addClass("fieldrequired");
$tdCompany.removeClass("fieldrequired");
@ -816,6 +821,7 @@ if (getDolGlobalString('MEMBER_SKIP_TABLE') || getDolGlobalString('MEMBER_NEWFOR
$morInput.prop({disabled: false, checked: true}); */
$span2.addClass("member-company-back").removeClass("nonature-back");
$span1.removeClass("member-individual-back").addClass("nonature-back");
$("#moralinput").prop("checked", true);
$tdCompany.addClass("fieldrequired");
$tdLast.removeClass("fieldrequired");
$tdFirst.removeClass("fieldrequired");
@ -855,14 +861,14 @@ if (getDolGlobalString('MEMBER_SKIP_TABLE') || getDolGlobalString('MEMBER_NEWFOR
}
// Firstname
print '<tr><td id="tdfirstname" class="classfortooltip'.($checkednature == "phy" ? ' fieldrequired"' : '').'">'.$langs->trans("Firstname").'</td><td><input type="text" name="firstname" class="minwidth150" value="'.dol_escape_htmltag(GETPOST('firstname')).'"></td></tr>'."\n";
print '<tr><td id="tdfirstname" class="classfortooltip'.($checkednature == "phy" ? ' fieldrequired"' : '').'">'.$langs->trans("Firstname").'</td><td><input type="text" name="firstname" class="minwidth150" value="'.dol_escape_htmltag(GETPOST('firstname')).'" spellcheck="false"></td></tr>'."\n";
// Lastname
print '<tr><td id="tdlastname" class="classfortooltip'.($checkednature == "phy" ? ' fieldrequired"' : '').'">'.$langs->trans("Lastname").'</td><td><input type="text" name="lastname" class="minwidth150" value="'.dol_escape_htmltag(GETPOST('lastname')).'"></td></tr>'."\n";
print '<tr><td id="tdlastname" class="classfortooltip'.($checkednature == "phy" ? ' fieldrequired"' : '').'">'.$langs->trans("Lastname").'</td><td><input type="text" name="lastname" class="minwidth150" value="'.dol_escape_htmltag(GETPOST('lastname')).'" spellcheck="false"></td></tr>'."\n";
// EMail
print '<tr><td>'.(getDolGlobalString('ADHERENT_MAIL_REQUIRED') ? '<span class="fieldrequired">' : '').$langs->trans("EMail").(getDolGlobalString('ADHERENT_MAIL_REQUIRED') ? '</span>' : '').'</td>';
print '<td>'.img_picto('', 'object_email').' <input type="text" name="member_email" class="minwidth150 maxwidth300 widthcentpercentminusx" maxlength="255" value="'.dol_escape_htmltag(GETPOST('member_email', "aZ09arobase")).'"></td></tr>'."\n";
print '<td>'.img_picto('', 'object_email').' <input type="text" name="member_email" class="minwidth150 maxwidth300 widthcentpercentminusx" maxlength="255" value="'.dol_escape_htmltag(GETPOST('member_email', "aZ09arobase")).'" spellcheck="false"></td></tr>'."\n";
// Login
if (!getDolGlobalString('ADHERENT_LOGIN_NOT_REQUIRED')) {

View file

@ -33,11 +33,6 @@
// Load Dolibarr environment
require '../main.inc.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.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.'/societe/class/societe.class.php';
/**
* @var Conf $conf
* @var DoliDB $db
@ -47,9 +42,14 @@ require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
* @var Translate $langs
* @var User $user
*/
require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.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.'/societe/class/societe.class.php';
require_once DOL_DOCUMENT_ROOT.'/product/class/productcustomerprice.class.php';
$prodcustprice = null;
if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) {
require_once DOL_DOCUMENT_ROOT.'/product/class/productcustomerprice.class.php';
$prodcustprice = new ProductCustomerPrice($db);
}
@ -754,7 +754,7 @@ if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT
$nbtotalofrecords = $prodcustprice->fetchAll('', '', 0, 0, $filter);
}
$result = $prodcustprice->fetchAll($sortorder, $sortfield, $conf->liste_limit, $offset, $filter);
$result = $prodcustprice->fetchAll($sortorder, $sortfield, $limit, $offset, $filter);
if ($result < 0) {
setEventMessages($prodcustprice->error, $prodcustprice->errors, 'errors');
}

View file

@ -613,12 +613,12 @@ if ($conf->use_javascript_ajax) {
}
print '</td></tr>';
if (getDolGlobalInt('STRIPE_AUTO_RECORD_PAYOUT')) {
print '<tr class="oddeven"><td>';
print $langs->trans("StripeUserAccountForActions").'</td><td>';
print img_picto('', 'user', 'class="pictofixedwidth"').$form->select_dolusers(getDolGlobalString('STRIPE_USER_ACCOUNT_FOR_ACTIONS'), 'STRIPE_USER_ACCOUNT_FOR_ACTIONS', 0);
print '</td></tr>';
print '<tr class="oddeven"><td>';
print $langs->trans("StripeUserAccountForActions").'</td><td>';
print img_picto('', 'user', 'class="pictofixedwidth"').$form->select_dolusers(getDolGlobalString('STRIPE_USER_ACCOUNT_FOR_ACTIONS'), 'STRIPE_USER_ACCOUNT_FOR_ACTIONS', 0);
print '</td></tr>';
if (getDolGlobalInt('STRIPE_AUTO_RECORD_PAYOUT')) {
print '<tr class="oddeven"><td>';
print $langs->trans("BankAccountForBankTransfer").'</td><td>';
print img_picto('', 'bank_account', 'class="pictofixedwidth"');

View file

@ -92,7 +92,7 @@ if (!$user->hasRight('takepos', 'run')) {
top_htmlhead('', '', 2);
if ((string) $place != '' && !empty($_SESSION["takeposterminal"])) {
if (!$facid && (string) $place != '' && !empty($_SESSION["takeposterminal"])) {
$sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."facture";
$sql .= " WHERE ref = '(PROV-POS".$db->escape($_SESSION["takeposterminal"]."-".$place).")'";
$sql .= " AND entity IN (".getEntity('invoice').")";

View file

@ -962,7 +962,7 @@ if ($action == 'create' || $action == 'presend') {
$morehtmlref .= '<input type="hidden" name="id" value="'.$object->id.'">';
$morehtmlref .= '<input type="text" class="minwidth300" id="subject" name="subject" value="'.$object->subject.'" autofocus="">';
$morehtmlref .= '<input type="submit" class="smallpaddingimp button valignmiddle" name="modify" value="'.$langs->trans("Modify").'">';
$morehtmlref .= '<input type="submit" class="smallpaddingimp button button-cancel vlignmiddle" name="cancel" value="'.$langs->trans("Cancel").'">';
$morehtmlref .= '<input type="submit" class="smallpaddingimp button button-cancel valignmiddle" name="cancel" value="'.$langs->trans("Cancel").'">';
$morehtmlref .= '</form>';
}

View file

@ -348,8 +348,22 @@ class Tickets extends DolibarrApi
if (!DolibarrApiAccess::$user->hasRight('ticket', 'write')) {
throw new RestException(403);
}
// Check mandatory fields
$result = $this->_validate($request_data);
$this->_validate($request_data);
// Check thirdparty validity
$socid = (int) $request_data['socid'];
if ($socid > 0) {
$thirdpartytmp = new Societe($this->db);
$thirdparty_result = $thirdpartytmp->fetch($socid);
if ($thirdparty_result < 1) {
throw new RestException(404, 'Thirdparty with id='.$socid.' not found or not allowed');
}
if (!DolibarrApi::_checkAccessToResource('societe', $thirdpartytmp->id)) {
throw new RestException(404, 'Thirdparty with id='.$thirdpartytmp->id.' not found or not allowed');
}
}
foreach ($request_data as $field => $value) {
if ($field === 'caller') {
@ -384,10 +398,10 @@ class Tickets extends DolibarrApi
*/
public function postNewMessage($request_data = null)
{
$ticketstatic = new Ticket($this->db);
if (!DolibarrApiAccess::$user->hasRight('ticket', 'write')) {
throw new RestException(403);
}
// Check mandatory fields
$result = $this->_validateMessage($request_data);
@ -405,6 +419,11 @@ class Tickets extends DolibarrApi
if (!$result) {
throw new RestException(404, 'Ticket not found');
}
if (!DolibarrApi::_checkAccessToResource('ticket', $this->ticket->id)) {
throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
}
$this->ticket->message = $ticketMessageText;
if (!$this->ticket->createTicketMessage(DolibarrApiAccess::$user)) {
throw new RestException(500, 'Error when creating ticket');
@ -436,6 +455,19 @@ class Tickets extends DolibarrApi
throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
}
// Check thirdparty validity
$socid = (int) $request_data['socid'];
if ($socid > 0) {
$thirdpartytmp = new Societe($this->db);
$thirdparty_result = $thirdpartytmp->fetch($socid);
if ($thirdparty_result < 1) {
throw new RestException(404, 'Thirdparty with id='.$socid.' not found or not allowed');
}
if (!DolibarrApi::_checkAccessToResource('societe', $thirdpartytmp->id)) {
throw new RestException(404, 'Thirdparty with id='.$thirdpartytmp->id.' not found or not allowed');
}
}
foreach ($request_data as $field => $value) {
if ($field === 'caller') {
// Add a mention of caller so on trigger called after action, we can filter to avoid a loop if we try to sync back again with the caller

View file

@ -3211,8 +3211,11 @@ class Ticket extends CommonObject
if ($mailfile->error) {
setEventMessages($langs->trans('ErrorFailedToSendMail', $from, $receiverstring), null, 'errors');
dol_syslog($langs->trans('ErrorFailedToSendMail', $from, $receiverstring).' : '.$mailfile->error);
} else {
} elseif (getDolGlobalString('MAIN_DISABLE_ALL_MAILS')) {
setEventMessages('No mail sent. Feature is disabled by option MAIN_DISABLE_ALL_MAILS', null, 'errors');
} else {
setEventMessages($langs->trans('ErrorFailedToSendMail', $from, $receiverstring), null, 'errors');
dol_syslog('ErrorFailedToSendMail (no error details) from='.$from.' to='.$receiverstring, LOG_WARNING);
}
}
}

View file

@ -279,13 +279,28 @@ class WebsitePage extends CommonObject
// Remove spaces and be sure we have main language only
$this->lang = preg_replace('/[_-].*$/', '', trim($this->lang)); // en_US or en-US -> en
// Check there is no PHP into HTML header
$dataposted = trim($this->htmlheader); // Must accept tags like '<script>' and '<link>'
$dataposted = preg_replace(array('/<html>\n*/ims', '/<\/html>\n*/ims'), array('', ''), $dataposted);
$dataposted = str_replace('<?=', '<?php', $dataposted);
// Test if page contains dynamic PHP content
if (!$user->hasRight('website', 'writephp')) {
// Check there is no PHP content into the imported file (must be only HTML + JS)
$phpcontent = dolKeepOnlyPhpCode($this->content);
if ($phpcontent) {
$this->error = 'Error: you try to create a page with PHP content without having permissions for that.';
$this->error = 'Error: you try to create a page with PHP content in HTML body without having permissions for that.';
$this->errors[] = $this->error;
return -1;
}
// Check there is no PHP content into the imported file (must be only HTML + JS)
// Note: This one may be uselss because this->htmlheader should be retrieved now using GETPOST(..., 'restricthtmlallowlinkscript') so without PHP content. We keep it in case of.
$phpcontent = dolKeepOnlyPhpCode($this->htmlheader);
if ($phpcontent) {
$this->error = 'Error: you try to create a page with PHP content in HTML header without having permissions for that.';
$this->errors[] = $this->error;
return -1;
}

View file

@ -1181,7 +1181,8 @@ if ($action == 'addcontainer' && $usercanedit) {
$objectpage->image = GETPOST('WEBSITE_IMAGE', 'alpha');
$objectpage->keywords = str_replace(array('<', '>'), '', GETPOST('WEBSITE_KEYWORDS', 'alphanohtml'));
$objectpage->allowed_in_frames = GETPOST('WEBSITE_ALLOWED_IN_FRAMES', 'aZ09') ? 1 : 0;
$objectpage->htmlheader = GETPOST('htmlheader', 'none'); // Must accept tags like '<script>' and '<link>'
$objectpage->htmlheader = GETPOST('htmlheader', 'restricthtmlallowlinkscript'); // Must accept tags like '<script>' and '<link>'
$objectpage->author_alias = GETPOST('WEBSITE_AUTHORALIAS', 'alphanohtml');
$objectpage->object_type = GETPOST('WEBSITE_OBJECTCLASS');
$objectpage->fk_object = GETPOST('WEBSITE_OBJECTID');
@ -1644,7 +1645,7 @@ if ($action == 'updatecss' && $usercanedit) {
if (!$errorphpcheck) {
$htmlheadercontent = '';
/* We disable php code since htmlheader is never executed as an include but only read by fgets_content.
/* We disable php code since global htmlheader for all website is never executed as an include but only read by fgets_content.
$htmlheadercontent.= "<?php // BEGIN PHP\n";
$htmlheadercontent.= '$websitekey=basename(__DIR__);'."\n";
$htmlheadercontent.= "if (! defined('USEDOLIBARRSERVER') && ! defined('USEDOLIBARREDITOR')) { require_once './master.inc.php'; } // Load env if not already loaded"."\n";
@ -4162,7 +4163,7 @@ if ($action == 'editcss') {
$head = websiteconfigPrepareHead($object);
print dol_get_fiche_head($head, 'general', $langs->trans("General"), 0, 'website');
print '<!-- Edit Website properties -->'."\n";
print '<!-- Edit Website properties (CSS, Language, ...) -->'."\n";
print '<table class="border centpercent">';
// Website
@ -4189,7 +4190,7 @@ if ($action == 'editcss') {
$htmltext = '';
print $form->textwithpicto($langs->trans('MainLanguage'), $htmltext, 1, 'help', '', 0, 2, 'WEBSITE_LANG');
print '</td><td>';
print img_picto('', 'language', 'class="picotfixedwidth"');
print img_picto('', 'language', 'class="pictofixedwidth"');
print $formadmin->select_language((GETPOSTISSET('WEBSITE_LANG') ? GETPOST('WEBSITE_LANG', 'aZ09comma') : ($object->lang ? $object->lang : '0')), 'WEBSITE_LANG', 0, array(), 1, 0, 0, 'minwidth300', 2, 0, 0, array(), 1);
print '</td>';
print '</tr>';
@ -4199,7 +4200,7 @@ if ($action == 'editcss') {
$htmltext = $langs->trans("Example").': fr,de,sv,it,pt';
print $form->textwithpicto($langs->trans('OtherLanguages'), $htmltext, 1, 'help', '', 0, 2);
print '</td><td>';
print img_picto('', 'language', 'class="picotfixedwidth"');
print img_picto('', 'language', 'class="pictofixedwidth"');
print '<input type="text" class="flat maxwidth200" value="'.(GETPOSTISSET('WEBSITE_OTHERLANG') ? GETPOST('WEBSITE_OTHERLANG', 'alpha') : $object->otherlang).'" name="WEBSITE_OTHERLANG">';
print '</td>';
print '</tr>';
@ -4815,7 +4816,7 @@ if ($action == 'editmeta' || $action == 'createcontainer') { // Edit properties
if (GETPOST('WEBSITE_ALLOWED_IN_FRAMES', 'aZ09')) {
$pageallowedinframes = 1;
}
if (GETPOST('htmlheader', 'none')) { // Must accept tags like '<script>' and '<link>'
if (GETPOST('htmlheader', 'restricthtmlallowlinkscript')) { // Must accept tags like '<script>' and '<link>'
$pagehtmlheader = GETPOST('htmlheader', 'none');
}
@ -5167,6 +5168,7 @@ if ($action == 'editmeta' || $action == 'createcontainer') { // Edit properties
print '<input type="text" class="flat minwidth300" name="WEBSITE_AUTHORALIAS" value="'.dol_escape_htmltag($pageauthoralias).'" placeholder="'.dol_escape_htmltag($langs->trans("Anonymous")).'">';
print '</td></tr>';
// Web page header
print '<tr><td class="tdhtmlheader tdtop">';
$htmlhelp = $langs->trans("EditTheWebSiteForACommonHeader").'<br><br>';
$htmlhelp .= $langs->trans("Examples").' :<br>';
@ -5176,7 +5178,7 @@ if ($action == 'editmeta' || $action == 'createcontainer') { // Edit properties
print $form->textwithpicto($langs->transnoentitiesnoconv('HtmlHeaderPage'), $htmlhelp, 1, 'help', '', 0, 2, 'htmlheadertooltip');
print '</td><td>';
$poscursor = array('x' => GETPOST('htmlheader_x'), 'y' => GETPOST('htmlheader_y'));
$doleditor = new DolEditor('htmlheader', $pagehtmlheader, '', 120, 'ace', 'In', true, false, 'ace', ROWS_3, '100%', 0, $poscursor);
$doleditor = new DolEditor('htmlheader', $pagehtmlheader, '', 160, 'ace', 'In', true, false, 'ace', ROWS_4, '100%', 0, $poscursor);
print $doleditor->Create(1, '', true, 'HTML Header', 'html');
print '</td></tr>';
@ -5191,12 +5193,13 @@ if ($action == 'editmeta' || $action == 'createcontainer') { // Edit properties
print '</table>';
if ($action == 'createcontainer') {
$langs->load("website");
print '<div class="center tablecheckboxcreatemanually'.$hiddenmanuallyafterload.'">';
print '<input type="submit" class="button small" name="addcontainer" value="'.$langs->trans("Create").'">';
print '<input type="submit" class="button small buttonforacesave" name="addcontainer" value="'.$langs->trans("Create").'">';
print '<input class="button button-cancel small" type="submit" name="preview" value="'.$langs->trans("Cancel").'">';
print '</div>';