CRM/backend/database/seeders/DatabaseSeeder.php

214 خطوط
15 KiB
PHP

<?php
namespace Database\Seeders;
use App\Models\CallResult;
use App\Models\LeadStatus;
use App\Models\LostReason;
use App\Models\PipelineStage;
use App\Models\Setting;
use App\Models\User;
use Illuminate\Database\Seeder;
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;
class DatabaseSeeder extends Seeder
{
public function run(): void
{
$this->seedRoles();
$this->seedLeadStatuses();
$this->seedPipelineStages();
$this->seedCallResults();
$this->seedSettings();
$this->seedDemoUsers();
}
private function seedRoles(): void
{
$admin = Role::firstOrCreate(['name' => 'admin', 'guard_name' => 'web']);
Role::firstOrCreate(['name' => 'supervisor', 'guard_name' => 'web']);
Role::firstOrCreate(['name' => 'agent', 'guard_name' => 'web']);
$permissions = [
'view_leads', 'create_leads', 'edit_leads', 'delete_leads',
'import_leads', 'export_leads', 'view_full_phone',
'view_reports', 'export_reports',
'manage_users', 'manage_roles', 'manage_campaigns', 'manage_settings',
'view_activity_logs', 'manage_scripts',
'view_quality_reviews', 'create_quality_reviews', 'listen_recordings',
'view_all_calls', 'view_team_calls', 'view_own_calls',
'assign_leads', 'reassign_leads',
];
foreach ($permissions as $p) {
Permission::firstOrCreate(['name' => $p, 'guard_name' => 'web']);
}
$admin->syncPermissions(Permission::all());
}
private function seedLeadStatuses(): void
{
$statuses = [
['slug' => 'open', 'name' => 'در جریان', 'color' => '#2563EB', 'sort_order' => 0, 'is_default' => true, 'is_won' => false, 'is_lost' => false],
['slug' => 'won', 'name' => 'موفق', 'color' => '#16A34A', 'sort_order' => 1, 'is_default' => false, 'is_won' => true, 'is_lost' => false],
['slug' => 'lost', 'name' => 'ناموفق', 'color' => '#DC2626', 'sort_order' => 2, 'is_default' => false, 'is_won' => false, 'is_lost' => true],
];
foreach ($statuses as $s) {
LeadStatus::updateOrCreate(['slug' => $s['slug']], $s);
}
}
private function seedPipelineStages(): void
{
$stages = [
['slug' => 'new', 'name' => 'لید جدید', 'color' => '#3B82F6', 'sort_order' => 0, 'is_default' => true, 'is_won' => false, 'is_lost' => false, 'requires_follow_up' => false],
['slug' => 'waiting_call', 'name' => 'در انتظار تماس', 'color' => '#6366F1', 'sort_order' => 1, 'is_default' => false, 'is_won' => false, 'is_lost' => false, 'requires_follow_up' => false],
['slug' => 'contacted', 'name' => 'تماس برقرار شد', 'color' => '#06B6D4', 'sort_order' => 2, 'is_default' => false, 'is_won' => false, 'is_lost' => false, 'requires_follow_up' => false],
['slug' => 'qualified', 'name' => 'واجد شرایط / علاقه‌مند', 'color' => '#22C55E', 'sort_order' => 3, 'is_default' => false, 'is_won' => false, 'is_lost' => false, 'requires_follow_up' => false],
['slug' => 'follow_up', 'name' => 'پیگیری', 'color' => '#F59E0B', 'sort_order' => 4, 'is_default' => false, 'is_won' => false, 'is_lost' => false, 'requires_follow_up' => true],
['slug' => 'proposal_sent', 'name' => 'پیشنهاد ارسال شد', 'color' => '#8B5CF6', 'sort_order' => 5, 'is_default' => false, 'is_won' => false, 'is_lost' => false, 'requires_follow_up' => false],
['slug' => 'closed', 'name' => 'موفق / ناموفق', 'color' => '#334155', 'sort_order' => 6, 'is_default' => false, 'is_won' => true, 'is_lost' => true, 'requires_follow_up' => false],
];
foreach ($stages as $s) {
PipelineStage::updateOrCreate(['slug' => $s['slug']], $s);
}
}
private function seedCallResults(): void
{
$results = [
['slug' => 'no_answer', 'name' => 'پاسخ نداد', 'color' => '#F59E0B', 'requires_follow_up' => true, 'phone_status' => 'no_answer', 'sort_order' => 0],
['slug' => 'busy', 'name' => 'اشغال بود', 'color' => '#F97316', 'requires_follow_up' => true, 'phone_status' => 'no_answer', 'sort_order' => 1],
['slug' => 'off', 'name' => 'خاموش بود', 'color' => '#64748B', 'requires_follow_up' => true, 'phone_status' => 'inactive', 'sort_order' => 2],
['slug' => 'wrong_number', 'name' => 'شماره اشتباه', 'color' => '#EF4444', 'is_negative' => true, 'is_final' => true, 'phone_status' => 'wrong', 'sort_order' => 3],
['slug' => 'call_later', 'name' => 'بعداً تماس بگیرید', 'color' => '#3B82F6', 'requires_follow_up' => true, 'sort_order' => 4],
['slug' => 'not_decision_maker', 'name' => 'تصمیم‌گیرنده نبود', 'color' => '#8B5CF6', 'requires_follow_up' => true, 'sort_order' => 5],
['slug' => 'not_interested', 'name' => 'علاقه‌مند نبود', 'color' => '#EF4444', 'is_negative' => true, 'sort_order' => 6],
['slug' => 'interested', 'name' => 'علاقه‌مند بود', 'color' => '#22C55E', 'is_positive' => true, 'sort_order' => 7],
['slug' => 'needs_follow_up', 'name' => 'نیازمند پیگیری', 'color' => '#0EA5E9', 'requires_follow_up' => true, 'sort_order' => 8],
['slug' => 'no_budget', 'name' => 'بودجه ندارد', 'color' => '#DC2626', 'is_negative' => true, 'sort_order' => 9],
['slug' => 'already_purchased', 'name' => 'قبلاً خرید کرده', 'color' => '#14B8A6', 'is_positive' => true, 'is_final' => true, 'sort_order' => 10],
['slug' => 'do_not_call', 'name' => 'عدم تماس مجدد', 'color' => '#475569', 'is_negative' => true, 'is_final' => true, 'sort_order' => 11],
['slug' => 'invalid_lead', 'name' => 'لید نامعتبر', 'color' => '#991B1B', 'is_negative' => true, 'is_final' => true, 'sort_order' => 12],
['slug' => 'answered', 'name' => 'پاسخ داد', 'color' => '#06B6D4', 'is_positive' => true, 'sort_order' => 13],
['slug' => 'proposal_sent', 'name' => 'پیشنهاد ارسال شد', 'color' => '#8B5CF6', 'is_positive' => true, 'sort_order' => 14],
['slug' => 'referral', 'name' => 'معرفی شماره جدید', 'color' => '#0EA5E9', 'is_positive' => true, 'requires_follow_up' => true, 'sort_order' => 15],
];
foreach ($results as $r) {
CallResult::updateOrCreate(['slug' => $r['slug']], $r);
}
$stageIds = PipelineStage::pluck('id', 'slug');
$statusIds = LeadStatus::pluck('id', 'slug');
$transitions = [
'answered' => ['stage' => 'contacted', 'phone' => 'active', 'next' => 'ثبت تماس انجام شد'],
'interested' => ['stage' => 'qualified', 'phone' => 'active', 'next' => 'ادامه مذاکره'],
'proposal_sent' => ['stage' => 'proposal_sent', 'phone' => 'active', 'next' => 'پیگیری پیشنهاد'],
'call_later' => ['stage' => 'follow_up', 'phone' => 'active', 'next' => 'پیگیری در زمان مشخص‌شده'],
'needs_follow_up' => ['stage' => 'follow_up', 'phone' => 'active', 'next' => 'پیگیری در زمان مشخص‌شده'],
'wrong_number' => ['phone' => 'wrong', 'next' => 'بررسی شماره جایگزین'],
'off' => ['phone' => 'inactive'],
'no_answer' => ['phone' => 'no_answer', 'next' => 'تماس مجدد در صف'],
'busy' => ['phone' => 'no_answer', 'next' => 'تماس مجدد در صف'],
'not_interested' => ['stage' => 'closed', 'status' => 'lost', 'phone' => 'inactive', 'next' => 'لید بسته شد'],
'do_not_call' => ['stage' => 'closed', 'status' => 'lost', 'phone' => 'inactive'],
'invalid_lead' => ['stage' => 'closed', 'status' => 'lost'],
'already_purchased' => ['stage' => 'closed', 'status' => 'won', 'phone' => 'active'],
'referral' => ['stage' => 'follow_up', 'phone' => 'active', 'next' => 'تماس با مخاطب معرفی‌شده'],
];
foreach ($transitions as $slug => $transition) {
CallResult::where('slug', $slug)->update([
'next_pipeline_stage_id' => isset($transition['stage']) ? ($stageIds[$transition['stage']] ?? null) : null,
'lead_status_id' => isset($transition['status']) ? ($statusIds[$transition['status']] ?? null) : null,
'phone_status' => $transition['phone'] ?? null,
'next_action' => $transition['next'] ?? null,
]);
}
foreach ([
['slug' => 'no_budget', 'name' => 'بودجه ندارد', 'sort_order' => 0],
['slug' => 'no_need', 'name' => 'عدم نیاز', 'sort_order' => 1],
['slug' => 'competitor', 'name' => 'رقیب انتخاب شد', 'sort_order' => 2],
['slug' => 'no_response', 'name' => 'عدم پاسخگویی', 'sort_order' => 3],
['slug' => 'invalid_lead', 'name' => 'لید نامعتبر', 'sort_order' => 4],
] as $reason) {
LostReason::updateOrCreate(['slug' => $reason['slug']], $reason + ['color' => '#DC2626', 'is_active' => true]);
}
}
private function seedSettings(): void
{
$settings = [
['key' => 'company_name', 'value' => 'CRM فروش', 'default_value' => 'CRM فروش', 'group' => 'general', 'type' => 'string', 'validation_rules' => ['string', 'max:255'], 'is_public' => true, 'is_runtime_enforced' => true, 'description' => 'نام نمایشی سامانه'],
['key' => 'phone_mask_enabled', 'value' => 'true', 'default_value' => 'true', 'group' => 'security', 'type' => 'boolean', 'validation_rules' => ['in:true,false,1,0'], 'is_public' => true, 'is_runtime_enforced' => true, 'description' => 'مخفی‌سازی شماره برای کاربران بدون مجوز'],
['key' => 'call_recording_enabled', 'value' => 'false', 'default_value' => 'false', 'group' => 'voip', 'type' => 'boolean', 'validation_rules' => ['in:true,false,1,0'], 'is_public' => true, 'is_runtime_enforced' => true, 'description' => 'فعال‌سازی ضبط تماس'],
['key' => 'voip_provider', 'value' => 'mock', 'default_value' => 'mock', 'group' => 'voip', 'type' => 'string', 'allowed_values' => ['mock', 'ami', 'api', 'socket'], 'is_runtime_enforced' => true],
['key' => 'voip_ami_host', 'value' => '', 'group' => 'voip', 'type' => 'string'],
['key' => 'voip_ami_port', 'value' => '5038', 'group' => 'voip', 'type' => 'integer'],
['key' => 'voip_ami_username', 'value' => '', 'group' => 'voip', 'type' => 'string'],
['key' => 'voip_ami_secret', 'value' => '', 'group' => 'voip', 'type' => 'string', 'is_secret' => true, 'is_runtime_enforced' => true],
['key' => 'voip_ami_channel_technology', 'value' => 'SIP', 'group' => 'voip', 'type' => 'string', 'allowed_values' => ['SIP', 'PJSIP']],
['key' => 'voip_ami_context', 'value' => 'from-internal', 'group' => 'voip', 'type' => 'string'],
['key' => 'voip_ami_caller_id_template', 'value' => 'CRM <{extension}>', 'group' => 'voip', 'type' => 'string'],
['key' => 'voip_ami_timeout', 'value' => '5', 'group' => 'voip', 'type' => 'integer'],
['key' => 'voip_ami_originate_timeout', 'value' => '30', 'group' => 'voip', 'type' => 'integer'],
['key' => 'voip_ami_recording_url', 'value' => '', 'group' => 'voip', 'type' => 'string'],
['key' => 'voip_api_base_url', 'value' => '', 'group' => 'voip', 'type' => 'string'],
['key' => 'voip_api_token', 'value' => '', 'group' => 'voip', 'type' => 'string', 'is_secret' => true, 'is_runtime_enforced' => true],
['key' => 'voip_api_call_path', 'value' => '/calls', 'group' => 'voip', 'type' => 'string'],
['key' => 'voip_api_status_path', 'value' => '/calls/{id}', 'group' => 'voip', 'type' => 'string'],
['key' => 'voip_api_recording_url', 'value' => '', 'group' => 'voip', 'type' => 'string'],
['key' => 'voip_socket_host', 'value' => '', 'group' => 'voip', 'type' => 'string'],
['key' => 'voip_socket_port', 'value' => '', 'group' => 'voip', 'type' => 'integer'],
['key' => 'voip_socket_token', 'value' => '', 'group' => 'voip', 'type' => 'string', 'is_secret' => true, 'is_runtime_enforced' => true],
['key' => 'voip_socket_timeout', 'value' => '5', 'group' => 'voip', 'type' => 'integer'],
['key' => 'voip_socket_recording_url', 'value' => '', 'group' => 'voip', 'type' => 'string'],
['key' => 'session_timeout_minutes', 'value' => '120', 'default_value' => '120', 'group' => 'security', 'type' => 'integer', 'validation_rules' => ['integer', 'min:5'], 'is_runtime_enforced' => false],
['key' => 'strong_passwords_enabled', 'value' => 'false', 'default_value' => 'false', 'group' => 'security', 'type' => 'boolean', 'validation_rules' => ['in:true,false,1,0'], 'is_runtime_enforced' => false],
['key' => 'two_factor_enabled', 'value' => 'false', 'default_value' => 'false', 'group' => 'security', 'type' => 'boolean', 'validation_rules' => ['in:true,false,1,0'], 'is_runtime_enforced' => false],
['key' => 'login_attempt_limit', 'value' => '5', 'default_value' => '5', 'group' => 'security', 'type' => 'integer', 'validation_rules' => ['integer', 'min:1'], 'is_runtime_enforced' => false],
['key' => 'default_follow_up_hours', 'value' => '24', 'default_value' => '24', 'group' => 'follow_up', 'type' => 'integer', 'validation_rules' => ['integer', 'min:1'], 'is_runtime_enforced' => true],
['key' => 'duplicate_phone_policy', 'value' => 'warn', 'default_value' => 'warn', 'group' => 'duplicate', 'type' => 'string', 'validation_rules' => ['string'], 'allowed_values' => ['allow', 'warn', 'block', 'merge_suggestion'], 'is_runtime_enforced' => true],
];
foreach ($settings as $s) {
Setting::updateOrCreate(['key' => $s['key']], $s);
}
}
private function seedDemoUsers(): void
{
$admin = User::create([
'name' => 'مدیر سیستم',
'email' => 'admin@crm.com',
'password' => bcrypt('password'),
'phone' => '09121111111',
'is_active' => true,
]);
$admin->assignRole('admin');
$supervisor = User::create([
'name' => 'سرپرست فروش',
'email' => 'supervisor@crm.com',
'password' => bcrypt('password'),
'phone' => '09122222222',
'is_active' => true,
]);
$supervisor->assignRole('supervisor');
$agent = User::create([
'name' => 'کارشناس فروش',
'email' => 'agent@crm.com',
'password' => bcrypt('password'),
'phone' => '09123333333',
'is_active' => true,
]);
$agent->assignRole('agent');
}
}