MERGE_UAT_METABASE_TPA_DASHBOARD
This commit is contained in:
commit
b58fa2ef06
@ -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],
|
||||
|
||||
@ -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',
|
||||
|
||||
@ -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');
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 '<div class="col-12">
|
||||
<div class="card text-center">
|
||||
<div class="card-body">
|
||||
<h3>Oops! ' . esc($page_type) . ' is under construction.</h3>
|
||||
<img src="https://omjsblog.files.wordpress.com/2023/07/errorimg.png" alt="Error Image" style="max-width: 100%; height: auto;">
|
||||
</div>
|
||||
</div>
|
||||
</div>';
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -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',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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()];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@ -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([
|
||||
|
||||
@ -10,6 +10,7 @@ class LeadsModel extends Model
|
||||
protected $primaryKey = 'id';
|
||||
protected $allowedFields = [
|
||||
'id',
|
||||
'actual_lead_id',
|
||||
'lead_type',
|
||||
'issuer',
|
||||
'client_type',
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -19,5 +19,6 @@ class TPAModel extends Model
|
||||
"created_by",
|
||||
"updated_by",
|
||||
"is_active",
|
||||
"dashboard_id",
|
||||
];
|
||||
}
|
||||
|
||||
@ -2077,6 +2077,37 @@
|
||||
</a>
|
||||
</li>
|
||||
<?php } ?>
|
||||
<?php if (in_array(get_role_id(), [1, 2, 3, 5])) { ?>
|
||||
<li class="li-seperate" id="app-sales-tracker-li">
|
||||
<a id="app_sales_tracker" href="#sidebarSalesTrackermenu" data-toggle="collapse" class="waves-effect img-inactive" style="color: grey;">
|
||||
<img
|
||||
src="<?= base_url() . "public"; ?>/assets/images/sales_tracker_dark_sb.png" alt="Logo" height="20">
|
||||
<span style="color: #02a8b5;">Sales Tracker</span>
|
||||
</a>
|
||||
<div class="collapse" id="sidebarSalesTrackermenu">
|
||||
<ul class="nav-second-level">
|
||||
<li>
|
||||
<a href="<?= base_url('/sales/page/Dashboard') ?>"> <i class="ri-dashboard-line"></i> Dashboard </a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="<?= base_url('/sales') ?>"> <i class="ri-group-line"></i> Leads </a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="<?= base_url('/sales/activities') ?>"><i class="ri-flashlight-line"></i> Activities </a>
|
||||
</li>
|
||||
<!-- <li>
|
||||
<a href="<?= base_url('/sales/page/Opportunities') ?>"> <i class="ri-checkbox-circle-line"></i> Opportunities </a>
|
||||
</li> -->
|
||||
<!-- <li>
|
||||
<a href="<?= base_url('sales/page/Reports') ?>"><i class="ri-bar-chart-line"></i> Reports </a>
|
||||
</li> -->
|
||||
<!-- <li>
|
||||
<a href="<?= base_url('sales/page/Team') ?>"><i class="ri-bar-chart-line"></i> Sales Team </a>
|
||||
</li> -->
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
<?php } ?>
|
||||
<!-- Tickets -->
|
||||
<?php if (in_array(get_role_id(), [1, 2, 3, 4, 5]) || in_array(CLAIMS_TEAM_ID, user_team())) { ?>
|
||||
<li class="li-seperate" id="tickets-li">
|
||||
|
||||
@ -131,6 +131,8 @@
|
||||
enctype="multipart/form-data">
|
||||
|
||||
<input type="hidden" name="id" id="leads_primarykey">
|
||||
<input type="hidden" name="actual_lead_id" id="actual_lead_id" value="<?= isset($actual_lead_id) ? $actual_lead_id : 0 ?>">
|
||||
|
||||
|
||||
<div class="card" id="collapseOne">
|
||||
<div class="card-body">
|
||||
@ -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);
|
||||
|
||||
@ -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 || '');
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -74,6 +74,7 @@
|
||||
|
||||
<input type="hidden" name="id" id="leads_primarykey">
|
||||
<input type="hidden" name="lead_form_type" id="lead_form_type_id" value="2">
|
||||
<input type="hidden" name="actual_lead_id" id="actual_lead_id" value="<?= isset($actual_lead_id) ? $actual_lead_id : 0 ?>">
|
||||
|
||||
<div class="card" id="collapseOne">
|
||||
<div class="card-body">
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
@ -460,7 +460,11 @@ table.dataTable thead th {
|
||||
// select2 document ready
|
||||
$(document).ready(function() {
|
||||
|
||||
getClientAndBranchAndPolicy()
|
||||
// getClientAndBranchAndPolicy()
|
||||
getClientAndBranchAndPolicy(function() {
|
||||
getURLParamsForReport();
|
||||
});
|
||||
|
||||
addHTMLInput();
|
||||
|
||||
<?php if (session()->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);
|
||||
|
||||
1744
app/Views/sales/activity_view.php
Normal file
1744
app/Views/sales/activity_view.php
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
||||
<style>
|
||||
.my-dash { padding: 25px; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background: #fff; }
|
||||
.my-dash { padding: 25px; margin-top: -21px; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background: #fff; }
|
||||
.target-card { background: #1e252b; color: white; padding: 30px; border-radius: 15px; position: relative; margin-bottom: 30px; }
|
||||
.target-amount { font-size: 32px; font-weight: bold; margin: 10px 0; }
|
||||
.progress-container { background: #333; height: 8px; border-radius: 4px; margin: 20px 0; overflow: hidden; position: relative; }
|
||||
@ -10,7 +10,7 @@
|
||||
.stat-box .num { font-size: 20px; font-weight: bold; display: block; margin-bottom: 2px; }
|
||||
.stat-box .lbl { font-size: 11px; color: #999; }
|
||||
|
||||
.chart-circle { position: absolute; right: 40px; top: 35px; width: 75px; height: 75px; border: 6px solid #333; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: bold; font-size: 18px; border-top-color: #ff6b35; }
|
||||
/* .chart-circle { position: absolute; right: 40px; top: 35px; width: 75px; height: 75px; border: 6px solid #333; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: bold; font-size: 18px; border-top-color: #ff6b35; } */
|
||||
|
||||
.dashboard-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 25px; }
|
||||
.list-card { border: 1px solid #f0f0f0; border-radius: 12px; padding: 25px; background: #fff; }
|
||||
@ -24,26 +24,39 @@
|
||||
<div class="my-dash">
|
||||
<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:25px;">
|
||||
<div>
|
||||
<h1 style="font-size:22px; margin:0; font-weight: 700;">My Dashboard</h1>
|
||||
<p style="color:#666; font-size:13px; margin-top: 4px;">Welcome back, <?= $user_name ?></p>
|
||||
<!-- <h1 style="font-size:22px; margin:0; font-weight: 700;">My Dashboard</h1>
|
||||
<p style="color:#666; font-size:13px; margin-top: 4px;">Welcome back, <?= $user_name ?></p> -->
|
||||
</div>
|
||||
<div style="position: relative;">
|
||||
<input type="text" placeholder="Search leads, activities..." style="background:#f5f5f5; padding:10px 20px; border-radius:8px; border:none; width: 250px; font-size: 13px;">
|
||||
<select id="financial_year" name="financial_year" onchange="onFinancialYearChange(this)" style="background:#f5f5f5; padding:10px 20px; border-radius:8px; border:none; width: 250px; font-size: 13px; cursor: pointer;">
|
||||
<?php if(!empty($fin_years)): ?>
|
||||
<?php foreach($fin_years as $year): ?>
|
||||
<option value="<?= $year; ?>"><?= $year; ?></option>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="target-card">
|
||||
<div style="font-size:11px; color:#999; letter-spacing: 1px; font-weight: 600;">YEARLY TARGET 2025</div>
|
||||
<div style="font-size:11px; color:#999; letter-spacing: 1px; font-weight: 600;">YEARLY TARGET</div>
|
||||
<div class="target-amount">₹<?= number_format($target / 100000, 1) ?>L</div>
|
||||
<div style="font-size:12px; color:#777;">Apr 2025 - Mar 2026</div>
|
||||
<div style="font-size:12px; color:#777;"><?= $display_fin_years ?></div>
|
||||
|
||||
<div class="chart-circle">
|
||||
<span style="color:#ff6b35"><?= $percent ?>%</span>
|
||||
<div class="chart-circle" style="position: absolute; right: 40px; top: 35px; width: 75px; height: 75px;">
|
||||
<svg width="75" height="75" viewBox="0 0 75 75" style="transform: rotate(-90deg);">
|
||||
<circle cx="37.5" cy="37.5" r="30" fill="none" stroke="#333" stroke-width="6"/>
|
||||
<circle cx="37.5" cy="37.5" r="30" fill="none" stroke="#ff6b35" stroke-width="6"
|
||||
stroke-dasharray="<?= round(2 * M_PI * 30 * $percent / 100, 2) ?> 188.5"
|
||||
stroke-linecap="round"/>
|
||||
</svg>
|
||||
<span style="position:absolute; top:50%; left:50%; transform:translate(-50%,-50%); color:#ff6b35; font-weight:bold; font-size:14px;"><?= $percent ?>%</span>
|
||||
</div>
|
||||
|
||||
<div class="progress-container">
|
||||
<div class="progress-bar" style="width: <?= $percent ?>%"></div>
|
||||
</div>
|
||||
|
||||
<div style="display:flex; justify-content:space-between; font-size:12px; color: #999;">
|
||||
<span>Achieved <strong style="color:white">₹<?= number_format($achieved / 100000, 1) ?>L</strong></span>
|
||||
<span>Remaining <strong style="color:white">₹<?= number_format($remaining / 100000, 1) ?>L</strong></span>
|
||||
@ -69,7 +82,7 @@
|
||||
<div style="font-weight:600; font-size:14px; color: #333;"><?= $u['company_name'] ?></div>
|
||||
<div style="font-size:11px; color:#999; margin-top: 3px;"><?= strtoupper($u['activity_type'] ?? 'EMAIL') ?> - <?= date('d Mar Y', strtotime($u['scheduled_date'])) ?></div>
|
||||
</div>
|
||||
<button class="badge-done">✓ Done</button>
|
||||
<button class="badge-done">✓ Mark as completed</button>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
@ -90,4 +103,22 @@
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const fy = params.get('fy');
|
||||
if (fy) {
|
||||
document.getElementById('financial_year').value = fy;
|
||||
}
|
||||
});
|
||||
|
||||
function onFinancialYearChange(select) {
|
||||
const url = new URL(window.location.href);
|
||||
url.searchParams.set('fy', select.value);
|
||||
window.location.href = url.toString();
|
||||
}
|
||||
|
||||
</script>
|
||||
File diff suppressed because it is too large
Load Diff
BIN
public/assets/images/sales_tracker_dark_sb.png
Normal file
BIN
public/assets/images/sales_tracker_dark_sb.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
Loading…
Reference in New Issue
Block a user