seed(RolePermissionSeeder::class); } public function test_campaign_assignments_store_the_correct_pivot_role_and_load_script(): void { $admin = $this->user('admin'); $agent = $this->user('agent'); $supervisor = $this->user('supervisor'); $script = SalesScript::create(['title' => 'Default script']); $campaignId = $this->actingAs($admin)->postJson('/api/campaigns', [ 'name' => 'Summer Campaign', 'status' => 'active', 'sales_script_id' => $script->id, 'agent_ids' => [$agent->id], 'supervisor_ids' => [$supervisor->id], ])->assertCreated()->json('data.id'); $this->assertDatabaseHas('campaign_user', ['campaign_id' => $campaignId, 'user_id' => $agent->id, 'role' => 'agent']); $this->assertDatabaseHas('campaign_user', ['campaign_id' => $campaignId, 'user_id' => $supervisor->id, 'role' => 'supervisor']); $this->actingAs($admin)->getJson("/api/campaigns/{$campaignId}") ->assertOk() ->assertJsonPath('data.sales_script.id', $script->id); } public function test_deal_show_loads_notes_without_missing_relation_error(): void { $admin = $this->user('admin'); $deal = Deal::create(['title' => 'Safe Deal', 'owner_id' => $admin->id, 'created_by' => $admin->id]); $deal->notes()->create([ 'user_id' => $admin->id, 'content' => 'Deal note', ]); $this->actingAs($admin)->getJson("/api/deals/{$deal->id}") ->assertOk() ->assertJsonPath('notes.0.content', 'Deal note'); } public function test_primary_contact_change_is_limited_to_the_same_parent_scope(): void { $admin = $this->user('admin'); $otherAdmin = $this->user('admin'); $first = Contact::create(['name' => 'First', 'created_by' => $admin->id, 'is_primary' => true]); $second = Contact::create(['name' => 'Second', 'created_by' => $admin->id, 'is_primary' => false]); $unrelated = Contact::create(['name' => 'Unrelated', 'created_by' => $otherAdmin->id, 'is_primary' => true]); $this->actingAs($admin)->patchJson("/api/contacts/{$second->id}/primary", ['reason' => 'Main contact'])->assertOk(); $this->assertFalse($first->fresh()->is_primary); $this->assertTrue($second->fresh()->is_primary); $this->assertTrue($unrelated->fresh()->is_primary); } public function test_sales_script_relationship_has_one_canonical_foreign_key_direction(): void { $this->assertFalse(Schema::hasColumn('sales_scripts', 'campaign_id')); $this->assertFalse(Schema::hasColumn('sales_scripts', 'product_id')); $this->assertTrue(Schema::hasColumn('campaigns', 'sales_script_id')); $this->assertTrue(Schema::hasColumn('products', 'sales_script_id')); } public function test_contact_rejects_incompatible_parent_relationships(): void { $admin = $this->user('admin'); $firstCompany = Company::create(['name' => 'First company', 'created_by' => $admin->id]); $secondCompany = Company::create(['name' => 'Second company', 'created_by' => $admin->id]); $lead = Lead::create([ 'company_id' => $firstCompany->id, 'first_name' => 'Ali', 'last_name' => 'Ahmadi', 'phone' => '09121111111', ]); $this->actingAs($admin)->postJson('/api/contacts', [ 'name' => 'Invalid contact', 'lead_id' => $lead->id, 'company_id' => $secondCompany->id, 'phones' => [['phone' => '09120000000', 'type' => 'mobile']], ])->assertUnprocessable() ->assertJsonValidationErrors('relationships'); $this->assertDatabaseMissing('contacts', ['name' => 'Invalid contact']); } private function user(string $role): User { $user = User::factory()->create(['is_active' => true]); $user->assignRole($role); return $user; } }