Sales tracker Database and basic files created : GWM
This commit is contained in:
parent
0f9aa3fe93
commit
794a63bd6c
@ -776,7 +776,7 @@ $routes->get('testTracelog','TestBusinessController::a');
|
||||
$routes->get("claimView", "EmployeeRestController::claimView");
|
||||
|
||||
// General Tickets
|
||||
$routes->post("ticketSave", "ThzController::ticketSave");
|
||||
$routes->post("ticketSave", "ThzController::ticketSave"); //
|
||||
$routes->get("ticketList", "ThzController::ticketList");
|
||||
$routes->post("ticketConversationSave", "ThzController::ticketConversationSave");
|
||||
$routes->get("ticketConversationList", "ThzController::ticketConversationList");
|
||||
@ -852,3 +852,89 @@ $routes->group('logs', function($routes) {
|
||||
$routes->get('delete/(:segment)', 'LogController::delete/$1');
|
||||
$routes->get('clearAll', 'LogController::clearAll');
|
||||
});
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
$routes->group('sales', function($routes) {
|
||||
|
||||
// ==================== LEAD ROUTES ====================
|
||||
|
||||
// Get all leads with filters
|
||||
$routes->get('leads', 'SalesController::getLeads');
|
||||
|
||||
// Get lead statistics
|
||||
$routes->get('leads/stats', 'SalesController::getLeadStats');
|
||||
|
||||
// Get single lead with complete details
|
||||
$routes->get('leads/(:num)', 'SalesController::getLead/$1');
|
||||
|
||||
// Create new lead
|
||||
$routes->post('leads', 'SalesController::createLead');
|
||||
|
||||
// Update lead
|
||||
$routes->put('leads/(:num)', 'SalesController::updateLead/$1');
|
||||
|
||||
// Delete lead
|
||||
$routes->delete('leads/(:num)', 'SalesController::deleteLead/$1');
|
||||
|
||||
// Get contacts for a lead
|
||||
$routes->get('leads/(:num)/contacts', 'SalesController::getContacts/$1');
|
||||
|
||||
// Get activities for a lead
|
||||
$routes->get('leads/(:num)/activities', 'SalesController::getLeadActivities/$1');
|
||||
|
||||
// Get activity timeline for a lead
|
||||
$routes->get('leads/(:num)/timeline', 'SalesController::getActivityTimeline/$1');
|
||||
|
||||
// Get notes for a lead
|
||||
$routes->get('leads/(:num)/notes', 'SalesController::getLeadNotes/$1');
|
||||
|
||||
// ==================== CONTACT PERSON ROUTES ====================
|
||||
|
||||
// Create contact person
|
||||
$routes->post('contacts', 'SalesController::createContact');
|
||||
|
||||
// Update contact person
|
||||
$routes->put('contacts/(:num)', 'SalesController::updateContact/$1');
|
||||
|
||||
// Delete contact person
|
||||
$routes->delete('contacts/(:num)', 'SalesController::deleteContact/$1');
|
||||
|
||||
// Set primary contact
|
||||
$routes->put('contacts/(:num)/set-primary', 'SalesController::setPrimaryContact/$1');
|
||||
|
||||
// ==================== ACTIVITY ROUTES ====================
|
||||
|
||||
// Get all activities with filters
|
||||
$routes->get('activities', 'SalesController::getActivities');
|
||||
|
||||
// Get upcoming activities
|
||||
$routes->get('activities/upcoming', 'SalesController::getUpcomingActivities');
|
||||
|
||||
// Get pending activities count
|
||||
$routes->get('activities/pending-count', 'SalesController::getPendingCount');
|
||||
|
||||
// Create activity
|
||||
$routes->post('activities', 'SalesController::createActivity');
|
||||
|
||||
// Update activity
|
||||
$routes->put('activities/(:num)', 'SalesController::updateActivity/$1');
|
||||
|
||||
// Complete activity
|
||||
$routes->post('activities/(:num)/complete', 'SalesController::completeActivity/$1');
|
||||
|
||||
// Delete activity
|
||||
$routes->delete('activities/(:num)', 'SalesController::deleteActivity/$1');
|
||||
|
||||
// ==================== NOTE ROUTES ====================
|
||||
|
||||
// Create note
|
||||
$routes->post('notes', 'SalesController::createNote');
|
||||
|
||||
// Update note
|
||||
$routes->put('notes/(:num)', 'SalesController::updateNote/$1');
|
||||
|
||||
// Delete note
|
||||
$routes->delete('notes/(:num)', 'SalesController::deleteNote/$1');
|
||||
});
|
||||
|
||||
|
||||
|
||||
695
app/Controllers/SalesController.php
Normal file
695
app/Controllers/SalesController.php
Normal file
@ -0,0 +1,695 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers\Api;
|
||||
|
||||
use App\Controllers\BaseController;
|
||||
use App\Models\SalesActualLeadModel;
|
||||
use App\Models\SalesContactPersonModel;
|
||||
use App\Models\SalesActivityModel;
|
||||
use App\Models\SalesLeadNoteModel;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use CodeIgniter\API\ResponseTrait;
|
||||
|
||||
class SalesController extends BaseController
|
||||
{
|
||||
use ResponseTrait;
|
||||
|
||||
protected $leadModel;
|
||||
protected $contactModel;
|
||||
protected $activityModel;
|
||||
protected $noteModel;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->leadModel = new SalesActualLeadModel();
|
||||
$this->contactModel = new SalesContactPersonModel();
|
||||
$this->activityModel = new SalesActivityModel();
|
||||
$this->noteModel = new SalesLeadNoteModel();
|
||||
}
|
||||
|
||||
// ==================== LEAD APIs ====================
|
||||
|
||||
/**
|
||||
* Get all leads with pagination and filters
|
||||
* GET /api/sales/leads
|
||||
*/
|
||||
public function getLeads()
|
||||
{
|
||||
try {
|
||||
$limit = $this->request->getGet('limit') ?? 10;
|
||||
$offset = $this->request->getGet('offset') ?? 0;
|
||||
|
||||
$filters = [
|
||||
'status' => $this->request->getGet('status'),
|
||||
'assigned_to' => $this->request->getGet('assigned_to'),
|
||||
'search' => $this->request->getGet('search'),
|
||||
];
|
||||
|
||||
$result = $this->leadModel->getLeadsWithFilters($filters, $limit, $offset);
|
||||
|
||||
return $this->respond([
|
||||
'status' => 'success',
|
||||
'data' => $result['data'],
|
||||
'total' => $result['total'],
|
||||
'limit' => $limit,
|
||||
'offset' => $offset
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->fail($e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get single lead with complete details
|
||||
* GET /api/sales/leads/{id}
|
||||
*/
|
||||
public function getLead($id)
|
||||
{
|
||||
try {
|
||||
$lead = $this->leadModel->getLeadComplete($id);
|
||||
|
||||
if (!$lead) {
|
||||
return $this->failNotFound('Lead not found');
|
||||
}
|
||||
|
||||
return $this->respond([
|
||||
'status' => 'success',
|
||||
'data' => $lead
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->fail($e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new lead
|
||||
* POST /api/sales/leads
|
||||
*/
|
||||
public function createLead()
|
||||
{
|
||||
try {
|
||||
$data = $this->request->getJSON(true);
|
||||
|
||||
// Set created_by and updated_by from authenticated user
|
||||
$data['created_by'] = $this->getUserId();
|
||||
$data['updated_by'] = $this->getUserId();
|
||||
|
||||
if (!$this->leadModel->insert($data)) {
|
||||
return $this->fail($this->leadModel->errors(), ResponseInterface::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$leadId = $this->leadModel->getInsertID();
|
||||
|
||||
// Insert contact persons if provided
|
||||
if (!empty($data['contact_persons'])) {
|
||||
foreach ($data['contact_persons'] as $contact) {
|
||||
$contact['lead_id'] = $leadId;
|
||||
$contact['created_by'] = $this->getUserId();
|
||||
$this->contactModel->insert($contact);
|
||||
}
|
||||
}
|
||||
|
||||
$lead = $this->leadModel->getLeadComplete($leadId);
|
||||
|
||||
return $this->respondCreated([
|
||||
'status' => 'success',
|
||||
'message' => 'Lead created successfully',
|
||||
'data' => $lead
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->fail($e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update lead
|
||||
* PUT /api/sales/leads/{id}
|
||||
*/
|
||||
public function updateLead($id)
|
||||
{
|
||||
try {
|
||||
if (!$this->leadModel->find($id)) {
|
||||
return $this->failNotFound('Lead not found');
|
||||
}
|
||||
|
||||
$data = $this->request->getJSON(true);
|
||||
$data['updated_by'] = $this->getUserId();
|
||||
|
||||
if (!$this->leadModel->update($id, $data)) {
|
||||
return $this->fail($this->leadModel->errors(), ResponseInterface::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$lead = $this->leadModel->getLeadComplete($id);
|
||||
|
||||
return $this->respond([
|
||||
'status' => 'success',
|
||||
'message' => 'Lead updated successfully',
|
||||
'data' => $lead
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->fail($e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete lead
|
||||
* DELETE /api/sales/leads/{id}
|
||||
*/
|
||||
public function deleteLead($id)
|
||||
{
|
||||
try {
|
||||
if (!$this->leadModel->find($id)) {
|
||||
return $this->failNotFound('Lead not found');
|
||||
}
|
||||
|
||||
$this->leadModel->delete($id);
|
||||
|
||||
return $this->respondDeleted([
|
||||
'status' => 'success',
|
||||
'message' => 'Lead deleted successfully'
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->fail($e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get lead statistics
|
||||
* GET /api/sales/leads/stats
|
||||
*/
|
||||
public function getLeadStats()
|
||||
{
|
||||
try {
|
||||
$userId = $this->request->getGet('user_id');
|
||||
$stats = $this->leadModel->getLeadStats($userId);
|
||||
|
||||
return $this->respond([
|
||||
'status' => 'success',
|
||||
'data' => $stats
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->fail($e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== CONTACT PERSON APIs ====================
|
||||
|
||||
/**
|
||||
* Get contacts for a lead
|
||||
* GET /api/sales/leads/{leadId}/contacts
|
||||
*/
|
||||
public function getContacts($leadId)
|
||||
{
|
||||
try {
|
||||
$contacts = $this->contactModel->getContactsByLead($leadId);
|
||||
|
||||
return $this->respond([
|
||||
'status' => 'success',
|
||||
'data' => $contacts
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->fail($e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create contact person
|
||||
* POST /api/sales/contacts
|
||||
*/
|
||||
public function createContact()
|
||||
{
|
||||
try {
|
||||
$data = $this->request->getJSON(true);
|
||||
$data['created_by'] = $this->getUserId();
|
||||
$data['updated_by'] = $this->getUserId();
|
||||
|
||||
if (!$this->contactModel->insert($data)) {
|
||||
return $this->fail($this->contactModel->errors(), ResponseInterface::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$contactId = $this->contactModel->getInsertID();
|
||||
$contact = $this->contactModel->find($contactId);
|
||||
|
||||
return $this->respondCreated([
|
||||
'status' => 'success',
|
||||
'message' => 'Contact created successfully',
|
||||
'data' => $contact
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->fail($e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update contact person
|
||||
* PUT /api/sales/contacts/{id}
|
||||
*/
|
||||
public function updateContact($id)
|
||||
{
|
||||
try {
|
||||
if (!$this->contactModel->find($id)) {
|
||||
return $this->failNotFound('Contact not found');
|
||||
}
|
||||
|
||||
$data = $this->request->getJSON(true);
|
||||
$data['updated_by'] = $this->getUserId();
|
||||
|
||||
if (!$this->contactModel->update($id, $data)) {
|
||||
return $this->fail($this->contactModel->errors(), ResponseInterface::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$contact = $this->contactModel->find($id);
|
||||
|
||||
return $this->respond([
|
||||
'status' => 'success',
|
||||
'message' => 'Contact updated successfully',
|
||||
'data' => $contact
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->fail($e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete contact person
|
||||
* DELETE /api/sales/contacts/{id}
|
||||
*/
|
||||
public function deleteContact($id)
|
||||
{
|
||||
try {
|
||||
if (!$this->contactModel->find($id)) {
|
||||
return $this->failNotFound('Contact not found');
|
||||
}
|
||||
|
||||
$this->contactModel->delete($id);
|
||||
|
||||
return $this->respondDeleted([
|
||||
'status' => 'success',
|
||||
'message' => 'Contact deleted successfully'
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->fail($e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set primary contact
|
||||
* PUT /api/sales/contacts/{id}/set-primary
|
||||
*/
|
||||
public function setPrimaryContact($id)
|
||||
{
|
||||
try {
|
||||
$contact = $this->contactModel->find($id);
|
||||
|
||||
if (!$contact) {
|
||||
return $this->failNotFound('Contact not found');
|
||||
}
|
||||
|
||||
$this->contactModel->setPrimaryContact($id, $contact['lead_id']);
|
||||
|
||||
return $this->respond([
|
||||
'status' => 'success',
|
||||
'message' => 'Primary contact updated successfully'
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->fail($e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== ACTIVITY APIs ====================
|
||||
|
||||
/**
|
||||
* Get all activities with filters
|
||||
* GET /api/sales/activities
|
||||
*/
|
||||
public function getActivities()
|
||||
{
|
||||
try {
|
||||
$limit = $this->request->getGet('limit') ?? 10;
|
||||
$offset = $this->request->getGet('offset') ?? 0;
|
||||
|
||||
$filters = [
|
||||
'status' => $this->request->getGet('status'),
|
||||
'activity_type' => $this->request->getGet('activity_type'),
|
||||
'assigned_to' => $this->request->getGet('assigned_to'),
|
||||
'date_from' => $this->request->getGet('date_from'),
|
||||
'date_to' => $this->request->getGet('date_to'),
|
||||
];
|
||||
|
||||
$result = $this->activityModel->getActivitiesWithFilters($filters, $limit, $offset);
|
||||
|
||||
return $this->respond([
|
||||
'status' => 'success',
|
||||
'data' => $result['data'],
|
||||
'total' => $result['total'],
|
||||
'limit' => $limit,
|
||||
'offset' => $offset
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->fail($e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get activities for a specific lead
|
||||
* GET /api/sales/leads/{leadId}/activities
|
||||
*/
|
||||
public function getLeadActivities($leadId)
|
||||
{
|
||||
try {
|
||||
$status = $this->request->getGet('status');
|
||||
$activities = $this->activityModel->getActivitiesByLead($leadId, $status);
|
||||
|
||||
return $this->respond([
|
||||
'status' => 'success',
|
||||
'data' => $activities
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->fail($e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get activity timeline for a lead
|
||||
* GET /api/sales/leads/{leadId}/timeline
|
||||
*/
|
||||
public function getActivityTimeline($leadId)
|
||||
{
|
||||
try {
|
||||
$timeline = $this->activityModel->getActivityTimeline($leadId);
|
||||
|
||||
return $this->respond([
|
||||
'status' => 'success',
|
||||
'data' => $timeline
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->fail($e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get upcoming activities for user
|
||||
* GET /api/sales/activities/upcoming
|
||||
*/
|
||||
public function getUpcomingActivities()
|
||||
{
|
||||
try {
|
||||
$userId = $this->getUserId();
|
||||
$days = $this->request->getGet('days') ?? 7;
|
||||
$limit = $this->request->getGet('limit') ?? 10;
|
||||
|
||||
$activities = $this->activityModel->getUpcomingActivities($userId, $days, $limit);
|
||||
|
||||
return $this->respond([
|
||||
'status' => 'success',
|
||||
'data' => $activities
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->fail($e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create activity
|
||||
* POST /api/sales/activities
|
||||
*/
|
||||
public function createActivity()
|
||||
{
|
||||
try {
|
||||
$data = $this->request->getJSON(true);
|
||||
$data['created_by'] = $this->getUserId();
|
||||
$data['updated_by'] = $this->getUserId();
|
||||
|
||||
if (!$this->activityModel->insert($data)) {
|
||||
return $this->fail($this->activityModel->errors(), ResponseInterface::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$activityId = $this->activityModel->getInsertID();
|
||||
$activity = $this->activityModel->find($activityId);
|
||||
|
||||
return $this->respondCreated([
|
||||
'status' => 'success',
|
||||
'message' => 'Activity created successfully',
|
||||
'data' => $activity
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->fail($e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update activity
|
||||
* PUT /api/sales/activities/{id}
|
||||
*/
|
||||
public function updateActivity($id)
|
||||
{
|
||||
try {
|
||||
if (!$this->activityModel->find($id)) {
|
||||
return $this->failNotFound('Activity not found');
|
||||
}
|
||||
|
||||
$data = $this->request->getJSON(true);
|
||||
$data['updated_by'] = $this->getUserId();
|
||||
|
||||
if (!$this->activityModel->update($id, $data)) {
|
||||
return $this->fail($this->activityModel->errors(), ResponseInterface::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$activity = $this->activityModel->find($id);
|
||||
|
||||
return $this->respond([
|
||||
'status' => 'success',
|
||||
'message' => 'Activity updated successfully',
|
||||
'data' => $activity
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->fail($e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete activity
|
||||
* POST /api/sales/activities/{id}/complete
|
||||
*/
|
||||
public function completeActivity($id)
|
||||
{
|
||||
try {
|
||||
$activity = $this->activityModel->find($id);
|
||||
|
||||
if (!$activity) {
|
||||
return $this->failNotFound('Activity not found');
|
||||
}
|
||||
|
||||
if ($activity['status'] === 'completed') {
|
||||
return $this->fail('Activity is already completed', ResponseInterface::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$data = $this->request->getJSON(true);
|
||||
$data['updated_by'] = $this->getUserId();
|
||||
|
||||
$this->activityModel->completeActivity($id, $data);
|
||||
|
||||
// Create follow-up activity if requested
|
||||
if (!empty($data['create_followup']) && $data['create_followup'] === true) {
|
||||
$followupData = [
|
||||
'lead_id' => $activity['lead_id'],
|
||||
'activity_type' => $data['followup_type'] ?? 'Call',
|
||||
'notes' => $data['followup_notes'] ?? '',
|
||||
'scheduled_date' => $data['followup_date'] ?? null,
|
||||
'assigned_to' => $activity['assigned_to'],
|
||||
'parent_activity_id' => $id,
|
||||
'created_by' => $this->getUserId(),
|
||||
'updated_by' => $this->getUserId(),
|
||||
];
|
||||
|
||||
$this->activityModel->insert($followupData);
|
||||
}
|
||||
|
||||
$updatedActivity = $this->activityModel->find($id);
|
||||
|
||||
return $this->respond([
|
||||
'status' => 'success',
|
||||
'message' => 'Activity completed successfully',
|
||||
'data' => $updatedActivity
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->fail($e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete activity
|
||||
* DELETE /api/sales/activities/{id}
|
||||
*/
|
||||
public function deleteActivity($id)
|
||||
{
|
||||
try {
|
||||
if (!$this->activityModel->find($id)) {
|
||||
return $this->failNotFound('Activity not found');
|
||||
}
|
||||
|
||||
$this->activityModel->delete($id);
|
||||
|
||||
return $this->respondDeleted([
|
||||
'status' => 'success',
|
||||
'message' => 'Activity deleted successfully'
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->fail($e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get pending activities count
|
||||
* GET /api/sales/activities/pending-count
|
||||
*/
|
||||
public function getPendingCount()
|
||||
{
|
||||
try {
|
||||
$userId = $this->getUserId();
|
||||
$count = $this->activityModel->getPendingActivitiesCount($userId);
|
||||
|
||||
return $this->respond([
|
||||
'status' => 'success',
|
||||
'data' => ['count' => $count]
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->fail($e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== LEAD NOTES APIs ====================
|
||||
|
||||
/**
|
||||
* Get notes for a lead
|
||||
* GET /api/sales/leads/{leadId}/notes
|
||||
*/
|
||||
public function getLeadNotes($leadId)
|
||||
{
|
||||
try {
|
||||
$notes = $this->noteModel->getNotesByLead($leadId);
|
||||
|
||||
return $this->respond([
|
||||
'status' => 'success',
|
||||
'data' => $notes
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->fail($e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create note
|
||||
* POST /api/sales/notes
|
||||
*/
|
||||
public function createNote()
|
||||
{
|
||||
try {
|
||||
$data = $this->request->getJSON(true);
|
||||
$data['user_id'] = $this->getUserId();
|
||||
$data['created_by'] = $this->getUserId();
|
||||
$data['updated_by'] = $this->getUserId();
|
||||
|
||||
if (!$this->noteModel->insert($data)) {
|
||||
return $this->fail($this->noteModel->errors(), ResponseInterface::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$noteId = $this->noteModel->getInsertID();
|
||||
$note = $this->noteModel->find($noteId);
|
||||
|
||||
return $this->respondCreated([
|
||||
'status' => 'success',
|
||||
'message' => 'Note created successfully',
|
||||
'data' => $note
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->fail($e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update note
|
||||
* PUT /api/sales/notes/{id}
|
||||
*/
|
||||
public function updateNote($id)
|
||||
{
|
||||
try {
|
||||
$note = $this->noteModel->find($id);
|
||||
|
||||
if (!$note) {
|
||||
return $this->failNotFound('Note not found');
|
||||
}
|
||||
|
||||
// Check if user owns the note
|
||||
if ($note['user_id'] != $this->getUserId()) {
|
||||
return $this->failUnauthorized('You are not authorized to update this note');
|
||||
}
|
||||
|
||||
$data = $this->request->getJSON(true);
|
||||
$data['updated_by'] = $this->getUserId();
|
||||
|
||||
if (!$this->noteModel->update($id, $data)) {
|
||||
return $this->fail($this->noteModel->errors(), ResponseInterface::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$updatedNote = $this->noteModel->find($id);
|
||||
|
||||
return $this->respond([
|
||||
'status' => 'success',
|
||||
'message' => 'Note updated successfully',
|
||||
'data' => $updatedNote
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->fail($e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete note
|
||||
* DELETE /api/sales/notes/{id}
|
||||
*/
|
||||
public function deleteNote($id)
|
||||
{
|
||||
try {
|
||||
$note = $this->noteModel->find($id);
|
||||
|
||||
if (!$note) {
|
||||
return $this->failNotFound('Note not found');
|
||||
}
|
||||
|
||||
// Check if user owns the note
|
||||
if ($note['user_id'] != $this->getUserId()) {
|
||||
return $this->failUnauthorized('You are not authorized to delete this note');
|
||||
}
|
||||
|
||||
$this->noteModel->delete($id);
|
||||
|
||||
return $this->respondDeleted([
|
||||
'status' => 'success',
|
||||
'message' => 'Note deleted successfully'
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->fail($e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== HELPER METHODS ====================
|
||||
|
||||
/**
|
||||
* Get current user ID from session or JWT token
|
||||
* You'll need to implement this based on your authentication system
|
||||
*/
|
||||
private function getUserId()
|
||||
{
|
||||
// If using session
|
||||
if (session()->has('user_id')) {
|
||||
return session()->get('user_id');
|
||||
}
|
||||
|
||||
// If using JWT, decode token and get user_id
|
||||
// Example: return $this->decodeJWT()['user_id'];
|
||||
|
||||
// For development/testing, you can return a default value
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
166
app/Models/SalesActivityModel.php
Normal file
166
app/Models/SalesActivityModel.php
Normal file
@ -0,0 +1,166 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use CodeIgniter\Model;
|
||||
|
||||
/**
|
||||
* Activity Model
|
||||
*/
|
||||
class SalesActivityModel extends Model
|
||||
{
|
||||
protected $table = 'sales_activities';
|
||||
protected $primaryKey = 'activity_id';
|
||||
protected $useAutoIncrement = true;
|
||||
protected $returnType = 'array';
|
||||
protected $useSoftDeletes = false;
|
||||
protected $protectFields = true;
|
||||
protected $allowedFields = [
|
||||
'lead_id',
|
||||
'activity_type',
|
||||
'notes',
|
||||
'scheduled_date',
|
||||
'assigned_to',
|
||||
'status',
|
||||
'completion_notes',
|
||||
'completed_date',
|
||||
'parent_activity_id',
|
||||
'created_by',
|
||||
'updated_by'
|
||||
];
|
||||
|
||||
// Dates
|
||||
protected $useTimestamps = true;
|
||||
protected $dateFormat = 'datetime';
|
||||
protected $createdField = 'created_at';
|
||||
protected $updatedField = 'updated_at';
|
||||
|
||||
// Validation
|
||||
protected $validationRules = [
|
||||
'lead_id' => 'required|integer',
|
||||
'activity_type' => 'required|in_list[Call,Email,Meeting,Demo,Share,Todo]',
|
||||
'notes' => 'required',
|
||||
'scheduled_date' => 'required|valid_date',
|
||||
'assigned_to' => 'required|integer',
|
||||
'status' => 'in_list[pending,completed]',
|
||||
];
|
||||
|
||||
protected $validationMessages = [
|
||||
'lead_id' => [
|
||||
'required' => 'Lead ID is required',
|
||||
],
|
||||
'activity_type' => [
|
||||
'required' => 'Activity type is required',
|
||||
],
|
||||
'notes' => [
|
||||
'required' => 'Activity notes are required',
|
||||
],
|
||||
];
|
||||
|
||||
protected $skipValidation = false;
|
||||
|
||||
/**
|
||||
* Get activities by lead with user details
|
||||
*/
|
||||
public function getActivitiesByLead($leadId, $status = null)
|
||||
{
|
||||
$builder = $this->select('activities.*, user_profiles.username as assigned_to_name')
|
||||
->join('user_profiles', 'user_profiles.id = activities.assigned_to', 'left')
|
||||
->where('activities.lead_id', $leadId);
|
||||
|
||||
if ($status) {
|
||||
$builder->where('activities.status', $status);
|
||||
}
|
||||
|
||||
return $builder->orderBy('activities.scheduled_date', 'DESC')->findAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all activities with filters
|
||||
*/
|
||||
public function getActivitiesWithFilters($filters = [], $limit = 10, $offset = 0)
|
||||
{
|
||||
$builder = $this->select('activities.*, actual_leads.company_name, user_profiles.username as assigned_to_name')
|
||||
->join('actual_leads', 'actual_leads.lead_id = activities.lead_id', 'left')
|
||||
->join('user_profiles', 'user_profiles.id = activities.assigned_to', 'left');
|
||||
|
||||
if (!empty($filters['status'])) {
|
||||
$builder->where('activities.status', $filters['status']);
|
||||
}
|
||||
|
||||
if (!empty($filters['activity_type'])) {
|
||||
$builder->where('activities.activity_type', $filters['activity_type']);
|
||||
}
|
||||
|
||||
if (!empty($filters['assigned_to'])) {
|
||||
$builder->where('activities.assigned_to', $filters['assigned_to']);
|
||||
}
|
||||
|
||||
if (!empty($filters['date_from'])) {
|
||||
$builder->where('activities.scheduled_date >=', $filters['date_from']);
|
||||
}
|
||||
|
||||
if (!empty($filters['date_to'])) {
|
||||
$builder->where('activities.scheduled_date <=', $filters['date_to']);
|
||||
}
|
||||
|
||||
return [
|
||||
'data' => $builder->orderBy('activities.scheduled_date', 'DESC')
|
||||
->limit($limit, $offset)->findAll(),
|
||||
'total' => $builder->countAllResults(false)
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete an activity
|
||||
*/
|
||||
public function completeActivity($activityId, $completionData)
|
||||
{
|
||||
return $this->update($activityId, [
|
||||
'status' => 'completed',
|
||||
'completion_notes' => $completionData['completion_notes'],
|
||||
'completed_date' => date('Y-m-d H:i:s'),
|
||||
'updated_by' => $completionData['updated_by'] ?? null
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get pending activities count by user
|
||||
*/
|
||||
public function getPendingActivitiesCount($userId)
|
||||
{
|
||||
return $this->where('assigned_to', $userId)
|
||||
->where('status', 'pending')
|
||||
->where('scheduled_date <=', date('Y-m-d H:i:s'))
|
||||
->countAllResults();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get upcoming activities for a user
|
||||
*/
|
||||
public function getUpcomingActivities($userId, $days = 7, $limit = 10)
|
||||
{
|
||||
$endDate = date('Y-m-d H:i:s', strtotime("+{$days} days"));
|
||||
|
||||
return $this->select('activities.*, actual_leads.company_name')
|
||||
->join('actual_leads', 'actual_leads.lead_id = activities.lead_id', 'left')
|
||||
->where('activities.assigned_to', $userId)
|
||||
->where('activities.status', 'pending')
|
||||
->where('activities.scheduled_date <=', $endDate)
|
||||
->orderBy('activities.scheduled_date', 'ASC')
|
||||
->limit($limit)
|
||||
->findAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get activity timeline for a lead
|
||||
*/
|
||||
public function getActivityTimeline($leadId)
|
||||
{
|
||||
return $this->select('activities.*, user_profiles.username as assigned_to_name')
|
||||
->join('user_profiles', 'user_profiles.id = activities.assigned_to', 'left')
|
||||
->where('activities.lead_id', $leadId)
|
||||
->orderBy('activities.scheduled_date', 'DESC')
|
||||
->findAll();
|
||||
}
|
||||
}
|
||||
145
app/Models/SalesActualLeadModel.php
Normal file
145
app/Models/SalesActualLeadModel.php
Normal file
@ -0,0 +1,145 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use CodeIgniter\Model;
|
||||
|
||||
/**
|
||||
* Lead Model
|
||||
* Handles all operations related to actual_leads table
|
||||
*/
|
||||
class SalesActualLeadModel extends Model
|
||||
{
|
||||
protected $table = 'sales_actual_leads';
|
||||
protected $primaryKey = 'lead_id';
|
||||
protected $useAutoIncrement = true;
|
||||
protected $returnType = 'array';
|
||||
protected $useSoftDeletes = false;
|
||||
protected $protectFields = true;
|
||||
protected $allowedFields = [
|
||||
'company_name',
|
||||
'email',
|
||||
'phone',
|
||||
'address',
|
||||
'website',
|
||||
'gst_number',
|
||||
'status',
|
||||
'assigned_to',
|
||||
'created_by',
|
||||
'updated_by'
|
||||
];
|
||||
|
||||
// Dates
|
||||
protected $useTimestamps = true;
|
||||
protected $dateFormat = 'datetime';
|
||||
protected $createdField = 'created_at';
|
||||
protected $updatedField = 'updated_at';
|
||||
|
||||
// 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]',
|
||||
];
|
||||
|
||||
protected $validationMessages = [
|
||||
'company_name' => [
|
||||
'required' => 'Company name is required',
|
||||
],
|
||||
'email' => [
|
||||
'required' => 'Email is required',
|
||||
'valid_email' => 'Please provide a valid email address',
|
||||
],
|
||||
'phone' => [
|
||||
'required' => 'Phone number is required',
|
||||
],
|
||||
];
|
||||
|
||||
protected $skipValidation = false;
|
||||
|
||||
/**
|
||||
* Get lead with assigned user details
|
||||
*/
|
||||
public function getLeadWithUser($leadId)
|
||||
{
|
||||
return $this->select('actual_leads.*, user_profiles.username as assigned_to_name, user_profiles.email as assigned_to_email')
|
||||
->join('user_profiles', 'user_profiles.id = actual_leads.assigned_to', 'left')
|
||||
->where('actual_leads.lead_id', $leadId)
|
||||
->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all leads with pagination and filters
|
||||
*/
|
||||
public function getLeadsWithFilters($filters = [], $limit = 10, $offset = 0)
|
||||
{
|
||||
$builder = $this->select('actual_leads.*, user_profiles.username as assigned_to_name')
|
||||
->join('user_profiles', 'user_profiles.id = actual_leads.assigned_to', 'left');
|
||||
|
||||
if (!empty($filters['status'])) {
|
||||
$builder->where('actual_leads.status', $filters['status']);
|
||||
}
|
||||
|
||||
if (!empty($filters['assigned_to'])) {
|
||||
$builder->where('actual_leads.assigned_to', $filters['assigned_to']);
|
||||
}
|
||||
|
||||
if (!empty($filters['search'])) {
|
||||
$builder->groupStart()
|
||||
->like('actual_leads.company_name', $filters['search'])
|
||||
->orLike('actual_leads.email', $filters['search'])
|
||||
->orLike('actual_leads.phone', $filters['search'])
|
||||
->groupEnd();
|
||||
}
|
||||
|
||||
return [
|
||||
'data' => $builder->limit($limit, $offset)->findAll(),
|
||||
'total' => $builder->countAllResults(false)
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get lead with all related data (contacts, activities, notes)
|
||||
*/
|
||||
public function getLeadComplete($leadId)
|
||||
{
|
||||
$lead = $this->getLeadWithUser($leadId);
|
||||
|
||||
if (!$lead) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$contactModel = new SalesContactPersonModel();
|
||||
$activityModel = new SalesActivityModel();
|
||||
$noteModel = new SalesLeadNoteModel();
|
||||
|
||||
$lead['contact_persons'] = $contactModel->where('lead_id', $leadId)->findAll();
|
||||
$lead['activities'] = $activityModel->getActivitiesByLead($leadId);
|
||||
$lead['notes'] = $noteModel->getNotesByLead($leadId);
|
||||
|
||||
return $lead;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get leads statistics
|
||||
*/
|
||||
public function getLeadStats($userId = null)
|
||||
{
|
||||
$builder = $this->builder();
|
||||
|
||||
if ($userId) {
|
||||
$builder->where('assigned_to', $userId);
|
||||
}
|
||||
|
||||
$stats = [
|
||||
'total' => $builder->countAllResults(false),
|
||||
'new' => $builder->where('status', 'New')->countAllResults(false),
|
||||
'potential' => $builder->where('status', 'Potential')->countAllResults(false),
|
||||
'prospects' => $builder->where('status', 'Prospects')->countAllResults(false),
|
||||
'non_prospects' => $builder->where('status', 'Non prospects')->countAllResults(false),
|
||||
];
|
||||
|
||||
return $stats;
|
||||
}
|
||||
}
|
||||
95
app/Models/SalesContactPersonModel.php
Normal file
95
app/Models/SalesContactPersonModel.php
Normal file
@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use CodeIgniter\Model;
|
||||
|
||||
/**
|
||||
* Contact Person Model
|
||||
*/
|
||||
class SalesContactPersonModel extends Model
|
||||
{
|
||||
protected $table = 'sales_contact_persons';
|
||||
protected $primaryKey = 'contact_id';
|
||||
protected $useAutoIncrement = true;
|
||||
protected $returnType = 'array';
|
||||
protected $useSoftDeletes = false;
|
||||
protected $protectFields = true;
|
||||
protected $allowedFields = [
|
||||
'lead_id',
|
||||
'name',
|
||||
'mobile',
|
||||
'designation',
|
||||
'email',
|
||||
'is_primary',
|
||||
'created_by',
|
||||
'updated_by'
|
||||
];
|
||||
|
||||
// Dates
|
||||
protected $useTimestamps = true;
|
||||
protected $dateFormat = 'datetime';
|
||||
protected $createdField = 'created_at';
|
||||
protected $updatedField = 'updated_at';
|
||||
|
||||
// Validation
|
||||
protected $validationRules = [
|
||||
'lead_id' => 'required|integer',
|
||||
'name' => 'required|min_length[2]|max_length[100]',
|
||||
'mobile' => 'required|min_length[10]|max_length[20]',
|
||||
];
|
||||
|
||||
protected $validationMessages = [
|
||||
'lead_id' => [
|
||||
'required' => 'Lead ID is required',
|
||||
],
|
||||
'name' => [
|
||||
'required' => 'Contact person name is required',
|
||||
],
|
||||
'mobile' => [
|
||||
'required' => 'Mobile number is required',
|
||||
],
|
||||
];
|
||||
|
||||
protected $skipValidation = false;
|
||||
|
||||
/**
|
||||
* Get all contacts for a lead
|
||||
*/
|
||||
public function getContactsByLead($leadId)
|
||||
{
|
||||
return $this->where('lead_id', $leadId)
|
||||
->orderBy('is_primary', 'DESC')
|
||||
->findAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get primary contact for a lead
|
||||
*/
|
||||
public function getPrimaryContact($leadId)
|
||||
{
|
||||
return $this->where('lead_id', $leadId)
|
||||
->where('is_primary', 1)
|
||||
->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a contact as primary (unset others)
|
||||
*/
|
||||
public function setPrimaryContact($contactId, $leadId)
|
||||
{
|
||||
$this->db->transStart();
|
||||
|
||||
// Unset all primary contacts for this lead
|
||||
$this->where('lead_id', $leadId)
|
||||
->set(['is_primary' => 0])
|
||||
->update();
|
||||
|
||||
// Set the specified contact as primary
|
||||
$this->update($contactId, ['is_primary' => 1]);
|
||||
|
||||
$this->db->transComplete();
|
||||
|
||||
return $this->db->transStatus();
|
||||
}
|
||||
}
|
||||
75
app/Models/SalesLeadNoteModel.php
Normal file
75
app/Models/SalesLeadNoteModel.php
Normal file
@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use CodeIgniter\Model;
|
||||
|
||||
|
||||
/**
|
||||
* Lead Note Model
|
||||
*/
|
||||
class SalesLeadNoteModel extends Model
|
||||
{
|
||||
protected $table = 'sales_lead_notes';
|
||||
protected $primaryKey = 'note_id';
|
||||
protected $useAutoIncrement = true;
|
||||
protected $returnType = 'array';
|
||||
protected $useSoftDeletes = false;
|
||||
protected $protectFields = true;
|
||||
protected $allowedFields = [
|
||||
'lead_id',
|
||||
'user_id',
|
||||
'note_text',
|
||||
'created_by',
|
||||
'updated_by'
|
||||
];
|
||||
|
||||
// Dates
|
||||
protected $useTimestamps = true;
|
||||
protected $dateFormat = 'datetime';
|
||||
protected $createdField = 'created_at';
|
||||
protected $updatedField = 'updated_at';
|
||||
|
||||
// Validation
|
||||
protected $validationRules = [
|
||||
'lead_id' => 'required|integer',
|
||||
'user_id' => 'required|integer',
|
||||
'note_text' => 'required|min_length[3]',
|
||||
];
|
||||
|
||||
protected $validationMessages = [
|
||||
'lead_id' => [
|
||||
'required' => 'Lead ID is required',
|
||||
],
|
||||
'note_text' => [
|
||||
'required' => 'Note text is required',
|
||||
],
|
||||
];
|
||||
|
||||
protected $skipValidation = false;
|
||||
|
||||
/**
|
||||
* Get notes by lead with user details
|
||||
*/
|
||||
public function getNotesByLead($leadId)
|
||||
{
|
||||
return $this->select('lead_notes.*, user_profiles.username')
|
||||
->join('user_profiles', 'user_profiles.id = lead_notes.user_id', 'left')
|
||||
->where('lead_notes.lead_id', $leadId)
|
||||
->orderBy('lead_notes.created_at', 'DESC')
|
||||
->findAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get notes by user
|
||||
*/
|
||||
public function getNotesByUser($userId, $limit = 20, $offset = 0)
|
||||
{
|
||||
return $this->select('lead_notes.*, actual_leads.company_name')
|
||||
->join('actual_leads', 'actual_leads.lead_id = lead_notes.lead_id', 'left')
|
||||
->where('lead_notes.user_id', $userId)
|
||||
->orderBy('lead_notes.created_at', 'DESC')
|
||||
->limit($limit, $offset)
|
||||
->findAll();
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user