feat: Enhance email functionality and PDF generation for Sales Orders
- Enabled SMTP debugging in PHPMailer for better error tracking. - Added a "Test send email" link in the Inventory Detail View for quick email testing. - Implemented automatic PDF generation and email sending upon Sales Order creation. - Created a new action for sending Sales Order emails with attached PDFs. - Added a new AJAX action for testing outgoing email server configurations. - Updated outgoing server settings to use new SMTP credentials. - Improved email templates for better user experience. - Added test scripts for validating PDF generation and email sending.
This commit is contained in:
@@ -7,19 +7,21 @@
|
||||
* Portions created by vtiger are Copyright (C) vtiger.
|
||||
* All Rights Reserved.
|
||||
************************************************************************************/
|
||||
require_once dirname(__FILE__) .'/ModTracker.php';
|
||||
require_once dirname(__FILE__) . '/ModTracker.php';
|
||||
require_once 'data/VTEntityDelta.php';
|
||||
|
||||
class ModTrackerHandler extends VTEventHandler {
|
||||
class ModTrackerHandler extends VTEventHandler
|
||||
{
|
||||
|
||||
function handleEvent($eventName, $data) {
|
||||
function handleEvent($eventName, $data)
|
||||
{
|
||||
global $adb, $current_user;
|
||||
$moduleName = $data->getModuleName();
|
||||
$isTrackingEnabled = ModTracker::isTrackingEnabledForModule($moduleName);
|
||||
if(!$isTrackingEnabled) {
|
||||
if (!$isTrackingEnabled) {
|
||||
return;
|
||||
}
|
||||
if($eventName == 'vtiger.entity.aftersave.final') {
|
||||
if ($eventName == 'vtiger.entity.aftersave.final') {
|
||||
$recordId = $data->getId();
|
||||
$columnFields = $data->getData();
|
||||
$vtEntityDelta = new VTEntityDelta();
|
||||
@@ -28,50 +30,222 @@ class ModTrackerHandler extends VTEventHandler {
|
||||
$newerEntity = $vtEntityDelta->getNewEntity($moduleName, $recordId);
|
||||
$newerColumnFields = $newerEntity->getData();
|
||||
|
||||
if(is_array($delta)) {
|
||||
|
||||
if ($moduleName === 'SalesOrder') {
|
||||
|
||||
$recordId = $data->getId();
|
||||
$focus = CRMEntity::getInstance($moduleName);
|
||||
$focus->retrieve_entity_info($recordId, $moduleName);
|
||||
|
||||
$accountId = $focus->column_fields['account_id'];
|
||||
if (empty($accountId)) return;
|
||||
|
||||
$toEmail = "souldibachir3150@gmail.com";
|
||||
// $toEmail = getSingleFieldValue('vtiger_account', 'email1', 'accountid', $accountId);
|
||||
if (empty($toEmail)) return;
|
||||
|
||||
|
||||
/** -----------------------------------------------------------
|
||||
* 🔥 Secure ExportPDF with login cookie (your working version)
|
||||
* ----------------------------------------------------------- */
|
||||
|
||||
ob_clean();
|
||||
|
||||
$loginUrl = "https://sophal.net/sophalcrm/index.php?module=Users&action=Login";
|
||||
$exportUrl = "https://sophal.net/sophalcrm/index.php?module=SalesOrder&action=ExportPDF&record=$recordId";
|
||||
|
||||
// 1) Login
|
||||
$post = http_build_query([
|
||||
'username' => 'admin', // ⚠️ Replace later with "pdfbot"
|
||||
'password' => 'Sophal@Crm@Sophal', // ⚠️ Replace later with another password
|
||||
]);
|
||||
|
||||
$contextLogin = stream_context_create([
|
||||
'http' => [
|
||||
'method' => 'POST',
|
||||
'header' => "Content-Type: application/x-www-form-urlencoded\r\n",
|
||||
'content' => $post,
|
||||
]
|
||||
]);
|
||||
|
||||
file_get_contents($loginUrl, false, $contextLogin);
|
||||
|
||||
// Extract session cookie
|
||||
$cookies = [];
|
||||
foreach ($http_response_header as $hdr) {
|
||||
if (stripos($hdr, 'Set-Cookie:') === 0) {
|
||||
$cookies[] = trim(substr($hdr, 11), ';');
|
||||
}
|
||||
}
|
||||
$cookieHeader = 'Cookie: ' . implode('; ', $cookies);
|
||||
|
||||
// 2) Download PDF
|
||||
$contextPDF = stream_context_create([
|
||||
'http' => [
|
||||
'method' => 'GET',
|
||||
'header' => $cookieHeader
|
||||
]
|
||||
]);
|
||||
|
||||
$pdfContent = file_get_contents($exportUrl, false, $contextPDF);
|
||||
|
||||
// 3) Validate
|
||||
if (strpos($pdfContent, '%PDF') !== 0) {
|
||||
error_log("❌ ExportPDF returned invalid PDF for SalesOrder #$recordId");
|
||||
return;
|
||||
}
|
||||
|
||||
// 4) Save to storage
|
||||
$pdfPath = "storage/SalesOrder_{$recordId}.pdf";
|
||||
$filePath = $_SERVER['DOCUMENT_ROOT']."/sophalcrm/storage/SalesOrder_$recordId.pdf";
|
||||
file_put_contents($filePath, $pdfContent);
|
||||
|
||||
ob_end_clean();
|
||||
|
||||
|
||||
/** -----------------------------------------------------------
|
||||
* 📧 Email body + send
|
||||
* ----------------------------------------------------------- */
|
||||
|
||||
$subject = "Sales Order #" . $focus->column_fields['salesorder_no'];
|
||||
$body = '<html>
|
||||
<body style="font-family: Arial, sans-serif; background-color:#f5f5f5; margin:0; padding:0;">
|
||||
|
||||
<!-- HEADER -->
|
||||
<table width="100%" cellpadding="0" cellspacing="0" style="background-color:#0d6efd; padding:20px 0;">
|
||||
<tr>
|
||||
<td align="center">
|
||||
<img src="https://sophal.net/sophalcrm/layouts/v7/skins/images/favicon.ico" alt="SOPHAL SPA" style="max-height:60px;">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" style="color:#ffffff; font-size:20px; padding-top:10px;">
|
||||
<strong>SOPHAL SPA</strong>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- BODY -->
|
||||
<table width="100%" cellpadding="0" cellspacing="0" style="padding:30px;">
|
||||
<tr>
|
||||
<td style="background:#ffffff; padding:25px; border-radius:8px;">
|
||||
|
||||
<p>Bonjour <strong>'.$accountId.'</strong>,</p>
|
||||
|
||||
<p>Votre <strong>bon de commande n° '.$focus->column_fields['salesorder_no'].'</strong> est maintenant disponible.</p>
|
||||
<p>Vous pouvez le télécharger en cliquant sur le bouton ci-dessous :</p>
|
||||
|
||||
<!-- DOWNLOAD BUTTON -->
|
||||
<p style="text-align:center; margin:30px 0;">
|
||||
<a href="https://sophal.net/sophalcrm/'.$pdfPath.'"
|
||||
style="
|
||||
background-color:#0d6efd;
|
||||
color:#ffffff;
|
||||
padding:14px 28px;
|
||||
text-decoration:none;
|
||||
font-size:16px;
|
||||
border-radius:6px;
|
||||
display:inline-block;
|
||||
font-weight:bold;
|
||||
">
|
||||
📄 Télécharger le Bon de Commande
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<p style="color:#b00; font-size:13px; margin-top:20px;">
|
||||
⚠️ Ceci est un email automatique. Merci de ne pas répondre à ce message.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Pour toute assistance, veuillez contacter notre service client :<br>
|
||||
📞 +213541229487<br>
|
||||
✉️ COMMERCIAL@SOPHAL.DZ
|
||||
</p>
|
||||
|
||||
<p>Cordialement,<br>
|
||||
<strong>SOPHAL SPA</strong></p>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- FOOTER -->
|
||||
<table width="100%" cellpadding="0" cellspacing="0" style="background:#f0f0f0; padding:15px 0; border-top:1px solid #ddd;">
|
||||
<tr>
|
||||
<td align="center" style="font-size:12px; color:#666;">
|
||||
© 2025 SOPHAL SPA — Tous droits réservés.<br>
|
||||
HASSI BEN OKBA ORAN
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</body>
|
||||
</html>';
|
||||
|
||||
// Send email
|
||||
$outgoingModel = Settings_Vtiger_Systems_Model::getInstanceFromServerType('email', 'OutgoingServer');
|
||||
$outgoingModel->pdf_path = $pdfPath;
|
||||
$outgoingModel->to_email = $toEmail;
|
||||
|
||||
$ajaxAction = new Settings_Vtiger_OutgoingServerAjax_Action();
|
||||
$ajaxAction->sendTestMail($outgoingModel, $subject, $body, $pdfPath);
|
||||
}
|
||||
|
||||
|
||||
if (is_array($delta)) {
|
||||
$inserted = false;
|
||||
foreach($delta as $fieldName => $values) {
|
||||
if($fieldName != 'modifiedtime') {
|
||||
if(!$inserted) {
|
||||
foreach ($delta as $fieldName => $values) {
|
||||
if ($fieldName != 'modifiedtime') {
|
||||
if (!$inserted) {
|
||||
$checkRecordPresentResult = $adb->pquery('SELECT * FROM vtiger_modtracker_basic WHERE crmid = ? AND status = ?', array($recordId, ModTracker::$CREATED));
|
||||
if(!$adb->num_rows($checkRecordPresentResult) && $data->isNew()) {
|
||||
if (!$adb->num_rows($checkRecordPresentResult) && $data->isNew()) {
|
||||
$status = ModTracker::$CREATED;
|
||||
} else {
|
||||
$status = ModTracker::$UPDATED;
|
||||
}
|
||||
$this->id = $adb->getUniqueId('vtiger_modtracker_basic');
|
||||
$changedOn = $newerColumnFields['modifiedtime'];
|
||||
if($moduleName == 'Users') {
|
||||
if ($moduleName == 'Users') {
|
||||
$date_var = date("Y-m-d H:i:s");
|
||||
$changedOn = $adb->formatDate($date_var,true);
|
||||
$changedOn = $adb->formatDate($date_var, true);
|
||||
}
|
||||
$adb->pquery('INSERT INTO vtiger_modtracker_basic(id, crmid, module, whodid, changedon, status)
|
||||
VALUES(?,?,?,?,?,?)', Array($this->id, $recordId, $moduleName,
|
||||
$current_user->id, $changedOn, $status));
|
||||
VALUES(?,?,?,?,?,?)', array(
|
||||
$this->id,
|
||||
$recordId,
|
||||
$moduleName,
|
||||
$current_user->id,
|
||||
$changedOn,
|
||||
$status
|
||||
));
|
||||
$inserted = true;
|
||||
}
|
||||
$adb->pquery('INSERT INTO vtiger_modtracker_detail(id,fieldname,prevalue,postvalue) VALUES(?,?,?,?)',
|
||||
Array($this->id, $fieldName, $values['oldValue'], $values['currentValue']));
|
||||
$adb->pquery(
|
||||
'INSERT INTO vtiger_modtracker_detail(id,fieldname,prevalue,postvalue) VALUES(?,?,?,?)',
|
||||
array($this->id, $fieldName, $values['oldValue'], $values['currentValue'])
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
header("Location: index.php");
|
||||
exit;
|
||||
}
|
||||
|
||||
if($eventName == 'vtiger.entity.beforedelete') {
|
||||
if ($eventName == 'vtiger.entity.beforedelete') {
|
||||
$recordId = $data->getId();
|
||||
$columnFields = $data->getData();
|
||||
$id = $adb->getUniqueId('vtiger_modtracker_basic');
|
||||
$adb->pquery('INSERT INTO vtiger_modtracker_basic(id, crmid, module, whodid, changedon, status)
|
||||
VALUES(?,?,?,?,?,?)', Array($id, $recordId, $moduleName, $current_user->id, date('Y-m-d H:i:s',time()), ModTracker::$DELETED));
|
||||
VALUES(?,?,?,?,?,?)', array($id, $recordId, $moduleName, $current_user->id, date('Y-m-d H:i:s', time()), ModTracker::$DELETED));
|
||||
}
|
||||
|
||||
if($eventName == 'vtiger.entity.afterrestore') {
|
||||
if ($eventName == 'vtiger.entity.afterrestore') {
|
||||
$recordId = $data->getId();
|
||||
$columnFields = $data->getData();
|
||||
$id = $adb->getUniqueId('vtiger_modtracker_basic');
|
||||
$adb->pquery('INSERT INTO vtiger_modtracker_basic(id, crmid, module, whodid, changedon, status)
|
||||
VALUES(?,?,?,?,?,?)', Array($id, $recordId, $moduleName, $current_user->id, date('Y-m-d H:i:s',time()), ModTracker::$RESTORED));
|
||||
VALUES(?,?,?,?,?,?)', array($id, $recordId, $moduleName, $current_user->id, date('Y-m-d H:i:s', time()), ModTracker::$RESTORED));
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
Reference in New Issue
Block a user