Merge branch '23.0' of git@github.com:Dolibarr/dolibarr.git into develop
This commit is contained in:
commit
2ff2ee02ed
31 changed files with 274 additions and 219 deletions
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
exclude: (?x)^( htdocs/includes/ckeditor/.*|(\.(?!github/workflows)[^/]*/.*))$
|
||||
exclude: (?x)^( htdocs/includes/ckeditor/.*|htdocs/public/includes/ckeditor/.*|(\.(?!github/workflows)[^/]*/.*))$
|
||||
repos:
|
||||
# Several miscellaneous checks and fix (on yaml files, end of files fix)
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
|
|
|
|||
|
|
@ -114,8 +114,8 @@ if ( !$ENV{"DESTIBETARC"} || !$ENV{"DESTISTABLE"} ) {
|
|||
print "On Linux:\n";
|
||||
print "export DESTIBETARC='/tmp'; export DESTISTABLE='/tmp';\n";
|
||||
print "On Windows:\n";
|
||||
print "set DESTIBETARC=c:/tmp\n";
|
||||
print "set DESTISTABLE=c:/tmp\n";
|
||||
print "set DESTIBETARC=c:/temp\n";
|
||||
print "set DESTISTABLE=c:/temp\n";
|
||||
print "\n";
|
||||
print "Example in .bashrc:\n";
|
||||
print
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ require_once DOL_DOCUMENT_ROOT.'/accountancy/class/lettering.class.php';
|
|||
*/
|
||||
|
||||
// Load translation files required by the page
|
||||
$langs->loadLangs(array("accountancy", "categories", "compta"));
|
||||
$langs->loadLangs(array("accountancy", "categories", "compta", "other"));
|
||||
|
||||
// Get Parameters
|
||||
$socid = GETPOSTINT('socid');
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/* Copyright (C) 2016 Neil Orley <neil.orley@oeris.fr>
|
||||
* Copyright (C) 2013-2016 Olivier Geffroy <jeff@jeffinfo.com>
|
||||
* Copyright (C) 2013-2020 Florian Henry <florian.henry@open-concept.pro>
|
||||
* Copyright (C) 2013-2025 Alexandre Spangaro <alexandre@inovea-conseil.com>
|
||||
* Copyright (C) 2013-2026 Alexandre Spangaro <alexandre@inovea-conseil.com>
|
||||
* Copyright (C) 2018-2025 Frédéric France <frederic.france@free.fr>
|
||||
* Copyright (C) 2024-2025 MDW <mdeweerd@users.noreply.github.com>
|
||||
* Copyright (C) 2025 Nicolas Barrouillet <nicolas@pragma-tech.fr>
|
||||
|
|
@ -49,7 +49,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
|
|||
*/
|
||||
|
||||
// Load translation files required by the page
|
||||
$langs->loadLangs(array("accountancy", "categories", "compta"));
|
||||
$langs->loadLangs(array("accountancy", "categories", "compta", "other"));
|
||||
|
||||
$journal_code = GETPOST('code_journal', 'alpha');
|
||||
$account = GETPOST("account", 'int');
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ print "<br>\n";
|
|||
$texttoshow = $langs->trans("AccountancySetupDoneFromAccountancyMenu", '{s1}'.$langs->transnoentitiesnoconv("Accounting").' - '.$langs->transnoentitiesnoconv("Setup").'{s2}');
|
||||
$texttoshow = str_replace('{s1}', '<a href="'.dolBuildUrl(DOL_URL_ROOT.'/accountancy/index.php', ['mainmenu' => 'accountancy', 'leftmenu' => 'accountancy_admin', 'showtuto' => 1]).'">', $texttoshow);
|
||||
$texttoshow = str_replace('{s2}', '</a>'.img_picto("", "url", 'class="paddingleft"'), $texttoshow);
|
||||
print '<span class="opacitymedium">'.$texttoshow."</span><br>\n";
|
||||
print '<div class="info">'.$texttoshow."</div><br>\n";
|
||||
print "<br>\n";
|
||||
|
||||
llxFooter();
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ require_once DOL_DOCUMENT_ROOT.'/admin/remotestore/class/externalModules.class.p
|
|||
$langs->loadLangs(array("errors", "admin", "modulebuilder"));
|
||||
|
||||
$action = GETPOST('action', 'aZ09');
|
||||
$page = GETPOSTINT('page');
|
||||
$page_y = GETPOSTINT('page_y');
|
||||
$optioncss = GETPOST('optioncss', 'aZ09');
|
||||
$sortfield = GETPOST('sortfield', 'aZ09');
|
||||
|
|
@ -520,7 +521,7 @@ $i = 0; // is a sequencer of modules found
|
|||
$j = 0; // j is module number. Automatically affected if module number not defined.
|
||||
$modNameLoaded = array();
|
||||
|
||||
//if ($mode == 'common' || $mode == 'commonkanban') {
|
||||
|
||||
// Load $modules (required for the badge count)
|
||||
foreach ($modulesdir as $dir) {
|
||||
// Load modules attributes in arrays (name, numero, orders) from dir directory
|
||||
|
|
@ -1213,7 +1214,7 @@ if ($mode == 'common' || $mode == 'commonkanban') {
|
|||
print "</td>\n";
|
||||
|
||||
// Desc
|
||||
print '<td class="valignmiddle tdoverflowmax300 minwidth200imp">';
|
||||
print '<td class="valignmiddle tdoverflowmax300 minwidth200imp opacitylow">';
|
||||
print nl2br($objMod->getDesc());
|
||||
print "</td>\n";
|
||||
|
||||
|
|
|
|||
|
|
@ -821,6 +821,11 @@ class ActionComm extends CommonObject
|
|||
$result = $this->create($fuser);
|
||||
if ($result < 0) {
|
||||
$error++;
|
||||
} else {
|
||||
$resultcat = $this->cloneCategories($objFrom->id, $this->id);
|
||||
if ($resultcat < 0) {
|
||||
$error++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$error) {
|
||||
|
|
|
|||
|
|
@ -703,7 +703,7 @@ if ($action == 'create') {
|
|||
print '<table class="border centpercent tableforfield">';
|
||||
|
||||
// Type
|
||||
print '<tr><td class="titlefield">'.$langs->trans("AccountType").'</td>';
|
||||
print '<tr><td class="titlefieldmiddle">'.$langs->trans("AccountType").'</td>';
|
||||
print '<td>'.$object->type_lib[$object->type].'</td></tr>';
|
||||
|
||||
// Currency
|
||||
|
|
@ -739,10 +739,13 @@ if ($action == 'create') {
|
|||
print '<tr class="liste_titre_add"><td class="titlefield">'.$langs->trans("AccountancyCode").'</td>';
|
||||
print '<td>';
|
||||
if (isModEnabled('accounting')) {
|
||||
$accountingaccount = new AccountingAccount($db);
|
||||
$accountingaccount->fetch(0, $object->account_number, 1);
|
||||
|
||||
print $accountingaccount->getNomUrl(0, 1, 1, '', 1);
|
||||
if (empty($object->account_number)) {
|
||||
print img_warning($langs->trans("Mandatory"));
|
||||
} else {
|
||||
$accountingaccount = new AccountingAccount($db);
|
||||
$accountingaccount->fetch(0, $object->account_number, 1);
|
||||
print $accountingaccount->getNomUrl(0, 1, 1, '', 1);
|
||||
}
|
||||
} else {
|
||||
print $object->account_number;
|
||||
}
|
||||
|
|
@ -752,11 +755,11 @@ if ($action == 'create') {
|
|||
if (isModEnabled('accounting')) {
|
||||
print '<tr><td>'.$langs->trans("AccountancyJournal").'</td>';
|
||||
print '<td>';
|
||||
|
||||
if ($object->fk_accountancy_journal > 0) {
|
||||
if (empty($object->fk_accountancy_journal)) {
|
||||
print img_warning($langs->trans("Mandatory"));
|
||||
} elseif ($object->fk_accountancy_journal > 0) {
|
||||
$accountingjournal = new AccountingJournal($db);
|
||||
$accountingjournal->fetch($object->fk_accountancy_journal);
|
||||
|
||||
print $accountingjournal->getNomUrl(0, 1, 1, '', 1);
|
||||
}
|
||||
print '</td></tr>';
|
||||
|
|
@ -869,15 +872,15 @@ if ($action == 'create') {
|
|||
print nl2br($object->owner_address);
|
||||
print "</td></tr>\n";
|
||||
|
||||
print '<tr><td class="tdtop">'.$langs->trans("BankAccountOwnerZip").'</td>';
|
||||
print '<tr><td>'.$langs->trans("BankAccountOwnerZip").'</td>';
|
||||
print '<td>'.dol_escape_htmltag($object->owner_zip);
|
||||
print '</td></tr>';
|
||||
|
||||
print '<tr><td class="tdtop">'.$langs->trans("BankAccountOwnerTown").'</td>';
|
||||
print '<tr><td>'.$langs->trans("BankAccountOwnerTown").'</td>';
|
||||
print '<td>'.dol_escape_htmltag($object->owner_town);
|
||||
print '</td></tr>';
|
||||
|
||||
print '<tr><td class="tdtop">'.$langs->trans("BankAccountOwnerCountry").'</td>';
|
||||
print '<tr><td>'.$langs->trans("BankAccountOwnerCountry").'</td>';
|
||||
print '<td>';
|
||||
$object->owner_country_code = dol_getIdFromCode($db, $object->owner_country_id, 'c_country', 'rowid', 'code');
|
||||
$langs->load("dict");
|
||||
|
|
|
|||
|
|
@ -712,12 +712,16 @@ foreach ($accounts as $key => $type) {
|
|||
// Account number
|
||||
if (!empty($arrayfields['b.account_number']['checked'])) {
|
||||
print '<td class="tdoverflowmax250">';
|
||||
if (isModEnabled('accounting') && !empty($objecttmp->account_number)) {
|
||||
$accountingaccount = new AccountingAccount($db);
|
||||
$accountingaccount->fetch(0, $objecttmp->account_number, 1);
|
||||
print '<span title="'.dol_escape_htmltag($accountingaccount->account_number.' - '.$accountingaccount->label).'">';
|
||||
print $accountingaccount->getNomUrl(0, 1, 1, '', 0);
|
||||
print '</span>';
|
||||
if (isModEnabled('accounting')) {
|
||||
if (empty($objecttmp->account_number)) {
|
||||
print img_warning($langs->trans("Mandatory"));
|
||||
} else {
|
||||
$accountingaccount = new AccountingAccount($db);
|
||||
$accountingaccount->fetch(0, $objecttmp->account_number, 1);
|
||||
print '<span title="'.dol_escape_htmltag($accountingaccount->account_number.' - '.$accountingaccount->label).'">';
|
||||
print $accountingaccount->getNomUrl(0, 1, 1, '', 0);
|
||||
print '</span>';
|
||||
}
|
||||
} else {
|
||||
print '<span title="'.dol_escape_htmltag($objecttmp->account_number).'">'.$objecttmp->account_number.'</span>';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -402,6 +402,11 @@ if ($search_date_when_end) {
|
|||
// Add where from extra fields
|
||||
include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php';
|
||||
|
||||
// Add where from hooks
|
||||
$parameters = array();
|
||||
$reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
|
||||
$sql .= $hookmanager->resPrint;
|
||||
|
||||
if ($search_all) {
|
||||
$sql .= " AND EXISTS (SELECT fdc.rowid FROM ".MAIN_DB_PREFIX."facturedet_rec as fdc WHERE f.rowid = fdc.fk_facture ".natural_search(array_keys($fieldstosearchall), $search_all).")";
|
||||
}
|
||||
|
|
@ -854,6 +859,12 @@ if (!empty($arrayfields['f.tms']['checked'])) {
|
|||
}
|
||||
// Extra fields
|
||||
include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php';
|
||||
|
||||
// Hook fields
|
||||
$parameters = array('arrayfields'=>$arrayfields, 'param'=>$param, 'sortfield'=>$sortfield, 'sortorder'=>$sortorder, 'totalarray'=>$totalarray);
|
||||
$reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
|
||||
print $hookmanager->resPrint;
|
||||
|
||||
if (!empty($arrayfields['status']['checked'])) {
|
||||
print_liste_field_titre($arrayfields['status']['label'], $_SERVER['PHP_SELF'], "f.suspended,f.frequency", "", $param, '', $sortfield, $sortorder, 'center ');
|
||||
$totalarray['nbfield']++;
|
||||
|
|
|
|||
|
|
@ -1627,7 +1627,7 @@ if (getDolGlobalString('MAIN_VIEW_LINE_NUMBER_IN_LIST')) {
|
|||
// Ref
|
||||
if (!empty($arrayfields['f.ref']['checked'])) {
|
||||
print '<td class="liste_titre">';
|
||||
print '<input class="flat maxwidth50imp" type="text" name="search_ref" value="'.dol_escape_htmltag($search_ref).'">';
|
||||
print '<input class="flat maxwidth75imp" type="text" name="search_ref" value="'.dol_escape_htmltag($search_ref).'">';
|
||||
print '</td>';
|
||||
}
|
||||
// Ref customer
|
||||
|
|
|
|||
|
|
@ -1,58 +0,0 @@
|
|||
<?php
|
||||
/* Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
|
||||
*/
|
||||
|
||||
// Just for display errors in editor
|
||||
ini_set('display_errors', 1);
|
||||
|
||||
if (!defined('NOTOKENRENEWAL')) {
|
||||
define('NOTOKENRENEWAL', '1'); // Disables token renewal
|
||||
}
|
||||
if (!defined('NOREQUIREMENU')) {
|
||||
define('NOREQUIREMENU', '1');
|
||||
}
|
||||
if (!defined('NOREQUIREHTML')) {
|
||||
define('NOREQUIREHTML', '1');
|
||||
}
|
||||
if (!defined('NOREQUIREAJAX')) {
|
||||
define('NOREQUIREAJAX', '1');
|
||||
}
|
||||
if (!defined('NOREQUIRESOC')) {
|
||||
define('NOREQUIRESOC', '1');
|
||||
}
|
||||
require_once '../../main.inc.php';
|
||||
require_once DOL_DOCUMENT_ROOT.'/website/class/websitepage.class.php';
|
||||
|
||||
/**
|
||||
* @var Conf $conf
|
||||
* @var DoliDB $db
|
||||
* @var HookManager $hookmanager
|
||||
* @var Translate $langs
|
||||
* @var User $user
|
||||
*/
|
||||
|
||||
top_httphead();
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST' && GETPOSTISSET('selectedIds')) {
|
||||
$selectedIds = json_decode(GETPOST('selectedIds'), true);
|
||||
|
||||
$websitepage = new WebsitePage($db);
|
||||
$selectedPosts = array();
|
||||
|
||||
foreach ($selectedIds as $id) {
|
||||
$blog = new WebsitePage($db);
|
||||
$blog->fetch($id);
|
||||
|
||||
$selectedPosts[] = array(
|
||||
'id' => $blog->id,
|
||||
'title' => $blog->title,
|
||||
'description' => $blog->description,
|
||||
'date_creation' => $blog->date_creation,
|
||||
'image' => $blog->image,
|
||||
);
|
||||
}
|
||||
|
||||
print json_encode($selectedPosts);
|
||||
} else {
|
||||
print json_encode(array('error' => 'Invalid request'));
|
||||
}
|
||||
|
|
@ -52,6 +52,7 @@ require_once '../lib/files.lib.php';
|
|||
require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
|
||||
require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
|
||||
require_once DOL_DOCUMENT_ROOT.'/core/lib/website.lib.php';
|
||||
require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php';
|
||||
|
||||
$langs->load("mails");
|
||||
|
||||
|
|
@ -156,10 +157,11 @@ if (GETPOSTISSET('template')) {
|
|||
$content);
|
||||
|
||||
|
||||
$template = GETPOST('template', 'alpha');
|
||||
// Get list of selected news or products
|
||||
$selectedPostsStr = GETPOST('selectedPosts', 'alpha');
|
||||
$selectedIdsStr = GETPOST('selectedPosts', 'alpha');
|
||||
//$selectedPosts = array();
|
||||
$selectedPosts = json_decode($selectedPostsStr);
|
||||
$selectedIds = json_decode($selectedIdsStr);
|
||||
/*if (is_array($selectedPostsStr)) {
|
||||
$selectedPosts = explode(',', $selectedPostsStr);
|
||||
}*/
|
||||
|
|
@ -172,28 +174,43 @@ if (GETPOSTISSET('template')) {
|
|||
}
|
||||
} */
|
||||
|
||||
if (is_array($selectedPosts) && !empty($selectedPosts)) {
|
||||
if (!empty($selectedIds) && !empty($template) && is_array($selectedIds) ) {
|
||||
$newsList = '';
|
||||
$productList = '';
|
||||
foreach ($selectedIds as $Id) {
|
||||
if ($template == "news") {
|
||||
$post = getNewsDetailsById($Id);
|
||||
|
||||
foreach ($selectedPosts as $postId) {
|
||||
$post = getNewsDetailsById($postId);
|
||||
$newsList .= '<div style="display: flex; align-items: flex-start; justify-content: flex-start; width: 100%; max-width: 800px; margin-top: 20px;margin-bottom: 50px; padding: 20px;">
|
||||
<div style="flex-grow: 1; margin-right: 30px; max-width: 600px; margin-left: 100px;">
|
||||
<h2 style="margin: 0; font-size: 1.5em;">' . (empty($post['title']) ? '' : dol_htmlentitiesbr($post['title'])) . '</h2>
|
||||
<p style="margin: 10px 0; color: #555;">' . (empty($post['description']) ? '' : dol_htmlentitiesbr($post['description'])) . '</p>
|
||||
<span style="display: block; margin-bottom: 5px; color: #888;">Created By: <strong>' . dol_htmlentitiesbr(empty($post['user_fullname']) ? '' : $post['user_fullname']) . '</strong></span>
|
||||
<br>
|
||||
<span style="display: block; color: #888;">' . dol_print_date((empty($post['date_creation']) ? dol_now() : $post['date_creation']), 'daytext', 'tzserver', $langs) . '</span>
|
||||
</div>
|
||||
<div style="flex-shrink: 0; margin-left: 100px; float: right;">
|
||||
' . (!empty($post['image']) ? '<img alt="Image" width="130px" height="130px" style="border-radius: 10px;" src="' . DOL_URL_ROOT . '/viewimage.php?modulepart=medias&file=' . dol_htmlentitiesbr($post['image']) . '">' : '<img alt="Gray rectangle" width="130px" height="130px" style="border-radius: 10px;" src="__GRAY_RECTANGLE__">') . '
|
||||
</div>
|
||||
</div>';
|
||||
} elseif ($template == "product") {
|
||||
$product = getProductForEmailTemplate($Id);
|
||||
|
||||
$newsList .= '<div style="display: flex; align-items: flex-start; justify-content: flex-start; width: 100%; max-width: 800px; margin-top: 20px;margin-bottom: 50px; padding: 20px;">
|
||||
<div style="flex-grow: 1; margin-right: 30px; max-width: 600px; margin-left: 100px;">
|
||||
<h2 style="margin: 0; font-size: 1.5em;">' . htmlentities(empty($post['title']) ? '' : $post['title']) . '</h2>
|
||||
<p style="margin: 10px 0; color: #555;">' . htmlentities(empty($post['description']) ? '' : $post['description']) . '</p>
|
||||
<span style="display: block; margin-bottom: 5px; color: #888;">Created By: <strong>' . htmlentities(empty($post['user_fullname']) ? '' : $post['user_fullname']) . '</strong></span>
|
||||
<br>
|
||||
<span style="display: block; color: #888;">' . dol_print_date((empty($post['date_creation']) ? dol_now() : $post['date_creation']), 'daytext', 'tzserver', $langs) . '</span>
|
||||
</div>
|
||||
<div style="flex-shrink: 0; margin-left: 100px; float: right;">
|
||||
' . (!empty($post['image']) ? '<img alt="Image" width="130px" height="130px" style="border-radius: 10px;" src="' . DOL_URL_ROOT . '/viewimage.php?modulepart=medias&file=' . htmlentities($post['image']) . '">' : '<img alt="Gray rectangle" width="130px" height="130px" style="border-radius: 10px;" src="__GRAY_RECTANGLE__">') . '
|
||||
</div>
|
||||
</div>';
|
||||
$productList .= '<div style="width:100%; padding: 20px;">
|
||||
<div>
|
||||
' . (!empty($product['image']) ? dol_htmlentitiesbr($product['image']) : '<img alt="Gray rectangle" width="130px" height="130px" style="border-radius: 10px;" src="__GRAY_RECTANGLE__">') . '
|
||||
</div>
|
||||
<div>
|
||||
<h2>'.(dol_htmlentitiesbr($product["ref"])).(empty($product["label"]) ? '' : ' - '.dol_htmlentitiesbr($product["label"])).'</h2>
|
||||
<p style="margin: 10px 0; color: #555;">'. (empty($product['description']) ? '' : dol_htmlentitiesbr($product['description'])) .'</p>
|
||||
</div>
|
||||
</div>
|
||||
';
|
||||
}
|
||||
}
|
||||
|
||||
$content = str_replace('__NEWS_LIST__', $newsList, $content);
|
||||
$content = str_replace('__PRODUCT_SELECTED__', $newsList, $content);
|
||||
$content = str_replace('__PRODUCT_SELECTED__', $productList, $content);
|
||||
} else {
|
||||
$content = str_replace('__NEWS_LIST__', $langs->trans("SelectSomeArticlesOrEnterYourOwnContent"), $content);
|
||||
$content = str_replace('__PRODUCT_SELECTED__', $langs->trans("SelectOneArticleOrEnterYourOwnContent"), $content);
|
||||
|
|
|
|||
|
|
@ -11529,9 +11529,12 @@ abstract class CommonObject
|
|||
require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
|
||||
$categorystatic = new Categorie($this->db);
|
||||
|
||||
$sql = "INSERT INTO ".$this->db->prefix()."categorie_".(empty($categorystatic->MAP_CAT_TABLE[$type]) ? $type : $categorystatic->MAP_CAT_TABLE[$type])." (fk_categorie, fk_product)";
|
||||
$sql .= " SELECT fk_categorie, $toId FROM ".$this->db->prefix()."categorie_".(empty($categorystatic->MAP_CAT_TABLE[$type]) ? $type : $categorystatic->MAP_CAT_TABLE[$type]);
|
||||
$sql .= " WHERE fk_product = ".((int) $fromId);
|
||||
$tablename = $this->db->prefix()."categorie_".(empty($categorystatic->MAP_CAT_TABLE[$type]) ? $type : $categorystatic->MAP_CAT_TABLE[$type]);
|
||||
$fkname = 'fk_' . (empty($categorystatic->MAP_CAT_FK[$type]) ? $type : $categorystatic->MAP_CAT_FK[$type]);
|
||||
|
||||
$sql = "INSERT INTO ".$tablename." (fk_categorie, ".$fkname.")";
|
||||
$sql .= " SELECT fk_categorie, $toId FROM ".$tablename;
|
||||
$sql .= " WHERE ".$fkname." = ".((int) $fromId);
|
||||
|
||||
if (!$this->db->query($sql)) {
|
||||
$this->error = $this->db->lasterror();
|
||||
|
|
|
|||
|
|
@ -1146,6 +1146,10 @@ class ExtraFields
|
|||
$form = new Form($this->db);
|
||||
}
|
||||
|
||||
if ($mode == 1) { // When field is used for search input into a list, we limit its size.
|
||||
$morecss = 'maxwidth125';
|
||||
}
|
||||
|
||||
$parameters = array(
|
||||
'key' => $key,
|
||||
'value' => &$value,
|
||||
|
|
|
|||
|
|
@ -1578,11 +1578,28 @@ class FormMail extends Form
|
|||
}
|
||||
}
|
||||
|
||||
// Fetch Product / Services
|
||||
$productArray = array();
|
||||
if (isModEnabled('product') || isModEnabled('service')) {
|
||||
include_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
|
||||
$form = new Form($this->db);
|
||||
$arrayofproduct = $form->select_produits_list(0, 'product-select', '', 0, 0, '', 1, 2, 1);
|
||||
if (!empty($arrayofproduct)) {
|
||||
foreach ($arrayofproduct as $product) {
|
||||
$productArray[$product["key"]] = array(
|
||||
'id' => $product["key"],
|
||||
'label' => $product["value"].' - '.dol_trunc($product["label2"], 40),
|
||||
'labelhtml' => $product["value"].' - '.dol_trunc($product["label2"], 40),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Use the multiselect array function to create the dropdown
|
||||
$out .= '<div id="post-dropdown-container" class="email-layout-container hidden" style="height: 32px; display:none;">';
|
||||
$out .= '<label for="blogpost-select">Select Posts: </label>';
|
||||
$out .= '<!-- select component for selection of blog posts -->'."\n";
|
||||
$out .= self::multiselectarray('blogpost-select', $blogArray, array(), 0, 0, 'minwidth200');
|
||||
$out .= self::multiselectarray('blogpost-select', $blogArray, array(), 0, 0, 'minwidth200 select-template');
|
||||
$out .= ' <input type="submit" class="smallpaddingimp button" name="submit" id="post-submit" value="'.dolPrintHTMLForAttribute($langs->trans("Select")).'">';
|
||||
$out .= '</div>';
|
||||
|
||||
|
|
@ -1592,7 +1609,7 @@ class FormMail extends Form
|
|||
$out .= '<div id="product-dropdown-container" class="email-layout-container hidden" style="height: 32px; display:none;">';
|
||||
$out .= '<label for="product-select">'.img_picto('', 'product', 'class="pictofixedwidth"').$langs->trans("Product").' : </label>';
|
||||
$out .= '<!-- select component for selection of product -->'."\n";
|
||||
$out .= $form->select_produits(0, 'product-select', '', 0, 0, 1, 2, '', 0, array(), 0, '1', 0, '', 0, '', null, 1);
|
||||
$out .= self::multiselectarray('product-select', $productArray, array(), 0, 0, 'minwidth200 select-template');
|
||||
$out .= ' <input type="submit" class="smallpaddingimp button" name="submit" id="product-submit" value="'.dolPrintHTMLForAttribute($langs->trans("Select")).'">';
|
||||
$out .= '</div>';
|
||||
}
|
||||
|
|
@ -1612,6 +1629,7 @@ class FormMail extends Form
|
|||
|
||||
$(".template-option").removeClass("selected");
|
||||
$(this).addClass("selected");
|
||||
$(".select-template").val("").trigger("change");
|
||||
|
||||
if (template === "news") {
|
||||
$("#post-dropdown-container").show();
|
||||
|
|
@ -1659,46 +1677,38 @@ class FormMail extends Form
|
|||
|
||||
updateSelectedPostsContent(contentHtml, selectedIds);
|
||||
});
|
||||
$("#product-select").change(function() {
|
||||
var selectedIds = $(this).val();
|
||||
var contentHtml = $(".template-option.selected").data("content");
|
||||
|
||||
updateSelectedPostsContent(contentHtml, selectedIds);
|
||||
});
|
||||
|
||||
function updateSelectedPostsContent(contentHtml, selectedIds) {
|
||||
var csrfToken = "' .newToken().'";
|
||||
template = $(".template-option.selected").data("template");
|
||||
var subject = $("#subject").val();
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "'.dol_buildpath('/core/ajax/getnews.php', 1).'",
|
||||
url: "'.dol_buildpath('/core/ajax/mailtemplate.php', 1).'",
|
||||
data: {
|
||||
selectedIds: JSON.stringify(selectedIds),
|
||||
token : csrfToken
|
||||
token: csrfToken,
|
||||
template: template,
|
||||
subject: subject,
|
||||
selectedPosts: JSON.stringify(selectedIds)
|
||||
},
|
||||
success: function(response) {
|
||||
var selectedPosts = JSON.parse(response);
|
||||
var subject = $("#subject").val();
|
||||
contentHtml = contentHtml.replace(/__SUBJECT__/g, subject);
|
||||
template = $(".template-option.selected").data("template");
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "'.dol_buildpath('/core/ajax/mailtemplate.php', 1).'",
|
||||
data: {
|
||||
token: csrfToken,
|
||||
template: template,
|
||||
subject: subject,
|
||||
selectedPosts: JSON.stringify(selectedIds)
|
||||
},
|
||||
success: function(response) {
|
||||
jQuery("#'.$htmlContent.'").val(response);
|
||||
var editorInstance = CKEDITOR.instances["'.$htmlContent.'"];
|
||||
if (editorInstance) {
|
||||
editorInstance.setData(response);
|
||||
}
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
console.error("An error occurred: " + xhr.responseText);
|
||||
}
|
||||
});
|
||||
jQuery("#'.$htmlContent.'").val(response);
|
||||
var editorInstance = CKEDITOR.instances["'.$htmlContent.'"];
|
||||
if (editorInstance) {
|
||||
editorInstance.setData(response);
|
||||
}
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
console.error("An error occurred: " + xhr.responseText);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
</script>';
|
||||
|
|
|
|||
|
|
@ -167,6 +167,7 @@ class FormSetup
|
|||
|
||||
if ($editMode) {
|
||||
$out .= '<form ' . self::generateAttributesStringFromArray($this->formAttributes) . ' >';
|
||||
$out .= '<input type="hidden" name="page_y" value="">';
|
||||
|
||||
// generate hidden values from $this->formHiddenInputs
|
||||
if (!empty($this->formHiddenInputs) && is_array($this->formHiddenInputs)) {
|
||||
|
|
|
|||
|
|
@ -1925,16 +1925,21 @@ function dol_sanitizeFileName($str, $newstr = '_', $unaccent = 1, $includequotes
|
|||
*
|
||||
* @param string $str String to clean
|
||||
* @param string $newstr String to replace bad chars with
|
||||
* @param int $unaccent 1=Remove also accent (default), 0 do not remove them
|
||||
* @param int $unaccent 1=Remove also accent, 0 do not remove them
|
||||
* @param int $allowdash 1=Allow dash char after a space and before a string, 0 do not allow
|
||||
* @return string String cleaned
|
||||
*
|
||||
* @see dol_string_nospecial(), dol_string_unaccent(), dol_sanitizeFileName()
|
||||
*/
|
||||
function dol_sanitizePathName($str, $newstr = '_', $unaccent = 1)
|
||||
function dol_sanitizePathName($str, $newstr = '_', $unaccent = 0, $allowdash = 0)
|
||||
{
|
||||
// List of special chars for filenames in windows are defined on page https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file
|
||||
// Char '>' '<' '|' '$' and ';' are special chars for shells.
|
||||
// Chars '--' can be used into filename to inject special parameters like --use-compress-program to make command with file as parameter making remote execution of command
|
||||
// Char '>' '<' '|' '$' ';' and '`' are special chars for shells.
|
||||
// Char '?' and '*' are for wild card chars.
|
||||
// Char '"' is dangerous.
|
||||
// Char '°' is just not expected.
|
||||
// Chars '-' and '--' can be used into filename to inject special parameters like --use-compress-program to make command with file as parameter making remote execution of command
|
||||
// Chars '--' and '~' can be used for path transversal
|
||||
$filesystem_forbidden_chars = array('<', '>', '?', '*', '|', '"', '°', '$', ';', '`');
|
||||
|
||||
$tmp = $str;
|
||||
|
|
@ -1942,10 +1947,13 @@ function dol_sanitizePathName($str, $newstr = '_', $unaccent = 1)
|
|||
$tmp = dol_string_unaccent($tmp);
|
||||
}
|
||||
$tmp = dol_string_nospecial($tmp, $newstr, $filesystem_forbidden_chars);
|
||||
$tmp = preg_replace('/\-\-+/', '_', $tmp);
|
||||
$tmp = preg_replace('/\s+\-([^\s])/', ' _$1', $tmp);
|
||||
$tmp = preg_replace('/\s+\-$/', '', $tmp);
|
||||
$tmp = str_replace('..', '', $tmp);
|
||||
$tmp = preg_replace('/\-\-+/', $newstr, $tmp);
|
||||
if (empty($allowdash)) {
|
||||
$tmp = preg_replace('/\s+\-([^\s])/', ' '.$newstr.'$1', $tmp);
|
||||
$tmp = preg_replace('/\s+\-$/', '', $tmp);
|
||||
}
|
||||
$tmp = str_replace('..', $newstr, $tmp);
|
||||
$tmp = str_replace('~', $newstr, $tmp);
|
||||
return $tmp;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1024,3 +1024,42 @@ function measuring_units_cubed($unit)
|
|||
$measuring_units[99] = 89; // inch -> inch3
|
||||
return $measuring_units[$unit];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve and return product for mail template.
|
||||
*
|
||||
* @param int $id The ID of the product to retrieve.
|
||||
* @return array<string,mixed>|int<-1,-1> Return array if OK, -1 if KO
|
||||
*/
|
||||
function getProductForEmailTemplate($id)
|
||||
{
|
||||
require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
|
||||
global $db, $conf;
|
||||
|
||||
$productarray = array();
|
||||
$sql = "SELECT p.rowid as id, p.ref, p.label, p.description, p.entity";
|
||||
$sql .= " FROM ".MAIN_DB_PREFIX."product as p";
|
||||
$sql .= " WHERE p.entity IN (".getEntity('product').")";
|
||||
$sql .= " AND p.rowid = ".((int) $id);
|
||||
|
||||
$resql = $db->query($sql);
|
||||
|
||||
if ($resql) {
|
||||
$productarray = $db->fetch_array($resql);
|
||||
} else {
|
||||
dol_print_error($db);
|
||||
return -1;
|
||||
}
|
||||
|
||||
$object = new Product($db);
|
||||
$result = $object->fetch($id);
|
||||
if ($result < 0) {
|
||||
dol_print_error($db, $object->error, $object->errors);
|
||||
}
|
||||
$entity = (empty($object->entity) ? $conf->entity : $object->entity);
|
||||
$productarray["image"] = $object->show_photos('product', $conf->product->multidir_output[$entity], 1, 1, 0, 0, 0, 120, 160, 1, '');
|
||||
if ($object->nbphoto <= 0) {
|
||||
$productarray["image"] = "";
|
||||
}
|
||||
return $productarray;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2683,7 +2683,7 @@ class DolibarrModules // Can not be abstract, because we need to instantiate it
|
|||
|
||||
$return .= '</div>
|
||||
<div class="info-box-content info-box-text-module'.(!getDolGlobalString($const_name) ? '' : ' info-box-module-enabled'.($versiontrans ? ' info-box-content-warning' : '')).'">
|
||||
<span class="info-box-title">'.$this->getName().'</span>
|
||||
<span class="info-box-title noopacity">'.$this->getName().'</span>
|
||||
<span class="info-box-desc twolinesmax opacitymedium" title="'.dol_escape_htmltag($this->getDesc()).'">'.nl2br($this->getDesc()).'</span>';
|
||||
|
||||
$return .= '<div class="valignmiddle inline-block info-box-more">';
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ class modAccounting extends DolibarrModules
|
|||
[
|
||||
"MAIN_BANK_ACCOUNTANCY_CODE_ALWAYS_REQUIRED",
|
||||
"chaine",
|
||||
"1",
|
||||
"0",
|
||||
"With this constants on, bank account number is always required", 0, 'current', 1
|
||||
],
|
||||
[
|
||||
|
|
|
|||
|
|
@ -457,7 +457,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea
|
|||
include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_view.tpl.php';
|
||||
} else {
|
||||
// Login
|
||||
print '<tr><td class="titlefield">'.$langs->trans("Login").'</td>';
|
||||
print '<tr><td class="titlefieldmiddle">'.$langs->trans("Login").'</td>';
|
||||
if (!empty($object->ldap_sid) && $object->statut == 0) {
|
||||
print '<td class="error">';
|
||||
print $langs->trans("LoginAccountDisableInDolibarr");
|
||||
|
|
|
|||
|
|
@ -873,8 +873,8 @@ IMG;
|
|||
*
|
||||
* @param string $name Name of ODT file to generate before generating PDF
|
||||
* @param int $dooutputfordownload Output the file content to make the download
|
||||
* @throws OdfException
|
||||
* @return void
|
||||
* @throws OdfException
|
||||
* @return void
|
||||
*/
|
||||
public function exportAsAttachedPDF($name = "", $dooutputfordownload = 1)
|
||||
{
|
||||
|
|
@ -888,12 +888,11 @@ IMG;
|
|||
$execmethod = (getDolGlobalString('MAIN_EXEC_USE_POPEN') ? 2 : 1); // 1 or 2
|
||||
// Method 1 sometimes hang the server.
|
||||
|
||||
|
||||
// Export to PDF using LibreOffice
|
||||
if (getDolGlobalString('MAIN_ODT_AS_PDF') == 'libreoffice') {
|
||||
dol_mkdir($conf->user->dir_temp); // We must be sure the directory exists and is writable
|
||||
|
||||
// We delete and recreate a subdir because the soffice may have change pemrissions on it
|
||||
// We delete and recreate a subdir because the soffice may have change permissions on it
|
||||
$countdeleted = 0;
|
||||
dol_delete_dir_recursive($conf->user->dir_temp.'/odtaspdf', 0, 0, 0, $countdeleted, 0, 1);
|
||||
dol_mkdir($conf->user->dir_temp.'/odtaspdf');
|
||||
|
|
@ -902,8 +901,10 @@ IMG;
|
|||
// using windows libreoffice that must be in path
|
||||
// using linux/mac libreoffice that must be in path
|
||||
// Note PHP Config "fastcgi.impersonate=0" must set to 0 - Default is 1
|
||||
$command ='soffice --headless -env:UserInstallation=file:'.(getDolGlobalString('MAIN_ODT_ADD_SLASH_FOR_WINDOWS') ? '///' : '').'\''.$conf->user->dir_temp.'/odtaspdf\' --convert-to pdf --outdir '. escapeshellarg(dirname($name)). " ".escapeshellarg($name);
|
||||
$command ='soffice --headless -env:UserInstallation=file:'.escapeshellarg((getDolGlobalString('MAIN_ODT_ADD_SLASH_FOR_WINDOWS') ? '///' : '').dol_sanitizePathName($conf->user->dir_temp).'/odtaspdf').' --convert-to pdf --outdir '. escapeshellarg(dirname($name)). " ".escapeshellarg($name);
|
||||
} elseif (preg_match('/unoconv/', getDolGlobalString('MAIN_ODT_AS_PDF'))) {
|
||||
// This feature is now disabled by default. Must set var in conf.php to allow it.
|
||||
global $dolibarr_main_allow_unoconv;
|
||||
// If issue with unoconv, see https://github.com/dagwieers/unoconv/issues/87
|
||||
|
||||
// MAIN_ODT_AS_PDF should be "sudo -u unoconv /usr/bin/unoconv" and userunoconv must have sudo to be root by adding file /etc/sudoers.d/unoconv with content www-data ALL=(unoconv) NOPASSWD: /usr/bin/unoconv .
|
||||
|
|
@ -927,18 +928,22 @@ IMG;
|
|||
// If it fails:
|
||||
// - set shell of user to bash instead of nologin.
|
||||
// - set permission to read/write to user on home directory /var/www so user can create the libreoffice , dconf and .cache dir and files then set permission back
|
||||
|
||||
$command = getDolGlobalString('MAIN_ODT_AS_PDF').' '.escapeshellcmd($name);
|
||||
//$command = '/usr/bin/unoconv -vvv '.escapeshellcmd($name);
|
||||
if (!empty($dolibarr_main_allow_unoconv)) {
|
||||
$command = dol_sanitizePathName(getDolGlobalString('MAIN_ODT_AS_PDF'), '_', 0, 1).' '.escapeshellarg($name);
|
||||
//$command = '/usr/bin/unoconv -vvv '.escapeshellcmd($name);
|
||||
} else {
|
||||
throw new OdfException('Use of the unoconv method is deprecated. Try to use "libreoffice" method instead of set $dolibarr_main_allow_unoconv to 1 in conf.php for backward compatibility.');
|
||||
}
|
||||
} else {
|
||||
// deprecated old method using odt2pdf.sh (native, jodconverter, ...)
|
||||
$tmpname=preg_replace('/\.odt/i', '', $name);
|
||||
$tmpname = dol_sanitizePathName(preg_replace('/\.odt/i', '', $name));
|
||||
|
||||
if (getDolGlobalString('MAIN_DOL_SCRIPTS_ROOT')) {
|
||||
$command = getDolGlobalString('MAIN_DOL_SCRIPTS_ROOT').'/scripts/odt2pdf/odt2pdf.sh '.escapeshellcmd($tmpname).' '.(is_numeric(getDolGlobalString('MAIN_ODT_AS_PDF'))?'jodconverter':getDolGlobalString('MAIN_ODT_AS_PDF'));
|
||||
$paramodt2pdf = (is_numeric(getDolGlobalString('MAIN_ODT_AS_PDF')) ? 'jodconverter' : getDolGlobalString('MAIN_ODT_AS_PDF'));
|
||||
$paramodt2pdf = dol_sanitizePathName($paramodt2pdf);
|
||||
$command = dol_sanitizePathName(getDolGlobalString('MAIN_DOL_SCRIPTS_ROOT')).'/scripts/odt2pdf/odt2pdf.sh '.escapeshellarg($tmpname).' '.escapeshellarg($paramodt2pdf);
|
||||
} else {
|
||||
dol_syslog(get_class($this).'::exportAsAttachedPDF is used but the constant MAIN_DOL_SCRIPTS_ROOT with path to script directory was not defined.', LOG_WARNING);
|
||||
$command = '../../scripts/odt2pdf/odt2pdf.sh '.escapeshellcmd($tmpname).' '.(is_numeric(getDolGlobalString('MAIN_ODT_AS_PDF'))?'jodconverter':getDolGlobalString('MAIN_ODT_AS_PDF'));
|
||||
throw new OdfException('Use of the ODT to PDF convertion with odt2pdf.sh script is deprecated when option MAIN_DOL_SCRIPTS_ROOT to define path of scripts directory is no set.');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -946,6 +951,7 @@ IMG;
|
|||
//$command = DOL_DOCUMENT_ROOT.'/includes/odtphp/odt2pdf.sh '.$name.' '.$dirname;
|
||||
|
||||
dol_syslog(get_class($this).'::exportAsAttachedPDF $execmethod='.$execmethod.' Run command='.$command, LOG_DEBUG);
|
||||
|
||||
// TODO Use:
|
||||
// $outputfile = DOL_DATA_ROOT.'/odt2pdf.log';
|
||||
// $result = $utils->executeCLI($command, $outputfile); and replace test on $execmethod.
|
||||
|
|
@ -953,17 +959,17 @@ IMG;
|
|||
// $errorstring will be $result['output']
|
||||
$retval=0; $output_arr=array();
|
||||
if ($execmethod == 1) {
|
||||
exec($command, $output_arr, $retval);
|
||||
exec(escapeshellcmd($command), $output_arr, $retval);
|
||||
}
|
||||
if ($execmethod == 2) {
|
||||
$outputfile = DOL_DATA_ROOT.'/odt2pdf.log';
|
||||
|
||||
$ok=0;
|
||||
$handle = fopen($outputfile, 'w');
|
||||
if ($handle) {
|
||||
dol_syslog(get_class($this)."Run command ".$command, LOG_DEBUG);
|
||||
dol_syslog(get_class($this)."escapeshellcmd(command) = ".escapeshellcmd($command), LOG_DEBUG);
|
||||
fwrite($handle, $command."\n");
|
||||
$handlein = popen($command, 'r');
|
||||
$handlein = popen(escapeshellcmd($command), 'r');
|
||||
while (!feof($handlein)) {
|
||||
$read = fgets($handlein);
|
||||
fwrite($handle, $read);
|
||||
|
|
@ -987,6 +993,7 @@ IMG;
|
|||
|
||||
if (getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
|
||||
$name = preg_replace('/\.od(x|t)/i', '', $name);
|
||||
|
||||
header('Content-type: application/pdf');
|
||||
header('Content-Disposition: attachment; filename="' . basename($name) . '.pdf"');
|
||||
readfile($name . ".pdf");
|
||||
|
|
@ -1008,7 +1015,7 @@ IMG;
|
|||
foreach ($output_arr as $line) {
|
||||
$errorstring.= $line."<br>";
|
||||
}
|
||||
throw new OdfException('ODT to PDF convert fail (option MAIN_ODT_AS_PDF is '.$conf->global->MAIN_ODT_AS_PDF.', command was '.$command.', retval='.$retval.') : ' . $errorstring);
|
||||
throw new OdfException('ODT to PDF convert fail (option MAIN_ODT_AS_PDF is '.getDolGlobalString('MAIN_ODT_AS_PDF').', command was '.$command.', retval='.$retval.') : ' . $errorstring);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -448,8 +448,8 @@ if (!file_exists($conffile)) {
|
|||
|
||||
// Show title
|
||||
if (getDolGlobalString('MAIN_VERSION_LAST_UPGRADE') || getDolGlobalString('MAIN_VERSION_LAST_INSTALL')) {
|
||||
print $langs->trans("VersionLastUpgrade").' <b><span class="badge-text badge-secondary okinversed">'.getDolGlobalString('MAIN_VERSION_LAST_UPGRADE', getDolGlobalString('MAIN_VERSION_LAST_INSTALL')).'</span></b> - ';
|
||||
print $langs->trans("VersionProgram").' <b><span class="badge-text badge-secondary okinversed">'.DOL_VERSION.'</span></b>';
|
||||
print $langs->trans("VersionLastUpgrade").' <b><span class="badge-text okinversed">'.getDolGlobalString('MAIN_VERSION_LAST_UPGRADE', getDolGlobalString('MAIN_VERSION_LAST_INSTALL')).'</span></b> - ';
|
||||
print $langs->trans("VersionProgram").' <b><span class="badge-text okinversed">'.DOL_VERSION.'</span></b>';
|
||||
//print ' '.img_warning($langs->trans("RunningUpdateProcessMayBeRequired"));
|
||||
print '<br>';
|
||||
print '<br>';
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@
|
|||
}
|
||||
|
||||
.no-bottom {
|
||||
padding-bottom: 0;
|
||||
padding-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.small {
|
||||
|
|
|
|||
|
|
@ -178,7 +178,7 @@ if ($action == "set") { // Test on permissions not required here
|
|||
|
||||
$morehtml = '';
|
||||
|
||||
pHeader($langs->trans("DolibarrSetup"), "step5", 'set', '', '', 'main-inside main-inside-borderbottom');
|
||||
pHeader($langs->trans("DolibarrSetup"), "step5", 'set', '', '', 'main-inside main-inside-borderbottom no-bottom');
|
||||
print '<br>';
|
||||
|
||||
// Test if we can run a first install process
|
||||
|
|
|
|||
|
|
@ -7313,51 +7313,6 @@ class Product extends CommonObject
|
|||
$return .= '</div>';
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve and display products.
|
||||
*
|
||||
* @param int $limit The maximum number of results to return.
|
||||
* @return array<int, array<string, mixed>>|int return array if OK, -1 if KO
|
||||
*/
|
||||
public function getProductsToPreviewInEmail($limit)
|
||||
{
|
||||
|
||||
if (!is_numeric($limit)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
$sql = "SELECT p.rowid, p.ref, p.label, p.description, p.entity, ef.filename
|
||||
FROM ".MAIN_DB_PREFIX."product AS p
|
||||
JOIN ".MAIN_DB_PREFIX."ecm_files AS ef ON p.rowid = ef.src_object_id
|
||||
WHERE ef.entity IN (".getEntity('product').")
|
||||
AND (ef.filename LIKE '%.png' OR ef.filename LIKE '%.jpeg' OR ef.filename LIKE '%.svg')
|
||||
GROUP BY p.rowid, p.ref, p.label, p.description, p.entity, ef.filename
|
||||
ORDER BY p.datec ASC
|
||||
LIMIT " . ((int) $limit);
|
||||
|
||||
$resql = $this->db->query($sql);
|
||||
$products = array();
|
||||
|
||||
if ($resql) {
|
||||
while ($obj = $this->db->fetch_object($resql)) {
|
||||
$products[] = array(
|
||||
'rowid' => $obj->rowid,
|
||||
'ref' => $obj->ref,
|
||||
'label' => $obj->label,
|
||||
'description' => $obj->description,
|
||||
'entity' => $obj->entity,
|
||||
'filename' => $obj->filename
|
||||
);
|
||||
}
|
||||
} else {
|
||||
dol_print_error($this->db);
|
||||
}
|
||||
if (empty($products)) {
|
||||
return -1;
|
||||
}
|
||||
return $products;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -773,6 +773,9 @@ input.pageplusone {
|
|||
.opacitytransp {
|
||||
opacity: 0;
|
||||
}
|
||||
.noopacity {
|
||||
opacity: unset !important;
|
||||
}
|
||||
.colorwhite {
|
||||
color: var(--colorwhite);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -944,6 +944,9 @@ input.pageplusone {
|
|||
.opacitytransp {
|
||||
opacity: 0;
|
||||
}
|
||||
.noopacity {
|
||||
opacity: unset !important;
|
||||
}
|
||||
.colorwhite {
|
||||
color: var(--colorwhite);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
#!/bin/bash
|
||||
# @copyright GPL License 2010 - Vikas Mahajan - http://vikasmahajan.wordpress.com
|
||||
# @copyright GPL License 2013 - Florian HEnry - florian.henry@open-concept.pro
|
||||
# @copyright GPL License 2017 - Laurent Destailleur - eldy@users.sourceforge.net
|
||||
# @copyright GPL License 2019 - Camille Lafitte - cam.lafit@azerttyu.net
|
||||
# Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
|
||||
# Copyright (C) 2010 Vikas Mahajan http://vikasmahajan.wordpress.com
|
||||
# Copyright (C) 2013 Florian HEnry florian.henry@open-concept.pro
|
||||
# Copyright (C) 2017 Laurent Destailleur eldy@users.sourceforge.net
|
||||
# Copyright (C) 2019 Camille Lafitte cam.lafit@azerttyu.net
|
||||
# Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
|
||||
#
|
||||
# Convert an ODT into a PDF using "native" or "jodconverter" or "pyodconverter" or "unoconv" tool.
|
||||
# Convert an ODT into a PDF using "native" or "jodconverter" or "pyodconverter".
|
||||
# Dolibarr variable MAIN_ODT_AS_PDF must be defined ...
|
||||
# to value "libreoffice" to call soffice native exporter feature (in such a case, this script is useless)
|
||||
# or value "unoconv" to call unoconv CLI tool after ODT generation.
|
||||
|
|
@ -21,8 +21,7 @@
|
|||
|
||||
if [ "$1" = "" ] || [ "$2" = "" ]
|
||||
then
|
||||
echo "Usage: odt2pdf.sh fullfilename [native|unoconv|jodconverter|pyodconverter|pathtojodconverterjar|pandoc]"
|
||||
echo "Example: odt2pdf.sh myfile unoconv"
|
||||
echo "Usage: odt2pdf.sh fullfilename [native|jodconverter|pyodconverter|pathtojodconverterjar|pandoc]"
|
||||
echo "Example: odt2pdf.sh myfile ~/jodconverter/jodconverter-cli-2.2.2.jar"
|
||||
exit
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -2046,4 +2046,44 @@ class FunctionsLibTest extends CommonClassTest
|
|||
$this->assertEquals("1", $result[0]);
|
||||
$this->assertEquals("0", $result[1]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* testDolSanitizePathName
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testDolSanitizePathName()
|
||||
{
|
||||
global $conf,$user,$langs,$db;
|
||||
$conf = $this->savconf;
|
||||
$user = $this->savuser;
|
||||
$langs = $this->savlangs;
|
||||
$db = $this->savdb;
|
||||
|
||||
$s = '../aéa/bbb ccc/ddd';
|
||||
$result = dol_sanitizePathName($s);
|
||||
$this->assertEquals('_/aéa/bbb ccc/ddd', $result);
|
||||
|
||||
$s = '../aéa/bbb ccc/ddd';
|
||||
$result = dol_sanitizePathName($s, '_', 1);
|
||||
$this->assertEquals('_/aea/bbb ccc/ddd', $result);
|
||||
|
||||
$s = 'C:\ccc/d\'d"d$';
|
||||
$result = dol_sanitizePathName($s);
|
||||
$this->assertEquals('C:\ccc/d\'d_d_', $result);
|
||||
|
||||
$s = 'C:\ccc/d\'d"d$';
|
||||
$result = dol_sanitizePathName($s);
|
||||
$this->assertEquals('C:\ccc/d\'d_d_', $result);
|
||||
|
||||
$s = '/aaa/bbb -a -b';
|
||||
$result = dol_sanitizePathName($s);
|
||||
$this->assertEquals('/aaa/bbb _a _b', $result);
|
||||
|
||||
$s = '/aaa/bbb -a -b';
|
||||
$result = dol_sanitizePathName($s, '_', 0, 1);
|
||||
$this->assertEquals('/aaa/bbb -a -b', $result);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue