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:
12
.gitignore
vendored
12
.gitignore
vendored
@@ -1,5 +1,17 @@
|
||||
/test
|
||||
|
||||
/logs
|
||||
|
||||
/user_privileges
|
||||
|
||||
*.log
|
||||
|
||||
*.bak
|
||||
|
||||
test/templates_c/
|
||||
test/templates_c/*.tpl.php
|
||||
test/templates_c/v7/710e620183d7eba30794adcdaa65a6b9b5aba915.file.Footer.tpl.php
|
||||
test/templates_c/v7/833e7fc50cbf769ba11253f5188fa344a967b92e.file.SidebarAppMenu.tpl.php
|
||||
test/templates_c/v7/2627944103942efed50bd439d9d1dbdcc67dc480.file.ModalFooter.tpl.php
|
||||
test/templates_c/v7/b62713acd22803ca6b3ad6d54ce71cdbcc4dc22a.file.Topbar.tpl.php
|
||||
test/templates_c/v7/b307425d1b338e6a92e5cdf7e1d4fa12929b2d14.file.Multireference.tpl.php
|
||||
|
||||
@@ -234,7 +234,9 @@
|
||||
|
||||
LEFT JOIN vtiger_accountscf ON (vtiger_accountscf.accountid =vtiger_account.accountid)
|
||||
|
||||
WHERE vtiger_account.industry = '{$type}' and vtiger_accountscf.cf_990 <> ''
|
||||
INNER JOIN vtiger_crmentity ON vtiger_account.accountid = vtiger_crmentity.crmid
|
||||
|
||||
WHERE vtiger_account.industry = '{$type}' and vtiger_accountscf.cf_990 <> '' and vtiger_crmentity.deleted = 0
|
||||
|
||||
GROUP by vtiger_accountscf.cf_990 ORDER BY `region` ASC";
|
||||
|
||||
|
||||
@@ -1932,11 +1932,33 @@ function box(data) {
|
||||
|
||||
success: function (data) {
|
||||
|
||||
//console.log(data);
|
||||
let cleanData = data.trim();
|
||||
|
||||
data = data.replace('{', '{');
|
||||
|
||||
var dataResult = JSON.parse(data);
|
||||
console.log(data);
|
||||
|
||||
// Remove anything starting from the first <script> tag (and everything after)
|
||||
const scriptIndex = cleanData.indexOf('<script>');
|
||||
if (scriptIndex !== -1) {
|
||||
cleanData = cleanData.substring(0, scriptIndex);
|
||||
}
|
||||
|
||||
// Optional: remove BOM characters if present
|
||||
cleanData = cleanData.replace(/^\uFEFF/, '');
|
||||
|
||||
// Now you can safely parse
|
||||
let dataResult;
|
||||
try {
|
||||
dataResult = JSON.parse(cleanData);
|
||||
console.log("✅ Parsed JSON:", dataResult);
|
||||
} catch (e) {
|
||||
console.error("❌ Invalid JSON:", cleanData);
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
|
||||
// var dataResult = JSON.parse(data);
|
||||
|
||||
box(dataResult);
|
||||
|
||||
@@ -2036,6 +2058,34 @@ $(document).ready(function() {
|
||||
|
||||
LoadALLDashBoard();
|
||||
|
||||
|
||||
// const menuButton = document.querySelector('.app-navigator .app-icon');
|
||||
// menuButton.addEventListener('click', toggleSidebar);
|
||||
|
||||
// function toggleSidebar() {
|
||||
// console.log('clicked');
|
||||
|
||||
// const mainContainer = document.querySelector('.main-container');
|
||||
// const sidebar = document.querySelector('.vertical-menu');
|
||||
// const tabContainerD = document.querySelector('.tabContainer');
|
||||
// const dashboard = document.querySelector('.dashboard');
|
||||
|
||||
// const isOpen = sidebar.classList.contains('open');
|
||||
|
||||
// if (isOpen) {
|
||||
// sidebar.classList.remove('open');
|
||||
// sidebar.style.width = '0px';
|
||||
// if (mainContainer) mainContainer.style.marginLeft = '0px';
|
||||
// if (tabContainerD) tabContainerD.style.marginLeft = '0px';
|
||||
// if (dashboard) dashboard.style.marginLeft = '0px';
|
||||
// } else {
|
||||
// sidebar.classList.add('open');
|
||||
// sidebar.style.width = '250px';
|
||||
// if (mainContainer) mainContainer.style.marginLeft = '250px';
|
||||
// if (tabContainerD) tabContainerD.style.marginLeft = '250px';
|
||||
// if (dashboard) dashboard.style.marginLeft = '250px';
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
catch(err) {
|
||||
|
||||
@@ -8,6 +8,10 @@ vimport ('includes.runtime.EntryPoint');
|
||||
$roleid = $current_user->get('roleid');
|
||||
$userId = $current_user->get('id');
|
||||
|
||||
if($roleid == 'H37')
|
||||
die("Vous n'avez pas le droit d'accéder à cette page");
|
||||
|
||||
|
||||
if(isset($_POST["Export"])){
|
||||
$filename = "ETAT_DES_STOCKS".date('Ymd') . ".xls";
|
||||
header("Content-Type: application/vnd.ms-excel");
|
||||
|
||||
174
ExportData.php
174
ExportData.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 $dbconfig;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
global $adb;
|
||||
global $adb;
|
||||
|
||||
$query = "SHOW FULL TABLES IN {$dbconfig['db_name']} WHERE TABLE_TYPE LIKE 'VIEW';";
|
||||
$query = "SHOW FULL TABLES IN {$dbconfig['db_name']} WHERE TABLE_TYPE LIKE 'VIEW';";
|
||||
|
||||
$sql_get_result = $adb->query($query);
|
||||
$sql_get_result = $adb->query($query);
|
||||
|
||||
|
||||
|
||||
$result = array();
|
||||
$result = array();
|
||||
|
||||
while ($recordinfo = $adb->fetch_array($sql_get_result)) {
|
||||
while ($recordinfo = $adb->fetch_array($sql_get_result)) {
|
||||
|
||||
$result[] = $recordinfo;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if ($roleid == 'H8')
|
||||
// $filter = [];
|
||||
|
||||
$result = [['tables_in_sophalnexscrmnew' => 'comptes_medecins' ], ['tables_in_sophalnexscrmnew' => 'comptes_pharmacies'], ['tables_in_sophalnexscrmnew' => 'full_activity']];
|
||||
// $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);
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
|
||||
if ($roleid == 'H17' || $roleid == 'H18' || $roleid == 'H20' || $roleid == 'H21' || $roleid == 'H24' || $roleid == 'H25' || $roleid == 'H26' || $roleid == 'H39'){
|
||||
// echo "<pre>";
|
||||
// var_dump($filter);
|
||||
// var_dump($visiteurs);
|
||||
// echo "</pre>";
|
||||
// die();
|
||||
|
||||
$result = [['tables_in_sophalnexscrmnew' => 'comptes_medecins' ],['tables_in_sophalnexscrmnew' => 'comptes_pharmacies'],['tables_in_sophalnexscrmnew' => 'full_activity']];
|
||||
if ($roleid == 'H8')
|
||||
|
||||
}
|
||||
$result = [['tables_in_sophalnexscrmnew2' => 'comptes_medecins'], ['tables_in_sophalnexscrmnew2' => 'comptes_pharmacies'], ['tables_in_sophalnexscrmnew2' => 'full_activity']];
|
||||
|
||||
|
||||
|
||||
echo '<br><br>
|
||||
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'],
|
||||
}
|
||||
|
||||
if ($roleid == 'H34' || $roleid == 'H36' || $roleid == 'H38' || $roleid == 'H42' || $roleid == 'H44') {
|
||||
|
||||
$result = [['tables_in_sophalnexscrmnew2' => 'bc_produits'], ['tables_in_sophalnexscrmnew2' => 'bon_de_commande']];
|
||||
}
|
||||
|
||||
echo '<br><br>
|
||||
|
||||
<form action="ExportTable.php">';
|
||||
|
||||
if ($roleid == 'H8')
|
||||
if ($roleid == 'H8')
|
||||
|
||||
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"> ';
|
||||
|
||||
$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 '</select><br><br>
|
||||
echo '</select><br><br>
|
||||
|
||||
<button id="exportbtn" type="submit" class="btn btn-default addButton"> Export</button>
|
||||
|
||||
@@ -150,11 +180,11 @@ vimport ('includes.runtime.EntryPoint');
|
||||
|
||||
|
||||
|
||||
$viewer->view('CustomDashboardFooter.tpl');
|
||||
$viewer->view('CustomDashboardFooter.tpl');
|
||||
|
||||
|
||||
|
||||
?>
|
||||
?>
|
||||
|
||||
|
||||
|
||||
@@ -168,7 +198,7 @@ vimport ('includes.runtime.EntryPoint');
|
||||
|
||||
|
||||
|
||||
:root {
|
||||
:root {
|
||||
|
||||
--gray-color: rgb(220, 220, 220);
|
||||
|
||||
@@ -176,57 +206,57 @@ vimport ('includes.runtime.EntryPoint');
|
||||
|
||||
--my-color: rgb(20, 160, 217);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.addButton {
|
||||
.addButton {
|
||||
|
||||
margin-left: 10px;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.addButton2 {
|
||||
.addButton2 {
|
||||
|
||||
margin-left: 30px;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#btndiv {
|
||||
#btndiv {
|
||||
|
||||
margin-left: 0px;
|
||||
|
||||
height:50px;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#maintab {
|
||||
#maintab {
|
||||
|
||||
margin-left: 0px;
|
||||
|
||||
width: calc (100% - 550px) !important;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.gps-control {
|
||||
.gps-control {
|
||||
|
||||
display: none;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#map {
|
||||
#map {
|
||||
|
||||
|
||||
|
||||
@@ -236,11 +266,11 @@ vimport ('includes.runtime.EntryPoint');
|
||||
|
||||
background: rgba(140, 140, 140, 1);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#msg{
|
||||
#msg{
|
||||
|
||||
top: calc(100% - 100px);
|
||||
|
||||
@@ -248,19 +278,19 @@ vimport ('includes.runtime.EntryPoint');
|
||||
|
||||
height: 100px;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.leaflet-routing-container {
|
||||
.leaflet-routing-container {
|
||||
|
||||
display: none;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.closed {
|
||||
.closed {
|
||||
|
||||
max-height: 0;
|
||||
|
||||
@@ -268,11 +298,11 @@ vimport ('includes.runtime.EntryPoint');
|
||||
|
||||
visibility: hidden;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.opened {
|
||||
.opened {
|
||||
|
||||
max-height: calc(100% + 50px);
|
||||
|
||||
@@ -280,21 +310,21 @@ vimport ('includes.runtime.EntryPoint');
|
||||
|
||||
visibility: visible;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.fc-right {
|
||||
.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) {
|
||||
|
||||
|
||||
172
ExportTable.php
172
ExportTable.php
@@ -1,129 +1,273 @@
|
||||
<?php
|
||||
|
||||
require_once 'include/utils/utils.php';
|
||||
|
||||
require_once 'includes/Loader.php';
|
||||
|
||||
vimport ('includes.runtime.EntryPoint');
|
||||
|
||||
require_once 'SUtiles.php';
|
||||
|
||||
@session_start();
|
||||
|
||||
|
||||
require_once 'SUtiles.php';
|
||||
|
||||
@session_start();
|
||||
|
||||
// ✅ Securely initialize the current user (important for permission control)
|
||||
if (isset($_SESSION['authenticated_user_id'])) {
|
||||
$current_user = new Users();
|
||||
$current_user->retrieveCurrentUserInfoFromFile($_SESSION['authenticated_user_id']);
|
||||
$roleid = $current_user->roleid;
|
||||
} else {
|
||||
echo "Access denied. Not logged in.";
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
if(isset($_GET['table'])){
|
||||
|
||||
$table = $_GET['table'];
|
||||
|
||||
$current_user = new Users();
|
||||
$current_user->retrieveCurrentUserInfoFromFile($_SESSION['authenticated_user_id']);
|
||||
$roleid = $current_user->roleid;
|
||||
|
||||
$filename = "Data_".$table.".csv";
|
||||
|
||||
outputCsv($filename,$table,$roleid);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function outputCsv($fileName,$table,$roleid)
|
||||
|
||||
{
|
||||
|
||||
global $adb;
|
||||
|
||||
|
||||
|
||||
$filter = [];
|
||||
|
||||
|
||||
$sub = (getMySubordinates($roleid));
|
||||
|
||||
$flag = false;
|
||||
|
||||
foreach($sub as $key => $value){
|
||||
|
||||
array_push($filter,$value);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
$user_query = 'select * from '.$table;
|
||||
|
||||
|
||||
if ($roleid == 'H34' || $roleid == 'H36' || $roleid == 'H38' || $roleid == 'H42' || $roleid == 'H44') {
|
||||
$user_query = "SELECT * FROM `$table` WHERE parentrole LIKE '%::$roleid::%' OR parentrole = '$roleid'";
|
||||
}
|
||||
|
||||
$result =$adb->query($user_query);
|
||||
|
||||
|
||||
|
||||
ob_clean();
|
||||
|
||||
header('Pragma: public');
|
||||
|
||||
header('Expires: 0');
|
||||
|
||||
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
|
||||
|
||||
header('Cache-Control: private', false);
|
||||
|
||||
header('Content-Type: text/csv; charset=utf-8');
|
||||
|
||||
header('Content-Disposition: attachment;filename=' . $fileName);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$fp = fopen('php://output', 'w');
|
||||
|
||||
|
||||
|
||||
while ($row = $adb->fetchByAssoc($result)) {
|
||||
|
||||
if (!$flag) {
|
||||
|
||||
// display field/column names as first row
|
||||
|
||||
fputcsv($fp, array_keys($row),';');
|
||||
|
||||
$flag = true;
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
// if(isMedicalSuperviseur($roleid)){
|
||||
|
||||
// if (in_array($row['visiteur1'], $filter) || in_array($row['visiteur2'], $filter) || in_array($row['visiteur3'], $filter) || in_array($row['visiteur3'], $filter)) {
|
||||
|
||||
// $csv_values = array_map('decode_html', array_values($row));
|
||||
|
||||
// fputcsv($fp, $csv_values,';');
|
||||
|
||||
// }
|
||||
|
||||
// }
|
||||
|
||||
// else{
|
||||
|
||||
$csv_values = array_map('decode_html', array_values($row));
|
||||
|
||||
fputcsv($fp, $csv_values,';');
|
||||
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
$result =$adb->query($user_query);
|
||||
|
||||
|
||||
|
||||
ob_clean();
|
||||
|
||||
fclose($fp);
|
||||
|
||||
ob_flush();
|
||||
|
||||
die;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* ancien code lakheder ben
|
||||
|
||||
if(isset($_GET['table'])){
|
||||
|
||||
$table = $_GET['table'];
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
$extension = ".xls";//".csv";
|
||||
|
||||
if(isset($_GET['xls']) && $_GET['xls'] == true)
|
||||
|
||||
$extension = ".xls";
|
||||
|
||||
global $adb;
|
||||
|
||||
$filename = "Data_".$table.$extension; // File Name
|
||||
|
||||
// Download file
|
||||
|
||||
header("Content-Disposition: attachment; filename=\"$filename\"");
|
||||
|
||||
header("Content-Type: application/vnd.ms-excel");
|
||||
|
||||
$user_query = 'select * from '.$table;
|
||||
|
||||
$result =$adb->query($user_query);
|
||||
|
||||
// Write data to file
|
||||
|
||||
$flag = false;
|
||||
|
||||
ob_end_clean();
|
||||
|
||||
ob_start();
|
||||
|
||||
while ($row = $adb->fetch_array($result)) {
|
||||
|
||||
unset($row['0']);
|
||||
|
||||
unset($row['1']);
|
||||
|
||||
unset($row['2']);
|
||||
|
||||
unset($row['3']);
|
||||
|
||||
unset($row['4']);
|
||||
|
||||
unset($row['5']);
|
||||
|
||||
unset($row['6']);
|
||||
|
||||
unset($row['7']);
|
||||
|
||||
unset($row['8']);
|
||||
|
||||
unset($row['9']);
|
||||
|
||||
unset($row['10']);
|
||||
|
||||
unset($row['11']);
|
||||
|
||||
unset($row['12']);
|
||||
|
||||
unset($row['13']);
|
||||
|
||||
unset($row['14']);
|
||||
|
||||
unset($row['15']);
|
||||
|
||||
unset($row['16']);
|
||||
|
||||
unset($row['17']);
|
||||
|
||||
unset($row['18']);
|
||||
|
||||
unset($row['19']);
|
||||
|
||||
unset($row['20']);
|
||||
|
||||
unset($row['21']);
|
||||
|
||||
if (!$flag) {
|
||||
|
||||
// display field/column names as first row
|
||||
|
||||
echo implode("\t", array_keys($row)) . "\r\n";
|
||||
|
||||
$flag = true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
$temp = implode("\t", array_values($row));
|
||||
|
||||
$temp = str_replace("'", " ", $temp);
|
||||
|
||||
$temp = str_replace("’", " ", $temp);
|
||||
|
||||
$temp = str_replace("ç", "c", $temp);
|
||||
|
||||
$temp = str_replace("â", "a", $temp);
|
||||
|
||||
$temp = str_replace("è", "e", $temp);
|
||||
|
||||
$temp = str_replace('é', 'e', $temp);
|
||||
|
||||
$temp = str_replace('ï', 'e', $temp);
|
||||
|
||||
$temp = str_replace('Ï', 'i', $temp);
|
||||
|
||||
$temp = str_replace('É', 'E', $temp);
|
||||
|
||||
$temp = str_replace(' ', "", $temp);
|
||||
|
||||
$temp = str_replace('ô', "o", $temp);
|
||||
|
||||
$temp = str_replace(array("\r", "\n"), '', $temp);
|
||||
|
||||
//preg_replace( "/\r|\n/", "", $temp );
|
||||
|
||||
echo str_replace('.', ',', $temp)."\r\n";
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
?>
|
||||
@@ -232,6 +232,8 @@ $viewer->view('CustomDashboard.tpl');
|
||||
|
||||
$active8 = "";
|
||||
|
||||
$active9 = "";
|
||||
|
||||
if($active == 1) $active1 = 'active';
|
||||
|
||||
if($active == 2) $active2 = 'active';
|
||||
@@ -248,6 +250,10 @@ $viewer->view('CustomDashboard.tpl');
|
||||
|
||||
if($active == 8) $active8 = 'active';
|
||||
|
||||
if($active == 9) $active9 = 'active';
|
||||
|
||||
if($active == 10) $active10 = 'active';
|
||||
|
||||
|
||||
|
||||
return '<div class="dashBoardContainer clearfix">
|
||||
@@ -272,6 +278,10 @@ $viewer->view('CustomDashboard.tpl');
|
||||
|
||||
<li class="dashboardTab font-large-2 '.$active8.'" ><a href="index.php?module=MonitoringVpObjective&view=MonitoringVpObjective"><div><strong>Objective</strong></div></a></li>
|
||||
|
||||
<li class="dashboardTab font-large-2 '.$active9.'" ><a href="index.php?module=PharmexObjective&view=PharmexObjective&event=Saidalya"><div><strong>Salon SIPHAL</strong></div></a></li>
|
||||
|
||||
<li class="dashboardTab font-large-2 '.$active10.'" ><a href="index.php?module=PharmexObjective&view=PharmexObjective&event=November"><div><strong>Offres SIPHAL</strong></div></a></li>
|
||||
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -215,8 +215,8 @@ if(isset($_POST['comptes']) && isset($_POST['date'])) {
|
||||
}
|
||||
|
||||
else if (isMedecin($roleid)){
|
||||
$query = $query." WHERE ((e.smownerid like ? OR `vm2_id` like ? OR `vm3_id` like ?) AND e.deleted = 0 AND cf.cf_994 like ? ";
|
||||
$query = $query." AND a.industry ='Medecin') or (a.industry ='Pharmacie' AND cf.cf_994 like '{$communep}')";
|
||||
$query = $query." WHERE ((e.smownerid like ? OR `vm2_id` like ? OR `vm3_id` like ?)AND cf.cf_994 like ? ";
|
||||
$query = $query." AND a.industry ='Medecin') or (a.industry ='Pharmacie' AND cf.cf_994 like '{$communep}') AND e.deleted = 0 ";
|
||||
$result = $adb->pquery($query, array($userId, $userId, $userId, $communep));
|
||||
}
|
||||
|
||||
@@ -231,8 +231,8 @@ if(isset($_POST['comptes']) && isset($_POST['date'])) {
|
||||
|
||||
|
||||
else if (isMedecin($roleid)){
|
||||
$query = $query." WHERE ((e.smownerid like ? OR `vm2_id` like ? OR `vm3_id` like ?) AND e.deleted = 0 AND cf.cf_996 like ? ";
|
||||
$query = $query." AND a.industry ='Medecin') or (a.industry ='Pharmacie' AND cf.cf_996 like '{$brickp}')";
|
||||
$query = $query." WHERE ((e.smownerid like ? OR `vm2_id` like ? OR `vm3_id` like ?) AND cf.cf_996 like ? ";
|
||||
$query = $query." AND a.industry ='Medecin') or (a.industry ='Pharmacie' AND cf.cf_996 like '{$brickp}') AND e.deleted = 0 ";
|
||||
$result = $adb->pquery($query, array($userId, $userId, $userId, $brickp));
|
||||
}
|
||||
|
||||
|
||||
932
PharmexObjective.php
Normal file
932
PharmexObjective.php
Normal file
@@ -0,0 +1,932 @@
|
||||
<?php
|
||||
|
||||
$dbvp = true;
|
||||
|
||||
require_once 'MonitoringVMHeader.php';
|
||||
require_once 'MonitoringDBRequest.php';
|
||||
|
||||
?>
|
||||
<?php
|
||||
|
||||
$userId = $current_user->get('id');
|
||||
$event = $_GET["event"];
|
||||
$objective = 0;
|
||||
|
||||
if (!isVPSuperviseur($roleid) && !isTopDG($roleid) && !isResponsableCommercial($roleid)) {
|
||||
die("<div style='width:100%;height:100%;display:flex;justify-content: center;font-size: 2rem;font-style: normal;'> Vous n'êtes pas autorisé à lire cette ressource.</div>");
|
||||
}
|
||||
|
||||
if (isTopDG($roleid)) {
|
||||
$roleid = "H10";
|
||||
}
|
||||
// $datedeb = date("Y-m-d", strtotime("-1 month"));
|
||||
// $datefin = date('Y-m-d');
|
||||
|
||||
$datedeb = '2026-11-04';
|
||||
$datefin = '2026-11-30';
|
||||
|
||||
if ($event == "Saidalya") {
|
||||
$datedeb = '2026-02-04';
|
||||
$datefin = '2026-02-07';
|
||||
$objective = 300000000.00; // Objective value (0-100)
|
||||
echo getMonitoringMainBarVP(9);
|
||||
} else if ($event == "November") {
|
||||
$datedeb = '2026-01-13';
|
||||
$datefin = '2026-02-15';
|
||||
$objective = 500000000.00; // Objective value (0-100)
|
||||
|
||||
echo getMonitoringMainBarVP(10);
|
||||
} else {
|
||||
die("Unauthorized");
|
||||
}
|
||||
|
||||
$vpFilter = "";
|
||||
|
||||
if ($event == "Saidalya") {
|
||||
$vpFilter = " AND us.id IN (156,125,215,137,149,261,127,124,43,254,212,255,253,186,248,222)";
|
||||
}
|
||||
|
||||
$currentValue = 0; // Current gauge value (0-100)
|
||||
|
||||
?>
|
||||
|
||||
|
||||
<?php
|
||||
global $adb;
|
||||
$queryCA = "SELECT total_bc as bc FROM
|
||||
(SELECT us.id ,CONCAT(first_name,' ', last_name) as fullname ,EXTRACT(YEAR FROM so.duedate) as YEAR,EXTRACT(MONTH FROM so.duedate) as month, sum(subtotal) as total_bc, cf_992
|
||||
FROM vtiger_users us
|
||||
JOIN vtiger_user2role usr ON usr.userid = us.id
|
||||
JOIN vtiger_role ro ON ro.roleid = usr.roleid
|
||||
JOIN vtiger_crmentity crm on crm.smownerid = us.id and crm.setype='SalesOrder' and crm.deleted <> 1
|
||||
JOIN vtiger_salesorder so ON so.salesorderid = crm.crmid
|
||||
JOIN vtiger_accountscf acf ON acf.accountid = so.accountid";
|
||||
$queryCA = $queryCA . " WHERE so.duedate BETWEEN '" . $datedeb . "' and '" . $datefin . "' $vpFilter order by total_bc asc";
|
||||
$queryCA = $queryCA . ") AS subquery order by total_bc desc; ";
|
||||
|
||||
$sql_get_result_ca = $adb->query($queryCA);
|
||||
$result_ca = array();
|
||||
while ($recordinfo = $adb->fetch_array($sql_get_result_ca)) {
|
||||
$result_ca[] = $recordinfo;
|
||||
}
|
||||
$currentValue = $result_ca[0][0] ?? 0;
|
||||
|
||||
|
||||
// CA Par Client
|
||||
$query = "SELECT soc.cf_854 as accountname,
|
||||
sum(so.subtotal) as totalmargin
|
||||
FROM `vtiger_salesorder` so
|
||||
JOIN vtiger_salesordercf soc on soc.salesorderid = so.salesorderid
|
||||
JOIN vtiger_crmentity e on so.`salesorderid` = e.crmid and e.deleted <> 1 and e.setype='SalesOrder'
|
||||
JOIN vtiger_users us on us.id = e.smownerid and us.status <> 'Inactive'
|
||||
JOIN vtiger_user2role usr ON usr.userid = us.id
|
||||
JOIN vtiger_role ro ON ro.roleid = usr.roleid";
|
||||
$query = $query . " WHERE so.duedate BETWEEN '" . $datedeb . "' and '" . $datefin . "' $vpFilter";
|
||||
$query = $query . " GROUP by accountname order by totalmargin desc";
|
||||
$sql_get_result_client = $adb->query($query);
|
||||
$result_client = array();
|
||||
while ($recordinfo = $adb->fetch_array($sql_get_result_client)) {
|
||||
$result_client[] = $recordinfo;
|
||||
}
|
||||
$json_data = json_encode($result_client);
|
||||
|
||||
|
||||
// Par produit
|
||||
$query_produit = "SELECT p.productname, sum(ip.quantity) as totalquantity , sum(ip.margin) as totalmargin
|
||||
FROM `vtiger_salesorder` so
|
||||
JOIN vtiger_inventoryproductrel ip on so.`salesorderid` = ip.id
|
||||
JOIN vtiger_crmentity e on so.`salesorderid` = e.crmid and e.deleted = 0
|
||||
JOIN vtiger_products p on p.productid = ip.productid
|
||||
JOIN vtiger_users us on us.id = e.smownerid and us.status <> 'Inactive'
|
||||
JOIN vtiger_user2role usr ON usr.userid = us.id
|
||||
JOIN vtiger_role ro ON ro.roleid = usr.roleid";
|
||||
$query_produit = $query_produit . " WHERE so.duedate BETWEEN '" . $datedeb . "' and '" . $datefin . "' $vpFilter";
|
||||
$query_produit = $query_produit . " GROUP by p.productname order by totalmargin desc"; //, month , year";
|
||||
|
||||
|
||||
$sql_get_result_product = $adb->query($query_produit);
|
||||
$result_products_arr = array();
|
||||
while ($recordinfo = $adb->fetch_array($sql_get_result_product)) {
|
||||
$result_products_arr[] = $recordinfo;
|
||||
}
|
||||
|
||||
$result_products = json_encode($result_products_arr);
|
||||
// $totalMargins = array_column($result_products, 'totalmargin');
|
||||
|
||||
|
||||
// PAR VP
|
||||
$query_vp = "SELECT
|
||||
fullname,
|
||||
total_bc AS bc
|
||||
FROM
|
||||
(SELECT us.id,CONCAT(first_name, ' ', last_name) AS fullname,SUM(subtotal) AS total_bc
|
||||
FROM vtiger_users us JOIN vtiger_user2role usr ON usr.userid = us.id
|
||||
JOIN vtiger_crmentity crm ON crm.smownerid = us.id AND crm.setype = 'SalesOrder' AND crm.deleted <> 1
|
||||
JOIN vtiger_salesorder so ON so.salesorderid = crm.crmid ";
|
||||
$query_vp = $query_vp . " WHERE so.duedate BETWEEN '" . $datedeb . "' and '" . $datefin . "' $vpFilter";
|
||||
$query_vp = $query_vp . " GROUP BY us.id,fullname) as s ";
|
||||
|
||||
$sql_get_result_vp = $adb->query($query_vp);
|
||||
$result_vp = array();
|
||||
while ($recordinfo = $adb->fetch_array($sql_get_result_vp)) {
|
||||
$result_vp[] = $recordinfo;
|
||||
}
|
||||
|
||||
$result_vp = json_encode($result_vp);
|
||||
|
||||
|
||||
// echo "<pre>";
|
||||
// print_r($result_products);
|
||||
// echo "</pre>";
|
||||
// // print_r($productNames);
|
||||
// echo $result_vp;
|
||||
// die();
|
||||
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-US">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Dashboard</title>
|
||||
|
||||
<!-- Fonts & Icons -->
|
||||
<link href="file_upload/MyFont.css" rel="stylesheet">
|
||||
|
||||
<!-- Chart.js and Plugins -->
|
||||
<script src="file_upload/Chart.bundle.js"></script>
|
||||
<script src="file_upload/chartjs-gauge.js"></script>
|
||||
<script src="file_upload/chartjs-plugin-datalabels.js"></script>
|
||||
|
||||
<!-- DataTables CSS -->
|
||||
<link rel="stylesheet" href="file_upload/dataTables.bootstrap4.min.css">
|
||||
|
||||
<!-- jQuery + DataTables JS -->
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
<script src="file_upload/jquery.dataTables.min.js"></script>
|
||||
<script src="file_upload/dataTables.bootstrap4.min.js"></script>
|
||||
|
||||
|
||||
<!-- Modern Styles -->
|
||||
<style>
|
||||
:root {
|
||||
--primary: #3f51b5;
|
||||
--secondary: #f5f7fa;
|
||||
--text: #333;
|
||||
--card-bg: #fff;
|
||||
--border: #e0e0e0;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Inter', sans-serif;
|
||||
background-color: var(--secondary);
|
||||
color: var(--text);
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin-bottom: 10px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.dashboard {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(450px, 1fr));
|
||||
gap: 20px;
|
||||
margin-left: 280px;
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
.card {
|
||||
background-color: var(--card-bg);
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);
|
||||
padding: 40px;
|
||||
border: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.chart-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 500px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
margin-top: 40px;
|
||||
margin-bottom: 15px;
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
|
||||
.all {
|
||||
grid-column-start: 1;
|
||||
grid-column-end: 3;
|
||||
}
|
||||
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.dashboard {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
|
||||
<body>
|
||||
|
||||
<div class="container">
|
||||
<div class="dashboard">
|
||||
<div class="card all">
|
||||
<h3>CA % Objectif (<?php echo "$datedeb-$datefin" ?>)</h3>
|
||||
<div class="chart-container">
|
||||
<canvas id="chart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card all">
|
||||
<h3>CA % Client (<?php echo "$datedeb-$datefin" ?>)</h3>
|
||||
<div class="chart-container">
|
||||
<canvas id="myChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Par produit -->
|
||||
<div class="card all">
|
||||
<div class="section-title">Par Produit</div>
|
||||
<div class="chart-container">
|
||||
<canvas id="marginChart" width="600" height="400"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Par produit donuts -->
|
||||
<div class="card mt-4">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Répartition Marge Totale (Top 10 Produits)</h5>
|
||||
<canvas id="productDonutChart" width="400" height="400"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card mt-4">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Répartition Quantité Totale (Top 10 Produits - Pie Chart)</h5>
|
||||
<canvas id="productQuantityPieChart" width="400" height="400"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Marge par client</h5>
|
||||
<canvas id="myDonutChart" height="400"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card mt-4">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Répartition CA par VP (Top 10)</h5>
|
||||
<canvas id="vpDonutChart" width="400" height="400"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="card all">
|
||||
<div class="section-title">Par VP</div>
|
||||
<canvas id="vpChart" width="600" height="400"></canvas>
|
||||
</div>
|
||||
|
||||
<div class="card all">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">CA par Client</h5>
|
||||
<div class="table-responsive">
|
||||
<table id="clientMarginTable" class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Client</th>
|
||||
<th>Marge Totale (D.A)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($result_client as $row): ?>
|
||||
<tr>
|
||||
<td><?= htmlspecialchars($row['accountname']) ?></td>
|
||||
<td><?= $row['totalmargin'] ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="card mt-4 all">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Produits : Quantité & Marge Totale</h5>
|
||||
<div class="table-responsive">
|
||||
<table id="productTable" class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Produit</th>
|
||||
<th>Quantité Totale</th>
|
||||
<th>Marge Totale (D.A)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($result_products_arr as $row): ?>
|
||||
<tr>
|
||||
<td><?= htmlspecialchars($row['productname']) ?></td>
|
||||
<td><?= $row['totalquantity'] ?></td>
|
||||
<td><?= $row['totalmargin'] ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!-- Your Chart.js scripts here -->
|
||||
<script>
|
||||
const currentValue = <?php echo $currentValue; ?>;
|
||||
const objective = <?php echo $objective; ?>;
|
||||
const value = currentValue * 100 / objective;
|
||||
|
||||
const gaugeConfig = {
|
||||
type: 'gauge',
|
||||
data: {
|
||||
// labels: ['Fail', 'Warning', 'Success'],
|
||||
datasets: [{
|
||||
data: [30, 80, 100],
|
||||
value: value.toFixed(2),
|
||||
backgroundColor: ['#f44336', '#ff9800', '#4caf50'],
|
||||
borderWidth: 2
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
title: {
|
||||
display: true,
|
||||
text: 'CA Réalisé : ' + currentValue.toLocaleString() + ' D.A',
|
||||
fontSize: 16
|
||||
},
|
||||
layout: {
|
||||
padding: {
|
||||
bottom: 20
|
||||
}
|
||||
},
|
||||
needle: {
|
||||
radiusPercentage: 2,
|
||||
widthPercentage: 2.2,
|
||||
lengthPercentage: 60,
|
||||
color: 'rgba(0,0,0,1)'
|
||||
},
|
||||
valueLabel: {
|
||||
display: true
|
||||
},
|
||||
plugins: {
|
||||
datalabels: {
|
||||
display: true,
|
||||
formatter: (value, context) => context.chart.data.labels[context.dataIndex],
|
||||
color: '#000',
|
||||
font: {
|
||||
size: 10,
|
||||
weight: 'bold'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const ctx = document.getElementById('chart').getContext('2d');
|
||||
new Chart(ctx, gaugeConfig);
|
||||
|
||||
//
|
||||
const phpData = <?php echo $json_data; ?>;
|
||||
const barLabels = phpData.map(item => item.accountname);
|
||||
const barData = phpData.map(item => parseFloat(item.totalmargin));
|
||||
|
||||
var top10Clients = barData.sort((a, b) => parseFloat(b.totalmargin) - parseFloat(a.totalmargin)) // Descending sort
|
||||
.slice(0, 10); // Take top 10
|
||||
|
||||
const barChart = new Chart(document.getElementById('myChart').getContext('2d'), {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: barLabels,
|
||||
datasets: [{
|
||||
label: 'Total CA par Client',
|
||||
data: top10Clients,
|
||||
backgroundColor: 'rgba(63, 81, 181, 0.6)',
|
||||
borderColor: 'rgba(63, 81, 181, 1)',
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
scales: {
|
||||
yAxes: [{
|
||||
ticks: {
|
||||
beginAtZero: true,
|
||||
callback: value => value.toLocaleString() + ' D.A'
|
||||
}
|
||||
}],
|
||||
xAxes: [{
|
||||
ticks: {
|
||||
autoSkip: false,
|
||||
maxRotation: 45,
|
||||
minRotation: 45
|
||||
}
|
||||
}]
|
||||
},
|
||||
// ✅ Add this to show labels over bars
|
||||
plugins: {
|
||||
datalabels: {
|
||||
anchor: 'end',
|
||||
align: 'right',
|
||||
color: '#000',
|
||||
offset: 6,
|
||||
clamp: true,
|
||||
clip: false,
|
||||
font: {
|
||||
size: window.innerWidth < 768 ? 8 : 10,
|
||||
weight: 'bold'
|
||||
},
|
||||
formatter: function(value, context) {
|
||||
// Format with thousands separator and decimals
|
||||
return Number(value).toLocaleString('fr-FR', {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2
|
||||
}) + (context.dataset.label === 'Total Margin' ? ' D.A' : '');
|
||||
}
|
||||
}
|
||||
},
|
||||
layout: {
|
||||
padding: {
|
||||
left: 40
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// PRODUCTS
|
||||
const result_products = <?php echo $result_products; ?>;
|
||||
// Step 1: Sort by totalmargin in descending order
|
||||
const top10Products = result_products
|
||||
.sort((a, b) => parseFloat(b.totalmargin) - parseFloat(a.totalmargin)) // Descending sort
|
||||
.slice(0, 10); // Take top 10
|
||||
|
||||
// Step 2: Extract data for use (e.g., charts)
|
||||
const productNames = top10Products.map(item => item.productname);
|
||||
const totalquantity = top10Products.map(item => parseFloat(item.totalquantity));
|
||||
const totalMargins = top10Products.map(item => parseFloat(item.totalmargin));
|
||||
const ctxMarginChart = document.getElementById('marginChart').getContext('2d');
|
||||
const marginChart = new Chart(ctxMarginChart, {
|
||||
type: 'horizontalBar', // horizontal bar in Chart.js 2.8
|
||||
data: {
|
||||
labels: productNames,
|
||||
datasets: [{
|
||||
label: 'Total',
|
||||
data: totalquantity,
|
||||
backgroundColor: 'rgba(54, 162, 235, 0.6)',
|
||||
borderColor: 'rgba(54, 162, 235, 1)',
|
||||
borderWidth: 1
|
||||
},
|
||||
{
|
||||
label: 'Total Margin',
|
||||
data: totalMargins,
|
||||
backgroundColor: 'rgba(255, 99, 132, 0.6)',
|
||||
borderColor: 'rgba(255, 99, 132, 1)',
|
||||
borderWidth: 1
|
||||
}
|
||||
]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
scales: {
|
||||
xAxes: [{
|
||||
ticks: {
|
||||
beginAtZero: true,
|
||||
callback: function(value) {
|
||||
// Format ticks with thousands separator, 2 decimals for margin, 0 for quantity
|
||||
// Assuming values for margin may have decimals; quantity probably integers
|
||||
return Number(value).toLocaleString('fr-FR', {
|
||||
minimumFractionDigits: 0,
|
||||
maximumFractionDigits: 2
|
||||
});
|
||||
}
|
||||
}
|
||||
}],
|
||||
yAxes: [{
|
||||
barPercentage: 0.6
|
||||
}]
|
||||
},
|
||||
legend: {
|
||||
display: true,
|
||||
position: 'top'
|
||||
},
|
||||
tooltips: {
|
||||
callbacks: {
|
||||
label: function(tooltipItem, data) {
|
||||
const datasetLabel = data.datasets[tooltipItem.datasetIndex].label || '';
|
||||
const value = tooltipItem.xLabel;
|
||||
// Format tooltip number with 2 decimals + thousands separator
|
||||
return `${datasetLabel}: ${Number(value).toLocaleString('fr-FR', { minimumFractionDigits: 2, maximumFractionDigits: 2 })} ${datasetLabel === 'Total Margin' ? 'D.A' : ''}`;
|
||||
}
|
||||
}
|
||||
},
|
||||
// ✅ Add this to show labels over bars
|
||||
plugins: {
|
||||
datalabels: {
|
||||
anchor: 'end',
|
||||
align: 'right',
|
||||
color: '#000',
|
||||
font: {
|
||||
weight: 'bold',
|
||||
size: 10
|
||||
},
|
||||
formatter: function(value, context) {
|
||||
// Format with thousands separator and decimals
|
||||
return Number(value).toLocaleString('fr-FR', {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2
|
||||
}) + (context.dataset.label === 'Total Margin' ? ' D.A' : '');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Donuts Products
|
||||
// 🎯 Donut chart for Top 10 Products by Total Margin
|
||||
const productDonutColors = [
|
||||
'#4caf50', '#ff9800', '#2196f3', '#e91e63', '#9c27b0',
|
||||
'#00bcd4', '#ffc107', '#8bc34a', '#ff5722', '#3f51b5'
|
||||
];
|
||||
const ctxProductDonut = document.getElementById('productDonutChart').getContext('2d');
|
||||
const productDonutChart = new Chart(ctxProductDonut, {
|
||||
type: 'pie', // 🎯 Pie chart type
|
||||
data: {
|
||||
labels: productNames,
|
||||
datasets: [{
|
||||
data: totalMargins,
|
||||
backgroundColor: productDonutColors,
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
cutoutPercentage: 60,
|
||||
legend: {
|
||||
position: 'right',
|
||||
labels: {
|
||||
boxWidth: 12
|
||||
}
|
||||
},
|
||||
tooltips: {
|
||||
callbacks: {
|
||||
label: function(tooltipItem, data) {
|
||||
const index = tooltipItem.index;
|
||||
const name = data.labels[index];
|
||||
const value = data.datasets[0].data[index];
|
||||
return `${name}: ${Number(value).toLocaleString('fr-FR', {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2
|
||||
})} D.A`;
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
datalabels: {
|
||||
color: '#000',
|
||||
formatter: (value, ctx) => {
|
||||
const total = ctx.chart.data.datasets[0].data.reduce((a, b) => a + b, 0);
|
||||
const percentage = ((value / total) * 100).toFixed(1);
|
||||
return percentage + '%';
|
||||
},
|
||||
font: {
|
||||
weight: 'bold',
|
||||
size: 10
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const ctxProductQuantityPie = document.getElementById('productQuantityPieChart').getContext('2d');
|
||||
|
||||
const productQuantityPieChart = new Chart(ctxProductQuantityPie, {
|
||||
type: 'pie',
|
||||
data: {
|
||||
labels: productNames,
|
||||
datasets: [{
|
||||
data: totalquantity,
|
||||
backgroundColor: productDonutColors,
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
legend: {
|
||||
position: 'right',
|
||||
labels: {
|
||||
boxWidth: 12
|
||||
}
|
||||
},
|
||||
tooltips: {
|
||||
callbacks: {
|
||||
label: function(tooltipItem, data) {
|
||||
const index = tooltipItem.index;
|
||||
const name = data.labels[index];
|
||||
const value = data.datasets[0].data[index];
|
||||
return `${name}: ${Number(value).toLocaleString('fr-FR', {
|
||||
minimumFractionDigits: 0,
|
||||
maximumFractionDigits: 0
|
||||
})}`;
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
datalabels: {
|
||||
color: '#000',
|
||||
formatter: (value, context) => {
|
||||
const total = context.chart.data.datasets[0].data.reduce((a, b) => a + b, 0);
|
||||
const percentage = ((value / total) * 100).toFixed(1);
|
||||
return percentage + '%';
|
||||
},
|
||||
font: {
|
||||
weight: 'bold',
|
||||
size: 10
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// VP
|
||||
const result_vp = <?php echo $result_vp; ?>;
|
||||
// Step 1: Sort by `bc` descending and take top 10
|
||||
const top10VPs = result_vp
|
||||
.sort((a, b) => parseFloat(b.bc) - parseFloat(a.bc)) // Sort high to low
|
||||
.slice(0, 10); // Take top 10
|
||||
|
||||
// Step 2: Extract fullname and bc into arrays
|
||||
const fullnames = top10VPs.map(item => item.fullname);
|
||||
const bc = top10VPs.map(item => parseFloat(item.bc));
|
||||
const ctxVphart = document.getElementById('vpChart').getContext('2d');
|
||||
const vpChart = new Chart(ctxVphart, {
|
||||
type: 'horizontalBar', // ✅ horizontal bar for Chart.js v2.8
|
||||
data: {
|
||||
labels: fullnames,
|
||||
datasets: [{
|
||||
label: 'Total',
|
||||
data: bc,
|
||||
backgroundColor: 'rgba(54, 162, 235, 0.6)',
|
||||
borderColor: 'rgba(54, 162, 235, 1)',
|
||||
borderWidth: 1
|
||||
}, ]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
scales: {
|
||||
xAxes: [{
|
||||
ticks: {
|
||||
beginAtZero: true,
|
||||
callback: function(value) {
|
||||
return parseFloat(value).toFixed(2).toLocaleString() + " D.A";
|
||||
}
|
||||
}
|
||||
}],
|
||||
yAxes: [{
|
||||
barPercentage: 0.6
|
||||
}]
|
||||
},
|
||||
legend: {
|
||||
display: true,
|
||||
position: 'top'
|
||||
},
|
||||
tooltips: {
|
||||
callbacks: {
|
||||
label: function(tooltipItem, data) {
|
||||
const datasetLabel = (data.datasets[tooltipItem.datasetIndex].label || '');
|
||||
const value = parseFloat(tooltipItem.xLabel).toFixed(2)
|
||||
return `${datasetLabel}: ${Number(value).toLocaleString()} DA`;
|
||||
}
|
||||
}
|
||||
},
|
||||
// ✅ Add this to show labels over bars
|
||||
plugins: {
|
||||
datalabels: {
|
||||
anchor: 'end',
|
||||
align: 'top',
|
||||
color: '#000',
|
||||
font: {
|
||||
weight: 'bold',
|
||||
size: 10
|
||||
},
|
||||
formatter: function(value, context) {
|
||||
// Format with thousands separator and decimals
|
||||
return Number(value).toLocaleString('fr-FR', {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2
|
||||
}) + (context.dataset.label === 'Total Margin' ? ' D.A' : '');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
// donuts top 10 vps
|
||||
// 🎯 VP Donut Chart (Top 10)
|
||||
const donutColors = [
|
||||
'#3f51b5', '#e91e63', '#ff9800', '#4caf50', '#2196f3',
|
||||
'#9c27b0', '#00bcd4', '#ffc107', '#8bc34a', '#ff5722'
|
||||
];
|
||||
|
||||
const ctxVPDoughnut = document.getElementById('vpDonutChart').getContext('2d');
|
||||
const vpDonutChart = new Chart(ctxVPDoughnut, {
|
||||
type: 'doughnut',
|
||||
data: {
|
||||
labels: fullnames,
|
||||
datasets: [{
|
||||
data: bc,
|
||||
backgroundColor: donutColors,
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
cutoutPercentage: 60, // makes it a donut instead of a pie
|
||||
legend: {
|
||||
position: 'right',
|
||||
labels: {
|
||||
boxWidth: 12
|
||||
}
|
||||
},
|
||||
tooltips: {
|
||||
callbacks: {
|
||||
label: function(tooltipItem, data) {
|
||||
const index = tooltipItem.index;
|
||||
const name = data.labels[index];
|
||||
const value = data.datasets[0].data[index];
|
||||
return `${name}: ${Number(value).toLocaleString('fr-FR', {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2
|
||||
})} D.A`;
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
datalabels: {
|
||||
color: '#000',
|
||||
formatter: (value, ctx) => {
|
||||
const total = ctx.chart.data.datasets[0].data.reduce((a, b) => a + b, 0);
|
||||
const percentage = ((value / total) * 100).toFixed(1);
|
||||
return percentage + '%';
|
||||
},
|
||||
font: {
|
||||
weight: 'bold',
|
||||
size: 10
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
console.log('top10Clients', top10Clients);
|
||||
|
||||
|
||||
const donutChart = new Chart(document.getElementById('myDonutChart').getContext('2d'), {
|
||||
type: 'doughnut',
|
||||
data: {
|
||||
labels: barLabels,
|
||||
datasets: [{
|
||||
label: 'Répartition du CA par Client',
|
||||
data: top10Clients,
|
||||
backgroundColor: [
|
||||
'rgba(255, 99, 132, 0.6)',
|
||||
'rgba(54, 162, 235, 0.6)',
|
||||
'rgba(255, 206, 86, 0.6)',
|
||||
'rgba(75, 192, 192, 0.6)',
|
||||
'rgba(153, 102, 255, 0.6)',
|
||||
'rgba(255, 159, 64, 0.6)',
|
||||
'rgba(63, 81, 181, 0.6)'
|
||||
],
|
||||
borderColor: 'white',
|
||||
borderWidth: 2
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
plugins: {
|
||||
legend: {
|
||||
position: 'right'
|
||||
},
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
label: function(context) {
|
||||
const value = context.raw;
|
||||
return `${context.label} : ${value.toLocaleString('fr-FR', {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2
|
||||
})} D.A`;
|
||||
}
|
||||
}
|
||||
},
|
||||
datalabels: {
|
||||
color: '#000',
|
||||
font: {
|
||||
size: 10,
|
||||
weight: 'bold'
|
||||
},
|
||||
formatter: function(value) {
|
||||
const total = top10Clients.reduce((acc, val) => acc + val, 0);
|
||||
const percentage = (value / total * 100).toFixed(1);
|
||||
return percentage + '%';
|
||||
}
|
||||
}
|
||||
},
|
||||
cutout: '60%' // Thickness of the donut hole
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
$(document).ready(function() {
|
||||
$('#clientMarginTable').DataTable({
|
||||
// language: {
|
||||
// url: "//cdn.datatables.net/plug-ins/1.13.6/i18n/fr-FR.json"
|
||||
// },
|
||||
columnDefs: [{
|
||||
targets: 1, // Marge totale
|
||||
render: function(data, type) {
|
||||
const floatVal = parseFloat(data);
|
||||
if (type === 'sort' || type === 'type') {
|
||||
return floatVal; // return raw number for sorting
|
||||
}
|
||||
return floatVal.toLocaleString('fr-FR', {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2
|
||||
}) + ' D.A'; // formatted for display
|
||||
}
|
||||
}]
|
||||
});
|
||||
|
||||
$('#productTable').DataTable({
|
||||
language: {
|
||||
// url: "//cdn.datatables.net/plug-ins/1.13.6/i18n/fr-FR.json"
|
||||
},
|
||||
columnDefs: [{
|
||||
targets: 1, // Quantité Totale
|
||||
render: function(data, type) {
|
||||
const num = parseFloat(data);
|
||||
if (type === 'sort' || type === 'type') {
|
||||
return num;
|
||||
}
|
||||
return num.toLocaleString('fr-FR', {
|
||||
minimumFractionDigits: 0,
|
||||
maximumFractionDigits: 0
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
targets: 2, // Marge Totale
|
||||
render: function(data, type) {
|
||||
const value = parseFloat(data);
|
||||
if (type === 'sort' || type === 'type') {
|
||||
return value;
|
||||
}
|
||||
return value.toLocaleString('fr-FR', {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2
|
||||
}) + ' D.A';
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
312
SUtiles.php
312
SUtiles.php
@@ -1,176 +1,364 @@
|
||||
<?php
|
||||
|
||||
|
||||
|
||||
|
||||
function isPharma($roleid) {
|
||||
|
||||
return ($roleid == 'H7' || $roleid == 'H13' || $roleid == 'H14' || $roleid == "H34" || $roleid == "H35" || $roleid == "H36" || $roleid == "H38" || $roleid == "H42" || $roleid == "H43" || $roleid == "H44" || $roleid=="H45");
|
||||
function isPharma($roleid) {
|
||||
|
||||
return ($roleid == 'H7' || $roleid == 'H13' || $roleid == 'H14' || $roleid == "H34" || $roleid == "H35" || $roleid == "H36" || $roleid == "H38" || $roleid == "H42" || $roleid == "H43" || $roleid == "H44" || $roleid=="H45");
|
||||
}
|
||||
|
||||
|
||||
|
||||
function isMedecin($roleid) {
|
||||
|
||||
return ($roleid == 'H3' || $roleid == 'H9' || $roleid == 'H15' || $roleid == 'H16' || $roleid == 'H17' || $roleid == 'H18' || $roleid == 'H19' || $roleid == 'H20' || $roleid == 'H21' || $roleid == 'H39' || $roleid == 'H22' || $roleid == 'H23' || $roleid == 'H24' || $roleid == 'H25' || $roleid == 'H26' || $roleid == 'H27' || $roleid == 'H28' || $roleid == 'H29' || $roleid == 'H30' || $roleid == 'H31');
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function isGro($roleid) {
|
||||
|
||||
return ($roleid == 'H4' || $roleid == 'H11' || $roleid == 'H12' );
|
||||
function isMedecin($roleid) {
|
||||
|
||||
return ($roleid == 'H3' || $roleid == 'H9' || $roleid == 'H15' || $roleid == 'H16' || $roleid == 'H17' || $roleid == 'H18' || $roleid == 'H19' || $roleid == 'H20' || $roleid == 'H21' || $roleid == 'H39' || $roleid == 'H22' || $roleid == 'H23' || $roleid == 'H24' || $roleid == 'H25' || $roleid == 'H26' || $roleid == 'H27' || $roleid == 'H28' || $roleid == 'H29' || $roleid == 'H30' || $roleid == 'H31');
|
||||
}
|
||||
|
||||
|
||||
|
||||
function isDG($roleid) {
|
||||
|
||||
return ($roleid == 'H2' || $roleid == 'H10' || $roleid == 'H32' || $roleid == 'H37');
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function isTopDG($roleid) {
|
||||
|
||||
return ($roleid == 'H2' || $roleid == 'H32' || $roleid == 'H37');
|
||||
function isGro($roleid) {
|
||||
|
||||
return ($roleid == 'H4' || $roleid == 'H11' || $roleid == 'H12' );
|
||||
}
|
||||
|
||||
|
||||
|
||||
function isDRMedical($roleid) {
|
||||
|
||||
return ($roleid == 'H3' || $roleid == 'H15' || $roleid == 'H16' || $roleid == 'H8');
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function isNotSup($roleid) {
|
||||
|
||||
return ($roleid != "H17" && $roleid != "H18" && $roleid != "H20" && $roleid != "H21" && $roleid == 'H39' && $roleid != "H24" && $roleid != "H25" && $roleid != "H26");
|
||||
function isDG($roleid) {
|
||||
|
||||
return ($roleid == 'H2' || $roleid == 'H10' || $roleid == 'H32' || $roleid == 'H37');
|
||||
}
|
||||
|
||||
|
||||
|
||||
function isResponsable($roleid) {
|
||||
|
||||
return ($roleid != "H2" && $roleid != 'H32' && $roleid != 'H37' && !isDRMedical($roleid) && isNotSup($roleid));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function isVP($roleid) {
|
||||
|
||||
return ($roleid == 'H7' || $roleid == 'H13' || $roleid == 'H14' || $roleid == "H35" || $roleid == "H43" || $roleid=="H45");
|
||||
function isTopDG($roleid) {
|
||||
|
||||
return ($roleid == 'H2' || $roleid == 'H32' || $roleid == 'H37');
|
||||
}
|
||||
|
||||
|
||||
|
||||
function isVM($roleid) {
|
||||
|
||||
return ($roleid == "H19" || $roleid == "H22" || $roleid == "H23" || $roleid == "H27" || $roleid == "H28" || $roleid == "H29" || $roleid == "H30" || $roleid == "H31" || $roleid == "H9");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function isDR($roleid) {
|
||||
|
||||
return ($roleid == "DIRECTEUR REGIONAL OUEST" || $roleid == "DIRECTEUR REGIONAL EST" || $roleid == "DIRECTEUR REGIONAL CENTRE");
|
||||
function isDRMedical($roleid) {
|
||||
|
||||
return ($roleid == 'H3' || $roleid == 'H15' || $roleid == 'H16' || $roleid == 'H8');
|
||||
}
|
||||
|
||||
|
||||
|
||||
function isUserInRole($owuserid, $vm2, $vm3, $roleid) {
|
||||
|
||||
|
||||
|
||||
$sub = getSubordinateRoleAndUsers($roleid);
|
||||
|
||||
foreach($sub as $roleid=>$userids) {
|
||||
|
||||
foreach($userids as $roleid2=>$userids2) {
|
||||
|
||||
if($owuserid == $roleid2 || $vm2 == $roleid2 || $vm3 == $roleid2)
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function isResponsable($roleid) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
function isByWilaya($id) {
|
||||
|
||||
return $id == '26' || $id == '48' || $id == '51' || $id == '125' || $id == '126' || $id == '130' || $id == '152' || $id == '46' || $id == '47' || $id == '49' || $id == '50' || $id == '52' || $id == '53' || $id == '104' || $id == '128' || $id == '131' || $id == '135' || $id == '136' || $id == '150' || $id == '153' || $id == '154' || $id == '186' || $id == '217' || $id == '44' || $id == '54' || $id == '55' || $id == '43' || $id == '124' || $id == '143' || $id == '158' || $id == '181' || $id == '254' || $id == '259' || $id == '134' || $id == '137' || $id == '149' || $id == '184' || $id == '187' || $id == '248' || $id == '253' || $id == '255' || $id == '38' || $id == '39' || $id == '40' || $id == '41' || $id == '42' || $id == '112' || $id == '113' || $id == '123' || $id == '127' || $id == '200' || $id == '201' || $id == '212' || $id == '216';
|
||||
}
|
||||
|
||||
|
||||
|
||||
function isOuestVMVP($roleid) {
|
||||
|
||||
return ($roleid != "H2" && $roleid != 'H32' && $roleid != 'H37' && !isDRMedical($roleid) && isNotSup($roleid));
|
||||
return $roleid=="H9" || $roleid=="H31" || $roleid=="H3" || $roleid=="H19" || $roleid=="H18" || $roleid=="H17" || $roleid=="H7" || $roleid=="H4" || $roleid=="H36" ; //(H7,H4,H36 VP)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function isEstVMVP($roleid) {
|
||||
|
||||
return $roleid=="H28" || $roleid=="H29" || $roleid=="H27" || $roleid=="H24" || $roleid=="H25" || $roleid=="H26" || $roleid=="H15" || $roleid=="H12" || $roleid=="H13" || $roleid=="H34" || $roleid=="H35" || $roleid=="H42" || $roleid == "H43"; //(H12,H13,H34,H35 VP)
|
||||
function isVP($roleid) {
|
||||
|
||||
return ($roleid == 'H7' || $roleid == 'H13' || $roleid == 'H14' || $roleid == "H35" || $roleid == "H43" || $roleid=="H45");
|
||||
}
|
||||
|
||||
|
||||
|
||||
function isCentreVMVP($roleid) {
|
||||
|
||||
return $roleid=="H16" || $roleid=="H20" || $roleid=="H21" || $roleid == 'H39' || $roleid=="H22" || $roleid=="H23" || $roleid=="H30" || $roleid=="H11" || $roleid=="H14" || $roleid == "H44" || $roleid=="H45"; //(H11,H14 VP)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function isSuperviseur($role) {
|
||||
|
||||
return $role=="SUPERVISEUR MEDICAL EST1" || $role=="SUPERVISEUR MEDICAL EST2" || $role=="SUPERVISEUR MEDICAL EST3" ||
|
||||
|
||||
$role=="SUPERVISEUR MEDICAL CENTRE1" || $role=="SUPERVISEUR MEDICAL CENTRE2" || $role=="SUPERVISEUR MEDICAL CENTRE3" ||
|
||||
|
||||
$role=="SUPERVISEUR MEDICAL OUEST1" || $role=="SUPERVISEUR MEDICAL OUEST2";
|
||||
return ($roleid == "H19" || $roleid == "H22" || $roleid == "H23" || $roleid == "H27" || $roleid == "H28" || $roleid == "H29" || $roleid == "H30" || $roleid == "H31" || $roleid == "H9");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function isMedicalSuperviseur($roleid) {
|
||||
|
||||
return $roleid == 'H17' || $roleid == 'H18' || $roleid == 'H20' || $roleid == 'H21' || $roleid == 'H24' || $roleid == 'H25' || $roleid == 'H26' || $roleid == 'H39';
|
||||
|
||||
|
||||
function isDR($roleid) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
function isDM($role) {
|
||||
|
||||
return $role=="DELEGUE MEDICAL EST1" || $role=="DELEGUE MEDICAL EST2" || $role=="DELEGUE MEDICAL EST3" ||
|
||||
|
||||
$role=="DELEGUE MEDICAL CENTRE1" || $role=="DELEGUE MEDICAL CENTRE2" || $role=="DELEGUE MEDICAL CENTRE3" ||
|
||||
|
||||
$role=="DELEGUE MEDICAL OUEST1" || $role=="DELEGUE MEDICAL OUEST2" || $role=="DELEGUE MEDICAL OUEST";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function isOuestVMText($role) {
|
||||
|
||||
return $role=="DIRECTEUR REGIONAL OUEST" || $role=="SUPERVISEUR MEDICAL OUEST1" || $role=="DELEGUE MEDICAL OUEST1"
|
||||
|
||||
|| $role=="SUPERVISEUR MEDICAL OUEST2" || $role=="DELEGUE MEDICAL OUEST2" || $role=="DELEGUE MEDICAL OUEST";
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function isCentreVMText($role) {
|
||||
|
||||
return $role=="DIRECTEUR REGIONAL CENTRE" || $role=="SUPERVISEUR MEDICAL CENTRE1" || $role=="DELEGUE MEDICAL CENTRE1"
|
||||
|
||||
|| $role=="SUPERVISEUR MEDICAL CENTRE2" || $role=="DELEGUE MEDICAL CENTRE2" || $role=="DELEGUE MEDICAL CENTRE3" || $role=="SUPERVISEUR MEDICAL CENTRE3";
|
||||
foreach($sub as $roleid=>$userids) {
|
||||
|
||||
foreach($userids as $roleid2=>$userids2) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
function isEstVMText($role) {
|
||||
|
||||
return $role=="DIRECTEUR REGIONAL EST" || $role=="SUPERVISEUR MEDICAL EST1" || $role=="DELEGUE MEDICAL EST1"
|
||||
|
||||
|| $role=="SUPERVISEUR MEDICAL EST2" || $role=="DELEGUE MEDICAL EST2" || $role=="SUPERVISEUR MEDICAL EST3" || $role=="DELEGUE MEDICAL EST3";
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function isKAM($role) {
|
||||
|
||||
return $role=="KEY ACCOUNT MANAGER CENTRE" || $role=="KEY ACCOUNT MANAGER EST" || $role=="KEY ACCOUNT MANAGER OUEST";
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function isVPText($role) {
|
||||
|
||||
return $role=="DELEGUE COMMERCIAL EST" || $role=="DELEGUE COMMERCIAL EST2" || $role=="DELEGUE COMMERCIAL CENTRE" || $role=="DELEGUE COMMERCIAL OUEST";
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function isOuestVPText($role) {
|
||||
|
||||
return $role=="KEY ACCOUNT MANAGER OUEST" || $role=="DELEGUE COMMERCIAL OUEST";
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function isCentreVPText($role) {
|
||||
|
||||
return $role=="KEY ACCOUNT MANAGER CENTRE" || $role=="DELEGUE COMMERCIAL CENTRE";
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function isEstVPText($role) {
|
||||
|
||||
return $role=="KEY ACCOUNT MANAGER EST" || $role=="DELEGUE COMMERCIAL EST" || $role=="DELEGUE COMMERCIAL EST2";
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function showNewDashBoard($userID) {
|
||||
|
||||
|
||||
|
||||
require_once 'include/utils/GetGroupUsers.php';
|
||||
|
||||
$userGroups_DB = new GetGroupUsers();
|
||||
|
||||
//145 id group
|
||||
|
||||
$userGroups_DB->getAllUsersInGroup(145);
|
||||
|
||||
$GetGroupUsers_DB = $userGroups_DB->group_users;
|
||||
|
||||
$is = in_array($userID, $GetGroupUsers_DB);
|
||||
|
||||
if($is == true){
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return false;
|
||||
|
||||
|
||||
|
||||
return $roleid=="H16" || $roleid=="H20" || $roleid=="H21" || $roleid == 'H39' || $roleid=="H22" || $roleid=="H23" || $roleid=="H30" || $roleid=="H11" || $roleid=="H14" || $roleid == "H44" || $roleid=="H45"; //(H11,H14 VP)
|
||||
}
|
||||
|
||||
function hideStock($roleid)
|
||||
{
|
||||
return ($roleid == 'H36' || $roleid == 'H44' || $roleid == 'H34' || $roleid == 'H42' || $roleid == 'H38' || $roleid == 'H37');
|
||||
}
|
||||
|
||||
//note de frais admin
|
||||
|
||||
function isAdminNdf($userId){
|
||||
|
||||
global $adb;
|
||||
|
||||
|
||||
|
||||
$query = "SELECT id_validateur_2 FROM note_de_frais_parametres";
|
||||
|
||||
$sql_get_result = $adb->query($query);
|
||||
|
||||
$res= array();
|
||||
|
||||
|
||||
|
||||
while ($recordinfo = $adb->fetch_array($sql_get_result)) {
|
||||
|
||||
$res[] = $recordinfo;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
if( $userId == 1 || $userId == $res[0]['id_validateur_2']){
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
return false;
|
||||
|
||||
|
||||
function isMedicalSuperviseur($roleid) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
function generatePassword($user_name, $crypt_type) {
|
||||
|
||||
|
||||
|
||||
$password = makeRandomPassword();
|
||||
|
||||
|
||||
|
||||
$salt = substr($user_name, 0, 2);
|
||||
|
||||
$salt = '$1$' . str_pad($salt, 9, '0');
|
||||
|
||||
$enc_password = crypt($password, $salt);
|
||||
|
||||
|
||||
|
||||
$user_hash = strtolower(md5($password));
|
||||
|
||||
|
||||
|
||||
return [$enc_password, $user_hash, $password];
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
function isVPSuperviseur($role){
|
||||
return $role=="H36" || $role=="H44" ||
|
||||
$role=="H34" || $role=="H42" ||
|
||||
$role=="H38" ;
|
||||
}
|
||||
|
||||
function isResponsableCommercial($role){
|
||||
return $role=="H10" ;
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,298 +1,596 @@
|
||||
/*+***********************************************************************************
|
||||
|
||||
* The contents of this file are subject to the vtiger CRM Public License Version 1.2
|
||||
|
||||
* ("License.txt"); 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.
|
||||
|
||||
*************************************************************************************/
|
||||
|
||||
|
||||
|
||||
function MainController($scope, $api, $webapp, $modal, $translate, $translatePartialLoader) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$translatePartialLoader.addPart('login');
|
||||
|
||||
$translatePartialLoader.addPart('home');
|
||||
|
||||
$scope.loginUser = null;
|
||||
|
||||
$scope.modules = [];
|
||||
|
||||
$scope.modulesCount = 0;
|
||||
|
||||
$scope.language = "fr_fr";
|
||||
|
||||
$api.get('Portal/Ping').success(function (user) {
|
||||
|
||||
if (user) {
|
||||
|
||||
$scope.loginUser = true;
|
||||
|
||||
$translate.use(user.language);
|
||||
|
||||
$scope.language = user.language;
|
||||
|
||||
if (localStorage.getItem('modules') !== null && localStorage.getItem('modules') !== 'null') {
|
||||
|
||||
$scope.modules = JSON.parse(localStorage.getItem('modules'));
|
||||
|
||||
$scope.modulesCount = Object.keys($scope.modules).length;
|
||||
|
||||
if (localStorage.getItem('orgName') == undefined) {
|
||||
|
||||
$scope.companyDetails();
|
||||
|
||||
}
|
||||
|
||||
$scope.$root.$emit('LoginUser.Ready');
|
||||
|
||||
} else {
|
||||
|
||||
$scope.fecthModules($scope.language);
|
||||
|
||||
$scope.$root.$emit('LoginUser.Ready');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
$scope.fecthModules = function (language) {
|
||||
|
||||
|
||||
|
||||
$api.get('/FetchModules', {language: language}).success(function (result) {
|
||||
|
||||
|
||||
|
||||
delete(result.language);
|
||||
|
||||
$scope.modules = result.moduleInfo;
|
||||
|
||||
$scope.modulesCount = Object.keys($scope.modules).length;
|
||||
|
||||
localStorage.setItem('modules', JSON.stringify($scope.modules));
|
||||
|
||||
if (result.endDate !== undefined)
|
||||
|
||||
localStorage.setItem('supportNotification', result.endDate)
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
$scope.changePassword = function () {
|
||||
|
||||
var modalInstance = $modal.open({
|
||||
|
||||
templateUrl: 'changePassword.template',
|
||||
|
||||
controller: Main_Setting_Component,
|
||||
|
||||
backdrop: 'static',
|
||||
|
||||
keyboard: 'false',
|
||||
|
||||
resolve: {
|
||||
|
||||
record: function () {
|
||||
|
||||
return {};
|
||||
|
||||
},
|
||||
|
||||
api: function () {
|
||||
|
||||
return $api;
|
||||
|
||||
},
|
||||
|
||||
webapp: function () {
|
||||
|
||||
return $webapp;
|
||||
|
||||
},
|
||||
|
||||
module: function () {
|
||||
|
||||
return $scope.module;
|
||||
|
||||
},
|
||||
|
||||
translatePartialLoader: function () {
|
||||
|
||||
return $translatePartialLoader;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
$scope.forgotPassword = function () {
|
||||
|
||||
var modalInstance = $modal.open({
|
||||
|
||||
templateUrl: 'forgotPassword.template',
|
||||
|
||||
controller: ForgotPassword_Component,
|
||||
|
||||
backdrop: 'static',
|
||||
|
||||
keyboard: 'false',
|
||||
|
||||
resolve: {
|
||||
|
||||
api: function () {
|
||||
|
||||
return $api;
|
||||
|
||||
},
|
||||
|
||||
webapp: function () {
|
||||
|
||||
return $webapp;
|
||||
|
||||
},
|
||||
|
||||
translatePartialLoader: function () {
|
||||
|
||||
return $translatePartialLoader;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
$scope.setLanguage = function (lang) {
|
||||
|
||||
$translate.use(lang);
|
||||
|
||||
};
|
||||
|
||||
$scope.logout = function () {
|
||||
|
||||
localStorage.clear();
|
||||
|
||||
window.location.href = "index.php?module=Portal&view=Logout";
|
||||
|
||||
}
|
||||
|
||||
$scope.isActive = function (module) {
|
||||
|
||||
var url = purl();
|
||||
|
||||
var routeModule = url.param('module');
|
||||
|
||||
if (routeModule !== undefined) {
|
||||
|
||||
if (module === routeModule) {
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
else {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (module == 'Home' && routeModule === undefined) {
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$scope.companyDetails = function () {
|
||||
|
||||
$api.get('/FetchCompanyDetails').success(function (data) {
|
||||
|
||||
if (data.message === undefined && data.code === undefined)
|
||||
|
||||
$scope.companyInfo = angular.copy(data);
|
||||
|
||||
else if (data.message === 'Contacts module is disabled') {
|
||||
|
||||
alert(data.message);
|
||||
|
||||
localStorage.clear();
|
||||
|
||||
window.location.href = 'index.php?module=Portal&view=Logout';
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
$scope.disableSearch = true;
|
||||
|
||||
$scope.Query = {};
|
||||
|
||||
$scope.searchEvent = function (Query) {
|
||||
|
||||
$scope.$broadcast('searchFor', $scope.Query.search);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
$scope.makeAutoComplete = function () {
|
||||
|
||||
$scope.$broadcast("autofill:update");
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
$scope.login = function (validity) {
|
||||
|
||||
q = {};
|
||||
|
||||
q.username = $scope.username;
|
||||
|
||||
q.password = $scope.password;
|
||||
|
||||
q.language = $scope.language;
|
||||
|
||||
if (validity) {
|
||||
|
||||
$scope.noUserName = false;
|
||||
|
||||
$scope.noPassword = false;
|
||||
|
||||
$api.post('Portal/Login', {q: q}).success(function (response) {
|
||||
|
||||
if (response.success) {
|
||||
|
||||
window.location.href = 'index.php';
|
||||
|
||||
}
|
||||
|
||||
else {
|
||||
|
||||
$scope.loginFailed = true;
|
||||
|
||||
$scope.loginMessage = response.error.message;
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
else if (!validity) {
|
||||
|
||||
if (q.username === undefined && q.password === undefined) {
|
||||
|
||||
$scope.noUserName = true;
|
||||
|
||||
$scope.loginFailed = false;
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
if (q.password !== undefined && q.username === undefined) {
|
||||
|
||||
$scope.noUserName = true;
|
||||
|
||||
$scope.noPassword = false;
|
||||
|
||||
$scope.loginFailed = false;
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
if (q.username !== undefined && q.password === undefined) {
|
||||
|
||||
$scope.noPassword = true;
|
||||
|
||||
$scope.noUserName = false;
|
||||
|
||||
$scope.loginFailed = false;
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
$api.get('Portal/FetchCompanyTitle').then(function (err, data) {
|
||||
|
||||
if (err) {
|
||||
|
||||
//Error fetching company title.
|
||||
|
||||
$scope.companyTitle = '';
|
||||
|
||||
}
|
||||
|
||||
if (data) {
|
||||
|
||||
$scope.companyTitle = data.result;
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function Main_Setting_Component($scope, $modalInstance, record, api, $webapp, module, translatePartialLoader) {
|
||||
|
||||
if (translatePartialLoader !== undefined) {
|
||||
|
||||
translatePartialLoader.addPart('home');
|
||||
$scope.setLanguage = function (lang) {
|
||||
|
||||
$translate.use(lang);
|
||||
|
||||
};
|
||||
|
||||
$scope.logout = function () {
|
||||
|
||||
localStorage.clear();
|
||||
|
||||
window.location.href = "index.php?module=Portal&view=Logout";
|
||||
|
||||
}
|
||||
|
||||
$scope.isActive = function (module) {
|
||||
|
||||
var url = purl();
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (routeModule !== undefined) {
|
||||
$scope.editRecord = angular.copy(record);
|
||||
|
||||
$scope.data = {'oldPassword': "", 'newPassword': "", 'confirmPassword': ""};
|
||||
|
||||
$scope.save = function () {
|
||||
|
||||
api.post('Portal/ChangePassword', {record: $scope.data}).success(function (result) {
|
||||
|
||||
$modalInstance.dismiss();
|
||||
|
||||
if (result.result.message === undefined) {
|
||||
|
||||
alert(result.result);
|
||||
|
||||
$webapp.busy(false);
|
||||
|
||||
localStorage.clear();
|
||||
|
||||
window.location.href = 'index.php?module=Portal&view=Logout';
|
||||
|
||||
}
|
||||
|
||||
else if (result.result.message !== undefined) {
|
||||
|
||||
alert(result.result.message)
|
||||
|
||||
$webapp.busy(false);
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
$scope.cancel = function () {
|
||||
|
||||
$modalInstance.dismiss('cancel');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function ForgotPassword_Component($scope, $modalInstance, api, $webapp, translatePartialLoader) {
|
||||
|
||||
if (translatePartialLoader !== undefined) {
|
||||
|
||||
translatePartialLoader.addPart('home');
|
||||
|
||||
}
|
||||
|
||||
$scope.data = {'email': ""};
|
||||
|
||||
$scope.updatePassword = function () {
|
||||
|
||||
$webapp.busy(true);
|
||||
|
||||
api.post('Portal/ForgotPassword', {email: $scope.data.email}).success(function (data) {
|
||||
|
||||
$modalInstance.dismiss();
|
||||
|
||||
if (data.result.message === undefined) {
|
||||
|
||||
alert(data.result);
|
||||
|
||||
}
|
||||
|
||||
else if (data.result.message !== undefined) {
|
||||
|
||||
alert(data.result.message);
|
||||
|
||||
}
|
||||
|
||||
$webapp.busy(false);
|
||||
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
$scope.cancel = function () {
|
||||
|
||||
$modalInstance.dismiss('cancel');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function globalSearchController($scope, $http, $timeout, $webapp, $translate) {
|
||||
|
||||
|
||||
|
||||
jQuery(".search-icon").on('click', function (e) {
|
||||
|
||||
jQuery(".search-box").focus();
|
||||
|
||||
})
|
||||
|
||||
|
||||
|
||||
$scope.search = '';
|
||||
|
||||
|
||||
|
||||
$scope.getModuleLabelClass = function (module) {
|
||||
|
||||
return 'label label-info';
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
$scope.searchItemSelected = function (item, $timeout) {
|
||||
|
||||
if (item.model.count > 0) {
|
||||
|
||||
var module = item.model.module.module;
|
||||
|
||||
var url = "index.php?module=" + module + "&view=Detail&id=" + item.model.id;
|
||||
|
||||
window.location.href = url;
|
||||
|
||||
$scope.disableSearch = true;
|
||||
|
||||
$scope.Query = {};
|
||||
|
||||
|
||||
}
|
||||
|
||||
else {
|
||||
|
||||
$scope.search = '';
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
$scope.searchRecords = function (searchKey, $timeout) {
|
||||
|
||||
var params = {
|
||||
|
||||
"api": "SearchRecords",
|
||||
|
||||
"searchKey": searchKey,
|
||||
|
||||
"module": "Portal"
|
||||
|
||||
};
|
||||
|
||||
var result = [];
|
||||
|
||||
return $http.get("index.php", {params: params}).then(function (response) {
|
||||
|
||||
$webapp.busy();
|
||||
|
||||
var data = response.data.result;
|
||||
|
||||
angular.forEach(data, function (moduleInfo, i) {
|
||||
|
||||
if (angular.isObject(moduleInfo) && moduleInfo.length !== 0) {
|
||||
|
||||
if (i !== 'language') {
|
||||
|
||||
var labelField = 'label';
|
||||
|
||||
angular.forEach(moduleInfo, function (recordInfo) {
|
||||
|
||||
if (recordInfo.hasOwnProperty('id')) {
|
||||
|
||||
var res = {value: recordInfo[labelField], module: {"module": i, "uiLabel": moduleInfo.uiLabel}, id: recordInfo.id, count: 1};
|
||||
|
||||
result.push(res);
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
if (result.length < 1) {
|
||||
|
||||
//No results found
|
||||
|
||||
$scope.noMatchFound = true;
|
||||
|
||||
var noRecords = {value: $translate.instant('No matches found.'), module: {}, count: 0};
|
||||
|
||||
result.push(noRecords);
|
||||
|
||||
}
|
||||
|
||||
$webapp.busy(false);
|
||||
|
||||
return result;
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
</BODY>
|
||||
|
||||
</HTML>
|
||||
|
||||
|
||||
19288
file_upload/Chart.bundle.js
Normal file
19288
file_upload/Chart.bundle.js
Normal file
File diff suppressed because it is too large
Load Diff
126
file_upload/MyFont.css
Normal file
126
file_upload/MyFont.css
Normal file
@@ -0,0 +1,126 @@
|
||||
/* cyrillic-ext */
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2JL7SUc.woff2) format('woff2');
|
||||
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||
}
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa0ZL7SUc.woff2) format('woff2');
|
||||
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
/* greek-ext */
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2ZL7SUc.woff2) format('woff2');
|
||||
unicode-range: U+1F00-1FFF;
|
||||
}
|
||||
/* greek */
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1pL7SUc.woff2) format('woff2');
|
||||
unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
|
||||
}
|
||||
/* vietnamese */
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2pL7SUc.woff2) format('woff2');
|
||||
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa25L7SUc.woff2) format('woff2');
|
||||
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1ZL7.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
/* cyrillic-ext */
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2JL7SUc.woff2) format('woff2');
|
||||
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||
}
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa0ZL7SUc.woff2) format('woff2');
|
||||
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
/* greek-ext */
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2ZL7SUc.woff2) format('woff2');
|
||||
unicode-range: U+1F00-1FFF;
|
||||
}
|
||||
/* greek */
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1pL7SUc.woff2) format('woff2');
|
||||
unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
|
||||
}
|
||||
/* vietnamese */
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2pL7SUc.woff2) format('woff2');
|
||||
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa25L7SUc.woff2) format('woff2');
|
||||
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1ZL7.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
363
file_upload/chartjs-gauge.js
Normal file
363
file_upload/chartjs-gauge.js
Normal file
@@ -0,0 +1,363 @@
|
||||
/*!
|
||||
* chartjs-gauge.js v0.3.0
|
||||
* https://github.com/haiiaaa/chartjs-gauge/
|
||||
* (c) 2021 chartjs-gauge.js Contributors
|
||||
* Released under the MIT License
|
||||
*/
|
||||
(function (global, factory) {
|
||||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('chart.js')) :
|
||||
typeof define === 'function' && define.amd ? define(['chart.js'], factory) :
|
||||
(global = global || self, global.Gauge = factory(global.Chart));
|
||||
}(this, (function (Chart) { 'use strict';
|
||||
|
||||
Chart = Chart && Object.prototype.hasOwnProperty.call(Chart, 'default') ? Chart['default'] : Chart;
|
||||
|
||||
function _defineProperty(obj, key, value) {
|
||||
if (key in obj) {
|
||||
Object.defineProperty(obj, key, {
|
||||
value: value,
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true
|
||||
});
|
||||
} else {
|
||||
obj[key] = value;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
function ownKeys(object, enumerableOnly) {
|
||||
var keys = Object.keys(object);
|
||||
|
||||
if (Object.getOwnPropertySymbols) {
|
||||
var symbols = Object.getOwnPropertySymbols(object);
|
||||
if (enumerableOnly) symbols = symbols.filter(function (sym) {
|
||||
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
|
||||
});
|
||||
keys.push.apply(keys, symbols);
|
||||
}
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
function _objectSpread2(target) {
|
||||
for (var i = 1; i < arguments.length; i++) {
|
||||
var source = arguments[i] != null ? arguments[i] : {};
|
||||
|
||||
if (i % 2) {
|
||||
ownKeys(Object(source), true).forEach(function (key) {
|
||||
_defineProperty(target, key, source[key]);
|
||||
});
|
||||
} else if (Object.getOwnPropertyDescriptors) {
|
||||
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
|
||||
} else {
|
||||
ownKeys(Object(source)).forEach(function (key) {
|
||||
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
Chart.defaults._set('gauge', {
|
||||
needle: {
|
||||
// Needle circle radius as the percentage of the chart area width
|
||||
radiusPercentage: 2,
|
||||
// Needle width as the percentage of the chart area width
|
||||
widthPercentage: 3.2,
|
||||
// Needle length as the percentage of the interval between inner radius (0%) and outer radius (100%) of the arc
|
||||
lengthPercentage: 80,
|
||||
// The color of the needle
|
||||
color: 'rgba(0, 0, 0, 1)'
|
||||
},
|
||||
valueLabel: {
|
||||
// fontSize: undefined
|
||||
display: true,
|
||||
formatter: null,
|
||||
color: 'rgba(255, 255, 255, 1)',
|
||||
backgroundColor: 'rgba(0, 0, 0, 1)',
|
||||
borderRadius: 5,
|
||||
padding: {
|
||||
top: 5,
|
||||
right: 5,
|
||||
bottom: 5,
|
||||
left: 5
|
||||
},
|
||||
bottomMarginPercentage: 5
|
||||
},
|
||||
animation: {
|
||||
duration: 1000,
|
||||
animateRotate: true,
|
||||
animateScale: false
|
||||
},
|
||||
// The percentage of the chart that we cut out of the middle.
|
||||
cutoutPercentage: 50,
|
||||
// The rotation of the chart, where the first data arc begins.
|
||||
rotation: -Math.PI,
|
||||
// The total circumference of the chart.
|
||||
circumference: Math.PI,
|
||||
legend: {
|
||||
display: false
|
||||
},
|
||||
tooltips: {
|
||||
enabled: false
|
||||
}
|
||||
});
|
||||
|
||||
var GaugeController = Chart.controllers.doughnut.extend({
|
||||
getValuePercent: function getValuePercent(_ref, value) {
|
||||
var minValue = _ref.minValue,
|
||||
data = _ref.data;
|
||||
var min = minValue || 0;
|
||||
var max = data[data.length - 1] || 1;
|
||||
var length = max - min;
|
||||
var percent = (value - min) / length;
|
||||
return percent;
|
||||
},
|
||||
getWidth: function getWidth(chart) {
|
||||
return chart.chartArea.right - chart.chartArea.left;
|
||||
},
|
||||
getTranslation: function getTranslation(chart) {
|
||||
var chartArea = chart.chartArea,
|
||||
offsetX = chart.offsetX,
|
||||
offsetY = chart.offsetY;
|
||||
var centerX = (chartArea.left + chartArea.right) / 2;
|
||||
var centerY = (chartArea.top + chartArea.bottom) / 2;
|
||||
var dx = centerX + offsetX;
|
||||
var dy = centerY + offsetY;
|
||||
return {
|
||||
dx: dx,
|
||||
dy: dy
|
||||
};
|
||||
},
|
||||
getAngle: function getAngle(_ref2) {
|
||||
var chart = _ref2.chart,
|
||||
valuePercent = _ref2.valuePercent;
|
||||
var _chart$options = chart.options,
|
||||
rotation = _chart$options.rotation,
|
||||
circumference = _chart$options.circumference;
|
||||
return rotation + circumference * valuePercent;
|
||||
},
|
||||
|
||||
/* TODO set min padding, not applied until chart.update() (also chartArea must have been set)
|
||||
setBottomPadding(chart) {
|
||||
const needleRadius = this.getNeedleRadius(chart);
|
||||
const padding = this.chart.config.options.layout.padding;
|
||||
if (needleRadius > padding.bottom) {
|
||||
padding.bottom = needleRadius;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
*/
|
||||
drawNeedle: function drawNeedle(ease) {
|
||||
if (!this.chart.animating) {
|
||||
// triggered when hovering
|
||||
ease = 1;
|
||||
}
|
||||
|
||||
var _this$chart = this.chart,
|
||||
ctx = _this$chart.ctx,
|
||||
config = _this$chart.config,
|
||||
innerRadius = _this$chart.innerRadius,
|
||||
outerRadius = _this$chart.outerRadius;
|
||||
var dataset = config.data.datasets[this.index];
|
||||
|
||||
var _this$getMeta = this.getMeta(),
|
||||
previous = _this$getMeta.previous;
|
||||
|
||||
var _config$options$needl = config.options.needle,
|
||||
radiusPercentage = _config$options$needl.radiusPercentage,
|
||||
widthPercentage = _config$options$needl.widthPercentage,
|
||||
lengthPercentage = _config$options$needl.lengthPercentage,
|
||||
color = _config$options$needl.color;
|
||||
var width = this.getWidth(this.chart);
|
||||
var needleRadius = radiusPercentage / 100 * width;
|
||||
var needleWidth = widthPercentage / 100 * width;
|
||||
var needleLength = lengthPercentage / 100 * (outerRadius - innerRadius) + innerRadius; // center
|
||||
|
||||
var _this$getTranslation = this.getTranslation(this.chart),
|
||||
dx = _this$getTranslation.dx,
|
||||
dy = _this$getTranslation.dy; // interpolate
|
||||
|
||||
|
||||
var origin = this.getAngle({
|
||||
chart: this.chart,
|
||||
valuePercent: previous.valuePercent
|
||||
}); // TODO valuePercent is in current.valuePercent also
|
||||
|
||||
var target = this.getAngle({
|
||||
chart: this.chart,
|
||||
valuePercent: this.getValuePercent(dataset, dataset.value)
|
||||
});
|
||||
var angle = origin + (target - origin) * ease; // draw
|
||||
|
||||
ctx.save();
|
||||
ctx.translate(dx, dy);
|
||||
ctx.rotate(angle);
|
||||
ctx.fillStyle = color; // draw circle
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.ellipse(0, 0, needleRadius, needleRadius, 0, 0, 2 * Math.PI);
|
||||
ctx.fill(); // draw needle
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(0, needleWidth / 2);
|
||||
ctx.lineTo(needleLength, 0);
|
||||
ctx.lineTo(0, -needleWidth / 2);
|
||||
ctx.fill();
|
||||
ctx.restore();
|
||||
},
|
||||
drawValueLabel: function drawValueLabel(ease) {
|
||||
// eslint-disable-line no-unused-vars
|
||||
if (!this.chart.config.options.valueLabel.display) {
|
||||
return;
|
||||
}
|
||||
|
||||
var _this$chart2 = this.chart,
|
||||
ctx = _this$chart2.ctx,
|
||||
config = _this$chart2.config;
|
||||
var defaultFontFamily = config.options.defaultFontFamily;
|
||||
var dataset = config.data.datasets[this.index];
|
||||
var _config$options$value = config.options.valueLabel,
|
||||
formatter = _config$options$value.formatter,
|
||||
fontSize = _config$options$value.fontSize,
|
||||
color = _config$options$value.color,
|
||||
backgroundColor = _config$options$value.backgroundColor,
|
||||
borderRadius = _config$options$value.borderRadius,
|
||||
padding = _config$options$value.padding,
|
||||
bottomMarginPercentage = _config$options$value.bottomMarginPercentage;
|
||||
var width = this.getWidth(this.chart);
|
||||
var bottomMargin = bottomMarginPercentage / 100 * width;
|
||||
|
||||
var fmt = formatter || function (value) {
|
||||
return value;
|
||||
};
|
||||
|
||||
var valueText = fmt(dataset.value).toString();
|
||||
ctx.textBaseline = 'middle';
|
||||
ctx.textAlign = 'center';
|
||||
|
||||
if (fontSize) {
|
||||
ctx.font = "".concat(fontSize, "px ").concat(defaultFontFamily);
|
||||
} // const { width: textWidth, actualBoundingBoxAscent, actualBoundingBoxDescent } = ctx.measureText(valueText);
|
||||
// const textHeight = actualBoundingBoxAscent + actualBoundingBoxDescent;
|
||||
|
||||
|
||||
var _ctx$measureText = ctx.measureText(valueText),
|
||||
textWidth = _ctx$measureText.width; // approximate height until browsers support advanced TextMetrics
|
||||
|
||||
|
||||
var textHeight = Math.max(ctx.measureText('m').width, ctx.measureText("\uFF37").width);
|
||||
var x = -(padding.left + textWidth / 2);
|
||||
var y = -(padding.top + textHeight / 2);
|
||||
var w = padding.left + textWidth + padding.right;
|
||||
var h = padding.top + textHeight + padding.bottom; // center
|
||||
|
||||
var _this$getTranslation2 = this.getTranslation(this.chart),
|
||||
dx = _this$getTranslation2.dx,
|
||||
dy = _this$getTranslation2.dy; // add rotation
|
||||
|
||||
|
||||
var rotation = this.chart.options.rotation % (Math.PI * 2.0);
|
||||
dx += bottomMargin * Math.cos(rotation + Math.PI / 2);
|
||||
dy += bottomMargin * Math.sin(rotation + Math.PI / 2); // draw
|
||||
|
||||
ctx.save();
|
||||
ctx.translate(dx, dy); // draw background
|
||||
|
||||
ctx.beginPath();
|
||||
Chart.helpers.canvas.roundedRect(ctx, x, y, w, h, borderRadius);
|
||||
ctx.fillStyle = backgroundColor;
|
||||
ctx.fill(); // draw value text
|
||||
|
||||
ctx.fillStyle = color || config.options.defaultFontColor;
|
||||
var magicNumber = 0.075; // manual testing
|
||||
|
||||
ctx.fillText(valueText, 0, textHeight * magicNumber);
|
||||
ctx.restore();
|
||||
},
|
||||
// overrides
|
||||
update: function update(reset) {
|
||||
var dataset = this.chart.config.data.datasets[this.index];
|
||||
dataset.minValue = dataset.minValue || 0;
|
||||
var meta = this.getMeta();
|
||||
var initialValue = {
|
||||
valuePercent: 0
|
||||
}; // animations on will call update(reset) before update()
|
||||
|
||||
if (reset) {
|
||||
meta.previous = null;
|
||||
meta.current = initialValue;
|
||||
} else {
|
||||
dataset.data.sort(function (a, b) {
|
||||
return a - b;
|
||||
});
|
||||
meta.previous = meta.current || initialValue;
|
||||
meta.current = {
|
||||
valuePercent: this.getValuePercent(dataset, dataset.value)
|
||||
};
|
||||
}
|
||||
|
||||
Chart.controllers.doughnut.prototype.update.call(this, reset);
|
||||
},
|
||||
updateElement: function updateElement(arc, index, reset) {
|
||||
// TODO handle reset and options.animation
|
||||
Chart.controllers.doughnut.prototype.updateElement.call(this, arc, index, reset);
|
||||
var dataset = this.getDataset();
|
||||
var data = dataset.data; // const { options } = this.chart.config;
|
||||
// scale data
|
||||
|
||||
var previousValue = index === 0 ? dataset.minValue : data[index - 1];
|
||||
var value = data[index];
|
||||
var startAngle = this.getAngle({
|
||||
chart: this.chart,
|
||||
valuePercent: this.getValuePercent(dataset, previousValue)
|
||||
});
|
||||
var endAngle = this.getAngle({
|
||||
chart: this.chart,
|
||||
valuePercent: this.getValuePercent(dataset, value)
|
||||
});
|
||||
var circumference = endAngle - startAngle;
|
||||
arc._model = _objectSpread2({}, arc._model, {
|
||||
startAngle: startAngle,
|
||||
endAngle: endAngle,
|
||||
circumference: circumference
|
||||
});
|
||||
},
|
||||
draw: function draw(ease) {
|
||||
Chart.controllers.doughnut.prototype.draw.call(this, ease);
|
||||
this.drawNeedle(ease);
|
||||
this.drawValueLabel(ease);
|
||||
}
|
||||
});
|
||||
|
||||
/* eslint-disable max-len, func-names */
|
||||
var polyfill = function polyfill() {
|
||||
if (CanvasRenderingContext2D.prototype.ellipse === undefined) {
|
||||
CanvasRenderingContext2D.prototype.ellipse = function (x, y, radiusX, radiusY, rotation, startAngle, endAngle, antiClockwise) {
|
||||
this.save();
|
||||
this.translate(x, y);
|
||||
this.rotate(rotation);
|
||||
this.scale(radiusX, radiusY);
|
||||
this.arc(0, 0, 1, startAngle, endAngle, antiClockwise);
|
||||
this.restore();
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
polyfill();
|
||||
Chart.controllers.gauge = GaugeController;
|
||||
|
||||
Chart.Gauge = function (context, config) {
|
||||
config.type = 'gauge';
|
||||
return new Chart(context, config);
|
||||
};
|
||||
|
||||
var index = Chart.Gauge;
|
||||
|
||||
return index;
|
||||
|
||||
})));
|
||||
1385
file_upload/chartjs-plugin-datalabels.js
Normal file
1385
file_upload/chartjs-plugin-datalabels.js
Normal file
File diff suppressed because it is too large
Load Diff
1
file_upload/dataTables.bootstrap4.min.css
vendored
Normal file
1
file_upload/dataTables.bootstrap4.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
4
file_upload/dataTables.bootstrap4.min.js
vendored
Normal file
4
file_upload/dataTables.bootstrap4.min.js
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
/*! DataTables Bootstrap 4 integration
|
||||
* ©2011-2017 SpryMedia Ltd - datatables.net/license
|
||||
*/
|
||||
!function(t){var n,o;"function"==typeof define&&define.amd?define(["jquery","datatables.net"],function(e){return t(e,window,document)}):"object"==typeof exports?(n=require("jquery"),o=function(e,a){a.fn.dataTable||require("datatables.net")(e,a)},"undefined"==typeof window?module.exports=function(e,a){return e=e||window,a=a||n(e),o(e,a),t(a,0,e.document)}:(o(window,n),module.exports=t(n,window,window.document))):t(jQuery,window,document)}(function(x,e,n,o){"use strict";var r=x.fn.dataTable;return x.extend(!0,r.defaults,{dom:"<'row'<'col-sm-12 col-md-6'l><'col-sm-12 col-md-6'f>><'row'<'col-sm-12'tr>><'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",renderer:"bootstrap"}),x.extend(r.ext.classes,{sWrapper:"dataTables_wrapper dt-bootstrap4",sFilterInput:"form-control form-control-sm",sLengthSelect:"custom-select custom-select-sm form-control form-control-sm",sProcessing:"dataTables_processing card",sPageButton:"paginate_button page-item"}),r.ext.renderer.pageButton.bootstrap=function(i,e,d,a,l,c){function u(e,a){for(var t,n,o=function(e){e.preventDefault(),x(e.currentTarget).hasClass("disabled")||m.page()==e.data.action||m.page(e.data.action).draw("page")},r=0,s=a.length;r<s;r++)if(t=a[r],Array.isArray(t))u(e,t);else{switch(f=p="",t){case"ellipsis":p="…",f="disabled";break;case"first":p=g.sFirst,f=t+(0<l?"":" disabled");break;case"previous":p=g.sPrevious,f=t+(0<l?"":" disabled");break;case"next":p=g.sNext,f=t+(l<c-1?"":" disabled");break;case"last":p=g.sLast,f=t+(l<c-1?"":" disabled");break;default:p=t+1,f=l===t?"active":""}p&&(n=-1!==f.indexOf("disabled"),n=x("<li>",{class:b.sPageButton+" "+f,id:0===d&&"string"==typeof t?i.sTableId+"_"+t:null}).append(x("<a>",{href:n?null:"#","aria-controls":i.sTableId,"aria-disabled":n?"true":null,"aria-label":w[t],role:"link","aria-current":"active"===f?"page":null,"data-dt-idx":t,tabindex:n?-1:i.iTabIndex,class:"page-link"}).html(p)).appendTo(e),i.oApi._fnBindAction(n,{action:t},o))}}var p,f,t,m=new r.Api(i),b=i.oClasses,g=i.oLanguage.oPaginate,w=i.oLanguage.oAria.paginate||{};try{t=x(e).find(n.activeElement).data("dt-idx")}catch(e){}u(x(e).empty().html('<ul class="pagination"/>').children("ul"),a),t!==o&&x(e).find("[data-dt-idx="+t+"]").trigger("focus")},r});
|
||||
4
file_upload/jquery.dataTables.min.js
vendored
Normal file
4
file_upload/jquery.dataTables.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
24
fix_permissions.php
Normal file
24
fix_permissions.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
function chmodRecursive($path, $filePerm = 0644, $dirPerm = 0755)
|
||||
{
|
||||
if (!file_exists($path)) return false;
|
||||
|
||||
if (is_file($path)) {
|
||||
return chmod($path, $filePerm);
|
||||
}
|
||||
|
||||
if (is_dir($path)) {
|
||||
$dir = new DirectoryIterator($path);
|
||||
foreach ($dir as $item) {
|
||||
if ($item->isDot()) continue;
|
||||
chmodRecursive($item->getPathname(), $filePerm, $dirPerm);
|
||||
}
|
||||
return chmod($path, $dirPerm);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
$storagePath = __DIR__ . '/storage';
|
||||
chmodRecursive($storagePath);
|
||||
echo "✅ Permissions fixed for storage folder.";
|
||||
?>
|
||||
@@ -2318,4 +2318,15 @@ function appendFromClauseToQuery($query,$fromClause) {
|
||||
return $query;
|
||||
}
|
||||
|
||||
function getMySubordinates($roleid){
|
||||
global $adb;
|
||||
$subordinates = array();
|
||||
$user_query = "select * from vw_users_with_roles where parentrole like '%::$roleid::%'";
|
||||
$result2 = $adb->query($user_query);
|
||||
while ($row = $adb->fetchByAssoc($result2)) {
|
||||
array_push($subordinates, $row['user_name']);
|
||||
}
|
||||
return $subordinates ;
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1193,7 +1193,13 @@ class Vtiger_WebUI extends Vtiger_EntryPoint {
|
||||
}
|
||||
|
||||
|
||||
if($module == "PharmexObjective"){
|
||||
|
||||
include "PharmexObjective.php";
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
1
layouts/v7/lib/vt-icons/variables.css
Normal file
1
layouts/v7/lib/vt-icons/variables.css
Normal file
@@ -0,0 +1 @@
|
||||
/*# sourceMappingURL=variables.css.map */
|
||||
1
layouts/v7/lib/vt-icons/variables.css.map
Normal file
1
layouts/v7/lib/vt-icons/variables.css.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":[],"names":[],"mappings":"","file":"variables.css"}
|
||||
@@ -28,6 +28,41 @@ Vtiger_Detail_Js("Inventory_Detail_Js", {
|
||||
app.helper.showModal(response,data);
|
||||
});
|
||||
},
|
||||
testSendEmailPDFClickHandler : function(url){
|
||||
var params = {
|
||||
module: 'Vtiger',
|
||||
parent: 'Settings',
|
||||
action: 'OutgoingServerAjax',
|
||||
mode: 'sendTestMail'
|
||||
};
|
||||
|
||||
app.helper.showProgress();
|
||||
|
||||
app.request.post({ data: params }).then(function (err, data) {
|
||||
console.log("data",data);
|
||||
console.log("err",err);
|
||||
|
||||
|
||||
app.helper.hideProgress();
|
||||
if (err === null) {
|
||||
if (data && data.success) {
|
||||
app.helper.showSuccessNotification({
|
||||
message: data.message || '✅ Test mail sent successfully!'
|
||||
});
|
||||
} else if (data && data.error) {
|
||||
app.helper.showErrorNotification({
|
||||
message: data.error.message || '❌ Mailer Error.'
|
||||
});
|
||||
} else {
|
||||
app.helper.showErrorNotification({
|
||||
message: '❌ Unknown error. Check logs.'
|
||||
});
|
||||
}
|
||||
} else {
|
||||
app.helper.showErrorNotification({ message: '❌ ' + err.message });
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
showRecordPreview: function(recordId, templateId) {
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
{*+**********************************************************************************
|
||||
* The contents of this file are subject to the vtiger CRM Public License Version 1.1
|
||||
* ("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.
|
||||
************************************************************************************}
|
||||
{* modules/Settings/Vtiger/views/OutgoingServerEdit.php *}
|
||||
{*+**********************************************************************************
|
||||
* The contents of this file are subject to the vtiger CRM Public License Version 1.1
|
||||
* ("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.
|
||||
************************************************************************************}
|
||||
{* modules/Settings/Vtiger/views/OutgoingServerEdit.php *}
|
||||
|
||||
{strip}
|
||||
{strip}
|
||||
<div class="editViewPageDiv editViewContainer" id="EditViewOutgoing" style="padding-top:0px;">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<div>
|
||||
@@ -87,6 +87,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<button class="btn btn-info" id="sendTestMail">Send Test Mail</button>
|
||||
</div>
|
||||
</div>
|
||||
{/strip}
|
||||
{/strip}
|
||||
|
||||
@@ -197,6 +197,45 @@ Vtiger.Class("Settings_Vtiger_OutgoingServer_Js",{},{
|
||||
}
|
||||
|
||||
});
|
||||
jQuery(document).ready(function () {
|
||||
jQuery('#sendTestMail').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
var params = {
|
||||
module: 'Vtiger',
|
||||
parent: 'Settings',
|
||||
action: 'OutgoingServerAjax',
|
||||
mode: 'sendTestMail'
|
||||
};
|
||||
|
||||
app.helper.showProgress();
|
||||
|
||||
app.request.post({ data: params }).then(function (err, data) {
|
||||
console.log("data",data);
|
||||
console.log("err",err);
|
||||
|
||||
|
||||
app.helper.hideProgress();
|
||||
if (err === null) {
|
||||
if (data && data.success) {
|
||||
app.helper.showSuccessNotification({
|
||||
message: data.message || '✅ Test mail sent successfully!'
|
||||
});
|
||||
} else if (data && data.error) {
|
||||
app.helper.showErrorNotification({
|
||||
message: data.error.message || '❌ Mailer Error.'
|
||||
});
|
||||
} else {
|
||||
app.helper.showErrorNotification({
|
||||
message: '❌ Unknown error. Check logs.'
|
||||
});
|
||||
}
|
||||
} else {
|
||||
app.helper.showErrorNotification({ message: '❌ ' + err.message });
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Settings_Vtiger_OutgoingServer_Js("Settings_Vtiger_OutgoingServerEdit_Js",{},{});
|
||||
|
||||
@@ -1,95 +1,189 @@
|
||||
{*+**********************************************************************************
|
||||
|
||||
* The contents of this file are subject to the vtiger CRM Public License Version 1.1
|
||||
|
||||
* ("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.
|
||||
|
||||
************************************************************************************}
|
||||
|
||||
{* modules/Vtiger/views/DashBoard.php *}
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
|
||||
function getSplashScreen(){
|
||||
|
||||
$.ajax({
|
||||
|
||||
type: "GET",
|
||||
|
||||
url: "index.php?module=SplashScreenAjax&view=SplashScreenAjax",
|
||||
|
||||
contentType: "application/json; charset=utf-8",
|
||||
|
||||
success: function(result) {
|
||||
|
||||
$("#SplashScreen").html(result);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
getSplashScreen();
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
{strip}
|
||||
|
||||
|
||||
|
||||
{assign var="roleid" value=$USER_MODEL->get('roleid')}
|
||||
|
||||
|
||||
|
||||
<div id="SplashScreen"></div>
|
||||
|
||||
|
||||
|
||||
<div class="dashBoardContainer clearfix">
|
||||
|
||||
<div class="tabContainer">
|
||||
|
||||
<ul class="nav nav-tabs tabs sortable container-fluid">
|
||||
|
||||
{foreach key=index item=TAB_DATA from=$DASHBOARD_TABS}
|
||||
|
||||
<li class="{if $TAB_DATA["id"] eq $SELECTED_TAB}active{/if} dashboardTab" data-tabid="{$TAB_DATA["id"]}" data-tabname="{$TAB_DATA["tabname"]}">
|
||||
|
||||
<a data-toggle="tab" href="#tab_{$TAB_DATA["id"]}">
|
||||
|
||||
<div>
|
||||
|
||||
<span class="name textOverflowEllipsis" value="{$TAB_DATA["tabname"]}" style="width:10%">
|
||||
|
||||
<strong>{$TAB_DATA["tabname"]}</strong>
|
||||
|
||||
</span>
|
||||
|
||||
<span class="editTabName hide">
|
||||
|
||||
<input type="text" name="tabName"/>
|
||||
|
||||
</span>
|
||||
|
||||
{if $TAB_DATA["isdefault"] eq 0}
|
||||
|
||||
<i class="fa fa-close deleteTab"></i>
|
||||
|
||||
{/if}
|
||||
|
||||
<i class="fa fa-bars moveTab hide"></i>
|
||||
|
||||
</div>
|
||||
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
{/foreach}
|
||||
|
||||
|
||||
|
||||
<!--
|
||||
|
||||
{if isGro($roleid) || isVP($roleid) || isDG($roleid)}
|
||||
|
||||
<li class="dashboardTab font-large-2" ><a href="index.php?module=CustomDashboard&view=CustomDashboard"><div><strong>Conventions</strong></div></a></li>
|
||||
|
||||
{/if}
|
||||
|
||||
-->
|
||||
|
||||
{if isDG($roleid) || $roleid == 'H8' || isMedecin($roleid)}
|
||||
|
||||
|
||||
|
||||
{if isVM($roleid)}
|
||||
|
||||
<!-- sophal --><li class="dashboardTab" style="font-size: 1.2rem"><a href="index.php?module=MonitoringVmCompte&view=MonitoringVmCompte"><div><strong>Monitoring Promotion Medicale</strong></div></a></li><!-- sophal -->
|
||||
|
||||
{else}
|
||||
|
||||
<!-- sophal --><li class="dashboardTab" style="font-size: 1.2rem"><a href="index.php?module=MonitoringVMPlanning&view=MonitoringVMPlanning"><div><strong>Monitoring Promotion Medicale</strong></div></a></li><!-- sophal -->
|
||||
|
||||
{/if}
|
||||
|
||||
{/if}
|
||||
|
||||
|
||||
|
||||
{if isGro($roleid) || isPharma($roleid) || isDG($roleid)}
|
||||
|
||||
<!-- sophal --><li class="dashboardTab" style="font-size: 1.2rem"><a href="index.php?module=MonitoringVpBCTotal&view=MonitoringVpBCTotal"><div><strong>Monitoring Commercial</strong></div></a></li><!-- sophal -->
|
||||
|
||||
{/if}
|
||||
|
||||
|
||||
|
||||
<div class="moreSettings pull-right">
|
||||
|
||||
<div class="dropdown dashBoardDropDown">
|
||||
|
||||
<button class="btn btn-default reArrangeTabs dropdown-toggle" type="button" data-toggle="dropdown">{vtranslate('LBL_MORE',$MODULE)}
|
||||
|
||||
<span class="caret"></span></button>
|
||||
|
||||
<ul class="dropdown-menu dropdown-menu-right moreDashBoards">
|
||||
|
||||
<li id="newDashBoardLi"{if count($DASHBOARD_TABS) eq $DASHBOARD_TABS_LIMIT}class="disabled"{/if}><a class = "addNewDashBoard" href="#">{vtranslate('LBL_ADD_NEW_DASHBOARD',$MODULE)}</a></li>
|
||||
|
||||
<li><a class = "reArrangeTabs" href="#">{vtranslate('LBL_REARRANGE_DASHBOARD_TABS',$MODULE)}</a></li>
|
||||
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
<button class="btn-success updateSequence pull-right hide">{vtranslate('LBL_SAVE_ORDER',$MODULE)}</button>
|
||||
|
||||
</div>
|
||||
|
||||
</ul>
|
||||
|
||||
<div class="tab-content">
|
||||
|
||||
{foreach key=index item=TAB_DATA from=$DASHBOARD_TABS}
|
||||
|
||||
<div id="tab_{$TAB_DATA["id"]}" data-tabid="{$TAB_DATA["id"]}" data-tabname="{$TAB_DATA["tabname"]}" class="tab-pane fade {if $TAB_DATA["id"] eq $SELECTED_TAB}in active{/if}">
|
||||
|
||||
{if $TAB_DATA["id"] eq $SELECTED_TAB}
|
||||
|
||||
{include file="dashboards/DashBoardTabContents.tpl"|vtemplate_path:$MODULE TABID=$TABID}
|
||||
|
||||
{/if}
|
||||
|
||||
</div>
|
||||
|
||||
{/foreach}
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{/strip}
|
||||
@@ -327,12 +327,15 @@
|
||||
<span style="font-size: 10pt" class="module-name textOverflowEllipsis">Questionnaire</span>
|
||||
</a>
|
||||
</li>
|
||||
{if !hideStock($roleid)}
|
||||
<li style=" padding: 2.5% 2% !important;">
|
||||
<a style=" color:#ffffff; " href="?module=EtatStockReporting&view=EtatStockReporting">
|
||||
<!--<span class="fa fa-cog module-icon"></span>-->
|
||||
<span style="font-size: 10pt" class="module-name textOverflowEllipsis">Stock</span>
|
||||
</a>
|
||||
</li>
|
||||
{/if}
|
||||
|
||||
{/if}
|
||||
{if $roleid == 'H8'}
|
||||
<li style=" padding: 2.5% 2% !important;">
|
||||
@@ -348,7 +351,8 @@
|
||||
</a>
|
||||
</li>
|
||||
{/if}
|
||||
{if $roleid == 'H12' || $roleid == 'H11' || $roleid == 'H4' || $roleid == 'H34' || $roleid == 'H36' || $roleid == 'H38' || $roleid == 'H42' || $roleid == 'H44'}
|
||||
{*if $roleid == 'H34' || $roleid == 'H36' || $roleid == 'H38' || $roleid == 'H42' || $roleid == 'H44' *}
|
||||
{if $roleid == 'H12' || $roleid == 'H11' || $roleid == 'H4' }
|
||||
<li style=" padding: 2.5% 2% !important;">
|
||||
<a style=" color:#ffffff; " href="?module=EtatStockReporting&view=EtatStockReporting">
|
||||
<!--<span class="fa fa-cog module-icon"></span>-->
|
||||
@@ -356,7 +360,8 @@
|
||||
</a>
|
||||
</li>
|
||||
{/if}
|
||||
{if $roleid != 'H12' && $roleid != 'H11' && $roleid != 'H4' && $roleid != 'H34' && $roleid != 'H36' && $roleid != 'H38' && $roleid != 'H42' && $roleid != 'H44' }
|
||||
{*&& $roleid != 'H34' && $roleid != 'H36' && $roleid != 'H38' && $roleid != 'H42' && $roleid != 'H44' *}
|
||||
{if $roleid != 'H12' && $roleid != 'H11' && $roleid != 'H4' }
|
||||
<li style=" padding: 2.5% 2% !important;">
|
||||
<a style=" color:#ffffff; " href="?module=ExportData&view=ExportData">
|
||||
<span style="font-size: 10pt" class="module-name textOverflowEllipsis">Export Data</span>
|
||||
|
||||
@@ -1881,6 +1881,7 @@ th {
|
||||
margin: 0px 1px !important;
|
||||
}
|
||||
.referencefield-wrapper .createReferenceRecord {
|
||||
display: none !important;
|
||||
float: left;
|
||||
margin-left: 5px;
|
||||
margin-top: 3px;
|
||||
|
||||
@@ -13,6 +13,42 @@ Vtiger_Detail_Js("Inventory_Detail_Js",{
|
||||
popupInstance.show(url,function(){}, app.vtranslate('JS_SEND_PDF_MAIL') );
|
||||
}
|
||||
|
||||
},{
|
||||
testSendEmailPDFClickHandler : function(url){
|
||||
var params = {
|
||||
module: 'Vtiger',
|
||||
parent: 'Settings',
|
||||
action: 'OutgoingServerAjax',
|
||||
mode: 'sendTestMail'
|
||||
};
|
||||
|
||||
app.helper.showProgress();
|
||||
|
||||
app.request.post({ data: params }).then(function (err, data) {
|
||||
console.log("data",data);
|
||||
console.log("err",err);
|
||||
|
||||
|
||||
app.helper.hideProgress();
|
||||
if (err === null) {
|
||||
if (data && data.success) {
|
||||
app.helper.showSuccessNotification({
|
||||
message: data.message || '✅ Test mail sent successfully!'
|
||||
});
|
||||
} else if (data && data.error) {
|
||||
app.helper.showErrorNotification({
|
||||
message: data.error.message || '❌ Mailer Error.'
|
||||
});
|
||||
} else {
|
||||
app.helper.showErrorNotification({
|
||||
message: '❌ Unknown error. Check logs.'
|
||||
});
|
||||
}
|
||||
} else {
|
||||
app.helper.showErrorNotification({ message: '❌ ' + err.message });
|
||||
}
|
||||
});
|
||||
}
|
||||
},{
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,304 +1,610 @@
|
||||
<?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 'SUtiles.php';
|
||||
|
||||
|
||||
|
||||
class Accounts_ListView_Model extends Vtiger_ListView_Model {
|
||||
|
||||
|
||||
|
||||
protected $isVMPharma = true;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
|
||||
* Function to get the list of Mass actions for the module
|
||||
|
||||
* @param <Array> $linkParams
|
||||
|
||||
* @return <Array> - Associative array of Link type to List of Vtiger_Link_Model instances for Mass Actions
|
||||
|
||||
*/
|
||||
|
||||
public function getListViewMassActions($linkParams) {
|
||||
|
||||
$massActionLinks = parent::getListViewMassActions($linkParams);
|
||||
|
||||
|
||||
|
||||
$currentUserModel = Users_Privileges_Model::getCurrentUserPrivilegesModel();
|
||||
|
||||
$emailModuleModel = Vtiger_Module_Model::getInstance('Emails');
|
||||
|
||||
|
||||
|
||||
if($currentUserModel->hasModulePermission($emailModuleModel->getId())) {
|
||||
|
||||
$massActionLink = array(
|
||||
|
||||
'linktype' => 'LISTVIEWMASSACTION',
|
||||
|
||||
'linklabel' => 'LBL_SEND_EMAIL',
|
||||
|
||||
'linkurl' => 'javascript:Vtiger_List_Js.triggerSendEmail("index.php?module='.$this->getModule()->getName().'&view=MassActionAjax&mode=showComposeEmailForm&step=step1","Emails");',
|
||||
|
||||
'linkicon' => ''
|
||||
|
||||
);
|
||||
|
||||
$massActionLinks['LISTVIEWMASSACTION'][] = Vtiger_Link_Model::getInstanceFromValues($massActionLink);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
$SMSNotifierModuleModel = Vtiger_Module_Model::getInstance('SMSNotifier');
|
||||
|
||||
if(!empty($SMSNotifierModuleModel) && $currentUserModel->hasModulePermission($SMSNotifierModuleModel->getId())) {
|
||||
|
||||
$massActionLink = array(
|
||||
|
||||
'linktype' => 'LISTVIEWMASSACTION',
|
||||
|
||||
'linklabel' => 'LBL_SEND_SMS',
|
||||
|
||||
'linkurl' => 'javascript:Vtiger_List_Js.triggerSendSms("index.php?module='.$this->getModule()->getName().'&view=MassActionAjax&mode=showSendSMSForm","SMSNotifier");',
|
||||
|
||||
'linkicon' => ''
|
||||
|
||||
);
|
||||
|
||||
$massActionLinks['LISTVIEWMASSACTION'][] = Vtiger_Link_Model::getInstanceFromValues($massActionLink);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
$currentUser = Users_Record_Model::getCurrentUserModel();
|
||||
|
||||
$userId = $currentUser->get('id');
|
||||
|
||||
|
||||
|
||||
if($userId == 1 || $userId == 17) {
|
||||
|
||||
$moduleModel = $this->getModule();
|
||||
|
||||
if($currentUserModel->hasModuleActionPermission($moduleModel->getId(), 'EditView')) {
|
||||
|
||||
$massActionLink = array(
|
||||
|
||||
'linktype' => 'LISTVIEWMASSACTION',
|
||||
|
||||
'linklabel' => 'LBL_TRANSFER_OWNERSHIP',
|
||||
|
||||
'linkurl' => 'javascript:Vtiger_List_Js.triggerTransferOwnership("index.php?module='.$moduleModel->getName().'&view=MassActionAjax&mode=transferOwnership")',
|
||||
|
||||
'linkicon' => ''
|
||||
|
||||
);
|
||||
|
||||
$massActionLinks['LISTVIEWMASSACTION'][] = Vtiger_Link_Model::getInstanceFromValues($massActionLink);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
return $massActionLinks;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
|
||||
* Function to get the list of listview links for the module
|
||||
|
||||
* @param <Array> $linkParams
|
||||
|
||||
* @return <Array> - Associate array of Link Type to List of Vtiger_Link_Model instances
|
||||
|
||||
*/
|
||||
|
||||
function getListViewLinks($linkParams) {
|
||||
|
||||
$links = parent::getListViewLinks($linkParams);
|
||||
|
||||
|
||||
|
||||
$index=0;
|
||||
|
||||
foreach($links['LISTVIEWBASIC'] as $link) {
|
||||
|
||||
if($link->linklabel == 'Send SMS') {
|
||||
|
||||
unset($links['LISTVIEWBASIC'][$index]);
|
||||
|
||||
}
|
||||
|
||||
$index++;
|
||||
|
||||
}
|
||||
|
||||
return $links;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
//filter account by default
|
||||
|
||||
private function customSearch($roleid) {
|
||||
|
||||
|
||||
|
||||
$field_value = "all";
|
||||
|
||||
$fullname = "";
|
||||
|
||||
$aCondition = ["columnname" => "vtiger_account:account_type:accounttype:Accounts_Type:V", "comparator" => "n", "value" => $field_value];
|
||||
|
||||
$aCondition2 = [];
|
||||
|
||||
$aCondition3 = [];
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$currentUser = Users_Record_Model::getCurrentUserModel();
|
||||
|
||||
if(isByWilaya($currentUser->get('id'))) {
|
||||
|
||||
|
||||
|
||||
$lieu = $currentUser->get('secteur1_id').','.$currentUser->get('secteur2_id').','.$currentUser->get('secteur3_id').','.$currentUser->get('secteur4_id');
|
||||
|
||||
|
||||
|
||||
$industry = "Pharmacie";
|
||||
|
||||
if(isMedecin($roleid))
|
||||
|
||||
$industry = "Medecin";
|
||||
|
||||
$aCondition = ["columnname" => "vtiger_account:industry:industry:Accounts_industry:V", "comparator" => "c", "value" => $industry, "column_condition" => "and"];
|
||||
|
||||
$aCondition2 = ["columnname" => "vtiger_accountscf:cf_992:cf_992:Accounts_Wilaya:V", "comparator" => "c", "value" => $lieu];
|
||||
|
||||
$asearchParams = $this->get('search_params');
|
||||
|
||||
if(empty($asearchParams)) {
|
||||
|
||||
$searchParams = [[ "columns" => [$aCondition, $aCondition2] ]];
|
||||
|
||||
$this->set('search_params', $searchParams);
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
} else
|
||||
|
||||
|
||||
|
||||
if(isMedecin($roleid) || isPharma($roleid)) {
|
||||
|
||||
$field_value = "Medecin";
|
||||
|
||||
$fullname = $currentUser->get('first_name').' '.$currentUser->get('last_name');
|
||||
|
||||
$sub = getSubordinateRoleAndUsers($roleid);
|
||||
|
||||
foreach($sub as $roleid=>$userids) {
|
||||
|
||||
foreach($userids as $roleid2=>$userids2) {
|
||||
|
||||
$fullname = $fullname.",".$userids2;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
$aCondition = ["columnname" => "vtiger_crmentity:smownerid:assigned_user_id:Accounts_Assigned_To:V", "comparator" => "c", "value" => $fullname, "column_condition" => "or"];
|
||||
|
||||
$aCondition2 = ["columnname" => "vtiger_account:vm2_id:vm2_id:Accounts_VM2:V", "comparator" => "c", "value" => $fullname, "column_condition" => "or"];
|
||||
|
||||
if($this->isVMPharma)
|
||||
|
||||
$aCondition3 = ["columnname" => "vtiger_account:industry:industry:Accounts_industry:V", "comparator" => "c", "value" => "Pharmacie"];
|
||||
|
||||
else
|
||||
|
||||
$aCondition3 = ["columnname" => "vtiger_account:vm3_id:vm3_id:Accounts_VM3:V", "comparator" => "c", "value" => $fullname];
|
||||
|
||||
|
||||
|
||||
} else if(isGro($roleid)) {
|
||||
|
||||
$field_value = "Grossiste";
|
||||
|
||||
$aCondition = ["columnname" => "vtiger_account:industry:industry:Accounts_industry:V", "comparator" => "c", "value" => $field_value];
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// update search_params
|
||||
|
||||
$searchParams = $this->get('search_params');
|
||||
|
||||
if(empty($searchParams)) {
|
||||
|
||||
if($aCondition2 != [] && $aCondition3 != []) {
|
||||
|
||||
$searchParams = [[ "columns" => [$aCondition, $aCondition2, $aCondition3] ]];
|
||||
|
||||
} else {
|
||||
|
||||
$searchParams = [[ "columns" => [$aCondition] ]];
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
$exist = 0;
|
||||
|
||||
$index = 0;
|
||||
|
||||
$columns = $searchParams[0]["columns"];
|
||||
|
||||
|
||||
|
||||
foreach ($columns as $column) {
|
||||
|
||||
|
||||
|
||||
if(isByWilaya($currentUser->get('id'))) {
|
||||
|
||||
if($column["columnname"] == "vtiger_account:account_type:accounttype:Accounts_Type:V") {
|
||||
|
||||
$column["value"] = $field_value;
|
||||
|
||||
|
||||
|
||||
$exist = 1;
|
||||
|
||||
}
|
||||
|
||||
} else
|
||||
|
||||
|
||||
|
||||
if(isGro($roleid)) {
|
||||
|
||||
if($column["columnname"] == "vtiger_account:industry:industry:Accounts_industry:V") {
|
||||
|
||||
|
||||
|
||||
if($roleid == 'H4' && ($column["value"] == 'Pharmacie' || $column["value"] == 'Grossiste')) {
|
||||
|
||||
} else {
|
||||
|
||||
$column["value"] = $field_value;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
$exist = 1;
|
||||
|
||||
}
|
||||
|
||||
} else if(isMedecin($roleid) || isPharma($roleid)) {
|
||||
|
||||
|
||||
|
||||
if($column["columnname"] == "vtiger_crmentity:smownerid:assigned_user_id:Accounts_Assigned_To:V" || $column["columnname"] == "vtiger_account:vm2_id:vm2_id:Accounts_VM2:V" || $column["columnname"] == "vtiger_account:vm3_id:vm3_id:Accounts_VM3:V") {
|
||||
|
||||
//$column["value"] = $fullname;
|
||||
|
||||
$fullnames = split(',', $fullname);
|
||||
|
||||
$acolumns = split(',', $column["value"]);
|
||||
|
||||
if (count(array_diff($fullnames, $acolumns)) == 0) {
|
||||
|
||||
$exist = 1;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
if($column["columnname"] == "vtiger_account:account_type:accounttype:Accounts_Type:V") {
|
||||
|
||||
$column["value"] = $field_value;
|
||||
|
||||
|
||||
|
||||
$exist = 1;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
if(!$exist && $index < count($columns)) {
|
||||
|
||||
//if($column["column_condition"] != 'or')
|
||||
|
||||
$column["column_condition"] = "and";
|
||||
|
||||
}
|
||||
|
||||
$columns[$index] = $column;
|
||||
|
||||
|
||||
|
||||
$index++;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
if(!$exist) {
|
||||
|
||||
|
||||
|
||||
if(isByWilaya($currentUser->get('id'))) {
|
||||
|
||||
array_push($columns, $aCondition, $aCondition2);
|
||||
|
||||
} else
|
||||
|
||||
|
||||
|
||||
if(isMedecin($roleid) || isPharma($roleid)) {
|
||||
|
||||
$tempColumns = $columns;
|
||||
|
||||
array_push($columns, $aCondition);
|
||||
|
||||
foreach ($tempColumns as $column) {
|
||||
|
||||
array_push($columns, $column);
|
||||
|
||||
$asearchParams = $this->get('search_params');
|
||||
|
||||
if(empty($asearchParams)) {
|
||||
|
||||
$searchParams = [[ "columns" => [$aCondition, $aCondition2] ]];
|
||||
|
||||
$this->set('search_params', $searchParams);
|
||||
|
||||
|
||||
}
|
||||
|
||||
array_push($columns, $aCondition2);
|
||||
|
||||
foreach ($tempColumns as $column) {
|
||||
|
||||
array_push($columns, $column);
|
||||
|
||||
}
|
||||
|
||||
array_push($columns, $aCondition3);
|
||||
|
||||
} else {
|
||||
|
||||
array_push($columns, $aCondition);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
$searchParams[0]["columns"] = $columns;
|
||||
|
||||
}
|
||||
|
||||
//print_r($searchParams);
|
||||
|
||||
$this->set('search_params', $searchParams);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public function getListViewEntries($pagingModel) {
|
||||
|
||||
|
||||
|
||||
$currentUser = Users_Record_Model::getCurrentUserModel();
|
||||
|
||||
$roleid = $currentUser->get('roleid');
|
||||
|
||||
|
||||
if($roleid != 'H2' && $_GET['viewname'] != 70) {
|
||||
|
||||
// if($roleid != 'H2' && $roleid != 'H20' && $roleid != 'H26' && $roleid != 'H39' && $_GET['viewname'] != 70) {
|
||||
|
||||
|
||||
$this->customSearch($roleid);
|
||||
|
||||
// }
|
||||
}
|
||||
|
||||
if($_GET['parent'] != '') {
|
||||
|
||||
|
||||
|
||||
$parent = $_GET['parent'];
|
||||
|
||||
$infousers = explode('user;', $parent);
|
||||
|
||||
|
||||
|
||||
if(count($infousers) > 1) {
|
||||
|
||||
$auser = $infousers[1];
|
||||
|
||||
|
||||
|
||||
$aCondition = ["columnname" => "vtiger_crmentity:smownerid:assigned_user_id:Accounts_Assigned_To:V", "comparator" => "c", "value" => $auser, "column_condition" => "and"];
|
||||
|
||||
$aCondition5 = ["columnname" => "vtiger_accountscf:cf_986:cf_986:Accounts_Latitude:V", "comparator" => "l", "value" => '0', "column_condition" => "or"];
|
||||
|
||||
$aCondition2 = ["columnname" => "vtiger_account:vm2_id:vm2_id:Accounts_VM2:V", "comparator" => "c", "value" => $auser, "column_condition" => "and"];
|
||||
|
||||
$aCondition6 = ["columnname" => "vtiger_accountscf:cf_986:cf_986:Accounts_Latitude:V", "comparator" => "l", "value" => '0', "column_condition" => "or"];
|
||||
|
||||
if($this->isVMPharma)
|
||||
|
||||
$aCondition3 = ["columnname" => "vtiger_account:industry:industry:Accounts_industry:V", "comparator" => "c", "value" => "Pharmacie", "column_condition" => "and"];
|
||||
|
||||
else
|
||||
|
||||
$aCondition3 = ["columnname" => "vtiger_account:vm3_id:vm3_id:Accounts_VM3:V", "comparator" => "c", "value" => $auser, "column_condition" => "and"];
|
||||
|
||||
$aCondition4 = ["columnname" => "vtiger_accountscf:cf_986:cf_986:Accounts_Latitude:V", "comparator" => "l", "value" => '0'];
|
||||
|
||||
|
||||
|
||||
$searchParams = [[ "columns" => [$aCondition, $aCondition5, $aCondition2, $aCondition6, $aCondition3, $aCondition4] ]];
|
||||
|
||||
|
||||
|
||||
//print_r($searchParams);
|
||||
|
||||
$this->set('search_params', $searchParams);
|
||||
|
||||
|
||||
}
|
||||
|
||||
} else if(isGro($roleid)) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
return parent::getListViewEntries($pagingModel);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public function getListViewCount() {
|
||||
|
||||
|
||||
|
||||
$currentUser = Users_Record_Model::getCurrentUserModel();
|
||||
|
||||
$roleid = $currentUser->get('roleid');
|
||||
|
||||
|
||||
if($roleid != 'H2' && $_GET['viewname'] != 70) {
|
||||
|
||||
// if($roleid != 'H2' && $roleid != 'H20' && $roleid != 'H26' && $roleid != 'H39' && $_GET['viewname'] != 70) {
|
||||
// update search_params
|
||||
|
||||
$this->customSearch($roleid);
|
||||
|
||||
// }
|
||||
}
|
||||
|
||||
if($_GET['parent'] != '') {
|
||||
|
||||
|
||||
|
||||
$parent = $_GET['parent'];
|
||||
|
||||
$infousers = explode('user;', $parent);
|
||||
|
||||
|
||||
|
||||
if(count($infousers) > 1) {
|
||||
|
||||
$auser = $infousers[1];
|
||||
|
||||
|
||||
|
||||
$aCondition = ["columnname" => "vtiger_crmentity:smownerid:assigned_user_id:Accounts_Assigned_To:V", "comparator" => "c", "value" => $auser, "column_condition" => "and"];
|
||||
|
||||
$aCondition5 = ["columnname" => "vtiger_accountscf:cf_986:cf_986:Accounts_Latitude:V", "comparator" => "l", "value" => '0', "column_condition" => "or"];
|
||||
|
||||
$aCondition2 = ["columnname" => "vtiger_account:vm2_id:vm2_id:Accounts_VM2:V", "comparator" => "c", "value" => $auser, "column_condition" => "and"];
|
||||
|
||||
$aCondition6 = ["columnname" => "vtiger_accountscf:cf_986:cf_986:Accounts_Latitude:V", "comparator" => "l", "value" => '0', "column_condition" => "or"];
|
||||
|
||||
if($this->isVMPharma)
|
||||
|
||||
$aCondition3 = ["columnname" => "vtiger_account:industry:industry:Accounts_industry:V", "comparator" => "c", "value" => "Pharmacie", "column_condition" => "and"];
|
||||
|
||||
else
|
||||
|
||||
$aCondition3 = ["columnname" => "vtiger_account:vm3_id:vm3_id:Accounts_VM3:V", "comparator" => "c", "value" => $auser, "column_condition" => "and"];
|
||||
|
||||
$aCondition4 = ["columnname" => "vtiger_accountscf:cf_986:cf_986:Accounts_Latitude:V", "comparator" => "l", "value" => '0'];
|
||||
|
||||
|
||||
|
||||
$searchParams = [[ "columns" => [$aCondition, $aCondition5, $aCondition2, $aCondition6, $aCondition3, $aCondition4] ]];
|
||||
|
||||
|
||||
|
||||
//print_r($searchParams);
|
||||
|
||||
$this->set('search_params', $searchParams);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
return parent::getListViewCount();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -301,7 +301,7 @@ class PHPMailer {
|
||||
* Sets SMTP class debugging on or off.
|
||||
* @var bool
|
||||
*/
|
||||
public $SMTPDebug = false;
|
||||
public $SMTPDebug = true;
|
||||
|
||||
/**
|
||||
* Sets the function/method to use for debugging output.
|
||||
|
||||
@@ -36,6 +36,15 @@ class Inventory_DetailView_Model extends Vtiger_DetailView_Model {
|
||||
);
|
||||
|
||||
$linkModelList['DETAILVIEW'][] = Vtiger_Link_Model::getInstanceFromValues($sendEmailLink);
|
||||
|
||||
|
||||
$testsendEmailLink = array(
|
||||
'linklabel' => "Test send email",
|
||||
'linkurl' => 'javascript:Inventory_Detail_Js.testSendEmailPDFClickHandler(\''.$recordModel->getSendEmailPDFUrl().'\')',
|
||||
'linkicon' => ''
|
||||
);
|
||||
|
||||
$linkModelList['DETAILVIEW'][] = Vtiger_Link_Model::getInstanceFromValues($testsendEmailLink);
|
||||
}
|
||||
|
||||
return $linkModelList;
|
||||
|
||||
@@ -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'])
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
header("Location: index.php");
|
||||
exit;
|
||||
}
|
||||
|
||||
if($eventName == 'vtiger.entity.afterrestore') {
|
||||
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::$RESTORED));
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
63
modules/SalesOrder/actions/SendSaleOrderMailAjax.php
Normal file
63
modules/SalesOrder/actions/SendSaleOrderMailAjax.php
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
class SalesOrder_SendSaleOrderMailAjax_Action extends Vtiger_BasicAjax_Action
|
||||
{
|
||||
public function process(Vtiger_Request $request)
|
||||
{
|
||||
$recordId = $request->get('record');
|
||||
$response = new Vtiger_Response();
|
||||
|
||||
try {
|
||||
// Get record model
|
||||
$recordModel = Vtiger_Record_Model::getInstanceById($recordId, 'SalesOrder');
|
||||
|
||||
// Load Outgoing Server config
|
||||
$outgoingServerSettingsModel = Settings_Vtiger_Systems_Model::getInstanceFromServerType('email', 'OutgoingServer');
|
||||
|
||||
// Include mailer
|
||||
require_once 'vtlib/Vtiger/Mailer.php';
|
||||
$mailer = new Vtiger_Mailer();
|
||||
|
||||
$mailer->IsSMTP();
|
||||
$mailer->Host = $outgoingServerSettingsModel->get('server');
|
||||
$mailer->Port = 587;
|
||||
$mailer->SMTPAuth = $outgoingServerSettingsModel->isSmtpAuthEnabled();
|
||||
$mailer->Username = $outgoingServerSettingsModel->get('server_username');
|
||||
$mailer->Password = $outgoingServerSettingsModel->get('server_password');
|
||||
$mailer->SMTPSecure = 'tls';
|
||||
$mailer->From = $outgoingServerSettingsModel->get('from_email_field');
|
||||
$mailer->FromName = 'Vtiger CRM';
|
||||
$mailer->AddAddress('souldibachir3150@gmail.com');
|
||||
$mailer->Subject = 'Sales Order #' . $recordModel->get('salesorder_no');
|
||||
|
||||
$mailer->Body = 'Attached is your Sales Order from Vtiger CRM.';
|
||||
|
||||
// Attach PDF
|
||||
$pdfPath = 'storage/SalesOrder_' . $recordId . '.pdf';
|
||||
$this->generatePDF($recordId, $pdfPath);
|
||||
$mailer->AddAttachment($pdfPath);
|
||||
|
||||
// Force send immediately
|
||||
$sent = $mailer->Send(true);
|
||||
|
||||
if ($sent) {
|
||||
$response->setResult(['success' => true, 'message' => '✅ Sales Order email sent successfully!']);
|
||||
} else {
|
||||
$response->setResult(['success' => false, 'message' => '⚠️ Failed to send Sales Order email.']);
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
$response->setError($e->getCode(), $e->getMessage());
|
||||
}
|
||||
|
||||
$response->emit();
|
||||
}
|
||||
|
||||
private function generatePDF($recordId, $pdfPath)
|
||||
{
|
||||
require_once 'modules/SalesOrder/SalesOrderPDFController.php';
|
||||
$pdfController = new Vtiger_SalesOrderPDFController('SalesOrder');
|
||||
$pdfController->loadRecord($recordId);
|
||||
$pdfContent = $pdfController->Output('', 'S'); // Output as string
|
||||
file_put_contents($pdfPath, $pdfContent);
|
||||
}
|
||||
}
|
||||
74
modules/Settings/Vtiger/actions/OutgoingServerAjax.php
Normal file
74
modules/Settings/Vtiger/actions/OutgoingServerAjax.php
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
/*+***********************************************************************************
|
||||
* Custom Action for Outgoing Server Test Mail
|
||||
*************************************************************************************/
|
||||
|
||||
class Settings_Vtiger_OutgoingServerAjax_Action extends Settings_Vtiger_Basic_Action
|
||||
{
|
||||
public function process(Vtiger_Request $request)
|
||||
{
|
||||
$outgoingServerSettingsModel = Settings_Vtiger_Systems_Model::getInstanceFromServerType('email', 'OutgoingServer');
|
||||
$response = new Vtiger_Response();
|
||||
|
||||
try {
|
||||
// Always send test mail
|
||||
$sent = $this->sendTestMail($outgoingServerSettingsModel);
|
||||
|
||||
if ($sent) {
|
||||
|
||||
$data = $outgoingServerSettingsModel->getData();
|
||||
$data['message'] = '✅ Configuration saved and test mail sent successfully.';
|
||||
$data['success'] = true;
|
||||
$response->setResult($data);
|
||||
} else {
|
||||
$response->setResult([
|
||||
'success' => false,
|
||||
'message' => '⚠️ Test mail failed to send. Check SMTP settings or logs.'
|
||||
]);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$response->setError($e->getCode(), $e->getMessage());
|
||||
}
|
||||
|
||||
// Important: emit and stop ALL further output
|
||||
$response->emit();
|
||||
exit; // 🔹 This prevents extra output after JSON
|
||||
}
|
||||
|
||||
public function sendTestMail($model , $subject = null, $body = null,$pdf_path = null)
|
||||
{
|
||||
require_once 'vtlib/Vtiger/Mailer.php';
|
||||
$mailer = new Vtiger_Mailer();
|
||||
|
||||
try {
|
||||
$mailer->IsSMTP();
|
||||
$mailer->Host = $model->get('server');
|
||||
$mailer->Port = 587;
|
||||
$mailer->SMTPAuth = $model->isSmtpAuthEnabled();
|
||||
$mailer->Username = $model->get('server_username');
|
||||
$mailer->Password = $model->get('server_password');
|
||||
$mailer->SMTPSecure = 'tls';
|
||||
$mailer->From = $model->get('from_email_field');
|
||||
$mailer->FromName = 'Vtiger Test Mail';
|
||||
$mailer->AddAddress($model->to_email ?? 'souldibachir3150@gmail.com');
|
||||
$mailer->AddCC('andryamo2231@gmail.com');
|
||||
$mailer->Subject = $subject ?? 'Test Mail from Vtiger CRM 2';
|
||||
$mailer->IsHTML(true);
|
||||
$mailer->Body = $body ?? 'This is a test mail sent when saving outgoing server configuration. 2'.$pdf_path;
|
||||
// // Attach Sales Order PDF if available
|
||||
// if (!empty($model->pdf_path) && file_exists($model->pdf_path)) {
|
||||
// $mailer->AddAttachment($model->pdf_path, basename($model->pdf_path));
|
||||
// }
|
||||
if (!$mailer->Send(true)) {
|
||||
error_log('SMTP send() failed: ' . $mailer->ErrorInfo);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (Exception $e) {
|
||||
error_log('SMTP Test Mail Error: ' . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,6 +18,7 @@ class Settings_Vtiger_OutgoingServerEdit_View extends Settings_Vtiger_Index_View
|
||||
$viewer->assign('MODEL',$systemDetailsModel);
|
||||
$viewer->assign('QUALIFIED_MODULE', $qualifiedName);
|
||||
$viewer->assign('CURRENT_USER_MODEL', Users_Record_Model::getCurrentUserModel());
|
||||
$viewer->assign('TEST_MAIL', true);
|
||||
$viewer->view('OutgoingServerEdit.tpl',$qualifiedName);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
; run quicker, but you won't get error messages back to the calling
|
||||
; application.
|
||||
|
||||
smtp_server=mail.sophal.dz
|
||||
smtp_server=mail.sophal.net
|
||||
|
||||
; smtp port (normally 25)
|
||||
|
||||
@@ -43,8 +43,8 @@ debug_logfile=debug.log
|
||||
|
||||
; if your smtp server requires authentication, modify the following two lines
|
||||
|
||||
auth_username=crm@sophal.dz
|
||||
auth_password=Sophal2019
|
||||
auth_username=erp@mail.sophal.net
|
||||
auth_password=Sophal@@25**
|
||||
|
||||
; if your smtp server uses pop3 before smtp authentication, modify the
|
||||
; following three lines. do not enable unless it is required.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?php /* Smarty version Smarty-3.1.7, created on 2025-09-26 16:22:51
|
||||
<?php /* Smarty version Smarty-3.1.7, created on 2025-09-30 08:46:30
|
||||
compiled from "C:\xampp\htdocs\sophalcrm\includes\runtime/../../layouts/v7\modules\Vtiger\ModalFooter.tpl" */ ?>
|
||||
<?php /*%%SmartyHeaderCode:35691707368d6bddb322281-34526287%%*/if(!defined('SMARTY_DIR')) exit('no direct access allowed');
|
||||
$_valid = $_smarty_tpl->decodeProperties(array (
|
||||
@@ -7,7 +7,7 @@ $_valid = $_smarty_tpl->decodeProperties(array (
|
||||
'2627944103942efed50bd439d9d1dbdcc67dc480' =>
|
||||
array (
|
||||
0 => 'C:\\xampp\\htdocs\\sophalcrm\\includes\\runtime/../../layouts/v7\\modules\\Vtiger\\ModalFooter.tpl',
|
||||
1 => 1758796678,
|
||||
1 => 1759179619,
|
||||
2 => 'file',
|
||||
),
|
||||
),
|
||||
@@ -15,6 +15,8 @@ $_valid = $_smarty_tpl->decodeProperties(array (
|
||||
'function' =>
|
||||
array (
|
||||
),
|
||||
'version' => 'Smarty-3.1.7',
|
||||
'unifunc' => 'content_68d6bddb32583',
|
||||
'variables' =>
|
||||
array (
|
||||
'BUTTON_NAME' => 0,
|
||||
@@ -23,8 +25,6 @@ $_valid = $_smarty_tpl->decodeProperties(array (
|
||||
'BUTTON_LABEL' => 0,
|
||||
),
|
||||
'has_nocache_code' => false,
|
||||
'version' => 'Smarty-3.1.7',
|
||||
'unifunc' => 'content_68d6bddb32583',
|
||||
),false); /*/%%SmartyHeaderCode%%*/?>
|
||||
<?php if ($_valid && !is_callable('content_68d6bddb32583')) {function content_68d6bddb32583($_smarty_tpl) {?>
|
||||
<div class="modal-footer "><center><?php if ($_smarty_tpl->tpl_vars['BUTTON_NAME']->value!=null){?><?php $_smarty_tpl->tpl_vars['BUTTON_LABEL'] = new Smarty_variable($_smarty_tpl->tpl_vars['BUTTON_NAME']->value, null, 0);?><?php }else{ ?><?php ob_start();?><?php echo vtranslate('LBL_SAVE',$_smarty_tpl->tpl_vars['MODULE']->value);?>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?php /* Smarty version Smarty-3.1.7, created on 2025-09-26 16:15:58
|
||||
<?php /* Smarty version Smarty-3.1.7, created on 2025-09-30 08:19:20
|
||||
compiled from "C:\xampp\htdocs\sophalcrm\includes\runtime/../../layouts/v7\modules\Vtiger\Footer.tpl" */ ?>
|
||||
<?php /*%%SmartyHeaderCode:147362918768d6bc3e892923-48997099%%*/if(!defined('SMARTY_DIR')) exit('no direct access allowed');
|
||||
$_valid = $_smarty_tpl->decodeProperties(array (
|
||||
@@ -7,7 +7,7 @@ $_valid = $_smarty_tpl->decodeProperties(array (
|
||||
'710e620183d7eba30794adcdaa65a6b9b5aba915' =>
|
||||
array (
|
||||
0 => 'C:\\xampp\\htdocs\\sophalcrm\\includes\\runtime/../../layouts/v7\\modules\\Vtiger\\Footer.tpl',
|
||||
1 => 1758796679,
|
||||
1 => 1759179585,
|
||||
2 => 'file',
|
||||
),
|
||||
),
|
||||
@@ -15,13 +15,13 @@ $_valid = $_smarty_tpl->decodeProperties(array (
|
||||
'function' =>
|
||||
array (
|
||||
),
|
||||
'version' => 'Smarty-3.1.7',
|
||||
'unifunc' => 'content_68d6bc3e9002c',
|
||||
'variables' =>
|
||||
array (
|
||||
'LANGUAGE_STRINGS' => 0,
|
||||
),
|
||||
'has_nocache_code' => false,
|
||||
'version' => 'Smarty-3.1.7',
|
||||
'unifunc' => 'content_68d6bc3e9002c',
|
||||
),false); /*/%%SmartyHeaderCode%%*/?>
|
||||
<?php if ($_valid && !is_callable('content_68d6bc3e9002c')) {function content_68d6bc3e9002c($_smarty_tpl) {?>
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?php /* Smarty version Smarty-3.1.7, created on 2025-09-26 16:17:25
|
||||
<?php /* Smarty version Smarty-3.1.7, created on 2025-09-30 09:14:25
|
||||
compiled from "C:\xampp\htdocs\sophalcrm\includes\runtime/../../layouts/v7\modules\Vtiger\partials\SidebarAppMenu.tpl" */ ?>
|
||||
<?php /*%%SmartyHeaderCode:88911824368d6bc952ae0a7-57885333%%*/if(!defined('SMARTY_DIR')) exit('no direct access allowed');
|
||||
$_valid = $_smarty_tpl->decodeProperties(array (
|
||||
@@ -7,7 +7,7 @@ $_valid = $_smarty_tpl->decodeProperties(array (
|
||||
'833e7fc50cbf769ba11253f5188fa344a967b92e' =>
|
||||
array (
|
||||
0 => 'C:\\xampp\\htdocs\\sophalcrm\\includes\\runtime/../../layouts/v7\\modules\\Vtiger\\partials\\SidebarAppMenu.tpl',
|
||||
1 => 1758796685,
|
||||
1 => 1759223637,
|
||||
2 => 'file',
|
||||
),
|
||||
),
|
||||
@@ -15,6 +15,8 @@ $_valid = $_smarty_tpl->decodeProperties(array (
|
||||
'function' =>
|
||||
array (
|
||||
),
|
||||
'version' => 'Smarty-3.1.7',
|
||||
'unifunc' => 'content_68d6bc952e7ed',
|
||||
'variables' =>
|
||||
array (
|
||||
'USER_MODEL' => 0,
|
||||
@@ -38,8 +40,6 @@ $_valid = $_smarty_tpl->decodeProperties(array (
|
||||
'DOCUMENTS_MODULE_MODEL' => 0,
|
||||
),
|
||||
'has_nocache_code' => false,
|
||||
'version' => 'Smarty-3.1.7',
|
||||
'unifunc' => 'content_68d6bc952e7ed',
|
||||
),false); /*/%%SmartyHeaderCode%%*/?>
|
||||
<?php if ($_valid && !is_callable('content_68d6bc952e7ed')) {function content_68d6bc952e7ed($_smarty_tpl) {?>
|
||||
|
||||
@@ -394,12 +394,15 @@ $_smarty_tpl->tpl_vars['moduleModel']->_loop = true;
|
||||
<span style="font-size: 10pt" class="module-name textOverflowEllipsis">Questionnaire</span>
|
||||
</a>
|
||||
</li>
|
||||
<?php if (!hideStock($_smarty_tpl->tpl_vars['roleid']->value)){?>
|
||||
<li style=" padding: 2.5% 2% !important;">
|
||||
<a style=" color:#ffffff; " href="?module=EtatStockReporting&view=EtatStockReporting">
|
||||
<!--<span class="fa fa-cog module-icon"></span>-->
|
||||
<span style="font-size: 10pt" class="module-name textOverflowEllipsis">Stock</span>
|
||||
</a>
|
||||
</li>
|
||||
<?php }?>
|
||||
|
||||
<?php }?>
|
||||
<?php if ($_smarty_tpl->tpl_vars['roleid']->value=='H8'){?>
|
||||
<li style=" padding: 2.5% 2% !important;">
|
||||
@@ -415,7 +418,8 @@ $_smarty_tpl->tpl_vars['moduleModel']->_loop = true;
|
||||
</a>
|
||||
</li>
|
||||
<?php }?>
|
||||
<?php if ($_smarty_tpl->tpl_vars['roleid']->value=='H12'||$_smarty_tpl->tpl_vars['roleid']->value=='H11'||$_smarty_tpl->tpl_vars['roleid']->value=='H4'||$_smarty_tpl->tpl_vars['roleid']->value=='H34'||$_smarty_tpl->tpl_vars['roleid']->value=='H36'||$_smarty_tpl->tpl_vars['roleid']->value=='H38'||$_smarty_tpl->tpl_vars['roleid']->value=='H42'||$_smarty_tpl->tpl_vars['roleid']->value=='H44'){?>
|
||||
|
||||
<?php if ($_smarty_tpl->tpl_vars['roleid']->value=='H12'||$_smarty_tpl->tpl_vars['roleid']->value=='H11'||$_smarty_tpl->tpl_vars['roleid']->value=='H4'){?>
|
||||
<li style=" padding: 2.5% 2% !important;">
|
||||
<a style=" color:#ffffff; " href="?module=EtatStockReporting&view=EtatStockReporting">
|
||||
<!--<span class="fa fa-cog module-icon"></span>-->
|
||||
@@ -423,7 +427,8 @@ $_smarty_tpl->tpl_vars['moduleModel']->_loop = true;
|
||||
</a>
|
||||
</li>
|
||||
<?php }?>
|
||||
<?php if ($_smarty_tpl->tpl_vars['roleid']->value!='H12'&&$_smarty_tpl->tpl_vars['roleid']->value!='H11'&&$_smarty_tpl->tpl_vars['roleid']->value!='H4'&&$_smarty_tpl->tpl_vars['roleid']->value!='H34'&&$_smarty_tpl->tpl_vars['roleid']->value!='H36'&&$_smarty_tpl->tpl_vars['roleid']->value!='H38'&&$_smarty_tpl->tpl_vars['roleid']->value!='H42'&&$_smarty_tpl->tpl_vars['roleid']->value!='H44'){?>
|
||||
|
||||
<?php if ($_smarty_tpl->tpl_vars['roleid']->value!='H12'&&$_smarty_tpl->tpl_vars['roleid']->value!='H11'&&$_smarty_tpl->tpl_vars['roleid']->value!='H4'){?>
|
||||
<li style=" padding: 2.5% 2% !important;">
|
||||
<a style=" color:#ffffff; " href="?module=ExportData&view=ExportData">
|
||||
<span style="font-size: 10pt" class="module-name textOverflowEllipsis">Export Data</span>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?php /* Smarty version Smarty-3.1.7, created on 2025-09-27 18:02:08
|
||||
<?php /* Smarty version Smarty-3.1.7, created on 2025-10-15 15:23:42
|
||||
compiled from "C:\xampp\htdocs\sophalcrm\includes\runtime/../../layouts/v7\modules\Events\uitypes\Multireference.tpl" */ ?>
|
||||
<?php /*%%SmartyHeaderCode:157938834968d826a00c4717-78770212%%*/if(!defined('SMARTY_DIR')) exit('no direct access allowed');
|
||||
$_valid = $_smarty_tpl->decodeProperties(array (
|
||||
@@ -7,7 +7,7 @@ $_valid = $_smarty_tpl->decodeProperties(array (
|
||||
'b307425d1b338e6a92e5cdf7e1d4fa12929b2d14' =>
|
||||
array (
|
||||
0 => 'C:\\xampp\\htdocs\\sophalcrm\\includes\\runtime/../../layouts/v7\\modules\\Events\\uitypes\\Multireference.tpl',
|
||||
1 => 1758796609,
|
||||
1 => 1759105402,
|
||||
2 => 'file',
|
||||
),
|
||||
),
|
||||
@@ -15,6 +15,8 @@ $_valid = $_smarty_tpl->decodeProperties(array (
|
||||
'function' =>
|
||||
array (
|
||||
),
|
||||
'version' => 'Smarty-3.1.7',
|
||||
'unifunc' => 'content_68d826a01474f',
|
||||
'variables' =>
|
||||
array (
|
||||
'FIELD_MODEL' => 0,
|
||||
@@ -30,8 +32,6 @@ $_valid = $_smarty_tpl->decodeProperties(array (
|
||||
'RELATED_CONTACTS' => 0,
|
||||
),
|
||||
'has_nocache_code' => false,
|
||||
'version' => 'Smarty-3.1.7',
|
||||
'unifunc' => 'content_68d826a01474f',
|
||||
),false); /*/%%SmartyHeaderCode%%*/?>
|
||||
<?php if ($_valid && !is_callable('content_68d826a01474f')) {function content_68d826a01474f($_smarty_tpl) {?>
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?php /* Smarty version Smarty-3.1.7, created on 2025-09-26 16:17:23
|
||||
<?php /* Smarty version Smarty-3.1.7, created on 2025-10-25 18:34:43
|
||||
compiled from "C:\xampp\htdocs\sophalcrm\includes\runtime/../../layouts/v7\modules\Vtiger\partials\Topbar.tpl" */ ?>
|
||||
<?php /*%%SmartyHeaderCode:82061580868d6bc93909675-76245406%%*/if(!defined('SMARTY_DIR')) exit('no direct access allowed');
|
||||
$_valid = $_smarty_tpl->decodeProperties(array (
|
||||
@@ -7,7 +7,7 @@ $_valid = $_smarty_tpl->decodeProperties(array (
|
||||
'b62713acd22803ca6b3ad6d54ce71cdbcc4dc22a' =>
|
||||
array (
|
||||
0 => 'C:\\xampp\\htdocs\\sophalcrm\\includes\\runtime/../../layouts/v7\\modules\\Vtiger\\partials\\Topbar.tpl',
|
||||
1 => 1758796685,
|
||||
1 => 1761417278,
|
||||
2 => 'file',
|
||||
),
|
||||
),
|
||||
@@ -15,6 +15,8 @@ $_valid = $_smarty_tpl->decodeProperties(array (
|
||||
'function' =>
|
||||
array (
|
||||
),
|
||||
'version' => 'Smarty-3.1.7',
|
||||
'unifunc' => 'content_68d6bc93933c4',
|
||||
'variables' =>
|
||||
array (
|
||||
'MODULE' => 0,
|
||||
@@ -37,8 +39,6 @@ $_valid = $_smarty_tpl->decodeProperties(array (
|
||||
'IMAGE_INFO' => 0,
|
||||
),
|
||||
'has_nocache_code' => false,
|
||||
'version' => 'Smarty-3.1.7',
|
||||
'unifunc' => 'content_68d6bc93933c4',
|
||||
),false); /*/%%SmartyHeaderCode%%*/?>
|
||||
<?php if ($_valid && !is_callable('content_68d6bc93933c4')) {function content_68d6bc93933c4($_smarty_tpl) {?>
|
||||
|
||||
|
||||
51
test_so_pdf.php
Normal file
51
test_so_pdf.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
$recordId = 1020725; // the SalesOrder ID
|
||||
|
||||
$module = 'SalesOrder';
|
||||
$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',
|
||||
'password' => 'Sophal@Crm@Sophal',
|
||||
]);
|
||||
|
||||
$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) Get 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 record $recordId");
|
||||
return;
|
||||
}
|
||||
|
||||
// 4) Save
|
||||
$filePath = $_SERVER['DOCUMENT_ROOT']."/sophalcrm/storage/SalesOrder_$recordId.pdf";
|
||||
file_put_contents($filePath, $pdfContent);
|
||||
24
testmail.php
Normal file
24
testmail.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
include_once 'vtlib/Vtiger/Mailer.php';
|
||||
|
||||
$mailer = new Vtiger_Mailer();
|
||||
$mailer->IsSMTP();
|
||||
$mailer->Host = 'mail.carixin.com'; // your SMTP host
|
||||
$mailer->Port = 587; // or 465
|
||||
$mailer->SMTPAuth = true;
|
||||
$mailer->Username = 'contact@carixin.com';
|
||||
$mailer->Password = 'carixin@2025';
|
||||
$mailer->SMTPSecure = 'tls'; // or 'ssl'
|
||||
$mailer->From = 'contact@carixin.com';
|
||||
$mailer->FromName = 'ERP Test';
|
||||
$mailer->AddAddress('souldibachir3150@gmail.com', 'Admin');
|
||||
$mailer->Subject = 'SMTP Test from Vtiger';
|
||||
$mailer->Body = 'If you see this email, SMTP works!';
|
||||
$mailer->SMTPDebug = 2;
|
||||
$mailer->Debugoutput = 'html';
|
||||
$mailer->Send();
|
||||
if ($mailer->Send()) {
|
||||
echo "✅ Mail sent successfully!";
|
||||
} else {
|
||||
echo "❌ Mail failed: " . $mailer->ErrorInfo;
|
||||
}
|
||||
Reference in New Issue
Block a user