272 خطوط
17 KiB
PHP
272 خطوط
17 KiB
PHP
<?php
|
|
|
|
use App\Http\Controllers\Api\ActivityLogController;
|
|
use App\Http\Controllers\Api\AgentMobileController;
|
|
use App\Http\Controllers\Api\AssignmentController;
|
|
use App\Http\Controllers\Api\AttachmentController;
|
|
use App\Http\Controllers\Api\AuthController;
|
|
use App\Http\Controllers\Api\CalendarController;
|
|
use App\Http\Controllers\Api\CallController;
|
|
use App\Http\Controllers\Api\CampaignController;
|
|
use App\Http\Controllers\Api\CompanyController;
|
|
use App\Http\Controllers\Api\ConfigurationController;
|
|
use App\Http\Controllers\Api\ContactController;
|
|
use App\Http\Controllers\Api\DashboardController;
|
|
use App\Http\Controllers\Api\DealController;
|
|
use App\Http\Controllers\Api\DuplicateController;
|
|
use App\Http\Controllers\Api\FollowUpController;
|
|
use App\Http\Controllers\Api\ImportController;
|
|
use App\Http\Controllers\Api\IntelligenceController;
|
|
use App\Http\Controllers\Api\InvoiceController;
|
|
use App\Http\Controllers\Api\LeadController;
|
|
use App\Http\Controllers\Api\LeadStatusController;
|
|
use App\Http\Controllers\Api\LostReasonController;
|
|
use App\Http\Controllers\Api\MediaController;
|
|
use App\Http\Controllers\Api\NoteController;
|
|
use App\Http\Controllers\Api\NotificationController;
|
|
use App\Http\Controllers\Api\PipelineController;
|
|
use App\Http\Controllers\Api\PipelineStageController;
|
|
use App\Http\Controllers\Api\ProductController;
|
|
use App\Http\Controllers\Api\QualityReviewController;
|
|
use App\Http\Controllers\Api\ReportController;
|
|
use App\Http\Controllers\Api\RoleController;
|
|
use App\Http\Controllers\Api\ScriptController;
|
|
use App\Http\Controllers\Api\SettingController;
|
|
use App\Http\Controllers\Api\TaskController;
|
|
use App\Http\Controllers\Api\TimelineController;
|
|
use App\Http\Controllers\Api\UserController;
|
|
use App\Http\Controllers\Api\VoipWebhookController;
|
|
use App\Http\Controllers\Api\WorkspaceController;
|
|
use Illuminate\Support\Facades\Route;
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| API Routes
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
// Public
|
|
Route::middleware(['web', 'throttle:5,1'])->post('auth/login', [AuthController::class, 'login']);
|
|
Route::middleware(['web', 'throttle:60,1'])->get('auth/me', [AuthController::class, 'me']);
|
|
Route::middleware(['web'])->get('settings/public', [SettingController::class, 'public']);
|
|
Route::middleware('throttle:120,1')->get('media/avatars/{filename}', [MediaController::class, 'avatar'])
|
|
->where('filename', '[A-Za-z0-9_-]+\.(?:jpe?g|png|webp)');
|
|
Route::middleware('throttle:120,1')->post('voip/webhook', VoipWebhookController::class);
|
|
|
|
// Authenticated
|
|
Route::middleware(['web', 'auth:sanctum'])->group(function () {
|
|
Route::post('auth/logout', [AuthController::class, 'logout']);
|
|
Route::post('auth/profile', [AuthController::class, 'updateProfile']);
|
|
|
|
Route::middleware('role:agent')->prefix('agent/mobile')->group(function () {
|
|
Route::get('bootstrap', [AgentMobileController::class, 'bootstrap']);
|
|
Route::get('dashboard', [AgentMobileController::class, 'dashboard']);
|
|
Route::get('call-queue', [AgentMobileController::class, 'callQueue']);
|
|
Route::get('leads', [AgentMobileController::class, 'leads']);
|
|
Route::get('leads/{lead}', [AgentMobileController::class, 'lead']);
|
|
Route::get('follow-ups', [AgentMobileController::class, 'followUps']);
|
|
Route::post('calls', [AgentMobileController::class, 'startCall']);
|
|
Route::post('call-results', [AgentMobileController::class, 'callResult']);
|
|
Route::post('follow-ups', [AgentMobileController::class, 'storeFollowUp']);
|
|
Route::post('new-contact', [AgentMobileController::class, 'newContact']);
|
|
Route::post('preferred-view', [AgentMobileController::class, 'preferredView']);
|
|
});
|
|
|
|
Route::get('lead-statuses', [LeadStatusController::class, 'index']);
|
|
Route::get('pipeline-stages', [PipelineStageController::class, 'index']);
|
|
Route::get('agents', [UserController::class, 'agents']);
|
|
Route::get('users/assignable', [UserController::class, 'assignable']);
|
|
Route::get('users/referral-targets', [UserController::class, 'referralTargets']);
|
|
Route::get('import/template', [ImportController::class, 'template'])->middleware('throttle:20,1');
|
|
Route::middleware(['role:admin|agent', 'throttle:10,1'])->group(function () {
|
|
Route::post('import/upload', [ImportController::class, 'upload']);
|
|
Route::post('import/confirm', [ImportController::class, 'confirm']);
|
|
});
|
|
|
|
// Users (admin)
|
|
Route::middleware('role:admin')->group(function () {
|
|
Route::apiResource('users', UserController::class);
|
|
Route::patch('users/{user}/toggle-active', [UserController::class, 'toggleActive']);
|
|
Route::post('users/{user}/assign-role', [UserController::class, 'assignRole']);
|
|
Route::post('users/{user}/assign-team', [UserController::class, 'assignTeam']);
|
|
|
|
Route::apiResource('roles', RoleController::class);
|
|
Route::post('roles/{role}/sync-permissions', [RoleController::class, 'syncPermissions']);
|
|
Route::get('permissions', [RoleController::class, 'permissions']);
|
|
|
|
Route::apiResource('lead-statuses', LeadStatusController::class);
|
|
Route::post('lead-statuses/reorder', [LeadStatusController::class, 'reorder']);
|
|
Route::apiResource('lost-reasons', LostReasonController::class)->except(['show']);
|
|
|
|
Route::apiResource('pipeline-stages', PipelineStageController::class)->only(['store', 'update', 'destroy']);
|
|
|
|
Route::post('import/{batch}/rollback', [ImportController::class, 'rollback']);
|
|
Route::get('import-batches', [ImportController::class, 'index']);
|
|
|
|
Route::get('activity-logs', [ActivityLogController::class, 'index']);
|
|
|
|
Route::get('settings', [SettingController::class, 'index']);
|
|
Route::put('settings', [SettingController::class, 'update']);
|
|
Route::post('settings/voip/test', [SettingController::class, 'testVoip']);
|
|
Route::post('settings/voip/test-call', [SettingController::class, 'testVoipCall']);
|
|
|
|
});
|
|
|
|
// Leads
|
|
Route::get('leads/next', [LeadController::class, 'nextLead']);
|
|
Route::get('leads/funnel', [LeadController::class, 'funnel']);
|
|
Route::get('leads/export', [LeadController::class, 'export'])->middleware('throttle:5,1');
|
|
Route::delete('leads/bulk-delete', [LeadController::class, 'bulkDestroy']);
|
|
Route::post('leads/{lead}/contacts', [ContactController::class, 'store']);
|
|
Route::patch('contacts/{contact}/primary', [ContactController::class, 'setPrimary']);
|
|
Route::apiResource('leads', LeadController::class);
|
|
Route::post('leads/{lead}/refer', [AssignmentController::class, 'refer']);
|
|
|
|
// Invoices
|
|
Route::get('invoices', [InvoiceController::class, 'index']);
|
|
Route::get('invoices-summary', [InvoiceController::class, 'summary']);
|
|
Route::get('invoices/{invoice}', [InvoiceController::class, 'show']);
|
|
Route::get('invoices/{invoice}/word', [InvoiceController::class, 'word']);
|
|
Route::post('leads/{lead}/invoice', [InvoiceController::class, 'fromLead']);
|
|
Route::put('invoices/{invoice}', [InvoiceController::class, 'update']);
|
|
Route::post('invoices/{invoice}/issue', [InvoiceController::class, 'issue']);
|
|
Route::post('invoices/{invoice}/approve', [InvoiceController::class, 'approve']);
|
|
Route::post('invoices/{invoice}/reject', [InvoiceController::class, 'reject']);
|
|
Route::post('invoices/{invoice}/void', [InvoiceController::class, 'void']);
|
|
Route::get('invoice-templates', [InvoiceController::class, 'templates']);
|
|
Route::post('invoice-templates', [InvoiceController::class, 'storeTemplate']);
|
|
Route::put('invoice-templates/{invoiceTemplate}', [InvoiceController::class, 'updateTemplate']);
|
|
Route::delete('invoice-templates/{invoiceTemplate}', [InvoiceController::class, 'destroyTemplate']);
|
|
Route::post('invoice-templates/{invoiceTemplate}/background', [InvoiceController::class, 'uploadTemplateBackground']);
|
|
Route::delete('invoice-templates/{invoiceTemplate}/background', [InvoiceController::class, 'deleteTemplateBackground']);
|
|
Route::get('invoice-templates/{invoiceTemplate}/background', [InvoiceController::class, 'templateBackground']);
|
|
Route::get('invoice-template-fields', [InvoiceController::class, 'fieldCatalog']);
|
|
|
|
// Core CRM
|
|
Route::apiResource('companies', CompanyController::class);
|
|
Route::post('companies/{company}/merge', [CompanyController::class, 'merge']);
|
|
Route::apiResource('deals', DealController::class);
|
|
Route::get('pipelines', [PipelineController::class, 'index']);
|
|
Route::post('pipelines', [PipelineController::class, 'store']);
|
|
Route::get('pipelines/{pipeline}/board', [PipelineController::class, 'board']);
|
|
Route::patch('deals/{deal}/stage', [PipelineController::class, 'move']);
|
|
Route::get('global-search', [WorkspaceController::class, 'search'])->middleware('throttle:60,1');
|
|
Route::get('saved-views', [WorkspaceController::class, 'savedViews']);
|
|
Route::post('saved-views', [WorkspaceController::class, 'storeSavedView']);
|
|
Route::delete('saved-views/{savedView}', [WorkspaceController::class, 'deleteSavedView']);
|
|
Route::get('workspace-preferences', [WorkspaceController::class, 'preferences']);
|
|
Route::put('workspace-preferences', [WorkspaceController::class, 'updatePreferences']);
|
|
Route::post('leads/bulk-score', [IntelligenceController::class, 'bulkScore']);
|
|
Route::post('leads/{lead}/score', [IntelligenceController::class, 'scoreLead']);
|
|
Route::get('sla-rules', [IntelligenceController::class, 'slaRules']);
|
|
Route::post('sla-rules', [IntelligenceController::class, 'storeSlaRule']);
|
|
Route::get('sla-breaches', [IntelligenceController::class, 'breaches']);
|
|
Route::post('sla/detect', [IntelligenceController::class, 'detect']);
|
|
Route::patch('sla-breaches/{slaBreach}/resolve', [IntelligenceController::class, 'resolve']);
|
|
Route::get('automations', [ConfigurationController::class, 'automations']);
|
|
Route::post('automations', [ConfigurationController::class, 'storeAutomation']);
|
|
Route::post('automations/{automationRule}/run', [ConfigurationController::class, 'runAutomation']);
|
|
Route::get('automation-runs', [ConfigurationController::class, 'automationRuns']);
|
|
Route::get('custom-fields', [ConfigurationController::class, 'customFields']);
|
|
Route::post('custom-fields', [ConfigurationController::class, 'storeCustomField']);
|
|
Route::get('custom-field-values/{entityType}/{entityId}', [ConfigurationController::class, 'values']);
|
|
Route::put('custom-field-values/{entityType}/{entityId}', [ConfigurationController::class, 'updateValues']);
|
|
Route::apiResource('products', ProductController::class);
|
|
Route::get('contacts', [ContactController::class, 'index']);
|
|
Route::post('contacts', [ContactController::class, 'storeStandalone']);
|
|
Route::put('contacts/{contact}', [ContactController::class, 'update']);
|
|
Route::delete('contacts/{contact}', [ContactController::class, 'destroy']);
|
|
Route::post('notes', [NoteController::class, 'store']);
|
|
Route::get('calls/{call}/notes', [NoteController::class, 'callIndex']);
|
|
Route::post('calls/{call}/notes', [NoteController::class, 'callStore']);
|
|
Route::patch('notes/{note}', [NoteController::class, 'update']);
|
|
Route::delete('notes/{note}', [NoteController::class, 'destroy']);
|
|
Route::post('notes/{note}/pin', [NoteController::class, 'pin']);
|
|
Route::post('notes/{note}/unpin', [NoteController::class, 'unpin']);
|
|
Route::get('timeline', [TimelineController::class, 'index']);
|
|
Route::get('attachments', [AttachmentController::class, 'index']);
|
|
Route::post('attachments', [AttachmentController::class, 'store']);
|
|
Route::get('attachments/{attachment}/download', [AttachmentController::class, 'download']);
|
|
Route::delete('attachments/{attachment}', [AttachmentController::class, 'destroy']);
|
|
Route::post('duplicates/check', [DuplicateController::class, 'check']);
|
|
|
|
// Assignments
|
|
Route::middleware('role:admin|supervisor')->prefix('assignments')->group(function () {
|
|
Route::post('assign', [AssignmentController::class, 'assign']);
|
|
Route::post('bulk-assign', [AssignmentController::class, 'bulkAssign']);
|
|
Route::post('round-robin', [AssignmentController::class, 'roundRobin']);
|
|
Route::post('reassign', [AssignmentController::class, 'reassign']);
|
|
Route::post('{lead}/return-to-pool', [AssignmentController::class, 'returnToPool']);
|
|
});
|
|
|
|
// Campaigns
|
|
Route::apiResource('campaigns', CampaignController::class);
|
|
|
|
// Calls
|
|
Route::get('call-results', [CallController::class, 'results']);
|
|
Route::get('calls', [CallController::class, 'index']);
|
|
Route::post('calls', [CallController::class, 'store']);
|
|
Route::post('calls/manual-result', [CallController::class, 'manualResult']);
|
|
Route::get('calls/{call}', [CallController::class, 'show']);
|
|
Route::post('calls/register-result', [CallController::class, 'registerResult']);
|
|
|
|
// Follow-ups
|
|
Route::get('follow-ups/today', [FollowUpController::class, 'today']);
|
|
Route::get('follow-ups/overdue', [FollowUpController::class, 'overdue']);
|
|
Route::patch('follow-ups/{followUp}/mark-done', [FollowUpController::class, 'markDone']);
|
|
Route::apiResource('follow-ups', FollowUpController::class)->only(['index', 'store', 'show', 'update', 'destroy']);
|
|
|
|
// Tasks
|
|
Route::post('tasks/bulk-assign', [TaskController::class, 'bulkAssign']);
|
|
Route::post('tasks/bulk-complete', [TaskController::class, 'bulkComplete']);
|
|
Route::post('tasks/{task}/assign', [TaskController::class, 'assign']);
|
|
Route::post('tasks/{task}/start', [TaskController::class, 'start']);
|
|
Route::post('tasks/{task}/complete', [TaskController::class, 'complete']);
|
|
Route::post('tasks/{task}/reopen', [TaskController::class, 'reopen']);
|
|
Route::post('tasks/{task}/cancel', [TaskController::class, 'cancel']);
|
|
Route::apiResource('tasks', TaskController::class);
|
|
Route::get('calendar/events', [CalendarController::class, 'index']);
|
|
|
|
// Pipeline
|
|
Route::put('pipeline/{pipelineStage}/lead/{lead}', [PipelineStageController::class, 'updateLeadStage']);
|
|
|
|
// Dashboards
|
|
Route::get('dashboard/admin', [DashboardController::class, 'admin'])->middleware('permission:view_admin_dashboard');
|
|
Route::get('dashboard/supervisor', [DashboardController::class, 'supervisor'])->middleware('permission:view_supervisor_dashboard');
|
|
Route::get('dashboard/agent', [DashboardController::class, 'agent'])->middleware('permission:view_agent_dashboard');
|
|
|
|
// Reports
|
|
Route::middleware('throttle:30,1')->group(function () {
|
|
Route::get('reports/kpi', [ReportController::class, 'kpi']);
|
|
Route::get('reports/agent-performance', [ReportController::class, 'agentPerformance']);
|
|
Route::get('reports/team-performance', [ReportController::class, 'teamPerformance']);
|
|
Route::get('reports/campaign/{campaign}', [ReportController::class, 'campaignReport']);
|
|
Route::get('reports/conversion', [ReportController::class, 'conversionReport']);
|
|
Route::get('reports/call', [ReportController::class, 'callReport']);
|
|
Route::get('reports/follow-up', [ReportController::class, 'followUpReport']);
|
|
Route::get('reports/lost-reasons', [ReportController::class, 'lostReasonReport']);
|
|
Route::get('reports/source-performance', [ReportController::class, 'sourcePerformance']);
|
|
Route::get('reports/duplicates', [ReportController::class, 'duplicateLeads']);
|
|
Route::get('reports/import-quality', [ReportController::class, 'importQuality']);
|
|
Route::get('reports/call-quality', [ReportController::class, 'callQuality']);
|
|
Route::get('reports/best-contact-time', [ReportController::class, 'bestContactTime']);
|
|
Route::get('reports/operations', [ReportController::class, 'operations']);
|
|
Route::get('reports/export/excel', [ReportController::class, 'exportExcel'])->middleware('throttle:5,1');
|
|
});
|
|
|
|
// Scripts
|
|
Route::apiResource('scripts', ScriptController::class);
|
|
|
|
// Quality Reviews
|
|
Route::apiResource('quality-reviews', QualityReviewController::class)->only(['index', 'store', 'show', 'update']);
|
|
Route::post('quality-reviews/{qualityReview}/acknowledge', [QualityReviewController::class, 'acknowledge']);
|
|
|
|
// Notifications
|
|
Route::get('notifications', [NotificationController::class, 'index']);
|
|
Route::patch('notifications/read-all', [NotificationController::class, 'markAllRead']);
|
|
Route::patch('notifications/{notification}/read', [NotificationController::class, 'markRead']);
|
|
Route::patch('notifications/{notification}/archive', [NotificationController::class, 'archive']);
|
|
Route::delete('notifications/{notification}', [NotificationController::class, 'destroy']);
|
|
Route::get('notifications/unread-count', [NotificationController::class, 'unreadCount']);
|
|
});
|