695 lines
21 KiB
PHP
695 lines
21 KiB
PHP
<?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((int)$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((int)$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((int)$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((int)$id)) {
|
|
return $this->failNotFound('Contact not found');
|
|
}
|
|
|
|
$data = $this->request->getJSON(true);
|
|
$data['updated_by'] = $this->getUserId();
|
|
|
|
if (!$this->contactModel->update((int)$id, $data)) {
|
|
return $this->fail($this->contactModel->errors(), ResponseInterface::HTTP_BAD_REQUEST);
|
|
}
|
|
|
|
$contact = $this->contactModel->find((int)$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((int)$id)) {
|
|
return $this->failNotFound('Contact not found');
|
|
}
|
|
|
|
$this->contactModel->delete((int)$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((int)$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((int)$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((int)$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((int)$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((int)$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((int)$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((int)$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((int)$id)) {
|
|
return $this->failNotFound('Activity not found');
|
|
}
|
|
|
|
$this->activityModel->delete((int)$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((int)$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((int)$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((int)$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((int)$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((int)$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;
|
|
}
|
|
} |