140 خطوط
5.2 KiB
PHP
140 خطوط
5.2 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature;
|
|
|
|
use App\Models\Call;
|
|
use App\Models\Lead;
|
|
use App\Models\QualityReview;
|
|
use App\Models\SalesScript;
|
|
use App\Models\Team;
|
|
use App\Models\User;
|
|
use Database\Seeders\RolePermissionSeeder;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Tests\TestCase;
|
|
|
|
class QualityScriptAuthorizationTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
$this->seed(RolePermissionSeeder::class);
|
|
}
|
|
|
|
public function test_quality_review_derives_agent_from_call_and_versions_reviews(): void
|
|
{
|
|
[$supervisor, $agent] = $this->team();
|
|
$otherAgent = $this->user('agent');
|
|
$call = $this->makeCall($agent);
|
|
|
|
$first = $this->actingAs($supervisor)->postJson('/api/quality-reviews', $this->reviewPayload($call, [
|
|
'agent_id' => $otherAgent->id,
|
|
'is_shared_with_agent' => false,
|
|
]))->assertCreated();
|
|
|
|
$this->assertSame($agent->id, $first->json('agent_id'));
|
|
$this->assertSame(1, $first->json('version'));
|
|
|
|
$second = $this->actingAs($supervisor)->postJson('/api/quality-reviews', $this->reviewPayload($call, [
|
|
'is_shared_with_agent' => true,
|
|
]))->assertCreated();
|
|
|
|
$this->assertSame(2, $second->json('version'));
|
|
$this->assertFalse(QualityReview::findOrFail($first->json('id'))->is_current);
|
|
$this->assertTrue(QualityReview::findOrFail($second->json('id'))->is_current);
|
|
}
|
|
|
|
public function test_agent_only_sees_shared_own_review_and_cannot_create_one(): void
|
|
{
|
|
[$supervisor, $agent] = $this->team();
|
|
$call = $this->makeCall($agent);
|
|
$review = $this->actingAs($supervisor)->postJson('/api/quality-reviews', $this->reviewPayload($call, [
|
|
'is_shared_with_agent' => false,
|
|
]))->assertCreated()->json();
|
|
|
|
$this->actingAs($agent)->getJson("/api/quality-reviews/{$review['id']}")->assertForbidden();
|
|
$this->actingAs($agent)->postJson('/api/quality-reviews', $this->reviewPayload($call))->assertForbidden();
|
|
|
|
$this->actingAs($supervisor)->putJson("/api/quality-reviews/{$review['id']}", ['is_shared_with_agent' => true])->assertOk();
|
|
$this->actingAs($agent)->getJson("/api/quality-reviews/{$review['id']}")->assertOk();
|
|
}
|
|
|
|
public function test_sales_scripts_are_transactional_and_agents_only_see_active_scripts(): void
|
|
{
|
|
[$supervisor, $agent] = $this->team();
|
|
|
|
$scriptId = $this->actingAs($supervisor)->postJson('/api/scripts', [
|
|
'title' => 'Outbound sales',
|
|
'description' => 'Approved script',
|
|
'is_active' => true,
|
|
'assigned_user_ids' => [$agent->id],
|
|
'sections' => [
|
|
['title' => 'Greeting', 'content' => 'Hello', 'sort_order' => 0],
|
|
['title' => 'Discovery', 'content' => 'Ask questions', 'sort_order' => 1],
|
|
],
|
|
])->assertCreated()->json('id');
|
|
|
|
$this->assertDatabaseHas('script_sections', ['sales_script_id' => $scriptId, 'sort_order' => 0]);
|
|
$this->actingAs($agent)->getJson("/api/scripts/{$scriptId}")->assertOk();
|
|
$this->actingAs($agent)->postJson('/api/scripts', ['title' => 'Unauthorized'])->assertForbidden();
|
|
|
|
SalesScript::whereKey($scriptId)->update(['is_active' => false]);
|
|
$this->actingAs($agent)->getJson("/api/scripts/{$scriptId}")->assertForbidden();
|
|
|
|
$this->actingAs($supervisor)->postJson('/api/scripts', [
|
|
'title' => 'Invalid script',
|
|
'sections' => [['title' => 'Missing content']],
|
|
])->assertUnprocessable();
|
|
$this->assertDatabaseMissing('sales_scripts', ['title' => 'Invalid script']);
|
|
}
|
|
|
|
private function reviewPayload(Call $call, array $overrides = []): array
|
|
{
|
|
return array_merge([
|
|
'call_id' => $call->id,
|
|
'greeting_score' => 80,
|
|
'product_intro_score' => 75,
|
|
'needs_discovery_score' => 70,
|
|
'objection_handling_score' => 65,
|
|
'closing_score' => 60,
|
|
'crm_accuracy_score' => 90,
|
|
'follow_up_quality_score' => 85,
|
|
'feedback' => 'Useful feedback',
|
|
], $overrides);
|
|
}
|
|
|
|
private function team(): array
|
|
{
|
|
$supervisor = $this->user('supervisor');
|
|
$agent = $this->user('agent');
|
|
$team = Team::create(['name' => 'Sales Team', 'supervisor_id' => $supervisor->id, 'is_active' => true]);
|
|
$supervisor->teams()->attach($team);
|
|
$agent->teams()->attach($team);
|
|
|
|
return [$supervisor, $agent];
|
|
}
|
|
|
|
private function makeCall(User $agent): Call
|
|
{
|
|
$lead = Lead::create([
|
|
'company' => 'Call Company',
|
|
'first_name' => 'Sara',
|
|
'last_name' => 'Ahmadi',
|
|
'phone' => fake()->unique()->numerify('021########'),
|
|
'assigned_to' => $agent->id,
|
|
'is_unassigned' => false,
|
|
]);
|
|
|
|
return Call::create(['lead_id' => $lead->id, 'user_id' => $agent->id, 'direction' => 'outbound', 'phone' => $lead->phone]);
|
|
}
|
|
|
|
private function user(string $role): User
|
|
{
|
|
$user = User::factory()->create(['is_active' => true]);
|
|
$user->assignRole($role);
|
|
|
|
return $user;
|
|
}
|
|
}
|