Files
CRM/modules/ModTracker/ModTrackerHandler.php
BACHIR SOULDI 2a647b138a 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.
2026-02-17 15:59:31 +01:00

252 lines
8.5 KiB
PHP

<?php
/*+**********************************************************************************
* The contents of this file are subject to the vtiger CRM Public License Version 1.0
* ("License"); You may not use this file except in compliance with the License
* The Original Code is: vtiger CRM Open Source
* The Initial Developer of the Original Code is vtiger.
* Portions created by vtiger are Copyright (C) vtiger.
* All Rights Reserved.
************************************************************************************/
require_once dirname(__FILE__) . '/ModTracker.php';
require_once 'data/VTEntityDelta.php';
class ModTrackerHandler extends VTEventHandler
{
function handleEvent($eventName, $data)
{
global $adb, $current_user;
$moduleName = $data->getModuleName();
$isTrackingEnabled = ModTracker::isTrackingEnabledForModule($moduleName);
if (!$isTrackingEnabled) {
return;
}
if ($eventName == 'vtiger.entity.aftersave.final') {
$recordId = $data->getId();
$columnFields = $data->getData();
$vtEntityDelta = new VTEntityDelta();
$delta = $vtEntityDelta->getEntityDelta($moduleName, $recordId, true);
$newerEntity = $vtEntityDelta->getNewEntity($moduleName, $recordId);
$newerColumnFields = $newerEntity->getData();
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) {
$checkRecordPresentResult = $adb->pquery('SELECT * FROM vtiger_modtracker_basic WHERE crmid = ? AND status = ?', array($recordId, ModTracker::$CREATED));
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') {
$date_var = date("Y-m-d H:i:s");
$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
));
$inserted = true;
}
$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') {
$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));
}
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));
}
}
}