FIX_SalesTracker

This commit is contained in:
sanjeev.p 2026-02-25 15:01:32 +05:30
parent 0540cd6585
commit 745a6b6049
14 changed files with 3579 additions and 200 deletions

View File

@ -418,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');
@ -912,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');

View File

@ -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

View File

@ -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) {

View File

@ -10,6 +10,7 @@ class LeadsModel extends Model
protected $primaryKey = 'id';
protected $allowedFields = [
'id',
'actual_lead_id',
'lead_type',
'issuer',
'client_type',

View File

@ -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)

View File

@ -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;

View File

@ -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">

View File

@ -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);

View File

@ -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 || '');

View File

@ -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;

View File

@ -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">

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB