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:
BACHIR SOULDI
2026-02-17 15:59:31 +01:00
parent 2794e62571
commit 2a647b138a
46 changed files with 25100 additions and 1296 deletions

View File

@@ -2,7 +2,7 @@
<?php
<?php
@@ -16,131 +16,161 @@ vimport ('includes.runtime.EntryPoint');
$current_user = Users_Record_Model::getCurrentUserModel();
$current_user = Users_Record_Model::getCurrentUserModel();
$current_user->set('activity_view', 'Today');
$current_user->set('activity_view', 'Today');
$current_user->set('submenuhide', true);
$current_user->set('submenuhide', true);
$current_user->set('leftpanelhide', true);
$current_user->set('leftpanelhide', true);
$roleid = $current_user->get('roleid');
$roleid = $current_user->get('roleid');
$_SESSION["roleid"]= $roleid ;
$viewer = new Vtiger_Viewer();
$viewer = new Vtiger_Viewer();
$viewer->assign('MODULE', 'Calendar');
$viewer->assign('MODULE', 'Calendar');
$viewer->assign('VIEW', 'Calendar');
$viewer->assign('VIEW', 'Calendar');
$viewer->assign('SELECTED_MENU_CATEGORY', 'SALES');
$viewer->assign('SELECTED_MENU_CATEGORY', 'SALES');
$viewer->assign('COMPANY_LOGO', Vtiger_CompanyDetails_Model::getInstanceById()->getLogo());
$viewer->assign('COMPANY_LOGO', Vtiger_CompanyDetails_Model::getInstanceById()->getLogo());
$viewer->assign('COMPANY_DETAILS_SETTINGS',new Settings_Vtiger_CompanyDetails_Model());
$viewer->assign('COMPANY_DETAILS_SETTINGS',new Settings_Vtiger_CompanyDetails_Model());
$viewer->assign('USER_MODEL', $current_user );
$viewer->assign('USER_MODEL', $current_user );
$viewer->assign('CURRENT_USER_MODEL', $current_user);
$viewer->assign('CURRENT_USER_MODEL', $current_user);
$viewer->assign('CURRENT_USER', $current_user);
$viewer->assign('CURRENT_USER', $current_user);
$viewer->assign('SEARCHABLE_MODULES', Vtiger_Module_Model::getSearchableModules());
$viewer->assign('SEARCHABLE_MODULES', Vtiger_Module_Model::getSearchableModules());
$viewer->assign('LANGUAGE_STRINGS', Vtiger_Language_Handler::export('Calendar', 'jsLanguageStrings'));
$viewer->assign('LANGUAGE_STRINGS', Vtiger_Language_Handler::export('Calendar', 'jsLanguageStrings'));
$detailViewModel = Vtiger_Module_Model::getInstance('Calendar');
$detailViewModel = Vtiger_Module_Model::getInstance('Calendar');
$linkParams = array('MODULE'=>'Calendar', 'ACTION'=>'Calendar');
$linkParams = array('MODULE'=>'Calendar', 'ACTION'=>'Calendar');
$linkModels = $detailViewModel->getSideBarLinks($linkParams);
$linkModels = $detailViewModel->getSideBarLinks($linkParams);
$viewer->assign('QUICK_LINKS', $linkModels);
$viewer->assign('QUICK_LINKS', $linkModels);
$viewer->assign('PAGETITLE','MA TOURNEE');
$viewer->assign('PAGETITLE','MA TOURNEE');
//$viewer->assign('IS_CREATE_PERMITTED', isPermitted('Calendar', 'CreateView'));
//$viewer->assign('IS_CREATE_PERMITTED', isPermitted('Calendar', 'CreateView'));
$viewer->view('CalendarViewPreProcess.tpl', 'Calendar');
$viewer->view('CalendarViewPreProcess.tpl', 'Calendar');
global $dbconfig;
global $adb;
$query = "SHOW FULL TABLES IN {$dbconfig['db_name']} WHERE TABLE_TYPE LIKE 'VIEW';";
$sql_get_result = $adb->query($query);
$result = array();
while ($recordinfo = $adb->fetch_array($sql_get_result)) {
$result[] = $recordinfo;
}
// $filter = [];
// $sub = (getMySubordinates($roleid));
// $flag = false;
// foreach ($sub as $key => $value) {
// array_push($filter, $value);
// };
// $visiteurs = [];
// $user_query = 'select * from comptes_medecins';
// $result2 = $adb->query($user_query);
// while ($row = $adb->fetchByAssoc($result2)) {
// if (in_array($row['visiteur1'], $filter) || in_array($row['visiteur2'], $filter) || in_array($row['visiteur3'], $filter) || in_array($row['visiteur3'], $filter)) {
// array_push($visiteurs, $row);
// }
// }
global $dbconfig;
// echo "<pre>";
// var_dump($filter);
// var_dump($visiteurs);
// echo "</pre>";
// die();
if ($roleid == 'H8')
$result = [['tables_in_sophalnexscrmnew2' => 'comptes_medecins'], ['tables_in_sophalnexscrmnew2' => 'comptes_pharmacies'], ['tables_in_sophalnexscrmnew2' => 'full_activity']];
if ($roleid == 'H17' || $roleid == 'H18' || $roleid == 'H20' || $roleid == 'H21' || $roleid == 'H24' || $roleid == 'H25' || $roleid == 'H26' || $roleid == 'H39') {
$result = [['tables_in_sophalnexscrmnew2' => 'comptes_medecins'], ['tables_in_sophalnexscrmnew2' => 'full_activity']];
// ['tables_in_sophalnexscrmnew2' => 'comptes_pharmacies'],
}
global $adb;
if ($roleid == 'H34' || $roleid == 'H36' || $roleid == 'H38' || $roleid == 'H42' || $roleid == 'H44') {
$query = "SHOW FULL TABLES IN {$dbconfig['db_name']} WHERE TABLE_TYPE LIKE 'VIEW';";
$result = [['tables_in_sophalnexscrmnew2' => 'bc_produits'], ['tables_in_sophalnexscrmnew2' => 'bon_de_commande']];
}
$sql_get_result = $adb->query($query);
$result = array();
while ($recordinfo = $adb->fetch_array($sql_get_result)) {
$result[] = $recordinfo;
}
if ($roleid == 'H8')
$result = [['tables_in_sophalnexscrmnew' => 'comptes_medecins' ], ['tables_in_sophalnexscrmnew' => 'comptes_pharmacies'], ['tables_in_sophalnexscrmnew' => 'full_activity']];
if ($roleid == 'H17' || $roleid == 'H18' || $roleid == 'H20' || $roleid == 'H21' || $roleid == 'H24' || $roleid == 'H25' || $roleid == 'H26' || $roleid == 'H39'){
$result = [['tables_in_sophalnexscrmnew' => 'comptes_medecins' ],['tables_in_sophalnexscrmnew' => 'comptes_pharmacies'],['tables_in_sophalnexscrmnew' => 'full_activity']];
}
echo '<br><br>
echo '<br><br>
<form action="ExportTable.php">';
if ($roleid == 'H8')
if ($roleid == 'H8')
echo '<input type="hidden" name="xls" value=true>';
echo '<input type="hidden" name="xls" value=true>';
echo '<div id="btndiv">
echo '<div id="btndiv">
<select id="table" class="form-control" name="table" style="font-size: 16px; font-weight: bold; width: 200px"> ';
<select id="table" class="form-control" name="table" style="font-size: 16px; font-weight: bold; width: 200px"> ';
$rowcolumn = 'tables_in_'.$dbconfig['db_name'];
$rowcolumn = 'tables_in_'.$dbconfig['db_name'];
foreach ($result as $row) {
foreach ($result as $row) {
echo '<option value="'.$row[$rowcolumn].'">'.$row[$rowcolumn].'</option>';
echo '<option value="'.$row[$rowcolumn].'">'.$row[$rowcolumn].'</option>';
}
}
echo '</select><br><br>
echo '</select><br><br>
<button id="exportbtn" type="submit" class="btn btn-default addButton"> Export</button>
@@ -148,13 +178,13 @@ vimport ('includes.runtime.EntryPoint');
</div></form>';
$viewer->view('CustomDashboardFooter.tpl');
$viewer->view('CustomDashboardFooter.tpl');
?>
?>
@@ -168,133 +198,133 @@ vimport ('includes.runtime.EntryPoint');
:root {
:root {
--gray-color: rgb(220, 220, 220);
--gray-color: rgb(220, 220, 220);
--light-gray-color: rgb(240, 240, 240);
--light-gray-color: rgb(240, 240, 240);
--my-color: rgb(20, 160, 217);
--my-color: rgb(20, 160, 217);
}
}
.addButton {
.addButton {
margin-left: 10px;
margin-left: 10px;
}
}
.addButton2 {
.addButton2 {
margin-left: 30px;
margin-left: 30px;
}
}
#btndiv {
#btndiv {
margin-left: 0px;
margin-left: 0px;
height:50px;
height:50px;
}
}
#maintab {
#maintab {
margin-left: 0px;
margin-left: 0px;
width: calc (100% - 550px) !important;
width: calc (100% - 550px) !important;
}
}
.gps-control {
.gps-control {
display: none;
display: none;
}
}
#map {
#map {
width: calc(100%);
height: calc(100% - 150px);
width: calc(100%);
background: rgba(140, 140, 140, 1);
height: calc(100% - 150px);
}
background: rgba(140, 140, 140, 1);
}
#msg{
top: calc(100% - 100px);
#msg{
width: calc(100% - 30px);
top: calc(100% - 100px);
height: 100px;
width: calc(100% - 30px);
}
height: 100px;
}
.leaflet-routing-container {
display: none;
.leaflet-routing-container {
}
display: none;
}
.closed {
max-height: 0;
.closed {
z-index: -1;
max-height: 0;
visibility: hidden;
z-index: -1;
}
visibility: hidden;
}
.opened {
max-height: calc(100% + 50px);
.opened {
z-index: 1;
max-height: calc(100% + 50px);
visibility: visible;
z-index: 1;
}
visibility: visible;
}
.fc-right {
display: none;
.fc-right {
}
display: none;
}
/*
/*
@media all and (max-width: 800px), only screen and (-webkit-min-device-pixel-ratio: 2) and (max-width: 1024px), only screen and (min--moz-device-pixel-ratio: 2) and (max-width: 1024px), only screen and (-o-min-device-pixel-ratio: 2/1) and (max-width: 1024px), only screen and (min-device-pixel-ratio: 2) and (max-width: 1024px), only screen and (min-resolution: 192dpi) and (max-width: 1024px), only screen and (min-resolution: 2dppx) and (max-width: 1024px) {
@@ -326,41 +356,41 @@ vimport ('includes.runtime.EntryPoint');
<script type="text/javascript">var _REQSTARTTIME = "1589749969";jQuery(document).ready(function() { window._PAGEREADYAT = new Date(); });
jQuery(window).load(function() {
jQuery(window).load(function() {
window._PAGELOADAT = new Date();
window._PAGELOADAT = new Date();
window._PAGELOADREQSENT = false;
window._PAGELOADREQSENT = false;
// Transmit the information to server about page render time now.
// Transmit the information to server about page render time now.
if (typeof _REQSTARTTIME != 'undefined') {
if (typeof _REQSTARTTIME != 'undefined') {
// Work with time converting it to GMT (assuming _REQSTARTTIME set by server is also in GMT)
// Work with time converting it to GMT (assuming _REQSTARTTIME set by server is also in GMT)
var _PAGEREADYTIME = _PAGEREADYAT.getTime() / 1000.0; // seconds
var _PAGEREADYTIME = _PAGEREADYAT.getTime() / 1000.0; // seconds
var _PAGELOADTIME = _PAGELOADAT.getTime() / 1000.0; // seconds
var _PAGELOADTIME = _PAGELOADAT.getTime() / 1000.0; // seconds
var data = { page_request: _REQSTARTTIME, page_ready: _PAGEREADYTIME, page_load: _PAGELOADTIME };
var data = { page_request: _REQSTARTTIME, page_ready: _PAGEREADYTIME, page_load: _PAGELOADTIME };
data['page_xfer'] = (_PAGELOADTIME - _REQSTARTTIME).toFixed(3);
data['page_xfer'] = (_PAGELOADTIME - _REQSTARTTIME).toFixed(3);
data['client_tzoffset']= -1*_PAGELOADAT.getTimezoneOffset()*60;
data['client_tzoffset']= -1*_PAGELOADAT.getTimezoneOffset()*60;
data['client_now'] = JSON.parse(JSON.stringify(new Date()));
data['client_now'] = JSON.parse(JSON.stringify(new Date()));
if (!window._PAGELOADREQSENT) {
if (!window._PAGELOADREQSENT) {
// To overcome duplicate firing on Chrome
// To overcome duplicate firing on Chrome
window._PAGELOADREQSENT = true;
}
window._PAGELOADREQSENT = true;
}
});
}
});
</script>