mirror of
https://github.com/Dolibarr/dolibarr.git
synced 2026-02-08 00:52:01 +01:00
Fix fill news & product on email template (#36756)
* Fix fill news & product on email template * fix CI * Update mailtemplate.php --------- Co-authored-by: Lucas Marcouiller <lmarcouiller@dolicloud.com> Co-authored-by: Laurent Destailleur <eldy@destailleur.fr>
This commit is contained in:
committed by
GitHub
parent
ac36cda432
commit
e0f3ee85ca
@@ -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);
|
||||
|
||||
@@ -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>';
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user