diff --git a/app/Config/Acl.php b/app/Config/Acl.php
index 80f7a2bd..86760bb0 100644
--- a/app/Config/Acl.php
+++ b/app/Config/Acl.php
@@ -17,6 +17,7 @@ class Acl
'#^/getVerifiedPosUserData#' => ['public' => true],
'#^/swagger#' => ['roles' => [ADMIN_ROLE_ID]],
'#^/getEmployeeActiveOrInactivePolicy#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID]],
+ '#^/bulkEcardDownloadAsZip#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID]],
'#^/sheet#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID]],
'#^/sendextraparam#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID]],
'#^/test/testingquerys#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID]],
@@ -28,6 +29,7 @@ class Acl
'#^/util/view_log#' => ['roles' => [ADMIN_ROLE_ID]],
'#^/util/download_log#' => ['roles' => [ADMIN_ROLE_ID]],
'#^/metaDashboardDemo#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID]],
+ '#^/metaTpaDashboardDemo#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID]],
// ===================== PUBLIC DOWNLOADS / FORMS =====================
'#^/download-#' => ['public' => true],
diff --git a/app/Config/Filters.php b/app/Config/Filters.php
index 6c031ae7..b219e60e 100755
--- a/app/Config/Filters.php
+++ b/app/Config/Filters.php
@@ -69,7 +69,7 @@ class Filters extends BaseConfig
'before' => [
'HttpRequestLog' => ['except' => 'cli/*'],
'Cors',
- 'AclFilter' => ['except' => ['login', 'logout', 'auth/*', 'oauth2callback','claim-form-download', 'claims-feedback-form', 'autobookstackLogin','employeeRest/*','processjob','getCommission']],
+ 'AclFilter' => ['except' => ['login', 'logout', 'auth/*', 'oauth2callback','claim-form-download', 'claims-feedback-form', 'autobookstackLogin','employeeRest/*','processjob','getCommission','downloadEmployeeEcardZip']],
'SecurityInputFilter' => ['except' => ['/client/notification/create','/ticket/crud_mail_template/*','test_mail','leads/sendMail'] ],
'GlobalPostFileUploadGuard'
// 'csrf',
diff --git a/app/Config/Routes.php b/app/Config/Routes.php
index efde3147..d7353cb7 100755
--- a/app/Config/Routes.php
+++ b/app/Config/Routes.php
@@ -32,6 +32,7 @@ $routes->get('/fedeploy', 'DeployController::fedeploy_view', ['filter' => 'authM
$routes->post('/fedeploy', 'DeployController::fedeploy', ['filter' => 'authMVC']);
$routes->get('/visitOffBoardCheck', 'EmployeeController::visitOffBoardCheck');
$routes->get('/metaDashboardDemo', 'TestingController::metaDashboardDemo');
+$routes->get('/metaTpaDashboardDemo', 'TestingController::metaTpaDashboardDemo');
// Reminder Mail Notification
@@ -87,6 +88,7 @@ $routes->get('claim-form-download/(:any)', 'TicketController::downloadClaimForm/
$routes->get('downloadClaimFile/(:any)', 'TicketController::downloadClaimFile/$1');
$routes->match (['get','post'],"claims-feedback-form/(:any)/(:any)", "TicketController::viewClaimFeedbackForm/$1/$2");
$routes->match (['get','post'],"claims-feedback-form/(:any)", "TicketController::viewClaimFeedbackForm/$1");
+$routes->get('downloadEmployeeEcardZip/(:any)', 'EmployeeController::downloadEmployeeEcardZip/$1');
@@ -416,7 +418,7 @@ $routes->group("/util", ["filter" => "authMVC"], function ($routes) {
$routes->get('getTheEmpDataForClaim/(:any)', 'ClientController::getTheEmpDataForClaim/$1');
// $routes->get('getTheEmpDataForClaimSearchByMobile/(:any)', 'ClientController::getTheEmpDataForClaimSearchByMobile/$1');
$routes->get('getTheEmpDataForClaimSearchByMobile', 'ClientController::getTheEmpDataForClaimSearchByMobile');
- $routes->get('getLeadNonEB/(:any)', 'LeadsController::getLeadNonEB/$1');
+ $routes->get('getLeadNonEB/(:any)/(:any)', 'LeadsController::getLeadNonEB/$1/$2');
$routes->get('getPolicyTypeFields', 'LeadsController::getPolicyTypeFields');
$routes->get('removeMultiFile', 'LeadsController::removeMultiFile');
$routes->get('removeInstallments', 'LeadsController::removeInstallments');
@@ -669,6 +671,7 @@ $routes->group("employeeRest", ["filter" => ['GlobalPostFileUploadGuard', 'ratel
$routes->post("hrFileUpload", "EmployeeRestController::hrFileUpload");
$routes->post("updateHrFileUploadData", "EmployeeRestController::updateHrFileUploadData");
$routes->post("getHrDashboad", "EmployeeRestController::getHrDashboad");
+ $routes->post("getHrTpaDashboard", "EmployeeRestController::getHrTpaDashboard");
//thz_master's
@@ -706,6 +709,7 @@ $routes->group("employeeRest", ["filter" => ['GlobalPostFileUploadGuard', 'ratel
$routes->get("downloadSampleExcel/(:any)", "EmployeeController::downloadSampleExcelFile/$1");
});
+$routes->post("bulkEcardDownloadAsZip", "EmployeeRestController::bulkEcardDownloadAsZip");
$routes->get("hrFileDownload", "EmployeeRestController::hrFileDownload");
$routes->post("hrFileList", "EmployeeRestController::hrFileList");
$routes->get("getEmployeeActiveOrInactivePolicy", "EmployeeRestController::getEmployeeActiveOrInactivePolicy");
@@ -908,6 +912,10 @@ $routes->group('sales', function($routes) {
$routes->get('/', 'SalesController::index');
+ $routes->get('activities', 'SalesController::activities');
+
+ $routes->get('page/(:segment)', 'SalesController::noPage/$1');
+
// Get all leads with filters
$routes->get('leads', 'SalesController::getLeads');
diff --git a/app/Controllers/EmployeeController.php b/app/Controllers/EmployeeController.php
index 4e7ddef7..01664e76 100755
--- a/app/Controllers/EmployeeController.php
+++ b/app/Controllers/EmployeeController.php
@@ -41,6 +41,7 @@ use App\Controllers\EmployeeServiceController;
use App\Controllers\EmpDataServiceController;
use App\Models\LeadsModel;
use App\Models\ThzMasterModel;
+use App\Models\UserActivityHistoryModel;
use CodeIgniter\API\ResponseTrait;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
@@ -78,6 +79,7 @@ class EmployeeController extends AdminController
protected $userModel;
protected $partnerEndorsementRequestModel;
protected $LevelContactModel;
+ protected $UserActivityHistoryModel;
public function __construct()
{
@@ -102,6 +104,7 @@ class EmployeeController extends AdminController
$this->userModel = new userModel();
$this->partnerEndorsementRequestModel = new PartnerEndorsementRequestModel();
$this->LevelContactModel = new LevelContactModel();
+ $this->UserActivityHistoryModel = new UserActivityHistoryModel();
}
public function list()
@@ -4862,8 +4865,133 @@ class EmployeeController extends AdminController
return $mail_response;
}
- public function downloadZip(){
+
+ public function bulkEcardDownloadAsZipFromS3New($params)
+ {
+ try {
+
+ $limit = $params['limit'] ?? 100;
+ $last_id = $params['last_id'] ?? 0;
+ $zip_id = $params['zip_id'];
+
+ $employee_data = $this->employeePolicyModel->getEmployeeDataWithPolicyUsingClientPolicyIdOrEmployeePolicyIds($params, $limit, $last_id);
+
+ if (empty($employee_data)) {
+ // No more records, move to Zipping phase
+ return Jobs::addJob(['job_name' => 'getEmployeeEcardFromTmpFolderAndZipToS3', 'payload' => $params]);
+ }
+
+ $tempPath = FCPATH . 'tmp/' . $params['folder_name'] . '/';
+ if (!is_dir($tempPath)) mkdir($tempPath, 0777, true);
+
+ $s3 = \Config\Services::getS3Service();
+ $current_last_id = $last_id;
+ $pdf_count = 0;
+
+ foreach ($employee_data as $emp) {
+ $current_last_id = $emp['emp_policy_id'];
+
+
+ $s3_key = 'ecard_' . $emp['name'] . '(' . $emp['emp_code'] . ')' . '_' . $emp['tpa_id'] . '.pdf';
+ $s3_key = $this->sanitizeFilePart($s3_key);
+
+ if ($s3->exists($s3_key)) {
+ $s3_url = $s3->getPresignedUrl($s3_key);
+ $pdf_content = file_get_contents($s3_url['url']);
+
+ if ($pdf_content !== false) {
+ file_put_contents($tempPath . $s3_key, $pdf_content);
+ $pdf_count++;
+ }
+ }
+ }
+
+ // Check if we need more batches
+ $params['last_id'] = $current_last_id;
+ $params['pdf_count'] = $pdf_count;
+ $params['batch_no'] = ($params['batch_no'] ?? 1) + 1;
+
+ if (count($employee_data) == $limit) {
+ return Jobs::addJob(['job_name' => 'bulkEcardDownloadAsZipFromS3', 'payload' => $params]);
+ } else {
+ return Jobs::addJob(['job_name' => 'getEmployeeEcardFromTmpFolderAndZipToS3', 'payload' => $params]);
+ }
+
+ } catch (\Throwable $e) {
+ $this->logAndNotifyError($e, $params);
+ }
+ }
+
+ public function getEmployeeEcardFromTmpFolderAndZipToS3New($params)
+ {
+ try {
+ $zipService = new \App\Libraries\ZipService();
+ $source = FCPATH . 'tmp/' . $params['folder_name'];
+ $zipName = $params['folder_name'] . '.zip';
+ $s3_dest_key = 'exports/zips/' . $zipName;
+
+ // 1. Create Zip and Upload
+ $result = $zipService->zipAndUploadS3($source, $s3_dest_key);
+
+ if ($result['status']) {
+ // 2. IMPORTANT: Update the Activity Record with the S3 Key
+ $history = $this->UserActivityHistoryModel->find($params['zip_id']);
+ $misc = json_decode($history['misc_data'], true);
+ $misc['status'] = 'completed';
+ $misc['s3_key'] = $s3_dest_key;
+
+ $this->UserActivityHistoryModel->update($params['zip_id'], [
+ 'misc_data' => json_encode($misc)
+ ]);
+
+ $params['url'] = base_url('downloadEmployeeEcardZip/' . md5($params['zip_id']));
+ }
+
+ // 3. Cleanup local files
+ $this->recursiveRemoveDir($source);
+
+ // 4. Email HR
+ return $this->sendMailToHrWithZipAttachments($params);
+
+ } catch (\Throwable $e) {
+ $this->logAndNotifyError($e, $params);
+ }
+ }
+
+ public function downloadEmployeeEcardZip($md5Id)
+ {
+ // Search by MD5 of ID
+ $data = $this->UserActivityHistoryModel->where('MD5(CAST(id AS CHAR))', $md5Id)->first();
+
+ if (!$data) return "File link expired or invalid.";
+
+ $misc = json_decode($data['misc_data'], true);
+ $s3Key = $misc['s3_key'] ?? null;
+
+ if (!$s3Key) return "File is still processing or failed to generate.";
+
+ $s3 = \Config\Services::getS3Service();
+ $presigned = $s3->getPresignedUrl($s3Key, 15); // 15 mins expiry
+
+ return redirect()->to($presigned['url']);
+ }
+
+ private function logAndNotifyError($e, $params)
+ {
+ $this->myLogger->logme('error', "[ECARD_ZIP]: " . $e->getMessage());
+ $params['url'] = null; // Forces "Failed" email
+ $this->sendMailToHrWithZipAttachments($params);
+ }
+
+ private function recursiveRemoveDir($dir)
+ {
+ if (!is_dir($dir)) return;
+ $files = array_diff(scandir($dir), array('.', '..'));
+ foreach ($files as $file) {
+ (is_dir("$dir/$file")) ? $this->recursiveRemoveDir("$dir/$file") : unlink("$dir/$file");
+ }
+ return rmdir($dir);
}
}
diff --git a/app/Controllers/EmployeeRestController.php b/app/Controllers/EmployeeRestController.php
index fb17d59a..5c87df6c 100755
--- a/app/Controllers/EmployeeRestController.php
+++ b/app/Controllers/EmployeeRestController.php
@@ -63,6 +63,7 @@ use App\Models\ClaimFilesModel;
use App\Models\PolicyTransactionModel;
use App\Models\TicketMailTemplateModel;
use App\Models\TpaApiSeviceModel;
+use App\Models\UserActivityHistoryModel;
use Composer\Pcre\Preg;
use Kreait\Firebase\Factory;
use Kreait\Firebase\Messaging\CloudMessage;
@@ -106,6 +107,7 @@ class EmployeeRestController extends AdminController
protected $ticketMailTemplateModel;
protected $employeeRetailPolicy;
protected $batchFileModel;
+ protected $UserActivityHistoryModel;
public function __construct()
@@ -141,6 +143,7 @@ class EmployeeRestController extends AdminController
$this->hrFileUploadModel = new HrFileUploadModel();
$this->ticketMailTemplateModel = new TicketMailTemplateModel();
$this->batchFileModel = new BatchFileModel();
+ $this->UserActivityHistoryModel = new UserActivityHistoryModel();
}
@@ -5498,9 +5501,15 @@ class EmployeeRestController extends AdminController
// 🔐 Move this to .env in real projects
$METABASE_SECRET_KEY = getenv('METABASE_SECRET_KEY');
+ $is_tpa_dashboard_enable = $this->clientPolicyModel
+ ->select('tpa.dashboard_id')
+ ->join('tpa', 'client_policy.tpa_id = tpa.id')
+ ->where('client_policy.id', $received_data['client_policy_id'])
+ ->where('tpa.dashboard_id IS NOT NULL')
+ ->first();
+
$payload = [
'resource' => [
- // 'dashboard' => 1
'dashboard' => 2
],
'params' => (object)['client_policy' => $received_data['client_policy_id']], // MUST be object for Metabase
@@ -5520,8 +5529,10 @@ class EmployeeRestController extends AdminController
'status' => 'success',
'message' => 'Form data received successfully!',
'data' => [
- 'metabaseToken' => $token,
- 'metabaseUrl' => 'https://nsights.nhanceindia.in']
+ 'metabaseToken' => $token,
+ 'metabaseUrl' => 'https://nsights.nhanceindia.in'
+ ],
+ 'is_tpa_dashboard_enable' => !empty($is_tpa_dashboard_enable ?? []),
]);
// }
@@ -5530,6 +5541,73 @@ class EmployeeRestController extends AdminController
'metabaseUrl' => 'https://nsights.nhanceindia.in',
]);
}
+
+ public function getHrTpaDashboard($client_policy_id = null, $return_type = 'api')
+ {
+ $METABASE_SECRET_KEY = getenv('METABASE_SECRET_KEY');
+
+ if ($return_type === 'api') {
+
+ $received_data = $this->request->getJSON(true) ?? [];
+ $policy_id = $received_data['client_policy_id'] ?? null;
+
+ } else {
+ // Internal call
+ $policy_id = $client_policy_id;
+ }
+
+ if (empty($policy_id)) {
+ return $this->respond([
+ 'status' => 'failed',
+ 'message' => 'Client Policy ID is required.',
+ 'data' => []
+ ]);
+ }
+
+ $client_policy_data = $this->clientPolicyModel
+ ->select('tpa.dashboard_id')
+ ->join('tpa', 'client_policy.tpa_id = tpa.id')
+ ->where('client_policy.id', $policy_id)
+ ->first();
+
+ $database_id = isset($client_policy_data['dashboard_id']) ? (int) $client_policy_data['dashboard_id'] : null;
+
+ if (empty($database_id)) {
+ return $this->respond([
+ 'status' => 'failed',
+ 'message' => 'There is no dashboard for this TPA.',
+ 'data' => []
+ ]);
+ }
+
+ $payload = [
+ 'resource' => [
+ 'dashboard' => $database_id
+ ],
+ 'exp' => time() + (10 * 60),
+ 'params' => (object)[]
+ ];
+
+ $token = JWT::encode($payload, $METABASE_SECRET_KEY, 'HS256');
+
+ if ($return_type === 'internal') {
+
+ // Return raw data for internal usage
+ return [
+ 'metabaseToken' => $token,
+ 'metabaseUrl' => 'https://nsights.nhanceindia.in'
+ ];
+ }
+
+ return $this->respond([
+ 'status' => 'success',
+ 'message' => 'Dashboard fetched successfully.',
+ 'data' => [
+ 'metabaseToken' => $token,
+ 'metabaseUrl' => 'https://nsights.nhanceindia.in'
+ ]
+ ]);
+ }
// get policy files
@@ -5648,5 +5726,55 @@ class EmployeeRestController extends AdminController
}
+ public function bulkEcardDownloadAsZipNew()
+ {
+ $received_data = $this->request->getJSON(true) ?? [];
+
+ if (empty($received_data['client_policy_id']) && empty($received_data['emp_policy_ids'])) {
+ return $this->respond(['status' => false, 'message' => 'client_policy_id or employee_policy_ids is required'], 400);
+ }
+
+ if (empty($received_data['hr_id'])) {
+ return $this->respond(['status' => false, 'message' => 'hr_id is required'], 400);
+ }
+
+ $employee_data = $this->employeePolicyModel->getEmployeeDataWithPolicyUsingClientPolicyIdOrEmployeePolicyIds($received_data, 1);
+
+ if (empty($employee_data)) {
+ return $this->respond(['status' => false, 'message' => 'No employee data found'], 404);
+ }
+
+ // Define naming convention
+ $folderName = 'bulk_ecards_' . ($employee_data[0]['client_short_name'] ?? 'export') . '_' . date('Ymd_His');
+
+ $insert_data = [
+ 'user_id' => $received_data['hr_id'],
+ 'user_type' => 'hr',
+ 'activity' => 'download_employees_ecard_zip',
+ 'misc_data' => json_encode([
+ 'folder_name' => $folderName,
+ 'status' => 'pending',
+ 's3_key' => null
+ ])
+ ];
+
+ $zip_id = $this->UserActivityHistoryModel->insert($insert_data);
+
+ $payload = array_merge($received_data, [
+ 'zip_id' => $zip_id,
+ 'folder_name' => $folderName,
+ 'batch_no' => 1,
+ 'last_id' => 0,
+ 'limit' => 100
+ ]);
+
+ // Dispatch job
+ Jobs::addJob(['job_name' => 'bulkEcardDownloadAsZipFromS3', 'payload' => $payload]);
+
+ return $this->respond([
+ 'status' => true,
+ 'message' => 'Process started. You will receive an email with the download link shortly.'
+ ], 200);
+ }
}
diff --git a/app/Controllers/LeadsController.php b/app/Controllers/LeadsController.php
index b4eaac06..2c2d9bcf 100644
--- a/app/Controllers/LeadsController.php
+++ b/app/Controllers/LeadsController.php
@@ -363,8 +363,9 @@ class LeadsController extends BaseController
public function createLead()
{
- // print_r($this->request->getPost()); die;
$id = $this->request->getPost('id');
+ $actual_lead_id = $this->request->getPost('actual_lead_id');
+ $actual_lead_id = !empty($actual_lead_id) ? $actual_lead_id : null;
$postData = $this->request->getPost();
$data = $this->prepareLeadData();
$rules = [
@@ -4349,8 +4350,10 @@ class LeadsController extends BaseController
}
// get lead data for edit both EB and NON-EB
- public function getLeadNonEB($type, $id = null)
+ public function getLeadNonEB($type, $actual_lead_id = null ,$id = null)
{
+ // Convert '0' to null so it doesn't break your existing DB checks
+ $actual_lead_id = ($actual_lead_id == 0 || $actual_lead_id == '0') ? null : $actual_lead_id;
// Set basic data
$data = [
'issuer' => $this->issuer,
@@ -4365,6 +4368,7 @@ class LeadsController extends BaseController
'gpaClaimType' => $this->claim_type_for_gpa,
'causeOfDeath' => $this->cause_of_death,
'selected_lead_type' => $type,
+ 'actual_lead_id' => $actual_lead_id,
];
// Fetch sales team members who are active in team 5
diff --git a/app/Controllers/SalesController.php b/app/Controllers/SalesController.php
index f79fd170..904217b1 100644
--- a/app/Controllers/SalesController.php
+++ b/app/Controllers/SalesController.php
@@ -27,15 +27,107 @@ class SalesController extends BaseController
$this->noteModel = new SalesLeadNoteModel();
}
+
public function index() {
- $db = \Config\Database::connect();
- // Fetch users for the assignment dropdowns
- $data['users'] = $db->table('user_profiles')
- ->select('id, first_name, last_name')
- ->where('is_active', 1)
- ->get()->getResultArray();
+ $data = $this->getSalesStaffData();
+
+ $data['tab_name'] = 'Leads';
+ $data['page_name'] = 'Leads';
+
+ return $this->loadLayout('sales/tracker_view', $data);
+ }
- $this->loadLayout('sales/tracker_view', $data);
+ public function activities(){
+ $data = $this->getSalesStaffData();
+
+ $data['tab_name'] = 'Activities';
+ $data['page_name'] = 'Activities';
+
+ $data['leads'] = $this->leadModel->select('lead_id, company_name')
+ ->orderBy('lead_id', 'DESC')
+ ->findAll();
+
+ return $this->loadLayout('sales/activity_view', $data);
+ }
+
+ /**
+ * HELPER: Fetches Sales Managers based on the logged-in user's role and branch
+ */
+ private function getSalesStaffData(): array
+ {
+ $db = \Config\Database::connect();
+ $logged_user_id = get_session_userid();
+
+ $data = [
+ 'users' => [],
+ 'sales_manager_ids' => []
+ ];
+
+ // Get the Branch ID, Role, Team, and Name of the logged-in user
+ $row = $db->table('user_profiles up')
+ ->select('up.id, up.first_name, up.last_name, up.nhance_branch_id, up.role, ut.team_id')
+ ->join('user_teams ut', 'ut.user_id = up.id', 'left')
+ ->where('up.is_active', 1)
+ ->where('up.id', $logged_user_id)
+ ->get()
+ ->getRow();
+
+ $nhance_branch_id = $row ? $row->nhance_branch_id : null;
+ $role = $row ? $row->role : null;
+ $team_id = $row ? $row->team_id : null;
+
+ // Is the logged-in user a Sales Manager? (Role 4, Team 5)
+ if ($role == 4 && $team_id == 5) {
+
+ $data['sales_manager_ids'] = [$logged_user_id];
+
+ $data['users'] = [
+ [
+ 'id' => $row->id,
+ 'sales_manager' => trim($row->first_name . ' ' . $row->last_name),
+ 'nhance_branch_id' => $nhance_branch_id
+ ]
+ ];
+
+ }
+ // Otherwise fetch ALL sales managers in this branch
+ elseif ($nhance_branch_id) {
+
+ $data['users'] = $db->table('user_profiles up')
+ ->select('up.id, up.first_name, up.last_name, up.nhance_branch_id')
+ ->join('user_teams ut', 'ut.user_id = up.id')
+ ->where('up.is_active', 1)
+ ->where('ut.is_active', 1)
+ ->where('up.role', 4)
+ ->where('ut.team_id', 5)
+ ->where('up.nhance_branch_id', $nhance_branch_id)
+ ->get()
+ ->getResultArray();
+
+ $data['sales_manager_ids'] = array_column($data['users'], 'id');
+ }
+
+ return $data;
+ }
+
+ public function noPage($type = null)
+ {
+
+ $page_type = $type ?? 'Page';
+
+ $data['tab_name'] = 'Sales ' . $page_type;
+ $data['page_name'] = 'Sales ' . $page_type;
+
+ echo view('layout/header', $data);
+ echo '
+
+
+
Oops! ' . esc($page_type) . ' is under construction.
+
+
+
+
';
+ echo view('layout/footer', $data);
}
public function completeActivity($id) {
@@ -672,7 +764,7 @@ class SalesController extends BaseController
}
- // ==================== Dashboard ====================
+ // ==================== Dashboard ====================
public function branchLevelDashboard()
{
@@ -736,19 +828,39 @@ class SalesController extends BaseController
public function salesManagerLevelDashboard()
{
- $userId = 1;
+ $userId = get_session_userid();
+ // $userId = 1;
$db = \Config\Database::connect();
try {
+
+ $payload = $this->request->getGet();
+ $current_fin_year = $payload['fy'] ?? getCurrentFinancialYear();
+
+
+ $fin_years = $db->table('sales_target')
+ ->select('fy_year')
+ ->where('user_id', $userId)
+ ->orderBy('fy_year', 'desc')
+ ->get()
+ ->getResultArray();
+ $fin_years = array_column($fin_years, 'fy_year');
+ $fin_years[] = '2024-2025';
+
$target = $db->table('sales_target')
->where('user_id', $userId)
- ->where('fy_year', '2025-2026')
- ->get()->getRowArray();
+ ->where('fy_year', $current_fin_year)
+ ->get()
+ ->getRowArray();
+
+ $targetAmount = $target['target_amount'] ?? 0.00;
+
+ // get achieved amount from leads table
+ $achievedAmount = $this->getUserAchievedAmount($current_fin_year, $userId);
- $targetAmount = $target['target_amount'] ?? 2500000.00;
- $achievedAmount = 600000.00;
$remainingAmount = $targetAmount - $achievedAmount;
- $achievementPercent = ($targetAmount > 0) ? round(($achievedAmount / $targetAmount) * 100) : 0;
+ // $achievementPercent = ($targetAmount > 0) ? round(($achievedAmount / $targetAmount) * 100) : 0;
+ $achievementPercent = ($targetAmount > 0) ? min(100, round(($achievedAmount / $targetAmount) * 100)) : 0;
$activitySummary = [
'total' => $this->activityModel->where('assigned_to', $userId)->countAllResults(),
@@ -779,9 +891,13 @@ class SalesController extends BaseController
'lead_count' => $myLeadsCount,
'upcoming' => $upcomingActivities,
'recent_leads' => $recentLeads,
- 'user_name' => session()->get('first_name') ?? 'John Doe'
+ 'fin_years' => $fin_years,
+ 'display_fin_years' => format_financial_year($current_fin_year),
+ 'user_name' => get_session_userdata()->first_namee ?? ''
];
+ // dd($data);
+
// return view('sales/my_dashboard_view', $data);
$this->loadLayout('sales/sales_manager_level_dashboard', $data);
@@ -789,4 +905,27 @@ class SalesController extends BaseController
return $this->failServerError($e->getMessage());
}
}
+
+ public function getUserAchievedAmount($financialYear, $userId)
+ {
+ // Split the string into two years
+ $years = explode('-', $financialYear);
+ $startYear = $years[0]; // 2025
+ $endYear = $years[1]; // 2026
+
+ // Create the timestamps
+ $startFY = $startYear . '-04-01 00:00:00';
+ $endFY = $endYear . '-03-31 23:59:59';
+
+ $achievedAmountData = $this->leadModel
+ ->select('SUM(leads.premium_amount) as achieved_amount')
+ ->join('leads', 'sales_actual_leads.lead_id = leads.actual_lead_id')
+ ->where('sales_actual_leads.assigned_to', $userId)
+ ->where('leads.status', 'won')
+ ->where('leads.updated_at >=', $startFY)
+ ->where('leads.updated_at <=', $endFY)
+ ->findAll();
+
+ return $achievedAmountData[0]['achieved_amount'] ?? 0.00;
+ }
}
\ No newline at end of file
diff --git a/app/Controllers/TestingController.php b/app/Controllers/TestingController.php
index 66957ea8..aaf62878 100644
--- a/app/Controllers/TestingController.php
+++ b/app/Controllers/TestingController.php
@@ -4,6 +4,7 @@ namespace App\Controllers;
use App\Controllers\BaseController;
use App\Models\EmployeePolicyModel;
+use App\Models\ClientPolicyModel;
use App\Models\InsurerBranchModel;
use App\Models\RFQModel;
use CodeIgniter\HTTP\ResponseInterface;
@@ -23,10 +24,12 @@ class TestingController extends BaseController
{
use ResponseTrait;
protected $myLogger;
+ protected $ClientPolicyModel;
public function __construct()
{
$this->myLogger = \Config\Services::mylogger();
+ $this->ClientPolicyModel = new ClientPolicyModel();
}
public function saveForm()
@@ -1060,4 +1063,59 @@ class TestingController extends BaseController
return $this->respond(['status' => 'failed', 'code' => '500' , 'message' => 'Error: ' . $e->getMessage()], 200);
}
}
+
+ public function metaTpaDashboardDemo()
+ {
+ $METABASE_SECRET_KEY = getenv('METABASE_SECRET_KEY');
+ $policy_id = $this->request->getGet('client_policy') ?? 4687;
+
+ $client_policy_data = $this->ClientPolicyModel
+ ->select('tpa.dashboard_id')
+ ->join('tpa', 'client_policy.tpa_id = tpa.id')
+ ->where('client_policy.id', $policy_id)
+ ->first();
+
+ $database_id = isset($client_policy_data['dashboard_id']) ? (int) $client_policy_data['dashboard_id'] : null;
+
+ if (empty($database_id)) {
+
+ if ($this->request->getGet('api') == 1) {
+ return $this->respond([
+ 'status' => 'failed',
+ 'message' => 'There is no dashboard for this TPA.',
+ 'data' => []
+ ]);
+ }
+
+ return view('errors/404', [
+ 'message' => 'There is no dashboard for this TPA.'
+ ]);
+ }
+
+ $payload = [
+ 'resource' => [
+ 'dashboard' => $database_id
+ ],
+ 'exp' => time() + (10 * 60), // 10 minutes
+ 'params' => (object)[]
+ ];
+
+ $token = JWT::encode($payload, $METABASE_SECRET_KEY, 'HS256');
+
+ if ($this->request->getGet('api') == 1) {
+ return $this->respond([
+ 'status' => 'success',
+ 'message' => 'Form data received successfully!',
+ 'data' => [
+ 'metabaseToken' => $token,
+ 'metabaseUrl' => 'https://nsights.nhanceindia.in'
+ ]
+ ]);
+ }
+
+ return view('meta_dashboard_demo_one', [
+ 'metabaseToken' => $token,
+ 'metabaseUrl' => 'https://nsights.nhanceindia.in',
+ ]);
+ }
}
diff --git a/app/Helpers/utility_helper.php b/app/Helpers/utility_helper.php
index 467f0338..efc2842e 100755
--- a/app/Helpers/utility_helper.php
+++ b/app/Helpers/utility_helper.php
@@ -1210,7 +1210,7 @@ if (!function_exists('map_relationship')) {
* Extract identity from POST body or GET params.
* Looks for 'email' or 'mobile_number'.
*/
- function resolveIdentity($request): ?string
+ function resolveIdentity($request): ?string
{
// Try POST body first
$email = $request->getPost('email');
@@ -1251,7 +1251,7 @@ if (!function_exists('map_relationship')) {
}
- function recordRateLimitFailure(string $context = 'authApi'): void
+ function recordRateLimitFailure(string $context = 'authApi'): void
{
/** @var IncomingRequest $request */
$request = \Config\Services::request();
@@ -1276,4 +1276,64 @@ if (!function_exists('map_relationship')) {
}
+ if (!function_exists('getCurrentFinancialYear')) {
+ function getCurrentFinancialYear()
+ {
+ // Get current year and month
+ $date = new DateTime();
+ $currentYear = (int)$date->format('Y');
+ $currentMonth = (int)$date->format('m');
+
+ // If month is Jan, Feb, or March, we are still in the previous year's FY
+ if ($currentMonth < 4) {
+ $startYear = $currentYear - 1;
+ $endYear = $currentYear;
+ } else {
+ $startYear = $currentYear;
+ $endYear = $currentYear + 1;
+ }
+
+ return $startYear . '-' . $endYear;
+ }
+ }
+
+
+ if (!function_exists('format_financial_year')) {
+ function format_financial_year(string $financialYear): string
+ {
+ if (empty($financialYear) || !str_contains($financialYear, '-')) {
+ return $financialYear;
+ }
+
+ $years = explode('-', $financialYear);
+
+ // Ensure we have both parts
+ $startYear = $years[0] ?? '';
+ $endYear = $years[1] ?? '';
+
+ return "APR " . $startYear . " - MAR " . $endYear;
+ }
+ }
+
+
+ if(!function_exists('add_google_calender_event')){
+ function add_google_calender_event($data){
+
+ $calendar = new \App\Libraries\GoogleCalendarService();
+
+ // Check if user is authenticated without passing tokens manually
+ if (!$calendar->isReady()) {
+ return ['status' => 'failed', 'code' => '404' , 'message' => 'Google Access Token Expired'];
+ }
+
+ try {
+ $response = $calendar->createEvent($data);
+ return ['status' => 'success', 'code' => '200' , 'message' => 'Follow-up Saved', 'response' => $response];
+ } catch (\Exception $e) {
+ return ['status' => 'failed', 'code' => '500' , 'message' => 'Error: ' . $e->getMessage()];
+ }
+ }
+ }
+
+
diff --git a/app/Models/EmployeePolicyModel.php b/app/Models/EmployeePolicyModel.php
index 908d1698..8171df0c 100755
--- a/app/Models/EmployeePolicyModel.php
+++ b/app/Models/EmployeePolicyModel.php
@@ -2260,9 +2260,12 @@ class EmployeePolicyModel extends Model
employees.id as emp_id,
tpa.short_name,
employee_polices.tpa_id,
- client_policy.policy_no
+ client_policy.policy_no,
+ clients.client_name as client_name,
+ clients.short_name as client_short_name
')
->join('client_policy', 'client_policy.id = employee_polices.client_policy_id')
+ ->join('clients', 'clients.id = client_policy.client_id')
->join('employees', 'employees.id = employee_polices.employee_id')
->join('tpa', 'tpa.id = client_policy.tpa_id')
->where([
diff --git a/app/Models/LeadsModel.php b/app/Models/LeadsModel.php
index 1c028645..72ac2f59 100644
--- a/app/Models/LeadsModel.php
+++ b/app/Models/LeadsModel.php
@@ -10,6 +10,7 @@ class LeadsModel extends Model
protected $primaryKey = 'id';
protected $allowedFields = [
'id',
+ 'actual_lead_id',
'lead_type',
'issuer',
'client_type',
diff --git a/app/Models/SalesActivityModel.php b/app/Models/SalesActivityModel.php
index 80b8aef6..8d82097f 100644
--- a/app/Models/SalesActivityModel.php
+++ b/app/Models/SalesActivityModel.php
@@ -38,9 +38,9 @@ class SalesActivityModel extends Model
// Validation
protected $validationRules = [
'lead_id' => 'required|integer',
- 'activity_type' => 'required|in_list[Call,Email,Meeting,Demo,Share,Todo]',
+ 'activity_type' => 'required|in_list[Call,Email,Meeting,Demo,Share,Todo,Visit]',
'notes' => 'required',
- 'scheduled_date' => 'required|valid_date',
+ 'scheduled_date' => 'required',
'assigned_to' => 'required|integer',
'status' => 'in_list[pending,completed]',
];
@@ -80,35 +80,63 @@ class SalesActivityModel extends Model
*/
public function getActivitiesWithFilters($filters = [], $limit = 10, $offset = 0)
{
- $builder = $this->select('sales_activities.*, actual_leads.company_name, user_profiles.first_name as assigned_to_name')
- ->join('actual_leads', 'actual_leads.lead_id = sales_activities.lead_id', 'left')
+ $this->select('sales_activities.*, sales_actual_leads.company_name, user_profiles.first_name as assigned_to_name')
+ ->join('sales_actual_leads', 'sales_actual_leads.lead_id = sales_activities.lead_id', 'left')
->join('user_profiles', 'user_profiles.id = sales_activities.assigned_to', 'left');
if (!empty($filters['status'])) {
- $builder->where('sales_activities.status', $filters['status']);
+ $this->where('sales_activities.status', $filters['status']);
}
if (!empty($filters['activity_type'])) {
- $builder->where('sales_activities.activity_type', $filters['activity_type']);
+ $this->where('sales_activities.activity_type', $filters['activity_type']);
}
+ // if (!empty($filters['assigned_to'])) {
+ // $this->where('sales_activities.assigned_to', $filters['assigned_to']);
+ // }
if (!empty($filters['assigned_to'])) {
- $builder->where('sales_activities.assigned_to', $filters['assigned_to']);
+ $assigned_to = $filters['assigned_to'];
+
+ // If it's already an array, use it. If it's a string, explode it into an array.
+ $assignedToIds = is_array($assigned_to) ? $assigned_to : explode(',', $assigned_to);
+
+ // Now it is guaranteed to be an array, making whereIn perfectly safe
+ $this->whereIn('sales_actual_leads.assigned_to', $assignedToIds);
}
+
+
if (!empty($filters['date_from'])) {
- $builder->where('sales_activities.scheduled_date >=', $filters['date_from']);
+ $this->where('sales_activities.scheduled_date >=', $filters['date_from']);
}
if (!empty($filters['date_to'])) {
- $builder->where('sales_activities.scheduled_date <=', $filters['date_to']);
+ $this->where('sales_activities.scheduled_date <=', $filters['date_to']);
}
- return [
- 'data' => $builder->orderBy('sales_activities.scheduled_date', 'DESC')
- ->limit($limit, $offset)->findAll(),
- 'total' => $builder->countAllResults(false)
- ];
+ if (!empty($filters['search'])) {
+ $this->groupStart()
+ ->like('sales_actual_leads.company_name', $filters['search'])
+ ->orLike('sales_actual_leads.email', $filters['search'])
+ ->orLike('sales_actual_leads.phone', $filters['search'])
+ ->orLike('user_profiles.first_name', $filters['search'])
+ ->groupEnd();
+ }
+
+ $this->orderBy('sales_activities.created_at', 'DESC');
+
+ $total = $this->countAllResults(false);
+
+ $data = $this->findAll($limit, $offset);
+
+ return ['data' => $data,'total' => $total];
+
+ // return [
+ // 'data' => $builder->orderBy('sales_activities.scheduled_date', 'DESC')
+ // ->limit($limit, $offset)->findAll(),
+ // 'total' => $builder->countAllResults(false)
+ // ];
}
/**
@@ -142,8 +170,8 @@ class SalesActivityModel extends Model
{
$endDate = date('Y-m-d H:i:s', strtotime("+{$days} days"));
- return $this->select('sales_activities.*, actual_leads.company_name')
- ->join('actual_leads', 'actual_leads.lead_id = sales_activities.lead_id', 'left')
+ return $this->select('sales_activities.*, sales_actual_leads.company_name')
+ ->join('sales_actual_leads', 'sales_actual_leads.lead_id = sales_activities.lead_id', 'left')
->where('sales_activities.assigned_to', $userId)
->where('sales_activities.status', 'pending')
->where('sales_activities.scheduled_date <=', $endDate)
diff --git a/app/Models/SalesActualLeadModel.php b/app/Models/SalesActualLeadModel.php
index 25603740..22db6a2a 100644
--- a/app/Models/SalesActualLeadModel.php
+++ b/app/Models/SalesActualLeadModel.php
@@ -37,23 +37,37 @@ class SalesActualLeadModel extends Model
// Validation
protected $validationRules = [
- 'company_name' => 'required|min_length[2]|max_length[255]',
- 'email' => 'required|valid_email|max_length[255]',
- 'phone' => 'required|min_length[10]|max_length[20]',
- 'status' => 'in_list[New,Potential,Prospects,Non prospects]',
+ 'company_name' => 'required|alpha_space|min_length[2]|max_length[255]',
+ 'email' => 'required_without[phone]|permit_empty|valid_email|max_length[255]',
+ 'phone' => 'required_without[email]|permit_empty|regex_match[/^[0-9+\s]+$/]|min_length[10]|max_length[20]',
+ 'status' => 'in_list[New,Potential,Prospects,Not a Prospects]',
+ 'assigned_to' => 'required',
+ 'gst_number' => 'permit_empty|exact_length[15]|regex_match[/^[0-9]{2}[A-Z]{5}[0-9]{4}[A-Z][0-9A-Z]Z[0-9A-Z]$/]',
];
protected $validationMessages = [
'company_name' => [
- 'required' => 'Company name is required',
+ 'required' => 'Company Name is Missing',
+ 'alpha_space' => 'Company Name must contain only letters and spaces',
+ 'min_length' => 'Company Name must be at least 2 characters long',
+ 'max_length' => 'Company Name must be at most 255 characters long'
],
'email' => [
- 'required' => 'Email is required',
+ 'required_without' => 'Either Email or Mobile Number is Needed.',
'valid_email' => 'Please provide a valid email address',
+ 'max_length' => 'Email must be at most 255 characters long',
],
'phone' => [
- 'required' => 'Phone number is required',
+ 'required_without' => 'Either Email or Mobile Number is Needed.',
+ 'regex_match' => 'Phone number can contain only digits, + and spaces.',
+ 'min_length' => 'Mobile Number must be at least 10 characters long',
+ 'max_length' => 'Mobile Number must be at most 20 characters long',
],
+ 'status' => [ 'in_list' => 'Please select a valid Status'],
+ 'assigned_to'=> [ 'required' => 'Please select a valid User' ],
+ 'gst_number' => [ 'exact_length' => 'GST Number must be exactly 15 characters long.',
+ 'regex_match' => 'Please enter a valid GST Number (e.g., 22AAAAA0000A1Z5).'
+ ],
];
protected $skipValidation = false;
@@ -74,29 +88,42 @@ class SalesActualLeadModel extends Model
*/
public function getLeadsWithFilters($filters = [], $limit = 10, $offset = 0)
{
- $builder = $this->select('sales_actual_leads.*, user_profiles.first_name as assigned_to_name')
+ $this->select('sales_actual_leads.*, user_profiles.first_name as assigned_to_name, user_profiles.email as assigned_to_email')
->join('user_profiles', 'user_profiles.id = sales_actual_leads.assigned_to', 'left');
if (!empty($filters['status'])) {
- $builder->where('sales_actual_leads.status', $filters['status']);
+ $this->where('sales_actual_leads.status', $filters['status']);
}
+ // if (!empty($filters['assigned_to'])) {
+ // $this->where('sales_actual_leads.assigned_to', $filters['assigned_to']);
+ // }
if (!empty($filters['assigned_to'])) {
- $builder->where('sales_actual_leads.assigned_to', $filters['assigned_to']);
+ $assigned_to = $filters['assigned_to'];
+
+ // If it's already an array, use it. If it's a string, explode it into an array.
+ $assignedToIds = is_array($assigned_to) ? $assigned_to : explode(',', $assigned_to);
+
+ // Now it is guaranteed to be an array, making whereIn perfectly safe
+ $this->whereIn('sales_actual_leads.assigned_to', $assignedToIds);
}
+ $this->orderBy('sales_actual_leads.created_at', 'DESC');
+
if (!empty($filters['search'])) {
- $builder->groupStart()
+ $this->groupStart()
->like('sales_actual_leads.company_name', $filters['search'])
->orLike('sales_actual_leads.email', $filters['search'])
->orLike('sales_actual_leads.phone', $filters['search'])
+ ->orLike('user_profiles.first_name', $filters['search'])
->groupEnd();
}
- return [
- 'data' => $builder->limit($limit, $offset)->findAll(),
- 'total' => $builder->countAllResults(false)
- ];
+ $total = $this->countAllResults(false);
+
+ $data = $this->findAll($limit, $offset);
+
+ return ['data' => $data,'total' => $total];
}
/**
@@ -113,9 +140,11 @@ class SalesActualLeadModel extends Model
$contactModel = new SalesContactPersonModel();
$activityModel = new SalesActivityModel();
$noteModel = new SalesLeadNoteModel();
+ $leadsModel = new LeadsModel();
$lead['contact_persons'] = $contactModel->where('lead_id', $leadId)->findAll();
$lead['activities'] = $activityModel->getActivitiesByLead($leadId);
+ $lead['opportunities'] = $leadsModel->where('actual_lead_id', $leadId)->findAll();
$lead['notes'] = $noteModel->getNotesByLead($leadId);
return $lead;
diff --git a/app/Models/TPAModel.php b/app/Models/TPAModel.php
index fe3f30cd..679cae2a 100755
--- a/app/Models/TPAModel.php
+++ b/app/Models/TPAModel.php
@@ -19,5 +19,6 @@ class TPAModel extends Model
"created_by",
"updated_by",
"is_active",
+ "dashboard_id",
];
}
diff --git a/app/Views/layout/header.php b/app/Views/layout/header.php
index 57aff2c2..61e63b23 100755
--- a/app/Views/layout/header.php
+++ b/app/Views/layout/header.php
@@ -2077,6 +2077,37 @@
+
+
+
+ /assets/images/sales_tracker_dark_sb.png" alt="Logo" height="20">
+ Sales Tracker
+
+
+
+
diff --git a/app/Views/leads_form.php b/app/Views/leads_form.php
index ef30ba59..87868d39 100644
--- a/app/Views/leads_form.php
+++ b/app/Views/leads_form.php
@@ -131,6 +131,8 @@
enctype="multipart/form-data">
+
+
@@ -741,6 +743,7 @@
$('#page_title').text(page_title);
$('#leads_primarykey').val(res.data.id);
+ $('#actual_lead_id').val(res.data.actual_lead_id || 0);
$('#policy_start_date').val(res.data.policy_end_date);
$('#lead_type').val(res.data.lead_type);
$('#issuer').val(res.data.issuer);
diff --git a/app/Views/leads_form_handler.php b/app/Views/leads_form_handler.php
index 6677520d..01960410 100644
--- a/app/Views/leads_form_handler.php
+++ b/app/Views/leads_form_handler.php
@@ -956,6 +956,7 @@ if (isset($selected_lead_type)) {
$('#page_title').text('Edit Lead');
$('#leads_primarykey').val(data.id || '');
+ $('#actual_lead_id').val(data.actual_lead_id || 0);
$('#policy_start_date').val(data.policy_end_date || '');
$('#lead_type').val(data.lead_type || '');
$('#issuer').val(data.issuer || '');
@@ -1130,6 +1131,7 @@ if (isset($selected_lead_type)) {
$('#page_title').text('Edit Lead');
$('#leads_primarykey').val(data.id || '');
+ $('#actual_lead_id').val(data.actual_lead_id || 0);
$('#policy_start_date').val(data.policy_end_date || '');
$('#lead_type').val(data.lead_type || '');
$('#issuer').val(data.issuer || '');
diff --git a/app/Views/leads_list.php b/app/Views/leads_list.php
index 896a1117..98b9f232 100644
--- a/app/Views/leads_list.php
+++ b/app/Views/leads_list.php
@@ -533,8 +533,11 @@ table.dataTable tbody td {
console.log('lead_id', lead_id);
console.log('lead_form_type', lead_form_type);
-
- let url = '=base_url('/util/getLeadNonEB/')?>' + lead_form_type + '/' + lead_id
+ let actual_lead_id = 0; // Hardcoded to 0 since this is an edit operation
+ //Here After Edit URL: /type / actual_lead_id (0) / lead_id
+ let url = '=base_url('/util/getLeadNonEB/')?>' + lead_form_type + '/' + actual_lead_id + '/' + lead_id;
+ // old URL
+ // let url = '=base_url('/util/getLeadNonEB/')?>' + lead_form_type + '/' + lead_id
console.log('url ', url)
window.location.href = url;
diff --git a/app/Views/leads_non_eb.php b/app/Views/leads_non_eb.php
index 6456935a..6d2049f0 100644
--- a/app/Views/leads_non_eb.php
+++ b/app/Views/leads_non_eb.php
@@ -74,6 +74,7 @@
+
diff --git a/app/Views/policy_transaction_endorsement_form.php b/app/Views/policy_transaction_endorsement_form.php
index 4b4ab0ba..0c9c579b 100644
--- a/app/Views/policy_transaction_endorsement_form.php
+++ b/app/Views/policy_transaction_endorsement_form.php
@@ -621,7 +621,7 @@
console.log('Business Team Logged in.');
}
- getURLParamsForReport()
+ // getURLParamsForReport()
})
$(document).ready(function(){
@@ -1086,10 +1086,10 @@
if(res.data.client_type == 2){
let data1 = policyListByClient[res.data.client_id];
- appendPolicies(data1, res.pt_id);
+ appendPolicies(data1, res.data.client_policy_id);
}else{
let data2 = policy_list[res.data.client_branch_id];
- appendPolicies(data2, res.pt_id);
+ appendPolicies(data2, res.data.client_policy_id);
}
setTimeout(function(){
@@ -2957,9 +2957,9 @@
if (pt_id != 0) {
hide_list_show_add();
- setTimeout(() =>
- getPolicyTransactionDataForEndorsementEdit(pt_id),
- 1500); // Reduced timeout
+ // setTimeout(() =>
+ getPolicyTransactionDataForEndorsementEdit(pt_id)
+ // 1500); // Reduced timeout
} else {
show_list_hide_add();
}
diff --git a/app/Views/policy_transaction_endorsement_list.php b/app/Views/policy_transaction_endorsement_list.php
index 0365496b..eed97902 100644
--- a/app/Views/policy_transaction_endorsement_list.php
+++ b/app/Views/policy_transaction_endorsement_list.php
@@ -460,7 +460,11 @@ table.dataTable thead th {
// select2 document ready
$(document).ready(function() {
- getClientAndBranchAndPolicy()
+ // getClientAndBranchAndPolicy()
+ getClientAndBranchAndPolicy(function() {
+ getURLParamsForReport();
+ });
+
addHTMLInput();
has('create_failed')) : ?>
@@ -632,7 +636,7 @@ table.dataTable thead th {
}
- function getClientAndBranchAndPolicy() {
+ function getClientAndBranchAndPolicy(callback) {
$.ajax({
url: '= base_url("/util/getClientAndBranchAndPolicy") ?>',
type: "GET",
@@ -652,6 +656,11 @@ table.dataTable thead th {
console.log('No data found');
}
+ // ✅ Data ellam set aanadhuku aparam callback call panrom
+ if (typeof callback === "function") {
+ callback();
+ }
+
},
error: function(xhr, status, error) {
console.error(xhr.responseText);
diff --git a/app/Views/sales/activity_view.php b/app/Views/sales/activity_view.php
new file mode 100644
index 00000000..4c5f939b
--- /dev/null
+++ b/app/Views/sales/activity_view.php
@@ -0,0 +1,1744 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Activities
+ Opportunities
+
+
+
+
+
Activity TimeLine
+ + Add Activity
+
+
+
+
+
+
+
Opportunity
+ + Add Opportunity
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Outcome / Notes *
+
+
+
+ Next Follow-up? *
+
+ No
+ Yes
+
+
+
+
Next Activity Type *
+
+
+ 📞 Call
+ ✉️ Email
+ 📅 Meeting
+ 🚗 Visit
+ 🎬 Demo
+ 📄 Share Docs
+ ✓ To Do
+
+
+
+
+ Follow-up Notes *
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/Views/sales/sales_manager_level_dashboard.php b/app/Views/sales/sales_manager_level_dashboard.php
index 5b75fc42..e103759c 100644
--- a/app/Views/sales/sales_manager_level_dashboard.php
+++ b/app/Views/sales/sales_manager_level_dashboard.php
@@ -1,5 +1,5 @@
-
-
-
@@ -119,23 +225,42 @@
+
-
-
-
-
-
+
-
-
Activity Timeline
-
+ Add Activity
+
+
Activities
+ Opportunities
-
+
+
+
+
Activity TimeLine
+ + Add Activity
+
+
+
+
+
+
+
Opportunity
+ + Add Opportunity
+
+
+
+
@@ -144,82 +269,407 @@
-
+
+
+
+
Activity Type
📞 Call
✉️ Email
📅 Meeting
+ 🚗 Visit
🎬 Demo
📄 Share Docs
✓ To Do
- Notes
+ Notes *
-
- Create Activity
-
+
+
-
+
-
+
+
+
+
+
- Outcome Notes
-
+ Outcome / Notes *
+
- Next Follow-up?
-
+ Next Follow-up? *
+
No
Yes
+
Next Activity Type *
+
+
+ 📞 Call
+ ✉️ Email
+ 📅 Meeting
+ 🚗 Visit
+ 🎬 Demo
+ 📄 Share Docs
+ ✓ To Do
+
+
+
- Date
-
+ Follow-up Notes *
+
+
+
-
Submit Outcome
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/assets/images/sales_tracker_dark_sb.png b/public/assets/images/sales_tracker_dark_sb.png
new file mode 100644
index 00000000..c38dd31f
Binary files /dev/null and b/public/assets/images/sales_tracker_dark_sb.png differ